1/* Copyright (c) 2012-2013 Apple Inc. All Rights Reserved. */
2
3#include "rule.h"
4#include "authutilities.h"
5#include "mechanism.h"
6#include "crc.h"
7#include "debugging.h"
8#include "authitems.h"
9#include "process.h"
10
11#include <Security/AuthorizationDB.h>
12#include <Security/AuthorizationTagsPriv.h>
13#include "server.h"
14
15static void _sql_get_id(rule_t,authdb_connection_t);
16static RuleClass _get_cf_rule_class(CFTypeRef);
17static bool _copy_cf_rule_mechanisms(rule_t,CFTypeRef,authdb_connection_t);
18static bool _copy_cf_rule_delegations(rule_t, CFTypeRef,authdb_connection_t);
19
20#define kMaximumAuthorizationTries 10000
21
22#define RULE_ID "id"
23#define RULE_NAME "name"
24#define RULE_TYPE "type"
25#define RULE_CLASS "class"
26#define RULE_GROUP "group"
27#define RULE_KOFN   "kofn"
28#define RULE_TIMEOUT "timeout"
29#define RULE_FLAGS "flags"
30#define RULE_TRIES "tries"
31#define RULE_COMMENT "comment"
32#define RULE_VERSION "version"
33#define RULE_CREATED "created"
34#define RULE_MODIFIED "modified"
35#define RULE_IDENTIFIER "identifier"
36#define RULE_REQUIREMENT "requirement"
37#define RULE_HASH "hash"
38
39struct _rule_s {
40    __AUTH_BASE_STRUCT_HEADER__;
41
42    auth_items_t data;
43    CFMutableArrayRef mechanisms;
44    CFMutableArrayRef delegations;
45
46    CFMutableDictionaryRef loc_prompts;
47    CFMutableDictionaryRef loc_buttons;
48
49    CFDataRef requirement_data;
50    SecRequirementRef requirement;
51};
52
53static void
54_rule_finalize(CFTypeRef value)
55{
56    rule_t rule = (rule_t)value;
57    CFReleaseSafe(rule->data);
58    CFReleaseSafe(rule->mechanisms);
59    CFReleaseSafe(rule->delegations);
60    CFReleaseSafe(rule->loc_prompts);
61    CFReleaseSafe(rule->loc_buttons);
62    CFReleaseSafe(rule->requirement_data);
63    CFReleaseSafe(rule->requirement);
64}
65
66static Boolean
67_rule_equal(CFTypeRef value1, CFTypeRef value2)
68{
69    rule_t rule1 = (rule_t)value1;
70    rule_t rule2 = (rule_t)value2;
71
72    return strcasecmp(rule_get_name(rule1), rule_get_name(rule2)) == 0;
73}
74
75static CFStringRef
76_rule_copy_description(CFTypeRef value)
77{
78    rule_t rule = (rule_t)value;
79    CFMutableStringRef str = CFStringCreateMutable(kCFAllocatorDefault, 0);
80    CFStringRef tmp = CFCopyDescription(rule->data);
81    CFStringAppend(str, tmp);
82    CFReleaseNull(tmp);
83    tmp = CFCopyDescription(rule->mechanisms);
84    CFStringAppend(str, tmp);
85    CFReleaseNull(tmp);
86    tmp = CFCopyDescription(rule->delegations);
87    CFStringAppend(str, tmp);
88    CFReleaseNull(tmp);
89    return str;
90}
91
92static CFHashCode
93_rule_hash(CFTypeRef value)
94{
95    rule_t rule = (rule_t)value;
96    const char * str = rule_get_name(rule);
97    return crc64(str, strlen(str));
98}
99
100AUTH_TYPE_INSTANCE(rule,
101                   .init = NULL,
102                   .copy = NULL,
103                   .finalize = _rule_finalize,
104                   .equal = _rule_equal,
105                   .hash = _rule_hash,
106                   .copyFormattingDesc = NULL,
107                   .copyDebugDesc = _rule_copy_description
108                   );
109
110static CFTypeID rule_get_type_id() {
111    static CFTypeID type_id = _kCFRuntimeNotATypeID;
112    static dispatch_once_t onceToken;
113
114    dispatch_once(&onceToken, ^{
115        type_id = _CFRuntimeRegisterClass(&_auth_type_rule);
116    });
117
118    return type_id;
119}
120
121static rule_t
122_rule_create()
123{
124    rule_t rule = (rule_t)_CFRuntimeCreateInstance(kCFAllocatorDefault, rule_get_type_id(), AUTH_CLASS_SIZE(rule), NULL);
125    require(rule != NULL, done);
126
127    rule->data = auth_items_create();
128    rule->delegations = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
129    rule->mechanisms = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
130
131done:
132    return rule;
133}
134
135static rule_t
136_rule_create_with_sql(auth_items_t sql)
137{
138    rule_t rule = NULL;
139    require(sql != NULL, done);
140
141    rule = _rule_create();
142    require(rule != NULL, done);
143
144    auth_items_copy(rule->data, sql);
145
146done:
147    return rule;
148}
149
150rule_t
151rule_create_default()
152{
153    rule_t rule = _rule_create();
154    require(rule != NULL, done);
155
156    auth_items_set_int64(rule->data, RULE_TYPE, RT_RIGHT);
157    auth_items_set_string(rule->data, RULE_NAME, "(default)");
158    auth_items_set_int64(rule->data, RULE_CLASS, RC_USER);
159    auth_items_set_string(rule->data, RULE_GROUP, "admin");
160    auth_items_set_int64(rule->data, RULE_TIMEOUT, 300);
161    auth_items_set_int64(rule->data, RULE_TRIES, kMaximumAuthorizationTries);
162    auth_items_set_int64(rule->data, RULE_FLAGS, RuleFlagShared | RuleFlagAuthenticateUser);
163
164    mechanism_t mech = mechanism_create_with_string("builtin:authenticate", NULL);
165    CFArrayAppendValue(rule->mechanisms, mech);
166    CFReleaseNull(mech);
167
168    mech = mechanism_create_with_string("builtin:reset-password,privileged", NULL);
169    CFArrayAppendValue(rule->mechanisms, mech);
170    CFReleaseNull(mech);
171
172    mech = mechanism_create_with_string("builtin:authenticate,privileged", NULL);
173    CFArrayAppendValue(rule->mechanisms, mech);
174    CFReleaseNull(mech);
175
176    mech = mechanism_create_with_string("PKINITMechanism:auth,privileged", NULL);
177    CFArrayAppendValue(rule->mechanisms, mech);
178    CFReleaseNull(mech);
179
180done:
181    return rule;
182}
183
184rule_t
185rule_create_with_string(const char * str, authdb_connection_t dbconn)
186{
187    rule_t rule = NULL;
188    require(str != NULL, done);
189
190    rule = _rule_create();
191    require(rule != NULL, done);
192
193    auth_items_set_string(rule->data, RULE_NAME, str);
194
195    if (dbconn) {
196        rule_sql_fetch(rule, dbconn);
197    }
198
199done:
200    return rule;
201}
202
203static void _set_data_string(rule_t rule, const char * key, CFStringRef str)
204{
205    char * tmpStr = _copy_cf_string(str, NULL);
206
207    if (tmpStr) {
208        auth_items_set_string(rule->data, key, tmpStr);
209        free_safe(tmpStr);
210    }
211}
212
213rule_t
214rule_create_with_plist(RuleType type, CFStringRef name, CFDictionaryRef plist, authdb_connection_t dbconn)
215{
216    rule_t rule = NULL;
217    require(name != NULL, done);
218    require(plist != NULL, done);
219
220    rule = _rule_create();
221    require(rule != NULL, done);
222
223    _set_data_string(rule, RULE_NAME, name);
224    require_action(rule_get_name(rule) != NULL, done, CFReleaseSafe(rule));
225
226    _sql_get_id(rule, dbconn);
227
228    auth_items_set_int64(rule->data, RULE_TYPE, type);
229
230    auth_items_set_int64(rule->data, RULE_CLASS, _get_cf_rule_class(CFDictionaryGetValue(plist, CFSTR(kAuthorizationRuleClass))));
231    _set_data_string(rule, RULE_COMMENT, CFDictionaryGetValue(plist, CFSTR(kAuthorizationComment)));
232
233
234    CFTypeRef loc_tmp = CFDictionaryGetValue(plist, CFSTR(kAuthorizationRuleParameterDefaultPrompt));
235    if (loc_tmp) {
236        rule->loc_prompts = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, loc_tmp);
237    }
238    loc_tmp = CFDictionaryGetValue(plist, CFSTR(kAuthorizationRuleParameterDefaultButton));
239    if (loc_tmp) {
240        rule->loc_buttons = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, loc_tmp);
241    }
242
243    auth_items_set_int64(rule->data, RULE_VERSION, _get_cf_int(CFDictionaryGetValue(plist, CFSTR("version")), 0));
244
245    RuleFlags flags = 0;
246
247    if (_get_cf_bool(CFDictionaryGetValue(plist, CFSTR(kAuthorizationRuleParameterEntitled)), false)) {
248        flags |= RuleFlagEntitled;
249    }
250
251    if (_get_cf_bool(CFDictionaryGetValue(plist, CFSTR(kAuthorizationRuleParameterRequireAppleSigned)), false)) {
252        flags |= RuleFlagRequireAppleSigned;
253    }
254
255    switch (rule_get_class(rule)) {
256        case RC_USER:
257            _set_data_string(rule, RULE_GROUP, CFDictionaryGetValue(plist, CFSTR(kAuthorizationRuleParameterGroup)));
258            auth_items_set_int64(rule->data, RULE_TIMEOUT, _get_cf_int(CFDictionaryGetValue(plist, CFSTR(kAuthorizationRuleParameterCredentialTimeout)), INT32_MAX));
259            auth_items_set_int64(rule->data, RULE_TRIES, _get_cf_int(CFDictionaryGetValue(plist, CFSTR("tries")), kMaximumAuthorizationTries));
260
261            if (_get_cf_bool(CFDictionaryGetValue(plist, CFSTR(kAuthorizationRuleParameterCredentialShared)), false)) {
262                flags |= RuleFlagShared;
263            }
264            if (_get_cf_bool(CFDictionaryGetValue(plist, CFSTR(kAuthorizationRuleParameterAllowRoot)), false)) {
265                flags |= RuleFlagAllowRoot;
266            }
267            if (_get_cf_bool(CFDictionaryGetValue(plist, CFSTR(kAuthorizationRuleParameterCredentialSessionOwner)), false)) {
268                flags |= RuleFlagSessionOwner;
269            }
270            if (_get_cf_bool(CFDictionaryGetValue(plist, CFSTR(kAuthorizationRuleParameterAuthenticateUser)), true)) {
271                flags |= RuleFlagAuthenticateUser;
272            }
273            if (_get_cf_bool(CFDictionaryGetValue(plist, CFSTR(kAuthorizationRuleParameterExtractPassword)), false)) {
274                flags |= RuleFlagExtractPassword;
275            }
276            if (_get_cf_bool(CFDictionaryGetValue(plist, CFSTR(kAuthorizationRuleParameterEntitledAndGroup)), false)) {
277                flags |= RuleFlagEntitledAndGroup;
278            }
279            if (_get_cf_bool(CFDictionaryGetValue(plist, CFSTR(kAuthorizationRuleParameterVPNEntitledAndGroup)), false)) {
280                flags |= RuleFlagVPNEntitledAndGroup;
281            }
282
283            _copy_cf_rule_mechanisms(rule, CFDictionaryGetValue(plist, CFSTR(kAuthorizationRuleParameterMechanisms)), dbconn);
284
285            break;
286        case RC_RULE:
287            auth_items_set_int64(rule->data, RULE_KOFN, _get_cf_int(CFDictionaryGetValue(plist, CFSTR(kAuthorizationRuleParameterKofN)), 0));
288
289            _copy_cf_rule_delegations(rule, CFDictionaryGetValue(plist, CFSTR(kAuthorizationRightRule)), dbconn);
290            break;
291        case RC_MECHANISM:
292            auth_items_set_int64(rule->data, RULE_TRIES, _get_cf_int(CFDictionaryGetValue(plist, CFSTR("tries")), kMaximumAuthorizationTries));
293            if (_get_cf_bool(CFDictionaryGetValue(plist, CFSTR(kAuthorizationRuleParameterCredentialShared)), true)) {
294                flags |= RuleFlagShared;
295            }
296            if (_get_cf_bool(CFDictionaryGetValue(plist, CFSTR(kAuthorizationRuleParameterExtractPassword)), false)) {
297                flags |= RuleFlagExtractPassword;
298            }
299
300            _copy_cf_rule_mechanisms(rule, CFDictionaryGetValue(plist, CFSTR(kAuthorizationRuleParameterMechanisms)), dbconn);
301
302            break;
303        case RC_DENY:
304            break;
305        case RC_ALLOW:
306            break;
307        default:
308            LOGD("rule: invalid rule class");
309            break;
310    }
311
312    auth_items_set_int64(rule->data, RULE_FLAGS, flags);
313
314done:
315    return rule;
316}
317
318static void
319_sql_get_id(rule_t rule, authdb_connection_t dbconn)
320{
321    authdb_step(dbconn, "SELECT id,created,identifier,requirement FROM rules WHERE name = ? LIMIT 1",
322    ^(sqlite3_stmt *stmt) {
323        sqlite3_bind_text(stmt, 1, rule_get_name(rule), -1, NULL);
324    }, ^bool(auth_items_t data) {
325        auth_items_copy(rule->data, data);
326        return true;
327    });
328}
329
330static bool
331_copy_cf_rule_delegations(rule_t rule, CFTypeRef value, authdb_connection_t dbconn)
332{
333    bool result = false;
334    char * tmp_str = NULL;
335    require(value != NULL, done);
336
337    if (CFGetTypeID(value) == CFStringGetTypeID()) {
338        tmp_str = _copy_cf_string(value, NULL);
339        rule_t delegate = rule_create_with_string(tmp_str, dbconn);
340        free_safe(tmp_str);
341        if (delegate) {
342            CFArrayAppendValue(rule->delegations, delegate);
343            CFReleaseSafe(delegate);
344        }
345    } else { //array
346        CFIndex count = CFArrayGetCount(value);
347        for (CFIndex i = 0; i < count; i++) {
348            tmp_str = _copy_cf_string(CFArrayGetValueAtIndex(value,i), NULL);
349            rule_t delegate = rule_create_with_string(tmp_str, dbconn);
350            free_safe(tmp_str);
351            if (delegate) {
352                CFArrayAppendValue(rule->delegations, delegate);
353                CFReleaseSafe(delegate);
354            }
355        }
356    }
357
358    result = true;
359
360done:
361    return result;
362}
363
364static bool
365_copy_cf_rule_mechanisms(rule_t rule, CFTypeRef array, authdb_connection_t dbconn)
366{
367    bool result = false;
368    require(array != NULL, done);
369    require(CFGetTypeID(array) == CFArrayGetTypeID(), done);
370
371    CFIndex count = CFArrayGetCount(array);
372    for (CFIndex i = 0; i < count; i++) {
373        mechanism_t mech = NULL;
374        char * string = _copy_cf_string(CFArrayGetValueAtIndex(array, i), NULL);
375
376        if (!string)
377            continue;
378
379        mech = mechanism_create_with_string(string, dbconn);
380        if (mech) {
381            CFArrayAppendValue(rule->mechanisms, mech);
382            CFReleaseSafe(mech);
383        }
384        free(string);
385    }
386
387    result = true;
388
389done:
390    return result;
391}
392
393static RuleClass
394_get_cf_rule_class(CFTypeRef str)
395{
396    RuleClass rc = RC_RULE;
397    require(str != NULL, done);
398    require(CFGetTypeID(str) == CFStringGetTypeID(), done);
399
400    if (CFEqual(str, CFSTR(kAuthorizationRuleClassUser)))
401        return RC_USER;
402
403    if (CFEqual(str, CFSTR(kAuthorizationRightRule)))
404        return RC_RULE;
405
406    if (CFEqual(str, CFSTR(kAuthorizationRuleClassMechanisms)))
407        return RC_MECHANISM;
408
409    if (CFEqual(str, CFSTR(kAuthorizationRuleClassDeny)))
410        return RC_DENY;
411
412    if (CFEqual(str, CFSTR(kAuthorizationRuleClassAllow)))
413        return RC_ALLOW;
414
415done:
416    return rc;
417}
418
419static bool
420_sql_bind(rule_t rule, sqlite3_stmt * stmt)
421{
422    int64_t n;
423    int32_t rc = 0;
424    require(stmt != NULL, err);
425
426    int32_t column = 1;
427    rc = sqlite3_bind_text(stmt, column++, rule_get_name(rule), -1, NULL);
428    require_noerr(rc, err);
429    rc = sqlite3_bind_int(stmt, column++, rule_get_type(rule));
430    require_noerr(rc, err);
431    rc = sqlite3_bind_int(stmt, column++, rule_get_class(rule));
432    require_noerr(rc, err);
433
434    switch (rule_get_class(rule)) {
435        case RC_USER:
436            rc = sqlite3_bind_text(stmt, column++, rule_get_group(rule), -1, NULL);
437            require_noerr(rc, err);
438            rc = sqlite3_bind_null(stmt, column++); // kofn
439            require_noerr(rc, err);
440            rc = sqlite3_bind_int64(stmt, column++, rule_get_timeout(rule));
441            require_noerr(rc, err);
442            rc = sqlite3_bind_int64(stmt, column++, auth_items_get_int64(rule->data, RULE_FLAGS));
443            require_noerr(rc, err);
444            rc = sqlite3_bind_int64(stmt, column++, rule_get_tries(rule));
445            require_noerr(rc, err);
446            break;
447        case RC_RULE:
448            rc = sqlite3_bind_null(stmt, column++); // group
449            require_noerr(rc, err);
450            n = rule_get_kofn(rule);
451            if (n) {
452                rc = sqlite3_bind_int64(stmt, column++, n);
453            } else {
454                rc = sqlite3_bind_null(stmt, column++);
455            }
456            require_noerr(rc, err);
457            rc = sqlite3_bind_null(stmt, column++); // timeout
458            require_noerr(rc, err);
459            rc = sqlite3_bind_int64(stmt, column++, auth_items_get_int64(rule->data, RULE_FLAGS));
460            require_noerr(rc, err);
461            rc = sqlite3_bind_null(stmt, column++); // tries
462            require_noerr(rc, err);
463            break;
464        case RC_MECHANISM:
465            rc = sqlite3_bind_null(stmt, column++); // group
466            require_noerr(rc, err);
467            rc = sqlite3_bind_null(stmt, column++); // kofn
468            require_noerr(rc, err);
469            rc = sqlite3_bind_null(stmt, column++); // timeout
470            require_noerr(rc, err);
471            rc = sqlite3_bind_int64(stmt, column++, auth_items_get_int64(rule->data, RULE_FLAGS));
472            require_noerr(rc, err);
473            rc = sqlite3_bind_int64(stmt, column++, rule_get_tries(rule));
474            require_noerr(rc, err);
475            break;
476        case RC_DENY:
477        case RC_ALLOW:
478            rc = sqlite3_bind_null(stmt, column++); // group
479            require_noerr(rc, err);
480            rc = sqlite3_bind_null(stmt, column++); // kofn
481            require_noerr(rc, err);
482            rc = sqlite3_bind_null(stmt, column++); // timeout
483            require_noerr(rc, err);
484            rc = sqlite3_bind_int64(stmt, column++, auth_items_get_int64(rule->data, RULE_FLAGS));
485            require_noerr(rc, err);
486            rc = sqlite3_bind_null(stmt, column++); // tries
487            require_noerr(rc, err);
488            break;
489        default:
490            LOGD("rule: sql bind, invalid rule class");
491            break;
492    }
493
494    rc = sqlite3_bind_int64(stmt, column++, rule_get_version(rule)); // version
495    require_noerr(rc, err);
496    rc = sqlite3_bind_double(stmt, column++, rule_get_created(rule)); // created
497    require_noerr(rc, err);
498    rc = sqlite3_bind_double(stmt, column++, rule_get_modified(rule)); // modified
499    require_noerr(rc, err);
500    rc = sqlite3_bind_null(stmt, column++); // hash
501    require_noerr(rc, err);
502    rc = sqlite3_bind_text(stmt, column++, rule_get_identifier(rule), -1, NULL);
503    require_noerr(rc, err);
504
505    CFDataRef data = rule_get_requirment_data(rule);
506    if (data) {
507        rc = sqlite3_bind_blob(stmt, column++, CFDataGetBytePtr(data), (int32_t)CFDataGetLength(data), NULL);
508    } else {
509        rc = sqlite3_bind_null(stmt, column++);
510    }
511    require_noerr(rc, err);
512
513    rc = sqlite3_bind_text(stmt, column++, rule_get_comment(rule), -1, NULL);
514    require_noerr(rc, err);
515
516    return true;
517
518err:
519    LOGD("rule: sql bind, error %i", rc);
520    return false;
521}
522
523static void
524_get_sql_mechanisms(rule_t rule, authdb_connection_t dbconn)
525{
526    CFArrayRemoveAllValues(rule->mechanisms);
527
528    authdb_step(dbconn, "SELECT mechanisms.* " \
529                "FROM mechanisms " \
530                "JOIN mechanisms_map ON mechanisms.id = mechanisms_map.m_id " \
531                "WHERE mechanisms_map.r_id = ? ORDER BY mechanisms_map.ord ASC",
532    ^(sqlite3_stmt *stmt) {
533        sqlite3_bind_int64(stmt, 1, rule_get_id(rule));
534    }, ^bool(auth_items_t data) {
535        mechanism_t mechanism = mechanism_create_with_sql(data);
536        CFArrayAppendValue(rule->mechanisms, mechanism);
537        CFReleaseSafe(mechanism);
538        return true;
539    });
540}
541
542static void
543_get_sql_delegates(rule_t rule, authdb_connection_t dbconn)
544{
545    CFArrayRemoveAllValues(rule->delegations);
546
547    authdb_step(dbconn, "SELECT rules.* " \
548                "FROM rules " \
549                "JOIN delegates_map ON rules.id = delegates_map.d_id " \
550                "WHERE delegates_map.r_id = ? ORDER BY delegates_map.ord ASC",
551                ^(sqlite3_stmt *stmt) {
552                    sqlite3_bind_int64(stmt, 1, rule_get_id(rule));
553                }, ^bool(auth_items_t data) {
554                    rule_t delegate = _rule_create_with_sql(data);
555                    if (delegate) {
556                        _get_sql_mechanisms(delegate, dbconn);
557
558                        if (rule_get_class(rule) == RC_RULE) {
559                            _get_sql_delegates(delegate, dbconn);
560                        }
561
562                        CFArrayAppendValue(rule->delegations, delegate);
563                        CFReleaseSafe(delegate);
564                    }
565                    return true;
566                });
567}
568
569bool
570rule_sql_fetch(rule_t rule, authdb_connection_t dbconn)
571{
572    __block bool result = false;
573
574    authdb_step(dbconn, "SELECT * FROM rules WHERE name = ? LIMIT 1",
575    ^(sqlite3_stmt *stmt) {
576        sqlite3_bind_text(stmt, 1, rule_get_name(rule), -1, NULL);
577    }, ^bool(auth_items_t data) {
578        result = true;
579        auth_items_copy(rule->data, data);
580        return true;
581    });
582
583    if (rule_get_id(rule) != 0) {
584        _get_sql_mechanisms(rule,dbconn);
585
586        if (rule_get_class(rule) == RC_RULE) {
587            _get_sql_delegates(rule, dbconn);
588        }
589    }
590
591    return result;
592}
593
594static bool
595_sql_update(rule_t rule, authdb_connection_t dbconn)
596{
597    bool result = false;
598
599    result = authdb_step(dbconn, "UPDATE rules " \
600                         "SET name=?,type=?,class=?,'group'=?,kofn=?,timeout=?,flags=?,tries=?,version=?,created=?,modified=?,hash=?,identifier=?,requirement=?,comment=? " \
601                         "WHERE id = ?",
602                         ^(sqlite3_stmt *stmt) {
603                             _sql_bind(rule, stmt);
604                             sqlite3_bind_int64(stmt, sqlite3_bind_parameter_count(stmt), rule_get_id(rule));
605                         }, NULL);
606    return result;
607}
608
609static bool
610_sql_insert(rule_t rule, authdb_connection_t dbconn)
611{
612    bool result = false;
613
614    result = authdb_step(dbconn, "INSERT INTO rules VALUES (NULL,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
615                         ^(sqlite3_stmt *stmt) {
616                             _sql_bind(rule, stmt);
617                         }, NULL);
618    return result;
619}
620
621static bool
622_sql_commit_mechanisms_map(rule_t rule, authdb_connection_t dbconn)
623{
624    bool result = false;
625
626    result = authdb_step(dbconn, "DELETE FROM mechanisms_map WHERE r_id = ?", ^(sqlite3_stmt *stmt) {
627        sqlite3_bind_int64(stmt, 1, rule_get_id(rule));
628    }, NULL);
629    require(result == true, done);
630
631    CFIndex count = CFArrayGetCount(rule->mechanisms);
632    for(CFIndex i = 0; i < count; i++) {
633        mechanism_t mech = (mechanism_t)CFArrayGetValueAtIndex(rule->mechanisms, i);
634        result = authdb_step(dbconn, "INSERT INTO mechanisms_map VALUES (?,?,?)", ^(sqlite3_stmt *stmt) {
635            sqlite3_bind_int64(stmt, 1, rule_get_id(rule));
636            sqlite3_bind_int64(stmt, 2, mechanism_get_id(mech));
637            sqlite3_bind_int64(stmt, 3, i);
638        }, NULL);
639        require(result == true, done);
640    }
641
642done:
643    return result;
644}
645
646static bool
647_sql_commit_delegates_map(rule_t rule, authdb_connection_t dbconn)
648{
649    bool result = false;
650
651    result = authdb_step(dbconn, "DELETE FROM delegates_map WHERE r_id = ?", ^(sqlite3_stmt *stmt) {
652        sqlite3_bind_int64(stmt, 1, rule_get_id(rule));
653    }, NULL);
654    require(result == true, done);
655
656    CFIndex count = CFArrayGetCount(rule->delegations);
657    for(CFIndex i = 0; i < count; i++) {
658        rule_t delegate = (rule_t)CFArrayGetValueAtIndex(rule->delegations, i);
659        result = authdb_step(dbconn, "INSERT INTO delegates_map VALUES (?,?,?)", ^(sqlite3_stmt *stmt) {
660            sqlite3_bind_int64(stmt, 1, rule_get_id(rule));
661            sqlite3_bind_int64(stmt, 2, rule_get_id(delegate));
662            sqlite3_bind_int64(stmt, 3, i);
663        }, NULL);
664        require(result == true, done);
665    }
666
667done:
668    return result;
669}
670
671static void
672_sql_commit_localization(rule_t rule, authdb_connection_t dbconn)
673{
674
675    authdb_step(dbconn, "DELETE FROM prompts WHERE r_id = ?", ^(sqlite3_stmt *stmt) {
676        sqlite3_bind_int64(stmt, 1, rule_get_id(rule));
677    }, NULL);
678
679    authdb_step(dbconn, "DELETE FROM buttons WHERE r_id = ?", ^(sqlite3_stmt *stmt) {
680        sqlite3_bind_int64(stmt, 1, rule_get_id(rule));
681    }, NULL);
682
683    if (rule->loc_prompts) {
684        _cf_dictionary_iterate(rule->loc_prompts, ^bool(CFTypeRef key, CFTypeRef value) {
685            char * lang = _copy_cf_string(key, NULL);
686            char * str = _copy_cf_string(value, NULL);
687
688            authdb_step(dbconn, "INSERT INTO prompts VALUES (?,?,?)", ^(sqlite3_stmt *stmt) {
689                sqlite3_bind_int64(stmt, 1, rule_get_id(rule));
690                sqlite3_bind_text(stmt, 2, lang, -1, NULL);
691                sqlite3_bind_text(stmt, 3, str, -1, NULL);
692            }, NULL);
693
694            free_safe(lang);
695            free_safe(str);
696
697            return true;
698        });
699    }
700
701    if (rule->loc_buttons) {
702        _cf_dictionary_iterate(rule->loc_buttons, ^bool(CFTypeRef key, CFTypeRef value) {
703            char * lang = _copy_cf_string(key, NULL);
704            char * str = _copy_cf_string(value, NULL);
705
706            authdb_step(dbconn, "INSERT INTO buttons VALUES (?,?,?)", ^(sqlite3_stmt *stmt) {
707                sqlite3_bind_int64(stmt, 1, rule_get_id(rule));
708                sqlite3_bind_text(stmt, 2, lang, -1, NULL);
709                sqlite3_bind_text(stmt, 3, str, -1, NULL);
710            }, NULL);
711
712            free_safe(lang);
713            free_safe(str);
714            return true;
715        });
716    }
717
718}
719
720bool
721rule_sql_commit(rule_t rule, authdb_connection_t dbconn, CFAbsoluteTime modified, process_t proc)
722{
723    bool result = false;
724    // type and class required else rule is name only?
725    RuleClass rule_class = rule_get_class(rule);
726    require(rule_get_type(rule) != 0, done);
727    require(rule_class != 0, done);
728
729    CFIndex mechCount = 0;
730    if (rule_class == RC_USER || rule_class == RC_MECHANISM) {
731        // Validate mechanisms
732        mechCount = CFArrayGetCount(rule->mechanisms);
733        for (CFIndex i = 0; i < mechCount; i++) {
734            mechanism_t mech = (mechanism_t)CFArrayGetValueAtIndex(rule->mechanisms, i);
735            if (mechanism_get_id(mech) == 0) {
736                if (!mechanism_sql_fetch(mech, dbconn)) {
737                    mechanism_sql_commit(mech, dbconn);
738                    mechanism_sql_fetch(mech, dbconn);
739                }
740            }
741            if (!mechanism_exists(mech)) {
742                LOGE("Warning mechanism not found on disk %s during import of %s", mechanism_get_string(mech), rule_get_name(rule));
743            }
744            require_action(mechanism_get_id(mech) != 0, done, LOGE("rule: commit, invalid mechanism %s:%s for %s", mechanism_get_plugin(mech), mechanism_get_param(mech), rule_get_name(rule)));
745        }
746    }
747
748    CFIndex delegateCount = 0;
749    if (rule_class == RC_RULE) {
750        // Validate delegates
751        delegateCount = CFArrayGetCount(rule->delegations);
752        for (CFIndex i = 0; i < delegateCount; i++) {
753            rule_t delegate = (rule_t)CFArrayGetValueAtIndex(rule->delegations, i);
754            if (rule_get_id(delegate) == 0) {
755                rule_sql_fetch(delegate, dbconn);
756            }
757            require_action(rule_get_id(delegate) != 0, done, LOGE("rule: commit, missing delegate %s for %s", rule_get_name(delegate), rule_get_name(rule)));
758        }
759    }
760
761    auth_items_set_double(rule->data, RULE_MODIFIED, modified);
762
763    result = authdb_transaction(dbconn, AuthDBTransactionNormal, ^bool{
764        bool update = false;
765
766        if (rule_get_id(rule)) {
767            update = _sql_update(rule, dbconn);
768        } else {
769            if (proc) {
770                const char * ident = process_get_identifier(proc);
771                if (ident) {
772                    auth_items_set_string(rule->data, RULE_IDENTIFIER, ident);
773                }
774                CFDataRef req = process_get_requirement_data(proc);
775                if (req) {
776                    auth_items_set_data(rule->data, RULE_REQUIREMENT, CFDataGetBytePtr(req), (size_t)CFDataGetLength(req));
777                }
778            }
779            auth_items_set_double(rule->data, RULE_CREATED, modified);
780            update = _sql_insert(rule, dbconn);
781            _sql_get_id(rule, dbconn);
782        }
783
784        _sql_commit_localization(rule, dbconn);
785
786        if (update) {
787            update = _sql_commit_mechanisms_map(rule, dbconn);
788        }
789
790        if (update) {
791            update = _sql_commit_delegates_map(rule,dbconn);
792        }
793
794        return update;
795    });
796
797
798done:
799    if (!result) {
800        LOGV("rule: commit, failed for %s (%llu)", rule_get_name(rule), rule_get_id(rule));
801    }
802    return result;
803}
804
805bool
806rule_sql_remove(rule_t rule, authdb_connection_t dbconn)
807{
808    bool result = false;
809    int64_t id = rule_get_id(rule);
810
811    if (id == 0) {
812        rule_sql_fetch(rule, dbconn);
813        id = rule_get_id(rule);
814        require(id != 0, done);
815    }
816
817    result = authdb_step(dbconn, "DELETE FROM rules WHERE id = ?",
818                         ^(sqlite3_stmt *stmt) {
819                             sqlite3_bind_int64(stmt, 1, id);
820                         }, NULL);
821done:
822    return result;
823}
824
825CFMutableDictionaryRef
826rule_copy_to_cfobject(rule_t rule, authdb_connection_t dbconn) {
827    CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
828
829    CFTypeRef tmp = NULL;
830    CFMutableArrayRef array = NULL;
831    CFIndex count = 0;
832    CFIndex i = 0;
833    int64_t n;
834    double d;
835
836    const char * comment = rule_get_comment(rule);
837    if (comment) {
838        tmp = CFStringCreateWithCString(kCFAllocatorDefault, comment, kCFStringEncodingUTF8);
839        CFDictionarySetValue(dict, CFSTR(kAuthorizationComment), tmp);
840        CFReleaseSafe(tmp);
841    }
842
843    n = rule_get_version(rule);
844    tmp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &n);
845    CFDictionarySetValue(dict, CFSTR(RULE_VERSION), tmp);
846    CFReleaseSafe(tmp);
847
848    d = rule_get_created(rule);
849    tmp = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloat64Type, &d);
850    CFDictionarySetValue(dict, CFSTR(RULE_CREATED), tmp);
851    CFReleaseSafe(tmp);
852
853    d = rule_get_modified(rule);
854    tmp = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloat64Type, &d);
855    CFDictionarySetValue(dict, CFSTR(RULE_MODIFIED), tmp);
856    CFReleaseSafe(tmp);
857
858    const char * identifier = rule_get_identifier(rule);
859    if (identifier) {
860        tmp = CFStringCreateWithCString(kCFAllocatorDefault, identifier, kCFStringEncodingUTF8);
861        CFDictionarySetValue(dict, CFSTR(RULE_IDENTIFIER), tmp);
862        CFReleaseSafe(tmp);
863    }
864
865    SecRequirementRef req = rule_get_requirment(rule);
866    if (req) {
867        CFStringRef reqStr = NULL;
868        SecRequirementCopyString(req, kSecCSDefaultFlags, &reqStr);
869        if (reqStr) {
870            CFDictionarySetValue(dict, CFSTR(RULE_REQUIREMENT), reqStr);
871            CFReleaseSafe(reqStr);
872        }
873    }
874
875    if (rule_check_flags(rule, RuleFlagEntitled)) {
876        CFDictionarySetValue(dict, CFSTR(kAuthorizationRuleParameterEntitled), kCFBooleanTrue);
877    }
878
879    if (rule_check_flags(rule, RuleFlagRequireAppleSigned)) {
880        CFDictionarySetValue(dict, CFSTR(kAuthorizationRuleParameterRequireAppleSigned), kCFBooleanTrue);
881    }
882
883    if (rule_get_type(rule) == RT_RIGHT) {
884        CFMutableDictionaryRef prompts = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
885        authdb_step(dbconn, "SELECT * FROM prompts WHERE r_id = ?", ^(sqlite3_stmt *stmt) {
886            sqlite3_bind_int64(stmt, 1, rule_get_id(rule));
887        }, ^bool(auth_items_t data) {
888            CFStringRef key = CFStringCreateWithCString(kCFAllocatorDefault, auth_items_get_string(data, "lang"), kCFStringEncodingUTF8);
889            CFStringRef value = CFStringCreateWithCString(kCFAllocatorDefault, auth_items_get_string(data, "value"), kCFStringEncodingUTF8);
890            CFDictionaryAddValue(prompts, key, value);
891            CFReleaseSafe(key);
892            CFReleaseSafe(value);
893            return true;
894        });
895
896        if (CFDictionaryGetCount(prompts)) {
897            CFDictionaryAddValue(dict, CFSTR(kAuthorizationRuleParameterDefaultPrompt), prompts);
898        }
899        CFReleaseSafe(prompts);
900
901        CFMutableDictionaryRef buttons = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
902        authdb_step(dbconn, "SELECT * FROM buttons WHERE r_id = ?", ^(sqlite3_stmt *stmt) {
903            sqlite3_bind_int64(stmt, 1, rule_get_id(rule));
904        }, ^bool(auth_items_t data) {
905            CFStringRef key = CFStringCreateWithCString(kCFAllocatorDefault, auth_items_get_string(data, "lang"), kCFStringEncodingUTF8);
906            CFStringRef value = CFStringCreateWithCString(kCFAllocatorDefault, auth_items_get_string(data, "value"), kCFStringEncodingUTF8);
907            CFDictionaryAddValue(buttons, key, value);
908            CFReleaseSafe(key);
909            CFReleaseSafe(value);
910            return true;
911        });
912
913        if (CFDictionaryGetCount(buttons)) {
914            CFDictionaryAddValue(dict, CFSTR(kAuthorizationRuleParameterDefaultButton), buttons);
915        }
916        CFReleaseSafe(buttons);
917    }
918
919    switch (rule_get_class(rule)) {
920        case RC_USER:
921            CFDictionarySetValue(dict, CFSTR(kAuthorizationRuleClass), CFSTR(kAuthorizationRuleClassUser));
922
923            const char * group = rule_get_group(rule);
924            if (group) {
925                tmp = CFStringCreateWithCString(kCFAllocatorDefault, group, kCFStringEncodingUTF8);
926                CFDictionarySetValue(dict, CFSTR(kAuthorizationRuleParameterGroup), tmp);
927                CFReleaseSafe(tmp);
928            }
929
930            n = rule_get_timeout(rule);
931            tmp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &n);
932            CFDictionarySetValue(dict, CFSTR(kAuthorizationRuleParameterCredentialTimeout), tmp);
933            CFReleaseSafe(tmp);
934
935            n = rule_get_tries(rule);
936            tmp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &n);
937            CFDictionarySetValue(dict, CFSTR("tries"), tmp);
938            CFReleaseSafe(tmp);
939
940            CFDictionarySetValue(dict, CFSTR(kAuthorizationRuleParameterCredentialShared), rule_get_shared(rule) ? kCFBooleanTrue : kCFBooleanFalse);
941            CFDictionarySetValue(dict, CFSTR(kAuthorizationRuleParameterAllowRoot), rule_get_allow_root(rule) ? kCFBooleanTrue : kCFBooleanFalse);
942            CFDictionarySetValue(dict, CFSTR(kAuthorizationRuleParameterCredentialSessionOwner), rule_get_session_owner(rule) ? kCFBooleanTrue : kCFBooleanFalse);
943            CFDictionarySetValue(dict, CFSTR(kAuthorizationRuleParameterAuthenticateUser), rule_get_authenticate_user(rule) ? kCFBooleanTrue : kCFBooleanFalse);
944            if (rule_check_flags(rule, RuleFlagEntitledAndGroup)) {
945                CFDictionarySetValue(dict, CFSTR(kAuthorizationRuleParameterEntitledAndGroup), kCFBooleanTrue);
946            }
947            if (rule_check_flags(rule, RuleFlagVPNEntitledAndGroup)) {
948                CFDictionarySetValue(dict, CFSTR(kAuthorizationRuleParameterVPNEntitledAndGroup), kCFBooleanTrue);
949            }
950            if (rule_get_extract_password(rule)) {
951                CFDictionarySetValue(dict, CFSTR(kAuthorizationRuleParameterExtractPassword), kCFBooleanTrue);
952            }
953
954            count = CFArrayGetCount(rule->mechanisms);
955            if (count) {
956                array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
957                for (i = 0; i < count; i++) {
958                    mechanism_t mech = (mechanism_t)CFArrayGetValueAtIndex(rule->mechanisms, i);
959                    tmp = CFStringCreateWithCString(kCFAllocatorDefault, mechanism_get_string(mech), kCFStringEncodingUTF8);
960                    CFArrayAppendValue(array, tmp);
961                    CFReleaseSafe(tmp);
962                }
963                CFDictionaryAddValue(dict, CFSTR(kAuthorizationRuleParameterMechanisms), array);
964                CFRelease(array);
965            }
966            break;
967        case RC_RULE:
968            CFDictionarySetValue(dict, CFSTR(kAuthorizationRuleClass), CFSTR(kAuthorizationRightRule));
969            int64_t kofn = rule_get_kofn(rule);
970            if (kofn) {
971                tmp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &kofn);
972                CFDictionarySetValue(dict, CFSTR(kAuthorizationRuleParameterKofN), tmp);
973                CFReleaseSafe(tmp);
974            }
975
976            count = CFArrayGetCount(rule->delegations);
977            if (count) {
978                array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
979                for (i = 0; i < count; i++) {
980                    rule_t delegate = (rule_t)CFArrayGetValueAtIndex(rule->delegations, i);
981                    tmp = CFStringCreateWithCString(kCFAllocatorDefault, rule_get_name(delegate), kCFStringEncodingUTF8);
982                    CFArrayAppendValue(array, tmp);
983                    CFReleaseSafe(tmp);
984                }
985                CFDictionaryAddValue(dict, CFSTR(kAuthorizationRightRule), array);
986                CFRelease(array);
987            }
988            break;
989        case RC_MECHANISM:
990            CFDictionarySetValue(dict, CFSTR(kAuthorizationRuleClass), CFSTR(kAuthorizationRuleClassMechanisms));
991
992            CFDictionarySetValue(dict, CFSTR(kAuthorizationRuleParameterCredentialShared), rule_get_shared(rule) ? kCFBooleanTrue : kCFBooleanFalse);
993            if (rule_get_extract_password(rule)) {
994                CFDictionarySetValue(dict, CFSTR(kAuthorizationRuleParameterExtractPassword), kCFBooleanTrue);
995            }
996
997            n = rule_get_tries(rule);
998            tmp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &n);
999            CFDictionarySetValue(dict, CFSTR("tries"), tmp);
1000            CFReleaseSafe(tmp);
1001
1002            count = CFArrayGetCount(rule->mechanisms);
1003            if (count) {
1004                array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
1005                for (i = 0; i < count; i++) {
1006                    mechanism_t mech = (mechanism_t)CFArrayGetValueAtIndex(rule->mechanisms, i);
1007                    tmp = CFStringCreateWithCString(kCFAllocatorDefault, mechanism_get_string(mech), kCFStringEncodingUTF8);
1008                    CFArrayAppendValue(array, tmp);
1009                    CFReleaseSafe(tmp);
1010                }
1011                CFDictionaryAddValue(dict, CFSTR(kAuthorizationRuleParameterMechanisms), array);
1012                CFRelease(array);
1013            }
1014            break;
1015        case RC_DENY:
1016            CFDictionarySetValue(dict, CFSTR(kAuthorizationRuleClass), CFSTR(kAuthorizationRuleClassDeny));
1017            break;
1018        case RC_ALLOW:
1019            CFDictionarySetValue(dict, CFSTR(kAuthorizationRuleClass), CFSTR(kAuthorizationRuleClassAllow));
1020            break;
1021        default:
1022            break;
1023    }
1024
1025    return dict;
1026}
1027
1028
1029CFArrayRef
1030rule_get_mechanisms(rule_t rule)
1031{
1032    return rule->mechanisms;
1033}
1034
1035size_t
1036rule_get_mechanisms_count(rule_t rule)
1037{
1038    return (size_t)CFArrayGetCount(rule->mechanisms);
1039}
1040
1041bool
1042rule_mechanisms_iterator(rule_t rule, mechanism_iterator_t iter)
1043{
1044    bool result = false;
1045
1046    CFIndex count = CFArrayGetCount(rule->mechanisms);
1047    for (CFIndex i = 0; i < count; i++) {
1048        mechanism_t mech = (mechanism_t)CFArrayGetValueAtIndex(rule->mechanisms, i);
1049        result = iter(mech);
1050        if (!result) {
1051            break;
1052        }
1053    }
1054
1055    return result;
1056}
1057
1058size_t
1059rule_get_delegates_count(rule_t rule)
1060{
1061    return (size_t)CFArrayGetCount(rule->delegations);
1062}
1063
1064bool
1065rule_delegates_iterator(rule_t rule, delegate_iterator_t iter)
1066{
1067    bool result = false;
1068
1069    CFIndex count = CFArrayGetCount(rule->delegations);
1070    for (CFIndex i = 0; i < count; i++) {
1071        rule_t tmp = (rule_t)CFArrayGetValueAtIndex(rule->delegations, i);
1072        result = iter(tmp);
1073        if (!result) {
1074            break;
1075        }
1076    }
1077
1078    return result;
1079}
1080
1081int64_t
1082rule_get_id(rule_t rule)
1083{
1084    return auth_items_get_int64(rule->data, RULE_ID);
1085}
1086
1087const char *
1088rule_get_name(rule_t rule)
1089{
1090    return auth_items_get_string(rule->data, RULE_NAME);
1091}
1092
1093RuleType
1094rule_get_type(rule_t rule)
1095{
1096    return (RuleType)auth_items_get_int64(rule->data, RULE_TYPE);
1097}
1098
1099RuleClass
1100rule_get_class(rule_t rule)
1101{
1102    return (RuleClass)auth_items_get_int64(rule->data, RULE_CLASS);
1103}
1104
1105const char *
1106rule_get_group(rule_t rule)
1107{
1108    return auth_items_get_string(rule->data, RULE_GROUP);
1109}
1110
1111int64_t
1112rule_get_kofn(rule_t rule)
1113{
1114    return auth_items_get_int64(rule->data, RULE_KOFN);
1115}
1116
1117int64_t
1118rule_get_timeout(rule_t rule)
1119{
1120    return auth_items_get_int64(rule->data, RULE_TIMEOUT);
1121}
1122
1123bool
1124rule_check_flags(rule_t rule, RuleFlags flags)
1125{
1126    return (auth_items_get_int64(rule->data, RULE_FLAGS) & flags) != 0;
1127}
1128
1129bool
1130rule_get_shared(rule_t rule)
1131{
1132    return rule_check_flags(rule, RuleFlagShared);
1133}
1134
1135bool
1136rule_get_allow_root(rule_t rule)
1137{
1138    return rule_check_flags(rule, RuleFlagAllowRoot);
1139}
1140
1141bool
1142rule_get_session_owner(rule_t rule)
1143{
1144    return rule_check_flags(rule, RuleFlagSessionOwner);
1145}
1146
1147bool
1148rule_get_authenticate_user(rule_t rule)
1149{
1150    return rule_check_flags(rule, RuleFlagAuthenticateUser);
1151}
1152
1153bool
1154rule_get_extract_password(rule_t rule)
1155{
1156    return rule_check_flags(rule, RuleFlagExtractPassword);
1157}
1158
1159int64_t
1160rule_get_tries(rule_t rule)
1161{
1162    return auth_items_get_int64(rule->data, RULE_TRIES);
1163}
1164
1165const char *
1166rule_get_comment(rule_t rule)
1167{
1168    return auth_items_get_string(rule->data, RULE_COMMENT);
1169}
1170
1171int64_t
1172rule_get_version(rule_t rule)
1173{
1174    return auth_items_get_int64(rule->data, RULE_VERSION);
1175}
1176
1177double rule_get_created(rule_t rule)
1178{
1179    return auth_items_get_double(rule->data, RULE_CREATED);
1180}
1181
1182double rule_get_modified(rule_t rule)
1183{
1184    return auth_items_get_double(rule->data, RULE_MODIFIED);
1185}
1186
1187const char * rule_get_identifier(rule_t rule)
1188{
1189    return auth_items_get_string(rule->data, RULE_IDENTIFIER);
1190}
1191
1192CFDataRef rule_get_requirment_data(rule_t rule)
1193{
1194    if (!rule->requirement_data && auth_items_exist(rule->data, RULE_REQUIREMENT)) {
1195        size_t len;
1196        const void * data = auth_items_get_data(rule->data, RULE_REQUIREMENT, &len);
1197        rule->requirement_data = CFDataCreate(kCFAllocatorDefault, data, (CFIndex)len);
1198    }
1199
1200    return rule->requirement_data;
1201}
1202
1203SecRequirementRef rule_get_requirment(rule_t rule)
1204{
1205    if (!rule->requirement) {
1206        CFDataRef data = rule_get_requirment_data(rule);
1207        if (data) {
1208            SecRequirementCreateWithData(data, kSecCSDefaultFlags, &rule->requirement);
1209        }
1210    }
1211
1212    return rule->requirement;
1213}
1214