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