1#include "MISEntitlement.h"
2
3static const CFStringRef kEntitlementAllValuesAllowed = CFSTR("*");
4
5static Boolean whitelistArrayAllowsEntitlementValue(CFArrayRef whitelist, CFStringRef value)
6{
7    Boolean allowed = false;
8
9    CFIndex i, count = CFArrayGetCount(whitelist);
10    for (i = 0; (i < count) && (allowed == false); i++) {
11        CFStringRef item = (CFStringRef) CFArrayGetValueAtIndex(whitelist, i);
12        if (CFGetTypeID(item) == CFStringGetTypeID()) {
13
14            CFIndex len = CFStringGetLength(item);
15            if (len > 0) {
16                if (CFStringGetCharacterAtIndex(item, len-1) != '*') {
17
18                    /* Not a wildcard, must be an exact match */
19                    allowed = CFStringCompare(item, value, 0) == kCFCompareEqualTo;
20                } else {
21
22                    /* Last character is a wildcard - do some matching */
23                    CFStringRef wildcardPrefix = CFStringCreateWithSubstring(kCFAllocatorDefault, item, CFRangeMake(0, len-1));
24                    allowed = CFStringHasPrefix(value, wildcardPrefix);
25                    CFRelease(wildcardPrefix);
26                }
27            }
28        } else {
29
30            /* Unexpected item in whitelist - bail */
31            break;
32        }
33    }
34
35    return allowed;
36}
37
38Boolean MISEntitlementDictionaryAllowsEntitlementValue(CFDictionaryRef entitlements, CFStringRef entitlement, CFTypeRef value)
39{
40    Boolean allowsEntitlement = false;
41
42    /* NULL is never a valid entitlement value */
43    if (value != NULL) {
44
45        /* Make sure the entitlement is present */
46        CFTypeRef storedValue = CFDictionaryGetValue(entitlements, entitlement);
47        if (storedValue != NULL) {
48
49            /*
50             * Handling depends on the type
51             * If the value matches our constant, the entitlement is permitted
52             * to have any value.
53             * If the value in the dictionary is a boolean, then the entitlement
54             * value must be a boolean with the same value
55             * If the value in the dictionary is an array (of strings), then the
56             * entitlement must be either one of those strings OR an array that
57             * includes only present strings
58             */
59            if (CFEqual(storedValue, kEntitlementAllValuesAllowed) == true) {
60
61                /* XXX: Does this need to restrict the value to some types */
62                allowsEntitlement = true;
63            } else if (CFGetTypeID(storedValue) == CFBooleanGetTypeID()) {
64                allowsEntitlement = CFEqual(storedValue, value);
65            } else if (CFGetTypeID(storedValue) == CFStringGetTypeID()) {
66                if (CFGetTypeID(value) == CFStringGetTypeID()) {
67                    CFArrayRef array = CFArrayCreate(kCFAllocatorDefault, (const void **) &storedValue, 1, &kCFTypeArrayCallBacks);
68                    allowsEntitlement = whitelistArrayAllowsEntitlementValue(array, (CFStringRef) value);
69                    CFRelease(array);
70                }
71            } else if (CFGetTypeID(storedValue) == CFArrayGetTypeID()) {
72
73                /* value is either a single string or array of strings */
74                if (CFGetTypeID(value) == CFStringGetTypeID()) {
75                    allowsEntitlement = whitelistArrayAllowsEntitlementValue((CFArrayRef) storedValue, (CFStringRef) value);
76                } else if (CFGetTypeID(value) == CFArrayGetTypeID()) {
77
78                    /*
79                     * Assume allowed, will set back to false if we encounter
80                     * elements that are not permitted
81                     */
82                    allowsEntitlement = true;
83
84                    /* Make sure each element is a string and in the array */
85                    CFIndex i, count = CFArrayGetCount((CFArrayRef) value);
86                    for (i = 0; (i < count) && (allowsEntitlement == true); i++) {
87                        CFTypeRef element = CFArrayGetValueAtIndex((CFArrayRef) value, i);
88                        if (CFGetTypeID(element) == CFStringGetTypeID()) {
89                            allowsEntitlement = whitelistArrayAllowsEntitlementValue((CFArrayRef) storedValue, (CFStringRef) element);
90                        } else {
91                            allowsEntitlement = false;
92                        }
93                    }
94                }
95            }
96        }
97    }
98
99    return allowsEntitlement;
100}
101