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