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