1 /* Copyright (c) 2012-2013 Apple Inc. All Rights Reserved. */ 
   9 #include "authutilities.h" 
  11 #include "mechanism.h" 
  13 #include "authitems.h" 
  14 #include "debugging.h" 
  16 #include "connection.h" 
  18 #include <bsm/libbsm.h> 
  19 #include <Security/Authorization.h> 
  20 #include <Security/AuthorizationPriv.h> 
  21 #include <Security/AuthorizationTagsPriv.h> 
  22 #include <Security/AuthorizationPlugin.h> 
  23 #include <xpc/private.h> 
  24 #include <dispatch/dispatch.h> 
  25 #include <CoreFoundation/CoreFoundation.h> 
  26 #include <CoreFoundation/CFXPCBridge.h> 
  27 #include <IOKit/IOMessage.h> 
  28 #include <IOKit/pwr_mgt/IOPMLib.h> 
  29 #include <IOKit/pwr_mgt/IOPMLibPrivate.h> 
  31 #define MAX_PROCESS_RIGHTS   100 
  33 static CFMutableDictionaryRef gProcessMap 
= NULL
; 
  34 static CFMutableDictionaryRef gSessionMap 
= NULL
; 
  35 static CFMutableDictionaryRef gAuthTokenMap 
= NULL
; 
  36 static authdb_t gDatabase 
= NULL
; 
  38 static dispatch_queue_t power_queue
; 
  39 static bool gInDarkWake 
= false; 
  40 static IOPMConnection gIOPMconn 
= NULL
; 
  41 static bool gXPCTransaction 
= false; 
  43 static dispatch_queue_t
 
  44 get_server_dispatch_queue() 
  46     static dispatch_once_t onceToken
; 
  47     static dispatch_queue_t server_queue 
