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