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"
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>
48 // SecDigestGetData, SecKeychainSearchCreateForCertificateByEmail, SecCertificateFindByEmail
49 #include <Security/SecCertificatePriv.h>
51 Boolean gDeleteIt
= 0;
53 // find_first_generic_password
55 // Returns a SecKeychainItemRef for the first item
56 // which matches the specified attributes. Caller is
57 // responsible for releasing the item (with CFRelease).
60 find_first_generic_password(CFTypeRef keychainOrArray
,
61 FourCharCode itemCreator
,
62 FourCharCode itemType
,
67 const char *serviceName
,
68 const char *accountName
)
70 OSStatus status
= noErr
;
71 SecKeychainSearchRef searchRef
= NULL
;
72 SecKeychainItemRef itemRef
= NULL
;
74 SecKeychainAttribute attrs
[8]; // maximum number of searchable attributes
75 SecKeychainAttributeList attrList
= { 0, attrs
};
77 // the primary key for a generic password item (i.e. the combination of
78 // attributes which determine whether the item is unique) consists of:
79 // { kSecAccountItemAttr, kSecServiceItemAttr }
81 // if we have a primary key, we don't need to search on other attributes
82 // (and we don't want to, if non-primary attributes are being updated)
83 Boolean primaryKey
= (accountName
&& serviceName
);
85 // build the attribute list for searching
86 if ((UInt32
)itemCreator
!= 0 && !primaryKey
) {
87 attrs
[attrList
.count
].tag
= kSecCreatorItemAttr
;
88 attrs
[attrList
.count
].length
= sizeof(FourCharCode
);
89 attrs
[attrList
.count
].data
= (FourCharCode
*)&itemCreator
;
92 if ((UInt32
)itemType
!= 0 && !primaryKey
) {
93 attrs
[attrList
.count
].tag
= kSecTypeItemAttr
;
94 attrs
[attrList
.count
].length
= sizeof(FourCharCode
);
95 attrs
[attrList
.count
].data
= (FourCharCode
*)&itemType
;
98 if (kind
!= NULL
&& !primaryKey
) {
99 attrs
[attrList
.count
].tag
= kSecDescriptionItemAttr
;
100 attrs
[attrList
.count
].length
= (UInt32
) strlen(kind
);
101 attrs
[attrList
.count
].data
= (void*)kind
;
104 if (value
!= NULL
&& !primaryKey
) {
105 attrs
[attrList
.count
].tag
= kSecGenericItemAttr
;
106 attrs
[attrList
.count
].length
= (UInt32
) strlen(value
);
107 attrs
[attrList
.count
].data
= (void*)value
;
110 if (comment
!= NULL
&& !primaryKey
) {
111 attrs
[attrList
.count
].tag
= kSecCommentItemAttr
;
112 attrs
[attrList
.count
].length
= (UInt32
) strlen(comment
);
113 attrs
[attrList
.count
].data
= (void*)comment
;
116 if (label
!= NULL
&& !primaryKey
) {
117 attrs
[attrList
.count
].tag
= kSecLabelItemAttr
;
118 attrs
[attrList
.count
].length
= (UInt32
) strlen(label
);
119 attrs
[attrList
.count
].data
= (void*)label
;
122 if (serviceName
!= NULL
) {
123 attrs
[attrList
.count
].tag
= kSecServiceItemAttr
;
124 attrs
[attrList
.count
].length
= (UInt32
) strlen(serviceName
);
125 attrs
[attrList
.count
].data
= (void*)serviceName
;
128 if (accountName
!= NULL
) {
129 attrs
[attrList
.count
].tag
= kSecAccountItemAttr
;
130 attrs
[attrList
.count
].length
= (UInt32
) strlen(accountName
);
131 attrs
[attrList
.count
].data
= (void*)accountName
;
135 status
= SecKeychainSearchCreateFromAttributes(keychainOrArray
, kSecGenericPasswordItemClass
, &attrList
, &searchRef
);
137 sec_perror("SecKeychainSearchCreateFromAttributes", status
);
140 // we're only interested in the first match, if there is a match at all
141 status
= SecKeychainSearchCopyNext(searchRef
, &itemRef
);
148 CFRelease(searchRef
);
153 // find_first_internet_password
155 // Returns a SecKeychainItemRef for the first item
156 // which matches the specified attributes. Caller is
157 // responsible for releasing the item (with CFRelease).
160 find_first_internet_password(CFTypeRef keychainOrArray
,
161 FourCharCode itemCreator
,
162 FourCharCode itemType
,
166 const char *serverName
,
167 const char *securityDomain
,
168 const char *accountName
,
171 SecProtocolType protocol
,
172 SecAuthenticationType authenticationType
)
174 OSStatus status
= noErr
;
175 SecKeychainSearchRef searchRef
= NULL
;
176 SecKeychainItemRef itemRef
= NULL
;
178 SecKeychainAttribute attrs
[12]; // maximum number of searchable attributes
179 SecKeychainAttributeList attrList
= { 0, attrs
};
181 // the primary key for an internet password item (i.e. the combination of
182 // attributes which determine whether the item is unique) consists of:
183 // { kSecAccountItemAttr, kSecSecurityDomainItemAttr, kSecServerItemAttr,
184 // kSecProtocolItemAttr, kSecAuthenticationTypeItemAttr,
185 // kSecPortItemAttr, kSecPathItemAttr }
187 // if we have a primary key, we don't need to search on other attributes.
188 // (and we don't want to, if non-primary attributes are being updated)
189 Boolean primaryKey
= (accountName
&& securityDomain
&& serverName
&&
190 protocol
&& authenticationType
&& port
&& path
);
192 // build the attribute list for searching
193 if ((UInt32
)itemCreator
!= 0 && !primaryKey
) {
194 attrs
[attrList
.count
].tag
= kSecCreatorItemAttr
;
195 attrs
[attrList
.count
].length
= sizeof(FourCharCode
);
196 attrs
[attrList
.count
].data
= (FourCharCode
*)&itemCreator
;
199 if ((UInt32
)itemType
!= 0 && !primaryKey
) {
200 attrs
[attrList
.count
].tag
= kSecTypeItemAttr
;
201 attrs
[attrList
.count
].length
= sizeof(FourCharCode
);
202 attrs
[attrList
.count
].data
= (FourCharCode
*)&itemType
;
205 if (kind
!= NULL
&& !primaryKey
) {
206 attrs
[attrList
.count
].tag
= kSecDescriptionItemAttr
;
207 attrs
[attrList
.count
].length
= (UInt32
) strlen(kind
);
208 attrs
[attrList
.count
].data
= (void*)kind
;
211 if (comment
!= NULL
&& !primaryKey
) {
212 attrs
[attrList
.count
].tag
= kSecCommentItemAttr
;
213 attrs
[attrList
.count
].length
= (UInt32
) strlen(comment
);
214 attrs
[attrList
.count
].data
= (void*)comment
;
217 if (label
!= NULL
&& !primaryKey
) {
218 attrs
[attrList
.count
].tag
= kSecLabelItemAttr
;
219 attrs
[attrList
.count
].length
= (UInt32
) strlen(label
);
220 attrs
[attrList
.count
].data
= (void*)label
;
223 if (serverName
!= NULL
) {
224 attrs
[attrList
.count
].tag
= kSecServerItemAttr
;
225 attrs
[attrList
.count
].length
= (UInt32
) strlen(serverName
);
226 attrs
[attrList
.count
].data
= (void*)serverName
;
229 if (securityDomain
!= NULL
) {
230 attrs
[attrList
.count
].tag
= kSecSecurityDomainItemAttr
;
231 attrs
[attrList
.count
].length
= (UInt32
) strlen(securityDomain
);
232 attrs
[attrList
.count
].data
= (void *)securityDomain
;
235 if (accountName
!= NULL
) {
236 attrs
[attrList
.count
].tag
= kSecAccountItemAttr
;
237 attrs
[attrList
.count
].length
= (UInt32
) strlen(accountName
);
238 attrs
[attrList
.count
].data
= (void *)accountName
;
242 attrs
[attrList
.count
].tag
= kSecPathItemAttr
;
243 attrs
[attrList
.count
].length
= (UInt32
) strlen(path
);
244 attrs
[attrList
.count
].data
= (void *)path
;
248 attrs
[attrList
.count
].tag
= kSecPortItemAttr
;
249 attrs
[attrList
.count
].length
= sizeof(UInt16
);
250 attrs
[attrList
.count
].data
= (UInt16
*)&port
;
253 if ((UInt32
)protocol
!= 0) {
254 attrs
[attrList
.count
].tag
= kSecProtocolItemAttr
;
255 attrs
[attrList
.count
].length
= sizeof(SecProtocolType
);
256 attrs
[attrList
.count
].data
= (SecProtocolType
*)&protocol
;
259 if ((UInt32
)authenticationType
!= 0) {
260 attrs
[attrList
.count
].tag
= kSecAuthenticationTypeItemAttr
;
261 attrs
[attrList
.count
].length
= sizeof(SecAuthenticationType
);
262 attrs
[attrList
.count
].data
= (SecAuthenticationType
*)&authenticationType
;
266 status
= SecKeychainSearchCreateFromAttributes(keychainOrArray
, kSecInternetPasswordItemClass
, &attrList
, &searchRef
);
268 sec_perror("SecKeychainSearchCreateFromAttributes", status
);
271 // we're only interested in the first match, if there is a match at all
272 status
= SecKeychainSearchCopyNext(searchRef
, &itemRef
);
279 CFRelease(searchRef
);
284 // find_unique_certificate
286 // Returns a SecKeychainItemRef for the certificate
287 // in the specified keychain (or keychain list)
288 // which is a unique match for either the specified name
289 // or SHA-1 hash. If more than one match exists, the
290 // certificate is not unique and none are returned. Caller is
291 // responsible for releasing the item (with CFRelease).
294 find_unique_certificate(CFTypeRef keychainOrArray
,
298 OSStatus status
= noErr
;
299 SecKeychainSearchRef searchRef
= NULL
;
300 SecKeychainItemRef uniqueItemRef
= NULL
;
302 status
= SecKeychainSearchCreateFromAttributes(keychainOrArray
, kSecCertificateItemClass
, NULL
, &searchRef
);
304 return uniqueItemRef
;
307 // check input hash string and convert to data
308 CSSM_DATA hashData
= { 0, NULL
};
310 CSSM_SIZE len
= strlen(hash
)/2;
311 hashData
.Length
= len
;
312 hashData
.Data
= (uint8
*)malloc(hashData
.Length
);
313 fromHex(hash
, &hashData
);
316 // filter candidates against the hash (or the name, if no hash provided)
317 CFStringRef matchRef
= (name
) ? CFStringCreateWithCString(NULL
, name
, kCFStringEncodingUTF8
) : NULL
;
318 Boolean exactMatch
= FALSE
;
320 CSSM_DATA certData
= { 0, NULL
};
321 SecKeychainItemRef candidate
= NULL
;
323 while (SecKeychainSearchCopyNext(searchRef
, &candidate
) == noErr
) {
324 SecCertificateRef cert
= (SecCertificateRef
)candidate
;
325 if (SecCertificateGetData(cert
, &certData
) != noErr
) {
326 safe_CFRelease(&candidate
);
330 uint8 candidate_sha1_hash
[20];
332 digest
.Length
= sizeof(candidate_sha1_hash
);
333 digest
.Data
= candidate_sha1_hash
;
334 if ((SecDigestGetData(CSSM_ALGID_SHA1
, &digest
, &certData
) == CSSM_OK
) &&
335 (hashData
.Length
== digest
.Length
) &&
336 (!memcmp(hashData
.Data
, digest
.Data
, digest
.Length
))) {
338 uniqueItemRef
= candidate
; // currently retained
339 break; // we're done - can't get more exact than this
342 // copy certificate name
343 CFStringRef nameRef
= NULL
;
344 if ((SecCertificateCopyCommonName(cert
, &nameRef
) != noErr
) || nameRef
== NULL
) {
345 safe_CFRelease(&candidate
);
346 continue; // no name, so no match is possible
348 CFIndex nameLen
= CFStringGetLength(nameRef
);
349 CFIndex bufLen
= 1 + CFStringGetMaximumSizeForEncoding(nameLen
, kCFStringEncodingUTF8
);
350 char *nameBuf
= (char *)malloc(bufLen
);
351 if (!CFStringGetCString(nameRef
, nameBuf
, bufLen
-1, kCFStringEncodingUTF8
))
354 CFRange find
= { kCFNotFound
, 0 };
355 if (nameRef
&& matchRef
)
356 find
= CFStringFind(nameRef
, matchRef
, kCFCompareCaseInsensitive
| kCFCompareNonliteral
);
357 Boolean isExact
= (find
.location
== 0 && find
.length
== nameLen
);
358 if (find
.location
== kCFNotFound
) {
360 safe_CFRelease(&nameRef
);
361 safe_CFRelease(&candidate
);
362 continue; // no match
364 if (uniqueItemRef
) { // got two matches
365 if (exactMatch
&& !isExact
) { // prior is better; ignore this one
367 safe_CFRelease(&nameRef
);
368 safe_CFRelease(&candidate
);
371 if (exactMatch
== isExact
) { // same class of match
372 if (CFEqual(uniqueItemRef
, candidate
)) { // same certificate
374 safe_CFRelease(&nameRef
);
375 safe_CFRelease(&candidate
);
378 // ambiguity - must fail
379 sec_error("\"%s\" is ambiguous, matches more than one certificate", name
);
381 safe_CFRelease(&nameRef
);
382 safe_CFRelease(&candidate
);
383 safe_CFRelease(&uniqueItemRef
);
386 safe_CFRelease(&uniqueItemRef
); // about to replace with this one
388 uniqueItemRef
= candidate
; // currently retained
389 exactMatch
= isExact
;
391 safe_CFRelease(&nameRef
);
395 safe_CFRelease(&searchRef
);
396 safe_CFRelease(&matchRef
);
401 return uniqueItemRef
;
405 do_password_item_printing( SecKeychainItemRef itemRef
,
406 Boolean get_password
,
407 Boolean password_stdout
)
409 OSStatus result
= noErr
;
410 void *passwordData
= NULL
;
411 UInt32 passwordLength
= 0;
414 result
= SecKeychainItemCopyContent(itemRef
, NULL
, NULL
, &passwordLength
, &passwordData
);
415 if(result
!= noErr
) return result
;
417 if(!password_stdout
) {
418 print_keychain_item_attributes(stdout
, itemRef
, FALSE
, FALSE
, FALSE
, FALSE
);
420 fputs("password: ", stderr
);
421 print_buffer(stderr
, passwordLength
, passwordData
);
425 char *password
= (char *) passwordData
;
427 for(int i
=0; i
<passwordLength
; i
++) if(!isprint(password
[i
])) doHex
= 1;
429 for(int i
=0; i
<passwordLength
; i
++) printf("%02x", password
[i
]);
431 for(int i
=0; i
<passwordLength
; i
++) putchar(password
[i
]);
436 if (passwordData
) SecKeychainItemFreeContent(NULL
, passwordData
);
442 do_keychain_find_generic_password(CFTypeRef keychainOrArray
,
443 FourCharCode itemCreator
,
444 FourCharCode itemType
,
449 const char *serviceName
,
450 const char *accountName
,
451 Boolean get_password
,
452 Boolean password_stdout
)
454 OSStatus result
= noErr
;
455 SecKeychainItemRef itemRef
= NULL
;
457 itemRef
= find_first_generic_password(keychainOrArray
,
468 result
= do_password_item_printing(itemRef
, get_password
, password_stdout
);
470 result
= errSecItemNotFound
;
471 sec_perror("SecKeychainSearchCopyNext", result
);
474 if (itemRef
) CFRelease(itemRef
);
480 do_keychain_delete_generic_password(CFTypeRef keychainOrArray
,
481 FourCharCode itemCreator
,
482 FourCharCode itemType
,
487 const char *serviceName
,
488 const char *accountName
)
490 OSStatus result
= noErr
;
491 SecKeychainItemRef itemRef
= NULL
;
492 void *passwordData
= NULL
;
494 itemRef
= find_first_generic_password(keychainOrArray
,
504 result
= errSecItemNotFound
;
505 sec_perror("SecKeychainSearchCopyNext", result
);
509 print_keychain_item_attributes(stdout
, itemRef
, FALSE
, FALSE
, FALSE
, FALSE
);
511 result
= SecKeychainItemDelete(itemRef
);
513 fputs("password has been deleted.\n", stderr
);
517 SecKeychainItemFreeContent(NULL
, passwordData
);
525 do_keychain_find_internet_password(CFTypeRef keychainOrArray
,
526 FourCharCode itemCreator
,
527 FourCharCode itemType
,
531 const char *serverName
,
532 const char *securityDomain
,
533 const char *accountName
,
536 SecProtocolType protocol
,
537 SecAuthenticationType authenticationType
,
538 Boolean get_password
,
539 Boolean password_stdout
)
541 OSStatus result
= noErr
;
542 SecKeychainItemRef itemRef
= NULL
;
544 itemRef
= find_first_internet_password(keychainOrArray
,
558 result
= do_password_item_printing(itemRef
, get_password
, password_stdout
);
560 result
= errSecItemNotFound
;
561 sec_perror("SecKeychainSearchCopyNext", result
);
568 do_keychain_delete_internet_password(CFTypeRef keychainOrArray
,
569 FourCharCode itemCreator
,
570 FourCharCode itemType
,
574 const char *serverName
,
575 const char *securityDomain
,
576 const char *accountName
,
579 SecProtocolType protocol
,
580 SecAuthenticationType authenticationType
)
582 OSStatus result
= noErr
;
583 SecKeychainItemRef itemRef
= NULL
;
584 void *passwordData
= NULL
;
586 itemRef
= find_first_internet_password(keychainOrArray
,
600 result
= errSecItemNotFound
;
601 sec_perror("SecKeychainSearchCopyNext", result
);
605 print_keychain_item_attributes(stdout
, itemRef
, FALSE
, FALSE
, FALSE
, FALSE
);
607 result
= SecKeychainItemDelete(itemRef
);
609 fputs("password has been deleted.\n", stderr
);
613 SecKeychainItemFreeContent(NULL
, passwordData
);
621 do_keychain_find_certificate(CFTypeRef keychainOrArray
,
623 const char *emailAddress
,
629 OSStatus result
= noErr
;
630 SecCertificateRef certificateRef
= NULL
;
631 SecKeychainSearchRef searchRef
= NULL
;
632 CFStringRef matchRef
= (name
) ? CFStringCreateWithCString(NULL
, name
, kCFStringEncodingUTF8
) : NULL
;
634 if (find_all
&& emailAddress
) {
635 result
= SecKeychainSearchCreateForCertificateByEmail(keychainOrArray
, emailAddress
, &searchRef
);
637 sec_perror("SecKeychainSearchCreateForCertificateByEmail", result
);
641 result
= SecKeychainSearchCreateFromAttributes(keychainOrArray
, kSecCertificateItemClass
, NULL
, &searchRef
);
643 sec_perror("SecKeychainSearchCreateFromAttributes", result
);
651 SecKeychainItemRef itemRef
= NULL
;
652 result
= SecKeychainSearchCopyNext(searchRef
, &itemRef
);
653 if (result
== errSecItemNotFound
) {
658 sec_perror("SecKeychainSearchCopyNext", result
);
662 if (!emailAddress
&& name
) {
663 // match name in common name
664 CFStringRef nameRef
= NULL
;
665 if (SecCertificateCopyCommonName((SecCertificateRef
)itemRef
, &nameRef
) != noErr
) {
666 safe_CFRelease(&itemRef
);
667 continue; // no name, so no match is possible
669 CFRange find
= { kCFNotFound
, 0 };
670 if (nameRef
&& matchRef
)
671 find
= CFStringFind(nameRef
, matchRef
, kCFCompareCaseInsensitive
| kCFCompareNonliteral
);
672 if (find
.location
== kCFNotFound
) {
673 safe_CFRelease(&nameRef
);
674 safe_CFRelease(&itemRef
);
675 continue; // no match
677 safe_CFRelease(&nameRef
);
679 safe_CFRelease(&certificateRef
);
680 certificateRef
= (SecCertificateRef
) itemRef
;
682 else { // only want the first match
684 result
= SecCertificateFindByEmail(keychainOrArray
, emailAddress
, &certificateRef
);
686 sec_perror("SecCertificateFindByEmail", result
);
690 SecKeychainItemRef itemRef
= NULL
;
691 while ((result
= SecKeychainSearchCopyNext(searchRef
, &itemRef
)) != errSecItemNotFound
) {
693 // match name in common name
694 CFStringRef nameRef
= NULL
;
695 if (SecCertificateCopyCommonName((SecCertificateRef
)itemRef
, &nameRef
) != noErr
) {
696 safe_CFRelease(&itemRef
);
697 continue; // no name, so no match is possible
699 CFRange find
= { kCFNotFound
, 0 };
700 if (nameRef
&& matchRef
)
701 find
= CFStringFind(nameRef
, matchRef
, kCFCompareCaseInsensitive
| kCFCompareNonliteral
);
702 if (find
.location
== kCFNotFound
) {
703 safe_CFRelease(&nameRef
);
704 safe_CFRelease(&itemRef
);
705 continue; // no match
707 safe_CFRelease(&nameRef
);
709 break; // we have a match!
711 if (result
== errSecItemNotFound
) {
712 sec_perror("SecKeychainSearchCopyNext", result
);
715 certificateRef
= (SecCertificateRef
) itemRef
;
719 // process the found certificate
725 digest
.Length
= sizeof(sha1_hash
);
726 digest
.Data
= sha1_hash
;
727 if ((SecCertificateGetData(certificateRef
, &data
) == noErr
) &&
728 (SecDigestGetData(CSSM_ALGID_SHA1
, &digest
, &data
) == CSSM_OK
)) {
730 size_t len
= digest
.Length
;
731 uint8
*cp
= digest
.Data
;
732 fprintf(stdout
, "SHA-1 hash: ");
733 for(i
=0; i
<len
; i
++) {
734 fprintf(stdout
, "%02X", ((unsigned char *)cp
)[i
]);
736 fprintf(stdout
, "\n");
742 CFArrayRef emailAddresses
= NULL
;
744 result
= SecCertificateCopyEmailAddresses(certificateRef
, &emailAddresses
);
747 sec_perror("SecCertificateCopyEmailAddresses", result
);
751 count
= CFArrayGetCount(emailAddresses
);
752 fputs("email addresses: ", stdout
);
753 for (ix
= 0; ix
< count
; ++ix
)
755 CFStringRef emailAddress
= (CFStringRef
)CFArrayGetValueAtIndex(emailAddresses
, ix
);
762 addr
= CFStringGetCStringPtr(emailAddress
, kCFStringEncodingUTF8
);
765 if (CFStringGetCString(emailAddress
, buffer
, sizeof(buffer
), kCFStringEncodingUTF8
))
769 fprintf(stdout
, "%s", addr
);
773 CFRelease(emailAddresses
);
778 CSSM_DATA certData
= {};
779 result
= SecCertificateGetData(certificateRef
, &certData
);
782 sec_perror("SecCertificateGetData", result
);
786 print_buffer_pem(stdout
, "CERTIFICATE", certData
.Length
, certData
.Data
);
790 print_keychain_item_attributes(stdout
, (SecKeychainItemRef
)certificateRef
, FALSE
, FALSE
, FALSE
, FALSE
);
795 safe_CFRelease(&searchRef
);
796 safe_CFRelease(&certificateRef
);
797 safe_CFRelease(&matchRef
);
803 keychain_delete_internet_password(int argc
, char * const *argv
)
805 char *serverName
= NULL
, *securityDomain
= NULL
, *accountName
= NULL
, *path
= NULL
;
806 char *kind
= NULL
, *label
= NULL
, *comment
= NULL
;
807 FourCharCode itemCreator
= 0, itemType
= 0;
809 SecProtocolType protocol
= 0;
810 SecAuthenticationType authenticationType
= 0;
811 CFTypeRef keychainOrArray
= NULL
;
815 * " -a Match \"account\" string\n"
816 * " -c Match \"creator\" (four-character code)\n"
817 * " -C Match \"type\" (four-character code)\n"
818 * " -d Match \"securityDomain\" string\n"
819 * " -D Match \"kind\" string\n"
820 * " -j Match \"comment\" string\n"
821 * " -l Match \"label\" string\n"
822 * " -p Match \"path\" string\n"
823 * " -P Match port number\n"
824 * " -r Match \"protocol\" (four-character code)\n"
825 * " -s Match \"server\" string\n"
826 * " -t Match \"authenticationType\" (four-character code)\n"
829 while ((ch
= getopt(argc
, argv
, "ha:c:C:d:D:hgj:l:p:P:r:s:t:")) != -1)
834 accountName
= optarg
;
837 result
= parse_fourcharcode(optarg
, &itemCreator
);
838 if (result
) goto cleanup
;
841 result
= parse_fourcharcode(optarg
, &itemType
);
842 if (result
) goto cleanup
;
845 securityDomain
= optarg
;
863 result
= parse_fourcharcode(optarg
, &protocol
);
864 if (result
) goto cleanup
;
870 result
= parse_fourcharcode(optarg
, &authenticationType
);
871 if (result
) goto cleanup
;
875 result
= 2; /* @@@ Return 2 triggers usage message. */
883 keychainOrArray
= keychain_create_array(argc
, argv
);
885 result
= do_keychain_delete_internet_password(keychainOrArray
,
900 CFRelease(keychainOrArray
);
906 keychain_find_internet_password(int argc
, char * const *argv
)
908 char *serverName
= NULL
, *securityDomain
= NULL
, *accountName
= NULL
, *path
= NULL
;
909 char *kind
= NULL
, *label
= NULL
, *comment
= NULL
;
910 FourCharCode itemCreator
= 0, itemType
= 0;
912 SecProtocolType protocol
= 0;
913 SecAuthenticationType authenticationType
= 0;
914 CFTypeRef keychainOrArray
= NULL
;
916 Boolean get_password
= FALSE
;
917 Boolean password_stdout
= FALSE
;
920 * " -a Match \"account\" string\n"
921 * " -c Match \"creator\" (four-character code)\n"
922 * " -C Match \"type\" (four-character code)\n"
923 * " -d Match \"securityDomain\" string\n"
924 * " -D Match \"kind\" string\n"
925 * " -j Match \"comment\" string\n"
926 * " -l Match \"label\" string\n"
927 * " -p Match \"path\" string\n"
928 * " -P Match port number\n"
929 * " -r Match \"protocol\" (four-character code)\n"
930 * " -s Match \"server\" string\n"
931 * " -t Match \"authenticationType\" (four-character code)\n"
932 * " -g Display the password for the item found\n"
933 * " -w Display the password(only) for the item(s) found\n"
936 while ((ch
= getopt(argc
, argv
, "ha:c:C:d:D:hgj:l:p:P:r:s:wt:")) != -1)
941 accountName
= optarg
;
944 result
= parse_fourcharcode(optarg
, &itemCreator
);
945 if (result
) goto cleanup
;
948 result
= parse_fourcharcode(optarg
, &itemType
);
949 if (result
) goto cleanup
;
952 securityDomain
= optarg
;
973 result
= parse_fourcharcode(optarg
, &protocol
);
974 if (result
) goto cleanup
;
981 password_stdout
= TRUE
;
984 result
= parse_fourcharcode(optarg
, &authenticationType
);
985 if (result
) goto cleanup
;
986 /* auth type attribute is special */
987 authenticationType
= OSSwapHostToBigInt32(authenticationType
);
991 result
= 2; /* @@@ Return 2 triggers usage message. */
999 keychainOrArray
= keychain_create_array(argc
, argv
);
1001 result
= do_keychain_find_internet_password(keychainOrArray
,
1017 if (keychainOrArray
)
1018 CFRelease(keychainOrArray
);
1024 keychain_delete_generic_password(int argc
, char * const *argv
)
1026 char *serviceName
= NULL
, *accountName
= NULL
;
1027 char *kind
= NULL
, *label
= NULL
, *value
= NULL
, *comment
= NULL
;
1028 FourCharCode itemCreator
= 0, itemType
= 0;
1029 CFTypeRef keychainOrArray
= nil
;
1033 * " -a Match \"account\" string\n"
1034 * " -c Match \"creator\" (four-character code)\n"
1035 * " -C Match \"type\" (four-character code)\n"
1036 * " -D Match \"kind\" string\n"
1037 * " -G Match \"value\" string (generic attribute)\n"
1038 * " -j Match \"comment\" string\n"
1039 * " -l Match \"label\" string\n"
1040 * " -s Match \"service\" string\n"
1043 while ((ch
= getopt(argc
, argv
, "ha:c:C:D:G:j:l:s:g")) != -1)
1048 accountName
= optarg
;
1051 result
= parse_fourcharcode(optarg
, &itemCreator
);
1052 if (result
) goto cleanup
;
1055 result
= parse_fourcharcode(optarg
, &itemType
);
1056 if (result
) goto cleanup
;
1071 serviceName
= optarg
;
1075 result
= 2; /* @@@ Return 2 triggers usage message. */
1083 keychainOrArray
= keychain_create_array(argc
, argv
);
1085 result
= do_keychain_delete_generic_password(keychainOrArray
,
1095 if (keychainOrArray
)
1096 CFRelease(keychainOrArray
);
1102 keychain_find_generic_password(int argc
, char * const *argv
)
1104 char *serviceName
= NULL
, *accountName
= NULL
;
1105 char *kind
= NULL
, *label
= NULL
, *value
= NULL
, *comment
= NULL
;
1106 FourCharCode itemCreator
= 0, itemType
= 0;
1107 CFTypeRef keychainOrArray
= nil
;
1109 Boolean get_password
= FALSE
;
1110 Boolean password_stdout
= FALSE
;
1113 * " -a Match \"account\" string\n"
1114 * " -c Match \"creator\" (four-character code)\n"
1115 * " -C Match \"type\" (four-character code)\n"
1116 * " -D Match \"kind\" string\n"
1117 * " -G Match \"value\" string (generic attribute)\n"
1118 * " -j Match \"comment\" string\n"
1119 * " -l Match \"label\" string\n"
1120 * " -s Match \"service\" string\n"
1121 * " -g Display the password for the item(s) found\n"
1122 * " -w Display the password(only) for the item(s) found\n"
1125 while ((ch
= getopt(argc
, argv
, "ha:c:C:D:G:j:l:s:wg")) != -1)
1130 accountName
= optarg
;
1133 result
= parse_fourcharcode(optarg
, &itemCreator
);
1134 if (result
) goto cleanup
;
1137 result
= parse_fourcharcode(optarg
, &itemType
);
1138 if (result
) goto cleanup
;
1153 serviceName
= optarg
;
1156 password_stdout
= TRUE
;
1157 get_password
= TRUE
;
1160 get_password
= TRUE
;
1164 result
= 2; /* @@@ Return 2 triggers usage message. */
1172 keychainOrArray
= keychain_create_array(argc
, argv
);
1174 result
= do_keychain_find_generic_password(keychainOrArray
,
1186 if (keychainOrArray
)
1187 CFRelease(keychainOrArray
);
1193 keychain_find_key(int argc
, char * const *argv
) {
1195 * " -a Match \"application label\" string\n"
1196 * " -c Match \"creator\" (four-character code)\n"
1197 * " -d Match keys that can decrypt\n"
1198 * " -D Match \"description\" string\n"
1199 * " -e Match keys that can encrypt\n"
1200 * " -j Match \"comment\" string\n"
1201 * " -l Match \"label\" string\n"
1202 * " -r Match keys that can derive\n"
1203 * " -s Match keys that can sign\n"
1204 * " -t Type of key to find: one of \"symmetric\", \"public\", or \"private\"\n"
1205 * " -u Match keys that can unwrap\n"
1206 * " -v Match keys that can verify\n"
1207 * " -w Match keys that can wrap\n"
1210 CFMutableDictionaryRef query
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1211 CFDictionarySetValue(query
, kSecClass
, kSecClassKey
);
1212 CFDictionarySetValue(query
, kSecMatchLimit
, kSecMatchLimitAll
);
1214 CFTypeRef results
= NULL
;
1217 while ((ch
= getopt(argc
, argv
, "a:c:dD:ej:l:rst:uvw")) != -1)
1222 CFDictionarySetValue(query
, kSecAttrApplicationLabel
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1225 CFDictionarySetValue(query
, kSecAttrCreator
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1228 CFDictionarySetValue(query
, kSecAttrCanDecrypt
, kCFBooleanTrue
);
1231 CFDictionarySetValue(query
, kSecAttrDescription
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1234 CFDictionarySetValue(query
, kSecAttrCanEncrypt
, kCFBooleanTrue
);
1237 CFDictionarySetValue(query
, kSecAttrComment
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1240 CFDictionarySetValue(query
, kSecAttrLabel
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1243 CFDictionarySetValue(query
, kSecAttrCanDerive
, kCFBooleanTrue
);
1246 CFDictionarySetValue(query
, kSecAttrCanSign
, kCFBooleanTrue
);
1249 if(strcmp(optarg
, "symmetric") == 0) {
1250 CFDictionarySetValue(query
, kSecAttrKeyClass
, kSecAttrKeyClassSymmetric
);
1251 } else if(strcmp(optarg
, "public") == 0) {
1252 CFDictionarySetValue(query
, kSecAttrKeyClass
, kSecAttrKeyClassPublic
);
1253 } else if(strcmp(optarg
, "private") == 0) {
1254 CFDictionarySetValue(query
, kSecAttrKeyClass
, kSecAttrKeyClassPrivate
);
1261 CFDictionarySetValue(query
, kSecAttrCanUnwrap
, kCFBooleanTrue
);
1264 CFDictionarySetValue(query
, kSecAttrCanVerify
, kCFBooleanTrue
);
1267 CFDictionarySetValue(query
, kSecAttrCanWrap
, kCFBooleanTrue
);
1279 CFTypeRef keychainOrArray
= keychain_create_array(argc
, argv
);
1281 if(keychainOrArray
&& CFGetTypeID(keychainOrArray
) == CFArrayGetTypeID()) {
1282 CFDictionarySetValue(query
, kSecMatchSearchList
, keychainOrArray
);
1283 } else if(keychainOrArray
) {
1284 // if it's not an array (but is something), it's a keychain. Put it in an array.
1285 CFMutableArrayRef searchList
= (CFMutableArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 1, &kCFTypeArrayCallBacks
);
1286 CFArrayAppendValue((CFMutableArrayRef
)searchList
, keychainOrArray
);
1287 CFDictionarySetValue(query
, kSecMatchSearchList
, searchList
);
1288 CFRelease(searchList
);
1291 OSStatus status
= SecItemCopyMatching(query
, &results
);
1293 sec_perror("SecItemCopyMatching", status
);
1298 if (CFGetTypeID(results
) == CFArrayGetTypeID()) {
1299 for(int i
= 0; i
< CFArrayGetCount(results
); i
++) {
1300 SecKeychainItemRef item
= (SecKeychainItemRef
) CFArrayGetValueAtIndex(results
, i
);
1302 print_keychain_item_attributes(stdout
, item
, FALSE
, FALSE
, FALSE
, FALSE
);
1307 safe_CFRelease(&results
);
1308 safe_CFRelease(&query
);
1312 // Declare here to use later.
1313 int keychain_set_partition_list(SecKeychainRef kc
, CFDictionaryRef query
, CFStringRef password
, CFStringRef partitionlist
);
1314 int keychain_parse_args_and_set_partition_list(int argc
, char * const *argv
, CFMutableDictionaryRef query
, CFStringRef partitionidsinput
, CFStringRef password
);
1316 int keychain_set_internet_password_partition_list(int argc
, char * const *argv
) {
1318 * " -a Match \"account\" string\n"
1319 * " -c Match \"creator\" (four-character code)\n"
1320 * " -C Match \"type\" (four-character code)\n"
1321 * " -d Match \"securityDomain\" string\n"
1322 * " -D Match \"kind\" string\n"
1323 * " -j Match \"comment\" string\n"
1324 * " -l Match \"label\" string\n"
1325 * " -p Match \"path\" string\n"
1326 * " -P Match port number\n"
1327 * " -r Match \"protocol\" (four-character code)\n"
1328 * " -s Match \"server\" string\n"
1329 * " -t Match \"authenticationType\" (four-character code)\n"
1330 * " -S Comma-separated list of allowed partition IDs"
1331 * " -k password for keychain"
1334 CFMutableDictionaryRef query
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1335 CFDictionarySetValue(query
, kSecClass
, kSecClassInternetPassword
);
1336 CFDictionarySetValue(query
, kSecMatchLimit
, kSecMatchLimitAll
);
1338 CFStringRef partitionidsinput
= NULL
;
1339 CFStringRef password
= NULL
;
1342 while ((ch
= getopt(argc
, argv
, "a:c:C:d:D:j:l:p:P:r:s:S:t:k:")) != -1)
1347 CFDictionarySetValue(query
, kSecAttrAccount
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1350 CFDictionarySetValue(query
, kSecAttrCreator
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1353 CFDictionarySetValue(query
, kSecAttrType
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1356 CFDictionarySetValue(query
, kSecAttrSecurityDomain
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1359 CFDictionarySetValue(query
, kSecAttrDescription
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1362 CFDictionarySetValue(query
, kSecAttrComment
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1365 CFDictionarySetValue(query
, kSecAttrLabel
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1368 CFDictionarySetValue(query
, kSecAttrPath
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1371 CFDictionarySetValue(query
, kSecAttrPort
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1374 CFDictionarySetValue(query
, kSecAttrProtocol
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1377 CFDictionarySetValue(query
, kSecAttrService
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1380 CFDictionarySetValue(query
, kSecAttrAuthenticationType
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1383 partitionidsinput
= CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1386 password
= CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1398 result
= keychain_parse_args_and_set_partition_list(argc
, argv
, query
, partitionidsinput
, password
);
1401 safe_CFRelease(&password
);
1402 safe_CFRelease(&partitionidsinput
);
1403 safe_CFRelease(&query
);
1408 keychain_set_generic_password_partition_list(int argc
, char * const *argv
) {
1409 CFMutableDictionaryRef query
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1411 // -a Match \"account\" string
1412 // -c Match \"creator\" (four-character code)
1413 // -C Match \"type\" (four-character code)
1414 // -D Match \"kind\" string
1415 // -G Match \"value\" string (generic attribute)
1416 // -j Match \"comment\" string
1417 // -l Match \"label\" string
1418 // -s Match \"service\" string
1419 // -S Comma-separated list of allowed partition IDs
1420 // -k password for keychain
1422 CFDictionarySetValue(query
, kSecClass
, kSecClassGenericPassword
);
1423 CFDictionarySetValue(query
, kSecMatchLimit
, kSecMatchLimitAll
);
1425 CFStringRef partitionidsinput
= NULL
;
1426 CFStringRef password
= NULL
;
1429 while ((ch
= getopt(argc
, argv
, ":a:c:C:D:G:j:l:s:S:k:")) != -1)
1434 CFDictionarySetValue(query
, kSecAttrAccount
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1437 CFDictionarySetValue(query
, kSecAttrCreator
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1440 CFDictionarySetValue(query
, kSecAttrType
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1443 CFDictionarySetValue(query
, kSecAttrDescription
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1446 CFDictionarySetValue(query
, kSecAttrGeneric
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1449 CFDictionarySetValue(query
, kSecAttrComment
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1452 CFDictionarySetValue(query
, kSecAttrLabel
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1455 CFDictionarySetValue(query
, kSecAttrService
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1458 partitionidsinput
= CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1461 password
= CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1465 // They supplied the -k but with no data
1466 // Leaving it null will cause prompt below
1467 if (optopt
== 'k') {
1471 goto cleanup
; /* @@@ Return 2 triggers usage message. */
1481 result
= keychain_parse_args_and_set_partition_list(argc
, argv
, query
, partitionidsinput
, password
);
1484 safe_CFRelease(&password
);
1485 safe_CFRelease(&partitionidsinput
);
1486 safe_CFRelease(&query
);
1491 keychain_set_key_partition_list(int argc
, char * const *argv
) {
1493 * " -a Match \"application label\" string\n"
1494 * " -c Match \"creator\" (four-character code)\n"
1495 * " -d Match keys that can decrypt\n"
1496 * " -D Match \"description\" string\n"
1497 * " -e Match keys that can encrypt\n"
1498 * " -j Match \"comment\" string\n"
1499 * " -l Match \"label\" string\n"
1500 * " -r Match keys that can derive\n"
1501 * " -s Match keys that can sign\n"
1502 * " -t Type of key to find: one of \"symmetric\", \"public\", or \"private\"\n"
1503 * " -u Match keys that can unwrap\n"
1504 * " -v Match keys that can verify\n"
1505 * " -w Match keys that can wrap\n"
1506 * " -S Comma-separated list of allowed partition IDs
1507 * " -k password for keychain (required)
1510 CFMutableDictionaryRef query
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1511 CFDictionarySetValue(query
, kSecClass
, kSecClassKey
);
1512 CFDictionarySetValue(query
, kSecMatchLimit
, kSecMatchLimitAll
);
1514 CFStringRef partitionidsinput
= NULL
;
1515 CFStringRef password
= NULL
;
1518 while ((ch
= getopt(argc
, argv
, ":a:c:dD:ej:k:l:rsS:t:uvw")) != -1)
1523 CFDictionarySetValue(query
, kSecAttrApplicationLabel
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1526 CFDictionarySetValue(query
, kSecAttrCreator
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1529 CFDictionarySetValue(query
, kSecAttrCanDecrypt
, kCFBooleanTrue
);
1532 CFDictionarySetValue(query
, kSecAttrDescription
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1535 CFDictionarySetValue(query
, kSecAttrCanEncrypt
, kCFBooleanTrue
);
1538 CFDictionarySetValue(query
, kSecAttrComment
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1541 CFDictionarySetValue(query
, kSecAttrLabel
, CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
));
1544 CFDictionarySetValue(query
, kSecAttrCanDerive
, kCFBooleanTrue
);
1546 CFDictionarySetValue(query
, kSecAttrCanSign
, kCFBooleanTrue
);
1549 if(strcmp(optarg
, "symmetric") == 0) {
1550 CFDictionarySetValue(query
, kSecAttrKeyClass
, kSecAttrKeyClassSymmetric
);
1551 } else if(strcmp(optarg
, "public") == 0) {
1552 CFDictionarySetValue(query
, kSecAttrKeyClass
, kSecAttrKeyClassPublic
);
1553 } else if(strcmp(optarg
, "private") == 0) {
1554 CFDictionarySetValue(query
, kSecAttrKeyClass
, kSecAttrKeyClassPrivate
);
1561 CFDictionarySetValue(query
, kSecAttrCanUnwrap
, kCFBooleanTrue
);
1564 CFDictionarySetValue(query
, kSecAttrCanVerify
, kCFBooleanTrue
);
1567 CFDictionarySetValue(query
, kSecAttrCanWrap
, kCFBooleanTrue
);
1570 partitionidsinput
= CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1573 password
= CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1577 // They supplied the -k but with no data
1578 // Leaving it null will cause prompt below
1579 if (optopt
== 'k') {
1583 goto cleanup
; /* @@@ Return 2 triggers usage message. */
1593 result
= keychain_parse_args_and_set_partition_list(argc
, argv
, query
, partitionidsinput
, password
);
1596 safe_CFRelease(&query
);
1601 int keychain_parse_args_and_set_partition_list(int argc
, char * const *argv
, CFMutableDictionaryRef query
, CFStringRef partitionidsinput
, CFStringRef password
) {
1603 const char *keychainName
= NULL
;
1604 SecKeychainRef kc
= NULL
;
1606 // if we were given a keychain, use it
1609 keychainName
= argv
[0];
1610 if (*keychainName
== '\0')
1616 kc
= keychain_open(keychainName
);
1618 sec_error("couldn't open \"%s\"", keychainName
);
1623 CFMutableArrayRef searchList
= (CFMutableArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 1, &kCFTypeArrayCallBacks
);
1624 CFArrayAppendValue((CFMutableArrayRef
)searchList
, kc
);
1625 CFDictionarySetValue(query
, kSecMatchSearchList
, searchList
);
1626 } else if (argc
!= 0) {
1631 if(!partitionidsinput
) {
1637 char* cpassword
= prompt_password(keychainName
);
1642 password
= CFStringCreateWithCString(NULL
, cpassword
, kCFStringEncodingUTF8
);
1646 result
= keychain_set_partition_list(kc
, query
, password
, partitionidsinput
);
1653 int keychain_set_partition_list(SecKeychainRef kc
, CFDictionaryRef query
, CFStringRef password
, CFStringRef partitionlist
) {
1656 char *passwordBuf
= NULL
;
1658 GetCStringFromCFString(password
, &passwordBuf
, &passwordLen
);
1662 // Unlock the keychain with the given password, since we'll be fetching ACLs
1663 status
= SecKeychainUnlock(kc
, (UInt32
) passwordLen
, passwordBuf
, true);
1665 sec_perror("SecKeychainUnlock", status
);
1670 CFTypeRef results
= NULL
;
1671 status
= SecItemCopyMatching(query
, &results
);
1673 sec_perror("SecItemCopyMatching", status
);
1683 if (CFGetTypeID(results
) == CFArrayGetTypeID()) {
1684 for(int i
= 0; i
< CFArrayGetCount(results
); i
++) {
1685 SecKeychainItemRef item
= (SecKeychainItemRef
) CFArrayGetValueAtIndex(results
, i
);
1686 SecAccessRef access
= NULL
;
1688 do_password_item_printing(item
, false, false);
1690 status
= SecKeychainItemCopyAccess(item
, &access
);
1691 if (status
== errSecNoAccessForItem
) {
1695 sec_perror("SecKeychainItemCopyAccess", status
);
1700 CFArrayRef aclList
= NULL
;
1701 status
= SecAccessCopyACLList(access
, &aclList
);
1704 sec_perror("SecAccessCopyACLList", status
);
1709 CFIndex size
= CFArrayGetCount(aclList
);
1710 for(CFIndex i
= 0; i
< size
; i
++) {
1711 SecACLRef acl
= (SecACLRef
) CFArrayGetValueAtIndex(aclList
, i
);
1712 CSSM_ACL_AUTHORIZATION_TAG tags
[64]; // Pick some upper limit
1713 uint32 tagix
, tagCount
= sizeof(tags
) / sizeof(*tags
);
1714 status
= SecACLGetAuthorizations(acl
, tags
, &tagCount
);
1718 sec_perror("SecACLGetAuthorizations", status
);
1723 CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector
= {};
1725 for (tagix
= 0; tagix
< tagCount
; ++tagix
)
1727 CSSM_ACL_AUTHORIZATION_TAG tag
= tags
[tagix
];
1728 if(tag
== CSSM_ACL_AUTHORIZATION_PARTITION_ID
) {
1730 CFArrayRef applicationList
;
1731 CFStringRef promptDescription
;
1733 status
= SecACLCopySimpleContents(acl
, &applicationList
, &promptDescription
, &promptSelector
);
1735 sec_perror("SecACLCopySimpleContents", status
);
1740 CFArrayRef partitionIDs
= CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault
, partitionlist
, CFSTR(","));
1741 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1742 CFDictionarySetValue(dict
, CFSTR("Partitions"), partitionIDs
);
1743 CFDataRef xml
= CFPropertyListCreateXMLData(NULL
, dict
);
1744 CFStringRef xmlstr
= cfToHex(xml
);
1746 SecACLSetSimpleContents(acl
, applicationList
, xmlstr
, &promptSelector
);
1748 safe_CFRelease(&xmlstr
);
1749 safe_CFRelease(&xml
);
1750 safe_CFRelease(&dict
);
1751 safe_CFRelease(&partitionIDs
);
1756 status
= SecKeychainItemSetAccessWithPassword(item
, access
, (UInt32
) passwordLen
, passwordBuf
);
1758 sec_perror("SecKeychainItemSetAccessWithPassword", status
);
1771 safe_CFRelease(&results
);
1779 keychain_find_certificate(int argc
, char * const *argv
)
1781 char *emailAddress
= NULL
;
1784 CFTypeRef keychainOrArray
= nil
;
1785 Boolean output_pem
= FALSE
;
1786 Boolean find_all
= FALSE
;
1787 Boolean print_hash
= FALSE
;
1788 Boolean print_email
= FALSE
;
1790 while ((ch
= getopt(argc
, argv
, "hac:e:mpZ")) != -1)
1801 emailAddress
= optarg
;
1814 result
= 2; /* @@@ Return 2 triggers usage message. */
1822 keychainOrArray
= keychain_create_array(argc
, argv
);
1824 result
= do_keychain_find_certificate(keychainOrArray
, name
, emailAddress
, print_hash
, output_pem
, find_all
, print_email
);
1827 if (keychainOrArray
)
1828 CFRelease(keychainOrArray
);
1835 do_keychain_dump_class(FILE *stream
, CFTypeRef keychainOrArray
, SecItemClass itemClass
, Boolean show_data
, Boolean show_raw_data
, Boolean show_acl
, Boolean interactive
)
1837 SecKeychainItemRef item
;
1838 SecKeychainSearchRef search
= NULL
;
1842 status
= SecKeychainSearchCreateFromAttributes(keychainOrArray
, itemClass
, NULL
, &search
);
1845 sec_perror("SecKeychainSearchCreateFromAttributes", status
);
1850 while ((status
= SecKeychainSearchCopyNext(search
, &item
)) == 0)
1852 print_keychain_item_attributes(stream
, item
, show_data
, show_raw_data
, show_acl
, interactive
);
1856 if (status
!= errSecItemNotFound
)
1858 sec_perror("SecKeychainSearchCopyNext", status
);
1871 do_keychain_dump(FILE *stream
, CFTypeRef keychainOrArray
, Boolean show_data
, Boolean show_raw_data
, Boolean show_acl
, Boolean interactive
)
1873 return do_keychain_dump_class(stream
, keychainOrArray
, CSSM_DL_DB_RECORD_ANY
, show_data
, show_raw_data
, show_acl
, interactive
);
1877 keychain_dump(int argc
, char * const *argv
)
1880 Boolean show_data
= FALSE
, show_raw_data
= FALSE
, show_acl
= FALSE
, interactive
= FALSE
;
1881 CFTypeRef keychainOrArray
= NULL
;
1882 const char *outputFilename
= NULL
;
1885 while ((ch
= getopt(argc
, argv
, "adhiro:")) != -1)
1900 show_raw_data
= TRUE
;
1903 outputFilename
= optarg
;
1907 return 2; /* @@@ Return 2 triggers usage message. */
1914 keychainOrArray
= keychain_create_array(argc
, argv
);
1917 output
= fopen(outputFilename
, "w");
1921 result
= do_keychain_dump(output
, keychainOrArray
, show_data
, show_raw_data
, show_acl
, interactive
);
1926 if (keychainOrArray
)
1927 CFRelease(keychainOrArray
);