]> git.saurik.com Git - apple/security.git/blob - sec/Security/SecItem.c
Security-55178.0.1.tar.gz
[apple/security.git] / sec / Security / SecItem.c
1 /*
2 * Copyright (c) 2006-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 * SecItem.c - CoreFoundation-based constants and functions for
26 access to Security items (certificates, keys, identities, and
27 passwords.)
28 */
29
30 #include <Security/SecItem.h>
31 #include <Security/SecItemPriv.h>
32 #include <Security/SecItemInternal.h>
33 #ifndef SECITEM_SHIM_OSX
34 #include <Security/SecKey.h>
35 #include <Security/SecKeyPriv.h>
36 #include <Security/SecCertificateInternal.h>
37 #include <Security/SecIdentity.h>
38 #include <Security/SecIdentityPriv.h>
39 #include <Security/SecRandom.h>
40 #include <Security/SecBasePriv.h>
41 #endif // *** END SECITEM_SHIM_OSX ***
42 #include <errno.h>
43 #include <limits.h>
44 #include <pthread.h>
45 #include <sqlite3.h>
46 #include <stdint.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <sys/param.h>
50 #include <sys/stat.h>
51 #include <Security/SecBase.h>
52 #include <CoreFoundation/CFData.h>
53 #include <CoreFoundation/CFDate.h>
54 #include <CoreFoundation/CFDictionary.h>
55 #include <CoreFoundation/CFNumber.h>
56 #include <CoreFoundation/CFString.h>
57 #include <CoreFoundation/CFURL.h>
58 #include <CommonCrypto/CommonDigest.h>
59 #include <libkern/OSByteOrder.h>
60 #include <security_utilities/debugging.h>
61 #include <assert.h>
62 #include <Security/SecInternal.h>
63 #include <TargetConditionals.h>
64 #include "securityd_client.h"
65 #include "securityd_server.h"
66 #include <AssertMacros.h>
67 #include <asl.h>
68 #include <sys/types.h>
69 #include <pwd.h>
70 #include <grp.h>
71 #include <unistd.h>
72 #ifndef SECITEM_SHIM_OSX
73 #include <libDER/asn1Types.h>
74 #endif // *** END SECITEM_SHIM_OSX ***
75
76 /* label when certificate data is joined with key data */
77 #define CERTIFICATE_DATA_COLUMN_LABEL "certdata"
78
79 /* IPC uses CFPropertyList to un/marshall input/output data and can handle:
80 CFData, CFString, CFArray, CFDictionary, CFDate, CFBoolean, and CFNumber
81
82 Currently in need of conversion below:
83 @@@ kSecValueRef allows SecKeychainItemRef and SecIdentityRef
84 @@@ kSecMatchPolicy allows a query with a SecPolicyRef
85 @@@ kSecUseItemList allows a query against a list of itemrefs, this isn't
86 currently implemented at all, but when it is needs to short circuit to
87 local evaluation, different from the sql query abilities
88 */
89
90 #ifndef SECITEM_SHIM_OSX
91 static CFDictionaryRef
92 SecItemCopyAttributeDictionary(CFTypeRef ref) {
93 CFDictionaryRef refDictionary = NULL;
94 CFTypeID typeID = CFGetTypeID(ref);
95 if (typeID == SecKeyGetTypeID()) {
96 refDictionary = SecKeyCopyAttributeDictionary((SecKeyRef)ref);
97 } else if (typeID == SecCertificateGetTypeID()) {
98 refDictionary =
99 SecCertificateCopyAttributeDictionary((SecCertificateRef)ref);
100 } else if (typeID == SecIdentityGetTypeID()) {
101 assert(false);
102 SecIdentityRef identity = (SecIdentityRef)ref;
103 SecCertificateRef cert = NULL;
104 SecKeyRef key = NULL;
105 if (!SecIdentityCopyCertificate(identity, &cert) &&
106 !SecIdentityCopyPrivateKey(identity, &key))
107 {
108 CFDataRef data = SecCertificateCopyData(cert);
109 CFDictionaryRef key_dict = SecKeyCopyAttributeDictionary(key);
110
111 if (key_dict && data) {
112 refDictionary = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, key_dict);
113 CFDictionarySetValue((CFMutableDictionaryRef)refDictionary,
114 CFSTR(CERTIFICATE_DATA_COLUMN_LABEL), data);
115 }
116 CFReleaseNull(key_dict);
117 CFReleaseNull(data);
118 }
119 CFReleaseNull(cert);
120 CFReleaseNull(key);
121 } else {
122 refDictionary = NULL;
123 }
124 return refDictionary;
125 }
126
127 static CFTypeRef
128 SecItemCreateFromAttributeDictionary(CFDictionaryRef refAttributes) {
129 CFTypeRef ref = NULL;
130 CFStringRef class = CFDictionaryGetValue(refAttributes, kSecClass);
131 if (CFEqual(class, kSecClassCertificate)) {
132 ref = SecCertificateCreateFromAttributeDictionary(refAttributes);
133 } else if (CFEqual(class, kSecClassKey)) {
134 ref = SecKeyCreateFromAttributeDictionary(refAttributes);
135 } else if (CFEqual(class, kSecClassIdentity)) {
136 CFAllocatorRef allocator = NULL;
137 CFDataRef data = CFDictionaryGetValue(refAttributes, CFSTR(CERTIFICATE_DATA_COLUMN_LABEL));
138 SecCertificateRef cert = SecCertificateCreateWithData(allocator, data);
139 SecKeyRef key = SecKeyCreateFromAttributeDictionary(refAttributes);
140 if (key && cert)
141 ref = SecIdentityCreate(allocator, cert, key);
142 CFReleaseSafe(cert);
143 CFReleaseSafe(key);
144 #if 0
145 /* We don't support SecKeychainItemRefs yet. */
146 } else if (CFEqual(class, kSecClassGenericPassword)) {
147 } else if (CFEqual(class, kSecClassInternetPassword)) {
148 } else if (CFEqual(class, kSecClassAppleSharePassword)) {
149 #endif
150 } else {
151 ref = NULL;
152 }
153 return ref;
154 }
155
156 /* Turn the returned dictionary that contains all the attributes to create a
157 ref into the exact result the client asked for */
158 static CFTypeRef makeRef(CFTypeRef ref, bool return_data, bool return_attributes)
159 {
160 CFTypeRef result = NULL;
161 if (!ref || (CFGetTypeID(ref) != CFDictionaryGetTypeID()))
162 return NULL;
163
164 CFTypeRef return_ref = SecItemCreateFromAttributeDictionary(ref);
165
166 if (return_data || return_attributes) {
167 if (return_attributes)
168 result = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, ref);
169 else
170 result = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
171
172 if (return_ref) {
173 CFDictionarySetValue((CFMutableDictionaryRef)result, kSecValueRef, return_ref);
174 CFRelease(return_ref);
175 }
176
177 if (!return_data)
178 CFDictionaryRemoveValue((CFMutableDictionaryRef)result, kSecValueData);
179 } else
180 result = return_ref;
181
182 return result;
183 }
184
185 OSStatus
186 SecItemCopyDisplayNames(CFArrayRef items, CFArrayRef *displayNames)
187 {
188 // @@@ TBI
189 return -1 /* unimpErr */;
190 }
191
192
193 static void merge_dictionary_by_overwrite(const void *key, const void *value, void *context)
194 {
195 if (!CFEqual(key, kSecValueRef))
196 CFDictionarySetValue((CFMutableDictionaryRef)context, key, value);
197 }
198
199 static void copy_applier(const void *key, const void *value, void *context)
200 {
201 CFDictionarySetValue(context, key, value);
202 }
203
204 static OSStatus cook_query(CFDictionaryRef query, CFMutableDictionaryRef *explode)
205 {
206 /* If a ref was specified we get it's attribute dictionary and parse it. */
207 CFMutableDictionaryRef args = NULL;
208 CFTypeRef value = CFDictionaryGetValue(query, kSecValueRef);
209 if (value) {
210 CFDictionaryRef refAttributes = SecItemCopyAttributeDictionary(value);
211 if (!refAttributes)
212 return errSecValueRefUnsupported;
213
214 /* Replace any attributes we already got from the ref with the ones
215 from the attributes dictionary the caller passed us. This allows
216 a caller to add an item using attributes from the ref and still
217 override some of them in the dictionary directly. */
218 args = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, refAttributes);
219 CFRelease(refAttributes);
220 CFDictionaryApplyFunction(query, merge_dictionary_by_overwrite, args);
221 }
222 value = CFDictionaryGetValue(query, kSecAttrIssuer);
223 if (value) {
224 /* convert DN to canonical issuer, if value is DN (top level sequence) */
225 const DERItem name = { (unsigned char *)CFDataGetBytePtr(value), CFDataGetLength(value) };
226 DERDecodedInfo content;
227 if (!DERDecodeItem(&name, &content) &&
228 (content.tag == ASN1_CONSTR_SEQUENCE))
229 {
230 CFDataRef canonical_issuer = createNormalizedX501Name(kCFAllocatorDefault, &content.content);
231 if (canonical_issuer) {
232 if (!args) {
233 args = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
234 /* This is necessary because we rely on non NULL callbacks */
235 CFDictionaryApplyFunction(query, copy_applier, args);
236 }
237 /* Overwrite with new issuer */
238 CFDictionarySetValue(args, kSecAttrIssuer, canonical_issuer);
239 CFRelease(canonical_issuer);
240 }
241 }
242 }
243 *explode = args;
244 return noErr;
245 }
246
247 typedef OSStatus (*secitem_operation)(CFDictionaryRef attributes, ...);
248
249 static bool explode_identity(CFDictionaryRef attributes, secitem_operation operation,
250 OSStatus *return_status, CFTypeRef *return_result)
251 {
252 bool handled = false;
253 CFTypeRef value = CFDictionaryGetValue(attributes, kSecValueRef);
254 if (value) {
255 CFTypeID typeID = CFGetTypeID(value);
256 if (typeID == SecIdentityGetTypeID()) {
257 handled = true;
258 OSStatus status = errSecSuccess;
259 SecIdentityRef identity = (SecIdentityRef)value;
260 SecCertificateRef cert = NULL;
261 SecKeyRef key = NULL;
262 if (!SecIdentityCopyCertificate(identity, &cert) &&
263 !SecIdentityCopyPrivateKey(identity, &key))
264 {
265 CFMutableDictionaryRef partial_query =
266 CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, attributes);
267 CFDictionarySetValue(partial_query, kSecValueRef, cert);
268 CFTypeRef result = NULL;
269 bool duplicate_cert = false;
270 /* an identity is first and foremost a key, but it can have multiple
271 certs associated with it: so we identify it by the cert */
272 status = operation(partial_query, return_result ? &result : NULL);
273 if ((operation == (secitem_operation)SecItemAdd) &&
274 (status == errSecDuplicateItem)) {
275 duplicate_cert = true;
276 status = errSecSuccess;
277 }
278
279 if (!status || status == errSecItemNotFound) {
280 bool skip_key_operation = false;
281
282 /* if the key is still in use, skip deleting it */
283 if (operation == (secitem_operation)SecItemDelete) {
284 // find certs with cert.pkhh == keys.klbl
285 CFDictionaryRef key_dict = NULL, query_dict = NULL;
286 CFDataRef pkhh = NULL;
287
288 key_dict = SecKeyCopyAttributeDictionary(key);
289 if (key_dict)
290 pkhh = (CFDataRef)CFDictionaryGetValue(key_dict, kSecAttrApplicationLabel);
291 const void *keys[] = { kSecClass, kSecAttrPublicKeyHash };
292 const void *vals[] = { kSecClassCertificate, pkhh };
293 if (pkhh)
294 query_dict = CFDictionaryCreate(NULL, keys,
295 vals, (sizeof(keys) / sizeof(*keys)),
296 NULL, NULL);
297 if (query_dict)
298 if (noErr == SecItemCopyMatching(query_dict, NULL))
299 skip_key_operation = true;
300 CFReleaseSafe(query_dict);
301 CFReleaseSafe(key_dict);
302 }
303
304 if (!skip_key_operation) {
305 /* now perform the operation for the key */
306 CFDictionarySetValue(partial_query, kSecValueRef, key);
307 CFDictionarySetValue(partial_query, kSecReturnPersistentRef, kCFBooleanFalse);
308 status = operation(partial_query, NULL);
309 if ((operation == (secitem_operation)SecItemAdd) &&
310 (status == errSecDuplicateItem) &&
311 !duplicate_cert)
312 status = errSecSuccess;
313 }
314
315 /* add and copy matching for an identityref have a persistent ref result */
316 if (result) {
317 if (!status) {
318 /* result is a persistent ref to a cert */
319 sqlite_int64 rowid;
320 if (_SecItemParsePersistentRef(result, NULL, &rowid)) {
321 *return_result = _SecItemMakePersistentRef(kSecClassIdentity, rowid);
322 }
323 }
324 CFRelease(result);
325 }
326 }
327 CFReleaseNull(partial_query);
328 }
329 else
330 status = errSecInvalidItemRef;
331
332 CFReleaseNull(cert);
333 CFReleaseNull(key);
334 *return_status = status;
335 }
336 } else {
337 value = CFDictionaryGetValue(attributes, kSecClass);
338 if (value && CFEqual(kSecClassIdentity, value) &&
339 (operation == (secitem_operation)SecItemDelete)) {
340 CFMutableDictionaryRef dict = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, attributes);
341 CFDictionaryRemoveValue(dict, kSecClass);
342 CFDictionarySetValue(dict, kSecClass, kSecClassCertificate);
343 OSStatus status = SecItemDelete(dict);
344 if (!status) {
345 CFDictionarySetValue(dict, kSecClass, kSecClassKey);
346 status = SecItemDelete(dict);
347 }
348 CFRelease(dict);
349 *return_status = status;
350 handled = true;
351 }
352 }
353 return handled;
354 }
355
356 static void infer_cert_label(CFDictionaryRef attributes, CFMutableDictionaryRef args)
357 {
358 if (!args || !attributes)
359 return;
360
361 if (CFDictionaryContainsKey(attributes, kSecAttrLabel))
362 return;
363
364 CFTypeRef value_ref = CFDictionaryGetValue(attributes, kSecValueRef);
365 if (!value_ref || (CFGetTypeID(value_ref) != SecCertificateGetTypeID()))
366 return;
367
368 SecCertificateRef certificate = (SecCertificateRef)value_ref;
369 CFStringRef label = SecCertificateCopySubjectSummary(certificate);
370 if (label) {
371 CFDictionarySetValue(args, kSecAttrLabel, label);
372 CFReleaseNull(label);
373 }
374 }
375
376 /* A persistent ref is just the class and the rowid of the record. */
377 CFDataRef _SecItemMakePersistentRef(CFTypeRef class, sqlite_int64 rowid)
378 {
379 uint8_t bytes[sizeof(sqlite_int64) + 4];
380 if (rowid < 0)
381 return NULL;
382 if (CFStringGetCString(class, (char *)bytes, 4 + 1 /*null-term*/,
383 kCFStringEncodingUTF8))
384 {
385 OSWriteBigInt64(bytes + 4, 0, rowid);
386 return CFDataCreate(NULL, bytes, sizeof(bytes));
387 }
388 return NULL;
389 }
390
391 /* AUDIT[securityd](done):
392 persistent_ref (ok) is a caller provided, non NULL CFTypeRef.
393 */
394 bool _SecItemParsePersistentRef(CFDataRef persistent_ref, CFStringRef *return_class, sqlite_int64 *return_rowid)
395 {
396 bool valid_ref = false;
397 if (CFGetTypeID(persistent_ref) == CFDataGetTypeID() &&
398 CFDataGetLength(persistent_ref) == (CFIndex)(sizeof(sqlite_int64) + 4)) {
399 const uint8_t *bytes = CFDataGetBytePtr(persistent_ref);
400 sqlite_int64 rowid = OSReadBigInt64(bytes + 4, 0);
401
402 CFStringRef class = CFStringCreateWithBytes(kCFAllocatorDefault,
403 bytes, CFStringGetLength(kSecClassGenericPassword),
404 kCFStringEncodingUTF8, true);
405 const void *valid_classes[] = { kSecClassGenericPassword,
406 kSecClassInternetPassword,
407 kSecClassAppleSharePassword,
408 kSecClassCertificate,
409 kSecClassKey,
410 kSecClassIdentity };
411 unsigned i;
412 for (i=0; i< sizeof(valid_classes)/sizeof(*valid_classes); i++) {
413 if (CFEqual(valid_classes[i], class)) {
414 if (return_class)
415 *return_class = valid_classes[i];
416 if (return_rowid)
417 *return_rowid = rowid;
418 valid_ref = true;
419 break;
420 }
421 }
422 CFRelease(class);
423 }
424 return valid_ref;
425 }
426
427 static bool cf_bool_value(CFTypeRef cf_bool)
428 {
429 return (cf_bool && CFEqual(kCFBooleanTrue, cf_bool));
430 }
431
432 static void
433 result_post(CFDictionaryRef query, CFTypeRef raw_result, CFTypeRef *result) {
434 if (!raw_result)
435 return;
436
437 bool return_ref = cf_bool_value(CFDictionaryGetValue(query, kSecReturnRef));
438 bool return_data = cf_bool_value(CFDictionaryGetValue(query, kSecReturnData));
439 bool return_attributes = cf_bool_value(CFDictionaryGetValue(query, kSecReturnAttributes));
440
441 if (return_ref) {
442 if (CFGetTypeID(raw_result) == CFArrayGetTypeID()) {
443 CFIndex i, count = CFArrayGetCount(raw_result);
444 CFMutableArrayRef tmp_array = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks);
445 for (i = 0; i < count; i++) {
446 CFTypeRef ref = makeRef(CFArrayGetValueAtIndex(raw_result, i), return_data, return_attributes);
447 if (ref) {
448 CFArrayAppendValue(tmp_array, ref);
449 CFRelease(ref);
450 }
451 }
452 *result = tmp_array;
453 } else
454 *result = makeRef(raw_result, return_data, return_attributes);
455
456 CFRelease(raw_result);
457 } else
458 *result = raw_result;
459 }
460 #endif // *** END SECITEM_SHIM_OSX ***
461
462 OSStatus
463 #if SECITEM_SHIM_OSX
464 SecItemAdd_ios(CFDictionaryRef attributes, CFTypeRef *result)
465 #else
466 SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result)
467 #endif // *** END SECITEM_SHIM_OSX ***
468 {
469 CFMutableDictionaryRef args = NULL;
470 CFTypeRef raw_result = NULL;
471 OSStatus status;
472
473 #ifndef SECITEM_SHIM_OSX
474 require_quiet(!explode_identity(attributes, (secitem_operation)SecItemAdd, &status, result), errOut);
475 require_noerr_quiet(status = cook_query(attributes, &args), errOut);
476 infer_cert_label(attributes, args);
477 #endif // *** END SECITEM_SHIM_OSX ***
478 if (args)
479 attributes = args;
480 status = SECURITYD_AG(sec_item_add, attributes, &raw_result);
481 #ifndef SECITEM_SHIM_OSX
482 result_post(attributes, raw_result, result);
483 #endif // *** END SECITEM_SHIM_OSX ***
484
485 errOut:
486 CFReleaseSafe(args);
487 return status;
488 }
489
490 OSStatus
491 #if SECITEM_SHIM_OSX
492 SecItemCopyMatching_ios(CFDictionaryRef query, CFTypeRef *result)
493 #else
494 SecItemCopyMatching(CFDictionaryRef query, CFTypeRef *result)
495 #endif // *** END SECITEM_SHIM_OSX ***
496 {
497 CFMutableDictionaryRef args = NULL;
498 CFTypeRef raw_result = NULL;
499 OSStatus status;
500
501 #ifndef SECITEM_SHIM_OSX
502 require_quiet(!explode_identity(query, (secitem_operation)SecItemCopyMatching, &status, result), errOut);
503 require_noerr_quiet(status = cook_query(query, &args), errOut);
504 #endif // *** END SECITEM_SHIM_OSX ***
505 if (args)
506 query = args;
507
508 status = SECURITYD_AG(sec_item_copy_matching, query, &raw_result);
509 #ifndef SECITEM_SHIM_OSX
510 result_post(query, raw_result, result);
511 #endif // *** END SECITEM_SHIM_OSX ***
512
513 errOut:
514 CFReleaseSafe(args);
515 return status;
516 }
517
518 OSStatus
519 #if SECITEM_SHIM_OSX
520 SecItemUpdate_ios(CFDictionaryRef query, CFDictionaryRef attributesToUpdate)
521 #else
522 SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate)
523 #endif // *** END SECITEM_SHIM_OSX ***
524 {
525 CFMutableDictionaryRef args = NULL;
526 OSStatus status;
527
528 #ifndef SECITEM_SHIM_OSX
529 require_noerr_quiet(status = cook_query(query, &args), errOut);
530 #endif // *** END SECITEM_SHIM_OSX ***
531 if (args)
532 query = args;
533
534 if (gSecurityd) {
535 status = gSecurityd->sec_item_update(query, attributesToUpdate, SecAccessGroupsGetCurrent());
536 } else {
537 const void *values[] = { (const void *)query, (const void *)attributesToUpdate };
538 CFArrayRef pair = CFArrayCreate(kCFAllocatorDefault, values, 2, NULL/*&kCFTypeArrayCallBacks*/);
539 if (pair) {
540 status = ServerCommandSendReceive(sec_item_update_id, pair, NULL);
541 CFRelease(pair);
542 } else {
543 status = errSecAllocate;
544 }
545 }
546
547 errOut:
548 CFReleaseSafe(args);
549 return status;
550 }
551
552 static void copy_all_keys_and_values(const void *key, const void *value, void *context)
553 {
554 CFDictionaryAddValue((CFMutableDictionaryRef)context, key, value);
555 }
556
557 static OSStatus explode_persistent_identity_ref(CFDictionaryRef query, CFMutableDictionaryRef *delete_query)
558 {
559 OSStatus status = errSecSuccess;
560 CFTypeRef persist = CFDictionaryGetValue(query, kSecValuePersistentRef);
561 CFStringRef class;
562 if (persist && _SecItemParsePersistentRef(persist, &class, NULL)
563 && CFEqual(class, kSecClassIdentity)) {
564 const void *keys[] = { kSecReturnRef, kSecValuePersistentRef };
565 const void *vals[] = { kCFBooleanTrue, persist };
566 CFDictionaryRef persistent_query = CFDictionaryCreate(NULL, keys,
567 vals, (sizeof(keys) / sizeof(*keys)), NULL, NULL);
568 CFTypeRef item_query = NULL;
569 status = SecItemCopyMatching(persistent_query, &item_query);
570 CFReleaseNull(persistent_query);
571 if (status)
572 return status;
573 CFMutableDictionaryRef new_query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
574 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
575 if (new_query) {
576 CFDictionaryApplyFunction(query, copy_all_keys_and_values, new_query);
577 CFDictionaryRemoveValue(new_query, kSecValuePersistentRef);
578 CFDictionarySetValue(new_query, kSecValueRef, item_query);
579 *delete_query = new_query;
580 } else
581 status = errSecAllocate;
582 CFRelease(item_query);
583 }
584
585 return status;
586 }
587
588 OSStatus
589 #if SECITEM_SHIM_OSX
590 SecItemDelete_ios(CFDictionaryRef query)
591 #else
592 SecItemDelete(CFDictionaryRef query)
593 #endif // *** END SECITEM_SHIM_OSX ***
594 {
595 CFMutableDictionaryRef args1 = NULL, args2 = NULL;
596 OSStatus status;
597
598 #ifndef SECITEM_SHIM_OSX
599 require_noerr_quiet(status = explode_persistent_identity_ref(query, &args1), errOut);
600 if (args1)
601 query = args1;
602 require_quiet(!explode_identity(query, (secitem_operation)SecItemDelete, &status, NULL), errOut);
603 require_noerr_quiet(status = cook_query(query, &args2), errOut);
604 #endif // *** END SECITEM_SHIM_OSX ***
605 if (args2)
606 query = args2;
607
608 if (gSecurityd) {
609 status = gSecurityd->sec_item_delete(query,
610 SecAccessGroupsGetCurrent());
611 } else {
612 status = ServerCommandSendReceive(sec_item_delete_id, query, NULL);
613 }
614
615 errOut:
616 CFReleaseSafe(args1);
617 CFReleaseSafe(args2);
618 return status;
619 }
620
621 OSStatus
622 SecItemDeleteAll(void)
623 {
624 OSStatus status = noErr;
625 if (gSecurityd) {
626 #ifndef SECITEM_SHIM_OSX
627 SecTrustStoreRef ts = SecTrustStoreForDomain(kSecTrustStoreDomainUser);
628 if (!gSecurityd->sec_truststore_remove_all(ts))
629 status = errSecInternal;
630 #endif // *** END SECITEM_SHIM_OSX ***
631 if (!gSecurityd->sec_item_delete_all())
632 status = errSecInternal;
633 } else {
634 status = ServerCommandSendReceive(sec_delete_all_id, NULL, NULL);
635 }
636 return status;
637 }
638
639 OSStatus _SecMigrateKeychain(int32_t handle_in, CFDataRef data_in,
640 int32_t *handle_out, CFDataRef *data_out)
641 {
642 CFMutableArrayRef args = NULL;
643 CFTypeRef raw_result = NULL;
644 CFNumberRef hin = NULL, hout = NULL;
645 OSStatus status = errSecAllocate;
646
647 require_quiet(args = CFArrayCreateMutable(kCFAllocatorDefault, 2, NULL), errOut);
648 require_quiet(hin = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &handle_in), errOut);
649 CFArrayAppendValue(args, hin);
650 if (data_in)
651 CFArrayAppendValue(args, data_in);
652
653 require_noerr_quiet(status = SECURITYD(sec_migrate_keychain, args, &raw_result), errOut);
654 hout = CFArrayGetValueAtIndex(raw_result, 0);
655 if (data_out) {
656 CFDataRef data;
657 if (CFArrayGetCount(raw_result) > 1) {
658 data = CFArrayGetValueAtIndex(raw_result, 1);
659 require_quiet(CFGetTypeID(data) == CFDataGetTypeID(), errOut);
660 CFRetain(data);
661 } else {
662 data = NULL;
663 }
664 *data_out = data;
665 }
666
667 errOut:
668 CFReleaseSafe(hin);
669 CFReleaseSafe(args);
670 CFReleaseSafe(raw_result);
671 return status;
672 }
673
674 /* TODO: Move to a location shared between securityd and Security framework. */
675 const char *restore_keychain_location = "/Library/Keychains/keychain.restoring";
676
677 OSStatus _SecRestoreKeychain(const char *path)
678 {
679 OSStatus status = errSecInternal;
680
681 require_quiet(!geteuid(), out);
682 struct passwd *pass = NULL;
683 require_quiet(pass = getpwnam("_securityd"), out);
684 uid_t securityUID = pass->pw_uid;
685 struct group *grp = NULL;
686 require_quiet(grp = getgrnam("wheel"), out);
687 gid_t wheelGID = grp->gr_gid;
688
689 require_noerr_quiet(rename(path , restore_keychain_location), out);
690 require_noerr_quiet(chmod(restore_keychain_location, 0600), out);
691 require_noerr_quiet(chown(restore_keychain_location, securityUID, wheelGID),
692 out);
693
694 status = ServerCommandSendReceive(sec_restore_keychain_id, NULL, NULL);
695 require_noerr_quiet(unlink(restore_keychain_location), out);
696
697 out:
698 return status;
699 }
700
701 CFDataRef _SecKeychainCopyOTABackup(void) {
702 CFTypeRef raw_result = NULL;
703 CFDataRef backup = NULL;
704 OSStatus status;
705
706 require_noerr_quiet(status = SECURITYD(sec_keychain_backup, NULL,
707 &raw_result), errOut);
708 if (raw_result && CFGetTypeID(raw_result) == CFDataGetTypeID()) {
709 backup = raw_result;
710 raw_result = NULL; /* So it doesn't get released below. */
711 }
712
713 errOut:
714 CFReleaseSafe(raw_result);
715 return backup;
716 }
717
718 CFDataRef _SecKeychainCopyBackup(CFDataRef backupKeybag, CFDataRef password) {
719 CFMutableArrayRef args;
720 CFTypeRef raw_result = NULL;
721 CFDataRef backup = NULL;
722 OSStatus status;
723
724 require_quiet(args = CFArrayCreateMutable(kCFAllocatorDefault, 2, NULL),
725 errOut);
726 CFArrayAppendValue(args, backupKeybag);
727 if (password)
728 CFArrayAppendValue(args, password);
729
730 require_noerr_quiet(status = SECURITYD(sec_keychain_backup, args,
731 &raw_result), errOut);
732 if (raw_result && CFGetTypeID(raw_result) == CFDataGetTypeID()) {
733 backup = raw_result;
734 raw_result = NULL; /* So it doesn't get released below. */
735 }
736
737 errOut:
738 CFReleaseSafe(args);
739 CFReleaseSafe(raw_result);
740 return backup;
741 }
742
743 bool _SecKeychainRestoreBackup(CFDataRef backup, CFDataRef backupKeybag,
744 CFDataRef password) {
745 CFMutableArrayRef args = NULL;
746 CFTypeRef raw_result = NULL;
747 OSStatus status = errSecAllocate;
748
749 require_quiet(args = CFArrayCreateMutable(kCFAllocatorDefault, 3, NULL),
750 errOut);
751 CFArrayAppendValue(args, backup);
752 CFArrayAppendValue(args, backupKeybag);
753 if (password)
754 CFArrayAppendValue(args, password);
755
756 require_noerr_quiet(status = SECURITYD(sec_keychain_restore, args, NULL),
757 errOut);
758
759 errOut:
760 CFReleaseSafe(args);
761 CFReleaseSafe(raw_result);
762 return status;
763 }