]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCPreferencesKeychainPrivate.c
configd-204.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCPreferencesKeychainPrivate.c
1 /*
2 * Copyright (c) 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 /*
25 * Modification History
26 *
27 * May 24, 2006 Allan Nathanson (ajn@apple.com)
28 * - adapted (for SystemConfiguration)
29 *
30 * May 10, 2006 Dieter Siegmund (dieter@apple.com)
31 * - created (for EAP)
32 */
33
34 #include <sys/param.h>
35
36 #include <CoreFoundation/CoreFoundation.h>
37 #include <CoreFoundation/CFBundlePriv.h> // for _CFBundleCopyMainBundleExecutableURL
38 #include <SystemConfiguration/SCPrivate.h> // for _SCErrorSet
39 #include <Security/Security.h>
40 #include "dy_framework.h"
41
42 #include "SCPreferencesInternal.h"
43
44
45 static CFDataRef
46 copyMyExecutablePath(void)
47 {
48 char fspath[MAXPATHLEN];
49 Boolean isBundle = FALSE;
50 Boolean ok;
51 CFDataRef path = NULL;
52 CFURLRef url;
53
54 url = _CFBundleCopyMainBundleExecutableURL(&isBundle);
55 if (url == NULL) {
56 return NULL;
57 }
58
59 ok = CFURLGetFileSystemRepresentation(url, TRUE, (UInt8 *)fspath, sizeof(fspath));
60 CFRelease(url);
61 if (!ok) {
62 return NULL;
63 }
64 fspath[sizeof(fspath) - 1] = '\0';
65
66 if (isBundle) {
67 const char *slash;
68
69 slash = strrchr(fspath, '/');
70 if (slash != NULL) {
71 const char *contents;
72
73 contents = strstr(fspath, "/Contents/MacOS/");
74 if ((contents != NULL) &&
75 ((contents + sizeof("/Contents/MacOS/") - 1) == slash)) {
76 path = CFDataCreate(NULL, (UInt8 *)fspath, contents - fspath);
77 goto done;
78 }
79 }
80 }
81
82 path = CFDataCreate(NULL, (UInt8 *)fspath, strlen(fspath));
83
84 done :
85
86 return path;
87 }
88
89
90 #pragma mark -
91 #pragma mark Keychain helper APIs
92
93
94 /*
95 * Create a SecAccessRef with a custom form.
96 *
97 * Both the owner and the ACL set allow free access to root,
98 * but nothing to anyone else.
99 *
100 * NOTE: This is not the easiest way to build up CSSM data structures
101 * but it is a way that does not depend on any outside software
102 * layers (other than CSSM and Security's Sec* layer, of course).
103 */
104 static SecAccessRef
105 _SCSecAccessCreateForUID(uid_t uid)
106 {
107 SecAccessRef access = NULL;
108 OSStatus status;
109
110 // make the "uid/gid" ACL subject
111 // this is a CSSM_LIST_ELEMENT chain
112
113 CSSM_ACL_PROCESS_SUBJECT_SELECTOR selector = {
114 CSSM_ACL_PROCESS_SELECTOR_CURRENT_VERSION, // version
115 CSSM_ACL_MATCH_UID, // active fields mask: match uids (only)
116 uid, // effective user id to match
117 0 // effective group id to match
118 };
119
120 CSSM_LIST_ELEMENT subject2 = {
121 NULL, // NextElement
122 0 // WordID
123 // rest is defaulted
124 };
125
126 subject2.Element.Word.Data = (UInt8 *)&selector;
127 subject2.Element.Word.Length = sizeof(selector);
128
129 CSSM_LIST_ELEMENT subject1 = {
130 &subject2, // NextElement
131 CSSM_ACL_SUBJECT_TYPE_PROCESS, // WordID
132 CSSM_LIST_ELEMENT_WORDID // ElementType
133 // rest is defaulted
134 };
135
136 // rights granted (replace with individual list if desired)
137 CSSM_ACL_AUTHORIZATION_TAG rights[] = {
138 CSSM_ACL_AUTHORIZATION_ANY // everything
139 };
140
141 // owner component (right to change ACL)
142 CSSM_ACL_OWNER_PROTOTYPE owner = {
143 { // TypedSubject
144 CSSM_LIST_TYPE_UNKNOWN, // type of this list
145 &subject1, // head of the list
146 &subject2 // tail of the list
147 },
148 FALSE // Delegate
149 };
150
151 // ACL entries (any number, just one here)
152 CSSM_ACL_ENTRY_INFO acls[] = {
153 {
154 { // EntryPublicInfo
155 { // TypedSubject
156 CSSM_LIST_TYPE_UNKNOWN, // type of this list
157 &subject1, // head of the list
158 &subject2 // tail of the list
159 },
160 FALSE, // Delegate
161 { // Authorization
162 sizeof(rights) / sizeof(rights[0]), // NumberOfAuthTags
163 rights // AuthTags
164 },
165 { // TimeRange
166 },
167 { // EntryTag
168 }
169 },
170 0 // EntryHandle
171 }
172 };
173
174 status = SecAccessCreateFromOwnerAndACL(&owner,
175 sizeof(acls) / sizeof(acls[0]),
176 acls,
177 &access);
178 if (status != noErr) {
179 _SCErrorSet(status);
180 }
181
182 return access;
183 }
184
185
186 // one example would be to pass a URL for "/System/Library/CoreServices/SystemUIServer.app"
187 static SecAccessRef
188 _SCSecAccessCreateForExecutables(CFStringRef label,
189 CFArrayRef executableURLs)
190 {
191 SecAccessRef access = NULL;
192 CFArrayRef aclList = NULL;
193 CFIndex i;
194 CFIndex n;
195 OSStatus status;
196 SecTrustedApplicationRef trustedApplication;
197 CFMutableArrayRef trustedApplications;
198
199 trustedApplications = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
200
201 // Use default access ("confirm access")
202
203 // Next, we make an exception list of applications you want to trust.
204 // These applications will be allowed to access the item without requiring
205 // user confirmation.
206
207 // Trust the calling application
208 status = SecTrustedApplicationCreateFromPath(NULL, &trustedApplication);
209 if (status == noErr) {
210 CFArrayAppendValue(trustedApplications, trustedApplication);
211 CFRelease(trustedApplication);
212 }
213
214 n = (executableURLs != NULL) ? CFArrayGetCount(executableURLs) : 0;
215 for (i = 0; i < n; i++) {
216 Boolean ok;
217 char path[MAXPATHLEN];
218 CFURLRef url;
219
220 url = CFArrayGetValueAtIndex(executableURLs, i);
221 ok = CFURLGetFileSystemRepresentation(url, TRUE, (UInt8 *)path, sizeof(path));
222 if (!ok) {
223 continue;
224 }
225
226 status = SecTrustedApplicationCreateFromPath(path, &trustedApplication);
227 if (status == noErr) {
228 CFArrayAppendValue(trustedApplications, trustedApplication);
229 CFRelease(trustedApplication);
230 }
231 }
232
233 status = SecAccessCreate(label, trustedApplications, &access);
234 if (status != noErr) {
235 goto done;
236 }
237
238 #ifdef NOT_NEEDED
239 // get the access control list for decryption operations (this controls access to an item's data)
240 status = SecAccessCopySelectedACLList(access, CSSM_ACL_AUTHORIZATION_DECRYPT, &aclList);
241 if (status == noErr) {
242 SecACLRef acl;
243 CFArrayRef applicationList = NULL;
244 CFStringRef description = NULL;
245 CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector;
246
247 // get the first entry in the access control list
248 acl = (SecACLRef)CFArrayGetValueAtIndex(aclList, 0);
249
250 // get the description and prompt selector
251 status = SecACLCopySimpleContents(acl, &applicationList, &description, &promptSelector);
252
253 // modify the application list
254 status = SecACLSetSimpleContents(acl, (CFArrayRef)trustedApplications, description, &promptSelector);
255
256 if (applicationList != NULL) CFRelease(applicationList);
257 if (description != NULL) CFRelease(description);
258 }
259 #endif // NOT_NEEDED
260
261 done :
262
263 if (aclList != NULL) CFRelease(aclList);
264 CFRelease(trustedApplications);
265
266 return access;
267 }
268
269
270 SecKeychainRef
271 _SCSecKeychainCopySystemKeychain(void)
272 {
273 SecPreferencesDomain domain;
274 SecKeychainRef keychain = NULL;
275 OSStatus status;
276
277 status = SecKeychainGetPreferenceDomain(&domain);
278 if (status != noErr) {
279 _SCErrorSet(status);
280 return NULL;
281 }
282
283 status = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
284 if (status != noErr) {
285 _SCErrorSet(status);
286 return NULL;
287 }
288
289 status = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, &keychain);
290 if (status != noErr) {
291 _SCErrorSet(status);
292 (void) SecKeychainSetPreferenceDomain(domain);
293 if (keychain != NULL) CFRelease(keychain);
294 return NULL;
295 }
296
297 status = SecKeychainSetPreferenceDomain(domain);
298 if (status != noErr) {
299 _SCErrorSet(status);
300 if (keychain != NULL) CFRelease(keychain);
301 return NULL;
302 }
303
304 return keychain;
305 }
306
307
308 static OSStatus
309 findKeychainItem(SecKeychainRef keychain,
310 UInt32 serviceNameLength,
311 void *serviceName,
312 SecKeychainItemRef *item)
313 {
314 SecKeychainAttribute attributes[1];
315 SecKeychainAttributeList attributeList = { 1, attributes };
316 SecKeychainSearchRef search = NULL;
317 OSStatus status;
318
319 attributes[0].tag = kSecServiceItemAttr;
320 attributes[0].data = serviceName;
321 attributes[0].length = serviceNameLength;
322
323 status = SecKeychainSearchCreateFromAttributes(keychain,
324 kSecGenericPasswordItemClass,
325 &attributeList,
326 &search);
327 if (status != noErr) {
328 return status;
329 }
330
331 status = SecKeychainSearchCopyNext(search, item);
332 CFRelease(search);
333
334 return status;
335 }
336
337
338 CFDataRef
339 _SCSecKeychainPasswordItemCopy(SecKeychainRef keychain,
340 CFStringRef unique_id)
341 {
342 SecKeychainItemRef item = NULL;
343 CFDataRef keychain_password = NULL;
344 const char *keychain_serviceName;
345 OSStatus status;
346
347 keychain_serviceName = _SC_cfstring_to_cstring(unique_id, NULL, 0, kCFStringEncodingUTF8);
348 status = findKeychainItem(keychain,
349 strlen(keychain_serviceName),
350 (void *)keychain_serviceName,
351 &item);
352 CFAllocatorDeallocate(NULL, (void *)keychain_serviceName);
353 if (status == noErr) {
354 void * pw = NULL;
355 UInt32 pw_len = 0;
356
357 status = SecKeychainItemCopyContent(item, NULL, NULL, &pw_len, &pw);
358 if (status == noErr) {
359 keychain_password = CFDataCreate(NULL, pw, pw_len);
360 status = SecKeychainItemFreeContent(NULL, pw);
361 }
362 }
363 if (item != NULL) CFRelease(item);
364 if (status != noErr) {
365 _SCErrorSet(status);
366 }
367
368 return keychain_password;
369 }
370
371
372 Boolean
373 _SCSecKeychainPasswordItemExists(SecKeychainRef keychain, CFStringRef unique_id)
374 {
375 SecKeychainItemRef item;
376 const char *keychain_serviceName;
377 OSStatus status;
378
379 keychain_serviceName = _SC_cfstring_to_cstring(unique_id, NULL, 0, kCFStringEncodingUTF8);
380 status = findKeychainItem(keychain,
381 strlen(keychain_serviceName),
382 (void *)keychain_serviceName,
383 &item);
384 CFAllocatorDeallocate(NULL, (void *)keychain_serviceName);
385 if (status != noErr) {
386 _SCErrorSet(status);
387 return FALSE;
388 }
389
390 CFRelease(item);
391 return TRUE;
392 }
393
394
395 Boolean
396 _SCSecKeychainPasswordItemRemove(SecKeychainRef keychain, CFStringRef unique_id)
397 {
398 SecKeychainItemRef item;
399 const char *keychain_serviceName;
400 OSStatus status;
401
402 keychain_serviceName = _SC_cfstring_to_cstring(unique_id, NULL, 0, kCFStringEncodingUTF8);
403 status = findKeychainItem(keychain,
404 strlen(keychain_serviceName),
405 (void *)keychain_serviceName,
406 &item);
407 CFAllocatorDeallocate(NULL, (void *)keychain_serviceName);
408 if (status != noErr) {
409 _SCErrorSet(status);
410 return FALSE;
411 }
412
413 status = SecKeychainItemDelete(item);
414 CFRelease(item);
415 if (status != noErr) {
416 _SCErrorSet(status);
417 return FALSE;
418 }
419
420 return TRUE;
421 }
422
423
424 Boolean
425 _SCSecKeychainPasswordItemSet(SecKeychainRef keychain,
426 CFStringRef unique_id,
427 CFStringRef label,
428 CFStringRef description,
429 CFStringRef account,
430 CFDataRef password,
431 CFDictionaryRef options)
432 {
433 SecAccessRef access = NULL;
434 CFBooleanRef allowRoot = NULL;
435 CFArrayRef allowedExecutables = NULL;
436 SecKeychainAttribute attributes[4];
437 SecKeychainAttributeList attributeList = { 0, attributes };
438 CFIndex i;
439 SecKeychainItemRef item = NULL;
440 CFIndex n = 0;
441 OSStatus status;
442
443 if (options != NULL) {
444 if (isA_CFDictionary(options)) {
445 allowRoot = CFDictionaryGetValue(options, kSCKeychainOptionsAllowRoot);
446 allowedExecutables = CFDictionaryGetValue(options, kSCKeychainOptionsAllowedExecutables);
447 } else {
448 _SCErrorSet(kSCStatusInvalidArgument);
449 return FALSE;
450 }
451 }
452
453 if (!isA_CFString(unique_id) ||
454 ((label != NULL) && !isA_CFString (label )) ||
455 ((description != NULL) && !isA_CFString (description )) ||
456 ((account != NULL) && !isA_CFString (account )) ||
457 ((password != NULL) && !isA_CFData (password )) ||
458 ((allowRoot != NULL) && !isA_CFBoolean(allowRoot )) ||
459 ((allowedExecutables != NULL) && !isA_CFArray (allowedExecutables)) ||
460 ((allowRoot != NULL) && (allowedExecutables != NULL))) {
461 _SCErrorSet(kSCStatusInvalidArgument);
462 return FALSE;
463 }
464
465 if ((allowRoot != NULL) && CFBooleanGetValue(allowRoot)) {
466 access = _SCSecAccessCreateForUID(0);
467 if (access == NULL) {
468 return FALSE;
469 }
470 } else if (allowedExecutables != NULL) {
471 access = _SCSecAccessCreateForExecutables(label, allowedExecutables);
472 if (access == NULL) {
473 return FALSE;
474 }
475 }
476
477 for (i = 0; i < 4; i++) {
478 CFStringRef str = NULL;
479 SecKeychainAttrType tag = 0;
480
481 switch (i) {
482 case 0 :
483 str = unique_id;
484 tag = kSecServiceItemAttr;
485 break;
486 case 1 :
487 str = label;
488 tag = kSecLabelItemAttr;
489 break;
490 case 2 :
491 str = description;
492 tag = kSecDescriptionItemAttr;
493 break;
494 case 3 :
495 str = account;
496 tag = kSecAccountItemAttr;
497 break;
498 }
499
500 if (str == NULL) {
501 continue;
502 }
503
504 attributes[n].tag = tag;
505 attributes[n].data = _SC_cfstring_to_cstring(str, NULL, 0, kCFStringEncodingUTF8);
506 attributes[n].length = strlen(attributes[n].data);
507 n++;
508 }
509
510 status = findKeychainItem(keychain,
511 attributes[0].length,
512 attributes[0].data,
513 &item);
514 switch (status) {
515 case noErr : {
516 const void *pw = NULL;
517 UInt32 pw_len = 0;
518
519 // keychain item exists
520 if (password != NULL) {
521 pw = CFDataGetBytePtr(password);
522 pw_len = CFDataGetLength(password);
523 }
524
525 attributeList.count = n;
526 status = SecKeychainItemModifyContent(item,
527 &attributeList,
528 pw_len,
529 pw);
530 break;
531 }
532
533 case errSecItemNotFound : {
534 // no keychain item
535 if (password == NULL) {
536 // creating new keychain item and password not specified
537 status = kSCStatusInvalidArgument;
538 goto done;
539 }
540
541 attributeList.count = n;
542 status = SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass,
543 &attributeList,
544 CFDataGetLength(password),
545 CFDataGetBytePtr(password),
546 keychain,
547 access,
548 NULL);
549 break;
550 }
551
552 // some other error
553 default :
554 break;
555 }
556
557 done :
558
559 if (access != NULL) CFRelease(access);
560 if (item != NULL) CFRelease(item);
561
562 for (i = 0; i < n; i++) {
563 CFAllocatorDeallocate(NULL, attributes[i].data);
564 }
565
566 if (status != noErr) {
567 _SCErrorSet(status);
568 return FALSE;
569 }
570
571 return TRUE;
572 }
573
574
575 #pragma mark -
576 #pragma mark "System" Keychain APIs (w/SCPreferences)
577
578
579 #include "SCHelper_client.h"
580
581 #include <fcntl.h>
582 #include <unistd.h>
583 #include <sys/errno.h>
584
585
586 static CFDataRef
587 __SCPreferencesSystemKeychainPasswordItemCopy_helper(SCPreferencesRef prefs,
588 CFStringRef unique_id)
589 {
590 CFDataRef data = NULL;
591 Boolean ok;
592 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
593 uint32_t status = kSCStatusOK;
594 CFDataRef reply = NULL;
595
596 if (prefsPrivate->helper == -1) {
597 ok = __SCPreferencesCreate_helper(prefs);
598 if (!ok) {
599 return FALSE;
600 }
601 }
602
603 ok = _SCSerializeString(unique_id, &data, NULL, NULL);
604 if (!ok) {
605 goto fail;
606 }
607
608 // have the helper set the "System" Keychain password
609 ok = _SCHelperExec(prefsPrivate->helper,
610 SCHELPER_MSG_KEYCHAIN_COPY,
611 data,
612 &status,
613 &reply);
614 if (data != NULL) CFRelease(data);
615 if (!ok) {
616 goto fail;
617 }
618
619 if (status != kSCStatusOK) {
620 goto error;
621 }
622
623 return reply;
624
625 fail :
626
627 // close helper
628 if (prefsPrivate->helper != -1) {
629 _SCHelperClose(prefsPrivate->helper);
630 prefsPrivate->helper = -1;
631 }
632
633 status = kSCStatusAccessError;
634
635 error :
636
637 // return error
638 if (reply != NULL) CFRelease(reply);
639 _SCErrorSet(status);
640 return NULL;
641 }
642
643
644 CFDataRef
645 _SCPreferencesSystemKeychainPasswordItemCopy(SCPreferencesRef prefs,
646 CFStringRef unique_id)
647 {
648 SecKeychainRef keychain = NULL;
649 CFDataRef password = NULL;
650 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
651
652 if (prefs == NULL) {
653 /* sorry, you must provide a session */
654 _SCErrorSet(kSCStatusNoPrefsSession);
655 return FALSE;
656 }
657
658 if (!isA_CFString(unique_id)) {
659 _SCErrorSet(kSCStatusInvalidArgument);
660 return FALSE;
661 }
662
663 if (prefsPrivate->authorizationData != NULL) {
664 password = __SCPreferencesSystemKeychainPasswordItemCopy_helper(prefs, unique_id);
665 goto done;
666 }
667
668 keychain = _SCSecKeychainCopySystemKeychain();
669 if (keychain == NULL) {
670 goto done;
671 }
672
673 password = _SCSecKeychainPasswordItemCopy(keychain, unique_id);
674
675 done :
676
677 if (keychain != NULL) CFRelease(keychain);
678 return password;
679 }
680
681
682 Boolean
683 _SCPreferencesSystemKeychainPasswordItemExists(SCPreferencesRef prefs,
684 CFStringRef unique_id)
685 {
686 SecKeychainRef keychain = NULL;
687 Boolean ok = FALSE;
688 // SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
689
690 if (prefs == NULL) {
691 /* sorry, you must provide a session */
692 _SCErrorSet(kSCStatusNoPrefsSession);
693 return FALSE;
694 }
695
696 if (!isA_CFString(unique_id)) {
697 _SCErrorSet(kSCStatusInvalidArgument);
698 return FALSE;
699 }
700
701 // if (prefsPrivate->authorizationData != NULL) {
702 // ok = __SCPreferencesSystemKeychainPasswordItemExists_helper(prefs, unique_id);
703 // goto done;
704 // }
705
706 keychain = _SCSecKeychainCopySystemKeychain();
707 if (keychain == NULL) {
708 goto done;
709 }
710
711 ok = _SCSecKeychainPasswordItemExists(keychain, unique_id);
712
713 done :
714
715 if (keychain != NULL) CFRelease(keychain);
716 return ok;
717 }
718
719
720 static Boolean
721 __SCPreferencesSystemKeychainPasswordItemRemove_helper(SCPreferencesRef prefs,
722 CFStringRef unique_id)
723 {
724 CFDataRef data = NULL;
725 Boolean ok;
726 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
727 uint32_t status = kSCStatusOK;
728 CFDataRef reply = NULL;
729
730 if (prefsPrivate->helper == -1) {
731 ok = __SCPreferencesCreate_helper(prefs);
732 if (!ok) {
733 return FALSE;
734 }
735 }
736
737 ok = _SCSerializeString(unique_id, &data, NULL, NULL);
738 if (!ok) {
739 goto fail;
740 }
741
742 // have the helper set the "System" Keychain password
743 ok = _SCHelperExec(prefsPrivate->helper,
744 SCHELPER_MSG_KEYCHAIN_REMOVE,
745 data,
746 &status,
747 &reply);
748 if (data != NULL) CFRelease(data);
749 if (!ok) {
750 goto fail;
751 }
752
753 if (status != kSCStatusOK) {
754 goto error;
755 }
756
757 return TRUE;
758
759 fail :
760
761 // close helper
762 if (prefsPrivate->helper != -1) {
763 _SCHelperClose(prefsPrivate->helper);
764 prefsPrivate->helper = -1;
765 }
766
767 status = kSCStatusAccessError;
768
769 error :
770
771 // return error
772 if (reply != NULL) CFRelease(reply);
773 _SCErrorSet(status);
774 return FALSE;
775 }
776
777
778 Boolean
779 _SCPreferencesSystemKeychainPasswordItemRemove(SCPreferencesRef prefs,
780 CFStringRef unique_id)
781 {
782 SecKeychainRef keychain = NULL;
783 Boolean ok = FALSE;
784 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
785
786 if (prefs == NULL) {
787 /* sorry, you must provide a session */
788 _SCErrorSet(kSCStatusNoPrefsSession);
789 return FALSE;
790 }
791
792 if (!isA_CFString(unique_id)) {
793 _SCErrorSet(kSCStatusInvalidArgument);
794 return FALSE;
795 }
796
797 if (prefsPrivate->authorizationData != NULL) {
798 ok = __SCPreferencesSystemKeychainPasswordItemRemove_helper(prefs, unique_id);
799 goto done;
800 }
801
802 keychain = _SCSecKeychainCopySystemKeychain();
803 if (keychain == NULL) {
804 goto done;
805 }
806
807 ok = _SCSecKeychainPasswordItemRemove(keychain, unique_id);
808
809 done :
810
811 if (keychain != NULL) CFRelease(keychain);
812 return ok;
813 }
814
815
816 static Boolean
817 __SCPreferencesSystemKeychainPasswordItemSet_helper(SCPreferencesRef prefs,
818 CFStringRef unique_id,
819 CFStringRef label,
820 CFStringRef description,
821 CFStringRef account,
822 CFDataRef password,
823 CFDictionaryRef options)
824 {
825 CFDataRef data = NULL;
826 CFMutableDictionaryRef newOptions = NULL;
827 Boolean ok;
828 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
829 uint32_t status = kSCStatusOK;
830 CFDataRef reply = NULL;
831
832 if (prefsPrivate->helper == -1) {
833 ok = __SCPreferencesCreate_helper(prefs);
834 if (!ok) {
835 return FALSE;
836 }
837 }
838
839 if (isA_CFDictionary(options)) {
840 CFArrayRef executableURLs = NULL;
841
842 newOptions = CFDictionaryCreateMutableCopy(NULL, 0, options);
843
844 if (CFDictionaryGetValueIfPresent(newOptions,
845 kSCKeychainOptionsAllowedExecutables,
846 (const void **)&executableURLs)) {
847 CFMutableArrayRef executablePaths;
848 CFIndex i;
849 CFIndex n;
850 CFDataRef path;
851
852 executablePaths = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
853
854 path = copyMyExecutablePath();
855 if (path != NULL) {
856 CFArrayAppendValue(executablePaths, path);
857 CFRelease(path);
858 }
859
860 n = CFArrayGetCount(executableURLs);
861 for (i = 0; i < n; i++) {
862 char fspath[MAXPATHLEN];
863 CFURLRef url;
864
865 url = CFArrayGetValueAtIndex(executableURLs, i);
866 ok = CFURLGetFileSystemRepresentation(url, TRUE, (UInt8 *)fspath, sizeof(fspath));
867 if (!ok) {
868 continue;
869 }
870 fspath[sizeof(fspath) - 1] = '\0';
871 path = CFDataCreate(NULL, (UInt8 *)fspath, strlen(fspath));
872 CFArrayAppendValue(executablePaths, path);
873 CFRelease(path);
874 }
875
876 CFDictionarySetValue(newOptions, kSCKeychainOptionsAllowedExecutables, executablePaths);
877 CFRelease(executablePaths);
878 }
879 } else {
880 newOptions = CFDictionaryCreateMutable(NULL,
881 0,
882 &kCFTypeDictionaryKeyCallBacks,
883 &kCFTypeDictionaryValueCallBacks);
884 }
885
886 if (unique_id != NULL) CFDictionarySetValue(newOptions, kSCKeychainOptionsUniqueID , unique_id);
887 if (label != NULL) CFDictionarySetValue(newOptions, kSCKeychainOptionsLabel , label);
888 if (description != NULL) CFDictionarySetValue(newOptions, kSCKeychainOptionsDescription, description);
889 if (account != NULL) CFDictionarySetValue(newOptions, kSCKeychainOptionsAccount , account);
890 if (password != NULL) CFDictionarySetValue(newOptions, kSCKeychainOptionsPassword , password);
891
892 //
893 // if not AllowRoot and a list of executables was not provided than
894 // pass the current executable
895 //
896 if (!CFDictionaryContainsKey(newOptions, kSCKeychainOptionsAllowRoot) &&
897 !CFDictionaryContainsKey(newOptions, kSCKeychainOptionsAllowedExecutables)) {
898 CFDataRef path;
899
900 path = copyMyExecutablePath();
901 if (path != NULL) {
902 CFArrayRef executablePaths;
903
904 executablePaths = CFArrayCreate(NULL, (const void **)&path, 1, &kCFTypeArrayCallBacks);
905 CFRelease(path);
906 CFDictionarySetValue(newOptions, kSCKeychainOptionsAllowedExecutables, executablePaths);
907 CFRelease(executablePaths);
908 }
909 }
910
911 ok = _SCSerialize(newOptions, &data, NULL, NULL);
912 CFRelease(newOptions);
913 if (!ok) {
914 goto fail;
915 }
916
917 // have the helper create the "System" Keychain password
918 ok = _SCHelperExec(prefsPrivate->helper,
919 SCHELPER_MSG_KEYCHAIN_SET,
920 data,
921 &status,
922 &reply);
923 if (data != NULL) CFRelease(data);
924 if (!ok) {
925 goto fail;
926 }
927
928 if (status != kSCStatusOK) {
929 goto error;
930 }
931
932 return TRUE;
933
934 fail :
935
936 // close helper
937 if (prefsPrivate->helper != -1) {
938 _SCHelperClose(prefsPrivate->helper);
939 prefsPrivate->helper = -1;
940 }
941
942 status = kSCStatusAccessError;
943
944 error :
945
946 // return error
947 if (reply != NULL) CFRelease(reply);
948 _SCErrorSet(status);
949 return FALSE;
950 }
951
952
953 Boolean
954 _SCPreferencesSystemKeychainPasswordItemSet(SCPreferencesRef prefs,
955 CFStringRef unique_id,
956 CFStringRef label,
957 CFStringRef description,
958 CFStringRef account,
959 CFDataRef password,
960 CFDictionaryRef options)
961 {
962 SecKeychainRef keychain = NULL;
963 Boolean ok = FALSE;
964 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
965
966 if (prefs == NULL) {
967 /* sorry, you must provide a session */
968 _SCErrorSet(kSCStatusNoPrefsSession);
969 return FALSE;
970 }
971
972 if (!isA_CFString(unique_id) ||
973 ((label != NULL) && !isA_CFString (label )) ||
974 ((description != NULL) && !isA_CFString (description)) ||
975 ((account != NULL) && !isA_CFString (account )) ||
976 ((password != NULL) && !isA_CFData (password )) ||
977 ((options != NULL) && !isA_CFDictionary(options ))) {
978 _SCErrorSet(kSCStatusInvalidArgument);
979 return FALSE;
980 }
981
982 if (prefsPrivate->authorizationData != NULL) {
983 ok = __SCPreferencesSystemKeychainPasswordItemSet_helper(prefs,
984 unique_id,
985 label,
986 description,
987 account,
988 password,
989 options);
990 goto done;
991 }
992
993 keychain = _SCSecKeychainCopySystemKeychain();
994 if (keychain == NULL) {
995 goto done;
996 }
997
998 ok = _SCSecKeychainPasswordItemSet(keychain,
999 unique_id,
1000 label,
1001 description,
1002 account,
1003 password,
1004 options);
1005
1006 done :
1007
1008 if (keychain != NULL) CFRelease(keychain);
1009 return ok;
1010 }