]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCPreferencesKeychainPrivate.c
configd-699.1.5.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCPreferencesKeychainPrivate.c
1 /*
2 * Copyright (c) 2006, 2007, 2010, 2014 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 SecKeychainRef keychain = NULL;
256 OSStatus status;
257
258 status = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, &keychain);
259 if (status != noErr) {
260 _SCErrorSet(status);
261 if (keychain != NULL) CFRelease(keychain);
262 return NULL;
263 }
264
265 return keychain;
266 #else // !TARGET_OS_IPHONE
267 _SCErrorSet(kSCStatusAccessError);
268 return NULL;
269 #endif // !TARGET_OS_IPHONE
270 }
271
272
273 #if !TARGET_OS_IPHONE
274 static OSStatus
275 findKeychainItem(SecKeychainRef keychain,
276 CFStringRef unique_id,
277 SecKeychainItemRef *item)
278 {
279 CFMutableDictionaryRef query;
280 OSStatus status;
281
282 query = CFDictionaryCreateMutable(NULL,
283 0,
284 &kCFTypeDictionaryKeyCallBacks,
285 &kCFTypeDictionaryValueCallBacks);
286 if (keychain != NULL) {
287 CFArrayRef keychains;
288
289 keychains = CFArrayCreate(NULL, (const void **)&keychain, 1, &kCFTypeArrayCallBacks);
290 CFDictionarySetValue(query, kSecMatchSearchList, keychains);
291 CFRelease(keychains);
292 }
293 CFDictionarySetValue(query, kSecClass , kSecClassGenericPassword);
294 CFDictionarySetValue(query, kSecAttrService, unique_id);
295 CFDictionarySetValue(query, kSecReturnRef , kCFBooleanTrue);
296 status = SecItemCopyMatching(query, (CFTypeRef *)item);
297 CFRelease(query);
298
299 return status;
300 }
301 #endif // !TARGET_OS_IPHONE
302
303
304 CFDataRef
305 _SCSecKeychainPasswordItemCopy(SecKeychainRef keychain,
306 CFStringRef unique_id)
307 {
308 #if !TARGET_OS_IPHONE
309 SecKeychainItemRef item = NULL;
310 CFDataRef keychain_password = NULL;
311 OSStatus status;
312
313 status = findKeychainItem(keychain, unique_id, &item);
314 if (status == noErr) {
315 void * pw = NULL;
316 UInt32 pw_len = 0;
317
318 status = SecKeychainItemCopyContent(item, NULL, NULL, &pw_len, &pw);
319 if (status == noErr) {
320 keychain_password = CFDataCreate(NULL, pw, pw_len);
321 status = SecKeychainItemFreeContent(NULL, pw);
322 }
323 }
324 if (item != NULL) CFRelease(item);
325 if (status != noErr) {
326 _SCErrorSet(status);
327 }
328
329 return keychain_password;
330 #else // !TARGET_OS_IPHONE
331 _SCErrorSet(kSCStatusAccessError);
332 return NULL;
333 #endif // !TARGET_OS_IPHONE
334 }
335
336
337 Boolean
338 _SCSecKeychainPasswordItemExists(SecKeychainRef keychain, CFStringRef unique_id)
339 {
340 #if !TARGET_OS_IPHONE
341 SecKeychainItemRef item;
342 OSStatus status;
343
344 status = findKeychainItem(keychain, unique_id, &item);
345 if (status != noErr) {
346 _SCErrorSet(status);
347 return FALSE;
348 }
349
350 CFRelease(item);
351 return TRUE;
352 #else // !TARGET_OS_IPHONE
353 _SCErrorSet(kSCStatusAccessError);
354 return FALSE;
355 #endif // !TARGET_OS_IPHONE
356 }
357
358
359 Boolean
360 _SCSecKeychainPasswordItemRemove(SecKeychainRef keychain, CFStringRef unique_id)
361 {
362 #if !TARGET_OS_IPHONE
363 SecKeychainItemRef item;
364 OSStatus status;
365
366 status = findKeychainItem(keychain, unique_id, &item);
367 if (status != noErr) {
368 _SCErrorSet(status);
369 return FALSE;
370 }
371
372 status = SecKeychainItemDelete(item);
373 CFRelease(item);
374 if (status != noErr) {
375 _SCErrorSet(status);
376 return FALSE;
377 }
378
379 return TRUE;
380 #else // !TARGET_OS_IPHONE
381 _SCErrorSet(kSCStatusAccessError);
382 return FALSE;
383 #endif // !TARGET_OS_IPHONE
384 }
385
386
387 Boolean
388 _SCSecKeychainPasswordItemSet(SecKeychainRef keychain,
389 CFStringRef unique_id,
390 CFStringRef label,
391 CFStringRef description,
392 CFStringRef account,
393 CFDataRef password,
394 CFDictionaryRef options)
395 {
396 #if !TARGET_OS_IPHONE
397 SecAccessRef access = NULL;
398 CFBooleanRef allowRoot = NULL;
399 CFArrayRef allowedExecutables = NULL;
400 SecKeychainAttribute attributes[4];
401 SecKeychainAttributeList attributeList = { 0, attributes };
402 CFIndex i;
403 SecKeychainItemRef item = NULL;
404 CFIndex n = 0;
405 OSStatus status;
406
407 if (options != NULL) {
408 if (isA_CFDictionary(options)) {
409 allowRoot = CFDictionaryGetValue(options, kSCKeychainOptionsAllowRoot);
410 allowedExecutables = CFDictionaryGetValue(options, kSCKeychainOptionsAllowedExecutables);
411 } else {
412 _SCErrorSet(kSCStatusInvalidArgument);
413 return FALSE;
414 }
415 }
416
417 if (!isA_CFString(unique_id) ||
418 ((label != NULL) && !isA_CFString (label )) ||
419 ((description != NULL) && !isA_CFString (description )) ||
420 ((account != NULL) && !isA_CFString (account )) ||
421 ((password != NULL) && !isA_CFData (password )) ||
422 ((allowRoot != NULL) && !isA_CFBoolean(allowRoot )) ||
423 ((allowedExecutables != NULL) && !isA_CFArray (allowedExecutables)) ||
424 ((allowRoot != NULL) && (allowedExecutables != NULL))) {
425 _SCErrorSet(kSCStatusInvalidArgument);
426 return FALSE;
427 }
428
429 if ((allowRoot != NULL) && CFBooleanGetValue(allowRoot)) {
430 #if (__MAC_OS_X_VERSION_MIN_REQUIRED < 1070)
431 access = _SCSecAccessCreateForUID(0);
432 if (access == NULL) {
433 return FALSE;
434 }
435 #else // (__MAC_OS_X_VERSION_MIN_REQUIRED < 1070)
436 CFErrorRef error = NULL;
437
438 access = SecAccessCreateWithOwnerAndACL(0, 0, kSecUseOnlyUID, NULL, &error);
439 if (access == NULL) {
440 CFIndex code = kSCStatusAccessError;
441
442 if (error != NULL) {
443
444 code = CFErrorGetCode(error);
445 CFRelease(error);
446 }
447 _SCErrorSet((int)code);
448 return FALSE;
449 }
450 #endif // (__MAC_OS_X_VERSION_MIN_REQUIRED < 1070)
451 } else if (allowedExecutables != NULL) {
452 access = _SCSecAccessCreateForExecutables(label, allowedExecutables);
453 if (access == NULL) {
454 return FALSE;
455 }
456 }
457
458 for (i = 0; i < 4; i++) {
459 CFStringRef str = NULL;
460 SecKeychainAttrType tag = 0;
461
462 switch (i) {
463 case 0 :
464 str = unique_id;
465 tag = kSecServiceItemAttr;
466 break;
467 case 1 :
468 str = label;
469 tag = kSecLabelItemAttr;
470 break;
471 case 2 :
472 str = description;
473 tag = kSecDescriptionItemAttr;
474 break;
475 case 3 :
476 str = account;
477 tag = kSecAccountItemAttr;
478 break;
479 }
480
481 if (str == NULL) {
482 continue;
483 }
484
485 attributes[n].tag = tag;
486 attributes[n].data = _SC_cfstring_to_cstring(str, NULL, 0, kCFStringEncodingUTF8);
487 attributes[n].length = (UInt32)strlen(attributes[n].data);
488 n++;
489 }
490
491 status = findKeychainItem(keychain, unique_id, &item);
492 switch (status) {
493 case noErr : {
494 const void *pw = NULL;
495 UInt32 pw_len = 0;
496
497 // keychain item exists
498 if (password != NULL) {
499 pw = CFDataGetBytePtr(password);
500 pw_len = (UInt32)CFDataGetLength(password);
501 }
502
503 attributeList.count = (UInt32)n;
504 status = SecKeychainItemModifyContent(item,
505 &attributeList,
506 pw_len,
507 pw);
508 break;
509 }
510
511 case errSecItemNotFound : {
512 // no keychain item
513 if (password == NULL) {
514 // creating new keychain item and password not specified
515 status = kSCStatusInvalidArgument;
516 goto done;
517 }
518
519 attributeList.count = (UInt32)n;
520 status = SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass,
521 &attributeList,
522 (UInt32)CFDataGetLength(password),
523 CFDataGetBytePtr(password),
524 keychain,
525 access,
526 NULL);
527 break;
528 }
529
530 // some other error
531 default :
532 break;
533 }
534
535 done :
536
537 if (access != NULL) CFRelease(access);
538 if (item != NULL) CFRelease(item);
539
540 for (i = 0; i < n; i++) {
541 CFAllocatorDeallocate(NULL, attributes[i].data);
542 }
543
544 if (status != noErr) {
545 _SCErrorSet(status);
546 return FALSE;
547 }
548
549 return TRUE;
550 #else // !TARGET_OS_IPHONE
551 _SCErrorSet(kSCStatusAccessError);
552 return FALSE;
553 #endif // !TARGET_OS_IPHONE
554 }
555
556
557 #pragma mark -
558 #pragma mark "System" Keychain APIs (w/SCPreferences)
559
560
561 #include "SCHelper_client.h"
562
563 #include <fcntl.h>
564 #include <unistd.h>
565 #include <sys/errno.h>
566
567
568 #if !TARGET_OS_IPHONE
569 static CFDataRef
570 __SCPreferencesSystemKeychainPasswordItemCopy_helper(SCPreferencesRef prefs,
571 CFStringRef unique_id)
572 {
573 CFDataRef data = NULL;
574 Boolean ok;
575 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
576 uint32_t status = kSCStatusOK;
577 CFDataRef reply = NULL;
578
579 if (prefsPrivate->helper_port == MACH_PORT_NULL) {
580 ok = __SCPreferencesCreate_helper(prefs);
581 if (!ok) {
582 return FALSE;
583 }
584 }
585
586 ok = _SCSerializeString(unique_id, &data, NULL, NULL);
587 if (!ok) {
588 goto fail;
589 }
590
591 // have the helper set the "System" Keychain password
592 ok = _SCHelperExec(prefsPrivate->helper_port,
593 SCHELPER_MSG_KEYCHAIN_COPY,
594 data,
595 &status,
596 &reply);
597 if (data != NULL) CFRelease(data);
598 if (!ok) {
599 goto fail;
600 }
601
602 if (status != kSCStatusOK) {
603 goto error;
604 }
605
606 return reply;
607
608 fail :
609
610 // close helper
611 if (prefsPrivate->helper_port != MACH_PORT_NULL) {
612 _SCHelperClose(&prefsPrivate->helper_port);
613 }
614
615 status = kSCStatusAccessError;
616
617 error :
618
619 // return error
620 if (reply != NULL) CFRelease(reply);
621 _SCErrorSet(status);
622 return NULL;
623 }
624 #endif // !TARGET_OS_IPHONE
625
626
627 CFDataRef
628 _SCPreferencesSystemKeychainPasswordItemCopy(SCPreferencesRef prefs,
629 CFStringRef unique_id)
630 {
631 #if !TARGET_OS_IPHONE
632 SecKeychainRef keychain = NULL;
633 CFDataRef password = NULL;
634 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
635
636 if (prefs == NULL) {
637 /* sorry, you must provide a session */
638 _SCErrorSet(kSCStatusNoPrefsSession);
639 return NULL;
640 }
641
642 if (!isA_CFString(unique_id)) {
643 _SCErrorSet(kSCStatusInvalidArgument);
644 return NULL;
645 }
646
647 if (prefsPrivate->authorizationData != NULL) {
648 password = __SCPreferencesSystemKeychainPasswordItemCopy_helper(prefs, unique_id);
649 goto done;
650 }
651
652 keychain = _SCSecKeychainCopySystemKeychain();
653 if (keychain == NULL) {
654 goto done;
655 }
656
657 password = _SCSecKeychainPasswordItemCopy(keychain, unique_id);
658
659 done :
660
661 if (keychain != NULL) CFRelease(keychain);
662 return password;
663 #else // !TARGET_OS_IPHONE
664 _SCErrorSet(kSCStatusAccessError);
665 return NULL;
666 #endif // !TARGET_OS_IPHONE
667 }
668
669
670 Boolean
671 _SCPreferencesSystemKeychainPasswordItemExists(SCPreferencesRef prefs,
672 CFStringRef unique_id)
673 {
674 #if !TARGET_OS_IPHONE
675 SecKeychainRef keychain = NULL;
676 Boolean ok = FALSE;
677 // SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
678
679 if (prefs == NULL) {
680 /* sorry, you must provide a session */
681 _SCErrorSet(kSCStatusNoPrefsSession);
682 return FALSE;
683 }
684
685 if (!isA_CFString(unique_id)) {
686 _SCErrorSet(kSCStatusInvalidArgument);
687 return FALSE;
688 }
689
690 // if (prefsPrivate->authorizationData != NULL) {
691 // ok = __SCPreferencesSystemKeychainPasswordItemExists_helper(prefs, unique_id);
692 // goto done;
693 // }
694
695 keychain = _SCSecKeychainCopySystemKeychain();
696 if (keychain == NULL) {
697 goto done;
698 }
699
700 ok = _SCSecKeychainPasswordItemExists(keychain, unique_id);
701
702 done :
703
704 if (keychain != NULL) CFRelease(keychain);
705 return ok;
706 #else // !TARGET_OS_IPHONE
707 _SCErrorSet(kSCStatusAccessError);
708 return FALSE;
709 #endif // !TARGET_OS_IPHONE
710 }
711
712
713 #if !TARGET_OS_IPHONE
714 static Boolean
715 __SCPreferencesSystemKeychainPasswordItemRemove_helper(SCPreferencesRef prefs,
716 CFStringRef unique_id)
717 {
718 CFDataRef data = NULL;
719 Boolean ok;
720 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
721 uint32_t status = kSCStatusOK;
722 CFDataRef reply = NULL;
723
724 if (prefsPrivate->helper_port == MACH_PORT_NULL) {
725 ok = __SCPreferencesCreate_helper(prefs);
726 if (!ok) {
727 return FALSE;
728 }
729 }
730
731 ok = _SCSerializeString(unique_id, &data, NULL, NULL);
732 if (!ok) {
733 goto fail;
734 }
735
736 // have the helper set the "System" Keychain password
737 ok = _SCHelperExec(prefsPrivate->helper_port,
738 SCHELPER_MSG_KEYCHAIN_REMOVE,
739 data,
740 &status,
741 &reply);
742 if (data != NULL) CFRelease(data);
743 if (!ok) {
744 goto fail;
745 }
746
747 if (status != kSCStatusOK) {
748 goto error;
749 }
750
751 return TRUE;
752
753 fail :
754
755 // close helper
756 if (prefsPrivate->helper_port != MACH_PORT_NULL) {
757 _SCHelperClose(&prefsPrivate->helper_port);
758 }
759
760 status = kSCStatusAccessError;
761
762 error :
763
764 // return error
765 if (reply != NULL) CFRelease(reply);
766 _SCErrorSet(status);
767 return FALSE;
768 }
769 #endif // !TARGET_OS_IPHONE
770
771
772 Boolean
773 _SCPreferencesSystemKeychainPasswordItemRemove(SCPreferencesRef prefs,
774 CFStringRef unique_id)
775 {
776 #if !TARGET_OS_IPHONE
777 SecKeychainRef keychain = NULL;
778 Boolean ok = FALSE;
779 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
780
781 if (prefs == NULL) {
782 /* sorry, you must provide a session */
783 _SCErrorSet(kSCStatusNoPrefsSession);
784 return FALSE;
785 }
786
787 if (!isA_CFString(unique_id)) {
788 _SCErrorSet(kSCStatusInvalidArgument);
789 return FALSE;
790 }
791
792 if (prefsPrivate->authorizationData != NULL) {
793 ok = __SCPreferencesSystemKeychainPasswordItemRemove_helper(prefs, unique_id);
794 goto done;
795 }
796
797 keychain = _SCSecKeychainCopySystemKeychain();
798 if (keychain == NULL) {
799 goto done;
800 }
801
802 ok = _SCSecKeychainPasswordItemRemove(keychain, unique_id);
803
804 done :
805
806 if (keychain != NULL) CFRelease(keychain);
807 return ok;
808 #else // !TARGET_OS_IPHONE
809 _SCErrorSet(kSCStatusAccessError);
810 return FALSE;
811 #endif // !TARGET_OS_IPHONE
812 }
813
814
815 #if !TARGET_OS_IPHONE
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_port == MACH_PORT_NULL) {
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_port,
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_port != MACH_PORT_NULL) {
938 _SCHelperClose(&prefsPrivate->helper_port);
939 }
940
941 status = kSCStatusAccessError;
942
943 error :
944
945 // return error
946 if (reply != NULL) CFRelease(reply);
947 _SCErrorSet(status);
948 return FALSE;
949 }
950 #endif // !TARGET_OS_IPHONE
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 #if !TARGET_OS_IPHONE
963 SecKeychainRef keychain = NULL;
964 Boolean ok = FALSE;
965 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
966
967 if (prefs == NULL) {
968 /* sorry, you must provide a session */
969 _SCErrorSet(kSCStatusNoPrefsSession);
970 return FALSE;
971 }
972
973 if (!isA_CFString(unique_id) ||
974 ((label != NULL) && !isA_CFString (label )) ||
975 ((description != NULL) && !isA_CFString (description)) ||
976 ((account != NULL) && !isA_CFString (account )) ||
977 ((password != NULL) && !isA_CFData (password )) ||
978 ((options != NULL) && !isA_CFDictionary(options ))) {
979 _SCErrorSet(kSCStatusInvalidArgument);
980 return FALSE;
981 }
982
983 if (prefsPrivate->authorizationData != NULL) {
984 ok = __SCPreferencesSystemKeychainPasswordItemSet_helper(prefs,
985 unique_id,
986 label,
987 description,
988 account,
989 password,
990 options);
991 goto done;
992 }
993
994 keychain = _SCSecKeychainCopySystemKeychain();
995 if (keychain == NULL) {
996 goto done;
997 }
998
999 ok = _SCSecKeychainPasswordItemSet(keychain,
1000 unique_id,
1001 label,
1002 description,
1003 account,
1004 password,
1005 options);
1006
1007 done :
1008
1009 if (keychain != NULL) CFRelease(keychain);
1010 return ok;
1011 #else // !TARGET_OS_IPHONE
1012 _SCErrorSet(kSCStatusAccessError);
1013 return FALSE;
1014 #endif // !TARGET_OS_IPHONE
1015 }