1/* Copyright (c) 2012 Apple Inc. All rights reserved. */
2
3#include "authutilities.h"
4#include "authd_private.h"
5#include "debugging.h"
6
7#include <AssertMacros.h>
8#include <assert.h>
9#include <syslog.h>
10
11xpc_object_t
12SerializeItemSet(const AuthorizationItemSet * itemSet)
13{
14    xpc_object_t set = NULL;
15    require_quiet(itemSet != NULL, done);
16    require_quiet(itemSet->count != 0, done);
17
18    set = xpc_array_create(NULL, 0);
19    require(set != NULL, done);
20
21    for (uint32_t i = 0; i < itemSet->count; i++) {
22        xpc_object_t item = xpc_dictionary_create(NULL, NULL, 0);
23        require(item != NULL, done);
24
25        xpc_dictionary_set_string(item, AUTH_XPC_ITEM_NAME, itemSet->items[i].name);
26        xpc_dictionary_set_uint64(item, AUTH_XPC_ITEM_FLAGS, itemSet->items[i].flags);
27        xpc_dictionary_set_data(item, AUTH_XPC_ITEM_VALUE, itemSet->items[i].value, itemSet->items[i].valueLength);
28        xpc_array_set_value(set, XPC_ARRAY_APPEND, item);
29        xpc_release(item);
30    }
31
32done:
33    return set;
34}
35
36AuthorizationItemSet *
37DeserializeItemSet(const xpc_object_t data)
38{
39    AuthorizationItemSet * set = NULL;
40    require_quiet(data != NULL, done);
41    xpc_retain(data);
42    require(xpc_get_type(data) == XPC_TYPE_ARRAY, done);
43
44    set = (AuthorizationItemSet*)calloc(1u, sizeof(AuthorizationItemSet));
45    require(set != NULL, done);
46
47    set->count = (uint32_t)xpc_array_get_count(data);
48    if (set->count) {
49        set->items = (AuthorizationItem*)calloc(set->count, sizeof(AuthorizationItem));
50        require_action(set->items != NULL, done, set->count = 0);
51
52        xpc_array_apply(data, ^bool(size_t index, xpc_object_t value) {
53            require(xpc_get_type(value) == XPC_TYPE_DICTIONARY, done);
54            size_t nameLen = 0;
55            const char * name = xpc_dictionary_get_string(value, AUTH_XPC_ITEM_NAME);
56            if (name) {
57                nameLen = strlen(name) + 1;
58                set->items[index].name = calloc(1u, nameLen);
59                require(set->items[index].name != NULL, done);
60
61                strlcpy((char*)set->items[index].name, name, nameLen);
62            }
63            set->items[index].flags = (uint32_t)xpc_dictionary_get_uint64(value, AUTH_XPC_ITEM_FLAGS);
64            size_t len;
65            const void * valueData = xpc_dictionary_get_data(value, AUTH_XPC_ITEM_VALUE, &len);
66            set->items[index].valueLength = len;
67            if (len) {
68                set->items[index].value = calloc(1u, len);
69                require(set->items[index].value != NULL, done);
70
71                memcpy(set->items[index].value, valueData, len);
72            }
73        done:
74            return true;
75        });
76    }
77
78done:
79    if (data != NULL) {
80        xpc_release(data);
81    }
82    return set;
83}
84
85void FreeItemSet(AuthorizationItemSet * itemSet)
86{
87    if (!itemSet) { return; }
88
89    for(uint32_t i = 0; i < itemSet->count; i++ ) {
90        if (itemSet->items[i].name) {
91            free((void*)itemSet->items[i].name);
92        }
93        if (itemSet->items[i].value) {
94            free(itemSet->items[i].value);
95        }
96    }
97    if (itemSet->items) {
98        free(itemSet->items);
99    }
100
101    free(itemSet);
102}
103
104char *
105_copy_cf_string(CFTypeRef str, const char * defaultValue)
106{
107    char * result = NULL;
108    require(str != NULL, done);
109    require(CFGetTypeID(str) == CFStringGetTypeID(), done);
110
111    CFIndex length = CFStringGetLength(str);
112    CFIndex size = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1;
113
114    result = (char*)calloc(1u, (size_t)size);
115    check(result != NULL);
116
117    if (!CFStringGetCString(str, result, size, kCFStringEncodingUTF8)) {
118        free_safe(result);
119    }
120
121done:
122    if (result == NULL && defaultValue) {
123        size_t len = strlen(defaultValue);
124        result = (char*)calloc(1u, len);
125        check(result != NULL);
126
127        strlcpy(result, defaultValue, len);
128    }
129
130    return result;
131}
132
133int64_t
134_get_cf_int(CFTypeRef num, int64_t defaultValue)
135{
136    int64_t result = defaultValue;
137    require(num != NULL, done);
138    require(CFGetTypeID(num) == CFNumberGetTypeID(), done);
139
140    if (!CFNumberGetValue(num, kCFNumberSInt64Type, &result)) {
141        result = defaultValue;
142    }
143
144done:
145    return result;
146}
147
148bool
149_get_cf_bool(CFTypeRef value, bool defaultValue)
150{
151    bool result = defaultValue;
152    require(value != NULL, done);
153    require(CFGetTypeID(value) == CFBooleanGetTypeID(), done);
154
155    result = CFBooleanGetValue(value);
156
157done:
158    return result;
159}
160
161bool
162_compare_string(const char * str1, const char * str2)
163{
164    if (!(str1 == str2)) {  // compare null or same pointer
165        if (str1 && str2) { // check both are non null
166            if (strcasecmp(str1, str2) != 0) { // compare strings
167                return false; // return false if not equal
168            }
169        } else {
170            return false; // return false if one null
171        }
172    }
173
174    return true;
175}
176
177char *
178_copy_string(const char * str)
179{
180    char * result = NULL;
181    require(str != NULL, done);
182
183    size_t len = strlen(str) + 1;
184    result = calloc(1u, len);
185    require(result != NULL, done);
186
187    strlcpy(result, str, len);
188
189done:
190    return result;
191}
192
193void *
194_copy_data(const void * data, size_t dataLen)
195{
196    void * result = NULL;
197    require(data != NULL, done);
198
199    result = calloc(1u, dataLen);
200    require(result != NULL, done);
201
202    memcpy(result, data, dataLen);
203
204done:
205    return result;
206}
207
208bool _cf_set_iterate(CFSetRef set, bool(^iterator)(CFTypeRef value))
209{
210    bool result = false;
211    CFTypeRef* values = NULL;
212
213    require(set != NULL, done);
214
215    CFIndex count = CFSetGetCount(set);
216    values = calloc((size_t)count, sizeof(CFTypeRef));
217    require(values != NULL, done);
218
219    CFSetGetValues(set, values);
220    for (CFIndex i = 0; i < count; i++) {
221        result = iterator(values[i]);
222        if (!result) {
223            break;
224        }
225    }
226
227done:
228    free_safe(values);
229    return result;
230}
231
232bool _cf_bag_iterate(CFBagRef bag, bool(^iterator)(CFTypeRef value))
233{
234    bool result = false;
235    CFTypeRef* values = NULL;
236
237    require(bag != NULL, done);
238
239    CFIndex count = CFBagGetCount(bag);
240    values = calloc((size_t)count, sizeof(CFTypeRef));
241    require(values != NULL, done);
242
243    CFBagGetValues(bag, values);
244    for (CFIndex i = 0; i < count; i++) {
245        result = iterator(values[i]);
246        if (!result) {
247            break;
248        }
249    }
250
251done:
252    free_safe(values);
253    return result;
254}
255
256bool _cf_dictionary_iterate(CFDictionaryRef dict, bool(^iterator)(CFTypeRef key, CFTypeRef value))
257{
258    bool result = false;
259    CFTypeRef* keys = NULL;
260    CFTypeRef* values = NULL;
261
262    require(dict != NULL, done);
263
264    CFIndex count = CFDictionaryGetCount(dict);
265    keys = calloc((size_t)count, sizeof(CFTypeRef));
266    require(keys != NULL, done);
267
268    values = calloc((size_t)count, sizeof(CFTypeRef));
269    require(values != NULL, done);
270
271    CFDictionaryGetKeysAndValues(dict, keys, values);
272    for (CFIndex i = 0; i < count; i++) {
273        result = iterator(keys[i], values[i]);
274        if (!result) {
275            break;
276        }
277    }
278
279done:
280    free_safe(keys);
281    free_safe(values);
282    return result;
283}
284