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