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