]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCPreferencesKeychainPrivate.c
597051457a680afc187f8093c74b996662851cad
[apple/configd.git] / SystemConfiguration.fproj / SCPreferencesKeychainPrivate.c
1 /*
2 * Copyright (c) 2006, 2007, 2010, 2014, 2016 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 "dy_framework.h"
40
41 #include "SCPreferencesInternal.h"
42
43
44 #if !TARGET_OS_IPHONE
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 #if (__MAC_OS_X_VERSION_MIN_REQUIRED < 1070)
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 #endif // (__MAC_OS_X_VERSION_MIN_REQUIRED < 1070)
186
187
188 // one example would be to pass a URL for "/System/Library/CoreServices/SystemUIServer.app"
189 static SecAccessRef
190 _SCSecAccessCreateForExecutables(CFStringRef label,
191 CFArrayRef executableURLs)
192 {
193 SecAccessRef access = 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 done :
240
241 CFRelease(trustedApplications);
242
243 return access;
244 }
245 #endif // !TARGET_OS_IPHONE
246
247
248 SecKeychainRef
249 _SCSecKeychainCopySystemKeychain(void)
250 {
251 #if !TARGET_OS_IPHONE
252 SecKeychainRef keychain = NULL;
253 OSStatus status;
254
255 status = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, &keychain);
256 if (status != noErr) {
257 _SCErrorSet(status);
258 if (keychain != NULL) CFRelease(keychain);
259 return NULL;
260 }
261
262 return keychain;
263 #else // !TARGET_OS_IPHONE
264 _SCErrorSet(kSCStatusAccessError);
265 return NULL;
266 #endif // !TARGET_OS_IPHONE
267 }
268
269
270 #if !TARGET_OS_IPHONE
271 static OSStatus
272 findKeychainItem(SecKeychainRef keychain,
273 CFStringRef unique_id,
274 SecKeychainItemRef *item)
275 {
276 CFMutableDictionaryRef query;
277 OSStatus status;
278
279 query = CFDictionaryCreateMutable(NULL,
280 0,
281 &kCFTypeDictionaryKeyCallBacks,
282 &kCFTypeDictionaryValueCallBacks);
283 if (keychain != NULL) {
284 CFArrayRef keychains;
285
286 keychains = CFArrayCreate(NULL, (const void **)&keychain, 1, &kCFTypeArrayCallBacks);
287 CFDictionarySetValue(query, kSecMatchSearchList, keychains);
288 CFRelease(keychains);
289 }
290 CFDictionarySetValue(query, kSecClass , kSecClassGenericPassword);
291 CFDictionarySetValue(query, kSecAttrService, unique_id);
292 CFDictionarySetValue(query, kSecReturnRef , kCFBooleanTrue);
293 status = SecItemCopyMatching(query, (CFTypeRef *)item);
294 CFRelease(query);
295
296 return status;
297 }
298 #endif // !TARGET_OS_IPHONE
299
300
301 CFDataRef
302 _SCSecKeychainPasswordItemCopy(SecKeychainRef keychain,
303 CFStringRef unique_id)
304 {
305 #if !TARGET_OS_IPHONE
306 SecKeychainItemRef item = NULL;
307 CFDataRef keychain_password = NULL;
308 OSStatus status;
309
310 status = findKeychainItem(keychain, unique_id, &item);
311 if (status == noErr) {
312 void * pw = NULL;
313 UInt32 pw_len = 0;
314
315 status = SecKeychainItemCopyContent(item, NULL, NULL, &pw_len, &pw);
316 if (status == noErr) {
317 keychain_password = CFDataCreate(NULL, pw, pw_len);
318 status = SecKeychainItemFreeContent(NULL, pw);
319 }
320 }
321 if (item != NULL) CFRelease(item);
322 if (status != noErr) {
323 _SCErrorSet(status);
324 }
325
326 return keychain_password;
327 #else // !TARGET_OS_IPHONE
328 _SCErrorSet(kSCStatusAccessError);
329 return NULL;
330 #endif // !TARGET_OS_IPHONE
331 }
332
333
334 Boolean
335 _SCSecKeychainPasswordItemExists(SecKeychainRef keychain, CFStringRef unique_id)
336 {
337 #if !TARGET_OS_IPHONE
338 SecKeychainItemRef item;
339 OSStatus status;
340
341 status = findKeychainItem(keychain, unique_id, &item);
342 if (status != noErr) {
343 _SCErrorSet(status);
344 return FALSE;
345 }
346
347 CFRelease(item);
348 return TRUE;
349 #else // !TARGET_OS_IPHONE
350 _SCErrorSet(kSCStatusAccessError);
351 return FALSE;
352 #endif // !TARGET_OS_IPHONE
353 }
354
355
356 Boolean
357 _SCSecKeychainPasswordItemRemove(SecKeychainRef keychain, CFStringRef unique_id)
358 {
359 #if !TARGET_OS_IPHONE
360 SecKeychainItemRef item;
361 OSStatus status;
362
363 status = findKeychainItem(keychain, unique_id, &item);
364 if (status != noErr) {
365 _SCErrorSet(status);
366 return FALSE;
367 }
368
369 status = SecKeychainItemDelete(item);
370 CFRelease(item);
371 if (status != noErr) {
372 _SCErrorSet(status);
373 return FALSE;
374 }
375
376 return TRUE;
377 #else // !TARGET_OS_IPHONE
378 _SCErrorSet(kSCStatusAccessError);
379 return FALSE;
380 #endif // !TARGET_OS_IPHONE
381 }
382
383
384 Boolean
385 _SCSecKeychainPasswordItemSet(SecKeychainRef keychain,
386 CFStringRef unique_id,
387 CFStringRef label,
388 CFStringRef description,
389 CFStringRef account,
390 CFDataRef password,
391 CFDictionaryRef options)
392 {
393 #if !TARGET_OS_IPHONE
394 SecAccessRef access = NULL;
395 CFBooleanRef allowRoot = NULL;
396 CFArrayRef allowedExecutables = NULL;
397 SecKeychainAttribute attributes[4];
398 SecKeychainAttributeList attributeList = { 0, attributes };
399 CFIndex i;
400 SecKeychainItemRef item = NULL;
401 CFIndex n = 0;
402 OSStatus status;
403
404 if (options != NULL) {
405 if (isA_CFDictionary(options)) {
406 allowRoot = CFDictionaryGetValue(options, kSCKeychainOptionsAllowRoot);
407 allowedExecutables = CFDictionaryGetValue(options, kSCKeychainOptionsAllowedExecutables);
408 } else {
409 _SCErrorSet(kSCStatusInvalidArgument);
410 return FALSE;
411 }
412 }
413
414 if (!isA_CFString(unique_id) ||
415 ((label != NULL) && !isA_CFString (label )) ||
416 ((description != NULL) && !isA_CFString (description )) ||
417 ((account != NULL) && !isA_CFString (account )) ||
418 ((password != NULL) && !isA_CFData (password )) ||
419 ((allowRoot != NULL) && !isA_CFBoolean(allowRoot )) ||
420 ((allowedExecutables != NULL) && !isA_CFArray (allowedExecutables)) ||
421 ((allowRoot != NULL) && (allowedExecutables != NULL))) {
422 _SCErrorSet(kSCStatusInvalidArgument);
423 return FALSE;
424 }
425
426 if ((allowRoot != NULL) && CFBooleanGetValue(allowRoot)) {
427 #if (__MAC_OS_X_VERSION_MIN_REQUIRED < 1070)
428 access = _SCSecAccessCreateForUID(0);
429 if (access == NULL) {
430 return FALSE;
431 }
432 #else // (__MAC_OS_X_VERSION_MIN_REQUIRED < 1070)
433 CFErrorRef error = NULL;
434
435 access = SecAccessCreateWithOwnerAndACL(0, 0, kSecUseOnlyUID, NULL, &error);
436 if (access == NULL) {
437 CFIndex code = kSCStatusAccessError;
438
439 if (error != NULL) {
440
441 code = CFErrorGetCode(error);
442 CFRelease(error);
443 }
444 _SCErrorSet((int)code);
445 return FALSE;
446 }
447 #endif // (__MAC_OS_X_VERSION_MIN_REQUIRED < 1070)
448 } else if (allowedExecutables != NULL) {
449 access = _SCSecAccessCreateForExecutables(label, allowedExecutables);
450 if (access == NULL) {
451 return FALSE;
452 }
453 }
454
455 for (i = 0; i < 4; i++) {
456 CFStringRef str = NULL;
457 SecKeychainAttrType tag = 0;
458
459 switch (i) {
460 case 0 :
461 str = unique_id;
462 tag = kSecServiceItemAttr;
463 break;
464 case 1 :
465 str = label;
466 tag = kSecLabelItemAttr;
467 break;
468 case 2 :
469 str = description;
470 tag = kSecDescriptionItemAttr;
471 break;
472 case 3 :
473 str = account;
474 tag = kSecAccountItemAttr;
475 break;
476 }
477
478 if (str == NULL) {
479 continue;
480 }
481
482 attributes[n].tag = tag;
483 attributes[n].data = _SC_cfstring_to_cstring(str, NULL, 0, kCFStringEncodingUTF8);
484 attributes[n].length = (UInt32)strlen(attributes[n].data);
485 n++;
486 }
487
488 status = findKeychainItem(keychain, unique_id, &item);
489 switch (status) {
490 case noErr : {
491 const void *pw = NULL;
492 UInt32 pw_len = 0;
493
494 // keychain item exists
495 if (password != NULL) {
496 pw = CFDataGetBytePtr(password);
497 pw_len = (UInt32)CFDataGetLength(password);
498 }
499
500 attributeList.count = (UInt32)n;
501 status = SecKeychainItemModifyContent(item,
502 &attributeList,
503 pw_len,
504 pw);
505 break;
506 }
507
508 case errSecItemNotFound : {
509 // no keychain item
510 if (password == NULL) {
511 // creating new keychain item and password not specified
512 status = kSCStatusInvalidArgument;
513 goto done;
514 }
515
516 attributeList.count = (UInt32)n;
517 status = SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass,
518 &attributeList,
519 (UInt32)CFDataGetLength(password),
520 CFDataGetBytePtr(password),
521 keychain,
522 access,
523 NULL);
524 break;
525 }
526
527 // some other error
528 default :
529 break;
530 }
531
532 done :
533
534 if (access != NULL) CFRelease(access);
535 if (item != NULL) CFRelease(item);
536
537 for (i = 0; i < n; i++) {
538 CFAllocatorDeallocate(NULL, attributes[i].data);
539 }
540
541 if (status != noErr) {
542 _SCErrorSet(status);
543 return FALSE;
544 }
545
546 return TRUE;
547 #else // !TARGET_OS_IPHONE
548 _SCErrorSet(kSCStatusAccessError);
549 return FALSE;
550 #endif // !TARGET_OS_IPHONE
551 }
552
553
554 #pragma mark -
555 #pragma mark "System" Keychain APIs (w/SCPreferences)
556
557
558 #include "SCHelper_client.h"
559
560 #include <fcntl.h>
561 #include <unistd.h>
562 #include <sys/errno.h>
563
564
565 #if !TARGET_OS_IPHONE
566 static CFDataRef
567 __SCPreferencesSystemKeychainPasswordItemCopy_helper(SCPreferencesRef prefs,
568 CFStringRef unique_id)
569 {
570 CFDataRef data = NULL;
571 Boolean ok;
572 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
573 uint32_t status = kSCStatusOK;
574 CFDataRef reply = NULL;
575
576 if (prefsPrivate->helper_port == MACH_PORT_NULL) {
577 ok = __SCPreferencesCreate_helper(prefs);
578 if (!ok) {
579 return FALSE;
580 }
581 }
582
583 ok = _SCSerializeString(unique_id, &data, NULL, NULL);
584 if (!ok) {
585 goto fail;
586 }
587
588 // have the helper set the "System" Keychain password
589 ok = _SCHelperExec(prefsPrivate->helper_port,
590 SCHELPER_MSG_KEYCHAIN_COPY,
591 data,
592 &status,
593 &reply);
594 if (data != NULL) CFRelease(data);
595 if (!ok) {
596 goto fail;
597 }
598
599 if (status != kSCStatusOK) {
600 goto error;
601 }
602
603 return reply;
604
605 fail :
606
607 // close helper
608 if (prefsPrivate->helper_port != MACH_PORT_NULL) {
609 _SCHelperClose(&prefsPrivate->helper_port);
610 }
611
612 status = kSCStatusAccessError;
613
614 error :
615
616 // return error
617 if (reply != NULL) CFRelease(reply);
618 _SCErrorSet(status);
619 return NULL;
620 }
621 #endif // !TARGET_OS_IPHONE
622
623
624 CFDataRef
625 _SCPreferencesSystemKeychainPasswordItemCopy(SCPreferencesRef prefs,
626 CFStringRef unique_id)
627 {
628 #if !TARGET_OS_IPHONE
629 SecKeychainRef keychain = NULL;
630 CFDataRef password = NULL;
631 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
632
633 if (prefs == NULL) {
634 /* sorry, you must provide a session */
635 _SCErrorSet(kSCStatusNoPrefsSession);
636 return NULL;
637 }
638
639 if (!isA_CFString(unique_id)) {
640 _SCErrorSet(kSCStatusInvalidArgument);
641 return NULL;
642 }
643
644 if (prefsPrivate->authorizationData != NULL) {
645 password = __SCPreferencesSystemKeychainPasswordItemCopy_helper(prefs, unique_id);
646 goto done;
647 }
648
649 keychain = _SCSecKeychainCopySystemKeychain();
650 if (keychain == NULL) {
651 goto done;
652 }
653
654 password = _SCSecKeychainPasswordItemCopy(keychain, unique_id);
655
656 done :
657
658 if (keychain != NULL) CFRelease(keychain);
659 return password;
660 #else // !TARGET_OS_IPHONE
661 _SCErrorSet(kSCStatusAccessError);
662 return NULL;
663 #endif // !TARGET_OS_IPHONE
664 }
665
666
667 Boolean
668 _SCPreferencesSystemKeychainPasswordItemExists(SCPreferencesRef prefs,
669 CFStringRef unique_id)
670 {
671 #if !TARGET_OS_IPHONE
672 SecKeychainRef keychain = NULL;
673 Boolean ok = FALSE;
674 // SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
675
676 if (prefs == NULL) {
677 /* sorry, you must provide a session */
678 _SCErrorSet(kSCStatusNoPrefsSession);
679 return FALSE;
680 }
681
682 if (!isA_CFString(unique_id)) {
683 _SCErrorSet(kSCStatusInvalidArgument);
684 return FALSE;
685 }
686
687 // if (prefsPrivate->authorizationData != NULL) {
688 // ok = __SCPreferencesSystemKeychainPasswordItemExists_helper(prefs, unique_id);
689 // goto done;
690 // }
691
692 keychain = _SCSecKeychainCopySystemKeychain();
693 if (keychain == NULL) {
694 goto done;
695 }
696
697 ok = _SCSecKeychainPasswordItemExists(keychain, unique_id);
698
699 done :
700
701 if (keychain != NULL) CFRelease(keychain);
702 return ok;
703 #else // !TARGET_OS_IPHONE
704 _SCErrorSet(kSCStatusAccessError);
705 return FALSE;
706 #endif // !TARGET_OS_IPHONE
707 }
708
709
710 #if !TARGET_OS_IPHONE
711 static Boolean
712 __SCPreferencesSystemKeychainPasswordItemRemove_helper(SCPreferencesRef prefs,
713 CFStringRef unique_id)
714 {
715 CFDataRef data = NULL;
716 Boolean ok;
717 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
718 uint32_t status = kSCStatusOK;
719 CFDataRef reply = NULL;
720
721 if (prefsPrivate->helper_port == MACH_PORT_NULL) {
722 ok = __SCPreferencesCreate_helper(prefs);
723 if (!ok) {
724 return FALSE;
725 }
726 }
727
728 ok = _SCSerializeString(unique_id, &data, NULL, NULL);
729 if (!ok) {
730 goto fail;
731 }
732
733 // have the helper set the "System" Keychain password
734 ok = _SCHelperExec(prefsPrivate->helper_port,
735 SCHELPER_MSG_KEYCHAIN_REMOVE,
736 data,
737 &status,
738 &reply);
739 if (data != NULL) CFRelease(data);
740 if (!ok) {
741 goto fail;
742 }
743
744 if (status != kSCStatusOK) {
745 goto error;
746 }
747
748 return TRUE;
749
750 fail :
751
752 // close helper
753 if (prefsPrivate->helper_port != MACH_PORT_NULL) {
754 _SCHelperClose(&prefsPrivate->helper_port);
755 }
756
757 status = kSCStatusAccessError;
758
759 error :
760
761 // return error
762 if (reply != NULL) CFRelease(reply);
763 _SCErrorSet(status);
764 return FALSE;
765 }
766 #endif // !TARGET_OS_IPHONE
767
768
769 Boolean
770 _SCPreferencesSystemKeychainPasswordItemRemove(SCPreferencesRef prefs,
771 CFStringRef unique_id)
772 {
773 #if !TARGET_OS_IPHONE
774 SecKeychainRef keychain = NULL;
775 Boolean ok = FALSE;
776 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
777
778 if (prefs == NULL) {
779 /* sorry, you must provide a session */
780 _SCErrorSet(kSCStatusNoPrefsSession);
781 return FALSE;
782 }
783
784 if (!isA_CFString(unique_id)) {
785 _SCErrorSet(kSCStatusInvalidArgument);
786 return FALSE;
787 }
788
789 if (prefsPrivate->authorizationData != NULL) {
790 ok = __SCPreferencesSystemKeychainPasswordItemRemove_helper(prefs, unique_id);
791 goto done;
792 }
793
794 keychain = _SCSecKeychainCopySystemKeychain();
795 if (keychain == NULL) {
796 goto done;
797 }
798
799 ok = _SCSecKeychainPasswordItemRemove(keychain, unique_id);
800
801 done :
802
803 if (keychain != NULL) CFRelease(keychain);
804 return ok;
805 #else // !TARGET_OS_IPHONE
806 _SCErrorSet(kSCStatusAccessError);
807 return FALSE;
808 #endif // !TARGET_OS_IPHONE
809 }
810
811
812 #if !TARGET_OS_IPHONE
813 static Boolean
814 __SCPreferencesSystemKeychainPasswordItemSet_helper(SCPreferencesRef prefs,
815 CFStringRef unique_id,
816 CFStringRef label,
817 CFStringRef description,
818 CFStringRef account,
819 CFDataRef password,
820 CFDictionaryRef options)
821 {
822 CFDataRef data = NULL;
823 CFMutableDictionaryRef newOptions = NULL;
824 Boolean ok;
825 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
826 uint32_t status = kSCStatusOK;
827 CFDataRef reply = NULL;
828
829 if (prefsPrivate->helper_port == MACH_PORT_NULL) {
830 ok = __SCPreferencesCreate_helper(prefs);
831 if (!ok) {
832 return FALSE;
833 }
834 }
835
836 if (isA_CFDictionary(options)) {
837 CFArrayRef executableURLs = NULL;
838
839 newOptions = CFDictionaryCreateMutableCopy(NULL, 0, options);
840
841 if (CFDictionaryGetValueIfPresent(newOptions,
842 kSCKeychainOptionsAllowedExecutables,
843 (const void **)&executableURLs)) {
844 CFMutableArrayRef executablePaths;
845 CFIndex i;
846 CFIndex n;
847 CFDataRef path;
848
849 executablePaths = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
850
851 path = copyMyExecutablePath();
852 if (path != NULL) {
853 CFArrayAppendValue(executablePaths, path);
854 CFRelease(path);
855 }
856
857 n = CFArrayGetCount(executableURLs);
858 for (i = 0; i < n; i++) {
859 char fspath[MAXPATHLEN];
860 CFURLRef url;
861
862 url = CFArrayGetValueAtIndex(executableURLs, i);
863 ok = CFURLGetFileSystemRepresentation(url, TRUE, (UInt8 *)fspath, sizeof(fspath));
864 if (!ok) {
865 continue;
866 }
867 fspath[sizeof(fspath) - 1] = '\0';
868 path = CFDataCreate(NULL, (UInt8 *)fspath, strlen(fspath));
869 CFArrayAppendValue(executablePaths, path);
870 CFRelease(path);
871 }
872
873 CFDictionarySetValue(newOptions, kSCKeychainOptionsAllowedExecutables, executablePaths);
874 CFRelease(executablePaths);
875 }
876 } else {
877 newOptions = CFDictionaryCreateMutable(NULL,
878 0,
879 &kCFTypeDictionaryKeyCallBacks,
880 &kCFTypeDictionaryValueCallBacks);
881 }
882
883 if (unique_id != NULL) CFDictionarySetValue(newOptions, kSCKeychainOptionsUniqueID , unique_id);
884 if (label != NULL) CFDictionarySetValue(newOptions, kSCKeychainOptionsLabel , label);
885 if (description != NULL) CFDictionarySetValue(newOptions, kSCKeychainOptionsDescription, description);
886 if (account != NULL) CFDictionarySetValue(newOptions, kSCKeychainOptionsAccount , account);
887 if (password != NULL) CFDictionarySetValue(newOptions, kSCKeychainOptionsPassword , password);
888
889 //
890 // if not AllowRoot and a list of executables was not provided than
891 // pass the current executable
892 //
893 if (!CFDictionaryContainsKey(newOptions, kSCKeychainOptionsAllowRoot) &&
894 !CFDictionaryContainsKey(newOptions, kSCKeychainOptionsAllowedExecutables)) {
895 CFDataRef path;
896
897 path = copyMyExecutablePath();
898 if (path != NULL) {
899 CFArrayRef executablePaths;
900
901 executablePaths = CFArrayCreate(NULL, (const void **)&path, 1, &kCFTypeArrayCallBacks);
902 CFRelease(path);
903 CFDictionarySetValue(newOptions, kSCKeychainOptionsAllowedExecutables, executablePaths);
904 CFRelease(executablePaths);
905 }
906 }
907
908 ok = _SCSerialize(newOptions, &data, NULL, NULL);
909 CFRelease(newOptions);
910 if (!ok) {
911 goto fail;
912 }
913
914 // have the helper create the "System" Keychain password
915 ok = _SCHelperExec(prefsPrivate->helper_port,
916 SCHELPER_MSG_KEYCHAIN_SET,
917 data,
918 &status,
919 &reply);
920 if (data != NULL) CFRelease(data);
921 if (!ok) {
922 goto fail;
923 }
924
925 if (status != kSCStatusOK) {
926 goto error;
927 }
928
929 return TRUE;
930
931 fail :
932
933 // close helper
934 if (prefsPrivate->helper_port != MACH_PORT_NULL) {
935 _SCHelperClose(&prefsPrivate->helper_port);
936 }
937
938 status = kSCStatusAccessError;
939
940 error :
941
942 // return error
943 if (reply != NULL) CFRelease(reply);
944 _SCErrorSet(status);
945 return FALSE;
946 }
947 #endif // !TARGET_OS_IPHONE
948
949
950 Boolean
951 _SCPreferencesSystemKeychainPasswordItemSet(SCPreferencesRef prefs,
952 CFStringRef unique_id,
953 CFStringRef label,
954 CFStringRef description,
955 CFStringRef account,
956 CFDataRef password,
957 CFDictionaryRef options)
958 {
959 #if !TARGET_OS_IPHONE
960 SecKeychainRef keychain = NULL;
961 Boolean ok = FALSE;
962 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
963
964 if (prefs == NULL) {
965 /* sorry, you must provide a session */
966 _SCErrorSet(kSCStatusNoPrefsSession);
967 return FALSE;
968 }
969
970 if (!isA_CFString(unique_id) ||
971 ((label != NULL) && !isA_CFString (label )) ||
972 ((description != NULL) && !isA_CFString (description)) ||
973 ((account != NULL) && !isA_CFString (account )) ||
974 ((password != NULL) && !isA_CFData (password )) ||
975 ((options != NULL) && !isA_CFDictionary(options ))) {
976 _SCErrorSet(kSCStatusInvalidArgument);
977 return FALSE;
978 }
979
980 if (prefsPrivate->authorizationData != NULL) {
981 ok = __SCPreferencesSystemKeychainPasswordItemSet_helper(prefs,
982 unique_id,
983 label,
984 description,
985 account,
986 password,
987 options);
988 goto done;
989 }
990
991 keychain = _SCSecKeychainCopySystemKeychain();
992 if (keychain == NULL) {
993 goto done;
994 }
995
996 ok = _SCSecKeychainPasswordItemSet(keychain,
997 unique_id,
998 label,
999 description,
1000 account,
1001 password,
1002 options);
1003
1004 done :
1005
1006 if (keychain != NULL) CFRelease(keychain);
1007 return ok;
1008 #else // !TARGET_OS_IPHONE
1009 _SCErrorSet(kSCStatusAccessError);
1010 return FALSE;
1011 #endif // !TARGET_OS_IPHONE
1012 }