= NULL
; 
  49     dispatch_once(&onceToken
, ^{ 
  50         server_queue 
= dispatch_queue_create("com.apple.security.auth.server", DISPATCH_QUEUE_SERIAL
); 
  51         check(server_queue 
!= NULL
); 
  57 static Boolean 
_processEqualCallBack(const void *value1
, const void *value2
) 
  59     audit_info_s 
* info1 
= (audit_info_s
*)value1
; 
  60     audit_info_s 
* info2 
= (audit_info_s
*)value2
; 
  61     if (info1
->pid 
== info2
->pid
) { 
  62         if (info1
->tid 
== info2
->tid
) { 
  69 static CFHashCode 
_processHashCallBack(const void *value
) 
  71     audit_info_s 
* info 
= (audit_info_s
*)value
; 
  72     uint64_t crc 
= crc64_init(); 
  73     crc 
= crc64_update(crc
, &info
->pid
, sizeof(info
->pid
)); 
  74     crc 
= crc64_update(crc
, &info
->tid
, sizeof(info
->tid
)); 
  75     crc 
= crc64_final(crc
); 
  76     return (CFHashCode
)crc
; 
  79 static const CFDictionaryKeyCallBacks kProcessMapKeyCallBacks 
= { 
  83     .copyDescription 
= NULL
, 
  84     .equal 
= &_processEqualCallBack
, 
  85     .hash 
= &_processHashCallBack
 
  88 static Boolean 
_sessionEqualCallBack(const void *value1
, const void *value2
) 
  90     return (*(session_id_t
*)value1
) == (*(session_id_t
*)value2
); 
  93 static CFHashCode 
_sessionHashCallBack(const void *value
) 
  95     return (CFHashCode
)(*(session_id_t
*)(value
)); 
  98 static const CFDictionaryKeyCallBacks kSessionMapKeyCallBacks 
= { 
 102     .copyDescription 
= NULL
, 
 103     .equal 
= &_sessionEqualCallBack
, 
 104     .hash 
= &_sessionHashCallBack
 
 107 void server_cleanup() 
 109     CFRelease(gProcessMap
); 
 110     CFRelease(gSessionMap
); 
 111     CFRelease(gAuthTokenMap
); 
 113     IOPMConnectionSetDispatchQueue(gIOPMconn
, NULL
); 
 114     IOPMConnectionRelease(gIOPMconn
); 
 116     dispatch_queue_t queue 
= get_server_dispatch_queue(); 
 118         dispatch_release(queue
); 
 120     dispatch_release(power_queue
); 
 123 static void _IOMPCallBack(void * param AUTH_UNUSED
, IOPMConnection connection
, IOPMConnectionMessageToken token
, IOPMSystemPowerStateCapabilities capabilities
) 
 125     LOGV("server: IOMP powerstates %i", capabilities
); 
 126     if (capabilities 
& kIOPMSystemPowerStateCapabilityDisk
) 
 127         LOGV("server: disk"); 
 128     if (capabilities 
& kIOPMSystemPowerStateCapabilityNetwork
) 
 130     if (capabilities 
& kIOPMSystemPowerStateCapabilityAudio
) 
 131         LOGV("server: audio"); 
 132     if (capabilities 
& kIOPMSystemPowerStateCapabilityVideo
) 
 133         LOGV("server: video"); 
 135     /* if cpu and no display -> in DarkWake */ 
 136     LOGD("server: DarkWake check current=%i==%i", (capabilities 
& (kIOPMSystemPowerStateCapabilityCPU
|kIOPMSystemPowerStateCapabilityVideo
)), kIOPMSystemPowerStateCapabilityCPU
); 
 137     if ((capabilities 
& (kIOPMSystemPowerStateCapabilityCPU
|kIOPMSystemPowerStateCapabilityVideo
)) == kIOPMSystemPowerStateCapabilityCPU
) { 
 138         LOGV("server: enter DarkWake"); 
 140     } else if (gInDarkWake
) { 
 141         LOGV("server: exit DarkWake"); 
 145     (void)IOPMConnectionAcknowledgeEvent(connection
, token
); 
 151 _setupDarkWake(void *__unused ctx
) 
 155     IOPMConnectionCreate(CFSTR("IOPowerWatcher"), 
 156                          kIOPMSystemPowerStateCapabilityDisk
 
 157                          | kIOPMSystemPowerStateCapabilityNetwork
 
 158                          | kIOPMSystemPowerStateCapabilityAudio
 
 159                          | kIOPMSystemPowerStateCapabilityVideo
, 
 162     ret 
= IOPMConnectionSetNotification(gIOPMconn
, NULL
, _IOMPCallBack
); 
 163     if (ret 
!= kIOReturnSuccess
) 
 166     IOPMConnectionSetDispatchQueue(gIOPMconn
, power_queue
); 
 168     IOPMScheduleUserActiveChangedNotification(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^(bool active
) { 
 175 bool server_in_dark_wake() 
 180 authdb_t 
server_get_database() 
 185 static void _setupAuditSessionMonitor() 
 187     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^{ 
 188         au_sdev_handle_t 
*dev 
= au_sdev_open(AU_SDEVF_ALLSESSIONS
); 
 190         auditinfo_addr_t aia
; 
 193             LOGE("server: could not open %s %d", AUDIT_SDEV_PATH
, errno
); 
 198             if (0 != au_sdev_read_aia(dev
, &event
, &aia
)) { 
 199                 LOGE("server: au_sdev_read_aia failed: %d", errno
); 
 202             LOGD("server: au_sdev_handle_t event=%i, session=%i", event
, aia
.ai_asid
); 
 203             if (event 
== AUE_SESSION_END
) { 
 204                 dispatch_async(get_server_dispatch_queue(), ^{ 
 205                     LOGV("server: session %i destroyed", aia
.ai_asid
); 
 206                     CFDictionaryRemoveValue(gSessionMap
, &aia
.ai_asid
); 
 214 static void _setupSignalHandlers() 
 216     signal(SIGTERM
, SIG_IGN
); 
 217     static dispatch_source_t sigtermHandler
; 
 218     sigtermHandler 
= dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL
, SIGTERM
, 0, get_server_dispatch_queue()); 
 219     if (sigtermHandler
) { 
 220         dispatch_source_set_event_handler(sigtermHandler
, ^{ 
 222             // should we clean up any state? 
 225         dispatch_resume(sigtermHandler
); 
 229 OSStatus 
server_init(void) 
 231     OSStatus status 
= errAuthorizationSuccess
; 
 233     auditinfo_addr_t info
; 
 234     memset(&info
, 0, sizeof(info
)); 
 235     getaudit_addr(&info
, sizeof(info
)); 
 236     LOGV("server: uid=%i, sid=%i", info
.ai_auid
, info
.ai_asid
); 
 238     require_action(get_server_dispatch_queue() != NULL
, done
, status 
= errAuthorizationInternal
); 
 240     gProcessMap 
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kProcessMapKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
 241     require_action(gProcessMap 
!= NULL
, done
, status 
= errAuthorizationInternal
); 
 243     gSessionMap 
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kSessionMapKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
 244     require_action(gSessionMap 
!= NULL
, done
, status 
= errAuthorizationInternal
); 
 246     gAuthTokenMap 
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kAuthTokenKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
 247     require_action(gAuthTokenMap 
!= NULL
, done
, status 
= errAuthorizationInternal
); 
 249     gDatabase 
= authdb_create(); 
 250     require_action(gDatabase 
!= NULL
, done
, status 
= errAuthorizationInternal
); 
 252     // check to see if we have an updates 
 253     authdb_connection_t dbconn 
= authdb_connection_acquire(gDatabase
); 
 254     authdb_maintenance(dbconn
); 
 255     authdb_connection_release(&dbconn
); 
 257     power_queue 
= dispatch_queue_create("com.apple.security.auth.power", DISPATCH_QUEUE_SERIAL
); 
 258     require_action(power_queue 
!= NULL
, done
, status 
= errAuthorizationInternal
); 
 259     dispatch_async_f(power_queue
, NULL
, _setupDarkWake
); 
 261     _setupAuditSessionMonitor(); 
 262     _setupSignalHandlers(); 
 268 static void _server_parse_audit_token(audit_token_t 
* token
, audit_info_s 
* info
) 
 271         memset(info
, 0, sizeof(*info
)); 
 273         memset(&tid
, 0, sizeof(tid
)); 
 274         audit_token_to_au32(*token
, &info
->auid
, &info
->euid
, 
 275                             &info
->egid
, &info
->ruid
, &info
->rgid
, 
 276                             &info
->pid
, &info
->asid
, &tid
); 
 277         info
->tid 
= tid
.port
; 
 278         info
->opaqueToken 
= *token
; 
 283 server_register_connection(xpc_connection_t connection
) 
 285     __block connection_t conn 
= NULL
; 
 286     __block session_t session 
= NULL
; 
 287     __block process_t proc 
= NULL
; 
 288     __block CFIndex conn_count 
= 0; 
 290     require(connection 
!= NULL
, done
); 
 292     audit_token_t auditToken
; 
 294     xpc_connection_get_audit_token(connection
, &auditToken
); 
 295     _server_parse_audit_token(&auditToken
, &info
); 
 298     dispatch_sync(get_server_dispatch_queue(), ^{ 
 299         session 
= (session_t
)CFDictionaryGetValue(gSessionMap
, &info
.asid
); 
 303             session 
= session_create(info
.asid
); 
 304             CFDictionarySetValue(gSessionMap
, session_get_key(session
), session
); 
 307         proc 
= (process_t
)CFDictionaryGetValue(gProcessMap
, &info
); 
 313             conn 
= connection_create(proc
); 
 314             conn_count 
= process_add_connection(proc
, conn
); 
 316             proc 
= process_create(&info
, session
); 
 318                 conn 
= connection_create(proc
); 
 319                 conn_count 
= process_add_connection(proc
, conn
); 
 320                 session_add_process(session
, proc
); 
 321                 CFDictionarySetValue(gProcessMap
, process_get_key(proc
), proc
); 
 325         if (!gXPCTransaction
) { 
 326             xpc_transaction_begin(); 
 327             gXPCTransaction 
= true; 
 331     LOGV("server[%i]: registered connection (total=%li)", info
.pid
, conn_count
); 
 334     CFReleaseSafe(session
); 
 340 server_unregister_connection(connection_t conn
) 
 342     assert(conn
); // marked non-null 
 343     process_t proc 
= connection_get_process(conn
); 
 345     dispatch_sync(get_server_dispatch_queue(), ^{ 
 346         CFIndex connectionCount 
= process_get_connection_count(proc
); 
 347         LOGV("server[%i]: unregistered connection (total=%li)", process_get_pid(proc
), connectionCount
); 
 349         if (connectionCount 
== 1) { 
 350             CFDictionaryRemoveValue(gProcessMap
, process_get_key(proc
)); 
 353         if (CFDictionaryGetCount(gProcessMap
) == 0) { 
 354             xpc_transaction_end(); 
 355             gXPCTransaction 
= false; 
 358     // move the destruction of the connection/process off the server queue 
 363 server_register_auth_token(auth_token_t auth
) 
 365     assert(auth
); // marked non-null 
 366     dispatch_sync(get_server_dispatch_queue(), ^{ 
 367         LOGV("server: registering auth %p", auth
); 
 368         CFDictionarySetValue(gAuthTokenMap
, auth_token_get_key(auth
), auth
); 
 369         auth_token_set_state(auth
, auth_token_state_registered
); 
 374 server_unregister_auth_token(auth_token_t auth
) 
 377     AuthorizationBlob blob 
= *(AuthorizationBlob
*)auth_token_get_key(auth
); 
 378     dispatch_async(get_server_dispatch_queue(), ^{ 
 379         LOGV("server: unregistering auth %p", auth
); 
 380         CFDictionaryRemoveValue(gAuthTokenMap
, &blob
); 
 385 server_find_copy_auth_token(AuthorizationBlob 
* blob
) 
 387     assert(blob
); // marked non-null 
 388     __block auth_token_t auth 
= NULL
; 
 389     dispatch_sync(get_server_dispatch_queue(), ^{ 
 390         auth 
= (auth_token_t
)CFDictionaryGetValue(gAuthTokenMap
, blob
); 
 399 server_find_copy_session(session_id_t sid
, bool create
) 
 401     __block session_t session 
= NULL
; 
 403     dispatch_sync(get_server_dispatch_queue(), ^{ 
 404         session 
= (session_t
)CFDictionaryGetValue(gSessionMap
, &sid
); 
 408             session 
= session_create(sid
); 
 410                 CFDictionarySetValue(gSessionMap
, session_get_key(session
), session
); 
 422 _process_find_copy_auth_token_from_xpc(process_t proc
, xpc_object_t message
, auth_token_t 
* auth_out
) 
 424     OSStatus status 
= errAuthorizationSuccess
; 
 425     require_action(auth_out 
!= NULL
, done
, status 
= errAuthorizationInternal
); 
 428     AuthorizationBlob 
* blob 
= (AuthorizationBlob 
*)xpc_dictionary_get_data(message
, AUTH_XPC_BLOB
, &len
); 
 429     require_action(blob 
!= NULL
, done
, status 
= errAuthorizationInvalidRef
); 
 430     require_action(len 
== sizeof(AuthorizationBlob
), done
, status 
= errAuthorizationInvalidRef
); 
 432     auth_token_t auth 
= process_find_copy_auth_token(proc
, blob
); 
 433     require_action(auth 
!= NULL
, done
, status 
= errAuthorizationInvalidRef
); 
 436     LOGV("server[%i]: authtoken lookup %#x%x %p", process_get_pid(proc
), blob
->data
[1],blob
->data
[0], auth
); 
 438     LOGV("server[%i]: authtoken lookup %p", process_get_pid(proc
), auth
); 
 447 static OSStatus 
_server_authorize(connection_t conn
, auth_token_t auth
, AuthorizationFlags flags
, auth_rights_t rights
, auth_items_t environment
, engine_t 
* engine_out
) 
 449     __block OSStatus status 
= errAuthorizationDenied
; 
 450     engine_t engine 
= NULL
; 
 452     require_action(conn
, done
, status 
= errAuthorizationInternal
); 
 454     engine 
= engine_create(conn
, auth
); 
 455     require_action(engine
, done
, status 
= errAuthorizationInternal
); 
 457     if (flags 
& kAuthorizationFlagInteractionAllowed
) { 
 458         dispatch_sync(connection_get_dispatch_queue(conn
), ^{ 
 459             connection_set_engine(conn
, engine
); 
 460             status 
= engine_authorize(engine
, rights
, environment
, flags
); 
 461             connection_set_engine(conn
, NULL
); 
 464         status 
= engine_authorize(engine
, rights
, environment
, flags
); 
 470             *engine_out 
= engine
; 
 478 // IN:  AUTH_XPC_RIGHTS, AUTH_XPC_ENVIRONMENT, AUTH_XPC_FLAGS 
 479 // OUT: AUTH_XPC_BLOB 
 481 authorization_create(connection_t conn
, xpc_object_t message
, xpc_object_t reply
) 
 483     OSStatus status 
= errAuthorizationDenied
; 
 485     process_t proc 
= connection_get_process(conn
); 
 488     auth_rights_t rights 
= auth_rights_create_with_xpc(xpc_dictionary_get_value(message
, AUTH_XPC_RIGHTS
)); 
 489     auth_items_t environment 
= auth_items_create_with_xpc(xpc_dictionary_get_value(message
, AUTH_XPC_ENVIRONMENT
)); 
 490     AuthorizationFlags flags 
= (AuthorizationFlags
)xpc_dictionary_get_uint64(message
, AUTH_XPC_FLAGS
); 
 492     // Create Authorization Token 
 493     auth_token_t auth 
= auth_token_create(proc
, flags 
& kAuthorizationFlagLeastPrivileged
); 
 494     require_action(auth 
!= NULL
, done
, status 
= errAuthorizationInternal
); 
 496     if (!(flags 
& kAuthorizationFlagNoData
)) { 
 497         process_add_auth_token(proc
,auth
); 
 500     status 
= _server_authorize(conn
, auth
, flags
, rights
, environment
, NULL
); 
 501     require_noerr(status
, done
); 
 504     xpc_dictionary_set_data(reply
, AUTH_XPC_BLOB
, auth_token_get_blob(auth
), sizeof(AuthorizationBlob
)); 
 507     CFReleaseSafe(rights
); 
 508     CFReleaseSafe(environment
); 
 513 // IN:  AUTH_XPC_DATA, AUTH_XPC_ENVIRONMENT, AUTH_XPC_FLAGS 
 514 // OUT: AUTH_XPC_BLOB 
 515 OSStatus 
authorization_create_with_audit_token(connection_t conn
, xpc_object_t message
, xpc_object_t reply
) 
 517     OSStatus status 
= errAuthorizationDenied
; 
 518     auth_token_t auth 
= NULL
; 
 520     process_t proc 
= connection_get_process(conn
); 
 521     require(process_get_uid(proc
) == 0, done
);  //only root can use this call 
 525     const char * data 
= xpc_dictionary_get_data(message
, AUTH_XPC_DATA
, &len
); 
 526     require(data 
!= NULL
, done
); 
 527     require(len 
== sizeof(audit_token_t
), done
); 
 529 //    auth_items_t environment = auth_items_create_with_xpc(xpc_dictionary_get_value(message, AUTH_XPC_ENVIRONMENT)); 
 530     AuthorizationFlags flags 
= (AuthorizationFlags
)xpc_dictionary_get_uint64(message
, AUTH_XPC_FLAGS
); 
 532     audit_info_s auditInfo
; 
 533     _server_parse_audit_token((audit_token_t
*)data
, &auditInfo
); 
 535     // Create Authorization Token 
 536     auth 
= auth_token_create(proc
, flags 
& kAuthorizationFlagLeastPrivileged
); 
 537     require_action(auth 
!= NULL
, done
, status 
= errAuthorizationInternal
); 
 539     process_add_auth_token(proc
,auth
); 
 542     xpc_dictionary_set_data(reply
, AUTH_XPC_BLOB
, auth_token_get_blob(auth
), sizeof(AuthorizationBlob
)); 
 545 //    CFReleaseSafe(environment); 
 550 // IN:  AUTH_XPC_BLOB, AUTH_XPC_FLAGS 
 553 authorization_free(connection_t conn
, xpc_object_t message
, xpc_object_t reply AUTH_UNUSED
) 
 555     OSStatus status 
= errAuthorizationSuccess
; 
 556     AuthorizationFlags flags 
= 0; 
 557     process_t proc 
= connection_get_process(conn
); 
 559     auth_token_t auth 
= NULL
; 
 560     status 
= _process_find_copy_auth_token_from_xpc(proc
, message
, &auth
); 
 561     require_noerr(status
, done
); 
 563     flags 
= (AuthorizationFlags
)xpc_dictionary_get_uint64(message
, AUTH_XPC_FLAGS
); 
 565     if (flags 
& kAuthorizationFlagDestroyRights
) { 
 566         auth_token_credentials_iterate(auth
, ^bool(credential_t cred
) { 
 567             credential_invalidate(cred
); 
 568             LOGV("engine[%i]: invalidating %scredential %s (%i) from authorization (%p)", connection_get_pid(conn
), credential_get_shared(cred
) ? "shared " : "", credential_get_name(cred
), credential_get_uid(cred
), auth
); 
 572         session_credentials_purge(auth_token_get_session(auth
)); 
 575     process_remove_auth_token(proc
, auth
, flags
); 
 579     LOGV("server[%i]: AuthorizationFree %d (flags:%x)", connection_get_pid(conn
), (int)status
, (unsigned int)flags
); 
 583 // IN:  AUTH_XPC_BLOB, AUTH_XPC_RIGHTS, AUTH_XPC_ENVIRONMENT, AUTH_XPC_FLAGS 
 584 // OUT: AUTH_XPC_OUT_ITEMS 
 586 authorization_copy_rights(connection_t conn
, xpc_object_t message
, xpc_object_t reply
) 
 588     OSStatus status 
= errAuthorizationDenied
; 
 589     engine_t engine 
= NULL
; 
 591     process_t proc 
= connection_get_process(conn
); 
 594     auth_rights_t rights 
= auth_rights_create_with_xpc(xpc_dictionary_get_value(message
, AUTH_XPC_RIGHTS
)); 
 595     auth_items_t environment 
= auth_items_create_with_xpc(xpc_dictionary_get_value(message
, AUTH_XPC_ENVIRONMENT
)); 
 596     AuthorizationFlags flags 
= (AuthorizationFlags
)xpc_dictionary_get_uint64(message
, AUTH_XPC_FLAGS
); 
 598     auth_token_t auth 
= NULL
; 
 599     status 
= _process_find_copy_auth_token_from_xpc(proc
, message
, &auth
); 
 600     require_noerr(status
, done
); 
 601     require_noerr_action_quiet(status
, done
, LOGE("copy_rights: no auth token")); 
 603     status 
= _server_authorize(conn
, auth
, flags
, rights
, environment
, &engine
); 
 604         require_noerr_action_quiet(status
, done
, LOGE("copy_rights: _server_authorize failed")); 
 607     xpc_object_t outItems 
= auth_rights_export_xpc(engine_get_granted_rights(engine
)); 
 608     xpc_dictionary_set_value(reply
, AUTH_XPC_OUT_ITEMS
, outItems
); 
 609     xpc_release_safe(outItems
); 
 612     CFReleaseSafe(rights
); 
 613     CFReleaseSafe(environment
); 
 615     CFReleaseSafe(engine
); 
 620 // IN:  AUTH_XPC_BLOB, AUTH_XPC_TAG 
 621 // OUT: AUTH_XPC_OUT_ITEMS 
 623 authorization_copy_info(connection_t conn
, xpc_object_t message
, xpc_object_t reply
) 
 626     OSStatus status 
= errAuthorizationSuccess
; 
 627     auth_items_t items 
= NULL
; 
 628     const char * tag 
= NULL
; 
 630     process_t proc 
= connection_get_process(conn
); 
 632     auth_token_t auth 
= NULL
; 
 633     status 
= _process_find_copy_auth_token_from_xpc(proc
, message
, &auth
); 
 634     require_noerr(status
, done
); 
 636     items 
= auth_items_create(); 
 638     tag 
= xpc_dictionary_get_string(message
, AUTH_XPC_TAG
); 
 639     LOGV("server[%i]: requested tag: %s", connection_get_pid(conn
), tag 
? tag 
: "(all)"); 
 642                 const void * data 
= auth_items_get_data_with_flags(auth_token_get_context(auth
), tag
, &len
, kAuthorizationContextFlagExtractable
); 
 644                         auth_items_set_data(items
, tag
, data
, len
); 
 646                 auth_items_copy_with_flags(items
, auth_token_get_context(auth
), kAuthorizationContextFlagExtractable
); 
 650     LOGV("server[%i]: Dumping requested AuthRef items", connection_get_pid(conn
)); 
 655     xpc_object_t outItems 
= auth_items_export_xpc(items
); 
 656     xpc_dictionary_set_value(reply
, AUTH_XPC_OUT_ITEMS
, outItems
); 
 657     xpc_release_safe(outItems
); 
 660     CFReleaseSafe(items
); 
 662     LOGV("server[%i]: AuthorizationCopyInfo %i", connection_get_pid(conn
), (int) status
); 
 667 // OUT: AUTH_XPC_EXTERNAL 
 669 authorization_make_external_form(connection_t conn
, xpc_object_t message
, xpc_object_t reply
) 
 671     OSStatus status 
= errAuthorizationSuccess
; 
 673     process_t proc 
= connection_get_process(conn
); 
 675     auth_token_t auth 
= NULL
; 
 676     status 
= _process_find_copy_auth_token_from_xpc(proc
, message
, &auth
); 
 677     require_noerr(status
, done
); 
 679     AuthorizationExternalForm exForm
; 
 680     AuthorizationExternalBlob 
* exBlob 
= (AuthorizationExternalBlob 
*)&exForm
; 
 681     memset(&exForm
, 0, sizeof(exForm
)); 
 683     exBlob
->blob 
= *auth_token_get_blob(auth
); 
 684     exBlob
->session 
= process_get_session_id(proc
); 
 686     xpc_dictionary_set_data(reply
, AUTH_XPC_EXTERNAL
, &exForm
, sizeof(exForm
)); 
 687     server_register_auth_token(auth
); 
 691     LOGV("server[%i]: AuthorizationMakeExternalForm %d", connection_get_pid(conn
), (int)status
); 
 695 // IN:  AUTH_XPC_EXTERNAL 
 696 // OUT: AUTH_XPC_BLOB 
 698 authorization_create_from_external_form(connection_t conn
, xpc_object_t message
, xpc_object_t reply
) 
 700     OSStatus status 
= errAuthorizationSuccess
; 
 701     auth_token_t auth 
= NULL
; 
 703     process_t proc 
= connection_get_process(conn
); 
 706     AuthorizationExternalForm 
* exForm 
= (AuthorizationExternalForm 
*)xpc_dictionary_get_data(message
, AUTH_XPC_EXTERNAL
, &len
); 
 707     require_action(exForm 
!= NULL
, done
, status 
= errAuthorizationInternal
); 
 708     require_action(len 
== sizeof(AuthorizationExternalForm
), done
, status 
= errAuthorizationInvalidRef
); 
 710     AuthorizationExternalBlob 
* exBlob 
= (AuthorizationExternalBlob 
*)exForm
; 
 711     auth 
= server_find_copy_auth_token(&exBlob
->blob
); 
 712     require_action(auth 
!= NULL
, done
, status 
= errAuthorizationDenied
); 
 714     process_add_auth_token(proc
, auth
); 
 715     xpc_dictionary_set_data(reply
, AUTH_XPC_BLOB
, auth_token_get_blob(auth
), sizeof(AuthorizationBlob
)); 
 719     LOGV("server[%i]: AuthorizationCreateFromExternalForm %d", connection_get_pid(conn
), (int)status
); 
 723 // IN:  AUTH_XPC_RIGHT_NAME 
 724 // OUT: AUTH_XPC_DATA 
 726 authorization_right_get(connection_t conn AUTH_UNUSED
, xpc_object_t message
, xpc_object_t reply
) 
 728     OSStatus status 
= errAuthorizationDenied
; 
 730     CFTypeRef cfdict 
= NULL
; 
 731     xpc_object_t xpcdict 
= NULL
; 
 733     authdb_connection_t dbconn 
= authdb_connection_acquire(server_get_database()); 
 734     rule 
= rule_create_with_string(xpc_dictionary_get_string(message
, AUTH_XPC_RIGHT_NAME
), dbconn
); 
 735     require(rule 
!= NULL
, done
); 
 736     require(rule_get_id(rule
) != 0, done
); 
 738     cfdict 
= rule_copy_to_cfobject(rule
, dbconn
); 
 739     require(cfdict 
!= NULL
, done
); 
 741     xpcdict 
= _CFXPCCreateXPCObjectFromCFObject(cfdict
); 
 742     require(xpcdict 
!= NULL
, done
); 
 745     xpc_dictionary_set_value(reply
, AUTH_XPC_DATA
, xpcdict
); 
 747     status 
= errAuthorizationSuccess
; 
 750     authdb_connection_release(&dbconn
); 
 751     CFReleaseSafe(cfdict
); 
 752     xpc_release_safe(xpcdict
); 
 754     LOGV("server[%i]: AuthorizationRightGet %d", connection_get_pid(conn
), (int)status
); 
 758 static bool _prompt_for_modifications(process_t __unused proc
, rule_t __unused rule
) 
 760 //    <rdar://problem/13853228> will put back it back at some later date 
 761 //    SecRequirementRef ruleReq = rule_get_requirement(rule); 
 763 //    if (ruleReq && process_verify_requirment(proc, ruleReq)) { 
 770 static CFIndex 
_get_mechanism_index(CFArrayRef mechanisms
, CFStringRef m_name
) 
 773     require(mechanisms
, done
); 
 775     CFIndex c 
= CFArrayGetCount(mechanisms
); 
 776     CFStringRef i_name 
= NULL
; 
 777     for (CFIndex i 
= 0; i 
< c
; ++i
) 
 779         i_name 
= CFArrayGetValueAtIndex(mechanisms
, i
); 
 780         if (i_name 
&& (CFGetTypeID(m_name
) == CFStringGetTypeID())) { 
 781             if (CFStringCompare(i_name
, m_name
, kCFCompareCaseInsensitive
) == kCFCompareEqualTo
) { 
 792 static bool _update_rule_mechanism(authdb_connection_t dbconn
, const char * rule_name
, CFStringRef mechanism_name
, CFStringRef insert_after_name
, bool remove
) 
 794     bool updated 
= false; 
 796     rule_t update_rule 
= NULL
; 
 797     CFMutableDictionaryRef cfdict 
= NULL
; 
 798     CFStringRef update_name 
= NULL
; 
 800     require(mechanism_name
, done
); 
 802     rule 
= rule_create_with_string(rule_name
, dbconn
); 
 803     require(rule_get_id(rule
) != 0, done
); // rule doesn't exist in the database 
 805     cfdict 
= rule_copy_to_cfobject(rule
, dbconn
); 
 806     require(cfdict 
!= NULL
, done
); 
 808     CFMutableArrayRef mechanisms 
= NULL
; 
 809     bool res 
= CFDictionaryGetValueIfPresent(cfdict
, CFSTR(kAuthorizationRuleParameterMechanisms
), (void*)&mechanisms
); 
 810     require(res 
== true, done
); 
 815         index 
= _get_mechanism_index(mechanisms
, mechanism_name
); 
 817         if (insert_after_name
) { 
 818             if ((index 
= _get_mechanism_index(mechanisms
, insert_after_name
)) != -1) { 
 821                 index 
= 0; // if we couldn't find the index add it to the begining 
 830             CFArrayRemoveValueAtIndex(mechanisms
, index
); 
 832             if (index 
< CFArrayGetCount(mechanisms
)) { 
 833                 require_action(CFStringCompare(CFArrayGetValueAtIndex(mechanisms
, index
), mechanism_name
, kCFCompareCaseInsensitive
) != kCFCompareEqualTo
, done
, updated 
= true); 
 835             CFArrayInsertValueAtIndex(mechanisms
, index
, mechanism_name
); 
 838         CFDictionarySetValue(cfdict
, CFSTR(kAuthorizationRuleParameterMechanisms
), mechanisms
); 
 841         update_name 
= CFStringCreateWithCString(kCFAllocatorDefault
, rule_name
, kCFStringEncodingUTF8
); 
 842         require(update_name
, done
); 
 843         update_rule 
= rule_create_with_plist(rule_get_type(rule
), update_name
, cfdict
, dbconn
); 
 844         require(update_rule
, done
); 
 846         require(rule_sql_commit(update_rule
, dbconn
, CFAbsoluteTimeGetCurrent(), NULL
), done
); 
 853     CFReleaseSafe(update_rule
); 
 854     CFReleaseSafe(cfdict
); 
 855     CFReleaseSafe(update_name
); 
 859 /// IN:  AUTH_XPC_BLOB, AUTH_XPC_INT64 
 862 authorization_enable_smartcard(connection_t conn
, xpc_object_t message
, xpc_object_t reply AUTH_UNUSED
) 
 864     const CFStringRef SMARTCARD_LINE 
= CFSTR("builtin:smartcard-sniffer,privileged"); 
 865     const CFStringRef BUILTIN_LINE 
= CFSTR("builtin:policy-banner"); 
 866     const char* SYSTEM_LOGIN_CONSOLE 
= "system.login.console"; 
 867     const char* AUTHENTICATE 
= "authenticate"; 
 869     __block OSStatus status 
= errAuthorizationSuccess
; 
 870     bool enable_smartcard 
= false; 
 871     authdb_connection_t dbconn 
= NULL
; 
 872     auth_token_t auth 
= NULL
; 
 873     auth_rights_t checkRight 
= NULL
; 
 875     process_t proc 
= connection_get_process(conn
); 
 877     status 
= _process_find_copy_auth_token_from_xpc(proc
, message
, &auth
); 
 878     require_noerr(status
, done
); 
 880     checkRight 
= auth_rights_create(); 
 881     auth_rights_add(checkRight
, "config.modify.smartcard"); 
 882     status 
= _server_authorize(conn
, auth
, kAuthorizationFlagDefaults 
| kAuthorizationFlagInteractionAllowed 
| kAuthorizationFlagExtendRights
, checkRight
, NULL
, NULL
); 
 883     require_noerr(status
, done
); 
 885     enable_smartcard 
= xpc_dictionary_get_bool(message
, AUTH_XPC_DATA
); 
 887     dbconn 
= authdb_connection_acquire(server_get_database()); 
 889     if (!_update_rule_mechanism(dbconn
, SYSTEM_LOGIN_CONSOLE
, SMARTCARD_LINE
, BUILTIN_LINE
, enable_smartcard 
? false : true)) { 
 890         status 
= errAuthorizationInternal
; 
 891         LOGE("server[%i]: smartcard: enable(%i) failed to update %s", connection_get_pid(conn
), enable_smartcard
, SYSTEM_LOGIN_CONSOLE
); 
 893     if (!_update_rule_mechanism(dbconn
, AUTHENTICATE
, SMARTCARD_LINE
, NULL
, enable_smartcard 
? false : true)) { 
 894         status 
= errAuthorizationInternal
; 
 895         LOGE("server[%i]: smartcard: enable(%i) failed to update %s", connection_get_pid(conn
), enable_smartcard
, AUTHENTICATE
); 
 898     authdb_checkpoint(dbconn
); 
 901     authdb_connection_release(&dbconn
); 
 902     CFReleaseSafe(checkRight
); 
 907 static int64_t _process_get_identifier_count(process_t proc
, authdb_connection_t conn
) 
 909     __block 
int64_t result 
= 0; 
 911     authdb_step(conn
, "SELECT COUNT(*) AS cnt FROM rules WHERE identifier = ? ", ^(sqlite3_stmt 
*stmt
) { 
 912         sqlite3_bind_text(stmt
, 1, process_get_identifier(proc
), -1, NULL
); 
 913     }, ^bool(auth_items_t data
) { 
 914         result 
= auth_items_get_int64(data
, "cnt"); 
 921 static int64_t _get_max_process_rights() 
 923     static dispatch_once_t onceToken
; 
 924     static int64_t max_rights 
= MAX_PROCESS_RIGHTS
; 
 926     //sudo defaults write /Library/Preferences/com.apple.authd max_process_rights -bool true 
 927     dispatch_once(&onceToken
, ^{ 
 928                 CFTypeRef max 
= (CFNumberRef
)CFPreferencesCopyValue(CFSTR("max_process_rights"), CFSTR(SECURITY_AUTH_NAME
), kCFPreferencesAnyUser
, kCFPreferencesCurrentHost
); 
 930         if (max 
&& CFGetTypeID(max
) == CFNumberGetTypeID()) { 
 931             CFNumberGetValue(max
, kCFNumberSInt64Type
, &max_rights
); 
 939 // IN:  AUTH_XPC_BLOB, AUTH_XPC_RIGHT_NAME, AUTH_XPC_DATA 
 942 authorization_right_set(connection_t conn
, xpc_object_t message
, xpc_object_t reply AUTH_UNUSED
) 
 944     __block OSStatus status 
= errAuthorizationDenied
; 
 945     __block engine_t engine 
= NULL
; 
 946     CFStringRef cf_rule_name 
= NULL
; 
 947     CFDictionaryRef cf_rule_dict 
= NULL
; 
 949     rule_t existingRule 
= NULL
; 
 950     authdb_connection_t dbconn 
= NULL
; 
 951     auth_token_t auth 
= NULL
; 
 952     bool force_modify 
= false; 
 953     RuleType rule_type 
= RT_RIGHT
; 
 954     const char * rule_name 
= NULL
; 
 955     bool auth_rule 
= false; 
 957     process_t proc 
= connection_get_process(conn
); 
 959     status 
= _process_find_copy_auth_token_from_xpc(proc
, message
, &auth
); 
 960     require_noerr(status
, done
); 
 962     require_action(xpc_dictionary_get_string(message
, AUTH_XPC_RIGHT_NAME
) != NULL
, done
, status 
= errAuthorizationInternal
); 
 963     require_action(xpc_dictionary_get_value(message
, AUTH_XPC_DATA
) != NULL
, done
, status 
= errAuthorizationInternal
); 
 965     rule_name 
= xpc_dictionary_get_string(message
, AUTH_XPC_RIGHT_NAME
); 
 966     require(rule_name 
!= NULL
, done
); 
 968     if (_compare_string(rule_name
, "authenticate")) { 
 973     cf_rule_name 
= CFStringCreateWithCString(kCFAllocatorDefault
, rule_name
, kCFStringEncodingUTF8
); 
 974     require(cf_rule_name 
!= NULL
, done
); 
 976     cf_rule_dict 
= _CFXPCCreateCFObjectFromXPCObject(xpc_dictionary_get_value(message
, AUTH_XPC_DATA
)); 
 977     require(cf_rule_dict 
!= NULL
, done
); 
 979     dbconn 
= authdb_connection_acquire(server_get_database()); 
 981     rule 
= rule_create_with_plist(rule_type
, cf_rule_name
, cf_rule_dict
, dbconn
); 
 982     if (process_get_uid(proc
) != 0) { 
 983         require_action(rule_get_extract_password(rule
) == false, done
, status 
= errAuthorizationDenied
; LOGE("server[%i]: AuthorizationRightSet not allowed to set extract-password. (denied)", connection_get_pid(conn
))); 
 986     // if rule doesn't currently exist then we have to check to see if they are over the Max. 
 987     if (rule_get_id(rule
) == 0) { 
 988         if (process_get_identifier(proc
) == NULL
) { 
 989             LOGE("server[%i]: AuthorizationRightSet required for process %s (missing code signature). To add rights to the Authorization database, your process must have a code signature.", connection_get_pid(conn
), process_get_code_url(proc
)); 
 992             int64_t process_rule_count 
= _process_get_identifier_count(proc
, dbconn
); 
 993             if ((process_rule_count 
>= _get_max_process_rights())) { 
 994                 if (!connection_get_syslog_warn(conn
)) { 
 995                     LOGE("server[%i]: AuthorizationRightSet Denied API abuse process %s already contains %lli rights.", connection_get_pid(conn
), process_get_code_url(proc
), _get_max_process_rights()); 
 996                     connection_set_syslog_warn(conn
); 
 998                 status 
= errAuthorizationDenied
; 
1004             if (process_get_uid(proc
) != 0) { 
1005                 LOGE("server[%i]: AuthorizationRightSet denied, root required to update the 'authenticate' rule", connection_get_pid(conn
)); 
1006                 status 
= errAuthorizationDenied
; 
1010             // verify they are updating a right and not a rule 
1011             existingRule 
= rule_create_with_string(rule_get_name(rule
), dbconn
); 
1012             if (rule_get_type(existingRule
) == RT_RULE
) { 
1013                 LOGE("server[%i]: AuthorizationRightSet Denied updating '%s' rule is prohibited", connection_get_pid(conn
), rule_get_name(existingRule
)); 
1014                 status 
= errAuthorizationDenied
; 
1020     if (_prompt_for_modifications(proc
,rule
)) { 
1021         authdb_connection_release(&dbconn
); 
1023         dispatch_sync(connection_get_dispatch_queue(conn
), ^{ 
1024             engine 
= engine_create(conn
, auth
); 
1025             connection_set_engine(conn
, engine
); 
1026             status 
= engine_verify_modification(engine
, rule
, false, force_modify
); 
1027             connection_set_engine(conn
, NULL
); 
1029         require_noerr(status
, done
); 
1031         dbconn 
= authdb_connection_acquire(server_get_database()); 
1034     if (rule_sql_commit(rule
, dbconn
, engine 
? engine_get_time(engine
) : CFAbsoluteTimeGetCurrent(), proc
)) { 
1035         LOGV("server[%i]: Successfully updated rule %s", connection_get_pid(conn
), rule_get_name(rule
)); 
1036         authdb_checkpoint(dbconn
); 
1037         status 
= errAuthorizationSuccess
; 
1039         LOGE("server[%i]: Failed to update rule %s", connection_get_pid(conn
), rule_get_name(rule
)); 
1040         status 
= errAuthorizationDenied
; 
1044     authdb_connection_release(&dbconn
); 
1045     CFReleaseSafe(existingRule
); 
1046     CFReleaseSafe(cf_rule_name
); 
1047     CFReleaseSafe(cf_rule_dict
); 
1048     CFReleaseSafe(auth
); 
1049     CFReleaseSafe(rule
); 
1050     CFReleaseSafe(engine
); 
1054 // IN:  AUTH_XPC_BLOB, AUTH_XPC_RIGHT_NAME 
1057 authorization_right_remove(connection_t conn
, xpc_object_t message
, xpc_object_t reply AUTH_UNUSED
) 
1059     __block OSStatus status 
= errAuthorizationDenied
; 
1060     __block engine_t engine 
= NULL
; 
1062     authdb_connection_t dbconn 
= NULL
; 
1064     process_t proc 
= connection_get_process(conn
); 
1066     auth_token_t auth 
= NULL
; 
1067     status 
= _process_find_copy_auth_token_from_xpc(proc
, message
, &auth
); 
1068     require_noerr(status
, done
); 
1070     dbconn 
= authdb_connection_acquire(server_get_database()); 
1072     rule 
= rule_create_with_string(xpc_dictionary_get_string(message
, AUTH_XPC_RIGHT_NAME
), dbconn
); 
1073     require(rule 
!= NULL
, done
); 
1075     if (_prompt_for_modifications(proc
,rule
)) { 
1076         authdb_connection_release(&dbconn
); 
1078         dispatch_sync(connection_get_dispatch_queue(conn
), ^{ 
1079             engine 
= engine_create(conn
, auth
); 
1080             connection_set_engine(conn
, engine
); 
1081             status 
= engine_verify_modification(engine
, rule
, true, false); 
1082             connection_set_engine(conn
, NULL
); 
1084         require_noerr(status
, done
); 
1086         dbconn 
= authdb_connection_acquire(server_get_database()); 
1089     if (rule_get_id(rule
) != 0) { 
1090         rule_sql_remove(rule
, dbconn
); 
1094     authdb_connection_release(&dbconn
); 
1095     CFReleaseSafe(auth
); 
1096     CFReleaseSafe(rule
); 
1097     CFReleaseSafe(engine
); 
1098     LOGV("server[%i]: AuthorizationRightRemove %d", connection_get_pid(conn
), (int)status
); 
1103 #pragma mark test code 
1106 session_set_user_preferences(connection_t conn
, xpc_object_t message
, xpc_object_t reply
) 
1111     return errAuthorizationSuccess
; 
1116 //    rule_t rule = rule_create_with_string("system.preferences.accounts"); 
1117 //    CFDictionaryRef dict = rule_copy_to_cfobject(rule); 
1119 //    CFReleaseSafe(rule); 
1120 //    CFReleaseSafe(dict); 
1122 //    auth_items_t config = NULL; 
1123 //    double d2 = 0, d1 = 5; 
1124 //    authdb_get_key_value(server_get_authdb_reader(), "config", &config); 
1125 //    auth_items_set_double(config, "test", d1); 
1126 //    d2 = auth_items_get_double(config, "test"); 
1127 //    LOGV("d1=%f d2=%f", d1, d2); 
1128 //    CFReleaseSafe(config); 
1131 //    auth_items_t items = auth_items_create(); 
1132 //    auth_items_set_string(items, "test", "testing 1"); 
1133 //    auth_items_set_string(items, "test2", "testing 2"); 
1134 //    auth_items_set_string(items, "test3", "testing 3"); 
1135 //    auth_items_set_flags(items, "test3", 4); 
1136 //    auth_items_set_string(items, "apple", "apple"); 
1137 //    auth_items_set_flags(items, "apple", 1); 
1138 //    auth_items_set_int(items, "int", 45); 
1139 //    auth_items_set_flags(items, "int", 2); 
1140 //    auth_items_set_bool(items, "true", true); 
1141 //    auth_items_set_bool(items, "false", false); 
1142 //    auth_items_set(items, "com.apple."); 
1143 //    auth_show(items); 
1144 //    LOGD("Yeah it works: %s", auth_items_get_string(items, "test3")); 
1145 //    LOGD("Yeah it works: %i", auth_items_get_bool(items, "true")); 
1146 //    LOGD("Yeah it works: %i", auth_items_get_bool(items, "false")); 
1147 //    LOGD("Yeah it works: %i", auth_items_get_int(items, "int")); 
1148 //    (void)auth_items_get_bool(items, "test3"); 
1149 //    AuthorizationItemSet * itemSet = auth_items_get_item_set(items); 
1150 //    for (uint32_t i = 0; i < itemSet->count; i++) { 
1151 //        LOGD("item: %s", itemSet->items[i].name); 
1154 //    xpc_object_t xpcdata = SerializeItemSet(auth_items_get_item_set(items)); 
1155 //    auth_items_t items2 = auth_items_create_with_xpc(xpcdata); 
1156 //    xpc_release(xpcdata); 
1157 //    auth_items_remove_with_flags(items2, 7); 
1158 ////    auth_items_set_string(items2, "test3", "testing 3 very good"); 
1159 //    auth_items_copy_with_flags(items2, items, 7); 
1160 //    LOGD("Yeah it works: %s", auth_items_get_string(items2, "test3")); 
1161 //    auth_show(items2); 
1162 //    CFReleaseSafe(items2); 
1164 //    CFReleaseSafe(items);