2 * Copyright (c) 2003-2010,2012-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 #include "keychain_find.h"
28 #include "keychain_utilities.h"
29 #include "readline_cssm.h"
30 #include "security_tool.h"
36 #include <libkern/OSByteOrder.h>
37 #include <Security/SecACL.h>
38 #include <Security/SecItem.h>
39 #include <Security/SecItemPriv.h>
40 #include <Security/SecKeychainItem.h>
41 #include <Security/SecKeychainItemPriv.h>
42 #include <Security/SecKeychainSearch.h>
43 #include <Security/SecCertificate.h>
44 #include <CoreFoundation/CFString.h>
46 #include <utilities/SecCFRelease.h>
49 // SecDigestGetData, SecKeychainSearchCreateForCertificateByEmail, SecCertificateFindByEmail
50 #include <Security/SecCertificatePriv.h>
52 Boolean gDeleteIt
= 0;
54 // find_first_generic_password
56 // Returns a SecKeychainItemRef for the first item
57 // which matches the specified attributes. Caller is
58 // responsible for releasing the item (with CFRelease).
61 find_first_generic_password(CFTypeRef keychainOrArray
,
62 FourCharCode itemCreator
,
63 FourCharCode itemType
,
68 const char *serviceName
,
69 const char *accountName
)
71 OSStatus status
= noErr
;
72 SecKeychainSearchRef searchRef
= NULL
;
73 SecKeychainItemRef itemRef
= NULL
;
75 SecKeychainAttribute attrs
[8]; // maximum number of searchable attributes
76 SecKeychainAttributeList attrList
= { 0, attrs
};
78 // the primary key for a generic password item (i.e. the combination of
79 // attributes which determine whether the item is unique) consists of:
80 // { kSecAccountItemAttr, kSecServiceItemAttr }
82 // if we have a primary key, we don't need to search on other attributes
83 // (and we don't want to, if non-primary attributes are being updated)
84 Boolean primaryKey
= (accountName
&& serviceName
);
86 // build the attribute list for searching
87 if ((UInt32
)itemCreator
!= 0 && !primaryKey
) {
88 attrs
[attrList
.count
].tag
= kSecCreatorItemAttr
;
89 attrs
[attrList
.count
].length
= sizeof(FourCharCode
);
90 attrs
[attrList
.count
].data
= (FourCharCode
*)&itemCreator
;
93 if ((UInt32
)itemType
!= 0 && !primaryKey
) {
94 attrs
[attrList
.count
].tag
= kSecTypeItemAttr
;
95 attrs
[attrList
.count
].length
= sizeof(FourCharCode
);
96 attrs
[attrList
.count
].data
= (FourCharCode
*)&itemType
;
99 if (kind
!= NULL
&& !primaryKey
) {
100 attrs
[attrList
.count
].tag
= kSecDescriptionItemAttr
;
101 attrs
[attrList
.count
].length
= (UInt32
) strlen(kind
);
102 attrs
[attrList
.count
].data
= (void*)kind
;
105 if (value
!= NULL
&& !primaryKey
) {
106 attrs
[attrList
.count
].tag
= kSecGenericItemAttr
;
107 attrs
[attrList
.count
].length
= (UInt32
) strlen(value
);
108 attrs
[attrList
.count
].data
= (void*)value
;
111 if (comment
!= NULL
&& !primaryKey
) {
112 attrs
[attrList
.count
].tag
= kSecCommentItemAttr
;
113 attrs
[attrList
.count
].length
= (UInt32
) strlen(comment
);
114 attrs
[attrList
.count
].data
= (void*)comment
;
117 if (label
!= NULL
&& !primaryKey
) {
118 attrs
[attrList
.count
].tag
= kSecLabelItemAttr
;
119 attrs
[attrList
.count
].length
= (UInt32
) strlen(label
);
120 attrs
[attrList
.count
].data
= (void*)label
;
123 if (serviceName
!= NULL
) {
124 attrs
[attrList
.count
].tag
= kSecServiceItemAttr
;
125 attrs
[attrList
.count
].length
= (UInt32
) strlen(serviceName
);
126 attrs
[attrList
.count
].data
= (void*)serviceName
;
129 if (accountName
!= NULL
) {
130 attrs
[attrList
.count
].tag
= kSecAccountItemAttr
;
131 attrs
[attrList
.count
].length
= (UInt32
) strlen(accountName
);
132 attrs
[attrList
.count
].data
= (void*)accountName
;
136 status
= SecKeychainSearchCreateFromAttributes(keychainOrArray
, kSecGenericPasswordItemClass
, &attrList
, &searchRef
);
138 sec_perror("SecKeychainSearchCreateFromAttributes", status
);
141 // we're only interested in the first match, if there is a match at all
142 status
= SecKeychainSearchCopyNext(searchRef
, &itemRef
);
149 CFRelease(searchRef
);
154 // find_first_internet_password
156 // Returns a SecKeychainItemRef for the first item
157 // which matches the specified attributes. Caller is
158 // responsible for releasing the item (with CFRelease).
161 find_first_internet_password(CFTypeRef keychainOrArray
,
162 FourCharCode itemCreator
,
163 FourCharCode itemType
,
167 const char *serverName
,
168 const char *securityDomain
,
169 const char *accountName
,
172 SecProtocolType protocol
,
173 SecAuthenticationType authenticationType
)
175 OSStatus status
= noErr
;
176 SecKeychainSearchRef searchRef
= NULL
;
177 SecKeychainItemRef itemRef
= NULL
;
179 SecKeychainAttribute attrs
[12]; // maximum number of searchable attributes
180 SecKeychainAttributeList attrList
= { 0, attrs
};
182 // the primary key for an internet password item (i.e. the combination of
183 // attributes which determine whether the item is unique) consists of:
184 // { kSecAccountItemAttr, kSecSecurityDomainItemAttr, kSecServerItemAttr,
185 // kSecProtocolItemAttr, kSecAuthenticationTypeItemAttr,
186 // kSecPortItemAttr, kSecPathItemAttr }
188 // if we have a primary key, we don't need to search on other attributes.
189 // (and we don't want to, if non-primary attributes are being updated)
190 Boolean primaryKey
= (accountName
&& securityDomain
&& serverName
&&
191 protocol
&& authenticationType
&& port
&& path
);
193 // build the attribute list for searching
194 if ((UInt32
)itemCreator
!= 0 && !primaryKey
) {
195 attrs
[attrList
.count
].tag
= kSecCreatorItemAttr
;
196 attrs
[attrList
.count
].length
= sizeof(FourCharCode
);
197 attrs
[attrList
.count
].data
= (FourCharCode
*)&itemCreator
;
200 if ((UInt32
)itemType
!= 0 && !primaryKey
) {
201 attrs
[attrList
.count
].tag
= kSecTypeItemAttr
;
202 attrs
[attrList
.count
].length
= sizeof(FourCharCode
);
203 attrs
[attrList
.count
].data
= (FourCharCode
*)&itemType
;
206 if (kind
!= NULL
&& !primaryKey
) {
207 attrs
[attrList
.count
].tag
= kSecDescriptionItemAttr
;
208 attrs
[attrList
.count
].length
= (UInt32
) strlen(kind
);
209 attrs
[attrList
.count
].data
= (void*)kind
;
212 if (comment
!= NULL
&& !primaryKey
) {
213 attrs
[attrList
.count
].tag
= kSecCommentItemAttr
;
214 attrs
[attrList
.count
].length
= (UInt32
) strlen(comment
);
215 attrs
[attrList
.count
].data
= (void*)comment
;
218 if (label
!= NULL
&& !primaryKey
) {
219 attrs
[attrList
.count
].tag
= kSecLabelItemAttr
;
220 attrs
[attrList
.count
].length
= (UInt32
) strlen(label
);
221 attrs
[attrList
.count
].data
= (void*)label
;
224 if (serverName
!= NULL
) {
225 attrs
[attrList
.count
].tag
= kSecServerItemAttr
;
226 attrs
[attrList
.count
].length
= (UInt32
) strlen(serverName
);
227 attrs
[attrList
.count
].data
= (void*)serverName
;
230 if (securityDomain
!= NULL
) {
231 attrs
[attrList
.count
].tag
= kSecSecurityDomainItemAttr
;
232 attrs
[attrList
.count
].length
= (UInt32
) strlen(securityDomain
);
233 attrs
[attrList
.count
].data
= (void *)securityDomain
;
236 if (accountName
!= NULL
) {
237 attrs
[attrList
.count
].tag
= kSecAccountItemAttr
;
238 attrs
[attrList
.count
].length
= (UInt32
) strlen(accountName
);
239 attrs
[attrList
.count
].data
= (void *)accountName
;
243 attrs
[attrList
.count
].tag
= kSecPathItemAttr
;
244 attrs
[attrList
.count
].length
= (UInt32
) strlen(path
);
245 attrs
[attrList
.count
].data
= (void *)path
;
249 attrs
[attrList
.count
].tag
= kSecPortItemAttr
;
250 attrs
[attrList
.count
].length
= sizeof(UInt16
);
251 attrs
[attrList
.count
].data
= (UInt16
*)&port
;
254 if ((UInt32
)protocol
!= 0) {
255 attrs
[attrList
.count
].tag
= kSecProtocolItemAttr
;
256 attrs
[attrList
.count
].length
= sizeof(SecProtocolType
);
257 attrs
[attrList
.count
].data
= (SecProtocolType
*)&protocol
;
260 if ((UInt32
)authenticationType
!= 0) {
261 attrs
[attrList
.count
].tag
= kSecAuthenticationTypeItemAttr
;
262 attrs
[attrList
.count
].length
= sizeof(SecAuthenticationType
);
263 attrs
[attrList
.count
].data
= (SecAuthenticationType
*)&authenticationType
;
267 status
= SecKeychainSearchCreateFromAttributes(keychainOrArray
, kSecInternetPasswordItemClass
, &attrList
, &searchRef
);
269 sec_perror("SecKeychainSearchCreateFromAttributes", status
);
272 // we're only interested in the first match, if there is a match at all
273 status
= SecKeychainSearchCopyNext(searchRef
, &itemRef
);
280 CFRelease(searchRef
);
285 // find_unique_certificate
287 // Returns a SecKeychainItemRef for the certificate
288 // in the specified keychain (or keychain list)
289 // which is a unique match for either the specified name
290 // or SHA-1 hash. If more than one match exists, the
291 // certificate is not unique and none are returned. Caller is
292 // responsible for releasing the item (with CFRelease).
295 find_unique_certificate(CFTypeRef keychainOrArray
,
299 OSStatus status
= noErr
;
300 SecKeychainSearchRef searchRef
= NULL
;
301 SecKeychainItemRef uniqueItemRef
= NULL
;
303 status
= SecKeychainSearchCreateFromAttributes(keychainOrArray
, kSecCertificateItemClass
, NULL
, &searchRef
);
305 return uniqueItemRef
;
308 // check input hash string and convert to data
309 CSSM_DATA hashData
= { 0, NULL
};
311 CSSM_SIZE len
= strlen(hash
)/2;
312 hashData
.Length
= len
;
313 hashData
.Data
= (uint8
*)malloc(hashData
.Length
);
314 fromHex(hash
, &hashData
);
317 // filter candidates against the hash (or the name, if no hash provided)
318 CFStringRef matchRef
= (name
) ? CFStringCreateWithCString(NULL
, name
, kCFStringEncodingUTF8
) : NULL
;
319 Boolean exactMatch
= FALSE
;
321 CSSM_DATA certData
= { 0, NULL
};
322 SecKeychainItemRef candidate
= NULL
;
324 while (SecKeychainSearchCopyNext(searchRef
, &candidate
) == noErr
) {
325 SecCertificateRef cert
= (SecCertificateRef
)candidate
;
326 if (SecCertificateGetData(cert
, &certData
) != noErr
) {
327 safe_CFRelease(&candidate
);
331 uint8 candidate_sha1_hash
[20];
333 digest
.Length
= sizeof(candidate_sha1_hash
);
334 digest
.Data
= candidate_sha1_hash
;
335 if ((SecDigestGetData(CSSM_ALGID_SHA1
, &digest
, &certData
) == CSSM_OK
) &&
336 (hashData
.Length
== digest
.Length
) &&
337 (!memcmp(hashData
.Data
, digest
.Data
, digest
.Length
))) {
339 uniqueItemRef
= candidate
; // currently retained
340 break; // we're done - can't get more exact than this
343 // copy certificate name
344 CFStringRef nameRef
= NULL
;
345 if ((SecCertificateCopyCommonName(cert
, &nameRef
) != noErr
) || nameRef
== NULL
) {
346 safe_CFRelease(&candidate
);
347 continue; // no name, so no match is possible
349 CFIndex nameLen
= CFStringGetLength(nameRef
);
350 CFIndex bufLen
= 1 + CFStringGetMaximumSizeForEncoding(nameLen
, kCFStringEncodingUTF8
);
351 char *nameBuf
= (char *)malloc(bufLen
);
352 if (!CFStringGetCString(nameRef
, nameBuf
, bufLen
-1, kCFStringEncodingUTF8
))
355 CFRange find
= { kCFNotFound
, 0 };
356 if (nameRef
&& matchRef
)
357 find
= CFStringFind(nameRef
, matchRef
, kCFCompareCaseInsensitive
| kCFCompareNonliteral
);
358 Boolean isExact
= (find
.location
== 0 && find
.length
== nameLen
);
359 if (find
.location
== kCFNotFound
) {
361 safe_CFRelease(&nameRef
);
362 safe_CFRelease(&candidate
);
363 continue; // no match
365 if (uniqueItemRef
) { // got two matches
366 if (exactMatch
&& !isExact
) { // prior is better; ignore this one
368 safe_CFRelease(&nameRef
);
369 safe_CFRelease(&candidate
);
372 if (exactMatch
== isExact
) { // same class of match
373 if (CFEqual(uniqueItemRef
, candidate
)) { // same certificate
375 safe_CFRelease(&nameRef
);
376 safe_CFRelease(&candidate
);
379 // ambiguity - must fail
380 sec_error("\"%s\" is ambiguous, matches more than one certificate", name
);
382 safe_CFRelease(&nameRef
);
383 safe_CFRelease(&candidate
);
384 safe_CFRelease(&uniqueItemRef
);
387 safe_CFRelease(&uniqueItemRef
); // about to replace with this one
389 uniqueItemRef
= candidate
; // currently retained
390 exactMatch
= isExact
;
392 safe_CFRelease(&nameRef
);
396 safe_CFRelease(&searchRef
);
397 safe_CFRelease(&matchRef
);
402 return uniqueItemRef
;
406 do_password_item_printing( SecKeychainItemRef itemRef
,
407 Boolean get_password
,
408 Boolean password_stdout
)
410 OSStatus result
= noErr
;
411 void *passwordData
= NULL
;
412 UInt32 passwordLength
= 0;
415 result
= SecKeychainItemCopyContent(itemRef
, NULL
, NULL
, &passwordLength
, &passwordData
);
416 if(result
!= noErr
) return result
;
418 if(!password_stdout
) {
419 print_keychain_item_attributes(stdout
, itemRef
, FALSE
, FALSE
, FALSE
, FALSE
);
421 fputs("password: ", stderr
);
422 print_buffer(stderr
, passwordLength
, passwordData
);
426 char *password
= (char *) passwordData
;
428 for(uint32_t i
=0; i
<passwordLength
; i
++) if(!isprint(password
[i
])) doHex
= 1;
430 for(uint32_t i
=0; i
<passwordLength
; i
++) printf("%02x", password
[i
]);
432 for(uint32_t i
=0; i
<passwordLength
; i
++) putchar(password
[i
]);
437 if (passwordData
) SecKeychainItemFreeContent(NULL
, passwordData
);
443 do_keychain_find_generic_password(CFTypeRef keychainOrArray
,
444 FourCharCode itemCreator
,
445 FourCharCode itemType
,
450 const char *serviceName
,
451 const char *accountName
,
452 Boolean get_password
,
453 Boolean password_stdout
)
455 OSStatus result
= noErr
;
456 SecKeychainItemRef itemRef
= NULL
;
458 itemRef
= find_first_generic_password(keychainOrArray
,
469 result
= do_password_item_printing(itemRef
, get_password
, password_stdout
);
471 result
= errSecItemNotFound
;
472 sec_perror("SecKeychainSearchCopyNext", result
);
475 if (itemRef
) CFRelease(itemRef
);
481 do_keychain_delete_generic_password(CFTypeRef keychainOrArray
,
482 FourCharCode itemCreator
,
483 FourCharCode itemType
,
488 const char *serviceName
,
489 const char *accountName
)
491 OSStatus result
= noErr
;
492 SecKeychainItemRef itemRef
= NULL
;
493 void *passwordData
= NULL
;
495 itemRef
= find_first_generic_password(keychainOrArray
,
505 result
= errSecItemNotFound
;
506 sec_perror("SecKeychainSearchCopyNext", result
);
510 print_keychain_item_attributes(stdout
, itemRef
, FALSE
, FALSE
, FALSE
, FALSE
);
512 result
= SecKeychainItemDelete(itemRef
);
514 fputs("password has been deleted.\n", stderr
);
518 SecKeychainItemFreeContent(NULL
, passwordData
);
526 do_keychain_find_internet_password(CFTypeRef keychainOrArray
,
527 FourCharCode itemCreator
,
528 FourCharCode itemType
,
532 const char *serverName
,
533 const char *securityDomain
,
534 const char *accountName
,
537 SecProtocolType protocol
,
538 SecAuthenticationType authenticationType
,
539 Boolean get_password
,
540 Boolean password_stdout
)
542 OSStatus result
= noErr
;
543 SecKeychainItemRef itemRef
= NULL
;
545 itemRef
= find_first_internet_password(keychainOrArray
,
559 result
= do_password_item_printing(itemRef
, get_password
, password_stdout
);
561 result
= errSecItemNotFound
;
562 sec_perror("SecKeychainSearchCopyNext", result
);
569 do_keychain_delete_internet_password(CFTypeRef keychainOrArray
,
570 FourCharCode itemCreator
,
571 FourCharCode itemType
,
575 const char *serverName
,
576 const char *securityDomain
,
577 const char *accountName
,
580 SecProtocolType protocol
,
581 SecAuthenticationType authenticationType
)
583 OSStatus result
= noErr
;
584 SecKeychainItemRef itemRef
= NULL
;
585 void *passwordData
= NULL
;
587 itemRef
= find_first_internet_password(keychainOrArray
,
601 result
= errSecItemNotFound
;
602 sec_perror("SecKeychainSearchCopyNext", result
);
606 print_keychain_item_attributes(stdout
, itemRef
, FALSE
, FALSE
, FALSE
, FALSE
);
608 result
= SecKeychainItemDelete(itemRef
);
610 fputs("password has been deleted.\n", stderr
);
614 SecKeychainItemFreeContent(NULL
, passwordData
);
622 do_keychain_find_certificate(CFTypeRef keychainOrArray
,
624 const char *emailAddress
,
630 OSStatus result
= noErr
;
631 SecCertificateRef certificateRef
= NULL
;
632 SecKeychainSearchRef searchRef
= NULL
;
633 CFStringRef matchRef
= (name
) ? CFStringCreateWithCString(NULL
, name
, kCFStringEncodingUTF8
) : NULL
;
635 if (find_all
&& emailAddress
) {
636 result
= SecKeychainSearchCreateForCertificateByEmail(keychainOrArray
, emailAddress
, &searchRef
);
638 sec_perror("SecKeychainSearchCreateForCertificateByEmail", result
);
642 result
= SecKeychainSearchCreateFromAttributes(keychainOrArray
, kSecCertificateItemClass
, NULL
, &searchRef
);
644 sec_perror("SecKeychainSearchCreateFromAttributes", result
);
652 SecKeychainItemRef itemRef
= NULL
;
653 result
= SecKeychainSearchCopyNext(searchRef
, &itemRef
);
654 if (result
== errSecItemNotFound
) {
659 sec_perror("SecKeychainSearchCopyNext", result
);
663 if (!emailAddress
&& name
) {
664 // match name in common name
665 CFStringRef nameRef
= NULL
;
666 if (SecCertificateCopyCommonName((SecCertificateRef
)itemRef
, &nameRef
) != noErr
) {
667 safe_CFRelease(&itemRef
);
668 continue; // no name, so no match is possible
670 CFRange find
= { kCFNotFound
, 0 };
671 if (nameRef
&& matchRef
)
672 find
= CFStringFind(nameRef
, matchRef
, kCFCompareCaseInsensitive
| kCFCompareNonliteral
);
673 if (find
.location
== kCFNotFound
) {
674 safe_CFRelease(&nameRef
);
675 safe_CFRelease(&itemRef
);
676 continue; // no match
678 safe_CFRelease(&nameRef
);
680 safe_CFRelease(&certificateRef
);
681 certificateRef
= (SecCertificateRef
) itemRef
;
683 else { // only want the first match
685 result
= SecCertificateFindByEmail(keychainOrArray
, emailAddress
, &certificateRef
);
687 sec_perror("SecCertificateFindByEmail", result
);
691 SecKeychainItemRef itemRef
= NULL
;
692 while ((result
= SecKeychainSearchCopyNext(searchRef
, &itemRef
)) != errSecItemNotFound
) {
694 // match name in common name
695 CFStringRef nameRef
= NULL
;
696 if (SecCertificateCopyCommonName((SecCertificateRef
)itemRef
, &nameRef
) != noErr
) {
697 safe_CFRelease(&itemRef
);
698 continue; // no name, so no match is possible
700 CFRange find
= { kCFNotFound
, 0 };
701 if (nameRef
&& matchRef
)
702 find
= CFStringFind(nameRef
, matchRef
, kCFCompareCaseInsensitive
| kCFCompareNonliteral
);
703 if (find
.location
== kCFNotFound
) {
704 safe_CFRelease(&nameRef
);
705 safe_CFRelease(&itemRef
);
706 continue; // no match
708 safe_CFRelease(&nameRef
);
710 break; // we have a match!
712 if (result
== errSecItemNotFound
) {
713 sec_perror("SecKeychainSearchCopyNext", result
);
716 certificateRef
= (SecCertificateRef
) itemRef
;
720 // process the found certificate
726 digest
.Length
= sizeof(sha1_hash
);
727 digest
.Data
= sha1_hash
;
728 if ((SecCertificateGetData(certificateRef
, &data
) == noErr
) &&
729 (SecDigestGetData(CSSM_ALGID_SHA1
, &digest
, &data
) == CSSM_OK
)) {
731 size_t len
= digest
.Length
;
732 uint8
*cp
= digest
.Data
;
733 fprintf(stdout
, "SHA-1 hash: ");
734 for(i
=0; i
<len
; i
++) {
735 fprintf(stdout
, "%02X", ((unsigned char *)cp
)[i
]);
737 fprintf(stdout
, "\n");
743 CFArrayRef emailAddresses
= NULL
;
745 result
= SecCertificateCopyEmailAddresses(certificateRef
, &emailAddresses
);
748 sec_perror("SecCertificateCopyEmailAddresses", result
);
752 count
= CFArrayGetCount(emailAddresses
);
753 fputs("email addresses: ", stdout
);
754 for (ix
= 0; ix
< count
; ++ix
)
756 CFStringRef emailAddress
= (CFStringRef
)CFArrayGetValueAtIndex(emailAddresses
, ix
);
763 addr
= CFStringGetCStringPtr(emailAddress
, kCFStringEncodingUTF8
);
766 if (CFStringGetCString(emailAddress
, buffer
, sizeof(buffer
), kCFStringEncodingUTF8
))
770 fprintf(stdout
, "%s", addr
);
774 CFRelease(emailAddresses
);
779 CSSM_DATA certData
= {};
780 result
= SecCertificateGetData(certificateRef
, &certData
);
783 sec_perror("SecCertificateGetData", result
);
787 print_buffer_pem(stdout
, "CERTIFICATE", certData
.Length
, certData
.Data
);
791 print_keychain_item_attributes(stdout
, (SecKeychainItemRef
)certificateRef
, FALSE
, FALSE
, FALSE
, FALSE
);
796 safe_CFRelease(&searchRef
);
797 safe_CFRelease(&certificateRef
);
798 safe_CFRelease(&matchRef
);
804 keychain_delete_internet_password(int argc
, char * const *argv
)
806 char *serverName
= NULL
, *securityDomain
= NULL
, *accountName
= NULL
, *path
= NULL
;
807 char *kind
= NULL
, *label
= NULL
, *comment
= NULL
;
808 FourCharCode itemCreator
= 0, itemType
= 0;
810 SecProtocolType protocol
= 0;
811 SecAuthenticationType authenticationType
= 0;
812 CFTypeRef keychainOrArray
= NULL
;
816 * " -a Match \"account\" string\n"
817 * " -c Match \"creator\" (four-character code)\n"
818 * " -C Match \"type\" (four-character code)\n"
819 * " -d Match \"securityDomain\" string\n"
820 * " -D Match \"kind\" string\n"
821 * " -j Match \"comment\" string\n"
822 * " -l Match \"label\" string\n"
823 * " -p Match \"path\" string\n"
824 * " -P Match port number\n"
825 * " -r Match \"protocol\" (four-character code)\n"
826 * " -s Match \"server\" string\n"
827 * " -t Match \"authenticationType\" (four-character code)\n"
830 while ((ch
= getopt(argc
, argv
, "ha:c:C:d:D:hgj:l:p:P:r:s:t:")) != -1)
835 accountName
= optarg
;
838 result
= parse_fourcharcode(optarg
, &itemCreator
);
839 if (result
) goto cleanup
;
842 result
= parse_fourcharcode(optarg
, &itemType
);
843 if (result
) goto cleanup
;
846 securityDomain
= optarg
;
864 result
= parse_fourcharcode(optarg
, &protocol
);
865 if (result
) goto cleanup
;
871 result
= parse_fourcharcode(optarg
, &authenticationType
);
872 if (result
) goto cleanup
;
876 result
= 2; /* @@@ Return 2 triggers usage message. */
884 keychainOrArray
= keychain_create_array(argc
, argv
);
886 result
= do_keychain_delete_internet_password(keychainOrArray
,
901 CFRelease(keychainOrArray
);
907 keychain_find_internet_password(int argc
, char * const *argv
)
909 char *serverName
= NULL
, *securityDomain
= NULL
, *accountName
= NULL
, *path
= NULL
;
910 char *kind
= NULL
, *label
= NULL
, *comment
= NULL
;
911 FourCharCode itemCreator
= 0, itemType
= 0;
913 SecProtocolType protocol
= 0;
914 SecAuthenticationType authenticationType
= 0;
915 CFTypeRef keychainOrArray
= NULL
;
917 Boolean get_password
= FALSE
;
918 Boolean password_stdout
= FALSE
;
921 * " -a Match \"account\" string\n"
922 * " -c Match \"creator\" (four-character code)\n"
923 * " -C Match \"type\" (four-character code)\n"
924 * " -d Match \"securityDomain\" string\n"
925 * " -D Match \"kind\" string\n"
926 * " -j Match \"comment\" string\n"
927 * " -l Match \"label\" string\n"
928 * " -p Match \"path\" string\n"
929 * " -P Match port number\n"
930 * " -r Match \"protocol\" (four-character code)\n"
931 * " -s Match \"server\" string\n"
932 * " -t Match \"authenticationType\" (four-character code)\n"
933 * " -g Display the password for the item found\n"
934 * " -w Display the password(only) for the item(s) found\n"
937 while ((ch
= getopt(argc
, argv
, "ha:c:C:d:D:hgj:l:p:P:r:s:wt:")) != -1)
942 accountName
= optarg
;
945 result
= parse_fourcharcode(optarg
, &itemCreator
);
946 if (result
) goto cleanup
;
949 result
= parse_fourcharcode(optarg
, &itemType
);
950 if (result
) goto cleanup
;
953 securityDomain
= optarg
;
974 result
= parse_fourcharcode(optarg
, &protocol
);
975 if (result
) goto cleanup
;
982 password_stdout
= TRUE
;
985 result
= parse_fourcharcode(optarg
, &authenticationType
);
986 if (result
) goto cleanup
;
987 /* auth type attribute is special */
988 authenticationType
= OSSwapHostToBigInt32(authenticationType
);
992 result
= 2; /* @@@ Return 2 triggers usage message. */
1000 keychainOrArray
= keychain_create_array(argc
, argv
);
1002 result
= do_keychain_find_internet_password(keychainOrArray
,
1018 if (keychainOrArray
)
1019 CFRelease(keychainOrArray
);
1025 keychain_delete_generic_password(int argc
, char * const *argv
)
1027 char *serviceName
= NULL
, *accountName
= NULL
;
1028 char *kind
= NULL
, *label
= NULL
, *value
= NULL
, *comment
= NULL
;
1029 FourCharCode itemCreator
= 0, itemType
= 0;
1030 CFTypeRef keychainOrArray
= nil
;
1034 * " -a Match \"account\" string\n"
1035 * " -c Match \"creator\" (four-character code)\n"
1036 * " -C Match \"type\" (four-character code)\n"
1037 * " -D Match \"kind\" string\n"
1038 * " -G Match \"value\" string (generic attribute)\n"
1039 * " -j Match \"comment\" string\n"
1040 * " -l Match \"label\" string\n"
1041 * " -s Match \"service\" string\n"
1044 while ((ch
= getopt(argc
, argv
, "ha:c:C:D:G:j:l:s:g")) != -1)
1049 accountName
= optarg
;
1052 result
= parse_fourcharcode(optarg
, &itemCreator
);
1053 if (result
) goto cleanup
;
1056 result
= parse_fourcharcode(optarg
, &itemType
);
1057 if (result
) goto cleanup
;
1072 serviceName
= optarg
;
1076 result
= 2; /* @@@ Return 2 triggers usage message. */
1084 keychainOrArray
= keychain_create_array(argc
, argv
);
1086 result
= do_keychain_delete_generic_password(keychainOrArray
,
1096 if (keychainOrArray
)
1097 CFRelease(keychainOrArray
);
1103 keychain_find_generic_password(int argc
, char * const *argv
)
1105 char *serviceName
= NULL
, *accountName
= NULL
;
1106 char *kind
= NULL
, *label
= NULL
, *value
= NULL
, *comment
= NULL
;
1107 FourCharCode itemCreator
= 0, itemType
= 0;
1108 CFTypeRef keychainOrArray
= nil
;
1110 Boolean get_password
= FALSE
;
1111 Boolean password_stdout
= FALSE
;
1114 * " -a Match \"account\" string\n"
1115 * " -c Match \"creator\" (four-character code)\n"
1116 * " -C Match \"type\" (four-character code)\n"
1117 * " -D Match \"kind\" string\n"
1118 * " -G Match \"value\" string (generic attribute)\n"
1119 * " -j Match \"comment\" string\n"
1120 * " -l Match \"label\" string\n"
1121 * " -s Match \"service\" string\n"
1122 * " -g Display the password for the item(s) found\n"
1123 * " -w Display the password(only) for the item(s) found\n"
1126 while ((ch
= getopt(argc
, argv
, "ha:c:C:D:G:j:l:s:wg")) != -1)
1131 accountName
= optarg
;
1134 result
= parse_fourcharcode(optarg
, &itemCreator
);
1135 if (result
) goto cleanup
;
1138 result
= parse_fourcharcode(optarg
, &itemType
);
1139 if (result
) goto cleanup
;
1154 serviceName
= optarg
;
1157 password_stdout
= TRUE
;
1158 get_password
= TRUE
;
1161 get_password
= TRUE
;
1165 result
= 2; /* @@@ Return 2 triggers usage message. */
1173 keychainOrArray
= keychain_create_array(argc
, argv
);
1175 result
= do_keychain_find_generic_password(keychainOrArray
,
1187 if (keychainOrArray
)
1188 CFRelease(keychainOrArray
);
1193 #define SetKeyToString(dict, key, arg) \
1195 CFStringRef str = CFStringCreateWithCStringNoCopy(NULL, arg, kCFStringEncodingUTF8, kCFAllocatorNull); \
1196 CFDictionarySetValue(dict, key, str); \
1197 CFReleaseNull(str); \
1201 keychain_find_key(int argc
, char * const *argv
) {
1203 * " -a Match \"application label\" string\n"
1204 * " -c Match \"creator\" (four-character code)\n"
1205 * " -d Match keys that can decrypt\n"
1206 * " -D Match \"description\" string\n"
1207 * " -e Match keys that can encrypt\n"
1208 * " -j Match \"comment\" string\n"
1209 * " -l Match \"label\" string\n"
1210 * " -r Match keys that can derive\n"
1211 * " -s Match keys that can sign\n"
1212 * " -t Type of key to find: one of \"symmetric\", \"public\", or \"private\"\n"
1213 * " -u Match keys that can unwrap\n"
1214 * " -v Match keys that can verify\n"
1215 * " -w Match keys that can wrap\n"
1218 CFMutableDictionaryRef query
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1219 CFDictionarySetValue(query
, kSecClass
, kSecClassKey
);
1220 CFDictionarySetValue(query
, kSecMatchLimit
, kSecMatchLimitAll
);
1222 CFTypeRef results
= NULL
;
1225 while ((ch
= getopt(argc
, argv
, "a:c:dD:ej:l:rst:uvw")) != -1)
1230 SetKeyToString(query
, kSecAttrApplicationLabel
, optarg
);
1233 SetKeyToString(query
, kSecAttrCreator
, optarg
);
1236 CFDictionarySetValue(query
, kSecAttrCanDecrypt
, kCFBooleanTrue
);
1239 SetKeyToString(query
, kSecAttrDescription
, optarg
);
1242 CFDictionarySetValue(query
, kSecAttrCanEncrypt
, kCFBooleanTrue
);
1245 SetKeyToString(query
, kSecAttrComment
, optarg
);
1248 SetKeyToString(query
, kSecAttrLabel
, optarg
);
1251 CFDictionarySetValue(query
, kSecAttrCanDerive
, kCFBooleanTrue
);
1254 CFDictionarySetValue(query
, kSecAttrCanSign
, kCFBooleanTrue
);
1257 if(strcmp(optarg
, "symmetric") == 0) {
1258 CFDictionarySetValue(query
, kSecAttrKeyClass
, kSecAttrKeyClassSymmetric
);
1259 } else if(strcmp(optarg
, "public") == 0) {
1260 CFDictionarySetValue(query
, kSecAttrKeyClass
, kSecAttrKeyClassPublic
);
1261 } else if(strcmp(optarg
, "private") == 0) {
1262 CFDictionarySetValue(query
, kSecAttrKeyClass
, kSecAttrKeyClassPrivate
);
1269 CFDictionarySetValue(query
, kSecAttrCanUnwrap
, kCFBooleanTrue
);
1272 CFDictionarySetValue(query
, kSecAttrCanVerify
, kCFBooleanTrue
);
1275 CFDictionarySetValue(query
, kSecAttrCanWrap
, kCFBooleanTrue
);
1287 CFTypeRef keychainOrArray
= keychain_create_array(argc
, argv
);
1289 if(keychainOrArray
&& CFGetTypeID(keychainOrArray
) == CFArrayGetTypeID()) {
1290 CFDictionarySetValue(query
, kSecMatchSearchList
, keychainOrArray
);
1291 } else if(keychainOrArray
) {
1292 // if it's not an array (but is something), it's a keychain. Put it in an array.
1293 CFMutableArrayRef searchList
= (CFMutableArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 1, &kCFTypeArrayCallBacks
);
1294 CFArrayAppendValue((CFMutableArrayRef
)searchList
, keychainOrArray
);
1295 CFDictionarySetValue(query
, kSecMatchSearchList
, searchList
);
1296 CFRelease(searchList
);
1298 CFReleaseNull(keychainOrArray
);
1300 OSStatus status
= SecItemCopyMatching(query
, &results
);
1302 sec_perror("SecItemCopyMatching", status
);
1307 if (CFGetTypeID(results
) == CFArrayGetTypeID()) {
1308 for(int i
= 0; i
< CFArrayGetCount(results
); i
++) {
1309 SecKeychainItemRef item
= (SecKeychainItemRef
) CFArrayGetValueAtIndex(results
, i
);
1311 print_keychain_item_attributes(stdout
, item
, FALSE
, FALSE
, FALSE
, FALSE
);
1316 safe_CFRelease(&results
);
1317 safe_CFRelease(&query
);
1321 // Declare here to use later.
1322 int keychain_set_partition_list(SecKeychainRef kc
, CFDictionaryRef query
, CFStringRef password
, CFStringRef partitionlist
);
1323 int keychain_parse_args_and_set_partition_list(int argc
, char * const *argv
, CFMutableDictionaryRef query
, CFStringRef partitionidsinput
, CFStringRef password
);
1325 int keychain_set_internet_password_partition_list(int argc
, char * const *argv
) {
1327 * " -a Match \"account\" string\n"
1328 * " -c Match \"creator\" (four-character code)\n"
1329 * " -C Match \"type\" (four-character code)\n"
1330 * " -d Match \"securityDomain\" string\n"
1331 * " -D Match \"kind\" string\n"
1332 * " -j Match \"comment\" string\n"
1333 * " -l Match \"label\" string\n"
1334 * " -p Match \"path\" string\n"
1335 * " -P Match port number\n"
1336 * " -r Match \"protocol\" (four-character code)\n"
1337 * " -s Match \"server\" string\n"
1338 * " -t Match \"authenticationType\" (four-character code)\n"
1339 * " -S Comma-separated list of allowed partition IDs"
1340 * " -k password for keychain"
1343 CFMutableDictionaryRef query
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1344 CFDictionarySetValue(query
, kSecClass
, kSecClassInternetPassword
);
1345 CFDictionarySetValue(query
, kSecMatchLimit
, kSecMatchLimitAll
);
1347 CFStringRef partitionidsinput
= NULL
;
1348 CFStringRef password
= NULL
;
1351 while ((ch
= getopt(argc
, argv
, "a:c:C:d:D:j:l:p:P:r:s:S:t:k:")) != -1)
1356 SetKeyToString(query
, kSecAttrAccount
, optarg
);
1359 SetKeyToString(query
, kSecAttrCreator
, optarg
);
1362 SetKeyToString(query
, kSecAttrType
, optarg
);
1365 SetKeyToString(query
, kSecAttrSecurityDomain
, optarg
);
1368 SetKeyToString(query
, kSecAttrDescription
, optarg
);
1371 SetKeyToString(query
, kSecAttrComment
, optarg
);
1374 SetKeyToString(query
, kSecAttrLabel
, optarg
);
1377 SetKeyToString(query
, kSecAttrPath
, optarg
);
1380 SetKeyToString(query
, kSecAttrPort
, optarg
);
1383 SetKeyToString(query
, kSecAttrProtocol
, optarg
);
1386 SetKeyToString(query
, kSecAttrServer
, optarg
);
1389 SetKeyToString(query
, kSecAttrAuthenticationType
, optarg
);
1392 CFReleaseNull(partitionidsinput
);
1393 partitionidsinput
= CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1396 CFReleaseNull(password
);
1397 password
= CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1409 result
= keychain_parse_args_and_set_partition_list(argc
, argv
, query
, partitionidsinput
, password
);
1412 safe_CFRelease(&password
);
1413 safe_CFRelease(&partitionidsinput
);
1414 safe_CFRelease(&query
);
1419 keychain_set_generic_password_partition_list(int argc
, char * const *argv
) {
1420 CFMutableDictionaryRef query
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1422 // -a Match \"account\" string
1423 // -c Match \"creator\" (four-character code)
1424 // -C Match \"type\" (four-character code)
1425 // -D Match \"kind\" string
1426 // -G Match \"value\" string (generic attribute)
1427 // -j Match \"comment\" string
1428 // -l Match \"label\" string
1429 // -s Match \"service\" string
1430 // -S Comma-separated list of allowed partition IDs
1431 // -k password for keychain
1433 CFDictionarySetValue(query
, kSecClass
, kSecClassGenericPassword
);
1434 CFDictionarySetValue(query
, kSecMatchLimit
, kSecMatchLimitAll
);
1436 CFStringRef partitionidsinput
= NULL
;
1437 CFStringRef password
= NULL
;
1440 while ((ch
= getopt(argc
, argv
, ":a:c:C:D:G:j:l:s:S:k:")) != -1)
1445 SetKeyToString(query
, kSecAttrAccount
, optarg
);
1448 SetKeyToString(query
, kSecAttrCreator
, optarg
);
1451 SetKeyToString(query
, kSecAttrType
, optarg
);
1454 SetKeyToString(query
, kSecAttrDescription
, optarg
);
1457 SetKeyToString(query
, kSecAttrGeneric
, optarg
);
1460 SetKeyToString(query
, kSecAttrComment
, optarg
);
1463 SetKeyToString(query
, kSecAttrLabel
, optarg
);
1466 SetKeyToString(query
, kSecAttrService
, optarg
);
1469 CFReleaseNull(partitionidsinput
);
1470 partitionidsinput
= CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1473 CFReleaseNull(password
);
1474 password
= CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1478 // They supplied the -k but with no data
1479 // Leaving it null will cause prompt below
1480 if (optopt
== 'k') {
1484 goto cleanup
; /* @@@ Return 2 triggers usage message. */
1494 result
= keychain_parse_args_and_set_partition_list(argc
, argv
, query
, partitionidsinput
, password
);
1497 safe_CFRelease(&password
);
1498 safe_CFRelease(&partitionidsinput
);
1499 safe_CFRelease(&query
);
1504 keychain_set_key_partition_list(int argc
, char * const *argv
) {
1506 * " -a Match \"application label\" string\n"
1507 * " -c Match \"creator\" (four-character code)\n"
1508 * " -d Match keys that can decrypt\n"
1509 * " -D Match \"description\" string\n"
1510 * " -e Match keys that can encrypt\n"
1511 * " -j Match \"comment\" string\n"
1512 * " -l Match \"label\" string\n"
1513 * " -r Match keys that can derive\n"
1514 * " -s Match keys that can sign\n"
1515 * " -t Type of key to find: one of \"symmetric\", \"public\", or \"private\"\n"
1516 * " -u Match keys that can unwrap\n"
1517 * " -v Match keys that can verify\n"
1518 * " -w Match keys that can wrap\n"
1519 * " -S Comma-separated list of allowed partition IDs
1520 * " -k password for keychain (required)
1523 CFMutableDictionaryRef query
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1524 CFDictionarySetValue(query
, kSecClass
, kSecClassKey
);
1525 CFDictionarySetValue(query
, kSecMatchLimit
, kSecMatchLimitAll
);
1527 CFStringRef partitionidsinput
= NULL
;
1528 CFStringRef password
= NULL
;
1531 while ((ch
= getopt(argc
, argv
, ":a:c:dD:ej:k:l:rsS:t:uvw")) != -1)
1536 SetKeyToString(query
, kSecAttrApplicationLabel
, optarg
);
1539 SetKeyToString(query
, kSecAttrCreator
, optarg
);
1542 SetKeyToString(query
, kSecAttrCanDecrypt
, optarg
);
1543 CFDictionarySetValue(query
, kSecAttrCanDecrypt
, kCFBooleanTrue
);
1546 SetKeyToString(query
, kSecAttrDescription
, optarg
);
1549 CFDictionarySetValue(query
, kSecAttrCanEncrypt
, kCFBooleanTrue
);
1552 SetKeyToString(query
, kSecAttrComment
, optarg
);
1555 SetKeyToString(query
, kSecAttrLabel
, optarg
);
1558 CFDictionarySetValue(query
, kSecAttrCanDerive
, kCFBooleanTrue
);
1560 CFDictionarySetValue(query
, kSecAttrCanSign
, kCFBooleanTrue
);
1563 if(strcmp(optarg
, "symmetric") == 0) {
1564 CFDictionarySetValue(query
, kSecAttrKeyClass
, kSecAttrKeyClassSymmetric
);
1565 } else if(strcmp(optarg
, "public") == 0) {
1566 CFDictionarySetValue(query
, kSecAttrKeyClass
, kSecAttrKeyClassPublic
);
1567 } else if(strcmp(optarg
, "private") == 0) {
1568 CFDictionarySetValue(query
, kSecAttrKeyClass
, kSecAttrKeyClassPrivate
);
1575 CFDictionarySetValue(query
, kSecAttrCanUnwrap
, kCFBooleanTrue
);
1578 CFDictionarySetValue(query
, kSecAttrCanVerify
, kCFBooleanTrue
);
1581 CFDictionarySetValue(query
, kSecAttrCanWrap
, kCFBooleanTrue
);
1584 CFReleaseNull(partitionidsinput
);
1585 partitionidsinput
= CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1588 CFReleaseNull(password
);
1589 password
= CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1593 // They supplied the -k but with no data
1594 // Leaving it null will cause prompt below
1595 if (optopt
== 'k') {
1599 goto cleanup
; /* @@@ Return 2 triggers usage message. */
1609 result
= keychain_parse_args_and_set_partition_list(argc
, argv
, query
, partitionidsinput
, password
);
1612 CFReleaseNull(partitionidsinput
);
1613 CFReleaseNull(password
);
1614 safe_CFRelease(&query
);
1619 int keychain_parse_args_and_set_partition_list(int argc
, char * const *argv
, CFMutableDictionaryRef query
, CFStringRef partitionidsinput
, CFStringRef password
) {
1621 const char *keychainName
= NULL
;
1622 SecKeychainRef kc
= NULL
;
1623 CFStringRef localPassword
= NULL
;
1625 // if we were given a keychain, use it
1628 keychainName
= argv
[0];
1629 if (*keychainName
== '\0')
1635 kc
= keychain_open(keychainName
);
1637 sec_error("couldn't open \"%s\"", keychainName
);
1642 CFMutableArrayRef searchList
= (CFMutableArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 1, &kCFTypeArrayCallBacks
);
1643 CFArrayAppendValue((CFMutableArrayRef
)searchList
, kc
);
1644 CFDictionarySetValue(query
, kSecMatchSearchList
, searchList
);
1645 } else if (argc
!= 0) {
1650 if(!partitionidsinput
) {
1656 char* cpassword
= prompt_password(keychainName
);
1661 localPassword
= CFStringCreateWithCString(NULL
, cpassword
, kCFStringEncodingUTF8
);
1662 password
= localPassword
;
1666 result
= keychain_set_partition_list(kc
, query
, password
, partitionidsinput
);
1669 CFReleaseNull(localPassword
);
1674 int keychain_set_partition_list(SecKeychainRef kc
, CFDictionaryRef query
, CFStringRef password
, CFStringRef partitionlist
) {
1677 char *passwordBuf
= NULL
;
1679 GetCStringFromCFString(password
, &passwordBuf
, &passwordLen
);
1682 CFTypeRef results
= NULL
;
1684 // Unlock the keychain with the given password, since we'll be fetching ACLs
1685 status
= SecKeychainUnlock(kc
, (UInt32
) passwordLen
, passwordBuf
, true);
1687 sec_perror("SecKeychainUnlock", status
);
1692 status
= SecItemCopyMatching(query
, &results
);
1694 sec_perror("SecItemCopyMatching", status
);
1704 if (CFGetTypeID(results
) == CFArrayGetTypeID()) {
1705 for(int i
= 0; i
< CFArrayGetCount(results
); i
++) {
1706 SecKeychainItemRef item
= (SecKeychainItemRef
) CFArrayGetValueAtIndex(results
, i
);
1707 SecAccessRef access
= NULL
;
1709 do_password_item_printing(item
, false, false);
1711 status
= SecKeychainItemCopyAccess(item
, &access
);
1712 if (status
== errSecNoAccessForItem
) {
1716 sec_perror("SecKeychainItemCopyAccess", status
);
1721 CFArrayRef aclList
= NULL
;
1722 status
= SecAccessCopyACLList(access
, &aclList
);
1725 sec_perror("SecAccessCopyACLList", status
);
1730 CFIndex size
= CFArrayGetCount(aclList
);
1731 for(CFIndex i
= 0; i
< size
; i
++) {
1732 SecACLRef acl
= (SecACLRef
) CFArrayGetValueAtIndex(aclList
, i
);
1733 CSSM_ACL_AUTHORIZATION_TAG tags
[64]; // Pick some upper limit
1734 uint32 tagix
, tagCount
= sizeof(tags
) / sizeof(*tags
);
1735 status
= SecACLGetAuthorizations(acl
, tags
, &tagCount
);
1739 sec_perror("SecACLGetAuthorizations", status
);
1744 CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector
= {};
1746 for (tagix
= 0; tagix
< tagCount
; ++tagix
)
1748 CSSM_ACL_AUTHORIZATION_TAG tag
= tags
[tagix
];
1749 if(tag
== CSSM_ACL_AUTHORIZATION_PARTITION_ID
) {
1751 CFArrayRef applicationList
;
1752 CFStringRef promptDescription
;
1754 status
= SecACLCopySimpleContents(acl
, &applicationList
, &promptDescription
, &promptSelector
);
1756 sec_perror("SecACLCopySimpleContents", status
);
1761 CFArrayRef partitionIDs
= CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault
, partitionlist
, CFSTR(","));
1762 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1763 CFDictionarySetValue(dict
, CFSTR("Partitions"), partitionIDs
);
1764 CFDataRef xml
= CFPropertyListCreateXMLData(NULL
, dict
);
1765 CFStringRef xmlstr
= cfToHex(xml
);
1767 SecACLSetSimpleContents(acl
, applicationList
, xmlstr
, &promptSelector
);
1769 safe_CFRelease(&xmlstr
);
1770 safe_CFRelease(&xml
);
1771 safe_CFRelease(&dict
);
1772 safe_CFRelease(&partitionIDs
);
1777 status
= SecKeychainItemSetAccessWithPassword(item
, access
, (UInt32
) passwordLen
, passwordBuf
);
1779 sec_perror("SecKeychainItemSetAccessWithPassword", status
);
1792 safe_CFRelease(&results
);
1800 keychain_find_certificate(int argc
, char * const *argv
)
1802 char *emailAddress
= NULL
;
1805 CFTypeRef keychainOrArray
= nil
;
1806 Boolean output_pem
= FALSE
;
1807 Boolean find_all
= FALSE
;
1808 Boolean print_hash
= FALSE
;
1809 Boolean print_email
= FALSE
;
1811 while ((ch
= getopt(argc
, argv
, "hac:e:mpZ")) != -1)
1822 emailAddress
= optarg
;
1835 result
= 2; /* @@@ Return 2 triggers usage message. */
1843 keychainOrArray
= keychain_create_array(argc
, argv
);
1845 result
= do_keychain_find_certificate(keychainOrArray
, name
, emailAddress
, print_hash
, output_pem
, find_all
, print_email
);
1848 if (keychainOrArray
)
1849 CFRelease(keychainOrArray
);
1856 do_keychain_dump_class(FILE *stream
, CFTypeRef keychainOrArray
, SecItemClass itemClass
, Boolean show_data
, Boolean show_raw_data
, Boolean show_acl
, Boolean interactive
)
1858 SecKeychainItemRef item
;
1859 SecKeychainSearchRef search
= NULL
;
1863 status
= SecKeychainSearchCreateFromAttributes(keychainOrArray
, itemClass
, NULL
, &search
);
1866 sec_perror("SecKeychainSearchCreateFromAttributes", status
);
1871 while ((status
= SecKeychainSearchCopyNext(search
, &item
)) == 0)
1873 print_keychain_item_attributes(stream
, item
, show_data
, show_raw_data
, show_acl
, interactive
);
1877 if (status
!= errSecItemNotFound
)
1879 sec_perror("SecKeychainSearchCopyNext", status
);
1892 do_keychain_dump(FILE *stream
, CFTypeRef keychainOrArray
, Boolean show_data
, Boolean show_raw_data
, Boolean show_acl
, Boolean interactive
)
1894 return do_keychain_dump_class(stream
, keychainOrArray
, CSSM_DL_DB_RECORD_ANY
, show_data
, show_raw_data
, show_acl
, interactive
);
1898 keychain_dump(int argc
, char * const *argv
)
1901 Boolean show_data
= FALSE
, show_raw_data
= FALSE
, show_acl
= FALSE
, interactive
= FALSE
;
1902 CFTypeRef keychainOrArray
= NULL
;
1903 const char *outputFilename
= NULL
;
1906 while ((ch
= getopt(argc
, argv
, "adhiro:")) != -1)
1921 show_raw_data
= TRUE
;
1924 outputFilename
= optarg
;
1928 return SHOW_USAGE_MESSAGE
;
1935 keychainOrArray
= keychain_create_array(argc
, argv
);
1938 output
= fopen(outputFilename
, "w");
1942 result
= do_keychain_dump(output
, keychainOrArray
, show_data
, show_raw_data
, show_acl
, interactive
);
1947 if (keychainOrArray
)
1948 CFRelease(keychainOrArray
);