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"
17 #include "AuthorizationTags.h"
18 #include "PreloginUserDb.h"
20 #include <bsm/libbsm.h>
21 #include <Security/Authorization.h>
22 #include <Security/AuthorizationPriv.h>
23 #include <Security/AuthorizationTagsPriv.h>
24 #include <Security/AuthorizationPlugin.h>
25 #include <xpc/private.h>
26 #include <dispatch/dispatch.h>
27 #include <CoreFoundation/CoreFoundation.h>
28 #include <CoreFoundation/CFXPCBridge.h>
29 #include <IOKit/IOMessage.h>
30 #include <IOKit/pwr_mgt/IOPMLib.h>
31 #include <IOKit/pwr_mgt/IOPMLibPrivate.h>
33 #include <security_utilities/simulatecrash_assert.h>
37 #define MAX_PROCESS_RIGHTS 100
39 static CFMutableDictionaryRef gProcessMap
= NULL
;
40 static CFMutableDictionaryRef gSessionMap
= NULL
;
41 static CFMutableDictionaryRef gAuthTokenMap
= NULL
;
42 static authdb_t gDatabase
= NULL
;
44 static bool gXPCTransaction
= false;
46 static dispatch_queue_t
47 get_server_dispatch_queue()
49 static dispatch_once_t onceToken
;
50 static dispatch_queue_t server_queue
= NULL
;
52 dispatch_once(&onceToken
, ^{
53 server_queue
= dispatch_queue_create("com.apple.security.auth.server", DISPATCH_QUEUE_SERIAL
);
54 check(server_queue
!= NULL
);
60 static Boolean
_processEqualCallBack(const void *value1
, const void *value2
)
62 audit_info_s
* info1
= (audit_info_s
*)value1
;
63 audit_info_s
* info2
= (audit_info_s
*)value2
;
64 if (info1
->pid
== info2
->pid
) {
65 if (info1
->tid
== info2
->tid
) {
72 static CFHashCode
_processHashCallBack(const void *value
)
74 audit_info_s
* info
= (audit_info_s
*)value
;
75 uint64_t crc
= crc64_init();
76 crc
= crc64_update(crc
, &info
->pid
, sizeof(info
->pid
));
77 crc
= crc64_update(crc
, &info
->tid
, sizeof(info
->tid
));
78 crc
= crc64_final(crc
);
79 return (CFHashCode
)crc
;
82 static const CFDictionaryKeyCallBacks kProcessMapKeyCallBacks
= {
86 .copyDescription
= NULL
,
87 .equal
= &_processEqualCallBack
,
88 .hash
= &_processHashCallBack
91 static Boolean
_sessionEqualCallBack(const void *value1
, const void *value2
)
93 return (*(session_id_t
*)value1
) == (*(session_id_t
*)value2
);
96 static CFHashCode
_sessionHashCallBack(const void *value
)
98 return (CFHashCode
)(*(session_id_t
*)(value
));
101 static const CFDictionaryKeyCallBacks kSessionMapKeyCallBacks
= {
105 .copyDescription
= NULL
,
106 .equal
= &_sessionEqualCallBack
,
107 .hash
= &_sessionHashCallBack
110 void server_cleanup()
112 CFRelease(gProcessMap
);
113 CFRelease(gSessionMap
);
114 CFRelease(gAuthTokenMap
);
116 dispatch_queue_t queue
= get_server_dispatch_queue();
118 dispatch_release(queue
);
122 bool server_in_dark_wake()
124 return IOPMIsADarkWake(IOPMConnectionGetSystemCapabilities());
127 authdb_t
server_get_database()
132 static void _setupAuditSessionMonitor()
134 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^{
135 au_sdev_handle_t
*dev
= au_sdev_open(AU_SDEVF_ALLSESSIONS
);
137 auditinfo_addr_t aia
;
140 os_log_error(AUTHD_LOG
, "server: could not open %{public}s %d", AUDIT_SDEV_PATH
, errno
);
145 if (0 != au_sdev_read_aia(dev
, &event
, &aia
)) {
146 os_log_error(AUTHD_LOG
, "server: au_sdev_read_aia failed: %d", errno
);
149 os_log_debug(AUTHD_LOG
, "server: au_sdev_handle_t event=%i, session=%i", event
, aia
.ai_asid
);
150 if (event
== AUE_SESSION_END
) {
151 dispatch_async(get_server_dispatch_queue(), ^{
152 os_log_debug(AUTHD_LOG
, "server: session %i destroyed", aia
.ai_asid
);
153 CFDictionaryRemoveValue(gSessionMap
, &aia
.ai_asid
);
161 static void _setupSignalHandlers()
163 signal(SIGTERM
, SIG_IGN
);
164 static dispatch_source_t sigtermHandler
;
165 sigtermHandler
= dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL
, SIGTERM
, 0, get_server_dispatch_queue());
166 if (sigtermHandler
) {
167 dispatch_source_set_event_handler(sigtermHandler
, ^{
169 // should we clean up any state?
172 dispatch_resume(sigtermHandler
);
176 OSStatus
server_init(void)
178 OSStatus status
= errAuthorizationSuccess
;
180 auditinfo_addr_t info
;
181 memset(&info
, 0, sizeof(info
));
182 getaudit_addr(&info
, sizeof(info
));
183 os_log_debug(AUTHD_LOG
, "server: uid=%i, sid=%i", info
.ai_auid
, info
.ai_asid
);
185 require_action(get_server_dispatch_queue() != NULL
, done
, status
= errAuthorizationInternal
);
187 gProcessMap
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kProcessMapKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
188 require_action(gProcessMap
!= NULL
, done
, status
= errAuthorizationInternal
);
190 gSessionMap
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kSessionMapKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
191 require_action(gSessionMap
!= NULL
, done
, status
= errAuthorizationInternal
);
193 gAuthTokenMap
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kAuthTokenKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
194 require_action(gAuthTokenMap
!= NULL
, done
, status
= errAuthorizationInternal
);
196 gDatabase
= authdb_create();
197 require_action(gDatabase
!= NULL
, done
, status
= errAuthorizationInternal
);
199 // check to see if we have an updates
200 authdb_connection_t dbconn
= authdb_connection_acquire(gDatabase
);
201 authdb_maintenance(dbconn
);
202 authdb_connection_release(&dbconn
);
204 _setupAuditSessionMonitor();
205 _setupSignalHandlers();
211 static void _server_parse_audit_token(audit_token_t
* token
, audit_info_s
* info
)
214 memset(info
, 0, sizeof(*info
));
216 memset(&tid
, 0, sizeof(tid
));
217 audit_token_to_au32(*token
, &info
->auid
, &info
->euid
,
218 &info
->egid
, &info
->ruid
, &info
->rgid
,
219 &info
->pid
, &info
->asid
, &tid
);
220 info
->tid
= tid
.port
;
221 info
->opaqueToken
= *token
;
226 server_register_connection(xpc_connection_t connection
)
228 __block connection_t conn
= NULL
;
229 __block session_t session
= NULL
;
230 __block process_t proc
= NULL
;
231 __block CFIndex conn_count
= 0;
233 require(connection
!= NULL
, done
);
235 audit_token_t auditToken
;
237 xpc_connection_get_audit_token(connection
, &auditToken
);
238 _server_parse_audit_token(&auditToken
, &info
);
241 dispatch_sync(get_server_dispatch_queue(), ^{
242 session
= (session_t
)CFDictionaryGetValue(gSessionMap
, &info
.asid
);
246 session
= session_create(info
.asid
);
247 CFDictionarySetValue(gSessionMap
, session_get_key(session
), session
);
250 proc
= (process_t
)CFDictionaryGetValue(gProcessMap
, &info
);
256 conn
= connection_create(proc
);
257 conn_count
= process_add_connection(proc
, conn
);
259 proc
= process_create(&info
, session
);
261 conn
= connection_create(proc
);
262 conn_count
= process_add_connection(proc
, conn
);
263 session_add_process(session
, proc
);
264 CFDictionarySetValue(gProcessMap
, process_get_key(proc
), proc
);
268 if (!gXPCTransaction
) {
269 xpc_transaction_begin();
270 gXPCTransaction
= true;
274 os_log_debug(AUTHD_LOG
, "server: registered connection (total=%li)", conn_count
);
277 CFReleaseSafe(session
);
283 server_unregister_connection(connection_t conn
)
285 assert(conn
); // marked non-null
286 process_t proc
= connection_get_process(conn
);
288 dispatch_sync(get_server_dispatch_queue(), ^{
289 CFIndex connectionCount
= process_get_connection_count(proc
);
290 os_log_debug(AUTHD_LOG
, "server: unregistered connection (total=%li)", connectionCount
);
292 if (connectionCount
== 1) {
293 CFDictionaryRemoveValue(gProcessMap
, process_get_key(proc
));
296 if (CFDictionaryGetCount(gProcessMap
) == 0) {
297 xpc_transaction_end();
298 gXPCTransaction
= false;
301 // move the destruction of the connection/process off the server queue
306 server_register_auth_token(auth_token_t auth
)
308 assert(auth
); // marked non-null
309 dispatch_sync(get_server_dispatch_queue(), ^{
310 os_log_debug(AUTHD_LOG
, "server: registering authorization");
311 CFDictionarySetValue(gAuthTokenMap
, auth_token_get_key(auth
), auth
);
312 auth_token_set_state(auth
, auth_token_state_registered
);
317 server_unregister_auth_token(auth_token_t auth
)
320 AuthorizationBlob blob
= *(AuthorizationBlob
*)auth_token_get_key(auth
);
321 dispatch_async(get_server_dispatch_queue(), ^{
322 os_log_debug(AUTHD_LOG
, "server: unregistering authorization");
323 CFDictionaryRemoveValue(gAuthTokenMap
, &blob
);
328 server_find_copy_auth_token(AuthorizationBlob
* blob
)
330 assert(blob
); // marked non-null
331 __block auth_token_t auth
= NULL
;
332 dispatch_sync(get_server_dispatch_queue(), ^{
333 auth
= (auth_token_t
)CFDictionaryGetValue(gAuthTokenMap
, blob
);
342 server_find_copy_session(session_id_t sid
, bool create
)
344 __block session_t session
= NULL
;
346 dispatch_sync(get_server_dispatch_queue(), ^{
347 session
= (session_t
)CFDictionaryGetValue(gSessionMap
, &sid
);
351 session
= session_create(sid
);
353 CFDictionarySetValue(gSessionMap
, session_get_key(session
), session
);
365 _process_find_copy_auth_token_from_xpc(process_t proc
, xpc_object_t message
, auth_token_t
* auth_out
)
367 OSStatus status
= errAuthorizationSuccess
;
368 require_action(auth_out
!= NULL
, done
, status
= errAuthorizationInternal
);
371 AuthorizationBlob
* blob
= (AuthorizationBlob
*)xpc_dictionary_get_data(message
, AUTH_XPC_BLOB
, &len
);
372 require_action(blob
!= NULL
, done
, status
= errAuthorizationInvalidRef
);
373 require_action(len
== sizeof(AuthorizationBlob
), done
, status
= errAuthorizationInvalidRef
);
375 auth_token_t auth
= process_find_copy_auth_token(proc
, blob
);
376 require_action(auth
!= NULL
, done
, status
= errAuthorizationInvalidRef
);
379 os_log_debug(AUTHD_LOG
, "server: authtoken lookup %#x%x %p", blob
->data
[1],blob
->data
[0], auth
);
381 os_log_debug(AUTHD_LOG
, "server: authtoken lookup");
390 static OSStatus
_server_get_right_properties(connection_t conn
, const char *rightName
, CFDictionaryRef
*properties
)
392 OSStatus status
= errAuthorizationDenied
;
393 auth_token_t auth
= NULL
;
394 engine_t engine
= NULL
;
396 require_action(conn
, done
, status
= errAuthorizationInternal
);
398 auth
= auth_token_create(connection_get_process(conn
), false);
399 require_action(auth
, done
, status
= errAuthorizationInternal
);
401 engine
= engine_create(conn
, auth
);
402 require_action(engine
, done
, status
= errAuthorizationInternal
);
404 status
= engine_get_right_properties(engine
, rightName
, properties
);
407 CFReleaseSafe(engine
);
412 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
)
414 __block OSStatus status
= errAuthorizationDenied
;
415 engine_t engine
= NULL
;
417 require_action(conn
, done
, status
= errAuthorizationInternal
);
419 engine
= engine_create(conn
, auth
);
420 require_action(engine
, done
, status
= errAuthorizationInternal
);
422 if (flags
& kAuthorizationFlagInteractionAllowed
) {
423 dispatch_sync(connection_get_dispatch_queue(conn
), ^{
424 connection_set_engine(conn
, engine
);
425 status
= engine_authorize(engine
, rights
, environment
, flags
);
426 connection_set_engine(conn
, NULL
);
429 status
= engine_authorize(engine
, rights
, environment
, flags
);
435 *engine_out
= engine
;
443 // IN: AUTH_XPC_RIGHTS, AUTH_XPC_ENVIRONMENT, AUTH_XPC_FLAGS
444 // OUT: AUTH_XPC_BLOB
446 authorization_create(connection_t conn
, xpc_object_t message
, xpc_object_t reply
)
448 OSStatus status
= errAuthorizationDenied
;
450 process_t proc
= connection_get_process(conn
);
453 auth_rights_t rights
= auth_rights_create_with_xpc(xpc_dictionary_get_value(message
, AUTH_XPC_RIGHTS
));
454 auth_items_t environment
= auth_items_create_with_xpc(xpc_dictionary_get_value(message
, AUTH_XPC_ENVIRONMENT
));
455 AuthorizationFlags flags
= (AuthorizationFlags
)xpc_dictionary_get_uint64(message
, AUTH_XPC_FLAGS
);
457 // Create Authorization Token
458 auth_token_t auth
= auth_token_create(proc
, flags
& kAuthorizationFlagLeastPrivileged
);
459 require_action(auth
!= NULL
, done
, status
= errAuthorizationInternal
);
461 if (!(flags
& kAuthorizationFlagNoData
)) {
462 process_add_auth_token(proc
,auth
);
465 status
= _server_authorize(conn
, auth
, flags
, rights
, environment
, NULL
);
466 require_noerr(status
, done
);
469 xpc_dictionary_set_data(reply
, AUTH_XPC_BLOB
, auth_token_get_blob(auth
), sizeof(AuthorizationBlob
));
472 CFReleaseSafe(rights
);
473 CFReleaseSafe(environment
);
478 // IN: AUTH_XPC_DATA, AUTH_XPC_ENVIRONMENT, AUTH_XPC_FLAGS
479 // OUT: AUTH_XPC_BLOB
480 OSStatus
authorization_create_with_audit_token(connection_t conn
, xpc_object_t message
, xpc_object_t reply
)
482 OSStatus status
= errAuthorizationDenied
;
483 auth_token_t auth
= NULL
;
485 process_t proc
= connection_get_process(conn
);
486 require(process_get_uid(proc
) == 0, done
); //only root can use this call
490 const char * data
= xpc_dictionary_get_data(message
, AUTH_XPC_DATA
, &len
);
491 require(data
!= NULL
, done
);
492 require(len
== sizeof(audit_token_t
), done
);
494 // auth_items_t environment = auth_items_create_with_xpc(xpc_dictionary_get_value(message, AUTH_XPC_ENVIRONMENT));
495 AuthorizationFlags flags
= (AuthorizationFlags
)xpc_dictionary_get_uint64(message
, AUTH_XPC_FLAGS
);
497 audit_info_s auditInfo
;
498 _server_parse_audit_token((audit_token_t
*)data
, &auditInfo
);
500 // Create Authorization Token
501 auth
= auth_token_create(proc
, flags
& kAuthorizationFlagLeastPrivileged
);
502 require_action(auth
!= NULL
, done
, status
= errAuthorizationInternal
);
504 process_add_auth_token(proc
,auth
);
507 xpc_dictionary_set_data(reply
, AUTH_XPC_BLOB
, auth_token_get_blob(auth
), sizeof(AuthorizationBlob
));
510 // CFReleaseSafe(environment);
515 // IN: AUTH_XPC_BLOB, AUTH_XPC_FLAGS
518 authorization_free(connection_t conn
, xpc_object_t message
, xpc_object_t reply AUTH_UNUSED
)
520 OSStatus status
= errAuthorizationSuccess
;
521 AuthorizationFlags flags
= 0;
522 process_t proc
= connection_get_process(conn
);
524 auth_token_t auth
= NULL
;
525 status
= _process_find_copy_auth_token_from_xpc(proc
, message
, &auth
);
526 require_noerr(status
, done
);
528 flags
= (AuthorizationFlags
)xpc_dictionary_get_uint64(message
, AUTH_XPC_FLAGS
);
530 if (flags
& kAuthorizationFlagDestroyRights
) {
531 auth_token_credentials_iterate(auth
, ^bool(credential_t cred
) {
532 credential_invalidate(cred
);
533 os_log_debug(AUTHD_LOG
, "engine[%i]: invalidating %{public}scredential %{public}s (%i)", connection_get_pid(conn
), credential_get_shared(cred
) ? "shared " : "", credential_get_name(cred
), credential_get_uid(cred
));
537 session_credentials_purge(auth_token_get_session(auth
));
540 process_remove_auth_token(proc
, auth
, flags
);
544 os_log_debug(AUTHD_LOG
, "server: AuthorizationFree %d (flags:%x)", (int)status
, (unsigned int)flags
);
548 // IN: AUTH_XPC_BLOB, AUTH_XPC_DATA
551 authorization_copy_right_properties(connection_t conn
, xpc_object_t message
, xpc_object_t reply
)
553 OSStatus status
= errAuthorizationDenied
;
554 CFDataRef serializedProperties
= NULL
;
555 CFDictionaryRef properties
= NULL
;
558 const char *right
= xpc_dictionary_get_string(message
, AUTH_XPC_RIGHT_NAME
);
559 os_log_debug(AUTHD_LOG
, "server: right %s", right
);
561 require_action(right
!= NULL
, done
, status
= errAuthorizationInvalidPointer
);
563 status
= _server_get_right_properties(conn
, right
, &properties
);
564 require_noerr(status
, done
);
567 serializedProperties
= CFPropertyListCreateData(kCFAllocatorDefault
, properties
, kCFPropertyListBinaryFormat_v1_0
, 0, NULL
);
568 if (serializedProperties
) {
569 xpc_dictionary_set_data(reply
, AUTH_XPC_OUT_ITEMS
, CFDataGetBytePtr(serializedProperties
), CFDataGetLength(serializedProperties
));
574 CFReleaseSafe(serializedProperties
);
575 CFReleaseSafe(properties
);
580 // IN: AUTH_XPC_BLOB, AUTH_XPC_RIGHTS, AUTH_XPC_ENVIRONMENT, AUTH_XPC_FLAGS
581 // OUT: AUTH_XPC_OUT_ITEMS
583 authorization_copy_rights(connection_t conn
, xpc_object_t message
, xpc_object_t reply
)
585 OSStatus status
= errAuthorizationDenied
;
586 engine_t engine
= NULL
;
588 process_t proc
= connection_get_process(conn
);
591 auth_rights_t rights
= auth_rights_create_with_xpc(xpc_dictionary_get_value(message
, AUTH_XPC_RIGHTS
));
592 auth_items_t environment
= auth_items_create_with_xpc(xpc_dictionary_get_value(message
, AUTH_XPC_ENVIRONMENT
));
593 AuthorizationFlags flags
= (AuthorizationFlags
)xpc_dictionary_get_uint64(message
, AUTH_XPC_FLAGS
);
595 auth_token_t auth
= NULL
;
596 status
= _process_find_copy_auth_token_from_xpc(proc
, message
, &auth
);
597 require_noerr_action_quiet(status
, done
, os_log_error(AUTHD_LOG
, "copy_rights: no auth token"));
599 status
= _server_authorize(conn
, auth
, flags
, rights
, environment
, &engine
);
600 require_noerr_action_quiet(status
, done
, os_log_error(AUTHD_LOG
, "copy_rights: authorization failed"));
603 xpc_object_t outItems
= auth_rights_export_xpc(engine_get_granted_rights(engine
));
604 xpc_dictionary_set_value(reply
, AUTH_XPC_OUT_ITEMS
, outItems
);
605 xpc_release_safe(outItems
);
608 CFReleaseSafe(rights
);
609 CFReleaseSafe(environment
);
611 CFReleaseSafe(engine
);
616 // IN: AUTH_XPC_BLOB, AUTH_XPC_TAG
617 // OUT: AUTH_XPC_OUT_ITEMS
619 authorization_copy_info(connection_t conn
, xpc_object_t message
, xpc_object_t reply
)
622 OSStatus status
= errAuthorizationSuccess
;
623 auth_items_t items
= NULL
;
624 auth_items_t local_items
= NULL
;
625 const char * tag
= NULL
;
627 process_t proc
= connection_get_process(conn
);
629 auth_token_t auth
= NULL
;
630 status
= _process_find_copy_auth_token_from_xpc(proc
, message
, &auth
);
631 require_noerr_action_quiet(status
, done
, os_log_error(AUTHD_LOG
, "copy_info: no auth token"));
633 items
= auth_items_create();
635 tag
= xpc_dictionary_get_string(message
, AUTH_XPC_TAG
);
636 os_log_debug(AUTHD_LOG
, "server: requested tag: %{public}s", tag
? tag
: "(all)");
639 const void * data
= auth_items_get_data_with_flags(auth_token_get_context(auth
), tag
, &len
, kAuthorizationContextFlagExtractable
);
641 os_log_debug(AUTHD_LOG
, "server: requested tag found");
642 auth_items_set_data(items
, tag
, data
, len
);
645 auth_items_copy_with_flags(items
, auth_token_get_context(auth
), kAuthorizationContextFlagExtractable
);
648 local_items
= auth_items_create();
649 auth_items_content_copy(local_items
, items
); // we do not want decrypt content of the authorizationref memory which is where pointers point to
650 auth_items_decrypt(local_items
, auth_token_get_encryption_key(auth
));
651 os_log_debug(AUTHD_LOG
, "server: decrypted authorization context data");
654 os_log_debug(AUTHD_LOG
, "server: Dumping requested AuthRef items: %{public}@", items
);
657 if (auth_items_exist(local_items
, kAuthorizationEnvironmentPassword
)) {
658 // check if caller is entitled to get the password
659 CFTypeRef extract_password_entitlement
= process_copy_entitlement_value(proc
, "com.apple.authorization.extract-password");
660 if (extract_password_entitlement
&& (CFGetTypeID(extract_password_entitlement
) == CFBooleanGetTypeID()) && extract_password_entitlement
== kCFBooleanTrue
) {
661 os_log_debug(AUTHD_LOG
, "server: caller allowed to extract password");
663 os_log_error(AUTHD_LOG
, "server: caller NOT allowed to extract password");
664 auth_items_remove(local_items
, kAuthorizationEnvironmentPassword
);
666 CFReleaseSafe(extract_password_entitlement
);
670 xpc_object_t outItems
= auth_items_export_xpc(local_items
);
671 xpc_dictionary_set_value(reply
, AUTH_XPC_OUT_ITEMS
, outItems
);
672 xpc_release_safe(outItems
);
675 CFReleaseSafe(local_items
);
676 CFReleaseSafe(items
);
678 os_log_debug(AUTHD_LOG
, "server: AuthorizationCopyInfo %i", (int) status
);
683 // OUT: AUTH_XPC_EXTERNAL
685 authorization_make_external_form(connection_t conn
, xpc_object_t message
, xpc_object_t reply
)
687 OSStatus status
= errAuthorizationSuccess
;
689 process_t proc
= connection_get_process(conn
);
691 auth_token_t auth
= NULL
;
692 status
= _process_find_copy_auth_token_from_xpc(proc
, message
, &auth
);
693 require_noerr(status
, done
);
695 AuthorizationExternalForm exForm
;
696 AuthorizationExternalBlob
* exBlob
= (AuthorizationExternalBlob
*)&exForm
;
697 memset(&exForm
, 0, sizeof(exForm
));
699 exBlob
->blob
= *auth_token_get_blob(auth
);
700 exBlob
->session
= process_get_session_id(proc
);
702 xpc_dictionary_set_data(reply
, AUTH_XPC_EXTERNAL
, &exForm
, sizeof(exForm
));
703 server_register_auth_token(auth
);
707 os_log_debug(AUTHD_LOG
, "server: AuthorizationMakeExternalForm %d", (int)status
);
711 // IN: AUTH_XPC_EXTERNAL
712 // OUT: AUTH_XPC_BLOB
714 authorization_create_from_external_form(connection_t conn
, xpc_object_t message
, xpc_object_t reply
)
716 OSStatus status
= errAuthorizationSuccess
;
717 auth_token_t auth
= NULL
;
719 process_t proc
= connection_get_process(conn
);
722 AuthorizationExternalForm
* exForm
= (AuthorizationExternalForm
*)xpc_dictionary_get_data(message
, AUTH_XPC_EXTERNAL
, &len
);
723 require_action(exForm
!= NULL
, done
, status
= errAuthorizationInternal
);
724 require_action(len
== sizeof(AuthorizationExternalForm
), done
, status
= errAuthorizationInvalidRef
);
726 AuthorizationExternalBlob
* exBlob
= (AuthorizationExternalBlob
*)exForm
;
727 auth
= server_find_copy_auth_token(&exBlob
->blob
);
728 require_action(auth
!= NULL
, done
, status
= errAuthorizationDenied
);
730 process_add_auth_token(proc
, auth
);
731 xpc_dictionary_set_data(reply
, AUTH_XPC_BLOB
, auth_token_get_blob(auth
), sizeof(AuthorizationBlob
));
735 os_log_debug(AUTHD_LOG
, "server: AuthorizationCreateFromExternalForm %d", (int)status
);
739 // IN: AUTH_XPC_RIGHT_NAME
740 // OUT: AUTH_XPC_DATA
742 authorization_right_get(connection_t conn AUTH_UNUSED
, xpc_object_t message
, xpc_object_t reply
)
744 OSStatus status
= errAuthorizationDenied
;
746 CFTypeRef cfdict
= NULL
;
747 xpc_object_t xpcdict
= NULL
;
749 authdb_connection_t dbconn
= authdb_connection_acquire(server_get_database());
750 rule
= rule_create_with_string(xpc_dictionary_get_string(message
, AUTH_XPC_RIGHT_NAME
), dbconn
);
751 require(rule
!= NULL
, done
);
752 require(rule_get_id(rule
) != 0, done
);
754 cfdict
= rule_copy_to_cfobject(rule
, dbconn
);
755 require(cfdict
!= NULL
, done
);
757 xpcdict
= _CFXPCCreateXPCObjectFromCFObject(cfdict
);
758 require(xpcdict
!= NULL
, done
);
761 xpc_dictionary_set_value(reply
, AUTH_XPC_DATA
, xpcdict
);
763 status
= errAuthorizationSuccess
;
766 authdb_connection_release(&dbconn
);
767 CFReleaseSafe(cfdict
);
768 xpc_release_safe(xpcdict
);
770 os_log_debug(AUTHD_LOG
, "server: AuthorizationRightGet %d", (int)status
);
774 static bool _prompt_for_modifications(process_t __unused proc
, rule_t __unused rule
)
776 // <rdar://problem/13853228> will put back it back at some later date
777 // SecRequirementRef ruleReq = rule_get_requirement(rule);
779 // if (ruleReq && process_verify_requirment(proc, ruleReq)) {
786 static CFIndex
_get_mechanism_index(CFArrayRef mechanisms
, CFStringRef m_name
)
789 require(mechanisms
, done
);
791 CFIndex c
= CFArrayGetCount(mechanisms
);
792 CFStringRef i_name
= NULL
;
793 for (CFIndex i
= 0; i
< c
; ++i
)
795 i_name
= CFArrayGetValueAtIndex(mechanisms
, i
);
796 if (i_name
&& (CFGetTypeID(m_name
) == CFStringGetTypeID())) {
797 if (CFStringCompare(i_name
, m_name
, kCFCompareCaseInsensitive
) == kCFCompareEqualTo
) {
808 static bool _update_rule_mechanism(authdb_connection_t dbconn
, const char * rule_name
, CFStringRef mechanism_name
, CFStringRef insert_after_name
, bool remove
)
810 bool updated
= false;
812 rule_t update_rule
= NULL
;
813 CFMutableDictionaryRef cfdict
= NULL
;
814 CFStringRef update_name
= NULL
;
816 require(mechanism_name
, done
);
818 rule
= rule_create_with_string(rule_name
, dbconn
);
819 require(rule_get_id(rule
) != 0, done
); // rule doesn't exist in the database
821 cfdict
= rule_copy_to_cfobject(rule
, dbconn
);
822 require(cfdict
!= NULL
, done
);
824 CFMutableArrayRef mechanisms
= NULL
;
825 bool res
= CFDictionaryGetValueIfPresent(cfdict
, CFSTR(kAuthorizationRuleParameterMechanisms
), (void*)&mechanisms
);
826 require(res
== true, done
);
831 index
= _get_mechanism_index(mechanisms
, mechanism_name
);
833 if (insert_after_name
) {
834 if ((index
= _get_mechanism_index(mechanisms
, insert_after_name
)) != -1) {
837 index
= 0; // if we couldn't find the index add it to the begining
846 CFArrayRemoveValueAtIndex(mechanisms
, index
);
848 if (index
< CFArrayGetCount(mechanisms
)) {
849 require_action(CFStringCompare(CFArrayGetValueAtIndex(mechanisms
, index
), mechanism_name
, kCFCompareCaseInsensitive
) != kCFCompareEqualTo
, done
, updated
= true);
851 CFArrayInsertValueAtIndex(mechanisms
, index
, mechanism_name
);
854 CFDictionarySetValue(cfdict
, CFSTR(kAuthorizationRuleParameterMechanisms
), mechanisms
);
857 update_name
= CFStringCreateWithCString(kCFAllocatorDefault
, rule_name
, kCFStringEncodingUTF8
);
858 require(update_name
, done
);
859 update_rule
= rule_create_with_plist(rule_get_type(rule
), update_name
, cfdict
, dbconn
);
860 require(update_rule
, done
);
862 require(rule_sql_commit(update_rule
, dbconn
, CFAbsoluteTimeGetCurrent(), NULL
), done
);
869 CFReleaseSafe(update_rule
);
870 CFReleaseSafe(cfdict
);
871 CFReleaseSafe(update_name
);
875 /// IN: AUTH_XPC_BLOB, AUTH_XPC_INT64
878 authorization_enable_smartcard(connection_t conn
, xpc_object_t message
, xpc_object_t reply AUTH_UNUSED
)
880 const CFStringRef SMARTCARD_LINE
= CFSTR("builtin:smartcard-sniffer,privileged");
881 const CFStringRef BUILTIN_LINE
= CFSTR("builtin:policy-banner");
882 const char* SYSTEM_LOGIN_CONSOLE
= "system.login.console";
883 const char* AUTHENTICATE
= "authenticate";
885 __block OSStatus status
= errAuthorizationSuccess
;
886 bool enable_smartcard
= false;
887 authdb_connection_t dbconn
= NULL
;
888 auth_token_t auth
= NULL
;
889 auth_rights_t checkRight
= NULL
;
891 process_t proc
= connection_get_process(conn
);
893 status
= _process_find_copy_auth_token_from_xpc(proc
, message
, &auth
);
894 require_noerr(status
, done
);
896 checkRight
= auth_rights_create();
897 auth_rights_add(checkRight
, "config.modify.smartcard");
898 status
= _server_authorize(conn
, auth
, kAuthorizationFlagDefaults
| kAuthorizationFlagInteractionAllowed
| kAuthorizationFlagExtendRights
, checkRight
, NULL
, NULL
);
899 require_noerr(status
, done
);
901 enable_smartcard
= xpc_dictionary_get_bool(message
, AUTH_XPC_DATA
);
903 dbconn
= authdb_connection_acquire(server_get_database());
905 if (!_update_rule_mechanism(dbconn
, SYSTEM_LOGIN_CONSOLE
, SMARTCARD_LINE
, BUILTIN_LINE
, enable_smartcard
? false : true)) {
906 status
= errAuthorizationInternal
;
907 os_log_error(AUTHD_LOG
, "server: smartcard: enable(%i) failed to update %{public}s", enable_smartcard
, SYSTEM_LOGIN_CONSOLE
);
909 if (!_update_rule_mechanism(dbconn
, AUTHENTICATE
, SMARTCARD_LINE
, NULL
, enable_smartcard
? false : true)) {
910 status
= errAuthorizationInternal
;
911 os_log_error(AUTHD_LOG
, "server: smartcard: enable(%i) failed to update %{public}s", enable_smartcard
, AUTHENTICATE
);
914 authdb_checkpoint(dbconn
);
917 authdb_connection_release(&dbconn
);
918 CFReleaseSafe(checkRight
);
923 static int64_t _process_get_identifier_count(process_t proc
, authdb_connection_t conn
)
925 __block
int64_t result
= 0;
927 authdb_step(conn
, "SELECT COUNT(*) AS cnt FROM rules WHERE identifier = ? ", ^(sqlite3_stmt
*stmt
) {
928 sqlite3_bind_text(stmt
, 1, process_get_identifier(proc
), -1, NULL
);
929 }, ^bool(auth_items_t data
) {
930 result
= auth_items_get_int64(data
, "cnt");
937 static int64_t _get_max_process_rights()
939 static dispatch_once_t onceToken
;
940 static int64_t max_rights
= MAX_PROCESS_RIGHTS
;
942 //sudo defaults write /Library/Preferences/com.apple.authd max_process_rights -bool true
943 dispatch_once(&onceToken
, ^{
944 CFTypeRef max
= (CFNumberRef
)CFPreferencesCopyValue(CFSTR("max_process_rights"), CFSTR(SECURITY_AUTH_NAME
), kCFPreferencesAnyUser
, kCFPreferencesCurrentHost
);
946 if (max
&& CFGetTypeID(max
) == CFNumberGetTypeID()) {
947 CFNumberGetValue(max
, kCFNumberSInt64Type
, &max_rights
);
955 // IN: AUTH_XPC_BLOB, AUTH_XPC_RIGHT_NAME, AUTH_XPC_DATA
958 authorization_right_set(connection_t conn
, xpc_object_t message
, xpc_object_t reply AUTH_UNUSED
)
960 __block OSStatus status
= errAuthorizationDenied
;
961 __block engine_t engine
= NULL
;
962 CFStringRef cf_rule_name
= NULL
;
963 CFDictionaryRef cf_rule_dict
= NULL
;
965 rule_t existingRule
= NULL
;
966 authdb_connection_t dbconn
= NULL
;
967 auth_token_t auth
= NULL
;
968 bool force_modify
= false;
969 RuleType rule_type
= RT_RIGHT
;
970 const char * rule_name
= NULL
;
971 bool auth_rule
= false;
973 process_t proc
= connection_get_process(conn
);
975 status
= _process_find_copy_auth_token_from_xpc(proc
, message
, &auth
);
976 require_noerr(status
, done
);
978 require_action(xpc_dictionary_get_string(message
, AUTH_XPC_RIGHT_NAME
) != NULL
, done
, status
= errAuthorizationInternal
);
979 require_action(xpc_dictionary_get_value(message
, AUTH_XPC_DATA
) != NULL
, done
, status
= errAuthorizationInternal
);
981 rule_name
= xpc_dictionary_get_string(message
, AUTH_XPC_RIGHT_NAME
);
982 require(rule_name
!= NULL
, done
);
984 if (_compare_string(rule_name
, "authenticate")) {
989 cf_rule_name
= CFStringCreateWithCString(kCFAllocatorDefault
, rule_name
, kCFStringEncodingUTF8
);
990 require(cf_rule_name
!= NULL
, done
);
992 cf_rule_dict
= _CFXPCCreateCFObjectFromXPCObject(xpc_dictionary_get_value(message
, AUTH_XPC_DATA
));
993 require(cf_rule_dict
!= NULL
, done
);
995 dbconn
= authdb_connection_acquire(server_get_database());
997 rule
= rule_create_with_plist(rule_type
, cf_rule_name
, cf_rule_dict
, dbconn
);
998 if (process_get_uid(proc
) != 0) {
999 require_action(rule_get_extract_password(rule
) == false, done
, status
= errAuthorizationDenied
; os_log_error(AUTHD_LOG
, "server: AuthorizationRightSet not allowed to set extract-password. (denied)"));
1002 // if rule doesn't currently exist then we have to check to see if they are over the Max.
1003 if (rule_get_id(rule
) == 0) {
1004 if (process_get_identifier(proc
) == NULL
) {
1005 os_log_error(AUTHD_LOG
, "server: AuthorizationRightSet required for process %{public}s (missing code signature). To add rights to the Authorization database, your process must have a code signature.", process_get_code_url(proc
));
1006 force_modify
= true;
1008 int64_t process_rule_count
= _process_get_identifier_count(proc
, dbconn
);
1009 if ((process_rule_count
>= _get_max_process_rights())) {
1010 if (!connection_get_syslog_warn(conn
)) {
1011 os_log_error(AUTHD_LOG
, "server: AuthorizationRightSet Denied API abuse process %{public}s already contains %lli rights.", process_get_code_url(proc
), _get_max_process_rights());
1012 connection_set_syslog_warn(conn
);
1014 status
= errAuthorizationDenied
;
1020 if (process_get_uid(proc
) != 0) {
1021 os_log_error(AUTHD_LOG
, "server: AuthorizationRightSet denied, root required to update the 'authenticate' rule");
1022 status
= errAuthorizationDenied
;
1026 // verify they are updating a right and not a rule
1027 existingRule
= rule_create_with_string(rule_get_name(rule
), dbconn
);
1028 if (rule_get_type(existingRule
) == RT_RULE
) {
1029 os_log_error(AUTHD_LOG
, "server: AuthorizationRightSet Denied updating '%{public}s' rule is prohibited", rule_get_name(existingRule
));
1030 status
= errAuthorizationDenied
;
1036 if (_prompt_for_modifications(proc
,rule
)) {
1037 authdb_connection_release(&dbconn
);
1039 dispatch_sync(connection_get_dispatch_queue(conn
), ^{
1040 engine
= engine_create(conn
, auth
);
1041 connection_set_engine(conn
, engine
);
1042 status
= engine_verify_modification(engine
, rule
, false, force_modify
);
1043 connection_set_engine(conn
, NULL
);
1045 require_noerr(status
, done
);
1047 dbconn
= authdb_connection_acquire(server_get_database());
1050 if (rule_sql_commit(rule
, dbconn
, engine
? engine_get_time(engine
) : CFAbsoluteTimeGetCurrent(), proc
)) {
1051 os_log_debug(AUTHD_LOG
, "server: Successfully updated rule %{public}s", rule_get_name(rule
));
1052 authdb_checkpoint(dbconn
);
1053 status
= errAuthorizationSuccess
;
1055 os_log_error(AUTHD_LOG
, "server: Failed to update rule %{public}s", rule_get_name(rule
));
1056 status
= errAuthorizationDenied
;
1060 authdb_connection_release(&dbconn
);
1061 CFReleaseSafe(existingRule
);
1062 CFReleaseSafe(cf_rule_name
);
1063 CFReleaseSafe(cf_rule_dict
);
1064 CFReleaseSafe(auth
);
1065 CFReleaseSafe(rule
);
1066 CFReleaseSafe(engine
);
1070 // IN: AUTH_XPC_BLOB, AUTH_XPC_RIGHT_NAME
1073 authorization_right_remove(connection_t conn
, xpc_object_t message
, xpc_object_t reply AUTH_UNUSED
)
1075 __block OSStatus status
= errAuthorizationDenied
;
1076 __block engine_t engine
= NULL
;
1078 authdb_connection_t dbconn
= NULL
;
1080 process_t proc
= connection_get_process(conn
);
1082 auth_token_t auth
= NULL
;
1083 status
= _process_find_copy_auth_token_from_xpc(proc
, message
, &auth
);
1084 require_noerr(status
, done
);
1086 dbconn
= authdb_connection_acquire(server_get_database());
1088 rule
= rule_create_with_string(xpc_dictionary_get_string(message
, AUTH_XPC_RIGHT_NAME
), dbconn
);
1089 require(rule
!= NULL
, done
);
1091 if (_prompt_for_modifications(proc
,rule
)) {
1092 authdb_connection_release(&dbconn
);
1094 dispatch_sync(connection_get_dispatch_queue(conn
), ^{
1095 engine
= engine_create(conn
, auth
);
1096 connection_set_engine(conn
, engine
);
1097 status
= engine_verify_modification(engine
, rule
, true, false);
1098 connection_set_engine(conn
, NULL
);
1100 require_noerr(status
, done
);
1102 dbconn
= authdb_connection_acquire(server_get_database());
1105 if (rule_get_id(rule
) != 0) {
1106 rule_sql_remove(rule
, dbconn
, proc
);
1110 authdb_connection_release(&dbconn
);
1111 CFReleaseSafe(auth
);
1112 CFReleaseSafe(rule
);
1113 CFReleaseSafe(engine
);
1114 os_log_debug(AUTHD_LOG
, "server: AuthorizationRightRemove %d", (int)status
);
1119 #pragma mark test code
1122 session_set_user_preferences(connection_t conn
, xpc_object_t message
, xpc_object_t reply
)
1127 return errAuthorizationSuccess
;
1132 // rule_t rule = rule_create_with_string("system.preferences.accounts");
1133 // CFDictionaryRef dict = rule_copy_to_cfobject(rule);
1135 // CFReleaseSafe(rule);
1136 // CFReleaseSafe(dict);
1138 // auth_items_t config = NULL;
1139 // double d2 = 0, d1 = 5;
1140 // authdb_get_key_value(server_get_authdb_reader(), "config", &config);
1141 // auth_items_set_double(config, "test", d1);
1142 // d2 = auth_items_get_double(config, "test");
1143 // os_log_debug(AUTHD_LOG, "d1=%f d2=%f", d1, d2);
1144 // CFReleaseSafe(config);
1147 // auth_items_t items = auth_items_create();
1148 // auth_items_set_string(items, "test", "testing 1");
1149 // auth_items_set_string(items, "test2", "testing 2");
1150 // auth_items_set_string(items, "test3", "testing 3");
1151 // auth_items_set_flags(items, "test3", 4);
1152 // auth_items_set_string(items, "apple", "apple");
1153 // auth_items_set_flags(items, "apple", 1);
1154 // auth_items_set_int(items, "int", 45);
1155 // auth_items_set_flags(items, "int", 2);
1156 // auth_items_set_bool(items, "true", true);
1157 // auth_items_set_bool(items, "false", false);
1158 // auth_items_set(items, "com.apple.");
1159 // auth_show(items);
1160 // LOGD("Yeah it works: %s", auth_items_get_string(items, "test3"));
1161 // LOGD("Yeah it works: %i", auth_items_get_bool(items, "true"));
1162 // LOGD("Yeah it works: %i", auth_items_get_bool(items, "false"));
1163 // LOGD("Yeah it works: %i", auth_items_get_int(items, "int"));
1164 // (void)auth_items_get_bool(items, "test3");
1165 // AuthorizationItemSet * itemSet = auth_items_get_item_set(items);
1166 // for (uint32_t i = 0; i < itemSet->count; i++) {
1167 // LOGD("item: %s", itemSet->items[i].name);
1170 // xpc_object_t xpcdata = SerializeItemSet(auth_items_get_item_set(items));
1171 // auth_items_t items2 = auth_items_create_with_xpc(xpcdata);
1172 // xpc_release(xpcdata);
1173 // auth_items_remove_with_flags(items2, 7);
1174 //// auth_items_set_string(items2, "test3", "testing 3 very good");
1175 // auth_items_copy_with_flags(items2, items, 7);
1176 // LOGD("Yeah it works: %s", auth_items_get_string(items2, "test3"));
1177 // auth_show(items2);
1178 // CFReleaseSafe(items2);
1180 // CFReleaseSafe(items);
1183 // IN: AUTH_XPC_TAG, AUTH_XPC_FLAGS
1184 // OUT: AUTH_XPC_DATA
1186 authorization_copy_prelogin_userdb(connection_t conn
, xpc_object_t message
, xpc_object_t reply
)
1188 OSStatus status
= errAuthorizationDenied
;
1189 xpc_object_t xpcarr
= NULL
;
1190 CFArrayRef cfarray
= NULL
;
1192 const char *uuid
= xpc_dictionary_get_string(message
, AUTH_XPC_TAG
);
1193 UInt32 flags
= (AuthorizationFlags
)xpc_dictionary_get_uint64(message
, AUTH_XPC_FLAGS
);
1195 status
= preloginudb_copy_userdb(uuid
, flags
, &cfarray
);
1196 xpc_dictionary_set_int64(reply
, AUTH_XPC_STATUS
, status
);
1197 require_noerr_action_quiet(status
, done
, os_log_error(AUTHD_LOG
, "authorization_copy_prelogin_userdb: database failed"));
1199 xpcarr
= _CFXPCCreateXPCObjectFromCFObject(cfarray
);
1200 require(xpcarr
!= NULL
, done
);
1201 xpc_dictionary_set_value(reply
, AUTH_XPC_DATA
, xpcarr
);
1204 CFReleaseSafe(cfarray
);
1205 xpc_release_safe(xpcarr
);