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