]>
Commit | Line | Data |
---|---|---|
5958d7c0 | 1 | /* |
9de8ab86 | 2 | * Copyright (c) 2000, 2001, 2003-2005, 2007-2015 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> | |
6bb65964 A |
42 | #include <sandbox.h> |
43 | ||
6f870c06 A |
44 | #if !TARGET_IPHONE_SIMULATOR || (defined(IPHONE_SIMULATOR_HOST_MIN_VERSION_REQUIRED) && (IPHONE_SIMULATOR_HOST_MIN_VERSION_REQUIRED >= 1090)) |
45 | #define HAVE_MACHPORT_GUARDS | |
46 | #endif | |
47 | ||
a40a14f8 | 48 | |
5958d7c0 | 49 | /* information maintained for each active session */ |
17d3ee29 A |
50 | static serverSessionRef *sessions = NULL; |
51 | static int nSessions = 0; /* # of allocated sessions */ | |
52 | static int lastSession = -1; /* # of last used session */ | |
5958d7c0 | 53 | |
6bb65964 A |
54 | /* CFMachPortInvalidation runloop */ |
55 | static CFRunLoopRef sessionRunLoop = NULL; | |
56 | ||
17d3ee29 A |
57 | /* temp session */ |
58 | static serverSessionRef temp_session = NULL; | |
59 | ||
6bb65964 | 60 | |
009ee3c6 | 61 | __private_extern__ |
5958d7c0 A |
62 | serverSessionRef |
63 | getSession(mach_port_t server) | |
64 | { | |
65 | int i; | |
66 | ||
67 | if (server == MACH_PORT_NULL) { | |
9de8ab86 | 68 | SC_log(LOG_NOTICE, "Excuse me, why is getSession() being called with an invalid port?"); |
5958d7c0 A |
69 | return NULL; |
70 | } | |
71 | ||
17d3ee29 A |
72 | /* look for matching session (note: slot 0 is the "server" port) */ |
73 | for (i = 1; i <= lastSession; i++) { | |
009ee3c6 A |
74 | serverSessionRef thisSession = sessions[i]; |
75 | ||
76 | if (thisSession == NULL) { | |
77 | /* found an empty slot, skip it */ | |
78 | continue; | |
17d3ee29 A |
79 | } |
80 | ||
81 | if (thisSession->key == server) { | |
82 | /* we've seen this server before */ | |
83 | return thisSession; | |
84 | } | |
85 | ||
86 | if ((thisSession->store != NULL) && | |
87 | (((SCDynamicStorePrivateRef)thisSession->store)->notifySignalTask == server)) { | |
88 | /* we've seen this task port before */ | |
009ee3c6 | 89 | return thisSession; |
5958d7c0 A |
90 | } |
91 | } | |
92 | ||
93 | /* no sessions available */ | |
94 | return NULL; | |
95 | } | |
96 | ||
97 | ||
17d3ee29 A |
98 | __private_extern__ |
99 | serverSessionRef | |
100 | tempSession(mach_port_t server, CFStringRef name, audit_token_t auditToken) | |
101 | { | |
102 | static dispatch_once_t once; | |
103 | SCDynamicStorePrivateRef storePrivate; | |
104 | ||
105 | if (sessions[0]->key != server) { | |
106 | // if not SCDynamicStore "server" port | |
107 | return NULL; | |
108 | } | |
109 | ||
110 | dispatch_once(&once, ^{ | |
111 | temp_session = sessions[0]; /* use "server" session */ | |
112 | (void) __SCDynamicStoreOpen(&temp_session->store, NULL); | |
113 | }); | |
114 | ||
5e9ce69e A |
115 | /* save audit token, caller entitlements */ |
116 | temp_session->auditToken = auditToken; | |
117 | temp_session->callerEUID = 1; /* not "root" */ | |
118 | temp_session->callerRootAccess = UNKNOWN; | |
5e9ce69e A |
119 | if ((temp_session->callerWriteEntitlement != NULL) && |
120 | (temp_session->callerWriteEntitlement != kCFNull)) { | |
121 | CFRelease(temp_session->callerWriteEntitlement); | |
122 | } | |
123 | temp_session->callerWriteEntitlement = kCFNull; /* UNKNOWN */ | |
17d3ee29 A |
124 | |
125 | /* save name */ | |
126 | storePrivate = (SCDynamicStorePrivateRef)temp_session->store; | |
127 | if (storePrivate->name != NULL) CFRelease(storePrivate->name); | |
128 | storePrivate->name = CFRetain(name); | |
129 | ||
130 | return temp_session; | |
131 | } | |
132 | ||
133 | ||
009ee3c6 | 134 | __private_extern__ |
5958d7c0 | 135 | serverSessionRef |
be997540 | 136 | addSession(mach_port_t server, CFStringRef (*copyDescription)(const void *info)) |
5958d7c0 | 137 | { |
6f870c06 A |
138 | CFMachPortContext context = { 0, NULL, NULL, NULL, NULL }; |
139 | kern_return_t kr; | |
140 | mach_port_t mp = server; | |
141 | int n = -1; | |
142 | serverSessionRef newSession = NULL; | |
6bb65964 A |
143 | |
144 | /* save current (SCDynamicStore) runloop */ | |
145 | if (sessionRunLoop == NULL) { | |
146 | sessionRunLoop = CFRunLoopGetCurrent(); | |
147 | } | |
5958d7c0 A |
148 | |
149 | if (nSessions <= 0) { | |
17d3ee29 A |
150 | /* if first session (the "server" port) */ |
151 | n = 0; /* use slot "0" */ | |
152 | lastSession = 0; /* last used slot */ | |
153 | ||
154 | nSessions = 64; | |
155 | sessions = malloc(nSessions * sizeof(serverSessionRef)); | |
6f870c06 A |
156 | |
157 | // allocate a new session for "the" server | |
158 | newSession = calloc(1, sizeof(serverSession)); | |
5958d7c0 | 159 | } else { |
6f870c06 A |
160 | int i; |
161 | #ifdef HAVE_MACHPORT_GUARDS | |
162 | mach_port_options_t opts; | |
163 | #endif // HAVE_MACHPORT_GUARDS | |
be997540 | 164 | |
17d3ee29 A |
165 | /* check to see if we already have an open session (note: slot 0 is the "server" port) */ |
166 | for (i = 1; i <= lastSession; i++) { | |
6f870c06 | 167 | serverSessionRef thisSession = sessions[i]; |
17d3ee29 A |
168 | |
169 | if (thisSession == NULL) { | |
170 | /* found an empty slot */ | |
171 | if (n < 0) { | |
172 | /* keep track of the first [empty] slot */ | |
173 | n = i; | |
174 | } | |
175 | ||
176 | /* and keep looking for a matching session */ | |
177 | continue; | |
178 | } | |
179 | ||
180 | if (thisSession->key == server) { | |
181 | /* we've seen this server before */ | |
182 | return NULL; | |
183 | } | |
184 | ||
185 | if ((thisSession->store != NULL) && | |
186 | (((SCDynamicStorePrivateRef)thisSession->store)->notifySignalTask == server)) { | |
187 | /* we've seen this task port before */ | |
188 | return NULL; | |
5958d7c0 A |
189 | } |
190 | } | |
17d3ee29 A |
191 | |
192 | /* add a new session */ | |
5958d7c0 | 193 | if (n < 0) { |
17d3ee29 A |
194 | /* if no empty slots */ |
195 | n = ++lastSession; | |
196 | if (lastSession >= nSessions) { | |
197 | /* expand the session list */ | |
198 | nSessions *= 2; | |
199 | sessions = reallocf(sessions, (nSessions * sizeof(serverSessionRef))); | |
200 | } | |
5958d7c0 | 201 | } |
17d3ee29 | 202 | |
6f870c06 A |
203 | // allocate a session for this client |
204 | newSession = calloc(1, sizeof(serverSession)); | |
205 | ||
17d3ee29 A |
206 | // create mach port for SCDynamicStore client |
207 | mp = MACH_PORT_NULL; | |
5958d7c0 | 208 | |
6f870c06 A |
209 | retry_allocate : |
210 | ||
211 | #ifdef HAVE_MACHPORT_GUARDS | |
212 | bzero(&opts, sizeof(opts)); | |
213 | opts.flags = MPO_CONTEXT_AS_GUARD; | |
214 | ||
215 | kr = mach_port_construct(mach_task_self(), &opts, newSession, &mp); | |
216 | #else // HAVE_MACHPORT_GUARDS | |
217 | kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp); | |
218 | #endif // HAVE_MACHPORT_GUARDS | |
219 | ||
220 | if (kr != KERN_SUCCESS) { | |
221 | char *err = NULL; | |
222 | ||
9de8ab86 | 223 | SC_log(LOG_NOTICE, "could not allocate mach port: %s", mach_error_string(kr)); |
6f870c06 A |
224 | if ((kr == KERN_NO_SPACE) || (kr == KERN_RESOURCE_SHORTAGE)) { |
225 | sleep(1); | |
226 | goto retry_allocate; | |
227 | } | |
228 | ||
9de8ab86 A |
229 | (void) asprintf(&err, "Could not allocate mach port: %s", mach_error_string(kr)); |
230 | _SC_crash(err != NULL ? err : "Could not allocate new session (mach) port", | |
6f870c06 A |
231 | NULL, |
232 | NULL); | |
233 | if (err != NULL) free(err); | |
234 | ||
235 | free(newSession); | |
236 | return NULL; | |
237 | } | |
238 | } | |
be997540 A |
239 | |
240 | // create server port | |
6f870c06 | 241 | context.info = newSession; |
17d3ee29 | 242 | context.copyDescription = copyDescription; |
a40a14f8 A |
243 | |
244 | // | |
245 | // Note: we create the CFMachPort *before* we insert a send | |
246 | // right present to ensure that CF does not establish | |
247 | // its dead name notification. | |
248 | // | |
6f870c06 A |
249 | newSession->serverPort = _SC_CFMachPortCreateWithPort("SCDynamicStore/session", |
250 | mp, | |
251 | configdCallback, | |
252 | &context); | |
6bb65964 | 253 | |
17d3ee29 | 254 | if (n > 0) { |
a40a14f8 | 255 | // insert send right that will be moved to the client |
6f870c06 A |
256 | kr = mach_port_insert_right(mach_task_self(), |
257 | mp, | |
258 | mp, | |
259 | MACH_MSG_TYPE_MAKE_SEND); | |
260 | if (kr != KERN_SUCCESS) { | |
261 | /* | |
262 | * We can't insert a send right into our own port! This should | |
263 | * only happen if someone stomped on OUR port (so let's leave | |
264 | * the port alone). | |
265 | */ | |
9de8ab86 | 266 | SC_log(LOG_NOTICE, "mach_port_insert_right() failed: %s", mach_error_string(kr)); |
6f870c06 A |
267 | |
268 | free(newSession); | |
269 | return NULL; | |
270 | } | |
be997540 | 271 | } |
a40a14f8 | 272 | |
6f870c06 | 273 | sessions[n] = newSession; |
5e9ce69e A |
274 | sessions[n]->key = mp; |
275 | // sessions[n]->serverRunLoopSource = NULL; | |
276 | // sessions[n]->store = NULL; | |
277 | sessions[n]->callerEUID = 1; /* not "root" */ | |
278 | sessions[n]->callerRootAccess = UNKNOWN; | |
5e9ce69e | 279 | sessions[n]->callerWriteEntitlement = kCFNull; /* UNKNOWN */ |
5958d7c0 | 280 | |
6f870c06 | 281 | return newSession; |
5958d7c0 A |
282 | } |
283 | ||
284 | ||
009ee3c6 | 285 | __private_extern__ |
5958d7c0 | 286 | void |
17d3ee29 | 287 | cleanupSession(mach_port_t server) |
5958d7c0 | 288 | { |
17d3ee29 | 289 | int i; |
5958d7c0 | 290 | |
17d3ee29 A |
291 | for (i = 1; i <= lastSession; i++) { |
292 | CFStringRef sessionKey; | |
293 | serverSessionRef thisSession = sessions[i]; | |
5958d7c0 A |
294 | |
295 | if (thisSession == NULL) { | |
296 | /* found an empty slot, skip it */ | |
297 | continue; | |
5958d7c0 | 298 | } |
5958d7c0 | 299 | |
17d3ee29 | 300 | if (thisSession->key == server) { |
5958d7c0 A |
301 | /* |
302 | * session entry still exists. | |
303 | */ | |
304 | ||
9de8ab86 | 305 | SC_trace(_configd_trace, "cleanup : %5d\n", server); |
009ee3c6 | 306 | |
5958d7c0 A |
307 | /* |
308 | * Close any open connections including cancelling any outstanding | |
309 | * notification requests and releasing any locks. | |
310 | */ | |
a40a14f8 | 311 | __MACH_PORT_DEBUG(TRUE, "*** cleanupSession", server); |
17d3ee29 | 312 | (void) __SCDynamicStoreClose(&thisSession->store); |
a40a14f8 | 313 | __MACH_PORT_DEBUG(TRUE, "*** cleanupSession (after __SCDynamicStoreClose)", server); |
5958d7c0 | 314 | |
be997540 | 315 | /* |
a40a14f8 | 316 | * Our send right has already been removed. Remove our receive right. |
be997540 | 317 | */ |
6f870c06 A |
318 | #ifdef HAVE_MACHPORT_GUARDS |
319 | (void) mach_port_destruct(mach_task_self(), server, 0, thisSession); | |
320 | #else // HAVE_MACHPORT_GUARDS | |
a40a14f8 | 321 | (void) mach_port_mod_refs(mach_task_self(), server, MACH_PORT_RIGHT_RECEIVE, -1); |
6f870c06 | 322 | #endif // HAVE_MACHPORT_GUARDS |
a40a14f8 | 323 | |
5e9ce69e A |
324 | /* |
325 | * release any entitlement info | |
326 | */ | |
327 | if ((thisSession->callerWriteEntitlement != NULL) && | |
328 | (thisSession->callerWriteEntitlement != kCFNull)) { | |
329 | CFRelease(thisSession->callerWriteEntitlement); | |
330 | } | |
5e9ce69e | 331 | |
5958d7c0 | 332 | /* |
17d3ee29 A |
333 | * We don't need any remaining information in the |
334 | * sessionData dictionary, remove it. | |
335 | */ | |
336 | sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), server); | |
337 | CFDictionaryRemoveValue(sessionData, sessionKey); | |
338 | CFRelease(sessionKey); | |
339 | ||
340 | /* | |
341 | * get rid of the per-session structure. | |
5958d7c0 | 342 | */ |
17d3ee29 A |
343 | free(thisSession); |
344 | sessions[i] = NULL; | |
345 | ||
346 | if (i == lastSession) { | |
347 | /* we are removing the last session, update last used slot */ | |
348 | while (--lastSession > 0) { | |
349 | if (sessions[lastSession] != NULL) { | |
350 | break; | |
351 | } | |
352 | } | |
353 | } | |
5958d7c0 A |
354 | |
355 | return; | |
356 | } | |
357 | } | |
a40a14f8 | 358 | |
9de8ab86 | 359 | SC_log(LOG_NOTICE, "MACH_NOTIFY_NO_SENDERS w/no session, port = %d", server); |
a40a14f8 | 360 | __MACH_PORT_DEBUG(TRUE, "*** cleanupSession w/no session", server); |
5958d7c0 A |
361 | return; |
362 | } | |
363 | ||
364 | ||
009ee3c6 | 365 | __private_extern__ |
5958d7c0 | 366 | void |
a40a14f8 | 367 | listSessions(FILE *f) |
5958d7c0 A |
368 | { |
369 | int i; | |
370 | ||
a40a14f8 | 371 | SCPrint(TRUE, f, CFSTR("Current sessions :\n")); |
17d3ee29 | 372 | for (i = 0; i <= lastSession; i++) { |
5958d7c0 A |
373 | serverSessionRef thisSession = sessions[i]; |
374 | ||
375 | if (thisSession == NULL) { | |
376 | continue; | |
377 | } | |
378 | ||
a40a14f8 A |
379 | SCPrint(TRUE, f, CFSTR("\t%d : port = 0x%x"), i, thisSession->key); |
380 | ||
381 | if (thisSession->store != NULL) { | |
382 | SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)thisSession->store; | |
383 | ||
384 | if (storePrivate->notifySignalTask != TASK_NULL) { | |
385 | SCPrint(TRUE, f, CFSTR(", task = %d"), storePrivate->notifySignalTask); | |
386 | } | |
387 | } | |
388 | ||
389 | if (sessionData != NULL) { | |
390 | CFDictionaryRef info; | |
391 | CFStringRef key; | |
392 | ||
393 | key = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), thisSession->key); | |
394 | info = CFDictionaryGetValue(sessionData, key); | |
395 | CFRelease(key); | |
396 | if (info != NULL) { | |
397 | CFStringRef name; | |
398 | ||
399 | name = CFDictionaryGetValue(info, kSCDName); | |
400 | if (name != NULL) { | |
401 | SCPrint(TRUE, f, CFSTR(", name = %@"), name); | |
402 | } | |
403 | } | |
404 | } | |
405 | ||
406 | if (thisSession->serverPort != NULL) { | |
407 | SCPrint(TRUE, f, CFSTR("\n\t\t%@"), thisSession->serverPort); | |
408 | } | |
409 | ||
410 | if (thisSession->serverRunLoopSource != NULL) { | |
411 | SCPrint(TRUE, f, CFSTR("\n\t\t%@"), thisSession->serverRunLoopSource); | |
412 | } | |
413 | ||
414 | SCPrint(TRUE, f, CFSTR("\n")); | |
415 | } | |
416 | ||
417 | SCPrint(TRUE, f, CFSTR("\n")); | |
418 | return; | |
419 | } | |
420 | ||
421 | ||
a40a14f8 A |
422 | #include <Security/Security.h> |
423 | #include <Security/SecTask.h> | |
5958d7c0 | 424 | |
a40a14f8 A |
425 | static CFStringRef |
426 | sessionName(serverSessionRef session) | |
427 | { | |
428 | CFDictionaryRef info; | |
429 | CFStringRef name = NULL; | |
430 | CFStringRef sessionKey; | |
431 | ||
432 | sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), session->key); | |
433 | info = CFDictionaryGetValue(sessionData, sessionKey); | |
434 | CFRelease(sessionKey); | |
435 | ||
436 | if (info != NULL) { | |
437 | name = CFDictionaryGetValue(info, kSCDName); | |
438 | } | |
5958d7c0 | 439 | |
a40a14f8 A |
440 | return (name != NULL) ? name : CFSTR("???"); |
441 | } | |
442 | ||
5e9ce69e A |
443 | static CFTypeRef |
444 | copyEntitlement(serverSessionRef session, CFStringRef entitlement) | |
a40a14f8 | 445 | { |
a40a14f8 | 446 | SecTaskRef task; |
5e9ce69e | 447 | CFTypeRef value = NULL; |
a40a14f8 | 448 | |
5e9ce69e | 449 | // Create the security task from the audit token |
a40a14f8 A |
450 | task = SecTaskCreateWithAuditToken(NULL, session->auditToken); |
451 | if (task != NULL) { | |
452 | CFErrorRef error = NULL; | |
a40a14f8 | 453 | |
5e9ce69e | 454 | // Get the value for the entitlement |
6bb65964 | 455 | value = SecTaskCopyValueForEntitlement(task, entitlement, &error); |
5e9ce69e A |
456 | if ((value == NULL) && (error != NULL)) { |
457 | CFIndex code = CFErrorGetCode(error); | |
458 | CFStringRef domain = CFErrorGetDomain(error); | |
459 | ||
460 | if (!CFEqual(domain, kCFErrorDomainMach) || | |
461 | ((code != kIOReturnInvalid) && (code != kIOReturnNotFound))) { | |
462 | // if unexpected error | |
9de8ab86 A |
463 | SC_log(LOG_NOTICE, "SecTaskCopyValueForEntitlement(,\"%@\",) failed, error = %@ : %@", |
464 | entitlement, | |
465 | error, | |
466 | sessionName(session)); | |
5958d7c0 | 467 | } |
a40a14f8 | 468 | CFRelease(error); |
5958d7c0 | 469 | } |
a40a14f8 A |
470 | |
471 | CFRelease(task); | |
472 | } else { | |
9de8ab86 A |
473 | SC_log(LOG_NOTICE, "SecTaskCreateWithAuditToken() failed: %@", |
474 | sessionName(session)); | |
5958d7c0 | 475 | } |
a40a14f8 | 476 | |
5e9ce69e | 477 | return value; |
5958d7c0 A |
478 | } |
479 | ||
5e9ce69e A |
480 | |
481 | static pid_t | |
482 | sessionPid(serverSessionRef session) | |
483 | { | |
484 | pid_t caller_pid; | |
485 | ||
486 | #if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) && !TARGET_OS_IPHONE | |
487 | caller_pid = audit_token_to_pid(session->auditToken); | |
488 | #else // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) && !TARGET_OS_IPHONE | |
489 | audit_token_to_au32(session->auditToken, | |
490 | NULL, // auidp | |
491 | NULL, // euid | |
492 | NULL, // egid | |
493 | NULL, // ruid | |
494 | NULL, // rgid | |
495 | &caller_pid, // pid | |
496 | NULL, // asid | |
497 | NULL); // tid | |
498 | #endif // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) && !TARGET_OS_IPHONE | |
499 | ||
500 | return caller_pid; | |
501 | } | |
a40a14f8 A |
502 | |
503 | ||
504 | __private_extern__ | |
505 | Boolean | |
506 | hasRootAccess(serverSessionRef session) | |
507 | { | |
5e9ce69e A |
508 | #if !TARGET_IPHONE_SIMULATOR |
509 | ||
a40a14f8 | 510 | if (session->callerRootAccess == UNKNOWN) { |
5e9ce69e A |
511 | #if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) && !TARGET_OS_IPHONE |
512 | session->callerEUID = audit_token_to_euid(session->auditToken); | |
513 | #else // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) && !TARGET_OS_IPHONE | |
a40a14f8 A |
514 | audit_token_to_au32(session->auditToken, |
515 | NULL, // auidp | |
516 | &session->callerEUID, // euid | |
517 | NULL, // egid | |
518 | NULL, // ruid | |
519 | NULL, // rgid | |
520 | NULL, // pid | |
521 | NULL, // asid | |
522 | NULL); // tid | |
5e9ce69e | 523 | #endif // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) && !TARGET_OS_IPHONE |
a40a14f8 A |
524 | session->callerRootAccess = (session->callerEUID == 0) ? YES : NO; |
525 | } | |
526 | ||
527 | return (session->callerRootAccess == YES) ? TRUE : FALSE; | |
5e9ce69e A |
528 | |
529 | #else // !TARGET_IPHONE_SIMULATOR | |
530 | ||
531 | /* | |
532 | * assume that all processes interacting with | |
533 | * the iOS Simulator "configd" are OK. | |
534 | */ | |
535 | return TRUE; | |
536 | ||
537 | #endif // !TARGET_IPHONE_SIMULATOR | |
a40a14f8 A |
538 | } |
539 | ||
540 | ||
541 | __private_extern__ | |
542 | Boolean | |
5e9ce69e | 543 | hasWriteAccess(serverSessionRef session, CFStringRef key) |
a40a14f8 | 544 | { |
5e9ce69e | 545 | Boolean isSetup; |
a40a14f8 | 546 | |
5e9ce69e A |
547 | // need to special case writing "Setup:" keys |
548 | isSetup = CFStringHasPrefix(key, kSCDynamicStoreDomainSetup); | |
549 | ||
550 | if (hasRootAccess(session)) { | |
551 | pid_t pid; | |
552 | ||
553 | // grant write access to eUID==0 processes | |
554 | ||
555 | pid = sessionPid(session); | |
556 | if (isSetup && (pid != getpid())) { | |
557 | /* | |
558 | * WAIT!!! | |
559 | * | |
560 | * This is NOT configd (or a plugin) trying to | |
561 | * write to an SCDynamicStore "Setup:" key. In | |
562 | * general, this is unwise and we should at the | |
563 | * very least complain. | |
564 | */ | |
9de8ab86 A |
565 | SC_log(LOG_NOTICE, "*** Non-configd process (pid=%d) attempting to modify \"%@\" ***", |
566 | pid, | |
567 | key); | |
a40a14f8 | 568 | } |
5e9ce69e A |
569 | |
570 | return TRUE; | |
571 | } | |
572 | ||
573 | if (isSetup) { | |
574 | /* | |
575 | * STOP!!! | |
576 | * | |
577 | * This is a non-root process trying to write to | |
578 | * an SCDynamicStore "Setup:" key. This is not | |
579 | * something we should ever allow (regardless of | |
580 | * any entitlements). | |
581 | */ | |
9de8ab86 A |
582 | SC_log(LOG_NOTICE, "*** Non-root process (pid=%d) attempting to modify \"%@\" ***", |
583 | sessionPid(session), | |
584 | key); | |
5e9ce69e A |
585 | |
586 | //return FALSE; // return FALSE when rdar://9811832 has beed fixed | |
587 | } | |
588 | ||
5e9ce69e A |
589 | if (session->callerWriteEntitlement == kCFNull) { |
590 | session->callerWriteEntitlement = copyEntitlement(session, | |
591 | kSCWriteEntitlementName); | |
592 | } | |
593 | ||
594 | if (session->callerWriteEntitlement == NULL) { | |
595 | return FALSE; | |
596 | } | |
597 | ||
598 | if (isA_CFBoolean(session->callerWriteEntitlement) && | |
599 | CFBooleanGetValue(session->callerWriteEntitlement)) { | |
600 | // grant write access to "entitled" processes | |
601 | return TRUE; | |
602 | } | |
603 | ||
604 | if (isA_CFDictionary(session->callerWriteEntitlement)) { | |
605 | CFArrayRef keys; | |
606 | CFArrayRef patterns; | |
607 | ||
608 | keys = CFDictionaryGetValue(session->callerWriteEntitlement, CFSTR("keys")); | |
609 | if (isA_CFArray(keys)) { | |
610 | if (CFArrayContainsValue(keys, | |
611 | CFRangeMake(0, CFArrayGetCount(keys)), | |
612 | key)) { | |
613 | // if key matches one of the entitlement "keys", grant | |
614 | // write access | |
615 | return TRUE; | |
616 | } | |
617 | } | |
618 | ||
619 | patterns = CFDictionaryGetValue(session->callerWriteEntitlement, CFSTR("patterns")); | |
620 | if (isA_CFArray(patterns)) { | |
621 | CFIndex i; | |
622 | CFIndex n = CFArrayGetCount(patterns); | |
623 | ||
624 | for (i = 0; i < n; i++) { | |
625 | CFStringRef pattern; | |
626 | ||
627 | pattern = CFArrayGetValueAtIndex(patterns, i); | |
628 | if (isA_CFString(pattern)) { | |
629 | if (patternKeyMatches(pattern, key)) { | |
630 | // if key matches one of the entitlement | |
631 | // "patterns", grant write access | |
632 | return TRUE; | |
633 | } | |
634 | } | |
635 | } | |
a40a14f8 | 636 | } |
a40a14f8 A |
637 | } |
638 | ||
5e9ce69e | 639 | return FALSE; |
a40a14f8 | 640 | } |
6bb65964 A |
641 | |
642 | ||
643 | __private_extern__ | |
644 | Boolean | |
645 | hasPathAccess(serverSessionRef session, const char *path) | |
646 | { | |
647 | pid_t pid; | |
648 | char realPath[PATH_MAX]; | |
649 | ||
650 | if (realpath(path, realPath) == NULL) { | |
9de8ab86 | 651 | SC_log(LOG_INFO, "realpath() failed: %s", strerror(errno)); |
6bb65964 A |
652 | return FALSE; |
653 | } | |
654 | ||
5e9ce69e A |
655 | #if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) && !TARGET_OS_IPHONE |
656 | pid = audit_token_to_pid(session->auditToken); | |
657 | #else // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) && !TARGET_OS_IPHONE | |
6bb65964 A |
658 | audit_token_to_au32(session->auditToken, |
659 | NULL, // auidp | |
660 | NULL, // euid | |
661 | NULL, // egid | |
662 | NULL, // ruid | |
663 | NULL, // rgid | |
664 | &pid, // pid | |
665 | NULL, // asid | |
666 | NULL); // tid | |
5e9ce69e A |
667 | #endif // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) && !TARGET_OS_IPHONE |
668 | if (sandbox_check(pid, // pid | |
669 | "file-write-data", // operation | |
670 | SANDBOX_FILTER_PATH | SANDBOX_CHECK_NO_REPORT, // sandbox_filter_type | |
671 | realPath) > 0) { // ... | |
9de8ab86 | 672 | SC_log(LOG_INFO, "sandbox access denied: %s", strerror(errno)); |
6bb65964 A |
673 | return FALSE; |
674 | } | |
675 | ||
676 | return TRUE; | |
677 | } |