1/* Copyright (c) 2012 Apple Inc. All rights reserved. */
2
3#include "Authorization.h"
4#include "authd_private.h"
5#include "authutilities.h"
6#include "debugging.h"
7
8#include <Security/AuthorizationPriv.h>
9#include <Security/AuthorizationDB.h>
10#include <Security/AuthorizationTags.h>
11#include <Security/AuthorizationTagsPriv.h>
12#include <xpc/xpc.h>
13#include <xpc/private.h>
14#include <mach/mach.h>
15#include <syslog.h>
16#include <AssertMacros.h>
17#include <CoreFoundation/CFXPCBridge.h>
18
19static dispatch_queue_t
20get_authorization_dispatch_queue()
21{
22    static dispatch_once_t onceToken = 0;
23    static dispatch_queue_t connection_queue = NULL;
24
25    dispatch_once(&onceToken, ^{
26        connection_queue = dispatch_queue_create("authorization-connection-queue", DISPATCH_QUEUE_SERIAL);
27    });
28
29    return connection_queue;
30}
31
32static xpc_connection_t
33get_authorization_connection()
34{
35    static xpc_connection_t connection = NULL;
36
37    dispatch_sync(get_authorization_dispatch_queue(), ^{
38        if (connection == NULL) {
39            connection = xpc_connection_create(SECURITY_AUTH_NAME, NULL);
40
41            if (!connection) {
42                syslog(LOG_ERR, "Authorization, failed to create xpc connection to %s", SECURITY_AUTH_NAME);
43                connection = xpc_connection_create(SECURITY_AUTH_NAME, NULL);
44            }
45
46            xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {
47                if (xpc_get_type(event) == XPC_TYPE_ERROR) {
48                    if (event == XPC_ERROR_CONNECTION_INVALID) {
49                        syslog(LOG_ERR, "Authorization, server not available");
50                    }
51                    // XPC_ERROR_CONNECTION_INTERRUPTED
52                    // XPC_ERROR_TERMINATION_IMMINENT
53                } else {
54                    char * desc = xpc_copy_description(event);
55                    syslog(LOG_ERR, "Authorization, we should never get messages on this connection: %s", desc);
56                    free(desc);
57                }
58            });
59
60            xpc_connection_resume(connection);
61
62            // Send
63            xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
64            xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_SETUP);
65            mach_port_t bootstrap = MACH_PORT_NULL;
66            task_get_bootstrap_port(mach_task_self(), &bootstrap);
67            xpc_dictionary_set_mach_send(message, AUTH_XPC_BOOTSTRAP, bootstrap);
68            xpc_object_t reply = xpc_connection_send_message_with_reply_sync(connection, message);
69            xpc_release_safe(message);
70            xpc_release_safe(reply);
71        }
72    });
73
74    return connection;
75}
76
77static void
78setItemSet(xpc_object_t message, const char * key, const AuthorizationItemSet * itemSet)
79{
80    xpc_object_t serialized = SerializeItemSet(itemSet);
81    if (serialized) {
82        xpc_dictionary_set_value(message, key, serialized);
83        xpc_release(serialized);
84    }
85}
86
87OSStatus AuthorizationCreate(const AuthorizationRights *rights,
88                    const AuthorizationEnvironment *environment,
89                    AuthorizationFlags flags,
90                    AuthorizationRef *authorization)
91{
92    OSStatus status = errAuthorizationInternal;
93    xpc_object_t message = NULL;
94    xpc_object_t reply = NULL;
95
96//    require_action(!(rights == NULL && authorization == NULL), done, status = errAuthorizationInvalidSet);
97
98    // Send
99    message = xpc_dictionary_create(NULL, NULL, 0);
100    require_action(message != NULL, done, status = errAuthorizationInternal);
101
102    xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_CREATE);
103    setItemSet(message, AUTH_XPC_RIGHTS, rights);
104    setItemSet(message, AUTH_XPC_ENVIROMENT, environment);
105    xpc_dictionary_set_uint64(message, AUTH_XPC_FLAGS, flags | (authorization ? 0 : kAuthorizationFlagNoData));
106
107    // Reply
108    reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message);
109    require_action(reply != NULL, done, status = errAuthorizationInternal);
110    require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
111
112    // Status
113    status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
114
115    // Out
116    if (authorization && status == errAuthorizationSuccess) {
117        size_t len;
118        const void * data = xpc_dictionary_get_data(reply, AUTH_XPC_BLOB, &len);
119        require_action(data != NULL, done, status = errAuthorizationInternal);
120        assert(len == sizeof(AuthorizationBlob));
121
122        AuthorizationBlob * blob = (AuthorizationBlob*)calloc(1u, sizeof(AuthorizationBlob));
123        require_action(blob != NULL, done, status = errAuthorizationInternal);
124        *blob = *(AuthorizationBlob*)data;
125
126        *authorization = (AuthorizationRef)blob;
127    }
128
129done:
130    xpc_release_safe(message);
131    xpc_release_safe(reply);
132    return status;
133}
134
135OSStatus AuthorizationCreateWithAuditToken(audit_token_t token,
136                                 const AuthorizationEnvironment *environment,
137                                 AuthorizationFlags flags,
138                                 AuthorizationRef *authorization)
139{
140    OSStatus status = errAuthorizationInternal;
141    xpc_object_t message = NULL;
142    xpc_object_t reply = NULL;
143
144    require_action(authorization != NULL, done, status = errAuthorizationInvalidPointer);
145
146    // Send
147    message = xpc_dictionary_create(NULL, NULL, 0);
148    require_action(message != NULL, done, status = errAuthorizationInternal);
149
150    xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_CREATE_WITH_AUDIT_TOKEN);
151    xpc_dictionary_set_data(message, AUTH_XPC_DATA, &token, sizeof(token));
152    setItemSet(message, AUTH_XPC_ENVIROMENT, environment);
153    xpc_dictionary_set_uint64(message, AUTH_XPC_FLAGS, flags);
154
155    // Reply
156    reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message);
157    require_action(reply != NULL, done, status = errAuthorizationInternal);
158    require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
159
160    // Status
161    status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
162
163    // Out
164    if (status == errAuthorizationSuccess) {
165        size_t len;
166        const void * data = xpc_dictionary_get_data(reply, AUTH_XPC_BLOB, &len);
167        require_action(data != NULL, done, status = errAuthorizationInternal);
168        assert(len == sizeof(AuthorizationBlob));
169
170        AuthorizationBlob * blob = (AuthorizationBlob*)calloc(1u, sizeof(AuthorizationBlob));
171        require_action(blob != NULL, done, status = errAuthorizationInternal);
172        *blob = *(AuthorizationBlob*)data;
173
174        *authorization = (AuthorizationRef)blob;
175    }
176
177done:
178    xpc_release_safe(message);
179    xpc_release_safe(reply);
180    return status;
181}
182
183OSStatus AuthorizationFree(AuthorizationRef authorization, AuthorizationFlags flags)
184{
185    OSStatus status = errAuthorizationInternal;
186    xpc_object_t message = NULL;
187    xpc_object_t reply = NULL;
188    AuthorizationBlob *blob = NULL;
189
190    require_action(authorization != NULL, done, status = errAuthorizationInvalidRef);
191    blob = (AuthorizationBlob *)authorization;
192
193    // Send
194    message = xpc_dictionary_create(NULL, NULL, 0);
195    require_action(message != NULL, done, status = errAuthorizationInternal);
196
197    xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_FREE);
198    xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
199    xpc_dictionary_set_uint64(message, AUTH_XPC_FLAGS, flags);
200
201    // Reply
202    reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message);
203    require_action(reply != NULL, done, status = errAuthorizationInternal);
204    require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
205
206    // Status
207    status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
208
209    // Free
210    free(blob);
211
212done:
213    xpc_release_safe(message);
214    xpc_release_safe(reply);
215    return status;
216}
217
218static OSStatus
219_AuthorizationCopyRights_send_message(xpc_object_t message, AuthorizationRights **authorizedRights)
220{
221    OSStatus status = errAuthorizationInternal;
222    xpc_object_t reply = NULL;
223
224    // Send
225    require_action(message != NULL, done, status = errAuthorizationInternal);
226
227    // Reply
228    reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message);
229    require_action(reply != NULL, done, status = errAuthorizationInternal);
230    require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
231
232    // Status
233    status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
234
235    // Out
236    if (authorizedRights && status == errAuthorizationSuccess) {
237        xpc_object_t tmpItems = xpc_dictionary_get_value(reply, AUTH_XPC_OUT_ITEMS);
238        AuthorizationRights * grantedRights = DeserializeItemSet(tmpItems);
239        require_action(grantedRights != NULL, done, status = errAuthorizationInternal);
240
241        *authorizedRights = grantedRights;
242    }
243
244done:
245    xpc_release_safe(reply);
246    return status;
247}
248
249static OSStatus
250_AuthorizationCopyRights_prepare_message(AuthorizationRef authorization, const AuthorizationRights *rights, const AuthorizationEnvironment *environment, AuthorizationFlags flags, xpc_object_t *message_out)
251{
252    OSStatus status = errAuthorizationInternal;
253    AuthorizationBlob *blob = NULL;
254    xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
255    require_action(message != NULL, done, status = errAuthorizationInternal);
256
257    require_action(authorization != NULL, done, status = errAuthorizationInvalidRef);
258    blob = (AuthorizationBlob *)authorization;
259
260    xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_COPY_RIGHTS);
261    xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
262    setItemSet(message, AUTH_XPC_RIGHTS, rights);
263    setItemSet(message, AUTH_XPC_ENVIROMENT, environment);
264    xpc_dictionary_set_uint64(message, AUTH_XPC_FLAGS, flags);
265
266    *message_out = message;
267    message = NULL;
268    status = errAuthorizationSuccess;
269
270done:
271    xpc_release_safe(message);
272    return status;
273}
274
275OSStatus AuthorizationCopyRights(AuthorizationRef authorization,
276                        const AuthorizationRights *rights,
277                        const AuthorizationEnvironment *environment,
278                        AuthorizationFlags flags,
279                        AuthorizationRights **authorizedRights)
280{
281    OSStatus status = errAuthorizationInternal;
282    xpc_object_t message = NULL;
283
284    require_noerr(status = _AuthorizationCopyRights_prepare_message(authorization, rights, environment, flags, &message), done);
285    require_noerr(status = _AuthorizationCopyRights_send_message(message, authorizedRights), done);
286
287done:
288    xpc_release_safe(message);
289    return status;
290}
291
292
293void AuthorizationCopyRightsAsync(AuthorizationRef authorization,
294                         const AuthorizationRights *rights,
295                         const AuthorizationEnvironment *environment,
296                         AuthorizationFlags flags,
297                         AuthorizationAsyncCallback callbackBlock)
298{
299    OSStatus prepare_status = errAuthorizationInternal;
300    __block xpc_object_t message = NULL;
301
302    prepare_status = _AuthorizationCopyRights_prepare_message(authorization, rights, environment, flags, &message);
303    if (prepare_status != errAuthorizationSuccess) {
304        callbackBlock(prepare_status, NULL);
305    }
306
307    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
308		AuthorizationRights *blockAuthorizedRights = NULL;
309        OSStatus status = _AuthorizationCopyRights_send_message(message, &blockAuthorizedRights);
310        callbackBlock(status, blockAuthorizedRights);
311        xpc_release_safe(message);
312	});
313}
314
315OSStatus AuthorizationDismiss()
316{
317    OSStatus status = errAuthorizationInternal;
318    xpc_object_t message = NULL;
319    xpc_object_t reply = NULL;
320
321    // Send
322    message = xpc_dictionary_create(NULL, NULL, 0);
323    require(message != NULL, done);
324
325    xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_DISMISS);
326
327    // Reply
328    reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message);
329    require_action(reply != NULL, done, status = errAuthorizationInternal);
330    require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
331
332    // Status
333    status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
334
335done:
336    xpc_release_safe(message);
337    xpc_release_safe(reply);
338    return status;
339}
340
341OSStatus AuthorizationCopyInfo(AuthorizationRef authorization,
342                      AuthorizationString tag,
343                      AuthorizationItemSet **info)
344{
345    OSStatus status = errAuthorizationInternal;
346    xpc_object_t message = NULL;
347    xpc_object_t reply = NULL;
348    AuthorizationBlob *blob = NULL;
349
350    require_action(info != NULL, done, status = errAuthorizationInvalidSet);
351    require_action(authorization != NULL, done, status = errAuthorizationInvalidRef);
352    blob = (AuthorizationBlob *)authorization;
353
354    // Send
355    message = xpc_dictionary_create(NULL, NULL, 0);
356    require_action(message != NULL, done, status = errAuthorizationInternal);
357
358    xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_COPY_INFO);
359    xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
360    if (tag) {
361        xpc_dictionary_set_string(message, AUTH_XPC_TAG, tag);
362    }
363
364    // Reply
365    reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message);
366    require_action(reply != NULL, done, status = errAuthorizationInternal);
367    require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
368
369    // Status
370    status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
371
372    // Out
373    if (info && status == errAuthorizationSuccess) {
374        xpc_object_t tmpItems = xpc_dictionary_get_value(reply, AUTH_XPC_OUT_ITEMS);
375        AuthorizationRights * outInfo = DeserializeItemSet(tmpItems);
376        require_action(outInfo != NULL, done, status = errAuthorizationInternal);
377
378        *info = outInfo;
379    }
380
381done:
382    xpc_release_safe(message);
383    xpc_release_safe(reply);
384    return status;
385}
386
387OSStatus AuthorizationMakeExternalForm(AuthorizationRef authorization,
388                              AuthorizationExternalForm *extForm)
389{
390    OSStatus status = errAuthorizationInternal;
391    xpc_object_t message = NULL;
392    xpc_object_t reply = NULL;
393    AuthorizationBlob *blob = NULL;
394
395    require_action(extForm != NULL, done, status = errAuthorizationInvalidPointer);
396    require_action(authorization != NULL, done, status = errAuthorizationInvalidRef);
397    blob = (AuthorizationBlob *)authorization;
398
399    // Send
400    message = xpc_dictionary_create(NULL, NULL, 0);
401    require_action(message != NULL, done, status = errAuthorizationInternal);
402
403    xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_MAKE_EXTERNAL_FORM);
404    xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
405
406    // Reply
407    reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message);
408    require_action(reply != NULL, done, status = errAuthorizationInternal);
409    require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
410
411    // Status
412    status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
413
414    // out
415    if (status == errAuthorizationSuccess) {
416        size_t len;
417        const void * data = xpc_dictionary_get_data(reply, AUTH_XPC_EXTERNAL, &len);
418        require_action(data != NULL, done, status = errAuthorizationInternal);
419        assert(len == sizeof(AuthorizationExternalForm));
420
421        *extForm = *(AuthorizationExternalForm*)data;
422    }
423
424done:
425    xpc_release_safe(message);
426    xpc_release_safe(reply);
427    return status;
428}
429
430OSStatus AuthorizationCreateFromExternalForm(const AuthorizationExternalForm *extForm,
431                                    AuthorizationRef *authorization)
432{
433    OSStatus status = errAuthorizationInternal;
434    xpc_object_t message = NULL;
435    xpc_object_t reply = NULL;
436
437    require_action(extForm != NULL, done, status = errAuthorizationInvalidPointer);
438    require_action(authorization != NULL, done, status = errAuthorizationInvalidRef);
439
440    // Send
441    message = xpc_dictionary_create(NULL, NULL, 0);
442    require_action(message != NULL, done, status = errAuthorizationInternal);
443
444    xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_CREATE_FROM_EXTERNAL_FORM);
445    xpc_dictionary_set_data(message, AUTH_XPC_EXTERNAL, extForm, sizeof(AuthorizationExternalForm));
446
447    // Reply
448    reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message);
449    require_action(reply != NULL, done, status = errAuthorizationInternal);
450    require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
451
452    // Status
453    status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
454
455    // Out
456    if (authorization && status == errAuthorizationSuccess) {
457        size_t len;
458        const void * data = xpc_dictionary_get_data(reply, AUTH_XPC_BLOB, &len);
459        require_action(data != NULL, done, status = errAuthorizationInternal);
460        assert(len == sizeof(AuthorizationBlob));
461
462        AuthorizationBlob * blob = (AuthorizationBlob*)calloc(1u, sizeof(AuthorizationBlob));
463        require_action(blob != NULL, done, status = errAuthorizationInternal);
464        *blob = *(AuthorizationBlob*)data;
465
466        *authorization = (AuthorizationRef)blob;
467    }
468
469done:
470    xpc_release_safe(message);
471    xpc_release_safe(reply);
472    return status;
473}
474
475OSStatus AuthorizationFreeItemSet(AuthorizationItemSet *set)
476{
477    FreeItemSet(set);
478    return errAuthorizationSuccess;
479}
480
481OSStatus AuthorizationEnableSmartCard(AuthorizationRef authRef, Boolean enable)
482{
483    OSStatus status = errAuthorizationInternal;
484    xpc_object_t message = NULL;
485    xpc_object_t reply = NULL;
486    AuthorizationBlob *blob = NULL;
487
488    // Send
489    message = xpc_dictionary_create(NULL, NULL, 0);
490    require_action(message != NULL, done, status = errAuthorizationInternal);
491    require_action(authRef != NULL, done, status = errAuthorizationInvalidRef);
492    blob = (AuthorizationBlob *)authRef;
493    xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_ENABLE_SMARTCARD);
494    xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
495    xpc_dictionary_set_bool(message, AUTH_XPC_DATA, enable);
496
497    // Reply
498    reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message);
499    require_action(reply != NULL, done, status = errAuthorizationInternal);
500    require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
501
502    status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
503
504done:
505    xpc_release_safe(message);
506    xpc_release_safe(reply);
507    return status;
508}
509
510
511OSStatus AuthorizationRightGet(const char *rightName,
512                      CFDictionaryRef *rightDefinition)
513{
514    OSStatus status = errAuthorizationInternal;
515    xpc_object_t message = NULL;
516    xpc_object_t reply = NULL;
517
518    require_action(rightName != NULL, done, status = errAuthorizationInvalidPointer);
519
520    // Send
521    message = xpc_dictionary_create(NULL, NULL, 0);
522    require_action(message != NULL, done, status = errAuthorizationInternal);
523
524    xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_RIGHT_GET);
525    xpc_dictionary_set_string(message, AUTH_XPC_RIGHT_NAME, rightName);
526
527    // Reply
528    reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message);
529    require_action(reply != NULL, done, status = errAuthorizationInternal);
530    require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
531
532    // Status
533    status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
534
535    // Out
536    if (rightDefinition && status == errAuthorizationSuccess) {
537        xpc_object_t value = xpc_dictionary_get_value(reply, AUTH_XPC_DATA);
538        require_action(value != NULL, done, status = errAuthorizationInternal);
539        require_action(xpc_get_type(value) == XPC_TYPE_DICTIONARY, done, status = errAuthorizationInternal);
540
541        CFTypeRef cfdict = _CFXPCCreateCFObjectFromXPCObject(value);
542        require_action(cfdict != NULL, done, status = errAuthorizationInternal);
543
544        *rightDefinition = cfdict;
545    }
546
547done:
548    xpc_release_safe(message);
549    xpc_release_safe(reply);
550    return status;
551}
552
553OSStatus AuthorizationRightSet(AuthorizationRef authRef,
554                      const char *rightName,
555                      CFTypeRef rightDefinition,
556                      CFStringRef descriptionKey,
557                      CFBundleRef bundle,
558                      CFStringRef tableName)
559{
560    OSStatus status = errAuthorizationInternal;
561    xpc_object_t message = NULL;
562    xpc_object_t reply = NULL;
563    AuthorizationBlob *blob = NULL;
564    CFMutableDictionaryRef rightDict = NULL;
565    CFBundleRef clientBundle = bundle;
566
567    if (bundle) {
568        CFRetain(bundle);
569    }
570
571    require_action(rightDefinition != NULL, done, status = errAuthorizationInvalidPointer);
572    require_action(rightName != NULL, done, status = errAuthorizationInvalidPointer);
573    require_action(authRef != NULL, done, status = errAuthorizationInvalidRef);
574    blob = (AuthorizationBlob *)authRef;
575
576    // Send
577    message = xpc_dictionary_create(NULL, NULL, 0);
578    require_action(message != NULL, done, status = errAuthorizationInternal);
579
580    xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_RIGHT_SET);
581    xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
582    xpc_dictionary_set_string(message, AUTH_XPC_RIGHT_NAME, rightName);
583
584    // Create rightDict
585    if (CFGetTypeID(rightDefinition) == CFStringGetTypeID()) {
586        rightDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
587        require_action(rightDict != NULL, done, status = errAuthorizationInternal);
588
589        CFDictionarySetValue(rightDict, CFSTR(kAuthorizationRightRule), rightDefinition);
590
591    } else if (CFGetTypeID(rightDefinition) == CFDictionaryGetTypeID()) {
592        rightDict = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, rightDefinition);
593        require_action(rightDict != NULL, done, status = errAuthorizationInternal);
594
595    } else {
596        status = errAuthorizationInvalidPointer;
597        goto done;
598    }
599
600    // Create locDict
601    if (descriptionKey) {
602        CFMutableDictionaryRef locDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
603        require_action(locDict != NULL, done, status = errAuthorizationInternal);
604
605        if (clientBundle == NULL) {
606            clientBundle = CFBundleGetMainBundle();
607            CFRetain(clientBundle);
608        }
609
610        if (clientBundle) {
611            CFArrayRef bundleLocalizations = CFBundleCopyBundleLocalizations(clientBundle);
612            if (bundleLocalizations) {
613                // for every CFString in localizations do
614                CFIndex locIndex, allLocs = CFArrayGetCount(bundleLocalizations);
615                for (locIndex = 0; locIndex < allLocs; locIndex++)
616                {
617                    CFStringRef oneLocalization = (CFStringRef)CFArrayGetValueAtIndex(bundleLocalizations, locIndex);
618
619                    if (!oneLocalization)
620                        continue;
621
622                    // @@@ no way to get "Localized" and "strings" as constants?
623                    CFURLRef locURL = CFBundleCopyResourceURLForLocalization(clientBundle, tableName ? tableName :  CFSTR("Localizable"), CFSTR("strings"), NULL /*subDirName*/, oneLocalization);
624
625                    if (!locURL)
626                        continue;
627
628                    CFDataRef tableData = NULL;
629                    SInt32 errCode;
630                    CFStringRef errStr = NULL;
631                    CFPropertyListRef stringTable = NULL;
632
633                    CFURLCreateDataAndPropertiesFromResource(CFGetAllocator(clientBundle), locURL, &tableData, NULL, NULL, &errCode);
634                    CFReleaseSafe(locURL);
635                    if (errCode)
636                    {
637                        CFReleaseSafe(tableData);
638                        continue;
639                    }
640
641                    stringTable = CFPropertyListCreateFromXMLData(CFGetAllocator(clientBundle), tableData, kCFPropertyListImmutable, &errStr);
642                    CFReleaseSafe(errStr);
643                    CFReleaseSafe(tableData);
644
645                    CFStringRef value = (CFStringRef)CFDictionaryGetValue(stringTable, descriptionKey);
646                    if (value == NULL || CFEqual(value, CFSTR(""))) {
647                        CFReleaseSafe(stringTable);
648                        continue;
649                    } else {
650                        // oneLocalization/value into our dictionary
651                        CFDictionarySetValue(locDict, oneLocalization, value);
652                        CFReleaseSafe(stringTable);
653                    }
654                }
655                CFReleaseSafe(bundleLocalizations);
656            }
657        }
658
659        // add the description as the default localization into the dictionary
660		CFDictionarySetValue(locDict, CFSTR(""), descriptionKey);
661
662		// stuff localization table into right definition
663		CFDictionarySetValue(rightDict, CFSTR(kAuthorizationRuleParameterDefaultPrompt), locDict);
664        CFReleaseSafe(locDict);
665    }
666
667    xpc_object_t value = _CFXPCCreateXPCObjectFromCFObject(rightDict);
668    xpc_dictionary_set_value(message, AUTH_XPC_DATA, value);
669    xpc_release_safe(value);
670
671    // Reply
672    reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message);
673    require_action(reply != NULL, done, status = errAuthorizationInternal);
674    require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
675
676    // Status
677    status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
678
679done:
680    CFReleaseSafe(clientBundle);
681    CFReleaseSafe(rightDict);
682    xpc_release_safe(message);
683    xpc_release_safe(reply);
684    return status;
685}
686
687OSStatus AuthorizationRightRemove(AuthorizationRef authorization,
688                         const char *rightName)
689{
690    OSStatus status = errAuthorizationInternal;
691    xpc_object_t message = NULL;
692    xpc_object_t reply = NULL;
693    AuthorizationBlob *blob = NULL;
694
695    require_action(rightName != NULL, done, status = errAuthorizationInvalidPointer);
696    require_action(authorization != NULL, done, status = errAuthorizationInvalidRef);
697    blob = (AuthorizationBlob *)authorization;
698
699    // Send
700    message = xpc_dictionary_create(NULL, NULL, 0);
701    require_action(message != NULL, done, status = errAuthorizationInternal);
702
703    xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_RIGHT_REMOVE);
704    xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
705    xpc_dictionary_set_string(message, AUTH_XPC_RIGHT_NAME, rightName);
706
707    // Reply
708    reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message);
709    require_action(reply != NULL, done, status = errAuthorizationInternal);
710    require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
711
712    // Status
713    status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
714
715done:
716    xpc_release_safe(message);
717    xpc_release_safe(reply);
718    return status;
719}
720