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