1 /* Copyright (c) 2012 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 <xpc/private.h>
23 #include <dispatch/dispatch.h>
24 #include <CoreFoundation/CoreFoundation.h>
25 #include <CoreFoundation/CFXPCBridge.h>
26 #include <IOKit/IOMessage.h>
27 #include <IOKit/pwr_mgt/IOPMLib.h>
28 #include <IOKit/pwr_mgt/IOPMLibPrivate.h>
30 #define MAX_PROCESS_RIGHTS 30
32 static CFMutableDictionaryRef gProcessMap
= NULL
;
33 static CFMutableDictionaryRef gSessionMap
= NULL
;
34 static CFMutableDictionaryRef gAuthTokenMap
= NULL
;
35 static authdb_t gDatabase
= NULL
;
37 static dispatch_queue_t power_queue
;
38 static bool gInDarkWake
= false;
39 static IOPMConnection gIOPMconn
= NULL
;
40 static bool gXPCTransaction
= false;
42 static dispatch_queue_t
43 get_server_dispatch_queue()
45 static dispatch_once_t onceToken
;
46 static dispatch_queue_t server_queue
= NULL
;
48 dispatch_once(&onceToken
, ^{
49 server_queue
= dispatch_queue_create("com.apple.security.auth.server", DISPATCH_QUEUE_SERIAL
);
50 check(server_queue
!= NULL
);
56 static Boolean
_processEqualCallBack(const void *value1
, const void *value2
)
58 audit_info_s
* info1
= (audit_info_s
*)value1
;
59 audit_info_s
* info2
= (audit_info_s
*)value2
;
60 if (info1
->pid
== info2
->pid
) {
61 if (info1
->tid
== info2
->tid
) {
68 static CFHashCode
_processHashCallBack(const void *value
)
70 audit_info_s
* info
= (audit_info_s
*)value
;
71 uint64_t crc
= crc64_init();
72 crc
= crc64_update(crc
, &info
->pid
, sizeof(info
->pid
));
73 crc
= crc64_update(crc
, &info
->tid
, sizeof(info
->tid
));
74 crc
= crc64_final(crc
);
78 static const CFDictionaryKeyCallBacks kProcessMapKeyCallBacks
= {
82 .copyDescription
= NULL
,
83 .equal
= &_processEqualCallBack
,
84 .hash
= &_processHashCallBack
87 static Boolean
_sessionEqualCallBack(const void *value1
, const void *value2
)
89 return (*(session_id_t
*)value1
) == (*(session_id_t
*)value2
);
92 static CFHashCode
_sessionHashCallBack(const void *value
)
94 return (CFHashCode
)(*(session_id_t
*)(value
));
97 static const CFDictionaryKeyCallBacks kSessionMapKeyCallBacks
= {
101 .copyDescription
= NULL
,
102 .equal
= &_sessionEqualCallBack
,
103 .hash
= &_sessionHashCallBack
106 void server_cleanup()
108 CFRelease(gProcessMap
);
109 CFRelease(gSessionMap
);
110 CFRelease(gAuthTokenMap
);
112 IOPMConnectionSetDispatchQueue(gIOPMconn
, NULL
);
113 IOPMConnectionRelease(gIOPMconn
);
115 dispatch_queue_t queue
= get_server_dispatch_queue();
117 dispatch_release(queue
);
119 dispatch_release(power_queue
);
122 static void _IOMPCallBack(void * param AUTH_UNUSED
, IOPMConnection connection
, IOPMConnectionMessageToken token
, IOPMSystemPowerStateCapabilities capabilities
)
124 LOGV("server: IOMP powerstates %i", capabilities
);
125 if (capabilities
& kIOPMSystemPowerStateCapabilityDisk
)
126 LOGV("server: disk");
127 if (capabilities
& kIOPMSystemPowerStateCapabilityNetwork
)
129 if (capabilities
& kIOPMSystemPowerStateCapabilityAudio
)
130 LOGV("server: audio");
131 if (capabilities
& kIOPMSystemPowerStateCapabilityVideo
)
132 LOGV("server: video");
134 /* if cpu and no display -> in DarkWake */
135 LOGD("server: DarkWake check current=%i==%i", (capabilities
& (kIOPMSystemPowerStateCapabilityCPU
|kIOPMSystemPowerStateCapabilityVideo
)), kIOPMSystemPowerStateCapabilityCPU
);
136 if ((capabilities
& (kIOPMSystemPowerStateCapabilityCPU
|kIOPMSystemPowerStateCapabilityVideo
)) == kIOPMSystemPowerStateCapabilityCPU
) {
137 LOGV("server: enter DarkWake");
139 } else if (gInDarkWake
) {
140 LOGV("server: exit DarkWake");
144 (void)IOPMConnectionAcknowledgeEvent(connection
, token
);
150 _setupDarkWake(void *ctx
)
154 IOPMConnectionCreate(CFSTR("IOPowerWatcher"),
155 kIOPMSystemPowerStateCapabilityDisk
156 | kIOPMSystemPowerStateCapabilityNetwork
157 | kIOPMSystemPowerStateCapabilityAudio
158 | kIOPMSystemPowerStateCapabilityVideo
,
161 ret
= IOPMConnectionSetNotification(gIOPMconn
, NULL
, _IOMPCallBack
);
162 if (ret
!= kIOReturnSuccess
)
165 IOPMConnectionSetDispatchQueue(gIOPMconn
, power_queue
);
167 IOPMScheduleUserActiveChangedNotification(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^(bool active
) {
174 bool server_in_dark_wake()
179 authdb_t
server_get_database()
184 static void _setupAuditSessionMonitor()
186 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^{
187 au_sdev_handle_t
*dev
= au_sdev_open(AU_SDEVF_ALLSESSIONS
);
189 auditinfo_addr_t aia
;
192 LOGE("server: could not open %s %d", AUDIT_SDEV_PATH
, errno
);
197 if (0 != au_sdev_read_aia(dev
, &event
, &aia
)) {
198 LOGE("server: au_sdev_read_aia failed: %d", errno
);
201 LOGD("server: au_sdev_handle_t event=%i, session=%i", event
, aia
.ai_asid
);
202 if (event
== AUE_SESSION_CLOSE
) {
203 dispatch_async(get_server_dispatch_queue(), ^{
204 LOGV("server: session %i destroyed", aia
.ai_asid
);
205 CFDictionaryRemoveValue(gSessionMap
, &aia
.ai_asid
);
213 static void _setupSignalHandlers()
215 signal(SIGTERM
, SIG_IGN
);
216 static dispatch_source_t sigtermHandler
;
217 sigtermHandler
= dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL
, SIGTERM
, 0, get_server_dispatch_queue());
218 if (sigtermHandler
) {
219 dispatch_source_set_event_handler(sigtermHandler
, ^{
221 // should we clean up any state?
224 dispatch_resume(sigtermHandler
);
228 OSStatus
server_init(void)
230 OSStatus status
= errAuthorizationSuccess
;
232 auditinfo_addr_t info
;
233 memset(&info
, 0, sizeof(info
));
234 getaudit_addr(&info
, sizeof(info
));
235 LOGV("server: uid=%i, sid=%i", info
.ai_auid
, info
.ai_asid
);
237 require_action(get_server_dispatch_queue() != NULL
, done
, status
= errAuthorizationInternal
);
239 gProcessMap
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kProcessMapKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
240 require_action(gProcessMap
!= NULL
, done
, status
= errAuthorizationInternal
);
242 gSessionMap
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kSessionMapKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
243 require_action(gSessionMap
!= NULL
, done
, status
= errAuthorizationInternal
);
245 gAuthTokenMap
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kAuthTokenKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
246 require_action(gAuthTokenMap
!= NULL
, done
, status
= errAuthorizationInternal
);
248 gDatabase
= authdb_create();
249 require_action(gDatabase
!= NULL
, done
, status
= errAuthorizationInternal
);
251 // check to see if we have an updates
252 authdb_connection_t dbconn
= authdb_connection_acquire(gDatabase
);
253 authdb_maintenance(dbconn
);
254 authdb_connection_release(&dbconn
);
256 power_queue
= dispatch_queue_create("com.apple.security.auth.power", DISPATCH_QUEUE_SERIAL
);
257 check(power_queue
!= NULL
);
258 dispatch_async_f(power_queue
, NULL
, _setupDarkWake
);
260 _setupAuditSessionMonitor();
261 _setupSignalHandlers();
267 static void _server_parse_audit_token(audit_token_t
* token
, audit_info_s
* info
)
270 memset(info
, 0, sizeof(*info
));
272 memset(&tid
, 0, sizeof(tid
));
273 audit_token_to_au32(*token
, &info
->auid
, &info
->euid
,
274 &info
->egid
, &info
->ruid
, &info
->rgid
,
275 &info
->pid
, &info
->asid
, &tid
);
276 info
->tid
= tid
.port
;
277 info
->opaqueToken
= *token
;
282 server_register_connection(xpc_connection_t connection
)
284 __block connection_t conn
= NULL
;
285 __block session_t session
= NULL
;
286 __block process_t proc
= NULL
;
287 __block CFIndex conn_count
= 0;
289 require(connection
!= NULL
, done
);
291 audit_token_t auditToken
;
293 xpc_connection_get_audit_token(connection
, &auditToken
);
294 _server_parse_audit_token(&auditToken
, &info
);
297 dispatch_sync(get_server_dispatch_queue(), ^{
298 session
= (session_t
)CFDictionaryGetValue(gSessionMap
, &info
.asid
);
302 session
= session_create(info
.asid
);
303 CFDictionarySetValue(gSessionMap
, session_get_key(session
), session
);
306 proc
= (process_t
)CFDictionaryGetValue(gProcessMap
, &info
);
312 conn
= connection_create(proc
);
313 conn_count
= process_add_connection(proc
, conn
);
315 proc
= process_create(&info
, session
);
317 conn
= connection_create(proc
);
318 conn_count
= process_add_connection(proc
, conn
);
319 session_add_process(session
, proc
);
320 CFDictionarySetValue(gProcessMap
, process_get_key(proc
), proc
);
324 if (!gXPCTransaction
) {
325 xpc_transaction_begin();
326 gXPCTransaction
= true;
330 LOGV("server[%i]: registered connection (total=%li)", info
.pid
, conn_count
);
333 CFReleaseSafe(session
);
339 server_unregister_connection(connection_t conn
)
342 process_t proc
= connection_get_process(conn
);
344 dispatch_sync(get_server_dispatch_queue(), ^{
345 CFIndex connectionCount
= process_get_connection_count(proc
);
346 LOGV("server[%i]: unregistered connection (total=%li)", process_get_pid(proc
), connectionCount
);
348 if (connectionCount
== 1) {
349 CFDictionaryRemoveValue(gProcessMap
, process_get_key(proc
));
352 if (CFDictionaryGetCount(gProcessMap
) == 0) {
353 xpc_transaction_end();
354 gXPCTransaction
= false;
357 // move the destruction of the connection/process off the server queue
363 server_register_auth_token(auth_token_t auth
)
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
);
375 server_unregister_auth_token(auth_token_t auth
)
378 AuthorizationBlob blob
= *(AuthorizationBlob
*)auth_token_get_key(auth
);
379 dispatch_async(get_server_dispatch_queue(), ^{
380 LOGV("server: unregistering auth %p", auth
);
381 CFDictionaryRemoveValue(gAuthTokenMap
, &blob
);
387 server_find_copy_auth_token(AuthorizationBlob
* blob
)
389 __block auth_token_t auth
= NULL
;
391 dispatch_sync(get_server_dispatch_queue(), ^{
392 auth
= (auth_token_t
)CFDictionaryGetValue(gAuthTokenMap
, blob
);
402 server_find_copy_session(session_id_t sid
, bool create
)
404 __block session_t session
= NULL
;
406 dispatch_sync(get_server_dispatch_queue(), ^{
407 session
= (session_t
)CFDictionaryGetValue(gSessionMap
, &sid
);
411 session
= session_create(sid
);
413 CFDictionarySetValue(gSessionMap
, session_get_key(session
), session
);
425 _process_find_copy_auth_token_from_xpc(process_t proc
, xpc_object_t message
, auth_token_t
* auth_out
)
427 OSStatus status
= errAuthorizationSuccess
;
428 require_action(auth_out
!= NULL
, done
, status
= errAuthorizationInternal
);
431 AuthorizationBlob
* blob
= (AuthorizationBlob
*)xpc_dictionary_get_data(message
, AUTH_XPC_BLOB
, &len
);
432 require_action(blob
!= NULL
, done
, status
= errAuthorizationInvalidRef
);
433 require_action(len
== sizeof(AuthorizationBlob
), done
, status
= errAuthorizationInvalidRef
);
435 auth_token_t auth
= process_find_copy_auth_token(proc
, blob
);
436 require_action(auth
!= NULL
, done
, status
= errAuthorizationInvalidRef
);
439 LOGV("server[%i]: authtoken lookup %#x%x %p", process_get_pid(proc
), blob
->data
[1],blob
->data
[0], auth
);
441 LOGV("server[%i]: authtoken lookup %p", process_get_pid(proc
), auth
);
450 static OSStatus
_server_authorize(connection_t conn
, auth_token_t auth
, AuthorizationFlags flags
, auth_rights_t rights
, auth_items_t enviroment
, engine_t
* engine_out
)
452 __block OSStatus status
= errAuthorizationDenied
;
453 engine_t engine
= NULL
;
455 require_action(conn
, done
, status
= errAuthorizationInternal
);
457 engine
= engine_create(conn
, auth
);
458 require_action(engine
, done
, status
= errAuthorizationInternal
);
460 if (flags
& kAuthorizationFlagInteractionAllowed
) {
461 dispatch_sync(connection_get_dispatch_queue(conn
), ^{
462 connection_set_engine(conn
, engine
);
463 status
= engine_authorize(engine
, rights
, enviroment
, flags
);
464 connection_set_engine(conn
, NULL
);
467 status
= engine_authorize(engine
, rights
, enviroment
, flags
);
473 *engine_out
= engine
;
481 // IN: AUTH_XPC_RIGHTS, AUTH_XPC_ENVIROMENT, AUTH_XPC_FLAGS
482 // OUT: AUTH_XPC_BLOB
484 authorization_create(connection_t conn
, xpc_object_t message
, xpc_object_t reply
)
486 OSStatus status
= errAuthorizationDenied
;
488 process_t proc
= connection_get_process(conn
);
491 auth_rights_t rights
= auth_rights_create_with_xpc(xpc_dictionary_get_value(message
, AUTH_XPC_RIGHTS
));
492 auth_items_t enviroment
= auth_items_create_with_xpc(xpc_dictionary_get_value(message
, AUTH_XPC_ENVIROMENT
));
493 AuthorizationFlags flags
= (AuthorizationFlags
)xpc_dictionary_get_uint64(message
, AUTH_XPC_FLAGS
);
495 // Create Authorization Token
496 auth_token_t auth
= auth_token_create(proc
, flags
& kAuthorizationFlagLeastPrivileged
);
497 require_action(auth
!= NULL
, done
, status
= errAuthorizationInternal
);
499 if (!(flags
& kAuthorizationFlagNoData
)) {
500 process_add_auth_token(proc
,auth
);
503 status
= _server_authorize(conn
, auth
, flags
, rights
, enviroment
, NULL
);
504 require_noerr(status
, done
);
507 xpc_dictionary_set_data(reply
, AUTH_XPC_BLOB
, auth_token_get_blob(auth
), sizeof(AuthorizationBlob
));
510 CFReleaseSafe(rights
);
511 CFReleaseSafe(enviroment
);
516 // IN: AUTH_XPC_DATA, AUTH_XPC_ENVIROMENT, AUTH_XPC_FLAGS
517 // OUT: AUTH_XPC_BLOB
518 OSStatus
authorization_create_with_audit_token(connection_t conn
, xpc_object_t message
, xpc_object_t reply
)
520 OSStatus status
= errAuthorizationDenied
;
521 auth_token_t auth
= NULL
;
523 process_t proc
= connection_get_process(conn
);
524 require(process_get_uid(proc
) == 0, done
); //only root can use this call
528 const char * data
= xpc_dictionary_get_data(message
, AUTH_XPC_DATA
, &len
);
529 require(data
!= NULL
, done
);
530 require(len
== sizeof(audit_token_t
), done
);
532 // auth_items_t enviroment = auth_items_create_with_xpc(xpc_dictionary_get_value(message, AUTH_XPC_ENVIROMENT));
533 AuthorizationFlags flags
= (AuthorizationFlags
)xpc_dictionary_get_uint64(message
, AUTH_XPC_FLAGS
);
535 audit_info_s auditInfo
;
536 _server_parse_audit_token((audit_token_t
*)data
, &auditInfo
);
538 // Create Authorization Token
539 auth
= auth_token_create(proc
, flags
& kAuthorizationFlagLeastPrivileged
);
540 require_action(auth
!= NULL
, done
, status
= errAuthorizationInternal
);
542 process_add_auth_token(proc
,auth
);
545 xpc_dictionary_set_data(reply
, AUTH_XPC_BLOB
, auth_token_get_blob(auth
), sizeof(AuthorizationBlob
));
548 // CFReleaseSafe(enviroment);
553 // IN: AUTH_XPC_BLOB, AUTH_XPC_FLAGS
556 authorization_free(connection_t conn
, xpc_object_t message
, xpc_object_t reply AUTH_UNUSED
)
558 OSStatus status
= errAuthorizationSuccess
;
559 AuthorizationFlags flags
= 0;
560 process_t proc
= connection_get_process(conn
);
562 auth_token_t auth
= NULL
;
563 status
= _process_find_copy_auth_token_from_xpc(proc
, message
, &auth
);
564 require_noerr(status
, done
);
566 flags
= (AuthorizationFlags
)xpc_dictionary_get_uint64(message
, AUTH_XPC_FLAGS
);
568 if (flags
& kAuthorizationFlagDestroyRights
) {
569 auth_token_credentials_iterate(auth
, ^bool(credential_t cred
) {
570 credential_invalidate(cred
);
571 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
);
575 session_credentials_purge(auth_token_get_session(auth
));
578 process_remove_auth_token(proc
, auth
, flags
);
582 LOGV("server[%i]: AuthorizationFree %i (flags:%x)", connection_get_pid(conn
), status
, flags
);
586 // IN: AUTH_XPC_BLOB, AUTH_XPC_RIGHTS, AUTH_XPC_ENVIROMENT, AUTH_XPC_FLAGS
587 // OUT: AUTH_XPC_OUT_ITEMS
589 authorization_copy_rights(connection_t conn
, xpc_object_t message
, xpc_object_t reply
)
591 OSStatus status
= errAuthorizationDenied
;
592 engine_t engine
= NULL
;
594 process_t proc
= connection_get_process(conn
);
597 auth_rights_t rights
= auth_rights_create_with_xpc(xpc_dictionary_get_value(message
, AUTH_XPC_RIGHTS
));
598 auth_items_t enviroment
= auth_items_create_with_xpc(xpc_dictionary_get_value(message
, AUTH_XPC_ENVIROMENT
));
599 AuthorizationFlags flags
= (AuthorizationFlags
)xpc_dictionary_get_uint64(message
, AUTH_XPC_FLAGS
);
601 auth_token_t auth
= NULL
;
602 status
= _process_find_copy_auth_token_from_xpc(proc
, message
, &auth
);
603 require_noerr(status
, done
);
605 status
= _server_authorize(conn
, auth
, flags
, rights
, enviroment
, &engine
);
606 require_noerr(status
, done
);
609 xpc_object_t outItems
= auth_rights_export_xpc(engine_get_granted_rights(engine
));
610 xpc_dictionary_set_value(reply
, AUTH_XPC_OUT_ITEMS
, outItems
);
611 xpc_release_safe(outItems
);
614 CFReleaseSafe(rights
);
615 CFReleaseSafe(enviroment
);
617 CFReleaseSafe(engine
);
622 // IN: AUTH_XPC_BLOB, AUTH_XPC_TAG
623 // OUT: AUTH_XPC_OUT_ITEMS
625 authorization_copy_info(connection_t conn
, xpc_object_t message
, xpc_object_t reply
)
628 OSStatus status
= errAuthorizationSuccess
;
629 auth_items_t items
= NULL
;
630 const char * tag
= NULL
;
632 process_t proc
= connection_get_process(conn
);
634 auth_token_t auth
= NULL
;
635 status
= _process_find_copy_auth_token_from_xpc(proc
, message
, &auth
);
636 require_noerr(status
, done
);
638 items
= auth_items_create();
640 tag
= xpc_dictionary_get_string(message
, AUTH_XPC_TAG
);
641 LOGV("server[%i]: requested tag: %s", connection_get_pid(conn
), tag
? tag
: "(all)");
644 const void * data
= auth_items_get_data(auth_token_get_context(auth
), tag
, &len
);
646 auth_items_set_data(items
, tag
, data
, len
);
649 auth_items_copy(items
, auth_token_get_context(auth
));
653 LOGV("server[%i]: Dumping requested AuthRef items", connection_get_pid(conn
));
658 xpc_object_t outItems
= auth_items_export_xpc(items
);
659 xpc_dictionary_set_value(reply
, AUTH_XPC_OUT_ITEMS
, outItems
);
660 xpc_release_safe(outItems
);
663 CFReleaseSafe(items
);
665 LOGV("server[%i]: AuthorizationCopyInfo %i", connection_get_pid(conn
), status
);
670 // OUT: AUTH_XPC_EXTERNAL
672 authorization_make_external_form(connection_t conn
, xpc_object_t message
, xpc_object_t reply
)
674 OSStatus status
= errAuthorizationSuccess
;
676 process_t proc
= connection_get_process(conn
);
678 auth_token_t auth
= NULL
;
679 status
= _process_find_copy_auth_token_from_xpc(proc
, message
, &auth
);
680 require_noerr(status
, done
);
682 AuthorizationExternalForm exForm
;
683 AuthorizationExternalBlob
* exBlob
= (AuthorizationExternalBlob
*)&exForm
;
684 memset(&exForm
, 0, sizeof(exForm
));
686 exBlob
->blob
= *auth_token_get_blob(auth
);
687 exBlob
->session
= process_get_session_id(proc
);
689 xpc_dictionary_set_data(reply
, AUTH_XPC_EXTERNAL
, &exForm
, sizeof(exForm
));
690 server_register_auth_token(auth
);
694 LOGV("server[%i]: AuthorizationMakeExternalForm %i", connection_get_pid(conn
), status
);
698 // IN: AUTH_XPC_EXTERNAL
699 // OUT: AUTH_XPC_BLOB
701 authorization_create_from_external_form(connection_t conn
, xpc_object_t message
, xpc_object_t reply
)
703 OSStatus status
= errAuthorizationSuccess
;
704 auth_token_t auth
= NULL
;
706 process_t proc
= connection_get_process(conn
);
709 AuthorizationExternalForm
* exForm
= (AuthorizationExternalForm
*)xpc_dictionary_get_data(message
, AUTH_XPC_EXTERNAL
, &len
);
710 require_action(exForm
!= NULL
, done
, status
= errAuthorizationInternal
);
711 require_action(len
== sizeof(AuthorizationExternalForm
), done
, status
= errAuthorizationInvalidRef
);
713 AuthorizationExternalBlob
* exBlob
= (AuthorizationExternalBlob
*)exForm
;
714 auth
= server_find_copy_auth_token(&exBlob
->blob
);
715 require_action(auth
!= NULL
, done
, status
= errAuthorizationDenied
);
717 process_add_auth_token(proc
, auth
);
718 xpc_dictionary_set_data(reply
, AUTH_XPC_BLOB
, auth_token_get_blob(auth
), sizeof(AuthorizationBlob
));
722 LOGV("server[%i]: AuthorizationCreateFromExternalForm %i", connection_get_pid(conn
), status
);
726 // IN: AUTH_XPC_RIGHT_NAME
727 // OUT: AUTH_XPC_DATA
729 authorization_right_get(connection_t conn AUTH_UNUSED
, xpc_object_t message
, xpc_object_t reply
)
731 OSStatus status
= errAuthorizationDenied
;
733 CFTypeRef cfdict
= NULL
;
734 xpc_object_t xpcdict
= NULL
;
736 authdb_connection_t dbconn
= authdb_connection_acquire(server_get_database());
737 rule
= rule_create_with_string(xpc_dictionary_get_string(message
, AUTH_XPC_RIGHT_NAME
), dbconn
);
738 require(rule
!= NULL
, done
);
739 require(rule_get_id(rule
) != 0, done
);
741 cfdict
= rule_copy_to_cfobject(rule
, dbconn
);
742 require(cfdict
!= NULL
, done
);
744 xpcdict
= _CFXPCCreateXPCObjectFromCFObject(cfdict
);
745 require(xpcdict
!= NULL
, done
);
748 xpc_dictionary_set_value(reply
, AUTH_XPC_DATA
, xpcdict
);
750 status
= errAuthorizationSuccess
;
753 authdb_connection_release(&dbconn
);
754 CFReleaseSafe(cfdict
);
755 xpc_release_safe(xpcdict
);
757 LOGV("server[%i]: AuthorizationRightGet %i", connection_get_pid(conn
), status
);
761 static bool _prompt_for_modifications(process_t proc
, rule_t rule
)
763 // <rdar://problem/13853228> will put back it back at some later date
764 // SecRequirementRef ruleReq = rule_get_requirment(rule);
766 // if (ruleReq && process_verify_requirment(proc, ruleReq)) {
773 static CFIndex
_get_mechanism_index(CFArrayRef mechanisms
, CFStringRef m_name
)
776 require(mechanisms
, done
);
778 CFIndex c
= CFArrayGetCount(mechanisms
);
779 CFStringRef i_name
= NULL
;
780 for (CFIndex i
= 0; i
< c
; ++i
)
782 i_name
= CFArrayGetValueAtIndex(mechanisms
, i
);
783 if (i_name
&& (CFGetTypeID(m_name
) == CFStringGetTypeID())) {
784 if (CFStringCompare(i_name
, m_name
, kCFCompareCaseInsensitive
) == kCFCompareEqualTo
) {
795 static bool _update_rule_mechanism(authdb_connection_t dbconn
, const char * rule_name
, CFStringRef mechanism_name
, CFStringRef insert_after_name
, bool remove
)
797 bool updated
= false;
799 rule_t update_rule
= NULL
;
800 CFMutableDictionaryRef cfdict
= NULL
;
801 CFStringRef update_name
= NULL
;
803 require(mechanism_name
, done
);
805 rule
= rule_create_with_string(rule_name
, dbconn
);
806 require(rule_get_id(rule
) != 0, done
); // rule doesn't exist in the database
808 cfdict
= rule_copy_to_cfobject(rule
, dbconn
);
809 require(cfdict
!= NULL
, done
);
811 CFMutableArrayRef mechanisms
= NULL
;
812 bool res
= CFDictionaryGetValueIfPresent(cfdict
, CFSTR(kAuthorizationRuleParameterMechanisms
), (void*)&mechanisms
);
813 require(res
== true, done
);
818 index
= _get_mechanism_index(mechanisms
, mechanism_name
);
820 if (insert_after_name
) {
821 if ((index
= _get_mechanism_index(mechanisms
, insert_after_name
)) != -1) {
824 index
= 0; // if we couldn't find the index add it to the begining
833 CFArrayRemoveValueAtIndex(mechanisms
, index
);
835 if (index
< CFArrayGetCount(mechanisms
)) {
836 require_action(CFStringCompare(CFArrayGetValueAtIndex(mechanisms
, index
), mechanism_name
, kCFCompareCaseInsensitive
) != kCFCompareEqualTo
, done
, updated
= true);
838 CFArrayInsertValueAtIndex(mechanisms
, index
, mechanism_name
);
841 CFDictionarySetValue(cfdict
, CFSTR(kAuthorizationRuleParameterMechanisms
), mechanisms
);
844 update_name
= CFStringCreateWithCString(kCFAllocatorDefault
, rule_name
, kCFStringEncodingUTF8
);
845 require(update_name
, done
);
846 update_rule
= rule_create_with_plist(rule_get_type(rule
), update_name
, cfdict
, dbconn
);
847 require(update_rule
, done
);
849 require(rule_sql_commit(update_rule
, dbconn
, CFAbsoluteTimeGetCurrent(), NULL
), done
);
856 CFReleaseSafe(update_rule
);
857 CFReleaseSafe(cfdict
);
858 CFReleaseSafe(update_name
);
862 /// IN: AUTH_XPC_BLOB, AUTH_XPC_INT64
865 authorization_enable_smartcard(connection_t conn
, xpc_object_t message
, xpc_object_t reply AUTH_UNUSED
)
867 const CFStringRef SMARTCARD_LINE
= CFSTR("builtin:smartcard-sniffer,privileged");
868 const CFStringRef BUILTIN_LINE
= CFSTR("builtin:policy-banner");
869 const char* SYSTEM_LOGIN_CONSOLE
= "system.login.console";
870 const char* AUTHENTICATE
= "authenticate";
872 __block OSStatus status
= errAuthorizationSuccess
;
873 bool enable_smartcard
= false;
874 authdb_connection_t dbconn
= NULL
;
875 auth_token_t auth
= NULL
;
876 auth_rights_t checkRight
= NULL
;
878 process_t proc
= connection_get_process(conn
);
880 status
= _process_find_copy_auth_token_from_xpc(proc
, message
, &auth
);
881 require_noerr(status
, done
);
883 checkRight
= auth_rights_create();
884 auth_rights_add(checkRight
, "config.modify.smartcard");
885 status
= _server_authorize(conn
, auth
, kAuthorizationFlagDefaults
| kAuthorizationFlagInteractionAllowed
| kAuthorizationFlagExtendRights
, checkRight
, NULL
, NULL
);
886 require_noerr(status
, done
);
888 enable_smartcard
= xpc_dictionary_get_bool(message
, AUTH_XPC_DATA
);
890 dbconn
= authdb_connection_acquire(server_get_database());
892 if (!_update_rule_mechanism(dbconn
, SYSTEM_LOGIN_CONSOLE
, SMARTCARD_LINE
, BUILTIN_LINE
, enable_smartcard
? false : true)) {
893 status
= errAuthorizationInternal
;
894 LOGE("server[%i]: smartcard: enable(%i) failed to update %s", connection_get_pid(conn
), enable_smartcard
, SYSTEM_LOGIN_CONSOLE
);
896 if (!_update_rule_mechanism(dbconn
, AUTHENTICATE
, SMARTCARD_LINE
, NULL
, enable_smartcard
? false : true)) {
897 status
= errAuthorizationInternal
;
898 LOGE("server[%i]: smartcard: enable(%i) failed to update %s", connection_get_pid(conn
), enable_smartcard
, AUTHENTICATE
);
901 authdb_checkpoint(dbconn
);
904 authdb_connection_release(&dbconn
);
905 CFReleaseSafe(checkRight
);
910 static int64_t _process_get_identifier_count(process_t proc
, authdb_connection_t conn
)
912 __block
int64_t result
= 0;
914 authdb_step(conn
, "SELECT COUNT(*) AS cnt FROM rules WHERE identifier = ? ", ^(sqlite3_stmt
*stmt
) {
915 sqlite3_bind_text(stmt
, 1, process_get_identifier(proc
), -1, NULL
);
916 }, ^bool(auth_items_t data
) {
917 result
= auth_items_get_int64(data
, "cnt");
924 static int64_t _get_max_process_rights()
926 static dispatch_once_t onceToken
;
927 static int64_t max_rights
= MAX_PROCESS_RIGHTS
;
929 //sudo defaults write /Library/Preferences/com.apple.authd max_process_rights -bool true
930 dispatch_once(&onceToken
, ^{
931 CFTypeRef max
= (CFNumberRef
)CFPreferencesCopyValue(CFSTR("max_process_rights"), CFSTR(SECURITY_AUTH_NAME
), kCFPreferencesAnyUser
, kCFPreferencesCurrentHost
);
933 if (max
&& CFGetTypeID(max
) == CFNumberGetTypeID()) {
934 CFNumberGetValue(max
, kCFNumberSInt64Type
, &max_rights
);
942 // IN: AUTH_XPC_BLOB, AUTH_XPC_RIGHT_NAME, AUTH_XPC_DATA
945 authorization_right_set(connection_t conn
, xpc_object_t message
, xpc_object_t reply AUTH_UNUSED
)
947 __block OSStatus status
= errAuthorizationDenied
;
948 __block engine_t engine
= NULL
;
949 CFStringRef cf_rule_name
= NULL
;
950 CFDictionaryRef cf_rule_dict
= NULL
;
952 rule_t existingRule
= NULL
;
953 authdb_connection_t dbconn
= NULL
;
954 auth_token_t auth
= NULL
;
955 bool force_modify
= false;
956 RuleType rule_type
= RT_RIGHT
;
957 const char * rule_name
= NULL
;
958 bool auth_rule
= false;
960 process_t proc
= connection_get_process(conn
);
962 status
= _process_find_copy_auth_token_from_xpc(proc
, message
, &auth
);
963 require_noerr(status
, done
);
965 require_action(xpc_dictionary_get_string(message
, AUTH_XPC_RIGHT_NAME
) != NULL
, done
, status
= errAuthorizationInternal
);
966 require_action(xpc_dictionary_get_value(message
, AUTH_XPC_DATA
) != NULL
, done
, status
= errAuthorizationInternal
);
968 rule_name
= xpc_dictionary_get_string(message
, AUTH_XPC_RIGHT_NAME
);
969 require(rule_name
!= NULL
, done
);
971 if (_compare_string(rule_name
, "authenticate")) {
976 cf_rule_name
= CFStringCreateWithCString(kCFAllocatorDefault
, rule_name
, kCFStringEncodingUTF8
);
977 require(cf_rule_name
!= NULL
, done
);
979 cf_rule_dict
= _CFXPCCreateCFObjectFromXPCObject(xpc_dictionary_get_value(message
, AUTH_XPC_DATA
));
980 require(cf_rule_dict
!= NULL
, done
);
982 dbconn
= authdb_connection_acquire(server_get_database());
984 rule
= rule_create_with_plist(rule_type
, cf_rule_name
, cf_rule_dict
, dbconn
);
985 if (process_get_uid(proc
) != 0) {
986 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
)));
989 // if rule doesn't currently exist then we have to check to see if they are over the Max.
990 if (rule_get_id(rule
) == 0) {
991 if (process_get_identifier(proc
) == NULL
) {
992 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
));
995 int64_t process_rule_count
= _process_get_identifier_count(proc
, dbconn
);
996 if ((process_rule_count
>= _get_max_process_rights())) {
997 if (!connection_get_syslog_warn(conn
)) {
998 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());
999 connection_set_syslog_warn(conn
);
1001 status
= errAuthorizationDenied
;
1007 if (process_get_uid(proc
) != 0) {
1008 LOGE("server[%i]: AuthorizationRightSet denied, root required to update the 'authenticate' rule", connection_get_pid(conn
));
1009 status
= errAuthorizationDenied
;
1013 // verify they are updating a right and not a rule
1014 existingRule
= rule_create_with_string(rule_get_name(rule
), dbconn
);
1015 if (rule_get_type(existingRule
) == RT_RULE
) {
1016 LOGE("server[%i]: AuthorizationRightSet Denied updating '%s' rule is prohibited", connection_get_pid(conn
), rule_get_name(existingRule
));
1017 status
= errAuthorizationDenied
;
1023 if (_prompt_for_modifications(proc
,rule
)) {
1024 authdb_connection_release(&dbconn
);
1026 dispatch_sync(connection_get_dispatch_queue(conn
), ^{
1027 engine
= engine_create(conn
, auth
);
1028 connection_set_engine(conn
, engine
);
1029 status
= engine_verify_modification(engine
, rule
, false, force_modify
);
1030 connection_set_engine(conn
, NULL
);
1032 require_noerr(status
, done
);
1034 dbconn
= authdb_connection_acquire(server_get_database());
1037 if (rule_sql_commit(rule
, dbconn
, engine
? engine_get_time(engine
) : CFAbsoluteTimeGetCurrent(), proc
)) {
1038 LOGV("server[%i]: Successfully updated rule %s", connection_get_pid(conn
), rule_get_name(rule
));
1039 authdb_checkpoint(dbconn
);
1040 status
= errAuthorizationSuccess
;
1042 LOGE("server[%i]: Failed to update rule %s", connection_get_pid(conn
), rule_get_name(rule
));
1043 status
= errAuthorizationDenied
;
1047 authdb_connection_release(&dbconn
);
1048 CFReleaseSafe(existingRule
);
1049 CFReleaseSafe(cf_rule_name
);
1050 CFReleaseSafe(cf_rule_dict
);
1051 CFReleaseSafe(auth
);
1052 CFReleaseSafe(rule
);
1053 CFReleaseSafe(engine
);
1057 // IN: AUTH_XPC_BLOB, AUTH_XPC_RIGHT_NAME
1060 authorization_right_remove(connection_t conn
, xpc_object_t message
, xpc_object_t reply AUTH_UNUSED
)
1062 __block OSStatus status
= errAuthorizationDenied
;
1063 __block engine_t engine
= NULL
;
1065 authdb_connection_t dbconn
= NULL
;
1067 process_t proc
= connection_get_process(conn
);
1069 auth_token_t auth
= NULL
;
1070 status
= _process_find_copy_auth_token_from_xpc(proc
, message
, &auth
);
1071 require_noerr(status
, done
);
1073 dbconn
= authdb_connection_acquire(server_get_database());
1075 rule
= rule_create_with_string(xpc_dictionary_get_string(message
, AUTH_XPC_RIGHT_NAME
), dbconn
);
1076 require(rule
!= NULL
, done
);
1078 if (_prompt_for_modifications(proc
,rule
)) {
1079 authdb_connection_release(&dbconn
);
1081 dispatch_sync(connection_get_dispatch_queue(conn
), ^{
1082 engine
= engine_create(conn
, auth
);
1083 connection_set_engine(conn
, engine
);
1084 status
= engine_verify_modification(engine
, rule
, true, false);
1085 connection_set_engine(conn
, NULL
);
1087 require_noerr(status
, done
);
1089 dbconn
= authdb_connection_acquire(server_get_database());
1092 if (rule_get_id(rule
) != 0) {
1093 rule_sql_remove(rule
, dbconn
);
1097 authdb_connection_release(&dbconn
);
1098 CFReleaseSafe(auth
);
1099 CFReleaseSafe(rule
);
1100 CFReleaseSafe(engine
);
1101 LOGV("server[%i]: AuthorizationRightRemove %i", connection_get_pid(conn
), status
);
1106 #pragma mark test code
1109 session_set_user_preferences(connection_t conn
, xpc_object_t message
, xpc_object_t reply
)
1114 return errAuthorizationSuccess
;
1119 // rule_t rule = rule_create_with_string("system.preferences.accounts");
1120 // CFDictionaryRef dict = rule_copy_to_cfobject(rule);
1122 // CFReleaseSafe(rule);
1123 // CFReleaseSafe(dict);
1125 // auth_items_t config = NULL;
1126 // double d2 = 0, d1 = 5;
1127 // authdb_get_key_value(server_get_authdb_reader(), "config", &config);
1128 // auth_items_set_double(config, "test", d1);
1129 // d2 = auth_items_get_double(config, "test");
1130 // LOGV("d1=%f d2=%f", d1, d2);
1131 // CFReleaseSafe(config);
1134 // auth_items_t items = auth_items_create();
1135 // auth_items_set_string(items, "test", "testing 1");
1136 // auth_items_set_string(items, "test2", "testing 2");
1137 // auth_items_set_string(items, "test3", "testing 3");
1138 // auth_items_set_flags(items, "test3", 4);
1139 // auth_items_set_string(items, "apple", "apple");
1140 // auth_items_set_flags(items, "apple", 1);
1141 // auth_items_set_int(items, "int", 45);
1142 // auth_items_set_flags(items, "int", 2);
1143 // auth_items_set_bool(items, "true", true);
1144 // auth_items_set_bool(items, "false", false);
1145 // auth_items_set(items, "com.apple.");
1146 // auth_show(items);
1147 // LOGD("Yeah it works: %s", auth_items_get_string(items, "test3"));
1148 // LOGD("Yeah it works: %i", auth_items_get_bool(items, "true"));
1149 // LOGD("Yeah it works: %i", auth_items_get_bool(items, "false"));
1150 // LOGD("Yeah it works: %i", auth_items_get_int(items, "int"));
1151 // (void)auth_items_get_bool(items, "test3");
1152 // AuthorizationItemSet * itemSet = auth_items_get_item_set(items);
1153 // for (uint32_t i = 0; i < itemSet->count; i++) {
1154 // LOGD("item: %s", itemSet->items[i].name);
1157 // xpc_object_t xpcdata = SerializeItemSet(auth_items_get_item_set(items));
1158 // auth_items_t items2 = auth_items_create_with_xpc(xpcdata);
1159 // xpc_release(xpcdata);
1160 // auth_items_remove_with_flags(items2, 7);
1161 //// auth_items_set_string(items2, "test3", "testing 3 very good");
1162 // auth_items_copy_with_flags(items2, items, 7);
1163 // LOGD("Yeah it works: %s", auth_items_get_string(items2, "test3"));
1164 // auth_show(items2);
1165 // CFReleaseSafe(items2);
1167 // CFReleaseSafe(items);