]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_authorization/lib/Authorization.c
Security-59754.60.13.tar.gz
[apple/security.git] / OSX / libsecurity_authorization / lib / Authorization.c
1 /* Copyright (c) 2012-2013 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 <utilities/SecDispatchRelease.h>
13 #include <utilities/SecCFRelease.h>
14 #include <xpc/xpc.h>
15 #include <xpc/private.h>
16 #include <mach/mach.h>
17 #include <AssertMacros.h>
18 #include <CoreFoundation/CFXPCBridge.h>
19 #include <CoreGraphics/CGWindow.h>
20 #include <dlfcn.h>
21 #include <os/log.h>
22
23 static os_log_t AUTH_LOG_DEFAULT() {
24 static dispatch_once_t once;
25 static os_log_t log;
26 dispatch_once(&once, ^{ log = os_log_create("com.apple.Authorization", "framework"); });
27 return log;
28 };
29
30 #define AUTH_LOG AUTH_LOG_DEFAULT()
31
32 static dispatch_queue_t
33 get_authorization_dispatch_queue()
34 {
35 static dispatch_once_t onceToken = 0;
36 static dispatch_queue_t connection_queue = NULL;
37
38 dispatch_once(&onceToken, ^{
39 connection_queue = dispatch_queue_create("authorization-connection-queue", DISPATCH_QUEUE_SERIAL);
40 });
41
42 return connection_queue;
43 }
44
45 static xpc_connection_t
46 get_authorization_connection()
47 {
48 static xpc_connection_t connection = NULL;
49
50 dispatch_sync(get_authorization_dispatch_queue(), ^{
51 if (connection == NULL) {
52 connection = xpc_connection_create(SECURITY_AUTH_NAME, NULL);
53
54 if (!connection) {
55 os_log_error(AUTH_LOG, "Failed to create xpc connection to %s", SECURITY_AUTH_NAME);
56 connection = xpc_connection_create(SECURITY_AUTH_NAME, NULL);
57 }
58
59 if (connection == NULL) {
60 os_log_error(AUTH_LOG, "Still failed to create xpc connection to %s", SECURITY_AUTH_NAME);
61 return;
62 }
63 xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {
64 if (xpc_get_type(event) == XPC_TYPE_ERROR) {
65 if (event == XPC_ERROR_CONNECTION_INVALID) {
66 os_log_error(AUTH_LOG, "Server not available");
67 }
68 // XPC_ERROR_CONNECTION_INTERRUPTED
69 // XPC_ERROR_TERMINATION_IMMINENT
70 } else {
71 char * desc = xpc_copy_description(event);
72 os_log_error(AUTH_LOG, "We should never get messages on this connection: %s", desc);
73 free(desc);
74 }
75 });
76
77 xpc_connection_resume(connection);
78
79 // Send
80 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
81 xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_SETUP);
82 mach_port_t bootstrap = MACH_PORT_NULL;
83 task_get_bootstrap_port(mach_task_self(), &bootstrap);
84 xpc_dictionary_set_mach_send(message, AUTH_XPC_BOOTSTRAP, bootstrap);
85 xpc_object_t reply = xpc_connection_send_message_with_reply_sync(connection, message);
86 xpc_release_safe(message);
87 xpc_release_safe(reply);
88 }
89 });
90
91 return connection;
92 }
93
94 static void
95 setItemSet(xpc_object_t message, const char * key, const AuthorizationItemSet * itemSet)
96 {
97 xpc_object_t serialized = SerializeItemSet(itemSet);
98 if (serialized) {
99 xpc_dictionary_set_value(message, key, serialized);
100 xpc_release(serialized);
101 }
102 }
103
104 OSStatus AuthorizationCreate(const AuthorizationRights *rights,
105 const AuthorizationEnvironment *environment,
106 AuthorizationFlags flags,
107 AuthorizationRef *authorization)
108 {
109 OSStatus status = errAuthorizationInternal;
110 xpc_object_t message = NULL;
111 xpc_object_t reply = NULL;
112
113 // require_action(!(rights == NULL && authorization == NULL), done, status = errAuthorizationInvalidSet);
114
115 // Send
116 message = xpc_dictionary_create(NULL, NULL, 0);
117 require_action(message != NULL, done, status = errAuthorizationInternal);
118
119 xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_CREATE);
120 setItemSet(message, AUTH_XPC_RIGHTS, rights);
121 setItemSet(message, AUTH_XPC_ENVIRONMENT, environment);
122 xpc_dictionary_set_uint64(message, AUTH_XPC_FLAGS, flags | (authorization ? 0 : kAuthorizationFlagNoData));
123
124 // Reply
125 xpc_connection_t conn = get_authorization_connection();
126 require_action(conn != NULL, done, status = errAuthorizationInternal);
127 reply = xpc_connection_send_message_with_reply_sync(conn, message);
128 require_action_quiet(reply != NULL, done, status = errAuthorizationInternal);
129 require_action_quiet(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal;);
130
131 // Status
132 status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
133
134 // Out
135 if (authorization && status == errAuthorizationSuccess) {
136 size_t len;
137 const void * data = xpc_dictionary_get_data(reply, AUTH_XPC_BLOB, &len);
138 require_action(data != NULL, done, status = errAuthorizationInternal);
139 require_action(len == sizeof(AuthorizationBlob), done, status = errAuthorizationInternal);
140
141 AuthorizationBlob * blob = (AuthorizationBlob*)calloc(1u, sizeof(AuthorizationBlob));
142 require_action(blob != NULL, done, status = errAuthorizationInternal);
143 *blob = *(AuthorizationBlob*)data;
144
145 *authorization = (AuthorizationRef)blob;
146 }
147
148 done:
149 xpc_release_safe(message);
150 xpc_release_safe(reply);
151 return status;
152 }
153
154 OSStatus AuthorizationCreateWithAuditToken(audit_token_t token,
155 const AuthorizationEnvironment *environment,
156 AuthorizationFlags flags,
157 AuthorizationRef *authorization)
158 {
159 OSStatus status = errAuthorizationInternal;
160 xpc_object_t message = NULL;
161 xpc_object_t reply = NULL;
162
163 require_action(authorization != NULL, done, status = errAuthorizationInvalidPointer);
164
165 // Send
166 message = xpc_dictionary_create(NULL, NULL, 0);
167 require_action(message != NULL, done, status = errAuthorizationInternal);
168
169 xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_CREATE_WITH_AUDIT_TOKEN);
170 xpc_dictionary_set_data(message, AUTH_XPC_DATA, &token, sizeof(token));
171 setItemSet(message, AUTH_XPC_ENVIRONMENT, environment);
172 xpc_dictionary_set_uint64(message, AUTH_XPC_FLAGS, flags);
173
174 // Reply
175 xpc_connection_t conn = get_authorization_connection();
176 require_action(conn != NULL, done, status = errAuthorizationInternal);
177 reply = xpc_connection_send_message_with_reply_sync(conn, message);
178 require_action(reply != NULL, done, status = errAuthorizationInternal);
179 require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
180
181 // Status
182 status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
183
184 // Out
185 if (status == errAuthorizationSuccess) {
186 size_t len;
187 const void * data = xpc_dictionary_get_data(reply, AUTH_XPC_BLOB, &len);
188 require_action(data != NULL, done, status = errAuthorizationInternal);
189 require_action(len == sizeof(AuthorizationBlob), done, status = errAuthorizationInternal);
190
191 AuthorizationBlob * blob = (AuthorizationBlob*)calloc(1u, sizeof(AuthorizationBlob));
192 require_action(blob != NULL, done, status = errAuthorizationInternal);
193 *blob = *(AuthorizationBlob*)data;
194
195 *authorization = (AuthorizationRef)blob;
196 }
197
198 done:
199 xpc_release_safe(message);
200 xpc_release_safe(reply);
201 return status;
202 }
203
204 OSStatus AuthorizationFree(AuthorizationRef authorization, AuthorizationFlags flags)
205 {
206 OSStatus status = errAuthorizationInternal;
207 xpc_object_t message = NULL;
208 xpc_object_t reply = NULL;
209 AuthorizationBlob *blob = NULL;
210
211 require_action(authorization != NULL, done, status = errAuthorizationInvalidRef);
212 blob = (AuthorizationBlob *)authorization;
213
214 // Send
215 message = xpc_dictionary_create(NULL, NULL, 0);
216 require_action(message != NULL, done, status = errAuthorizationInternal);
217
218 xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_FREE);
219 xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
220 xpc_dictionary_set_uint64(message, AUTH_XPC_FLAGS, flags);
221
222 // Reply
223 xpc_connection_t conn = get_authorization_connection();
224 require_action(conn != NULL, done, status = errAuthorizationInternal);
225 reply = xpc_connection_send_message_with_reply_sync(conn, message);
226 require_action(reply != NULL, done, status = errAuthorizationInternal);
227 require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
228
229 // Status
230 status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
231
232 // Free
233 free(blob);
234
235 done:
236 xpc_release_safe(message);
237 xpc_release_safe(reply);
238 return status;
239 }
240
241 OSStatus AuthorizationCopyRightProperties(const char *rightName, CFDictionaryRef *output)
242 {
243 OSStatus status = errAuthorizationInternal;
244 xpc_object_t reply = NULL;
245 CFDataRef data = NULL;
246 xpc_object_t message = NULL;
247 require_action(rightName != NULL, done, status = errAuthorizationInvalidPointer);
248
249 message = xpc_dictionary_create(NULL, NULL, 0);
250 require_action(message != NULL, done, status = errAuthorizationInternal);
251
252 xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_COPY_RIGHT_PROPERTIES);
253 xpc_dictionary_set_string(message, AUTH_XPC_RIGHT_NAME, rightName);
254
255 xpc_connection_t conn = get_authorization_connection();
256 require_action(conn != NULL, done, status = errAuthorizationInternal);
257 reply = xpc_connection_send_message_with_reply_sync(conn, message);
258 require_action(reply != NULL, done, status = errAuthorizationInternal);
259 require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
260
261 // Status
262 status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
263 if (output && status == errAuthorizationSuccess) {
264 size_t len;
265 const void *bytes = xpc_dictionary_get_data(reply, AUTH_XPC_OUT_ITEMS, &len);
266 data = CFDataCreate(kCFAllocatorDefault, bytes, len);
267 require_action(data != NULL, done, status = errAuthorizationInternal);
268 *output = CFPropertyListCreateWithData(kCFAllocatorDefault, data, kCFPropertyListImmutable, NULL, NULL);
269 }
270 done:
271 xpc_release_safe(message);
272 xpc_release_safe(reply);
273 CFReleaseSafe(data);
274
275 return status;
276 }
277
278 static OSStatus
279 _AuthorizationCopyRights_send_message(xpc_object_t message, AuthorizationRights **authorizedRights)
280 {
281 OSStatus status = errAuthorizationInternal;
282 xpc_object_t reply = NULL;
283
284 // Send
285 require_action(message != NULL, done, status = errAuthorizationInternal);
286
287 // Reply
288 xpc_connection_t conn = get_authorization_connection();
289 require_action(conn != NULL, done, status = errAuthorizationInternal);
290 reply = xpc_connection_send_message_with_reply_sync(conn, message);
291 require_action(reply != NULL, done, status = errAuthorizationInternal);
292 require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
293
294 // Status
295 status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
296
297 // Out
298 if (authorizedRights && status == errAuthorizationSuccess) {
299 xpc_object_t tmpItems = xpc_dictionary_get_value(reply, AUTH_XPC_OUT_ITEMS);
300 AuthorizationRights * grantedRights = DeserializeItemSet(tmpItems);
301 require_action(grantedRights != NULL, done, status = errAuthorizationInternal);
302
303 *authorizedRights = grantedRights;
304 }
305
306 done:
307 xpc_release_safe(reply);
308 return status;
309 }
310
311 static OSStatus
312 _AuthorizationCopyRights_prepare_message(AuthorizationRef authorization, const AuthorizationRights *rights, const AuthorizationEnvironment *environment, AuthorizationFlags flags, xpc_object_t *message_out)
313 {
314 OSStatus status = errAuthorizationInternal;
315 AuthorizationBlob *blob = NULL;
316 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
317 require_action(message != NULL, done, status = errAuthorizationInternal);
318
319 require_action(authorization != NULL, done, status = errAuthorizationInvalidRef);
320 blob = (AuthorizationBlob *)authorization;
321
322 xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_COPY_RIGHTS);
323 xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
324 setItemSet(message, AUTH_XPC_RIGHTS, rights);
325 setItemSet(message, AUTH_XPC_ENVIRONMENT, environment);
326 xpc_dictionary_set_uint64(message, AUTH_XPC_FLAGS, flags);
327
328 *message_out = message;
329 message = NULL;
330 status = errAuthorizationSuccess;
331
332 done:
333 xpc_release_safe(message);
334 return status;
335 }
336
337 OSStatus AuthorizationCopyRights(AuthorizationRef authorization,
338 const AuthorizationRights *rights,
339 const AuthorizationEnvironment *environment,
340 AuthorizationFlags flags,
341 AuthorizationRights **authorizedRights)
342 {
343 OSStatus status = errAuthorizationInternal;
344
345 if ((flags & kAuthorizationFlagSheet) && environment) {
346 // check if window ID is present in environment
347 CGWindowID window = 0;
348 for (UInt32 i = 0; i < environment->count; ++i) {
349 if (strncmp(environment->items[i].name, kAuthorizationEnvironmentWindowId, strlen(kAuthorizationEnvironmentWindowId)) == 0
350 && (environment->items[i].valueLength = sizeof(window)) && environment->items[i].value) {
351 window = *(CGWindowID *)environment->items[i].value;
352 break;
353 }
354 }
355 if (window > 0) {
356 os_log_debug(AUTH_LOG, "Trying to use sheet version");
357 static OSStatus (*sheetAuthorizationWorker)(CGWindowID windowID, AuthorizationRef authorization,
358 const AuthorizationRights *rights,
359 const AuthorizationEnvironment *environment,
360 AuthorizationFlags flags,
361 AuthorizationRights **authorizedRights,
362 Boolean *authorizationLaunched) = NULL;
363 static dispatch_once_t onceToken;
364 dispatch_once(&onceToken, ^{
365 void *handle = dlopen("/System/Library/Frameworks/SecurityInterface.framework/SecurityInterface", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
366 if (handle) {
367 sheetAuthorizationWorker = dlsym(handle, "sheetAuthorizationWorker");
368 }
369 });
370
371 if (sheetAuthorizationWorker) {
372 Boolean authorizationLaunched;
373 status = sheetAuthorizationWorker(window, authorization, rights, environment, flags, authorizedRights, &authorizationLaunched);
374 if (authorizationLaunched == true) {
375 os_log_debug(AUTH_LOG, "Returning sheet result %d", (int)status);
376 return status;
377 }
378 os_log(AUTH_LOG, "Sheet authorization cannot be used this time, falling back to the SecurityAgent UI");
379 } else {
380 os_log_debug(AUTH_LOG, "Failed to find sheet support in SecurityInterface");
381 }
382 // fall back to the standard (windowed) version if sheets are not available
383 flags &= ~kAuthorizationFlagSheet;
384 }
385 }
386
387 xpc_object_t message = NULL;
388
389 require_noerr(status = _AuthorizationCopyRights_prepare_message(authorization, rights, environment, flags, &message), done);
390 require_noerr(status = _AuthorizationCopyRights_send_message(message, authorizedRights), done);
391
392 done:
393 xpc_release_safe(message);
394 return status;
395 }
396
397
398 void AuthorizationCopyRightsAsync(AuthorizationRef authorization,
399 const AuthorizationRights *rights,
400 const AuthorizationEnvironment *environment,
401 AuthorizationFlags flags,
402 AuthorizationAsyncCallback callbackBlock)
403 {
404 OSStatus prepare_status = errAuthorizationInternal;
405 __block xpc_object_t message = NULL;
406
407 prepare_status = _AuthorizationCopyRights_prepare_message(authorization, rights, environment, flags, &message);
408 if (prepare_status != errAuthorizationSuccess) {
409 callbackBlock(prepare_status, NULL);
410 }
411
412 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
413 AuthorizationRights *blockAuthorizedRights = NULL;
414 OSStatus status = _AuthorizationCopyRights_send_message(message, &blockAuthorizedRights);
415 callbackBlock(status, blockAuthorizedRights);
416 xpc_release_safe(message);
417 });
418 }
419
420 OSStatus AuthorizationDismiss()
421 {
422 OSStatus status = errAuthorizationInternal;
423 xpc_object_t message = NULL;
424 xpc_object_t reply = NULL;
425
426 // Send
427 message = xpc_dictionary_create(NULL, NULL, 0);
428 require(message != NULL, done);
429
430 xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_DISMISS);
431
432 // Reply
433 xpc_connection_t conn = get_authorization_connection();
434 require_action(conn != NULL, done, status = errAuthorizationInternal);
435 reply = xpc_connection_send_message_with_reply_sync(conn, message);
436 require_action(reply != NULL, done, status = errAuthorizationInternal);
437 require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
438
439 // Status
440 status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
441
442 done:
443 xpc_release_safe(message);
444 xpc_release_safe(reply);
445 return status;
446 }
447
448 OSStatus AuthorizationCopyInfo(AuthorizationRef authorization,
449 AuthorizationString tag,
450 AuthorizationItemSet **info)
451 {
452 OSStatus status = errAuthorizationInternal;
453 xpc_object_t message = NULL;
454 xpc_object_t reply = NULL;
455 AuthorizationBlob *blob = NULL;
456
457 require_action(info != NULL, done, status = errAuthorizationInvalidSet);
458 require_action(authorization != NULL, done, status = errAuthorizationInvalidRef);
459 blob = (AuthorizationBlob *)authorization;
460
461 // Send
462 message = xpc_dictionary_create(NULL, NULL, 0);
463 require_action(message != NULL, done, status = errAuthorizationInternal);
464
465 xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_COPY_INFO);
466 xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
467 if (tag) {
468 xpc_dictionary_set_string(message, AUTH_XPC_TAG, tag);
469 }
470
471 // Reply
472 xpc_connection_t conn = get_authorization_connection();
473 require_action(conn != NULL, done, status = errAuthorizationInternal);
474 reply = xpc_connection_send_message_with_reply_sync(conn, message);
475 require_action(reply != NULL, done, status = errAuthorizationInternal);
476 require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
477
478 // Status
479 status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
480
481 // Out
482 if (info && status == errAuthorizationSuccess) {
483 xpc_object_t tmpItems = xpc_dictionary_get_value(reply, AUTH_XPC_OUT_ITEMS);
484 AuthorizationRights * outInfo = DeserializeItemSet(tmpItems);
485 require_action(outInfo != NULL, done, status = errAuthorizationInternal);
486
487 *info = outInfo;
488 }
489
490 done:
491 xpc_release_safe(message);
492 xpc_release_safe(reply);
493 return status;
494 }
495
496 OSStatus AuthorizationMakeExternalForm(AuthorizationRef authorization,
497 AuthorizationExternalForm *extForm)
498 {
499 OSStatus status = errAuthorizationInternal;
500 xpc_object_t message = NULL;
501 xpc_object_t reply = NULL;
502 AuthorizationBlob *blob = NULL;
503
504 require_action(extForm != NULL, done, status = errAuthorizationInvalidPointer);
505 require_action(authorization != NULL, done, status = errAuthorizationInvalidRef);
506 blob = (AuthorizationBlob *)authorization;
507
508 // Send
509 message = xpc_dictionary_create(NULL, NULL, 0);
510 require_action(message != NULL, done, status = errAuthorizationInternal);
511
512 xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_MAKE_EXTERNAL_FORM);
513 xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
514
515 // Reply
516 xpc_connection_t conn = get_authorization_connection();
517 require_action(conn != NULL, done, status = errAuthorizationInternal);
518 reply = xpc_connection_send_message_with_reply_sync(conn, message);
519 require_action(reply != NULL, done, status = errAuthorizationInternal);
520 require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
521
522 // Status
523 status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
524
525 // out
526 if (status == errAuthorizationSuccess) {
527 size_t len;
528 const void * data = xpc_dictionary_get_data(reply, AUTH_XPC_EXTERNAL, &len);
529 require_action(data != NULL, done, status = errAuthorizationInternal);
530 require_action(len == sizeof(AuthorizationExternalForm), done, status = errAuthorizationInternal);
531
532 *extForm = *(AuthorizationExternalForm*)data;
533 }
534
535 done:
536 xpc_release_safe(message);
537 xpc_release_safe(reply);
538 return status;
539 }
540
541 OSStatus AuthorizationCreateFromExternalForm(const AuthorizationExternalForm *extForm,
542 AuthorizationRef *authorization)
543 {
544 OSStatus status = errAuthorizationInternal;
545 xpc_object_t message = NULL;
546 xpc_object_t reply = NULL;
547
548 require_action(extForm != NULL, done, status = errAuthorizationInvalidPointer);
549 require_action(authorization != NULL, done, status = errAuthorizationInvalidRef);
550
551 // Send
552 message = xpc_dictionary_create(NULL, NULL, 0);
553 require_action(message != NULL, done, status = errAuthorizationInternal);
554
555 xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_CREATE_FROM_EXTERNAL_FORM);
556 xpc_dictionary_set_data(message, AUTH_XPC_EXTERNAL, extForm, sizeof(AuthorizationExternalForm));
557
558 // Reply
559 xpc_connection_t conn = get_authorization_connection();
560 require_action(conn != NULL, done, status = errAuthorizationInternal);
561 reply = xpc_connection_send_message_with_reply_sync(conn, message);
562 require_action(reply != NULL, done, status = errAuthorizationInternal);
563 require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
564
565 // Status
566 status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
567
568 // Out
569 if (authorization && status == errAuthorizationSuccess) {
570 size_t len;
571 const void * data = xpc_dictionary_get_data(reply, AUTH_XPC_BLOB, &len);
572 require_action(data != NULL, done, status = errAuthorizationInternal);
573 require_action(len == sizeof(AuthorizationBlob), done, status = errAuthorizationInternal);
574
575 AuthorizationBlob * blob = (AuthorizationBlob*)calloc(1u, sizeof(AuthorizationBlob));
576 require_action(blob != NULL, done, status = errAuthorizationInternal);
577 *blob = *(AuthorizationBlob*)data;
578
579 *authorization = (AuthorizationRef)blob;
580 }
581
582 done:
583 xpc_release_safe(message);
584 xpc_release_safe(reply);
585 return status;
586 }
587
588 OSStatus AuthorizationFreeItemSet(AuthorizationItemSet *set)
589 {
590 FreeItemSet(set);
591 return errAuthorizationSuccess;
592 }
593
594 OSStatus AuthorizationEnableSmartCard(AuthorizationRef authRef, Boolean enable)
595 {
596 OSStatus status = errAuthorizationInternal;
597 xpc_object_t message = NULL;
598 xpc_object_t reply = NULL;
599 AuthorizationBlob *blob = NULL;
600
601 // Send
602 message = xpc_dictionary_create(NULL, NULL, 0);
603 require_action(message != NULL, done, status = errAuthorizationInternal);
604 require_action(authRef != NULL, done, status = errAuthorizationInvalidRef);
605 blob = (AuthorizationBlob *)authRef;
606 xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_ENABLE_SMARTCARD);
607 xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
608 xpc_dictionary_set_bool(message, AUTH_XPC_DATA, enable);
609
610 // Reply
611 xpc_connection_t conn = get_authorization_connection();
612 require_action(conn != NULL, done, status = errAuthorizationInternal);
613 reply = xpc_connection_send_message_with_reply_sync(conn, message);
614 require_action(reply != NULL, done, status = errAuthorizationInternal);
615 require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
616
617 status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
618
619 done:
620 xpc_release_safe(message);
621 xpc_release_safe(reply);
622 return status;
623 }
624
625
626 OSStatus AuthorizationRightGet(const char *rightName,
627 CFDictionaryRef *rightDefinition)
628 {
629 OSStatus status = errAuthorizationInternal;
630 xpc_object_t message = NULL;
631 xpc_object_t reply = NULL;
632
633 require_action(rightName != NULL, done, status = errAuthorizationInvalidPointer);
634
635 // Send
636 message = xpc_dictionary_create(NULL, NULL, 0);
637 require_action(message != NULL, done, status = errAuthorizationInternal);
638
639 xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_RIGHT_GET);
640 xpc_dictionary_set_string(message, AUTH_XPC_RIGHT_NAME, rightName);
641
642 // Reply
643 xpc_connection_t conn = get_authorization_connection();
644 require_action(conn != NULL, done, status = errAuthorizationInternal);
645 reply = xpc_connection_send_message_with_reply_sync(conn, message);
646 require_action(reply != NULL, done, status = errAuthorizationInternal);
647 require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
648
649 // Status
650 status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
651
652 // Out
653 if (rightDefinition && status == errAuthorizationSuccess) {
654 xpc_object_t value = xpc_dictionary_get_value(reply, AUTH_XPC_DATA);
655 require_action(value != NULL, done, status = errAuthorizationInternal);
656 require_action(xpc_get_type(value) == XPC_TYPE_DICTIONARY, done, status = errAuthorizationInternal);
657
658 CFTypeRef cfdict = _CFXPCCreateCFObjectFromXPCObject(value);
659 require_action(cfdict != NULL, done, status = errAuthorizationInternal);
660
661 *rightDefinition = cfdict;
662 }
663
664 done:
665 xpc_release_safe(message);
666 xpc_release_safe(reply);
667 return status;
668 }
669
670 OSStatus AuthorizationRightSet(AuthorizationRef authRef,
671 const char *rightName,
672 CFTypeRef rightDefinition,
673 CFStringRef descriptionKey,
674 CFBundleRef bundle,
675 CFStringRef tableName)
676 {
677 OSStatus status = errAuthorizationInternal;
678 xpc_object_t message = NULL;
679 xpc_object_t reply = NULL;
680 AuthorizationBlob *blob = NULL;
681 CFMutableDictionaryRef rightDict = NULL;
682 CFBundleRef clientBundle = bundle;
683
684 if (bundle) {
685 CFRetain(bundle);
686 }
687
688 require_action(rightDefinition != NULL, done, status = errAuthorizationInvalidPointer);
689 require_action(rightName != NULL, done, status = errAuthorizationInvalidPointer);
690 require_action(authRef != NULL, done, status = errAuthorizationInvalidRef);
691 blob = (AuthorizationBlob *)authRef;
692
693 // Send
694 message = xpc_dictionary_create(NULL, NULL, 0);
695 require_action(message != NULL, done, status = errAuthorizationInternal);
696
697 xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_RIGHT_SET);
698 xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
699 xpc_dictionary_set_string(message, AUTH_XPC_RIGHT_NAME, rightName);
700
701 // Create rightDict
702 if (CFGetTypeID(rightDefinition) == CFStringGetTypeID()) {
703 rightDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
704 require_action(rightDict != NULL, done, status = errAuthorizationInternal);
705
706 CFDictionarySetValue(rightDict, CFSTR(kAuthorizationRightRule), rightDefinition);
707
708 } else if (CFGetTypeID(rightDefinition) == CFDictionaryGetTypeID()) {
709 rightDict = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, rightDefinition);
710 require_action(rightDict != NULL, done, status = errAuthorizationInternal);
711
712 } else {
713 status = errAuthorizationInvalidPointer;
714 goto done;
715 }
716
717 // Create locDict
718 if (descriptionKey) {
719 CFMutableDictionaryRef locDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
720 require_action(locDict != NULL, done, status = errAuthorizationInternal);
721
722 if (clientBundle == NULL) {
723 clientBundle = CFBundleGetMainBundle();
724 CFRetain(clientBundle);
725 }
726
727 if (clientBundle) {
728 CFArrayRef bundleLocalizations = CFBundleCopyBundleLocalizations(clientBundle);
729 if (bundleLocalizations) {
730 // for every CFString in localizations do
731 CFIndex locIndex, allLocs = CFArrayGetCount(bundleLocalizations);
732 for (locIndex = 0; locIndex < allLocs; locIndex++)
733 {
734 CFStringRef oneLocalization = (CFStringRef)CFArrayGetValueAtIndex(bundleLocalizations, locIndex);
735
736 if (!oneLocalization)
737 continue;
738
739 // @@@ no way to get "Localized" and "strings" as constants?
740 CFURLRef locURL = CFBundleCopyResourceURLForLocalization(clientBundle, tableName ? tableName : CFSTR("Localizable"), CFSTR("strings"), NULL /*subDirName*/, oneLocalization);
741
742 if (!locURL)
743 continue;
744
745 CFDataRef tableData = NULL;
746 SInt32 errCode;
747 CFStringRef errStr = NULL;
748 CFPropertyListRef stringTable = NULL;
749
750 CFURLCreateDataAndPropertiesFromResource(CFGetAllocator(clientBundle), locURL, &tableData, NULL, NULL, &errCode);
751 CFReleaseSafe(locURL);
752 if (errCode)
753 {
754 CFReleaseSafe(tableData);
755 continue;
756 }
757
758 stringTable = CFPropertyListCreateFromXMLData(CFGetAllocator(clientBundle), tableData, kCFPropertyListImmutable, &errStr);
759 CFReleaseSafe(errStr);
760 CFReleaseSafe(tableData);
761
762 CFStringRef value = (CFStringRef)CFDictionaryGetValue(stringTable, descriptionKey);
763 if (value == NULL || CFEqual(value, CFSTR(""))) {
764 CFReleaseSafe(stringTable);
765 continue;
766 } else {
767 // oneLocalization/value into our dictionary
768 CFDictionarySetValue(locDict, oneLocalization, value);
769 CFReleaseSafe(stringTable);
770 }
771 }
772 CFReleaseSafe(bundleLocalizations);
773 }
774 }
775
776 // add the description as the default localization into the dictionary
777 CFDictionarySetValue(locDict, CFSTR(""), descriptionKey);
778
779 // stuff localization table into right definition
780 CFDictionarySetValue(rightDict, CFSTR(kAuthorizationRuleParameterDefaultPrompt), locDict);
781 CFReleaseSafe(locDict);
782 }
783
784 xpc_object_t value = _CFXPCCreateXPCObjectFromCFObject(rightDict);
785 xpc_dictionary_set_value(message, AUTH_XPC_DATA, value);
786 xpc_release_safe(value);
787
788 // Reply
789 xpc_connection_t conn = get_authorization_connection();
790 require_action(conn != NULL, done, status = errAuthorizationInternal);
791 reply = xpc_connection_send_message_with_reply_sync(conn, message);
792 require_action(reply != NULL, done, status = errAuthorizationInternal);
793 require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
794
795 // Status
796 status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
797
798 done:
799 CFReleaseSafe(clientBundle);
800 CFReleaseSafe(rightDict);
801 xpc_release_safe(message);
802 xpc_release_safe(reply);
803 return status;
804 }
805
806 OSStatus AuthorizationRightRemove(AuthorizationRef authorization,
807 const char *rightName)
808 {
809 OSStatus status = errAuthorizationInternal;
810 xpc_object_t message = NULL;
811 xpc_object_t reply = NULL;
812 AuthorizationBlob *blob = NULL;
813
814 require_action(rightName != NULL, done, status = errAuthorizationInvalidPointer);
815 require_action(authorization != NULL, done, status = errAuthorizationInvalidRef);
816 blob = (AuthorizationBlob *)authorization;
817
818 // Send
819 message = xpc_dictionary_create(NULL, NULL, 0);
820 require_action(message != NULL, done, status = errAuthorizationInternal);
821
822 xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_RIGHT_REMOVE);
823 xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
824 xpc_dictionary_set_string(message, AUTH_XPC_RIGHT_NAME, rightName);
825
826 // Reply
827 xpc_connection_t conn = get_authorization_connection();
828 require_action(conn != NULL, done, status = errAuthorizationInternal);
829 reply = xpc_connection_send_message_with_reply_sync(conn, message);
830 require_action(reply != NULL, done, status = errAuthorizationInternal);
831 require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
832
833 // Status
834 status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
835
836 done:
837 xpc_release_safe(message);
838 xpc_release_safe(reply);
839 return status;
840 }
841
842 OSStatus AuthorizationCopyPreloginUserDatabase(const char * _Nullable const volumeUuid, const UInt32 flags, CFArrayRef _Nonnull * _Nonnull output)
843 {
844 OSStatus status = errAuthorizationInternal;
845 xpc_object_t message = NULL;
846 xpc_object_t reply = NULL;
847
848 require_action(output != NULL, done, status = errAuthorizationInvalidRef);
849
850 // Send
851 message = xpc_dictionary_create(NULL, NULL, 0);
852 require_action(message != NULL, done, status = errAuthorizationInternal);
853 xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_COPY_PRELOGIN_USERDB);
854 if (volumeUuid) {
855 xpc_dictionary_set_string(message, AUTH_XPC_TAG, volumeUuid);
856 }
857 xpc_dictionary_set_uint64(message, AUTH_XPC_FLAGS, flags);
858
859 // Reply
860 xpc_connection_t conn = get_authorization_connection();
861 require_action(conn != NULL, done, status = errAuthorizationInternal);
862 reply = xpc_connection_send_message_with_reply_sync(conn, message);
863 require_action(reply != NULL, done, status = errAuthorizationInternal);
864 require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
865
866 status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
867
868 // fill the output
869 if (status == errAuthorizationSuccess) {
870 *output = _CFXPCCreateCFObjectFromXPCObject(xpc_dictionary_get_value(reply, AUTH_XPC_DATA));
871 }
872
873 done:
874 xpc_release_safe(message);
875 xpc_release_safe(reply);
876 return status;
877 }