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