2 * Copyright (c) 2003-2009,2011-2019 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_add.h"
27 #include "keychain_find.h"
28 #include "readline_cssm.h"
29 #include "security_tool.h"
30 #include "access_utils.h"
31 #include "keychain_utilities.h"
36 #include <AssertMacros.h>
37 #include <libkern/OSByteOrder.h>
38 #include <Security/SecAccess.h>
39 #include <Security/SecCertificate.h>
40 #include <Security/SecKeychain.h>
41 #include <Security/SecKeychainItem.h>
42 #include <Security/SecTrustedApplication.h>
44 // SecTrustedApplicationCreateApplicationGroup
45 #include <Security/SecTrustedApplicationPriv.h>
49 do_update_generic_password(const char *keychainName
,
50 FourCharCode itemCreator
,
51 FourCharCode itemType
,
56 const char *serviceName
,
57 const char *accountName
,
58 const void *passwordData
,
59 uint32_t passwordLength
,
63 SecKeychainRef keychainRef
= NULL
;
64 SecKeychainItemRef itemRef
= NULL
;
67 keychainRef
= keychain_open(keychainName
);
69 itemRef
= find_first_generic_password(keychainRef
,itemCreator
,itemType
,kind
,value
,comment
,label
,serviceName
,accountName
);
71 CFRelease(keychainRef
);
74 return errSecItemNotFound
;
77 // build list of attributes
78 SecKeychainAttribute attrs
[8]; // maximum number of attributes
79 SecKeychainAttributeList attrList
= { 0, attrs
};
81 if ((UInt32
)itemCreator
!= 0) {
82 attrs
[attrList
.count
].tag
= kSecCreatorItemAttr
;
83 attrs
[attrList
.count
].length
= sizeof(FourCharCode
);
84 attrs
[attrList
.count
].data
= (FourCharCode
*)&itemCreator
;
87 if ((UInt32
)itemType
!= 0) {
88 attrs
[attrList
.count
].tag
= kSecTypeItemAttr
;
89 attrs
[attrList
.count
].length
= sizeof(FourCharCode
);
90 attrs
[attrList
.count
].data
= (FourCharCode
*)&itemType
;
94 attrs
[attrList
.count
].tag
= kSecDescriptionItemAttr
;
95 attrs
[attrList
.count
].length
= (UInt32
) strlen(kind
);
96 attrs
[attrList
.count
].data
= (void *)kind
;
100 attrs
[attrList
.count
].tag
= kSecGenericItemAttr
;
101 attrs
[attrList
.count
].length
= (UInt32
) strlen(value
);
102 attrs
[attrList
.count
].data
= (void *)value
;
105 if (comment
!= NULL
) {
106 attrs
[attrList
.count
].tag
= kSecCommentItemAttr
;
107 attrs
[attrList
.count
].length
= (UInt32
) strlen(comment
);
108 attrs
[attrList
.count
].data
= (void *)comment
;
112 attrs
[attrList
.count
].tag
= kSecLabelItemAttr
;
113 attrs
[attrList
.count
].length
= (UInt32
) strlen(label
);
114 attrs
[attrList
.count
].data
= (void *)label
;
117 if (serviceName
!= NULL
) {
118 attrs
[attrList
.count
].tag
= kSecServiceItemAttr
;
119 attrs
[attrList
.count
].length
= (UInt32
) strlen(serviceName
);
120 attrs
[attrList
.count
].data
= (void *)serviceName
;
123 if (accountName
!= NULL
) {
124 attrs
[attrList
.count
].tag
= kSecAccountItemAttr
;
125 attrs
[attrList
.count
].length
= (UInt32
) strlen(accountName
);
126 attrs
[attrList
.count
].data
= (void *)accountName
;
130 // modify attributes and password data, if provided
131 status
= SecKeychainItemModifyContent(itemRef
, &attrList
, passwordLength
, passwordData
);
133 sec_error("SecKeychainItemModifyContent: %s", sec_errstr(status
));
136 // modify access, if provided
137 if (!status
&& access
) {
138 SecAccessRef curAccess
= NULL
;
139 // for historical reasons, we have to modify the item's existing access reference
140 // (setting the item's access to a freshly created SecAccessRef instance doesn't behave as expected)
141 status
= SecKeychainItemCopyAccess(itemRef
, &curAccess
);
143 sec_error("SecKeychainItemCopyAccess: %s", sec_errstr(status
));
145 int result
= merge_access(curAccess
, access
); // make changes to the existing access reference
146 if (result
== noErr
) {
147 status
= SecKeychainItemSetAccess(itemRef
, curAccess
); // will prompt
149 sec_error("SecKeychainItemSetAccess: %s", sec_errstr(status
));
154 CFRelease(curAccess
);
164 do_add_generic_password(const char *keychainName
,
165 FourCharCode itemCreator
,
166 FourCharCode itemType
,
171 const char *serviceName
,
172 const char *accountName
,
173 const void *passwordData
,
174 uint32_t passwordLength
,
178 SecKeychainRef keychain
= NULL
;
180 SecKeychainItemRef itemRef
= NULL
;
182 // if update flag is specified, try to find and update an existing item
184 result
= do_update_generic_password(keychainName
,itemCreator
,itemType
,kind
,value
,
185 comment
,label
,serviceName
,accountName
,passwordData
,passwordLength
,access
);
192 keychain
= keychain_open(keychainName
);
200 // set up attribute vector for new item (each attribute consists of {tag, length, pointer})
201 SecKeychainAttribute attrs
[] = {
202 { kSecLabelItemAttr
, label
? (UInt32
) strlen(label
) : 0, (char *)label
},
203 { kSecDescriptionItemAttr
, kind
? (UInt32
) strlen(kind
) : 0, (char *)kind
},
204 { kSecGenericItemAttr
, value
? (UInt32
) strlen(value
) : 0, (char *)value
},
205 { kSecCommentItemAttr
, comment
? (UInt32
) strlen(comment
) : 0, (char *)comment
},
206 { kSecServiceItemAttr
, serviceName
? (UInt32
) strlen(serviceName
) : 0, (char *)serviceName
},
207 { kSecAccountItemAttr
, accountName
? (UInt32
) strlen(accountName
) : 0, (char *)accountName
},
208 { (SecKeychainAttrType
)0, sizeof(FourCharCode
), NULL
}, /* placeholder */
209 { (SecKeychainAttrType
)0, sizeof(FourCharCode
), NULL
} /* placeholder */
211 SecKeychainAttributeList attributes
= { sizeof(attrs
) / sizeof(attrs
[0]), attrs
};
212 attributes
.count
-= 2;
214 if (itemCreator
!= 0)
216 attrs
[attributes
.count
].tag
= kSecCreatorItemAttr
;
217 attrs
[attributes
.count
].data
= (FourCharCode
*)&itemCreator
;
222 attrs
[attributes
.count
].tag
= kSecTypeItemAttr
;
223 attrs
[attributes
.count
].data
= (FourCharCode
*)&itemType
;
227 result
= SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass
,
237 sec_error("SecKeychainItemCreateFromContent (%s): %s", keychainName
? keychainName
: "<default>", sec_errstr(result
));
250 do_update_internet_password(const char *keychainName
,
251 FourCharCode itemCreator
,
252 FourCharCode itemType
,
256 const char *serverName
,
257 const char *securityDomain
,
258 const char *accountName
,
261 SecProtocolType protocol
,
262 SecAuthenticationType authenticationType
,
263 const void *passwordData
,
264 uint32_t passwordLength
,
268 SecKeychainRef keychainRef
= NULL
;
269 SecKeychainItemRef itemRef
= NULL
;
272 keychainRef
= keychain_open(keychainName
);
274 itemRef
= find_first_internet_password(keychainRef
,itemCreator
,itemType
,kind
,comment
,label
,serverName
,
275 securityDomain
,accountName
,path
,port
,protocol
,authenticationType
);
277 CFRelease(keychainRef
);
280 return errSecItemNotFound
;
283 // build list of attributes
284 SecKeychainAttribute attrs
[12]; // maximum number of attributes
285 SecKeychainAttributeList attrList
= { 0, attrs
};
287 if ((UInt32
)itemCreator
!= 0) {
288 attrs
[attrList
.count
].tag
= kSecCreatorItemAttr
;
289 attrs
[attrList
.count
].length
= sizeof(FourCharCode
);
290 attrs
[attrList
.count
].data
= (FourCharCode
*)&itemCreator
;
293 if ((UInt32
)itemType
!= 0) {
294 attrs
[attrList
.count
].tag
= kSecTypeItemAttr
;
295 attrs
[attrList
.count
].length
= sizeof(FourCharCode
);
296 attrs
[attrList
.count
].data
= (FourCharCode
*)&itemType
;
300 attrs
[attrList
.count
].tag
= kSecDescriptionItemAttr
;
301 attrs
[attrList
.count
].length
= (UInt32
) strlen(kind
);
302 attrs
[attrList
.count
].data
= (void *)kind
;
305 if (comment
!= NULL
) {
306 attrs
[attrList
.count
].tag
= kSecCommentItemAttr
;
307 attrs
[attrList
.count
].length
= (UInt32
) strlen(comment
);
308 attrs
[attrList
.count
].data
= (void *)comment
;
312 attrs
[attrList
.count
].tag
= kSecLabelItemAttr
;
313 attrs
[attrList
.count
].length
= (UInt32
) strlen(label
);
314 attrs
[attrList
.count
].data
= (void *)label
;
317 if (serverName
!= NULL
) {
318 attrs
[attrList
.count
].tag
= kSecServerItemAttr
;
319 attrs
[attrList
.count
].length
= (UInt32
) strlen(serverName
);
320 attrs
[attrList
.count
].data
= (void *)serverName
;
323 if (securityDomain
!= NULL
) {
324 attrs
[attrList
.count
].tag
= kSecSecurityDomainItemAttr
;
325 attrs
[attrList
.count
].length
= (UInt32
) strlen(securityDomain
);
326 attrs
[attrList
.count
].data
= (void *)securityDomain
;
329 if (accountName
!= NULL
) {
330 attrs
[attrList
.count
].tag
= kSecAccountItemAttr
;
331 attrs
[attrList
.count
].length
= (UInt32
) strlen(accountName
);
332 attrs
[attrList
.count
].data
= (void *)accountName
;
336 attrs
[attrList
.count
].tag
= kSecPathItemAttr
;
337 attrs
[attrList
.count
].length
= (UInt32
) strlen(path
);
338 attrs
[attrList
.count
].data
= (void *)path
;
342 attrs
[attrList
.count
].tag
= kSecPortItemAttr
;
343 attrs
[attrList
.count
].length
= sizeof(UInt16
);
344 attrs
[attrList
.count
].data
= (UInt16
*)&port
;
347 if ((UInt32
)protocol
!= 0) {
348 attrs
[attrList
.count
].tag
= kSecProtocolItemAttr
;
349 attrs
[attrList
.count
].length
= sizeof(SecProtocolType
);
350 attrs
[attrList
.count
].data
= (SecProtocolType
*)&protocol
;
353 if ((UInt32
)authenticationType
!= 0) {
354 attrs
[attrList
.count
].tag
= kSecAuthenticationTypeItemAttr
;
355 attrs
[attrList
.count
].length
= sizeof(SecAuthenticationType
);
356 attrs
[attrList
.count
].data
= (SecAuthenticationType
*)&authenticationType
;
360 // modify attributes and password data, if provided
361 status
= SecKeychainItemModifyContent(itemRef
, &attrList
, passwordLength
, passwordData
);
363 sec_error("SecKeychainItemModifyContent: %s", sec_errstr(status
));
366 // modify access, if provided
367 if (!status
&& access
) {
368 status
= modify_access(itemRef
, access
);
377 do_add_internet_password(const char *keychainName
,
378 FourCharCode itemCreator
,
379 FourCharCode itemType
,
383 const char *serverName
,
384 const char *securityDomain
,
385 const char *accountName
,
388 SecProtocolType protocol
,
389 SecAuthenticationType authenticationType
,
390 const void *passwordData
,
391 uint32_t passwordLength
,
395 SecKeychainRef keychain
= NULL
;
396 SecKeychainItemRef itemRef
= NULL
;
399 // if update flag is specified, try to find and update an existing item
401 result
= do_update_internet_password(keychainName
,itemCreator
,itemType
,kind
,comment
,label
,serverName
,
402 securityDomain
,accountName
,path
,port
,protocol
,authenticationType
,
403 passwordData
,passwordLength
,access
);
410 keychain
= keychain_open(keychainName
);
418 // set up attribute vector for new item (each attribute consists of {tag, length, pointer})
419 SecKeychainAttribute attrs
[] = {
420 { kSecLabelItemAttr
, label
? (UInt32
) strlen(label
) : 0, (char *)label
},
421 { kSecDescriptionItemAttr
, kind
? (UInt32
) strlen(kind
) : 0, (char *)kind
},
422 { kSecCommentItemAttr
, comment
? (UInt32
) strlen(comment
) : 0, (char *)comment
},
423 { kSecServerItemAttr
, serverName
? (UInt32
) strlen(serverName
) : 0, (char *)serverName
},
424 { kSecSecurityDomainItemAttr
, securityDomain
? (UInt32
) strlen(securityDomain
) : 0, (char *)securityDomain
},
425 { kSecAccountItemAttr
, accountName
? (UInt32
) strlen(accountName
) : 0, (char *)accountName
},
426 { kSecPathItemAttr
, path
? (UInt32
) strlen(path
) : 0, (char *)path
},
427 { kSecPortItemAttr
, sizeof(UInt16
), (UInt16
*)&port
},
428 { kSecProtocolItemAttr
, sizeof(SecProtocolType
), (SecProtocolType
*)&protocol
},
429 { kSecAuthenticationTypeItemAttr
, sizeof(SecAuthenticationType
), (SecAuthenticationType
*)&authenticationType
},
430 { (SecKeychainAttrType
)0, sizeof(FourCharCode
), NULL
}, /* placeholder */
431 { (SecKeychainAttrType
)0, sizeof(FourCharCode
), NULL
} /* placeholder */
433 SecKeychainAttributeList attributes
= { sizeof(attrs
) / sizeof(attrs
[0]), attrs
};
434 attributes
.count
-= 2;
436 if (itemCreator
!= 0)
438 attrs
[attributes
.count
].tag
= kSecCreatorItemAttr
;
439 attrs
[attributes
.count
].data
= (FourCharCode
*)&itemCreator
;
444 attrs
[attributes
.count
].tag
= kSecTypeItemAttr
;
445 attrs
[attributes
.count
].data
= (FourCharCode
*)&itemType
;
449 result
= SecKeychainItemCreateFromContent(kSecInternetPasswordItemClass
,
459 sec_error("SecKeychainAddInternetPassword %s: %s", keychainName
? keychainName
: "<NULL>", sec_errstr(result
));
472 do_add_certificates(const char *keychainName
, int argc
, char * const *argv
)
474 SecKeychainRef keychain
= NULL
;
479 keychain
= keychain_open(keychainName
);
487 for (ix
= 0; ix
< argc
; ++ix
)
489 CSSM_DATA certData
= {};
491 SecCertificateRef certificate
= NULL
;
493 if (read_file(argv
[ix
], &certData
))
499 status
= SecCertificateCreateFromData(&certData
, CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_UNKNOWN
, &certificate
);
502 sec_perror("SecCertificateCreateFromData", status
);
507 status
= SecCertificateAddToKeychain(certificate
, keychain
);
510 if (status
== errSecDuplicateItem
)
513 sec_error("%s: already in %s", argv
[ix
], keychainName
);
515 sec_error("%s: already in default keychain", argv
[ix
]);
519 sec_perror("SecCertificateAddToKeychain", status
);
528 CFRelease(certificate
);
538 static bool convertPasswordData(const char *hexString
, char **outData
, uint32_t *outLength
) {
540 bool result
= convertHex(hexString
, (uint8_t **)outData
, &length
);
541 if (result
&& outLength
) {
542 *outLength
= (uint32_t)length
& 0xFFFFFFFF;
547 static bool promptForPasswordData(char **returnedPasswordData
) {
548 // Caller must zero memory and free returned value.
549 // Returns true if we have data; false means the user canceled
550 if (!returnedPasswordData
)
554 char *password
= NULL
;
557 for (tries
= 3; tries
-- > 0;) {
558 bool passwordsMatch
= false;
559 char *firstpass
= NULL
;
561 password
= getpass("password data for new item: ");
565 firstpass
= malloc(strlen(password
) + 1);
566 strcpy(firstpass
, password
);
567 password
= getpass("retype password for new item: ");
568 passwordsMatch
= password
&& (strcmp(password
, firstpass
) == 0);
569 memset(firstpass
, 0, strlen(firstpass
));
574 if (passwordsMatch
) {
579 fprintf(stderr
, "passwords don't match\n");
580 memset(password
, 0, strlen(password
));
584 *returnedPasswordData
= password
;
592 keychain_add_generic_password(int argc
, char * const *argv
)
594 char *serviceName
= NULL
, *passwordData
= NULL
, *accountName
= NULL
;
595 char *kind
= NULL
, *label
= NULL
, *value
= NULL
, *comment
= NULL
;
596 FourCharCode itemCreator
= 0, itemType
= 0;
598 uint32_t passwordLength
= 0;
599 const char *keychainName
= NULL
;
600 Boolean access_specified
= FALSE
;
601 Boolean always_allow
= FALSE
;
602 Boolean update_item
= FALSE
;
603 SecAccessRef access
= NULL
;
604 CFMutableArrayRef trusted_list
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
606 bool mustFreePasswordData
= false; // if we got it via user prompting
609 * " -a Specify account name (required)\n"
610 * " -c Specify item creator (optional four-character code)\n"
611 * " -C Specify item type (optional four-character code)\n"
612 * " -D Specify kind (default is \"application password\")\n"
613 * " -G Specify generic attribute (optional)\n"
614 * " -j Specify comment string (optional)\n"
615 * " -l Specify label (if omitted, service name is used as default label)\n"
616 * " -s Specify service name (required)\n"
617 * " -p Specify password to be added (legacy option, equivalent to -w)\n"
618 * " -w Specify password to be added\n"
619 * " -X Specify password data to be added as a hexadecimal string\n"
620 * " -A Allow any application to access this item without warning (insecure, not recommended!)\n"
621 * " -T Specify an application which may access this item (multiple -T options are allowed)\n"
622 * " -U Update item if it already exists (if omitted, the item cannot already exist)\n"
625 while ((ch
= getopt(argc
, argv
, ":a:c:C:D:G:j:l:s:p:w:X:UAT:h")) != -1)
630 accountName
= optarg
;
633 result
= parse_fourcharcode(optarg
, &itemCreator
);
634 if (result
) goto cleanup
;
637 result
= parse_fourcharcode(optarg
, &itemType
);
638 if (result
) goto cleanup
;
653 serviceName
= optarg
;
657 passwordData
= optarg
;
658 passwordLength
= (passwordData
) ? (uint32_t)strlen(passwordData
) : 0;
665 access_specified
= TRUE
;
671 SecTrustedApplicationRef app
= NULL
;
672 /* check whether the argument specifies an application group */
673 const char *groupPrefix
= "group://";
674 size_t prefixLen
= strlen(groupPrefix
);
675 if (strlen(optarg
) > prefixLen
&& !memcmp(optarg
, groupPrefix
, prefixLen
)) {
676 const char *groupName
= &optarg
[prefixLen
];
677 if ((status
= SecTrustedApplicationCreateApplicationGroup(groupName
, NULL
, &app
)) != noErr
) {
678 sec_error("SecTrustedApplicationCreateApplicationGroup %s: %s", optarg
, sec_errstr(status
));
681 if ((status
= SecTrustedApplicationCreateFromPath(optarg
, &app
)) != noErr
) {
682 sec_error("SecTrustedApplicationCreateFromPath %s: %s", optarg
, sec_errstr(status
));
691 CFArrayAppendValue(trusted_list
, app
);
694 access_specified
= TRUE
;
698 if (convertPasswordData(optarg
, &passwordData
, &passwordLength
)) {
699 mustFreePasswordData
= true;
702 sec_error("Unable to convert password data (-X must specify valid hex digits)");
704 goto cleanup
; /* @@@ Return 2 triggers usage message. */
707 // They supplied the -p or -w but with no data, so prompt
708 // This differs from the case where no -p or -w was given, where we set the data to empty
709 if (optopt
== 'p' || optopt
== 'w') {
710 if (promptForPasswordData(&passwordData
)) {
711 passwordLength
= (passwordData
) ? (uint32_t)strlen(passwordData
) : 0;
712 mustFreePasswordData
= true;
716 goto cleanup
; /* @@@ Do not trigger usage message, but indicate failure. */
720 goto cleanup
; /* @@@ Return 2 triggers usage message. */
723 goto cleanup
; /* @@@ Return 2 triggers usage message. */
730 if (!accountName
|| !serviceName
)
737 keychainName
= argv
[0];
738 if (argc
> 1 || *keychainName
== '\0')
745 if (access_specified
)
747 const char *accessName
= (label
) ? label
: (serviceName
) ? serviceName
: (accountName
) ? accountName
: "";
748 if ((result
= create_access(accessName
, always_allow
, trusted_list
, &access
)) != 0)
752 result
= do_add_generic_password(keychainName
,
758 (label
) ? label
: serviceName
,
767 if (mustFreePasswordData
) {
771 CFRelease(trusted_list
);
781 keychain_add_internet_password(int argc
, char * const *argv
)
783 char *serverName
= NULL
, *securityDomain
= NULL
, *accountName
= NULL
, *path
= NULL
, *passwordData
= NULL
;
784 char *kind
= NULL
, *comment
= NULL
, *label
= NULL
;
785 FourCharCode itemCreator
= 0, itemType
= 0;
787 SecProtocolType protocol
= 0;
788 SecAuthenticationType authenticationType
= OSSwapHostToBigInt32('dflt');
790 uint32_t passwordLength
= 0;
791 const char *keychainName
= NULL
;
792 Boolean access_specified
= FALSE
;
793 Boolean always_allow
= FALSE
;
794 Boolean update_item
= FALSE
;
795 SecAccessRef access
= NULL
;
796 CFMutableArrayRef trusted_list
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
798 bool mustFreePasswordData
= false; // if we got it via user prompting
801 * " -a Specify account name (required)\n"
802 * " -c Specify item creator (optional four-character code)\n"
803 * " -C Specify item type (optional four-character code)\n"
804 * " -d Specify security domain string (optional)\n"
805 * " -D Specify kind (default is \"Internet password\")\n"
806 * " -j Specify comment string (optional)\n"
807 * " -l Specify label (if omitted, server name is used as default label)\n"
808 * " -p Specify path string (optional)\n"
809 * " -P Specify port number (optional)\n"
810 * " -r Specify protocol (optional four-character SecProtocolType, e.g. \"http\", \"ftp \")\n"
811 * " -s Specify server name (required)\n"
812 * " -t Specify authentication type (as a four-character SecAuthenticationType, default is \"dflt\")\n"
813 * " -w Specify password to be added\n"
814 * " -X Specify password data to be added as a hexadecimal string\n"
815 * " -A Allow any application to access this item without warning (insecure, not recommended!)\n"
816 * " -T Specify an application which may access this item (multiple -T options are allowed)\n"
817 * " -U Update item if it already exists (if omitted, the item cannot already exist)\n"
820 while ((ch
= getopt(argc
, argv
, ":a:c:C:d:D:j:l:p:P:r:s:t:w:X:UAT:h")) != -1)
825 accountName
= optarg
;
828 result
= parse_fourcharcode(optarg
, &itemCreator
);
829 if (result
) goto cleanup
;
832 result
= parse_fourcharcode(optarg
, &itemType
);
833 if (result
) goto cleanup
;
836 securityDomain
= optarg
;
854 result
= parse_fourcharcode(optarg
, &protocol
);
855 if (result
) goto cleanup
;
861 result
= parse_fourcharcode(optarg
, &authenticationType
);
862 if (result
) goto cleanup
;
863 /* auth type attribute is special */
864 authenticationType
= OSSwapHostToBigInt32(authenticationType
);
867 passwordData
= optarg
;
868 passwordLength
= (passwordData
) ? (uint32_t)strlen(passwordData
) : 0;
875 access_specified
= TRUE
;
881 SecTrustedApplicationRef app
= NULL
;
882 /* check whether the argument specifies an application group */
883 const char *groupPrefix
= "group://";
884 size_t prefixLen
= strlen(groupPrefix
);
885 if (strlen(optarg
) > prefixLen
&& !memcmp(optarg
, groupPrefix
, prefixLen
)) {
886 const char *groupName
= &optarg
[prefixLen
];
887 if ((status
= SecTrustedApplicationCreateApplicationGroup(groupName
, NULL
, &app
)) != noErr
) {
888 sec_error("SecTrustedApplicationCreateApplicationGroup %s: %s", optarg
, sec_errstr(status
));
891 if ((status
= SecTrustedApplicationCreateFromPath(optarg
, &app
)) != noErr
) {
892 sec_error("SecTrustedApplicationCreateFromPath %s: %s", optarg
, sec_errstr(status
));
901 CFArrayAppendValue(trusted_list
, app
);
904 access_specified
= TRUE
;
908 if (convertPasswordData(optarg
, &passwordData
, &passwordLength
)) {
909 mustFreePasswordData
= true;
912 sec_error("Unable to convert password data (-X must specify valid hex digits)");
914 goto cleanup
; /* @@@ Return 2 triggers usage message. */
917 // They supplied the -p or -w but with no data, so prompt
918 // This differs from the case where no -p or -w was given, where we set the data to empty
919 if (optopt
== 'p' || optopt
== 'w') {
920 if (promptForPasswordData(&passwordData
)) {
921 passwordLength
= (passwordData
) ? (uint32_t)strlen(passwordData
) : 0;
922 mustFreePasswordData
= true;
926 goto cleanup
; /* @@@ Do not trigger usage message, but indicate failure. */
930 goto cleanup
; /* @@@ Return 2 triggers usage message. */
934 goto cleanup
; /* @@@ Return 2 triggers usage message. */
941 if (!accountName
|| !serverName
)
948 keychainName
= argv
[0];
949 if (argc
> 1 || *keychainName
== '\0')
956 if (access_specified
)
958 const char *accessName
= (label
) ? label
: (serverName
) ? serverName
: (accountName
) ? accountName
: "";
959 if ((result
= create_access(accessName
, always_allow
, trusted_list
, &access
)) != 0)
963 result
= do_add_internet_password(keychainName
,
968 (label
) ? label
: serverName
,
982 if (mustFreePasswordData
) {
986 CFRelease(trusted_list
);
996 keychain_add_certificates(int argc
, char * const *argv
)
999 const char *keychainName
= NULL
;
1000 while ((ch
= getopt(argc
, argv
, "hk:")) != -1)
1005 keychainName
= optarg
;
1006 if (*keychainName
== '\0')
1007 return SHOW_USAGE_MESSAGE
;
1011 return SHOW_USAGE_MESSAGE
;
1019 return SHOW_USAGE_MESSAGE
;
1021 result
= do_add_certificates(keychainName
, argc
, argv
);