]> git.saurik.com Git - apple/security.git/blob - OSX/authd/server.c
Security-59306.41.2.tar.gz
[apple/security.git] / OSX / authd / server.c
1 /* Copyright (c) 2012-2013 Apple Inc. All Rights Reserved. */
2
3 #include "server.h"
4 #include "session.h"
5 #include "process.h"
6 #include "authtoken.h"
7 #include "authdb.h"
8 #include "rule.h"
9 #include "authutilities.h"
10 #include "crc.h"
11 #include "mechanism.h"
12 #include "agent.h"
13 #include "authitems.h"
14 #include "debugging.h"
15 #include "engine.h"
16 #include "connection.h"
17 #include "AuthorizationTags.h"
18
19 #include <bsm/libbsm.h>
20 #include <Security/Authorization.h>
21 #include <Security/AuthorizationPriv.h>
22 #include <Security/AuthorizationTagsPriv.h>
23 #include <Security/AuthorizationPlugin.h>
24 #include <xpc/private.h>
25 #include <dispatch/dispatch.h>
26 #include <CoreFoundation/CoreFoundation.h>
27 #include <CoreFoundation/CFXPCBridge.h>
28 #include <IOKit/IOMessage.h>
29 #include <IOKit/pwr_mgt/IOPMLib.h>
30 #include <IOKit/pwr_mgt/IOPMLibPrivate.h>
31
32 AUTHD_DEFINE_LOG
33
34 #define MAX_PROCESS_RIGHTS 100
35
36 static CFMutableDictionaryRef gProcessMap = NULL;
37 static CFMutableDictionaryRef gSessionMap = NULL;
38 static CFMutableDictionaryRef gAuthTokenMap = NULL;
39 static authdb_t gDatabase = NULL;
40
41 static bool gXPCTransaction = false;
42
43 static dispatch_queue_t
44 get_server_dispatch_queue()
45 {
46 static dispatch_once_t onceToken;
47 static dispatch_queue_t server_queue = NULL;
48
49 dispatch_once(&onceToken, ^{
50 server_queue = dispatch_queue_create("com.apple.security.auth.server", DISPATCH_QUEUE_SERIAL);
51 check(server_queue != NULL);
52 });
53
54 return server_queue;
55 }
56
57 static Boolean _processEqualCallBack(const void *value1, const void *value2)
58 {
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) {
63 return true;
64 }
65 }
66 return false;
67 }
68
69 static CFHashCode _processHashCallBack(const void *value)
70 {
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;
77 }
78
79 static const CFDictionaryKeyCallBacks kProcessMapKeyCallBacks = {
80 .version = 0,
81 .retain = NULL,
82 .release = NULL,
83 .copyDescription = NULL,
84 .equal = &_processEqualCallBack,
85 .hash = &_processHashCallBack
86 };
87
88 static Boolean _sessionEqualCallBack(const void *value1, const void *value2)
89 {
90 return (*(session_id_t*)value1) == (*(session_id_t*)value2);
91 }
92
93 static CFHashCode _sessionHashCallBack(const void *value)
94 {
95 return (CFHashCode)(*(session_id_t*)(value));
96 }
97
98 static const CFDictionaryKeyCallBacks kSessionMapKeyCallBacks = {
99 .version = 0,
100 .retain = NULL,
101 .release = NULL,
102 .copyDescription = NULL,
103 .equal = &_sessionEqualCallBack,
104 .hash = &_sessionHashCallBack
105 };
106
107 void server_cleanup()
108 {
109 CFRelease(gProcessMap);
110 CFRelease(gSessionMap);
111 CFRelease(gAuthTokenMap);
112
113 dispatch_queue_t queue = get_server_dispatch_queue();
114 if (queue) {
115 dispatch_release(queue);
116 }
117 }
118
119 bool server_in_dark_wake()
120 {
121 return IOPMIsADarkWake(IOPMConnectionGetSystemCapabilities());
122 }
123
124 authdb_t server_get_database()
125 {
126 return gDatabase;
127 }
128
129 static void _setupAuditSessionMonitor()
130 {
131 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
132 au_sdev_handle_t *dev = au_sdev_open(AU_SDEVF_ALLSESSIONS);
133 int event;
134 auditinfo_addr_t aia;
135
136 if (NULL == dev) {
137 os_log_error(AUTHD_LOG, "server: could not open %{public}s %d", AUDIT_SDEV_PATH, errno);
138 return;
139 }
140
141 for (;;) {
142 if (0 != au_sdev_read_aia(dev, &event, &aia)) {
143 os_log_error(AUTHD_LOG, "server: au_sdev_read_aia failed: %d", errno);
144 continue;
145 }
146 os_log_debug(AUTHD_LOG, "server: au_sdev_handle_t event=%i, session=%i", event, aia.ai_asid);
147 if (event == AUE_SESSION_END) {
148 dispatch_async(get_server_dispatch_queue(), ^{
149 os_log_debug(AUTHD_LOG, "server: session %i destroyed", aia.ai_asid);
150 CFDictionaryRemoveValue(gSessionMap, &aia.ai_asid);
151 });
152 }
153 }
154
155 });
156 }
157
158 static void _setupSignalHandlers()
159 {
160 signal(SIGTERM, SIG_IGN);
161 static dispatch_source_t sigtermHandler;
162 sigtermHandler = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGTERM, 0, get_server_dispatch_queue());
163 if (sigtermHandler) {
164 dispatch_source_set_event_handler(sigtermHandler, ^{
165
166 // should we clean up any state?
167 exit(EXIT_SUCCESS);
168 });
169 dispatch_resume(sigtermHandler);
170 }
171 }
172
173 OSStatus server_init(void)
174 {
175 OSStatus status = errAuthorizationSuccess;
176
177 auditinfo_addr_t info;
178 memset(&info, 0, sizeof(info));
179 getaudit_addr(&info, sizeof(info));
180 os_log_debug(AUTHD_LOG, "server: uid=%i, sid=%i", info.ai_auid, info.ai_asid);
181
182 require_action(get_server_dispatch_queue() != NULL, done, status = errAuthorizationInternal);
183
184 gProcessMap = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kProcessMapKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
185 require_action(gProcessMap != NULL, done, status = errAuthorizationInternal);
186
187 gSessionMap = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kSessionMapKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
188 require_action(gSessionMap != NULL, done, status = errAuthorizationInternal);
189
190 gAuthTokenMap = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kAuthTokenKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
191 require_action(gAuthTokenMap != NULL, done, status = errAuthorizationInternal);
192
193 gDatabase = authdb_create();
194 require_action(gDatabase != NULL, done, status = errAuthorizationInternal);
195
196 // check to see if we have an updates
197 authdb_connection_t dbconn = authdb_connection_acquire(gDatabase);
198 authdb_maintenance(dbconn);
199 authdb_connection_release(&dbconn);
200
201 _setupAuditSessionMonitor();
202 _setupSignalHandlers();
203
204 done:
205 return status;
206 }
207
208 static void _server_parse_audit_token(audit_token_t * token, audit_info_s * info)
209 {
210 if (token && info) {
211 memset(info, 0, sizeof(*info));
212 au_tid_t tid;
213 memset(&tid, 0, sizeof(tid));
214 audit_token_to_au32(*token, &info->auid, &info->euid,
215 &info->egid, &info->ruid, &info->rgid,
216 &info->pid, &info->asid, &tid);
217 info->tid = tid.port;
218 info->opaqueToken = *token;
219 }
220 }
221
222 connection_t
223 server_register_connection(xpc_connection_t connection)
224 {
225 __block connection_t conn = NULL;
226 __block session_t session = NULL;
227 __block process_t proc = NULL;
228 __block CFIndex conn_count = 0;
229
230 require(connection != NULL, done);
231
232 audit_token_t auditToken;
233 audit_info_s info;
234 xpc_connection_get_audit_token(connection, &auditToken);
235 _server_parse_audit_token(&auditToken, &info);
236
237
238 dispatch_sync(get_server_dispatch_queue(), ^{
239 session = (session_t)CFDictionaryGetValue(gSessionMap, &info.asid);
240 if (session) {
241 CFRetain(session);
242 } else {
243 session = session_create(info.asid);
244 CFDictionarySetValue(gSessionMap, session_get_key(session), session);
245 }
246
247 proc = (process_t)CFDictionaryGetValue(gProcessMap, &info);
248 if (proc) {
249 CFRetain(proc);
250 }
251
252 if (proc) {
253 conn = connection_create(proc);
254 conn_count = process_add_connection(proc, conn);
255 } else {
256 proc = process_create(&info, session);
257 if (proc) {
258 conn = connection_create(proc);
259 conn_count = process_add_connection(proc, conn);
260 session_add_process(session, proc);
261 CFDictionarySetValue(gProcessMap, process_get_key(proc), proc);
262 }
263 }
264
265 if (!gXPCTransaction) {
266 xpc_transaction_begin();
267 gXPCTransaction = true;
268 }
269 });
270
271 os_log_debug(AUTHD_LOG, "server: registered connection (total=%li)", conn_count);
272
273 done:
274 CFReleaseSafe(session);
275 CFReleaseSafe(proc);
276 return conn;
277 }
278
279 void
280 server_unregister_connection(connection_t conn)
281 {
282 assert(conn); // marked non-null
283 process_t proc = connection_get_process(conn);
284
285 dispatch_sync(get_server_dispatch_queue(), ^{
286 CFIndex connectionCount = process_get_connection_count(proc);
287 os_log_debug(AUTHD_LOG, "server: unregistered connection (total=%li)", connectionCount);
288
289 if (connectionCount == 1) {
290 CFDictionaryRemoveValue(gProcessMap, process_get_key(proc));
291 }
292
293 if (CFDictionaryGetCount(gProcessMap) == 0) {
294 xpc_transaction_end();
295 gXPCTransaction = false;
296 }
297 });
298 // move the destruction of the connection/process off the server queue
299 CFRelease(conn);
300 }
301
302 void
303 server_register_auth_token(auth_token_t auth)
304 {
305 assert(auth); // marked non-null
306 dispatch_sync(get_server_dispatch_queue(), ^{
307 os_log_debug(AUTHD_LOG, "server: registering authorization");
308 CFDictionarySetValue(gAuthTokenMap, auth_token_get_key(auth), auth);
309 auth_token_set_state(auth, auth_token_state_registered);
310 });
311 }
312
313 void
314 server_unregister_auth_token(auth_token_t auth)
315 {
316 assert(auth);
317 AuthorizationBlob blob = *(AuthorizationBlob*)auth_token_get_key(auth);
318 dispatch_async(get_server_dispatch_queue(), ^{
319 os_log_debug(AUTHD_LOG, "server: unregistering authorization");
320 CFDictionaryRemoveValue(gAuthTokenMap, &blob);
321 });
322 }
323
324 auth_token_t
325 server_find_copy_auth_token(AuthorizationBlob * blob)
326 {
327 assert(blob); // marked non-null
328 __block auth_token_t auth = NULL;
329 dispatch_sync(get_server_dispatch_queue(), ^{
330 auth = (auth_token_t)CFDictionaryGetValue(gAuthTokenMap, blob);
331 if (auth) {
332 CFRetain(auth);
333 }
334 });
335 return auth;
336 }
337
338 session_t
339 server_find_copy_session(session_id_t sid, bool create)
340 {
341 __block session_t session = NULL;
342
343 dispatch_sync(get_server_dispatch_queue(), ^{
344 session = (session_t)CFDictionaryGetValue(gSessionMap, &sid);
345 if (session) {
346 CFRetain(session);
347 } else if (create) {
348 session = session_create(sid);
349 if (session) {
350 CFDictionarySetValue(gSessionMap, session_get_key(session), session);
351 }
352 }
353 });
354
355 return session;
356 }
357
358 #pragma mark -
359 #pragma mark API
360
361 static OSStatus
362 _process_find_copy_auth_token_from_xpc(process_t proc, xpc_object_t message, auth_token_t * auth_out)
363 {
364 OSStatus status = errAuthorizationSuccess;
365 require_action(auth_out != NULL, done, status = errAuthorizationInternal);
366
367 size_t len;
368 AuthorizationBlob * blob = (AuthorizationBlob *)xpc_dictionary_get_data(message, AUTH_XPC_BLOB, &len);
369 require_action(blob != NULL, done, status = errAuthorizationInvalidRef);
370 require_action(len == sizeof(AuthorizationBlob), done, status = errAuthorizationInvalidRef);
371
372 auth_token_t auth = process_find_copy_auth_token(proc, blob);
373 require_action(auth != NULL, done, status = errAuthorizationInvalidRef);
374
375 #if DEBUG
376 os_log_debug(AUTHD_LOG, "server: authtoken lookup %#x%x %p", blob->data[1],blob->data[0], auth);
377 #else
378 os_log_debug(AUTHD_LOG, "server: authtoken lookup");
379 #endif
380
381 *auth_out = auth;
382
383 done:
384 return status;
385 }
386
387 static OSStatus _server_preauthorize(connection_t conn, auth_token_t auth, auth_items_t context, engine_t * engine_out)
388 {
389 __block OSStatus status = errAuthorizationDenied;
390 engine_t engine = NULL;
391
392 require_action(conn, done, status = errAuthorizationInternal);
393
394 engine = engine_create(conn, auth);
395 require_action(engine, done, status = errAuthorizationInternal);
396
397 status = engine_preauthorize(engine, context);
398
399 done:
400 if (engine) {
401 if (engine_out) {
402 *engine_out = engine;
403 } else {
404 CFRelease(engine);
405 }
406 }
407 return status;
408 }
409
410 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)
411 {
412 __block OSStatus status = errAuthorizationDenied;
413 engine_t engine = NULL;
414
415 require_action(conn, done, status = errAuthorizationInternal);
416
417 engine = engine_create(conn, auth);
418 require_action(engine, done, status = errAuthorizationInternal);
419
420 if (flags & kAuthorizationFlagInteractionAllowed) {
421 dispatch_sync(connection_get_dispatch_queue(conn), ^{
422 connection_set_engine(conn, engine);
423 status = engine_authorize(engine, rights, environment, flags);
424 connection_set_engine(conn, NULL);
425 });
426 } else {
427 status = engine_authorize(engine, rights, environment, flags);
428 }
429
430 done:
431 if (engine) {
432 if (engine_out) {
433 *engine_out = engine;
434 } else {
435 CFRelease(engine);
436 }
437 }
438 return status;
439 }
440
441 // IN: AUTH_XPC_RIGHTS, AUTH_XPC_ENVIRONMENT, AUTH_XPC_FLAGS
442 // OUT: AUTH_XPC_BLOB
443 OSStatus
444 authorization_create(connection_t conn, xpc_object_t message, xpc_object_t reply)
445 {
446 OSStatus status = errAuthorizationDenied;
447
448 process_t proc = connection_get_process(conn);
449
450 // Passed in args
451 auth_rights_t rights = auth_rights_create_with_xpc(xpc_dictionary_get_value(message, AUTH_XPC_RIGHTS));
452 auth_items_t environment = auth_items_create_with_xpc(xpc_dictionary_get_value(message, AUTH_XPC_ENVIRONMENT));
453 AuthorizationFlags flags = (AuthorizationFlags)xpc_dictionary_get_uint64(message, AUTH_XPC_FLAGS);
454
455 // Create Authorization Token
456 auth_token_t auth = auth_token_create(proc, flags & kAuthorizationFlagLeastPrivileged);
457 require_action(auth != NULL, done, status = errAuthorizationInternal);
458
459 if (!(flags & kAuthorizationFlagNoData)) {
460 process_add_auth_token(proc,auth);
461 }
462
463 status = _server_authorize(conn, auth, flags, rights, environment, NULL);
464 require_noerr(status, done);
465
466 //reply
467 xpc_dictionary_set_data(reply, AUTH_XPC_BLOB, auth_token_get_blob(auth), sizeof(AuthorizationBlob));
468
469 done:
470 CFReleaseSafe(rights);
471 CFReleaseSafe(environment);
472 CFReleaseSafe(auth);
473 return status;
474 }
475
476 // IN: AUTH_XPC_DATA, AUTH_XPC_ENVIRONMENT, AUTH_XPC_FLAGS
477 // OUT: AUTH_XPC_BLOB
478 OSStatus authorization_create_with_audit_token(connection_t conn, xpc_object_t message, xpc_object_t reply)
479 {
480 OSStatus status = errAuthorizationDenied;
481 auth_token_t auth = NULL;
482
483 process_t proc = connection_get_process(conn);
484 require(process_get_uid(proc) == 0, done); //only root can use this call
485
486 // Passed in args
487 size_t len = 0;
488 const char * data = xpc_dictionary_get_data(message, AUTH_XPC_DATA, &len);
489 require(data != NULL, done);
490 require(len == sizeof(audit_token_t), done);
491
492 // auth_items_t environment = auth_items_create_with_xpc(xpc_dictionary_get_value(message, AUTH_XPC_ENVIRONMENT));
493 AuthorizationFlags flags = (AuthorizationFlags)xpc_dictionary_get_uint64(message, AUTH_XPC_FLAGS);
494
495 audit_info_s auditInfo;
496 _server_parse_audit_token((audit_token_t*)data, &auditInfo);
497
498 // Create Authorization Token
499 auth = auth_token_create(proc, flags & kAuthorizationFlagLeastPrivileged);
500 require_action(auth != NULL, done, status = errAuthorizationInternal);
501
502 process_add_auth_token(proc,auth);
503
504 //reply
505 xpc_dictionary_set_data(reply, AUTH_XPC_BLOB, auth_token_get_blob(auth), sizeof(AuthorizationBlob));
506
507 done:
508 // CFReleaseSafe(environment);
509 CFReleaseSafe(auth);
510 return status;
511 }
512
513 // IN: AUTH_XPC_BLOB, AUTH_XPC_FLAGS
514 // OUT:
515 OSStatus
516 authorization_free(connection_t conn, xpc_object_t message, xpc_object_t reply AUTH_UNUSED)
517 {
518 OSStatus status = errAuthorizationSuccess;
519 AuthorizationFlags flags = 0;
520 process_t proc = connection_get_process(conn);
521
522 auth_token_t auth = NULL;
523 status = _process_find_copy_auth_token_from_xpc(proc, message, &auth);
524 require_noerr(status, done);
525
526 flags = (AuthorizationFlags)xpc_dictionary_get_uint64(message, AUTH_XPC_FLAGS);
527
528 if (flags & kAuthorizationFlagDestroyRights) {
529 auth_token_credentials_iterate(auth, ^bool(credential_t cred) {
530 credential_invalidate(cred);
531 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));
532 return true;
533 });
534
535 session_credentials_purge(auth_token_get_session(auth));
536 }
537
538 process_remove_auth_token(proc, auth, flags);
539
540 done:
541 CFReleaseSafe(auth);
542 os_log_debug(AUTHD_LOG, "server: AuthorizationFree %d (flags:%x)", (int)status, (unsigned int)flags);
543 return status;
544 }
545
546 // IN: AUTH_XPC_BLOB, AUTH_XPC_DATA
547 // OUT:
548 OSStatus
549 authorization_preauthorize_credentials(connection_t conn, xpc_object_t message, xpc_object_t reply)
550 {
551 OSStatus status = errAuthorizationDenied;
552 engine_t engine = NULL;
553
554 process_t proc = connection_get_process(conn);
555
556 // Passed in args
557 auth_items_t context = auth_items_create_with_xpc(xpc_dictionary_get_value(message, AUTH_XPC_DATA));
558
559 auth_token_t auth = NULL;
560 status = _process_find_copy_auth_token_from_xpc(proc, message, &auth);
561 require_noerr_action_quiet(status, done, os_log_error(AUTHD_LOG, "preauthorize_credentials: no auth token"));
562
563 status = _server_preauthorize(conn, auth, context, &engine);
564 require_noerr_action_quiet(status, done, os_log_error(AUTHD_LOG, "preauthorize_credentials: authorization failed"));
565
566 done:
567 CFReleaseSafe(context);
568 CFReleaseSafe(auth);
569 CFReleaseSafe(engine);
570
571 return status;
572 }
573
574
575 // IN: AUTH_XPC_BLOB, AUTH_XPC_RIGHTS, AUTH_XPC_ENVIRONMENT, AUTH_XPC_FLAGS
576 // OUT: AUTH_XPC_OUT_ITEMS
577 OSStatus
578 authorization_copy_rights(connection_t conn, xpc_object_t message, xpc_object_t reply)
579 {
580 OSStatus status = errAuthorizationDenied;
581 engine_t engine = NULL;
582
583 process_t proc = connection_get_process(conn);
584
585 // Passed in args
586 auth_rights_t rights = auth_rights_create_with_xpc(xpc_dictionary_get_value(message, AUTH_XPC_RIGHTS));
587 auth_items_t environment = auth_items_create_with_xpc(xpc_dictionary_get_value(message, AUTH_XPC_ENVIRONMENT));
588 AuthorizationFlags flags = (AuthorizationFlags)xpc_dictionary_get_uint64(message, AUTH_XPC_FLAGS);
589
590 auth_token_t auth = NULL;
591 status = _process_find_copy_auth_token_from_xpc(proc, message, &auth);
592 require_noerr_action_quiet(status, done, os_log_error(AUTHD_LOG, "copy_rights: no auth token"));
593
594 status = _server_authorize(conn, auth, flags, rights, environment, &engine);
595 require_noerr_action_quiet(status, done, os_log_error(AUTHD_LOG, "copy_rights: authorization failed"));
596
597 //reply
598 xpc_object_t outItems = auth_rights_export_xpc(engine_get_granted_rights(engine));
599 xpc_dictionary_set_value(reply, AUTH_XPC_OUT_ITEMS, outItems);
600 xpc_release_safe(outItems);
601
602 done:
603 CFReleaseSafe(rights);
604 CFReleaseSafe(environment);
605 CFReleaseSafe(auth);
606 CFReleaseSafe(engine);
607
608 return status;
609 }
610
611 // IN: AUTH_XPC_BLOB, AUTH_XPC_TAG
612 // OUT: AUTH_XPC_OUT_ITEMS
613 OSStatus
614 authorization_copy_info(connection_t conn, xpc_object_t message, xpc_object_t reply)
615 {
616
617 OSStatus status = errAuthorizationSuccess;
618 auth_items_t items = NULL;
619 auth_items_t local_items = NULL;
620 const char * tag = NULL;
621
622 process_t proc = connection_get_process(conn);
623
624 auth_token_t auth = NULL;
625 status = _process_find_copy_auth_token_from_xpc(proc, message, &auth);
626 require_noerr_action_quiet(status, done, os_log_error(AUTHD_LOG, "copy_info: no auth token"));
627
628 items = auth_items_create();
629
630 tag = xpc_dictionary_get_string(message, AUTH_XPC_TAG);
631 os_log_debug(AUTHD_LOG, "server: requested tag: %{public}s", tag ? tag : "(all)");
632 if (tag) {
633 size_t len;
634 const void * data = auth_items_get_data_with_flags(auth_token_get_context(auth), tag, &len, kAuthorizationContextFlagExtractable);
635 if (data) {
636 os_log_debug(AUTHD_LOG, "server: requested tag found");
637 auth_items_set_data(items, tag, data, len);
638 }
639 } else {
640 auth_items_copy_with_flags(items, auth_token_get_context(auth), kAuthorizationContextFlagExtractable);
641 }
642
643 local_items = auth_items_create();
644 auth_items_content_copy(local_items, items); // we do not want decrypt content of the authorizationref memory which is where pointers point to
645 auth_items_decrypt(local_items, auth_token_get_encryption_key(auth));
646 os_log_debug(AUTHD_LOG, "server: decrypted authorization context data");
647
648 #if DEBUG
649 os_log_debug(AUTHD_LOG, "server: Dumping requested AuthRef items: %{public}@", items);
650 #endif
651
652 if (auth_items_exist(local_items, kAuthorizationEnvironmentPassword)) {
653 // check if caller is entitled to get the password
654 CFTypeRef extract_password_entitlement = process_copy_entitlement_value(proc, "com.apple.authorization.extract-password");
655 if (extract_password_entitlement && (CFGetTypeID(extract_password_entitlement) == CFBooleanGetTypeID()) && extract_password_entitlement == kCFBooleanTrue) {
656 os_log_debug(AUTHD_LOG, "server: caller allowed to extract password");
657 } else {
658 os_log_error(AUTHD_LOG, "server: caller NOT allowed to extract password");
659 auth_items_remove(local_items, kAuthorizationEnvironmentPassword);
660 }
661 CFReleaseSafe(extract_password_entitlement);
662 }
663
664 //reply
665 xpc_object_t outItems = auth_items_export_xpc(local_items);
666 xpc_dictionary_set_value(reply, AUTH_XPC_OUT_ITEMS, outItems);
667 xpc_release_safe(outItems);
668
669 done:
670 CFReleaseSafe(local_items);
671 CFReleaseSafe(items);
672 CFReleaseSafe(auth);
673 os_log_debug(AUTHD_LOG, "server: AuthorizationCopyInfo %i", (int) status);
674 return status;
675 }
676
677 // IN: AUTH_XPC_BLOB
678 // OUT: AUTH_XPC_EXTERNAL
679 OSStatus
680 authorization_make_external_form(connection_t conn, xpc_object_t message, xpc_object_t reply)
681 {
682 OSStatus status = errAuthorizationSuccess;
683
684 process_t proc = connection_get_process(conn);
685
686 auth_token_t auth = NULL;
687 status = _process_find_copy_auth_token_from_xpc(proc, message, &auth);
688 require_noerr(status, done);
689
690 AuthorizationExternalForm exForm;
691 AuthorizationExternalBlob * exBlob = (AuthorizationExternalBlob *)&exForm;
692 memset(&exForm, 0, sizeof(exForm));
693
694 exBlob->blob = *auth_token_get_blob(auth);
695 exBlob->session = process_get_session_id(proc);
696
697 xpc_dictionary_set_data(reply, AUTH_XPC_EXTERNAL, &exForm, sizeof(exForm));
698 server_register_auth_token(auth);
699
700 done:
701 CFReleaseSafe(auth);
702 os_log_debug(AUTHD_LOG, "server: AuthorizationMakeExternalForm %d", (int)status);
703 return status;
704 }
705
706 // IN: AUTH_XPC_EXTERNAL
707 // OUT: AUTH_XPC_BLOB
708 OSStatus
709 authorization_create_from_external_form(connection_t conn, xpc_object_t message, xpc_object_t reply)
710 {
711 OSStatus status = errAuthorizationSuccess;
712 auth_token_t auth = NULL;
713
714 process_t proc = connection_get_process(conn);
715
716 size_t len;
717 AuthorizationExternalForm * exForm = (AuthorizationExternalForm *)xpc_dictionary_get_data(message, AUTH_XPC_EXTERNAL, &len);
718 require_action(exForm != NULL, done, status = errAuthorizationInternal);
719 require_action(len == sizeof(AuthorizationExternalForm), done, status = errAuthorizationInvalidRef);
720
721 AuthorizationExternalBlob * exBlob = (AuthorizationExternalBlob *)exForm;
722 auth = server_find_copy_auth_token(&exBlob->blob);
723 require_action(auth != NULL, done, status = errAuthorizationDenied);
724
725 process_add_auth_token(proc, auth);
726 xpc_dictionary_set_data(reply, AUTH_XPC_BLOB, auth_token_get_blob(auth), sizeof(AuthorizationBlob));
727
728 done:
729 CFReleaseSafe(auth);
730 os_log_debug(AUTHD_LOG, "server: AuthorizationCreateFromExternalForm %d", (int)status);
731 return status;
732 }
733
734 // IN: AUTH_XPC_RIGHT_NAME
735 // OUT: AUTH_XPC_DATA
736 OSStatus
737 authorization_right_get(connection_t conn AUTH_UNUSED, xpc_object_t message, xpc_object_t reply)
738 {
739 OSStatus status = errAuthorizationDenied;
740 rule_t rule = NULL;
741 CFTypeRef cfdict = NULL;
742 xpc_object_t xpcdict = NULL;
743
744 authdb_connection_t dbconn = authdb_connection_acquire(server_get_database());
745 rule = rule_create_with_string(xpc_dictionary_get_string(message, AUTH_XPC_RIGHT_NAME), dbconn);
746 require(rule != NULL, done);
747 require(rule_get_id(rule) != 0, done);
748
749 cfdict = rule_copy_to_cfobject(rule, dbconn);
750 require(cfdict != NULL, done);
751
752 xpcdict = _CFXPCCreateXPCObjectFromCFObject(cfdict);
753 require(xpcdict != NULL, done);
754
755 // reply
756 xpc_dictionary_set_value(reply, AUTH_XPC_DATA, xpcdict);
757
758 status = errAuthorizationSuccess;
759
760 done:
761 authdb_connection_release(&dbconn);
762 CFReleaseSafe(cfdict);
763 xpc_release_safe(xpcdict);
764 CFReleaseSafe(rule);
765 os_log_debug(AUTHD_LOG, "server: AuthorizationRightGet %d", (int)status);
766 return status;
767 }
768
769 static bool _prompt_for_modifications(process_t __unused proc, rule_t __unused rule)
770 {
771 // <rdar://problem/13853228> will put back it back at some later date
772 // SecRequirementRef ruleReq = rule_get_requirement(rule);
773 //
774 // if (ruleReq && process_verify_requirment(proc, ruleReq)) {
775 // return false;
776 // }
777
778 return true;
779 }
780
781 static CFIndex _get_mechanism_index(CFArrayRef mechanisms, CFStringRef m_name)
782 {
783 CFIndex index = -1;
784 require(mechanisms, done);
785
786 CFIndex c = CFArrayGetCount(mechanisms);
787 CFStringRef i_name = NULL;
788 for (CFIndex i = 0; i < c; ++i)
789 {
790 i_name = CFArrayGetValueAtIndex(mechanisms, i);
791 if (i_name && (CFGetTypeID(m_name) == CFStringGetTypeID())) {
792 if (CFStringCompare(i_name, m_name, kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
793 index = i;
794 break;
795 }
796 }
797 }
798
799 done:
800 return index;
801 }
802
803 static bool _update_rule_mechanism(authdb_connection_t dbconn, const char * rule_name, CFStringRef mechanism_name, CFStringRef insert_after_name, bool remove)
804 {
805 bool updated = false;
806 rule_t rule = NULL;
807 rule_t update_rule = NULL;
808 CFMutableDictionaryRef cfdict = NULL;
809 CFStringRef update_name = NULL;
810
811 require(mechanism_name, done);
812
813 rule = rule_create_with_string(rule_name, dbconn);
814 require(rule_get_id(rule) != 0, done); // rule doesn't exist in the database
815
816 cfdict = rule_copy_to_cfobject(rule, dbconn);
817 require(cfdict != NULL, done);
818
819 CFMutableArrayRef mechanisms = NULL;
820 bool res = CFDictionaryGetValueIfPresent(cfdict, CFSTR(kAuthorizationRuleParameterMechanisms), (void*)&mechanisms);
821 require(res == true, done);
822
823 CFIndex index = -1;
824
825 if (remove) {
826 index = _get_mechanism_index(mechanisms, mechanism_name);
827 } else {
828 if (insert_after_name) {
829 if ((index = _get_mechanism_index(mechanisms, insert_after_name)) != -1) {
830 index++;
831 } else {
832 index = 0; // if we couldn't find the index add it to the begining
833 }
834 } else {
835 index = 0;
836 }
837 }
838
839 if (index != -1) {
840 if(remove) {
841 CFArrayRemoveValueAtIndex(mechanisms, index);
842 } else {
843 if (index < CFArrayGetCount(mechanisms)) {
844 require_action(CFStringCompare(CFArrayGetValueAtIndex(mechanisms, index), mechanism_name, kCFCompareCaseInsensitive) != kCFCompareEqualTo, done, updated = true);
845 }
846 CFArrayInsertValueAtIndex(mechanisms, index, mechanism_name);
847 }
848
849 CFDictionarySetValue(cfdict, CFSTR(kAuthorizationRuleParameterMechanisms), mechanisms);
850
851 // and write it back
852 update_name = CFStringCreateWithCString(kCFAllocatorDefault, rule_name, kCFStringEncodingUTF8);
853 require(update_name, done);
854 update_rule = rule_create_with_plist(rule_get_type(rule), update_name, cfdict, dbconn);
855 require(update_rule, done);
856
857 require(rule_sql_commit(update_rule, dbconn, CFAbsoluteTimeGetCurrent(), NULL), done);
858 }
859
860 updated = true;
861
862 done:
863 CFReleaseSafe(rule);
864 CFReleaseSafe(update_rule);
865 CFReleaseSafe(cfdict);
866 CFReleaseSafe(update_name);
867 return updated;
868 }
869
870 /// IN: AUTH_XPC_BLOB, AUTH_XPC_INT64
871 // OUT:
872 OSStatus
873 authorization_enable_smartcard(connection_t conn, xpc_object_t message, xpc_object_t reply AUTH_UNUSED)
874 {
875 const CFStringRef SMARTCARD_LINE = CFSTR("builtin:smartcard-sniffer,privileged");
876 const CFStringRef BUILTIN_LINE = CFSTR("builtin:policy-banner");
877 const char* SYSTEM_LOGIN_CONSOLE = "system.login.console";
878 const char* AUTHENTICATE = "authenticate";
879
880 __block OSStatus status = errAuthorizationSuccess;
881 bool enable_smartcard = false;
882 authdb_connection_t dbconn = NULL;
883 auth_token_t auth = NULL;
884 auth_rights_t checkRight = NULL;
885
886 process_t proc = connection_get_process(conn);
887
888 status = _process_find_copy_auth_token_from_xpc(proc, message, &auth);
889 require_noerr(status, done);
890
891 checkRight = auth_rights_create();
892 auth_rights_add(checkRight, "config.modify.smartcard");
893 status = _server_authorize(conn, auth, kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights, checkRight, NULL, NULL);
894 require_noerr(status, done);
895
896 enable_smartcard = xpc_dictionary_get_bool(message, AUTH_XPC_DATA);
897
898 dbconn = authdb_connection_acquire(server_get_database());
899
900 if (!_update_rule_mechanism(dbconn, SYSTEM_LOGIN_CONSOLE, SMARTCARD_LINE, BUILTIN_LINE, enable_smartcard ? false : true)) {
901 status = errAuthorizationInternal;
902 os_log_error(AUTHD_LOG, "server: smartcard: enable(%i) failed to update %{public}s", enable_smartcard, SYSTEM_LOGIN_CONSOLE);
903 }
904 if (!_update_rule_mechanism(dbconn, AUTHENTICATE, SMARTCARD_LINE, NULL, enable_smartcard ? false : true)) {
905 status = errAuthorizationInternal;
906 os_log_error(AUTHD_LOG, "server: smartcard: enable(%i) failed to update %{public}s", enable_smartcard, AUTHENTICATE);
907 }
908
909 authdb_checkpoint(dbconn);
910
911 done:
912 authdb_connection_release(&dbconn);
913 CFReleaseSafe(checkRight);
914 CFReleaseSafe(auth);
915 return status;
916 }
917
918 static int64_t _process_get_identifier_count(process_t proc, authdb_connection_t conn)
919 {
920 __block int64_t result = 0;
921
922 authdb_step(conn, "SELECT COUNT(*) AS cnt FROM rules WHERE identifier = ? ", ^(sqlite3_stmt *stmt) {
923 sqlite3_bind_text(stmt, 1, process_get_identifier(proc), -1, NULL);
924 }, ^bool(auth_items_t data) {
925 result = auth_items_get_int64(data, "cnt");
926 return true;
927 });
928
929 return result;
930 }
931
932 static int64_t _get_max_process_rights()
933 {
934 static dispatch_once_t onceToken;
935 static int64_t max_rights = MAX_PROCESS_RIGHTS;
936
937 //sudo defaults write /Library/Preferences/com.apple.authd max_process_rights -bool true
938 dispatch_once(&onceToken, ^{
939 CFTypeRef max = (CFNumberRef)CFPreferencesCopyValue(CFSTR("max_process_rights"), CFSTR(SECURITY_AUTH_NAME), kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
940
941 if (max && CFGetTypeID(max) == CFNumberGetTypeID()) {
942 CFNumberGetValue(max, kCFNumberSInt64Type, &max_rights);
943 }
944 CFReleaseSafe(max);
945 });
946
947 return max_rights;
948 }
949
950 // IN: AUTH_XPC_BLOB, AUTH_XPC_RIGHT_NAME, AUTH_XPC_DATA
951 // OUT:
952 OSStatus
953 authorization_right_set(connection_t conn, xpc_object_t message, xpc_object_t reply AUTH_UNUSED)
954 {
955 __block OSStatus status = errAuthorizationDenied;
956 __block engine_t engine = NULL;
957 CFStringRef cf_rule_name = NULL;
958 CFDictionaryRef cf_rule_dict = NULL;
959 rule_t rule = NULL;
960 rule_t existingRule = NULL;
961 authdb_connection_t dbconn = NULL;
962 auth_token_t auth = NULL;
963 bool force_modify = false;
964 RuleType rule_type = RT_RIGHT;
965 const char * rule_name = NULL;
966 bool auth_rule = false;
967
968 process_t proc = connection_get_process(conn);
969
970 status = _process_find_copy_auth_token_from_xpc(proc, message, &auth);
971 require_noerr(status, done);
972
973 require_action(xpc_dictionary_get_string(message, AUTH_XPC_RIGHT_NAME) != NULL, done, status = errAuthorizationInternal);
974 require_action(xpc_dictionary_get_value(message, AUTH_XPC_DATA) != NULL, done, status = errAuthorizationInternal);
975
976 rule_name = xpc_dictionary_get_string(message, AUTH_XPC_RIGHT_NAME);
977 require(rule_name != NULL, done);
978
979 if (_compare_string(rule_name, "authenticate")) {
980 rule_type = RT_RULE;
981 auth_rule = true;
982 }
983
984 cf_rule_name = CFStringCreateWithCString(kCFAllocatorDefault, rule_name, kCFStringEncodingUTF8);
985 require(cf_rule_name != NULL, done);
986
987 cf_rule_dict = _CFXPCCreateCFObjectFromXPCObject(xpc_dictionary_get_value(message, AUTH_XPC_DATA));
988 require(cf_rule_dict != NULL, done);
989
990 dbconn = authdb_connection_acquire(server_get_database());
991
992 rule = rule_create_with_plist(rule_type, cf_rule_name, cf_rule_dict, dbconn);
993 if (process_get_uid(proc) != 0) {
994 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)"));
995 }
996
997 // if rule doesn't currently exist then we have to check to see if they are over the Max.
998 if (rule_get_id(rule) == 0) {
999 if (process_get_identifier(proc) == NULL) {
1000 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));
1001 force_modify = true;
1002 } else {
1003 int64_t process_rule_count = _process_get_identifier_count(proc, dbconn);
1004 if ((process_rule_count >= _get_max_process_rights())) {
1005 if (!connection_get_syslog_warn(conn)) {
1006 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());
1007 connection_set_syslog_warn(conn);
1008 }
1009 status = errAuthorizationDenied;
1010 goto done;
1011 }
1012 }
1013 } else {
1014 if (auth_rule) {
1015 if (process_get_uid(proc) != 0) {
1016 os_log_error(AUTHD_LOG, "server: AuthorizationRightSet denied, root required to update the 'authenticate' rule");
1017 status = errAuthorizationDenied;
1018 goto done;
1019 }
1020 } else {
1021 // verify they are updating a right and not a rule
1022 existingRule = rule_create_with_string(rule_get_name(rule), dbconn);
1023 if (rule_get_type(existingRule) == RT_RULE) {
1024 os_log_error(AUTHD_LOG, "server: AuthorizationRightSet Denied updating '%{public}s' rule is prohibited", rule_get_name(existingRule));
1025 status = errAuthorizationDenied;
1026 goto done;
1027 }
1028 }
1029 }
1030
1031 if (_prompt_for_modifications(proc,rule)) {
1032 authdb_connection_release(&dbconn);
1033
1034 dispatch_sync(connection_get_dispatch_queue(conn), ^{
1035 engine = engine_create(conn, auth);
1036 connection_set_engine(conn, engine);
1037 status = engine_verify_modification(engine, rule, false, force_modify);
1038 connection_set_engine(conn, NULL);
1039 });
1040 require_noerr(status, done);
1041
1042 dbconn = authdb_connection_acquire(server_get_database());
1043 }
1044
1045 if (rule_sql_commit(rule, dbconn, engine ? engine_get_time(engine) : CFAbsoluteTimeGetCurrent(), proc)) {
1046 os_log_debug(AUTHD_LOG, "server: Successfully updated rule %{public}s", rule_get_name(rule));
1047 authdb_checkpoint(dbconn);
1048 status = errAuthorizationSuccess;
1049 } else {
1050 os_log_error(AUTHD_LOG, "server: Failed to update rule %{public}s", rule_get_name(rule));
1051 status = errAuthorizationDenied;
1052 }
1053
1054 done:
1055 authdb_connection_release(&dbconn);
1056 CFReleaseSafe(existingRule);
1057 CFReleaseSafe(cf_rule_name);
1058 CFReleaseSafe(cf_rule_dict);
1059 CFReleaseSafe(auth);
1060 CFReleaseSafe(rule);
1061 CFReleaseSafe(engine);
1062 return status;
1063 }
1064
1065 // IN: AUTH_XPC_BLOB, AUTH_XPC_RIGHT_NAME
1066 // OUT:
1067 OSStatus
1068 authorization_right_remove(connection_t conn, xpc_object_t message, xpc_object_t reply AUTH_UNUSED)
1069 {
1070 __block OSStatus status = errAuthorizationDenied;
1071 __block engine_t engine = NULL;
1072 rule_t rule = NULL;
1073 authdb_connection_t dbconn = NULL;
1074
1075 process_t proc = connection_get_process(conn);
1076
1077 auth_token_t auth = NULL;
1078 status = _process_find_copy_auth_token_from_xpc(proc, message, &auth);
1079 require_noerr(status, done);
1080
1081 dbconn = authdb_connection_acquire(server_get_database());
1082
1083 rule = rule_create_with_string(xpc_dictionary_get_string(message, AUTH_XPC_RIGHT_NAME), dbconn);
1084 require(rule != NULL, done);
1085
1086 if (_prompt_for_modifications(proc,rule)) {
1087 authdb_connection_release(&dbconn);
1088
1089 dispatch_sync(connection_get_dispatch_queue(conn), ^{
1090 engine = engine_create(conn, auth);
1091 connection_set_engine(conn, engine);
1092 status = engine_verify_modification(engine, rule, true, false);
1093 connection_set_engine(conn, NULL);
1094 });
1095 require_noerr(status, done);
1096
1097 dbconn = authdb_connection_acquire(server_get_database());
1098 }
1099
1100 if (rule_get_id(rule) != 0) {
1101 rule_sql_remove(rule, dbconn, proc);
1102 }
1103
1104 done:
1105 authdb_connection_release(&dbconn);
1106 CFReleaseSafe(auth);
1107 CFReleaseSafe(rule);
1108 CFReleaseSafe(engine);
1109 os_log_debug(AUTHD_LOG, "server: AuthorizationRightRemove %d", (int)status);
1110 return status;
1111 }
1112
1113 #pragma mark -
1114 #pragma mark test code
1115
1116 OSStatus
1117 session_set_user_preferences(connection_t conn, xpc_object_t message, xpc_object_t reply)
1118 {
1119 (void)conn;
1120 (void)message;
1121 (void)reply;
1122 return errAuthorizationSuccess;
1123 }
1124
1125 void
1126 server_dev() {
1127 // rule_t rule = rule_create_with_string("system.preferences.accounts");
1128 // CFDictionaryRef dict = rule_copy_to_cfobject(rule);
1129 // _show_cf(dict);
1130 // CFReleaseSafe(rule);
1131 // CFReleaseSafe(dict);
1132
1133 // auth_items_t config = NULL;
1134 // double d2 = 0, d1 = 5;
1135 // authdb_get_key_value(server_get_authdb_reader(), "config", &config);
1136 // auth_items_set_double(config, "test", d1);
1137 // d2 = auth_items_get_double(config, "test");
1138 // os_log_debug(AUTHD_LOG, "d1=%f d2=%f", d1, d2);
1139 // CFReleaseSafe(config);
1140
1141
1142 // auth_items_t items = auth_items_create();
1143 // auth_items_set_string(items, "test", "testing 1");
1144 // auth_items_set_string(items, "test2", "testing 2");
1145 // auth_items_set_string(items, "test3", "testing 3");
1146 // auth_items_set_flags(items, "test3", 4);
1147 // auth_items_set_string(items, "apple", "apple");
1148 // auth_items_set_flags(items, "apple", 1);
1149 // auth_items_set_int(items, "int", 45);
1150 // auth_items_set_flags(items, "int", 2);
1151 // auth_items_set_bool(items, "true", true);
1152 // auth_items_set_bool(items, "false", false);
1153 // auth_items_set(items, "com.apple.");
1154 // auth_show(items);
1155 // LOGD("Yeah it works: %s", auth_items_get_string(items, "test3"));
1156 // LOGD("Yeah it works: %i", auth_items_get_bool(items, "true"));
1157 // LOGD("Yeah it works: %i", auth_items_get_bool(items, "false"));
1158 // LOGD("Yeah it works: %i", auth_items_get_int(items, "int"));
1159 // (void)auth_items_get_bool(items, "test3");
1160 // AuthorizationItemSet * itemSet = auth_items_get_item_set(items);
1161 // for (uint32_t i = 0; i < itemSet->count; i++) {
1162 // LOGD("item: %s", itemSet->items[i].name);
1163 // }
1164 //
1165 // xpc_object_t xpcdata = SerializeItemSet(auth_items_get_item_set(items));
1166 // auth_items_t items2 = auth_items_create_with_xpc(xpcdata);
1167 // xpc_release(xpcdata);
1168 // auth_items_remove_with_flags(items2, 7);
1169 //// auth_items_set_string(items2, "test3", "testing 3 very good");
1170 // auth_items_copy_with_flags(items2, items, 7);
1171 // LOGD("Yeah it works: %s", auth_items_get_string(items2, "test3"));
1172 // auth_show(items2);
1173 // CFReleaseSafe(items2);
1174 //
1175 // CFReleaseSafe(items);
1176 }
1177