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