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