xref: /xnu-12377.41.6/EXTERNAL_HEADERS/CoreEntitlements/QueryHelpers.h (revision bbb1b6f9e71b8cdde6e5cd6f4841f207dee3d828)
1 //
2 //  QueryHelpers.h
3 //  CoreEntitlements
4 //
5 
6 #ifndef CORE_ENTITLEMENTS_HELPERS_H
7 #define CORE_ENTITLEMENTS_HELPERS_H
8 
9 #include <sys/cdefs.h>
10 __ptrcheck_abi_assume_single();
11 
12 /*!
13  * @function CEDynamic
14  * Marks an opcode as being dynamic
15  *
16  * @param op
17  * Opcode
18  */
19 #define CEDynamic(op) (CEQueryOpOpcode_t)((op) | kCEOpDynamic)
20 
21 /*!
22  * @function CESelectIndex
23  * Returns an operation that when executed will modify the context such that any subsequent operation is performed on the entitlement object at the specified index
24  *
25  * @param index
26  * The index of the object within a container
27  *
28  * @discussion
29  * Using an index that is past the container's size will result in an invalid context
30  */
31 #define CESelectIndex(index) (CEQueryOperation_t){.opcode = kCEOpSelectIndex, .parameters = {.numericParameter = index}}
32 
33 /*!
34  * @function CESelectKey
35  * Returns an operation that when executed will modify the context such that any subsequent operation is performed on the key of the dictionary pair
36  * @discussion
37  * Selecting a key on a non-dictionary-pair object is undefined behavior (i..e. it is implementation defined)
38  */
39 #define CESelectKey() CESelectIndex(0)
40 
41 /*!
42  * @function CESelectValue
43  * Returns an operation that when executed will modify the context such that any subsequent operation is performed on the value of the dictionary pair
44  * @discussion
45  * Selecting a value on a non-dictionary-pair object is undefined behavior (i..e. it is implementation defined)
46  */
47 #define CESelectValue() CESelectIndex(1)
48 
49 
50 /*!
51  * @function CESelectDictValue
52  * Returns an operation that when executed will modify the context such that any subsequent operation is performed on the object that corresponds
53  * to the value pointed to by the specified key
54  *
55  * @param key
56  * The key of the object within a container
57  *
58  * @discussion
59  * Using a key that is not found in the container will result in an invalid context
60  */
61 #define CESelectDictValue(key) (CEQueryOperation_t){.opcode = kCEOpSelectKey, .parameters = {.stringParameter = {.data = key, .length = sizeof(key) - 1}}}
62 #define CESelectDictValueDynamic(key, len) (CEQueryOperation_t){.opcode = CEDynamic(kCEOpSelectKey), .parameters = {.dynamicParameter = {.data = key, .length = len}}}
63 
64 /*!
65  * @function CEMatchString
66  * Returns an operation that will return a valid context if and only if the context corresponds to a valid string and matches the string exactly
67  *
68  * @param string
69  * The string to match against (MUST BE A STRING LITERAL)
70  *
71  * @discussion
72  * If a valid context is returned it will be in the same state as the execution context
73  */
74 #define CEMatchString(string) (CEQueryOperation_t){.opcode = kCEOpMatchString, .parameters = {.stringParameter = {.data = string, .length = sizeof(string) - 1}}}
75 #define CEMatchDynamicString(string, len) (CEQueryOperation_t){.opcode = CEDynamic(kCEOpMatchString), .parameters = {.dynamicParameter = {.data = string, .length = len}}}
76 
77 /*!
78  * @function CEMatchPrefix
79  * Returns an operation that will return a valid context if and only if the context corresponds to a valid string and it's prefix matched the passed in prefix
80  *
81  * @param prefix
82  * The prefix to match against (MUST BE A STRING LITERAL)
83  *
84  * @discussion
85  * If a valid context is returned it will be in the same state as the execution context
86  */
87 #define CEMatchPrefix(prefix) (CEQueryOperation_t){.opcode = kCEOpMatchStringPrefix, .parameters = {.stringParameter = {.data = prefix, .length = sizeof(prefix) - 1}}}
88 #define CEMatchDynamicPrefix(prefix, len) (CEQueryOperation_t){.opcode = CEDynamic(kCEOpMatchStringPrefix), .parameters = {.dynamicParameter = {.data = prefix, .length = len}}}
89 
90 /*!
91  * @function CEMatchType
92  * Returns an operation that will return a valid context if and only if the type selected by the context corresponds to the one passed in.
93  *
94  * @param type
95  * The type to match against
96  *
97  * @discussion
98  * If a valid context is returned it will be in the same state as the execution context
99  */
100 #define CEMatchType(type) (CEQueryOperation_t){.opcode = kCEOpMatchType, .parameters = {.numericParameter = (int64_t)type}}
101 
102 /*!
103  * @function CEMatchBool
104  * Returns an operation that will return a valid context if and only if the context corresponds to a valid boolean and matches the boolean exactly
105  *
106  * @param val
107  * The bool to match against
108  *
109  * @discussion
110  * If a valid context is returned it will be in the same state as the execution context
111  */
112 #define CEMatchBool(val) (CEQueryOperation_t){.opcode = kCEOpMatchBool, .parameters = {.numericParameter = !!val}}
113 
114 /*!
115  * @function CEMatchInteger
116  * Returns an operation that will return a valid context if and only if the context corresponds to a valid integer and matches the integer exactly
117  *
118  * @param val
119  * The integer to match against
120  *
121  * @discussion
122  * If a valid context is returned it will be in the same state as the execution context
123  */
124 #define CEMatchInteger(val) (CEQueryOperation_t){.opcode = kCEOpMatchInteger, .parameters = {.numericParameter = val}}
125 
126 /*!
127  * @function CEIsIntegerAllowed
128  * Returns an operation that will return a valid context if 1) the current context is an integer and allows the integer, or 2) the context is an array of integers that allows the integer
129  *
130  * @param integer
131  * The integer to match against
132  *
133  * @discussion
134  * If a valid context is returned it will be in the same state as the execution context
135  */
136 #define CEIsIntegerAllowed(integer) (CEQueryOperation_t){.opcode = kCEOpIntegerValueAllowed, .parameters = {.numericParameter = integer}}
137 
138 /*!
139  * @function CEIsStringAllowed
140  * Returns an operation that will return a valid context if 1) the current context is a string and allows the string via wildcard rules, or 2) the context is an array of strings that allows the string
141  *
142  * @param string
143  * The string to match against (MUST BE A STRING LITERAL)
144  *
145  * @discussion
146  * If a valid context is returned it will be in the same state as the execution context
147  */
148 #define CEIsStringAllowed(string) (CEQueryOperation_t){.opcode = kCEOpStringValueAllowed, .parameters = {.stringParameter = {.data = string, .length = sizeof(string) - 1}}}
149 #define CEIsDynamicStringAllowed(string, len) (CEQueryOperation_t){.opcode = CEDynamic(kCEOpStringValueAllowed), .parameters = {.dynamicParameter = {.data = string, .length = len}}}
150 
151 /*!
152  * @function CEIsStringPrefixAllowed
153  * Returns an operation that will return a valid context if 1) the current context is a string and matches the prefix or 2) has an array that has the matches the prefix
154  *
155  * @param string
156  * The string to match against (MUST BE A STRING LITERAL)
157  *
158  * @discussion
159  * If a valid context is returned it will be in the same state as the execution context
160  */
161 #define CEIsStringPrefixAllowed(string) (CEQueryOperation_t){.opcode = kCEOpStringPrefixValueAllowed, .parameters = {.stringParameter = {.data = string, .length = sizeof(string) - 1}}}
162 #define CEIsDynamicStringPrefixAllowed(string, len) (CEQueryOperation_t){.opcode = CEDynamic(kCEOpStringPrefixValueAllowed), .parameters = {.dynamicParameter = {.data = (const uint8_t*)(string), .length = len}}}
163 
164 /*!
165  * @function CEMatchData
166  * Returns an operation that will return a valid context if and only if the context corresponds to valid data and matches the data exactly
167  *
168  * @param string
169  * The data to match against (MUST BE A BYTE ARRAY)
170  *
171  * @discussion
172  * If a valid context is returned it will be in the same state as the execution context
173  */
174 #define CEMatchDynamicData(d, len) (CEQueryOperation_t){.opcode = CEDynamic(kCEOpMatchData), .parameters = {.dynamicParameter = {.data = d, .length = len}}}
175 
176 /*!
177  * @function CEIsDataAllowed
178  * Returns an operation that will return a valid context if 1) the current context is data and allows the data, or 2) the context is an array of data elements that allows the data
179  *
180  * @param string
181  * The data to match against (MUST BE A BYTE ARRAY)
182  *
183  * @discussion
184  * If a valid context is returned it will be in the same state as the execution context
185  */
186 #define CEIsDynamicDataAllowed(d, len) (CEQueryOperation_t){.opcode = CEDynamic(kCEOpMatchDataValueAllowed), .parameters = {.dynamicParameter = {.data = d, .length = len}}}
187 
188 #pragma mark Helpers
189 /*
190  Macro magic
191  */
192 #define _SELECT_NTH_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, N, ...) N
193 
194 #define _mc_1(_call, x) _call(x),
195 #define _mc_2(_call, x, ...) _call(x), _mc_1(_call, __VA_ARGS__)
196 #define _mc_3(_call, x, ...) _call(x), _mc_2(_call, __VA_ARGS__)
197 #define _mc_4(_call, x, ...) _call(x), _mc_3(_call, __VA_ARGS__)
198 #define _mc_5(_call, x, ...) _call(x), _mc_4(_call, __VA_ARGS__)
199 #define _mc_6(_call, x, ...) _call(x), _mc_5(_call, __VA_ARGS__)
200 #define _mc_7(_call, x, ...) _call(x), _mc_6(_call, __VA_ARGS__)
201 #define _mc_8(_call, x, ...) _call(x), _mc_7(_call, __VA_ARGS__)
202 #define _mc_9(_call, x, ...) _call(x), _mc_8(_call, __VA_ARGS__)
203 #define _mc_10(_call, x, ...) _call(x), _mc_9(_call, __VA_ARGS__)
204 
205 #define _MACRO_ITER(macro, ...) _SELECT_NTH_ARG(__VA_ARGS__, _mc_10, _mc_9, _mc_8 _mc_7, _mc_6, _mc_5, _mc_4, _mc_3, _mc_2, _mc_1)(macro, __VA_ARGS__)
206 
207 /*!
208  Macro to automatically generate a query path from a list of string sub components
209  So
210  @code
211  CE_SELECT_PATH("hello, "world") will select a key "hello" and then look up "world" in the dictionary stored in the value of "hello"
212  @endcode
213  */
214 #define CE_SELECT_PATH(...) _MACRO_ITER(CESelectDictValue, __VA_ARGS__)
215 
216 // Macro for string equals
217 #define CE_STRING_EQUALS(str) CEMatchString(str)
218 
219 /*
220  A macro that checks if the passed in context grants (via an explicit true boolean) the entitlement at the passed in path.
221  */
222 #define CE_CONTEXT_GRANTS_ENTITLEMENT(ctx, ...) (CEContextQuery(ctx, (CEQuery_t){CE_SELECT_PATH(__VA_ARGS__) CEMatchBool(true)}, sizeof((CEQuery_t){CE_SELECT_PATH(__VA_ARGS__) CEMatchBool(true)}) / sizeof(CEQueryOperation_t)) == kCENoError)
223 
224 #endif
225