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