]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/helper/SCHelper_server.c
9231e08221b7ab0ba86c660910a3201551583702
[apple/configd.git] / SystemConfiguration.fproj / helper / SCHelper_server.c
1 /*
2 * Copyright (c) 2005, 2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
12 *
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
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <sys/types.h>
27
28 #include <CoreFoundation/CoreFoundation.h>
29 #include <SystemConfiguration/SystemConfiguration.h>
30 #include <SystemConfiguration/SCPrivate.h>
31 #include <Security/Security.h>
32
33 #include "SCPreferencesInternal.h"
34 #include "SCHelper_client.h"
35 #include "helper_comm.h"
36
37
38 static AuthorizationRef authorization = NULL;
39 static SCPreferencesRef prefs = NULL;
40
41
42 /*
43 * EXIT
44 * (in) data = N/A
45 * (out) status = SCError()
46 * (out) reply = N/A
47 */
48 static Boolean
49 do_Exit(void *info, CFDataRef data, uint32_t *status, CFDataRef *reply)
50 {
51 return FALSE;
52 }
53
54
55 /*
56 * AUTHORIZE
57 * (in) data = AuthorizationExternalForm
58 * (out) status = OSStatus
59 * (out) reply = N/A
60 */
61 static Boolean
62 do_Auth(void *info, CFDataRef data, uint32_t *status, CFDataRef *reply)
63 {
64 if (authorization != NULL) {
65 AuthorizationFree(authorization, kAuthorizationFlagDefaults);
66 // AuthorizationFree(authorization, kAuthorizationFlagDestroyRights);
67 authorization = NULL;
68 }
69
70 if (data != NULL) {
71 AuthorizationExternalForm extForm;
72
73 if (CFDataGetLength(data) == sizeof(extForm.bytes)) {
74 OSStatus err;
75
76 memcpy(extForm.bytes, CFDataGetBytePtr(data), sizeof(extForm.bytes));
77 err = AuthorizationCreateFromExternalForm(&extForm, &authorization);
78 if (err != errAuthorizationSuccess) {
79 SCLog(TRUE, LOG_ERR,
80 CFSTR("AuthorizationCreateFromExternalForm() failed: status = %d"),
81 (int)err);
82 }
83 }
84
85 CFRelease(data);
86 }
87
88 *status = (authorization != NULL) ? 0 : 1;
89
90 return TRUE;
91 }
92
93
94 /*
95 * SCHELPER_MSG_KEYCHAIN_COPY
96 * (in) data = unique_id
97 * (out) status = SCError()
98 * (out) reply = password
99 */
100 static Boolean
101 do_keychain_copy(void *info, CFDataRef data, uint32_t *status, CFDataRef *reply)
102 {
103 CFStringRef unique_id = NULL;
104
105 if ((data != NULL) && !_SCUnserializeString(&unique_id, data, NULL, 0)) {
106 return FALSE;
107 }
108
109 if (!isA_CFString(unique_id)) {
110 return FALSE;
111 }
112
113 *reply = _SCPreferencesSystemKeychainPasswordItemCopy(prefs, unique_id);
114 CFRelease(unique_id);
115 if (*reply == NULL) {
116 *status = SCError();
117 }
118
119 return TRUE;
120 }
121
122
123 /*
124 * SCHELPER_MSG_KEYCHAIN_EXISTS
125 * (in) data = unique_id
126 * (out) status = SCError()
127 * (out) reply = N/A
128 */
129 static Boolean
130 do_keychain_exists(void *info, CFDataRef data, uint32_t *status, CFDataRef *reply)
131 {
132 Boolean ok;
133 CFStringRef unique_id = NULL;
134
135 if ((data != NULL) && !_SCUnserializeString(&unique_id, data, NULL, 0)) {
136 return FALSE;
137 }
138
139 if (!isA_CFString(unique_id)) {
140 return FALSE;
141 }
142
143 ok = _SCPreferencesSystemKeychainPasswordItemExists(prefs, unique_id);
144 CFRelease(unique_id);
145
146 if (!ok) {
147 *status = SCError();
148 }
149
150 return TRUE;
151 }
152
153
154 /*
155 * SCHELPER_MSG_KEYCHAIN_REMOVE
156 * (in) data = unique_id
157 * (out) status = SCError()
158 * (out) reply = N/A
159 */
160 static Boolean
161 do_keychain_remove(void *info, CFDataRef data, uint32_t *status, CFDataRef *reply)
162 {
163 Boolean ok;
164 CFStringRef unique_id = NULL;
165
166 if ((data != NULL) && !_SCUnserializeString(&unique_id, data, NULL, 0)) {
167 return FALSE;
168 }
169
170 if (!isA_CFString(unique_id)) {
171 return FALSE;
172 }
173
174 ok = _SCPreferencesSystemKeychainPasswordItemRemove(prefs, unique_id);
175 CFRelease(unique_id);
176
177 if (!ok) {
178 *status = SCError();
179 }
180
181 return TRUE;
182 }
183
184
185 /*
186 * SCHELPER_MSG_KEYCHAIN_SET
187 * (in) data = options dictionary
188 * (out) status = SCError()
189 * (out) reply = N/A
190 */
191 static Boolean
192 do_keychain_set(void *info, CFDataRef data, uint32_t *status, CFDataRef *reply)
193 {
194 CFStringRef account;
195 CFStringRef description;
196 CFArrayRef executablePaths = NULL;
197 CFStringRef label;
198 Boolean ok;
199 CFDictionaryRef options = NULL;
200 CFDataRef password;
201 CFStringRef unique_id;
202
203 if ((data != NULL) && !_SCUnserialize((CFPropertyListRef *)&options, data, NULL, 0)) {
204 return FALSE;
205 }
206
207 if (!isA_CFDictionary(options)) {
208 return FALSE;
209 }
210
211 if (CFDictionaryGetValueIfPresent(options,
212 kSCKeychainOptionsAllowedExecutables,
213 (const void **)&executablePaths)) {
214 CFMutableArrayRef executableURLs;
215 CFIndex i;
216 CFIndex n;
217 CFMutableDictionaryRef newOptions;
218
219 executableURLs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
220 n = CFArrayGetCount(executablePaths);
221 for (i = 0; i < n; i++) {
222 CFDataRef path;
223 CFURLRef url;
224
225 path = CFArrayGetValueAtIndex(executablePaths, i);
226 url = CFURLCreateFromFileSystemRepresentation(NULL,
227 CFDataGetBytePtr(path),
228 CFDataGetLength(path),
229 FALSE);
230 if (url != NULL) {
231 CFArrayAppendValue(executableURLs, url);
232 CFRelease(url);
233 }
234 }
235
236 newOptions = CFDictionaryCreateMutableCopy(NULL, 0, options);
237 CFDictionarySetValue(newOptions, kSCKeychainOptionsAllowedExecutables, executableURLs);
238 CFRelease(executableURLs);
239
240 CFRelease(options);
241 options = newOptions;
242 }
243
244 unique_id = CFDictionaryGetValue(options, kSCKeychainOptionsUniqueID);
245 label = CFDictionaryGetValue(options, kSCKeychainOptionsLabel);
246 description = CFDictionaryGetValue(options, kSCKeychainOptionsDescription);
247 account = CFDictionaryGetValue(options, kSCKeychainOptionsAccount);
248 password = CFDictionaryGetValue(options, kSCKeychainOptionsPassword);
249
250 ok = _SCPreferencesSystemKeychainPasswordItemSet(prefs,
251 unique_id,
252 label,
253 description,
254 account,
255 password,
256 options);
257 CFRelease(options);
258
259 if (!ok) {
260 *status = SCError();
261 }
262
263 return TRUE;
264 }
265
266
267 /*
268 * SCHELPER_MSG_INTERFACE_REFRESH
269 * (in) data = ifName
270 * (out) status = SCError()
271 * (out) reply = N/A
272 */
273 static Boolean
274 do_interface_refresh(void *info, CFDataRef data, uint32_t *status, CFDataRef *reply)
275 {
276 CFStringRef ifName = NULL;
277 Boolean ok;
278
279 if ((data != NULL) && !_SCUnserializeString(&ifName, data, NULL, 0)) {
280 SCLog(TRUE, LOG_ERR, CFSTR("interface name not valid"));
281 return FALSE;
282 }
283
284 if (!isA_CFString(ifName)) {
285 SCLog(TRUE, LOG_ERR, CFSTR("interface name not valid"));
286 return FALSE;
287 }
288
289 ok = _SCNetworkInterfaceForceConfigurationRefresh(ifName);
290 CFRelease(ifName);
291
292 if (!ok) {
293 *status = SCError();
294 }
295
296 return TRUE;
297 }
298
299
300 /*
301 * OPEN
302 * (in) data = prefsID
303 * (out) status = SCError()
304 * (out) reply = N/A
305 */
306 static Boolean
307 do_prefs_Open(void *info, CFDataRef data, uint32_t *status, CFDataRef *reply)
308 {
309 CFStringRef prefsID = NULL;
310
311 if (prefs != NULL) {
312 return FALSE;
313 }
314
315 if ((data != NULL) && !_SCUnserializeString(&prefsID, data, NULL, 0)) {
316 SCLog(TRUE, LOG_ERR, CFSTR("prefsID not valid"));
317 return FALSE;
318 }
319
320 prefs = SCPreferencesCreate(NULL, CFSTR("SCHelper"), prefsID);
321 if (prefsID != NULL) CFRelease(prefsID);
322
323 if (prefs == NULL) {
324 *status = SCError();
325 }
326
327 return TRUE;
328 }
329
330
331 /*
332 * ACCESS
333 * (in) data = N/A
334 * (out) status = SCError()
335 * (out) reply = current signature + current preferences
336 */
337 static Boolean
338 do_prefs_Access(void *info, CFDataRef data, uint32_t *status, CFDataRef *reply)
339 {
340 Boolean ok;
341 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
342 CFDataRef signature;
343
344 if (prefs == NULL) {
345 return FALSE;
346 }
347
348 signature = SCPreferencesGetSignature(prefs);
349 if (signature != NULL) {
350 const void * dictKeys[2];
351 const void * dictVals[2];
352 CFDictionaryRef replyDict;
353
354 dictKeys[0] = CFSTR("signature");
355 dictVals[0] = signature;
356
357 dictKeys[1] = CFSTR("preferences");
358 dictVals[1] = prefsPrivate->prefs;
359
360 replyDict = CFDictionaryCreate(NULL,
361 (const void **)&dictKeys,
362 (const void **)&dictVals,
363 sizeof(dictKeys)/sizeof(dictKeys[0]),
364 &kCFTypeDictionaryKeyCallBacks,
365 &kCFTypeDictionaryValueCallBacks);
366
367 ok = _SCSerialize(replyDict, reply, NULL, NULL);
368 CFRelease(replyDict);
369 if (!ok) {
370 return FALSE;
371 }
372 } else {
373 *status = SCError();
374 }
375
376 SCPreferencesSynchronize(prefs);
377 return TRUE;
378 }
379
380
381 /*
382 * LOCK
383 * (in) data = client prefs signature (NULL if check not needed)
384 * (out) status = SCError()
385 * (out) reply = N/A
386 */
387 static Boolean
388 do_prefs_Lock(void *info, CFDataRef data, uint32_t *status, CFDataRef *reply)
389 {
390 CFDataRef clientSignature = (CFDataRef)data;
391 Boolean ok;
392 Boolean wait = (info == (void *)FALSE) ? FALSE : TRUE;
393
394 if (prefs == NULL) {
395 return FALSE;
396 }
397
398 ok = SCPreferencesLock(prefs, wait);
399 if (!ok) {
400 *status = SCError();
401 return TRUE;
402 }
403
404 if (clientSignature != NULL) {
405 CFDataRef serverSignature;
406
407 serverSignature = SCPreferencesGetSignature(prefs);
408 if (!CFEqual(clientSignature, serverSignature)) {
409 (void)SCPreferencesUnlock(prefs);
410 *status = kSCStatusStale;
411 }
412 }
413
414 return TRUE;
415 }
416
417
418 /*
419 * COMMIT
420 * (in) data = new preferences (NULL if commit w/no changes)
421 * (out) status = SCError()
422 * (out) reply = new signature
423 */
424 static Boolean
425 do_prefs_Commit(void *info, CFDataRef data, uint32_t *status, CFDataRef *reply)
426 {
427 Boolean ok;
428 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
429
430 if (prefs == NULL) {
431 return FALSE;
432 }
433
434 if (data != NULL) {
435 if (prefsPrivate->prefs != NULL) {
436 CFRelease(prefsPrivate->prefs);
437 }
438
439 ok = _SCUnserialize((CFPropertyListRef *)&prefsPrivate->prefs, data, NULL, 0);
440 if (!ok) {
441 return FALSE;
442 }
443
444 prefsPrivate->accessed = TRUE;
445 prefsPrivate->changed = TRUE;
446 }
447
448 ok = SCPreferencesCommitChanges(prefs);
449 if (ok) {
450 *reply = SCPreferencesGetSignature(prefs);
451 CFRetain(*reply);
452 } else {
453 *status = SCError();
454 }
455
456 SCPreferencesSynchronize(prefs);
457 return TRUE;
458 }
459
460
461 /*
462 * APPLY
463 * (in) data = N/A
464 * (out) status = SCError()
465 * (out) reply = N/A
466 */
467 static Boolean
468 do_prefs_Apply(void *info, CFDataRef data, uint32_t *status, CFDataRef *reply)
469 {
470 Boolean ok;
471
472 if (prefs == NULL) {
473 return FALSE;
474 }
475
476 ok = SCPreferencesApplyChanges(prefs);
477 if (!ok) {
478 *status = SCError();
479 }
480
481 return TRUE;
482 }
483
484
485 /*
486 * UNLOCK
487 * (in) data = N/A
488 * (out) status = SCError()
489 * (out) reply = N/A
490 */
491 static Boolean
492 do_prefs_Unlock(void *info, CFDataRef data, uint32_t *status, CFDataRef *reply)
493 {
494 Boolean ok;
495
496 if (prefs == NULL) {
497 return FALSE;
498 }
499
500 ok = SCPreferencesUnlock(prefs);
501 if (!ok) {
502 *status = SCError();
503 }
504
505 return TRUE;
506 }
507
508
509 /*
510 * CLOSE
511 * (in) data = N/A
512 * (out) status = SCError()
513 * (out) reply = N/A
514 */
515 static Boolean
516 do_prefs_Close(void *info, CFDataRef data, uint32_t *status, CFDataRef *reply)
517 {
518 if (prefs == NULL) {
519 return FALSE;
520 }
521
522 CFRelease(prefs);
523 prefs = NULL;
524
525 return TRUE;
526 }
527
528
529 static Boolean
530 hasAuthorization()
531 {
532 AuthorizationFlags flags;
533 AuthorizationItem items[1];
534 AuthorizationRights rights;
535 OSStatus status;
536
537 if (authorization == NULL) {
538 return FALSE;
539 }
540
541 items[0].name = "system.preferences";
542 items[0].value = NULL;
543 items[0].valueLength = 0;
544 items[0].flags = 0;
545
546 rights.count = sizeof(items) / sizeof(items[0]);
547 rights.items = items;
548
549 flags = kAuthorizationFlagDefaults;
550 flags |= kAuthorizationFlagExtendRights;
551 flags |= kAuthorizationFlagInteractionAllowed;
552 // flags |= kAuthorizationFlagPartialRights;
553 // flags |= kAuthorizationFlagPreAuthorize;
554
555 status = AuthorizationCopyRights(authorization,
556 &rights,
557 kAuthorizationEmptyEnvironment,
558 flags,
559 NULL);
560 if (status != errAuthorizationSuccess) {
561 return FALSE;
562 }
563
564 if (items[0].flags != 0) SCLog(TRUE, LOG_DEBUG, CFSTR("***** success w/flags (%u) != 0"), items[0].flags);
565 return TRUE;
566 }
567
568
569 typedef Boolean (*helperFunction) (void *info,
570 CFDataRef data,
571 uint32_t *status,
572 CFDataRef *reply);
573
574
575 static const struct helper {
576 int command;
577 const char *commandName;
578 Boolean needsAuthorization;
579 helperFunction func;
580 void *info;
581 } helpers[] = {
582 { SCHELPER_MSG_AUTH, "AUTH", FALSE, do_Auth , NULL },
583
584 { SCHELPER_MSG_PREFS_OPEN, "PREFS open", FALSE, do_prefs_Open , NULL },
585 { SCHELPER_MSG_PREFS_ACCESS, "PREFS access", TRUE, do_prefs_Access , NULL },
586 { SCHELPER_MSG_PREFS_LOCK, "PREFS lock", TRUE, do_prefs_Lock , (void *)FALSE },
587 { SCHELPER_MSG_PREFS_LOCKWAIT, "PREFS lock/wait", TRUE, do_prefs_Lock , (void *)TRUE },
588 { SCHELPER_MSG_PREFS_COMMIT, "PREFS commit", TRUE, do_prefs_Commit , NULL },
589 { SCHELPER_MSG_PREFS_APPLY, "PREFS apply", TRUE, do_prefs_Apply , NULL },
590 { SCHELPER_MSG_PREFS_UNLOCK, "PREFS unlock", FALSE, do_prefs_Unlock , NULL },
591 { SCHELPER_MSG_PREFS_CLOSE, "PREFS close", FALSE, do_prefs_Close , NULL },
592
593 { SCHELPER_MSG_INTERFACE_REFRESH, "INTERFACE refresh", TRUE, do_interface_refresh , NULL },
594
595 { SCHELPER_MSG_KEYCHAIN_COPY, "KEYCHAIN copy", TRUE, do_keychain_copy , NULL },
596 { SCHELPER_MSG_KEYCHAIN_EXISTS, "KEYCHAIN exists", TRUE, do_keychain_exists , NULL },
597 { SCHELPER_MSG_KEYCHAIN_REMOVE, "KEYCHAIN remove", TRUE, do_keychain_remove , NULL },
598 { SCHELPER_MSG_KEYCHAIN_SET, "KEYCHAIN set", TRUE, do_keychain_set , NULL },
599
600 { SCHELPER_MSG_EXIT, "EXIT", FALSE, do_Exit , NULL }
601 };
602 #define nHELPERS (sizeof(helpers)/sizeof(struct helper))
603
604
605 static int
606 findHelper(command)
607 {
608 int i;
609
610 for (i = 0; i < (int)nHELPERS; i++) {
611 if (helpers[i].command == command) {
612 return i;
613 }
614 }
615
616 return -1;
617 }
618
619
620 int
621 main(int argc, char **argv)
622 {
623 int err = 0;
624 Boolean ok = TRUE;
625
626 openlog("SCHelper", LOG_CONS|LOG_PID, LOG_DAEMON);
627
628 if (geteuid() != 0) {
629 (void)__SCHelper_txMessage(STDOUT_FILENO, EACCES, NULL);
630 exit(EACCES);
631 }
632
633 // send "we are here" message
634 if (!__SCHelper_txMessage(STDOUT_FILENO, 0, NULL)) {
635 exit(EIO);
636 }
637
638 while (ok) {
639 uint32_t command;
640 CFDataRef data;
641 int i;
642 CFDataRef reply;
643 uint32_t status;
644
645 command = 0;
646 data = NULL;
647 if (!__SCHelper_rxMessage(STDIN_FILENO, &command, &data)) {
648 SCLog(TRUE, LOG_ERR, CFSTR("no command"));
649 err = EIO;
650 break;
651 }
652
653 i = findHelper(command);
654 if (i == -1) {
655 SCLog(TRUE, LOG_ERR, CFSTR("received unknown command : %u"), command);
656 err = EINVAL;
657 break;
658 }
659
660 SCLog(TRUE, LOG_DEBUG,
661 CFSTR("processing command \"%s\"%s"),
662 helpers[i].commandName,
663 (data != NULL) ? " w/data" : "");
664
665 status = kSCStatusOK;
666 reply = NULL;
667
668 if (helpers[i].needsAuthorization && !hasAuthorization()) {
669 SCLog(TRUE, LOG_DEBUG,
670 CFSTR("command \"%s\" : not authorized"),
671 helpers[i].commandName);
672 status = kSCStatusAccessError;
673 }
674
675 if (status == kSCStatusOK) {
676 ok = (*helpers[i].func)(helpers[i].info, data, &status, &reply);
677 }
678
679 SCLog(TRUE, LOG_DEBUG,
680 CFSTR("sending status %u%s"),
681 status,
682 (reply != NULL) ? " w/reply" : "");
683
684 if (!__SCHelper_txMessage(STDOUT_FILENO, status, reply)) {
685 err = EIO;
686 break;
687 }
688
689 if (reply != NULL) {
690 CFRelease(reply);
691 }
692 }
693
694 if (prefs != NULL) {
695 CFRelease(prefs);
696 }
697
698 if (authorization != NULL) {
699 AuthorizationFree(authorization, kAuthorizationFlagDefaults);
700 // AuthorizationFree(authorization, kAuthorizationFlagDestroyRights);
701 }
702
703 exit(err);
704 }