]> git.saurik.com Git - apple/configd.git/blame - configd.tproj/session.c
configd-1109.101.1.tar.gz
[apple/configd.git] / configd.tproj / session.c
CommitLineData
5958d7c0 1/*
c956c85e 2 * Copyright (c) 2000, 2001, 2003-2005, 2007-2020 Apple Inc. All rights reserved.
5958d7c0
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
9de8ab86 5 *
009ee3c6
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
9de8ab86 12 *
009ee3c6
A
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
5958d7c0
A
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
009ee3c6
A
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
9de8ab86 20 *
5958d7c0
A
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
0fae82ee
A
24/*
25 * Modification History
26 *
27 * June 1, 2001 Allan Nathanson <ajn@apple.com>
28 * - public API conversion
29 *
30 * March 24, 2000 Allan Nathanson <ajn@apple.com>
31 * - initial revision
32 */
33
5e9ce69e 34#include <SystemConfiguration/SystemConfiguration.h>
5958d7c0
A
35#include "configd.h"
36#include "configd_server.h"
5e9ce69e 37#include "pattern.h"
5958d7c0
A
38#include "session.h"
39
a40a14f8
A
40#include <unistd.h>
41#include <bsm/libbsm.h>
afb19109 42#include <os/state_private.h>
6bb65964
A
43#include <sandbox.h>
44
942cecd7 45#if !TARGET_OS_SIMULATOR || (defined(IPHONE_SIMULATOR_HOST_MIN_VERSION_REQUIRED) && (IPHONE_SIMULATOR_HOST_MIN_VERSION_REQUIRED >= 1090))
6f870c06
A
46#define HAVE_MACHPORT_GUARDS
47#endif
48
a40a14f8 49
afb19109
A
50/* information maintained for the main listener */
51static serverSessionRef server_session = NULL;
5958d7c0 52
afb19109
A
53/*
54 * information maintained for each active session
55 * Note: sync w/sessionQueue()
56 */
57static CFMutableDictionaryRef client_sessions = NULL;
c956c85e 58static CFIndex client_sessions_advise = 250; // when snapshot handler should detail sessions
6bb65964
A
59
60
afb19109
A
61static dispatch_queue_t
62sessionQueue(void)
5958d7c0 63{
afb19109
A
64 static dispatch_once_t once;
65 static dispatch_queue_t q;
5958d7c0 66
afb19109
A
67 dispatch_once(&once, ^{
68 // allocate mapping between [client] session mach port and session info
69 client_sessions = CFDictionaryCreateMutable(NULL,
70 0,
71 NULL, // use the actual mach_port_t as the key
72 &kCFTypeDictionaryValueCallBacks);
73
74 // and a queue to synchronize access to the mapping
75 q = dispatch_queue_create("SCDynamicStore/sessions", NULL);
76 });
5958d7c0 77
afb19109
A
78 return q;
79}
009ee3c6 80
17d3ee29 81
afb19109
A
82#pragma mark -
83#pragma mark __serverSession object
17d3ee29 84
afb19109
A
85static CFStringRef __serverSessionCopyDescription (CFTypeRef cf);
86static void __serverSessionDeallocate (CFTypeRef cf);
5958d7c0 87
afb19109
A
88static const CFRuntimeClass __serverSessionClass = {
89 0, // version
90 "serverSession", // className
91 NULL, // init
92 NULL, // copy
93 __serverSessionDeallocate, // dealloc
94 NULL, // equal
95 NULL, // hash
96 NULL, // copyFormattingDesc
97 __serverSessionCopyDescription // copyDebugDesc
98};
5958d7c0 99
afb19109 100static CFTypeID __serverSessionTypeID = _kCFRuntimeNotATypeID;
5958d7c0 101
afb19109
A
102
103static CFStringRef
104__serverSessionCopyDescription(CFTypeRef cf)
17d3ee29 105{
afb19109
A
106 CFAllocatorRef allocator = CFGetAllocator(cf);
107 CFMutableStringRef result;
108 serverSessionRef session = (serverSessionRef)cf;
942cecd7 109
afb19109
A
110 result = CFStringCreateMutable(allocator, 0);
111 CFStringAppendFormat(result, NULL, CFSTR("<serverSession %p [%p]> {"), cf, allocator);
17d3ee29 112
afb19109
A
113 // add client port
114 CFStringAppendFormat(result, NULL, CFSTR("port = 0x%x (%d)"), session->key, session->key);
17d3ee29 115
afb19109
A
116 // add session info
117 if (session->name != NULL) {
118 CFStringAppendFormat(result, NULL, CFSTR(", name = %@"), session->name);
5e9ce69e 119 }
17d3ee29 120
afb19109
A
121 CFStringAppendFormat(result, NULL, CFSTR("}"));
122 return result;
17d3ee29
A
123}
124
125
afb19109
A
126static void
127__serverSessionDeallocate(CFTypeRef cf)
5958d7c0 128{
afb19109
A
129#pragma unused(cf)
130 serverSessionRef session = (serverSessionRef)cf;
5958d7c0 131
afb19109
A
132 if (session->changedKeys != NULL) CFRelease(session->changedKeys);
133 if (session->name != NULL) CFRelease(session->name);
134 if (session->sessionKeys != NULL) CFRelease(session->sessionKeys);
17d3ee29 135
afb19109
A
136 return;
137}
17d3ee29 138
17d3ee29 139
afb19109
A
140static serverSessionRef
141__serverSessionCreate(CFAllocatorRef allocator, mach_port_t server)
142{
143 static dispatch_once_t once;
144 serverSessionRef session;
145 uint32_t size;
17d3ee29 146
afb19109
A
147 // initialize runtime
148 dispatch_once(&once, ^{
149 __serverSessionTypeID = _CFRuntimeRegisterClass(&__serverSessionClass);
150 });
17d3ee29 151
afb19109
A
152 // allocate session
153 size = sizeof(serverSession) - sizeof(CFRuntimeBase);
154 session = (serverSessionRef)_CFRuntimeCreateInstance(allocator,
155 __serverSessionTypeID,
156 size,
157 NULL);
158 if (session == NULL) {
159 return NULL;
160 }
6f870c06 161
afb19109
A
162 // if needed, allocate a mach port for SCDynamicStore client
163 if (server == MACH_PORT_NULL) {
164 kern_return_t kr;
165 mach_port_t mp = MACH_PORT_NULL;
166#ifdef HAVE_MACHPORT_GUARDS
167 mach_port_options_t opts;
168#endif // HAVE_MACHPORT_GUARDS
5958d7c0 169
6f870c06
A
170 retry_allocate :
171
172#ifdef HAVE_MACHPORT_GUARDS
afb19109 173 memset(&opts, 0, sizeof(opts));
6f870c06
A
174 opts.flags = MPO_CONTEXT_AS_GUARD;
175
afb19109 176 kr = mach_port_construct(mach_task_self(), &opts, (mach_port_context_t)session, &mp);
6f870c06
A
177#else // HAVE_MACHPORT_GUARDS
178 kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp);
179#endif // HAVE_MACHPORT_GUARDS
180
181 if (kr != KERN_SUCCESS) {
182 char *err = NULL;
183
9de8ab86 184 SC_log(LOG_NOTICE, "could not allocate mach port: %s", mach_error_string(kr));
6f870c06
A
185 if ((kr == KERN_NO_SPACE) || (kr == KERN_RESOURCE_SHORTAGE)) {
186 sleep(1);
187 goto retry_allocate;
188 }
189
9de8ab86
A
190 (void) asprintf(&err, "Could not allocate mach port: %s", mach_error_string(kr));
191 _SC_crash(err != NULL ? err : "Could not allocate new session (mach) port",
6f870c06
A
192 NULL,
193 NULL);
194 if (err != NULL) free(err);
afb19109 195 CFRelease(session);
6f870c06
A
196 return NULL;
197 }
be997540 198
a40a14f8 199 // insert send right that will be moved to the client
6f870c06
A
200 kr = mach_port_insert_right(mach_task_self(),
201 mp,
202 mp,
203 MACH_MSG_TYPE_MAKE_SEND);
204 if (kr != KERN_SUCCESS) {
205 /*
206 * We can't insert a send right into our own port! This should
207 * only happen if someone stomped on OUR port (so let's leave
208 * the port alone).
209 */
afb19109
A
210 SC_log(LOG_ERR, "mach_port_insert_right() failed: %s", mach_error_string(kr));
211 CFRelease(session);
6f870c06
A
212 return NULL;
213 }
afb19109
A
214
215 server = mp;
be997540 216 }
a40a14f8 217
afb19109
A
218 session->callerEUID = 1; /* not "root" */
219 session->callerRootAccess = UNKNOWN;
220 session->callerWriteEntitlement = kCFNull; /* UNKNOWN */
221 session->key = server;
222// session->store = NULL;
942cecd7 223
afb19109
A
224 return session;
225}
5958d7c0 226
afb19109
A
227
228#pragma mark -
229#pragma mark SCDynamicStore state handler
230
231
232static void
233addSessionReference(const void *key, const void *value, void *context)
234{
235#pragma unused(key)
236 CFMutableDictionaryRef dict = (CFMutableDictionaryRef)context;
237 serverSessionRef session = (serverSessionRef)value;
238
239 if (session->name != NULL) {
240 int cnt;
241 CFNumberRef num;
242
243 if (!CFDictionaryGetValueIfPresent(dict,
244 session->name,
245 (const void **)&num) ||
246 !CFNumberGetValue(num, kCFNumberIntType, &cnt)) {
247 // if first session
248 cnt = 0;
249 }
250 cnt++;
251 num = CFNumberCreate(NULL, kCFNumberIntType, &cnt);
252 CFDictionarySetValue(dict, session->name, num);
253 CFRelease(num);
254 }
255
256 return;
5958d7c0
A
257}
258
259
afb19109
A
260static void
261add_state_handler()
5958d7c0 262{
afb19109
A
263 os_state_block_t state_block;
264
265 state_block = ^os_state_data_t(os_state_hints_t hints) {
266#pragma unused(hints)
267 CFDataRef data = NULL;
268 CFIndex n;
269 Boolean ok;
270 os_state_data_t state_data;
271 size_t state_data_size;
272 CFIndex state_len;
273
274 n = CFDictionaryGetCount(client_sessions);
c956c85e 275 if (n < client_sessions_advise) {
afb19109
A
276 CFStringRef str;
277
278 str = CFStringCreateWithFormat(NULL, NULL, CFSTR("n = %ld"), n);
279 ok = _SCSerialize(str, &data, NULL, NULL);
280 CFRelease(str);
281 } else {
282 CFMutableDictionaryRef dict;
283
284 dict = CFDictionaryCreateMutable(NULL,
285 0,
286 &kCFTypeDictionaryKeyCallBacks,
287 &kCFTypeDictionaryValueCallBacks);
288 CFDictionaryApplyFunction(client_sessions, addSessionReference, dict);
289 ok = _SCSerialize(dict, &data, NULL, NULL);
290 CFRelease(dict);
291 }
5958d7c0 292
afb19109
A
293 state_len = (ok && (data != NULL)) ? CFDataGetLength(data) : 0;
294 state_data_size = OS_STATE_DATA_SIZE_NEEDED(state_len);
295 if (state_data_size > MAX_STATEDUMP_SIZE) {
296 SC_log(LOG_ERR, "SCDynamicStore/sessions : state data too large (%zd > %zd)",
297 state_data_size,
298 (size_t)MAX_STATEDUMP_SIZE);
299 if (data != NULL) CFRelease(data);
300 return NULL;
301 }
5958d7c0 302
afb19109
A
303 state_data = calloc(1, state_data_size);
304 if (state_data == NULL) {
305 SC_log(LOG_ERR, "SCDynamicStore/sessions: could not allocate state data");
306 if (data != NULL) CFRelease(data);
307 return NULL;
5958d7c0 308 }
5958d7c0 309
afb19109
A
310 state_data->osd_type = OS_STATE_DATA_SERIALIZED_NSCF_OBJECT;
311 state_data->osd_data_size = (uint32_t)state_len;
312 strlcpy(state_data->osd_title, "SCDynamicStore/sessions", sizeof(state_data->osd_title));
313 if (state_len > 0) {
314 memcpy(state_data->osd_data, CFDataGetBytePtr(data), state_len);
315 }
316 if (data != NULL) CFRelease(data);
5958d7c0 317
afb19109
A
318 return state_data;
319 };
009ee3c6 320
afb19109
A
321 (void) os_state_add_handler(sessionQueue(), state_block);
322 return;
323}
5958d7c0 324
a40a14f8 325
afb19109
A
326#pragma mark -
327#pragma mark SCDynamicStore session management
5e9ce69e 328
942cecd7 329
afb19109
A
330__private_extern__
331serverSessionRef
332getSession(mach_port_t server)
333{
334 __block serverSessionRef session;
17d3ee29 335
afb19109
A
336 assert(server != MACH_PORT_NULL);
337 dispatch_sync(sessionQueue(), ^{
338 session = (serverSessionRef)CFDictionaryGetValue(client_sessions,
339 (const void *)(uintptr_t)server);
340 });
5958d7c0 341
afb19109
A
342 return session;
343}
344
345
346__private_extern__
347serverSessionRef
348getSessionNum(CFNumberRef serverNum)
349{
350 union {
351 mach_port_t mp;
352 uint64_t val;
353 } server;
354 serverSessionRef session;
355
356 (void) CFNumberGetValue(serverNum, kCFNumberSInt64Type, &server.val);
357 session = getSession(server.mp);
358
359 return session;
360}
361
362
363__private_extern__
364serverSessionRef
365getSessionStr(CFStringRef serverKey)
366{
367 mach_port_t server;
368 serverSessionRef session;
369 char str[16];
370
371 (void) _SC_cfstring_to_cstring(serverKey, str, sizeof(str), kCFStringEncodingASCII);
372 server = atoi(str);
373 session = getSession(server);
374
375 return session;
376}
377
378
c956c85e
A
379#if __has_feature(ptrauth_intrinsics)
380extern const struct { char c; } objc_absolute_packed_isa_class_mask;
381#endif
382
383static void
384memcpy_objc_object(void* dst, const void* restrict src, size_t size)
385{
386 // first, we copy the object
387 memcpy(dst, src, size);
388
389 // then, if needed, fix the isa pointer
390 #if __has_feature(ptrauth_intrinsics)
391 uintptr_t flags;
392 uintptr_t isa_mask;
393 void ** opaqueObject;
394 uintptr_t raw_isa;
395 uintptr_t real_isa;
396
397 opaqueObject = (void**)src;
398 isa_mask = (uintptr_t)&objc_absolute_packed_isa_class_mask;
399 flags = (uintptr_t)(*opaqueObject) & ~isa_mask;
400 real_isa = (uintptr_t)(*opaqueObject) & isa_mask;
401
402 #if __has_feature(ptrauth_objc_isa)
403 raw_isa = (uintptr_t)ptrauth_auth_data((void *)real_isa,
404 ptrauth_key_process_independent_data,
405 ptrauth_blend_discriminator(opaqueObject, 0x6AE1));
406 #else // __has_feature(ptrauth_objc_isa)
407 raw_isa = (uintptr_t)ptrauth_strip((void*)real_isa, ptrauth_key_process_independent_data);
408 #endif // __has_feature(ptrauth_objc_isa)
409 ((CFRuntimeBase*)dst)->_cfisa = raw_isa;
410 ((uint64_t*)dst)[0] |= flags;
411 #endif // __has_feature(ptrauth_intrinsics)
412}
413
414
afb19109
A
415__private_extern__
416serverSessionRef
417tempSession(mach_port_t server, CFStringRef name, audit_token_t auditToken)
418{
419 static dispatch_once_t once;
420 SCDynamicStorePrivateRef storePrivate; /* temp session */
421 static serverSession temp_session;
422
423 dispatch_once(&once, ^{
c956c85e
A
424 memcpy_objc_object(&temp_session, /* use "server" session clone */
425 server_session,
426 sizeof(temp_session));
afb19109
A
427 (void) __SCDynamicStoreOpen(&temp_session.store, NULL);
428 });
429
430 if (temp_session.key != server) {
431 // if not SCDynamicStore "server" port
432 return NULL;
5958d7c0 433 }
a40a14f8 434
afb19109
A
435 /* save audit token, caller entitlements */
436 temp_session.auditToken = auditToken;
437 temp_session.callerEUID = 1; /* not "root" */
438 temp_session.callerRootAccess = UNKNOWN;
439 if ((temp_session.callerWriteEntitlement != NULL) &&
440 (temp_session.callerWriteEntitlement != kCFNull)) {
441 CFRelease(temp_session.callerWriteEntitlement);
442 }
443 temp_session.callerWriteEntitlement = kCFNull; /* UNKNOWN */
444
445 /* save name */
446 storePrivate = (SCDynamicStorePrivateRef)temp_session.store;
447 if (storePrivate->name != NULL) CFRelease(storePrivate->name);
448 storePrivate->name = CFRetain(name);
449
450 return &temp_session;
5958d7c0
A
451}
452
453
009ee3c6 454__private_extern__
5958d7c0 455void
afb19109 456addSession(serverSessionRef session, Boolean isMain)
5958d7c0 457{
afb19109
A
458 session->serverChannel = dispatch_mach_create_f("configd/SCDynamicStore",
459 server_queue(),
460 (void *)session,
461 server_mach_channel_handler);
462 if (!isMain) {
463 // if not main SCDynamicStore port, watch for exit
c956c85e 464 dispatch_mach_notify_no_senders(session->serverChannel, FALSE);
afb19109
A
465 }
466#if TARGET_OS_SIMULATOR
467 // simulators don't support MiG QoS propagation yet
468 dispatch_set_qos_class_fallback(session->serverChannel, QOS_CLASS_USER_INITIATED);
469#else
470 dispatch_set_qos_class_fallback(session->serverChannel, QOS_CLASS_BACKGROUND);
471#endif
472 dispatch_mach_connect(session->serverChannel, session->key, MACH_PORT_NULL, NULL);
473 return;
474}
5958d7c0 475
5958d7c0 476
afb19109
A
477__private_extern__
478serverSessionRef
479addClient(mach_port_t server, audit_token_t audit_token)
480{
5958d7c0 481
afb19109 482 __block serverSessionRef newSession = NULL;
a40a14f8 483
afb19109
A
484 dispatch_sync(sessionQueue(), ^{
485 Boolean ok;
a40a14f8 486
afb19109
A
487 // check to see if we already have an open session
488 ok = CFDictionaryContainsKey(client_sessions,
489 (const void *)(uintptr_t)server);
490 if (ok) {
491 // if we've already added a session for this port
492 return;
a40a14f8
A
493 }
494
afb19109
A
495 // allocate a new session for "the" server
496 newSession = __serverSessionCreate(NULL, MACH_PORT_NULL);
497 if (newSession != NULL) {
498 // and add a port --> session mapping
499 CFDictionarySetValue(client_sessions,
500 (const void *)(uintptr_t)newSession->key,
501 newSession);
a40a14f8 502
afb19109
A
503 // save the audit_token in case we need to check the callers credentials
504 newSession->auditToken = audit_token;
a40a14f8 505
afb19109 506 CFRelease(newSession); // reference held by dictionary
a40a14f8 507 }
afb19109 508 });
a40a14f8 509
afb19109
A
510 if (newSession != NULL) {
511 addSession(newSession, FALSE);
512 }
a40a14f8 513
afb19109
A
514 return newSession;
515}
a40a14f8 516
afb19109
A
517
518__private_extern__
519serverSessionRef
520addServer(mach_port_t server)
521{
522 // allocate a session for "the" server
523 server_session = __serverSessionCreate(NULL, server);
524 addSession(server_session, TRUE);
525
526 // add a state dump handler
527 add_state_handler();
528
529 return server_session;
530}
531
532
533__private_extern__
534void
535cleanupSession(serverSessionRef session)
536{
537 mach_port_t server = session->key;
538
539 SC_trace("cleanup : %5d", server);
540
541 /*
542 * Close any open connections including cancelling any outstanding
543 * notification requests and releasing any locks.
544 */
545 __MACH_PORT_DEBUG(TRUE, "*** cleanupSession", server);
546 (void) __SCDynamicStoreClose(&session->store);
547 __MACH_PORT_DEBUG(TRUE, "*** cleanupSession (after __SCDynamicStoreClose)", server);
548
549 /*
550 * Our send right has already been removed. Remove our receive right.
551 */
552#ifdef HAVE_MACHPORT_GUARDS
553 (void) mach_port_destruct(mach_task_self(), server, 0, (mach_port_context_t)session);
554#else // HAVE_MACHPORT_GUARDS
555 (void) mach_port_mod_refs(mach_task_self(), server, MACH_PORT_RIGHT_RECEIVE, -1);
556#endif // HAVE_MACHPORT_GUARDS
557
558 /*
559 * release any entitlement info
560 */
561 if ((session->callerWriteEntitlement != NULL) &&
562 (session->callerWriteEntitlement != kCFNull)) {
563 CFRelease(session->callerWriteEntitlement);
a40a14f8
A
564 }
565
afb19109
A
566 /*
567 * get rid of the per-session structure.
568 */
569 dispatch_sync(sessionQueue(), ^{
570 CFDictionaryRemoveValue(client_sessions,
571 (const void *)(uintptr_t)server);
572 });
573
a40a14f8
A
574 return;
575}
576
577
afb19109
A
578__private_extern__
579void
580closeSession(serverSessionRef session)
a40a14f8 581{
afb19109
A
582 /*
583 * cancel and release the mach channel
584 */
585 if (session->serverChannel != NULL) {
586 dispatch_mach_cancel(session->serverChannel);
587 dispatch_release(session->serverChannel);
588 session->serverChannel = NULL;
589 }
590
591 return;
592}
a40a14f8 593
a40a14f8 594
afb19109
A
595typedef struct ReportSessionInfo {
596 FILE *f;
597 int n;
598} ReportSessionInfo, *ReportSessionInfoRef;
599
600static void
601printOne(const void *key, const void *value, void *context)
602{
603#pragma unused(key)
604 ReportSessionInfoRef reportInfo = (ReportSessionInfoRef)context;
605 serverSessionRef session = (serverSessionRef)value;
606
607 SCPrint(TRUE, reportInfo->f, CFSTR(" %d : port = 0x%x"), ++reportInfo->n, session->key);
608 SCPrint(TRUE, reportInfo->f, CFSTR(", name = %@"), session->name);
609 if (session->changedKeys != NULL) {
610 SCPrint(TRUE, reportInfo->f, CFSTR("\n changedKeys = %@"), session->changedKeys);
a40a14f8 611 }
afb19109
A
612 if (session->sessionKeys != NULL) {
613 SCPrint(TRUE, reportInfo->f, CFSTR("\n sessionKeys = %@"), session->sessionKeys);
614 }
615 SCPrint(TRUE, reportInfo->f, CFSTR("\n"));
616 return;
617}
618
619
620__private_extern__
621void
622listSessions(FILE *f)
623{
624 dispatch_sync(sessionQueue(), ^{
625 ReportSessionInfo reportInfo = { .f = f, .n = 0 };
5958d7c0 626
afb19109
A
627 SCPrint(TRUE, f, CFSTR("Current sessions :\n"));
628 CFDictionaryApplyFunction(client_sessions,
629 printOne,
630 (void *)&reportInfo);
631 SCPrint(TRUE, f, CFSTR("\n"));
632 });
633 return;
a40a14f8
A
634}
635
afb19109
A
636
637#include <Security/Security.h>
638#include <Security/SecTask.h>
639
5e9ce69e
A
640static CFTypeRef
641copyEntitlement(serverSessionRef session, CFStringRef entitlement)
a40a14f8 642{
a40a14f8 643 SecTaskRef task;
5e9ce69e 644 CFTypeRef value = NULL;
a40a14f8 645
5e9ce69e 646 // Create the security task from the audit token
a40a14f8
A
647 task = SecTaskCreateWithAuditToken(NULL, session->auditToken);
648 if (task != NULL) {
649 CFErrorRef error = NULL;
a40a14f8 650
5e9ce69e 651 // Get the value for the entitlement
6bb65964 652 value = SecTaskCopyValueForEntitlement(task, entitlement, &error);
5e9ce69e
A
653 if ((value == NULL) && (error != NULL)) {
654 CFIndex code = CFErrorGetCode(error);
655 CFStringRef domain = CFErrorGetDomain(error);
656
657 if (!CFEqual(domain, kCFErrorDomainMach) ||
658 ((code != kIOReturnInvalid) && (code != kIOReturnNotFound))) {
659 // if unexpected error
9de8ab86
A
660 SC_log(LOG_NOTICE, "SecTaskCopyValueForEntitlement(,\"%@\",) failed, error = %@ : %@",
661 entitlement,
662 error,
afb19109 663 session->name);
5958d7c0 664 }
a40a14f8 665 CFRelease(error);
5958d7c0 666 }
a40a14f8
A
667
668 CFRelease(task);
669 } else {
9de8ab86 670 SC_log(LOG_NOTICE, "SecTaskCreateWithAuditToken() failed: %@",
afb19109 671 session->name);
5958d7c0 672 }
a40a14f8 673
5e9ce69e 674 return value;
5958d7c0
A
675}
676
5e9ce69e
A
677
678static pid_t
679sessionPid(serverSessionRef session)
680{
681 pid_t caller_pid;
682
683#if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) && !TARGET_OS_IPHONE
684 caller_pid = audit_token_to_pid(session->auditToken);
685#else // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) && !TARGET_OS_IPHONE
686 audit_token_to_au32(session->auditToken,
687 NULL, // auidp
688 NULL, // euid
689 NULL, // egid
690 NULL, // ruid
691 NULL, // rgid
692 &caller_pid, // pid
693 NULL, // asid
694 NULL); // tid
695#endif // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) && !TARGET_OS_IPHONE
696
697 return caller_pid;
698}
a40a14f8
A
699
700
701__private_extern__
702Boolean
703hasRootAccess(serverSessionRef session)
704{
942cecd7 705#if !TARGET_OS_SIMULATOR
5e9ce69e 706
a40a14f8 707 if (session->callerRootAccess == UNKNOWN) {
5e9ce69e
A
708#if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) && !TARGET_OS_IPHONE
709 session->callerEUID = audit_token_to_euid(session->auditToken);
710#else // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) && !TARGET_OS_IPHONE
a40a14f8
A
711 audit_token_to_au32(session->auditToken,
712 NULL, // auidp
713 &session->callerEUID, // euid
714 NULL, // egid
715 NULL, // ruid
716 NULL, // rgid
717 NULL, // pid
718 NULL, // asid
719 NULL); // tid
5e9ce69e 720#endif // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) && !TARGET_OS_IPHONE
a40a14f8
A
721 session->callerRootAccess = (session->callerEUID == 0) ? YES : NO;
722 }
723
724 return (session->callerRootAccess == YES) ? TRUE : FALSE;
5e9ce69e 725
942cecd7 726#else // !TARGET_OS_SIMULATOR
1ef45fa4 727#pragma unused(session)
5e9ce69e
A
728
729 /*
730 * assume that all processes interacting with
731 * the iOS Simulator "configd" are OK.
732 */
733 return TRUE;
734
942cecd7 735#endif // !TARGET_OS_SIMULATOR
a40a14f8
A
736}
737
738
739__private_extern__
740Boolean
1ef45fa4 741hasWriteAccess(serverSessionRef session, const char *op, CFStringRef key)
a40a14f8 742{
5e9ce69e 743 Boolean isSetup;
a40a14f8 744
5e9ce69e
A
745 // need to special case writing "Setup:" keys
746 isSetup = CFStringHasPrefix(key, kSCDynamicStoreDomainSetup);
747
748 if (hasRootAccess(session)) {
749 pid_t pid;
750
751 // grant write access to eUID==0 processes
752
753 pid = sessionPid(session);
754 if (isSetup && (pid != getpid())) {
755 /*
756 * WAIT!!!
757 *
758 * This is NOT configd (or a plugin) trying to
759 * write to an SCDynamicStore "Setup:" key. In
760 * general, this is unwise and we should at the
761 * very least complain.
762 */
1ef45fa4 763 SC_log(LOG_NOTICE, "*** Non-configd process (pid=%d) attempting to %s \"%@\" ***",
9de8ab86 764 pid,
1ef45fa4 765 op,
9de8ab86 766 key);
a40a14f8 767 }
5e9ce69e
A
768
769 return TRUE;
770 }
771
772 if (isSetup) {
773 /*
774 * STOP!!!
775 *
776 * This is a non-root process trying to write to
777 * an SCDynamicStore "Setup:" key. This is not
778 * something we should ever allow (regardless of
779 * any entitlements).
780 */
9de8ab86
A
781 SC_log(LOG_NOTICE, "*** Non-root process (pid=%d) attempting to modify \"%@\" ***",
782 sessionPid(session),
783 key);
5e9ce69e 784
afb19109 785 return FALSE;
5e9ce69e
A
786 }
787
5e9ce69e
A
788 if (session->callerWriteEntitlement == kCFNull) {
789 session->callerWriteEntitlement = copyEntitlement(session,
790 kSCWriteEntitlementName);
791 }
792
793 if (session->callerWriteEntitlement == NULL) {
794 return FALSE;
795 }
796
797 if (isA_CFBoolean(session->callerWriteEntitlement) &&
798 CFBooleanGetValue(session->callerWriteEntitlement)) {
799 // grant write access to "entitled" processes
800 return TRUE;
801 }
802
803 if (isA_CFDictionary(session->callerWriteEntitlement)) {
804 CFArrayRef keys;
805 CFArrayRef patterns;
806
807 keys = CFDictionaryGetValue(session->callerWriteEntitlement, CFSTR("keys"));
808 if (isA_CFArray(keys)) {
809 if (CFArrayContainsValue(keys,
810 CFRangeMake(0, CFArrayGetCount(keys)),
811 key)) {
812 // if key matches one of the entitlement "keys", grant
813 // write access
814 return TRUE;
815 }
816 }
817
818 patterns = CFDictionaryGetValue(session->callerWriteEntitlement, CFSTR("patterns"));
819 if (isA_CFArray(patterns)) {
820 CFIndex i;
821 CFIndex n = CFArrayGetCount(patterns);
822
823 for (i = 0; i < n; i++) {
824 CFStringRef pattern;
825
826 pattern = CFArrayGetValueAtIndex(patterns, i);
827 if (isA_CFString(pattern)) {
828 if (patternKeyMatches(pattern, key)) {
829 // if key matches one of the entitlement
830 // "patterns", grant write access
831 return TRUE;
832 }
833 }
834 }
a40a14f8 835 }
a40a14f8
A
836 }
837
5e9ce69e 838 return FALSE;
a40a14f8 839}
6bb65964
A
840
841
842__private_extern__
843Boolean
844hasPathAccess(serverSessionRef session, const char *path)
845{
846 pid_t pid;
847 char realPath[PATH_MAX];
848
849 if (realpath(path, realPath) == NULL) {
9de8ab86 850 SC_log(LOG_INFO, "realpath() failed: %s", strerror(errno));
6bb65964
A
851 return FALSE;
852 }
853
5e9ce69e
A
854#if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) && !TARGET_OS_IPHONE
855 pid = audit_token_to_pid(session->auditToken);
856#else // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) && !TARGET_OS_IPHONE
6bb65964
A
857 audit_token_to_au32(session->auditToken,
858 NULL, // auidp
859 NULL, // euid
860 NULL, // egid
861 NULL, // ruid
862 NULL, // rgid
863 &pid, // pid
864 NULL, // asid
865 NULL); // tid
5e9ce69e
A
866#endif // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) && !TARGET_OS_IPHONE
867 if (sandbox_check(pid, // pid
868 "file-write-data", // operation
869 SANDBOX_FILTER_PATH | SANDBOX_CHECK_NO_REPORT, // sandbox_filter_type
870 realPath) > 0) { // ...
9de8ab86 871 SC_log(LOG_INFO, "sandbox access denied: %s", strerror(errno));
6bb65964
A
872 return FALSE;
873 }
874
875 return TRUE;
876}