]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/helper/SCHelper_server.c
configd-210.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / helper / SCHelper_server.c
1 /*
2 * Copyright (c) 2005-2007 Apple 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 bcopy(CFDataGetBytePtr(data), extForm.bytes, 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 return TRUE;
377 }
378
379
380 /*
381 * LOCK
382 * (in) data = client prefs signature (NULL if check not needed)
383 * (out) status = SCError()
384 * (out) reply = N/A
385 */
386 static Boolean
387 do_prefs_Lock(void *info, CFDataRef data, uint32_t *status, CFDataRef *reply)
388 {
389 CFDataRef clientSignature = (CFDataRef)data;
390 Boolean ok;
391 Boolean wait = (info == (void *)FALSE) ? FALSE : TRUE;
392
393 if (prefs == NULL) {
394 return FALSE;
395 }
396
397 ok = SCPreferencesLock(prefs, wait);
398 if (!ok) {
399 *status = SCError();
400 return TRUE;
401 }
402
403 if (clientSignature != NULL) {
404 CFDataRef serverSignature;
405
406 serverSignature = SCPreferencesGetSignature(prefs);
407 if (!CFEqual(clientSignature, serverSignature)) {
408 (void)SCPreferencesUnlock(prefs);
409 *status = kSCStatusStale;
410 }
411 }
412
413 return TRUE;
414 }
415
416
417 /*
418 * COMMIT
419 * (in) data = new preferences (NULL if commit w/no changes)
420 * (out) status = SCError()
421 * (out) reply = new signature
422 */
423 static Boolean
424 do_prefs_Commit(void *info, CFDataRef data, uint32_t *status, CFDataRef *reply)
425 {
426 Boolean ok;
427 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
428
429 if (prefs == NULL) {
430 return FALSE;
431 }
432
433 if (data != NULL) {
434 if (prefsPrivate->prefs != NULL) {
435 CFRelease(prefsPrivate->prefs);
436 }
437
438 ok = _SCUnserialize((CFPropertyListRef *)&prefsPrivate->prefs, data, NULL, 0);
439 if (!ok) {
440 return FALSE;
441 }
442
443 prefsPrivate->accessed = TRUE;
444 prefsPrivate->changed = TRUE;
445 }
446
447 ok = SCPreferencesCommitChanges(prefs);
448 if (ok) {
449 *reply = SCPreferencesGetSignature(prefs);
450 CFRetain(*reply);
451 } else {
452 *status = SCError();
453 }
454
455 return TRUE;
456 }
457
458
459 /*
460 * APPLY
461 * (in) data = N/A
462 * (out) status = SCError()
463 * (out) reply = N/A
464 */
465 static Boolean
466 do_prefs_Apply(void *info, CFDataRef data, uint32_t *status, CFDataRef *reply)
467 {
468 Boolean ok;
469
470 if (prefs == NULL) {
471 return FALSE;
472 }
473
474 ok = SCPreferencesApplyChanges(prefs);
475 if (!ok) {
476 *status = SCError();
477 }
478
479 return TRUE;
480 }
481
482
483 /*
484 * UNLOCK
485 * (in) data = N/A
486 * (out) status = SCError()
487 * (out) reply = N/A
488 */
489 static Boolean
490 do_prefs_Unlock(void *info, CFDataRef data, uint32_t *status, CFDataRef *reply)
491 {
492 Boolean ok;
493
494 if (prefs == NULL) {
495 return FALSE;
496 }
497
498 ok = SCPreferencesUnlock(prefs);
499 if (!ok) {
500 *status = SCError();
501 }
502
503 return TRUE;
504 }
505
506
507 /*
508 * CLOSE
509 * (in) data = N/A
510 * (out) status = SCError()
511 * (out) reply = N/A
512 */
513 static Boolean
514 do_prefs_Close(void *info, CFDataRef data, uint32_t *status, CFDataRef *reply)
515 {
516 if (prefs == NULL) {
517 return FALSE;
518 }
519
520 CFRelease(prefs);
521 prefs = NULL;
522
523 return TRUE;
524 }
525
526
527 /*
528 * SYNCHRONIZE
529 * (in) data = N/A
530 * (out) status = kSCStatusOK
531 * (out) reply = N/A
532 */
533 static Boolean
534 do_prefs_Synchronize(void *info, CFDataRef data, uint32_t *status, CFDataRef *reply)
535 {
536 if (prefs == NULL) {
537 return FALSE;
538 }
539
540 SCPreferencesSynchronize(prefs);
541 *status = kSCStatusOK;
542 return TRUE;
543 }
544
545
546 static Boolean
547 hasAuthorization()
548 {
549 AuthorizationFlags flags;
550 AuthorizationItem items[1];
551 AuthorizationRights rights;
552 OSStatus status;
553
554 if (authorization == NULL) {
555 return FALSE;
556 }
557
558 items[0].name = "system.preferences";
559 items[0].value = NULL;
560 items[0].valueLength = 0;
561 items[0].flags = 0;
562
563 rights.count = sizeof(items) / sizeof(items[0]);
564 rights.items = items;
565
566 flags = kAuthorizationFlagDefaults;
567 flags |= kAuthorizationFlagExtendRights;
568 flags |= kAuthorizationFlagInteractionAllowed;
569 // flags |= kAuthorizationFlagPartialRights;
570 // flags |= kAuthorizationFlagPreAuthorize;
571
572 status = AuthorizationCopyRights(authorization,
573 &rights,
574 kAuthorizationEmptyEnvironment,
575 flags,
576 NULL);
577 if (status != errAuthorizationSuccess) {
578 return FALSE;
579 }
580
581 if (items[0].flags != 0) SCLog(TRUE, LOG_DEBUG, CFSTR("***** success w/flags (%u) != 0"), items[0].flags);
582 return TRUE;
583 }
584
585
586 typedef Boolean (*helperFunction) (void *info,
587 CFDataRef data,
588 uint32_t *status,
589 CFDataRef *reply);
590
591
592 static const struct helper {
593 int command;
594 const char *commandName;
595 Boolean needsAuthorization;
596 helperFunction func;
597 void *info;
598 } helpers[] = {
599 { SCHELPER_MSG_AUTH, "AUTH", FALSE, do_Auth , NULL },
600
601 { SCHELPER_MSG_PREFS_OPEN, "PREFS open", FALSE, do_prefs_Open , NULL },
602 { SCHELPER_MSG_PREFS_ACCESS, "PREFS access", TRUE, do_prefs_Access , NULL },
603 { SCHELPER_MSG_PREFS_LOCK, "PREFS lock", TRUE, do_prefs_Lock , (void *)FALSE },
604 { SCHELPER_MSG_PREFS_LOCKWAIT, "PREFS lock/wait", TRUE, do_prefs_Lock , (void *)TRUE },
605 { SCHELPER_MSG_PREFS_COMMIT, "PREFS commit", TRUE, do_prefs_Commit , NULL },
606 { SCHELPER_MSG_PREFS_APPLY, "PREFS apply", TRUE, do_prefs_Apply , NULL },
607 { SCHELPER_MSG_PREFS_UNLOCK, "PREFS unlock", FALSE, do_prefs_Unlock , NULL },
608 { SCHELPER_MSG_PREFS_CLOSE, "PREFS close", FALSE, do_prefs_Close , NULL },
609 { SCHELPER_MSG_PREFS_SYNCHRONIZE, "PREFS synchronize", FALSE, do_prefs_Synchronize , NULL },
610
611 { SCHELPER_MSG_INTERFACE_REFRESH, "INTERFACE refresh", TRUE, do_interface_refresh , NULL },
612
613 { SCHELPER_MSG_KEYCHAIN_COPY, "KEYCHAIN copy", TRUE, do_keychain_copy , NULL },
614 { SCHELPER_MSG_KEYCHAIN_EXISTS, "KEYCHAIN exists", TRUE, do_keychain_exists , NULL },
615 { SCHELPER_MSG_KEYCHAIN_REMOVE, "KEYCHAIN remove", TRUE, do_keychain_remove , NULL },
616 { SCHELPER_MSG_KEYCHAIN_SET, "KEYCHAIN set", TRUE, do_keychain_set , NULL },
617
618 { SCHELPER_MSG_EXIT, "EXIT", FALSE, do_Exit , NULL }
619 };
620 #define nHELPERS (sizeof(helpers)/sizeof(struct helper))
621
622
623 static int
624 findHelper(command)
625 {
626 int i;
627
628 for (i = 0; i < (int)nHELPERS; i++) {
629 if (helpers[i].command == command) {
630 return i;
631 }
632 }
633
634 return -1;
635 }
636
637
638 int
639 main(int argc, char **argv)
640 {
641 int err = 0;
642 Boolean ok = TRUE;
643
644 openlog("SCHelper", LOG_CONS|LOG_PID, LOG_DAEMON);
645
646 if (geteuid() != 0) {
647 (void)__SCHelper_txMessage(STDOUT_FILENO, EACCES, NULL);
648 exit(EACCES);
649 }
650
651 // send "we are here" message
652 if (!__SCHelper_txMessage(STDOUT_FILENO, 0, NULL)) {
653 exit(EIO);
654 }
655
656 while (ok) {
657 uint32_t command;
658 CFDataRef data;
659 int i;
660 CFDataRef reply;
661 uint32_t status;
662
663 command = 0;
664 data = NULL;
665 if (!__SCHelper_rxMessage(STDIN_FILENO, &command, &data)) {
666 SCLog(TRUE, LOG_ERR, CFSTR("no command"));
667 err = EIO;
668 break;
669 }
670
671 i = findHelper(command);
672 if (i == -1) {
673 SCLog(TRUE, LOG_ERR, CFSTR("received unknown command : %u"), command);
674 err = EINVAL;
675 break;
676 }
677
678 SCLog(TRUE, LOG_DEBUG,
679 CFSTR("processing command \"%s\"%s"),
680 helpers[i].commandName,
681 (data != NULL) ? " w/data" : "");
682
683 status = kSCStatusOK;
684 reply = NULL;
685
686 if (helpers[i].needsAuthorization && !hasAuthorization()) {
687 SCLog(TRUE, LOG_DEBUG,
688 CFSTR("command \"%s\" : not authorized"),
689 helpers[i].commandName);
690 status = kSCStatusAccessError;
691 }
692
693 if (status == kSCStatusOK) {
694 ok = (*helpers[i].func)(helpers[i].info, data, &status, &reply);
695 }
696
697 SCLog(TRUE, LOG_DEBUG,
698 CFSTR("sending status %u%s"),
699 status,
700 (reply != NULL) ? " w/reply" : "");
701
702 if (!__SCHelper_txMessage(STDOUT_FILENO, status, reply)) {
703 err = EIO;
704 break;
705 }
706
707 if (reply != NULL) {
708 CFRelease(reply);
709 }
710 }
711
712 if (prefs != NULL) {
713 CFRelease(prefs);
714 }
715
716 if (authorization != NULL) {
717 AuthorizationFree(authorization, kAuthorizationFlagDefaults);
718 // AuthorizationFree(authorization, kAuthorizationFlagDestroyRights);
719 }
720
721 exit(err);
722 }