]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_authorization/lib/Authorization.c
Security-59754.41.1.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 }
384 }
385
386 xpc_object_t message = NULL;
387
388 require_noerr(status = _AuthorizationCopyRights_prepare_message(authorization, rights, environment, flags, &message), done);
389 require_noerr(status = _AuthorizationCopyRights_send_message(message, authorizedRights), done);
390
391 done:
392 xpc_release_safe(message);
393 return status;
394 }
395
396
397 void AuthorizationCopyRightsAsync(AuthorizationRef authorization,
398 const AuthorizationRights *rights,
399 const AuthorizationEnvironment *environment,
400 AuthorizationFlags flags,
401 AuthorizationAsyncCallback callbackBlock)
402 {
403 OSStatus prepare_status = errAuthorizationInternal;
404 __block xpc_object_t message = NULL;
405
406 prepare_status = _AuthorizationCopyRights_prepare_message(authorization, rights, environment, flags, &message);
407 if (prepare_status != errAuthorizationSuccess) {
408 callbackBlock(prepare_status, NULL);
409 }
410
411 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
412 AuthorizationRights *blockAuthorizedRights = NULL;
413 OSStatus status = _AuthorizationCopyRights_send_message(message, &blockAuthorizedRights);
414 callbackBlock(status, blockAuthorizedRights);
415 xpc_release_safe(message);
416 });
417 }
418
419 OSStatus AuthorizationDismiss()
420 {
421 OSStatus status = errAuthorizationInternal;
422 xpc_object_t message = NULL;
423 xpc_object_t reply = NULL;
424
425 // Send
426 message = xpc_dictionary_create(NULL, NULL, 0);
427 require(message != NULL, done);
428
429 xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_DISMISS);
430
431 // Reply
432 xpc_connection_t conn = get_authorization_connection();
433 require_action(conn != NULL, done, status = errAuthorizationInternal);
434 reply = xpc_connection_send_message_with_reply_sync(conn, message);
435 require_action(reply != NULL, done, status = errAuthorizationInternal);
436 require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
437
438 // Status
439 status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
440
441 done:
442 xpc_release_safe(message);
443 xpc_release_safe(reply);
444 return status;
445 }
446
447 OSStatus AuthorizationCopyInfo(AuthorizationRef authorization,
448 AuthorizationString tag,
449 AuthorizationItemSet **info)
450 {
451 OSStatus status = errAuthorizationInternal;
452 xpc_object_t message = NULL;
453 xpc_object_t reply = NULL;
454 AuthorizationBlob *blob = NULL;
455
456 require_action(info != NULL, done, status = errAuthorizationInvalidSet);
457 require_action(authorization != NULL, done, status = errAuthorizationInvalidRef);
458 blob = (AuthorizationBlob *)authorization;
459
460 // Send
461 message = xpc_dictionary_create(NULL, NULL, 0);
462 require_action(message != NULL, done, status = errAuthorizationInternal);
463
464 xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_COPY_INFO);
465 xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
466 if (tag) {
467 xpc_dictionary_set_string(message, AUTH_XPC_TAG, tag);
468 }
469
470 // Reply
471 xpc_connection_t conn = get_authorization_connection();
472 require_action(conn != NULL, done, status = errAuthorizationInternal);
473 reply = xpc_connection_send_message_with_reply_sync(conn, message);
474 require_action(reply != NULL, done, status = errAuthorizationInternal);
475 require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
476
477 // Status
478 status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
479
480 // Out
481 if (info && status == errAuthorizationSuccess) {
482 xpc_object_t tmpItems = xpc_dictionary_get_value(reply, AUTH_XPC_OUT_ITEMS);
483 AuthorizationRights * outInfo = DeserializeItemSet(tmpItems);
484 require_action(outInfo != NULL, done, status = errAuthorizationInternal);
485
486 *info = outInfo;
487 }
488
489 done:
490 xpc_release_safe(message);
491 xpc_release_safe(reply);
492 return status;
493 }
494
495 OSStatus AuthorizationMakeExternalForm(AuthorizationRef authorization,
496 AuthorizationExternalForm *extForm)
497 {
498 OSStatus status = errAuthorizationInternal;
499 xpc_object_t message = NULL;
500 xpc_object_t reply = NULL;
501 AuthorizationBlob *blob = NULL;
502
503 require_action(extForm != NULL, done, status = errAuthorizationInvalidPointer);
504 require_action(authorization != NULL, done, status = errAuthorizationInvalidRef);
505 blob = (AuthorizationBlob *)authorization;
506
507 // Send
508 message = xpc_dictionary_create(NULL, NULL, 0);
509 require_action(message != NULL, done, status = errAuthorizationInternal);
510
511 xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_MAKE_EXTERNAL_FORM);
512 xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
513
514 // Reply
515 xpc_connection_t conn = get_authorization_connection();
516 require_action(conn != NULL, done, status = errAuthorizationInternal);
517 reply = xpc_connection_send_message_with_reply_sync(conn, message);
518 require_action(reply != NULL, done, status = errAuthorizationInternal);
519 require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
520
521 // Status
522 status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
523
524 // out
525 if (status == errAuthorizationSuccess) {
526 size_t len;
527 const void * data = xpc_dictionary_get_data(reply, AUTH_XPC_EXTERNAL, &len);
528 require_action(data != NULL, done, status = errAuthorizationInternal);
529 require_action(len == sizeof(AuthorizationExternalForm), done, status = errAuthorizationInternal);
530
531 *extForm = *(AuthorizationExternalForm*)data;
532 }
533
534 done:
535 xpc_release_safe(message);
536 xpc_release_safe(reply);
537 return status;
538 }
539
540 OSStatus AuthorizationCreateFromExternalForm(const AuthorizationExternalForm *extForm,
541 AuthorizationRef *authorization)
542 {
543 OSStatus status = errAuthorizationInternal;
544 xpc_object_t message = NULL;
545 xpc_object_t reply = NULL;
546
547 require_action(extForm != NULL, done, status = errAuthorizationInvalidPointer);
548 require_action(authorization != NULL, done, status = errAuthorizationInvalidRef);
549
550 // Send
551 message = xpc_dictionary_create(NULL, NULL, 0);
552 require_action(message != NULL, done, status = errAuthorizationInternal);
553
554 xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_CREATE_FROM_EXTERNAL_FORM);
555 xpc_dictionary_set_data(message, AUTH_XPC_EXTERNAL, extForm, sizeof(AuthorizationExternalForm));
556
557 // Reply
558 xpc_connection_t conn = get_authorization_connection();
559 require_action(conn != NULL, done, status = errAuthorizationInternal);
560 reply = xpc_connection_send_message_with_reply_sync(conn, message);
561 require_action(reply != NULL, done, status = errAuthorizationInternal);
562 require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
563
564 // Status
565 status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
566
567 // Out
568 if (authorization && status == errAuthorizationSuccess) {
569 size_t len;
570 const void * data = xpc_dictionary_get_data(reply, AUTH_XPC_BLOB, &len);
571 require_action(data != NULL, done, status = errAuthorizationInternal);
572 require_action(len == sizeof(AuthorizationBlob), done, status = errAuthorizationInternal);
573
574 AuthorizationBlob * blob = (AuthorizationBlob*)calloc(1u, sizeof(AuthorizationBlob));
575 require_action(blob != NULL, done, status = errAuthorizationInternal);
576 *blob = *(AuthorizationBlob*)data;
577
578 *authorization = (AuthorizationRef)blob;
579 }
580
581 done:
582 xpc_release_safe(message);
583 xpc_release_safe(reply);
584 return status;
585 }
586
587 OSStatus AuthorizationFreeItemSet(AuthorizationItemSet *set)
588 {
589 FreeItemSet(set);
590 return errAuthorizationSuccess;
591 }
592
593 OSStatus AuthorizationEnableSmartCard(AuthorizationRef authRef, Boolean enable)
594 {
595 OSStatus status = errAuthorizationInternal;
596 xpc_object_t message = NULL;
597 xpc_object_t reply = NULL;
598 AuthorizationBlob *blob = NULL;
599
600 // Send
601 message = xpc_dictionary_create(NULL, NULL, 0);
602 require_action(message != NULL, done, status = errAuthorizationInternal);
603 require_action(authRef != NULL, done, status = errAuthorizationInvalidRef);
604 blob = (AuthorizationBlob *)authRef;
605 xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_ENABLE_SMARTCARD);
606 xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
607 xpc_dictionary_set_bool(message, AUTH_XPC_DATA, enable);
608
609 // Reply
610 xpc_connection_t conn = get_authorization_connection();
611 require_action(conn != NULL, done, status = errAuthorizationInternal);
612 reply = xpc_connection_send_message_with_reply_sync(conn, message);
613 require_action(reply != NULL, done, status = errAuthorizationInternal);
614 require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
615
616 status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
617
618 done:
619 xpc_release_safe(message);
620 xpc_release_safe(reply);
621 return status;
622 }
623
624
625 OSStatus AuthorizationRightGet(const char *rightName,
626 CFDictionaryRef *rightDefinition)
627 {
628 OSStatus status = errAuthorizationInternal;
629 xpc_object_t message = NULL;
630 xpc_object_t reply = NULL;
631
632 require_action(rightName != NULL, done, status = errAuthorizationInvalidPointer);
633
634 // Send
635 message = xpc_dictionary_create(NULL, NULL, 0);
636 require_action(message != NULL, done, status = errAuthorizationInternal);
637
638 xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_RIGHT_GET);
639 xpc_dictionary_set_string(message, AUTH_XPC_RIGHT_NAME, rightName);
640
641 // Reply
642 xpc_connection_t conn = get_authorization_connection();
643 require_action(conn != NULL, done, status = errAuthorizationInternal);
644 reply = xpc_connection_send_message_with_reply_sync(conn, message);
645 require_action(reply != NULL, done, status = errAuthorizationInternal);
646 require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
647
648 // Status
649 status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
650
651 // Out
652 if (rightDefinition && status == errAuthorizationSuccess) {
653 xpc_object_t value = xpc_dictionary_get_value(reply, AUTH_XPC_DATA);
654 require_action(value != NULL, done, status = errAuthorizationInternal);
655 require_action(xpc_get_type(value) == XPC_TYPE_DICTIONARY, done, status = errAuthorizationInternal);
656
657 CFTypeRef cfdict = _CFXPCCreateCFObjectFromXPCObject(value);
658 require_action(cfdict != NULL, done, status = errAuthorizationInternal);
659
660 *rightDefinition = cfdict;
661 }
662
663 done:
664 xpc_release_safe(message);
665 xpc_release_safe(reply);
666 return status;
667 }
668
669 OSStatus AuthorizationRightSet(AuthorizationRef authRef,
670 const char *rightName,
671 CFTypeRef rightDefinition,
672 CFStringRef descriptionKey,
673 CFBundleRef bundle,
674 CFStringRef tableName)
675 {
676 OSStatus status = errAuthorizationInternal;
677 xpc_object_t message = NULL;
678 xpc_object_t reply = NULL;
679 AuthorizationBlob *blob = NULL;
680 CFMutableDictionaryRef rightDict = NULL;
681 CFBundleRef clientBundle = bundle;
682
683 if (bundle) {
684 CFRetain(bundle);
685 }
686
687 require_action(rightDefinition != NULL, done, status = errAuthorizationInvalidPointer);
688 require_action(rightName != NULL, done, status = errAuthorizationInvalidPointer);
689 require_action(authRef != NULL, done, status = errAuthorizationInvalidRef);
690 blob = (AuthorizationBlob *)authRef;
691
692 // Send
693 message = xpc_dictionary_create(NULL, NULL, 0);
694 require_action(message != NULL, done, status = errAuthorizationInternal);
695
696 xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_RIGHT_SET);
697 xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
698 xpc_dictionary_set_string(message, AUTH_XPC_RIGHT_NAME, rightName);
699
700 // Create rightDict
701 if (CFGetTypeID(rightDefinition) == CFStringGetTypeID()) {
702 rightDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
703 require_action(rightDict != NULL, done, status = errAuthorizationInternal);
704
705 CFDictionarySetValue(rightDict, CFSTR(kAuthorizationRightRule), rightDefinition);
706
707 } else if (CFGetTypeID(rightDefinition) == CFDictionaryGetTypeID()) {
708 rightDict = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, rightDefinition);
709 require_action(rightDict != NULL, done, status = errAuthorizationInternal);
710
711 } else {
712 status = errAuthorizationInvalidPointer;
713 goto done;
714 }
715
716 // Create locDict
717 if (descriptionKey) {
718 CFMutableDictionaryRef locDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
719 require_action(locDict != NULL, done, status = errAuthorizationInternal);
720
721 if (clientBundle == NULL) {
722 clientBundle = CFBundleGetMainBundle();
723 CFRetain(clientBundle);
724 }
725
726 if (clientBundle) {
727 CFArrayRef bundleLocalizations = CFBundleCopyBundleLocalizations(clientBundle);
728 if (bundleLocalizations) {
729 // for every CFString in localizations do
730 CFIndex locIndex, allLocs = CFArrayGetCount(bundleLocalizations);
731 for (locIndex = 0; locIndex < allLocs; locIndex++)
732 {
733 CFStringRef oneLocalization = (CFStringRef)CFArrayGetValueAtIndex(bundleLocalizations, locIndex);
734
735 if (!oneLocalization)
736 continue;
737
738 // @@@ no way to get "Localized" and "strings" as constants?
739 CFURLRef locURL = CFBundleCopyResourceURLForLocalization(clientBundle, tableName ? tableName : CFSTR("Localizable"), CFSTR("strings"), NULL /*subDirName*/, oneLocalization);
740
741 if (!locURL)
742 continue;
743
744 CFDataRef tableData = NULL;
745 SInt32 errCode;
746 CFStringRef errStr = NULL;
747 CFPropertyListRef stringTable = NULL;
748
749 CFURLCreateDataAndPropertiesFromResource(CFGetAllocator(clientBundle), locURL, &tableData, NULL, NULL, &errCode);
750 CFReleaseSafe(locURL);
751 if (errCode)
752 {
753 CFReleaseSafe(tableData);
754 continue;
755 }
756
757 stringTable = CFPropertyListCreateFromXMLData(CFGetAllocator(clientBundle), tableData, kCFPropertyListImmutable, &errStr);
758 CFReleaseSafe(errStr);
759 CFReleaseSafe(tableData);
760
761 CFStringRef value = (CFStringRef)CFDictionaryGetValue(stringTable, descriptionKey);
762 if (value == NULL || CFEqual(value, CFSTR(""))) {
763 CFReleaseSafe(stringTable);
764 continue;
765 } else {
766 // oneLocalization/value into our dictionary
767 CFDictionarySetValue(locDict, oneLocalization, value);
768 CFReleaseSafe(stringTable);
769 }
770 }
771 CFReleaseSafe(bundleLocalizations);
772 }
773 }
774
775 // add the description as the default localization into the dictionary
776 CFDictionarySetValue(locDict, CFSTR(""), descriptionKey);
777
778 // stuff localization table into right definition
779 CFDictionarySetValue(rightDict, CFSTR(kAuthorizationRuleParameterDefaultPrompt), locDict);
780 CFReleaseSafe(locDict);
781 }
782
783 xpc_object_t value = _CFXPCCreateXPCObjectFromCFObject(rightDict);
784 xpc_dictionary_set_value(message, AUTH_XPC_DATA, value);
785 xpc_release_safe(value);
786
787 // Reply
788 xpc_connection_t conn = get_authorization_connection();
789 require_action(conn != NULL, done, status = errAuthorizationInternal);
790 reply = xpc_connection_send_message_with_reply_sync(conn, message);
791 require_action(reply != NULL, done, status = errAuthorizationInternal);
792 require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
793
794 // Status
795 status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
796
797 done:
798 CFReleaseSafe(clientBundle);
799 CFReleaseSafe(rightDict);
800 xpc_release_safe(message);
801 xpc_release_safe(reply);
802 return status;
803 }
804
805 OSStatus AuthorizationRightRemove(AuthorizationRef authorization,
806 const char *rightName)
807 {
808 OSStatus status = errAuthorizationInternal;
809 xpc_object_t message = NULL;
810 xpc_object_t reply = NULL;
811 AuthorizationBlob *blob = NULL;
812
813 require_action(rightName != NULL, done, status = errAuthorizationInvalidPointer);
814 require_action(authorization != NULL, done, status = errAuthorizationInvalidRef);
815 blob = (AuthorizationBlob *)authorization;
816
817 // Send
818 message = xpc_dictionary_create(NULL, NULL, 0);
819 require_action(message != NULL, done, status = errAuthorizationInternal);
820
821 xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_RIGHT_REMOVE);
822 xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
823 xpc_dictionary_set_string(message, AUTH_XPC_RIGHT_NAME, rightName);
824
825 // Reply
826 xpc_connection_t conn = get_authorization_connection();
827 require_action(conn != NULL, done, status = errAuthorizationInternal);
828 reply = xpc_connection_send_message_with_reply_sync(conn, message);
829 require_action(reply != NULL, done, status = errAuthorizationInternal);
830 require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
831
832 // Status
833 status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
834
835 done:
836 xpc_release_safe(message);
837 xpc_release_safe(reply);
838 return status;
839 }
840
841 OSStatus AuthorizationCopyPreloginUserDatabase(const char * _Nullable const volumeUuid, const UInt32 flags, CFArrayRef _Nonnull * _Nonnull output)
842 {
843 OSStatus status = errAuthorizationInternal;
844 xpc_object_t message = NULL;
845 xpc_object_t reply = NULL;
846
847 require_action(output != NULL, done, status = errAuthorizationInvalidRef);
848
849 // Send
850 message = xpc_dictionary_create(NULL, NULL, 0);
851 require_action(message != NULL, done, status = errAuthorizationInternal);
852 xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_COPY_PRELOGIN_USERDB);
853 if (volumeUuid) {
854 xpc_dictionary_set_string(message, AUTH_XPC_TAG, volumeUuid);
855 }
856 xpc_dictionary_set_uint64(message, AUTH_XPC_FLAGS, flags);
857
858 // Reply
859 xpc_connection_t conn = get_authorization_connection();
860 require_action(conn != NULL, done, status = errAuthorizationInternal);
861 reply = xpc_connection_send_message_with_reply_sync(conn, message);
862 require_action(reply != NULL, done, status = errAuthorizationInternal);
863 require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
864
865 status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
866
867 // fill the output
868 if (status == errAuthorizationSuccess) {
869 *output = _CFXPCCreateCFObjectFromXPCObject(xpc_dictionary_get_value(reply, AUTH_XPC_DATA));
870 }
871
872 done:
873 xpc_release_safe(message);
874 xpc_release_safe(reply);
875 return status;
876 }