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