2 * Copyright (c) 2003-2009,2011-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_add.h"
27 #include "keychain_find.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
,
62 SecKeychainRef keychainRef
= NULL
;
63 SecKeychainItemRef itemRef
= NULL
;
66 keychainRef
= keychain_open(keychainName
);
68 itemRef
= find_first_generic_password(keychainRef
,itemCreator
,itemType
,kind
,value
,comment
,label
,serviceName
,accountName
);
70 CFRelease(keychainRef
);
73 return errSecItemNotFound
;
76 // build list of attributes
77 SecKeychainAttribute attrs
[8]; // maximum number of attributes
78 SecKeychainAttributeList attrList
= { 0, attrs
};
80 if ((UInt32
)itemCreator
!= 0) {
81 attrs
[attrList
.count
].tag
= kSecCreatorItemAttr
;
82 attrs
[attrList
.count
].length
= sizeof(FourCharCode
);
83 attrs
[attrList
.count
].data
= (FourCharCode
*)&itemCreator
;
86 if ((UInt32
)itemType
!= 0) {
87 attrs
[attrList
.count
].tag
= kSecTypeItemAttr
;
88 attrs
[attrList
.count
].length
= sizeof(FourCharCode
);
89 attrs
[attrList
.count
].data
= (FourCharCode
*)&itemType
;
93 attrs
[attrList
.count
].tag
= kSecDescriptionItemAttr
;
94 attrs
[attrList
.count
].length
= (UInt32
) strlen(kind
);
95 attrs
[attrList
.count
].data
= (void *)kind
;
99 attrs
[attrList
.count
].tag
= kSecGenericItemAttr
;
100 attrs
[attrList
.count
].length
= (UInt32
) strlen(value
);
101 attrs
[attrList
.count
].data
= (void *)value
;
104 if (comment
!= NULL
) {
105 attrs
[attrList
.count
].tag
= kSecCommentItemAttr
;
106 attrs
[attrList
.count
].length
= (UInt32
) strlen(comment
);
107 attrs
[attrList
.count
].data
= (void *)comment
;
111 attrs
[attrList
.count
].tag
= kSecLabelItemAttr
;
112 attrs
[attrList
.count
].length
= (UInt32
) strlen(label
);
113 attrs
[attrList
.count
].data
= (void *)label
;
116 if (serviceName
!= NULL
) {
117 attrs
[attrList
.count
].tag
= kSecServiceItemAttr
;
118 attrs
[attrList
.count
].length
= (UInt32
) strlen(serviceName
);
119 attrs
[attrList
.count
].data
= (void *)serviceName
;
122 if (accountName
!= NULL
) {
123 attrs
[attrList
.count
].tag
= kSecAccountItemAttr
;
124 attrs
[attrList
.count
].length
= (UInt32
) strlen(accountName
);
125 attrs
[attrList
.count
].data
= (void *)accountName
;
129 // modify attributes and password data, if provided
130 status
= SecKeychainItemModifyContent(itemRef
, &attrList
, (passwordData
) ? ((UInt32
) strlen(passwordData
)) : 0, passwordData
);
132 sec_error("SecKeychainItemModifyContent: %s", sec_errstr(status
));
135 // modify access, if provided
136 if (!status
&& access
) {
137 SecAccessRef curAccess
= NULL
;
138 // for historical reasons, we have to modify the item's existing access reference
139 // (setting the item's access to a freshly created SecAccessRef instance doesn't behave as expected)
140 status
= SecKeychainItemCopyAccess(itemRef
, &curAccess
);
142 sec_error("SecKeychainItemCopyAccess: %s", sec_errstr(status
));
144 int result
= merge_access(curAccess
, access
); // make changes to the existing access reference
145 if (result
== noErr
) {
146 status
= SecKeychainItemSetAccess(itemRef
, curAccess
); // will prompt
148 sec_error("SecKeychainItemSetAccess: %s", sec_errstr(status
));
153 CFRelease(curAccess
);
163 do_add_generic_password(const char *keychainName
,
164 FourCharCode itemCreator
,
165 FourCharCode itemType
,
170 const char *serviceName
,
171 const char *accountName
,
172 const void *passwordData
,
176 SecKeychainRef keychain
= NULL
;
178 SecKeychainItemRef itemRef
= NULL
;
180 // if update flag is specified, try to find and update an existing item
182 result
= do_update_generic_password(keychainName
,itemCreator
,itemType
,kind
,value
,comment
,label
,serviceName
,accountName
,passwordData
,access
);
189 keychain
= keychain_open(keychainName
);
197 // set up attribute vector for new item (each attribute consists of {tag, length, pointer})
198 SecKeychainAttribute attrs
[] = {
199 { kSecLabelItemAttr
, label
? (UInt32
) strlen(label
) : 0, (char *)label
},
200 { kSecDescriptionItemAttr
, kind
? (UInt32
) strlen(kind
) : 0, (char *)kind
},
201 { kSecGenericItemAttr
, value
? (UInt32
) strlen(value
) : 0, (char *)value
},
202 { kSecCommentItemAttr
, comment
? (UInt32
) strlen(comment
) : 0, (char *)comment
},
203 { kSecServiceItemAttr
, serviceName
? (UInt32
) strlen(serviceName
) : 0, (char *)serviceName
},
204 { kSecAccountItemAttr
, accountName
? (UInt32
) strlen(accountName
) : 0, (char *)accountName
},
205 { (SecKeychainAttrType
)0, sizeof(FourCharCode
), NULL
}, /* placeholder */
206 { (SecKeychainAttrType
)0, sizeof(FourCharCode
), NULL
} /* placeholder */
208 SecKeychainAttributeList attributes
= { sizeof(attrs
) / sizeof(attrs
[0]), attrs
};
209 attributes
.count
-= 2;
211 if (itemCreator
!= 0)
213 attrs
[attributes
.count
].tag
= kSecCreatorItemAttr
;
214 attrs
[attributes
.count
].data
= (FourCharCode
*)&itemCreator
;
219 attrs
[attributes
.count
].tag
= kSecTypeItemAttr
;
220 attrs
[attributes
.count
].data
= (FourCharCode
*)&itemType
;
224 result
= SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass
,
226 passwordData
? (UInt32
) strlen(passwordData
) : 0,
234 sec_error("SecKeychainItemCreateFromContent (%s): %s", keychainName
? keychainName
: "<default>", sec_errstr(result
));
247 do_update_internet_password(const char *keychainName
,
248 FourCharCode itemCreator
,
249 FourCharCode itemType
,
253 const char *serverName
,
254 const char *securityDomain
,
255 const char *accountName
,
258 SecProtocolType protocol
,
259 SecAuthenticationType authenticationType
,
260 const void *passwordData
,
264 SecKeychainRef keychainRef
= NULL
;
265 SecKeychainItemRef itemRef
= NULL
;
268 keychainRef
= keychain_open(keychainName
);
270 itemRef
= find_first_internet_password(keychainRef
,itemCreator
,itemType
,kind
,comment
,label
,serverName
,
271 securityDomain
,accountName
,path
,port
,protocol
,authenticationType
);
273 CFRelease(keychainRef
);
276 return errSecItemNotFound
;
279 // build list of attributes
280 SecKeychainAttribute attrs
[12]; // maximum number of attributes
281 SecKeychainAttributeList attrList
= { 0, attrs
};
283 if ((UInt32
)itemCreator
!= 0) {
284 attrs
[attrList
.count
].tag
= kSecCreatorItemAttr
;
285 attrs
[attrList
.count
].length
= sizeof(FourCharCode
);
286 attrs
[attrList
.count
].data
= (FourCharCode
*)&itemCreator
;
289 if ((UInt32
)itemType
!= 0) {
290 attrs
[attrList
.count
].tag
= kSecTypeItemAttr
;
291 attrs
[attrList
.count
].length
= sizeof(FourCharCode
);
292 attrs
[attrList
.count
].data
= (FourCharCode
*)&itemType
;
296 attrs
[attrList
.count
].tag
= kSecDescriptionItemAttr
;
297 attrs
[attrList
.count
].length
= (UInt32
) strlen(kind
);
298 attrs
[attrList
.count
].data
= (void *)kind
;
301 if (comment
!= NULL
) {
302 attrs
[attrList
.count
].tag
= kSecCommentItemAttr
;
303 attrs
[attrList
.count
].length
= (UInt32
) strlen(comment
);
304 attrs
[attrList
.count
].data
= (void *)comment
;
308 attrs
[attrList
.count
].tag
= kSecLabelItemAttr
;
309 attrs
[attrList
.count
].length
= (UInt32
) strlen(label
);
310 attrs
[attrList
.count
].data
= (void *)label
;
313 if (serverName
!= NULL
) {
314 attrs
[attrList
.count
].tag
= kSecServerItemAttr
;
315 attrs
[attrList
.count
].length
= (UInt32
) strlen(serverName
);
316 attrs
[attrList
.count
].data
= (void *)serverName
;
319 if (securityDomain
!= NULL
) {
320 attrs
[attrList
.count
].tag
= kSecSecurityDomainItemAttr
;
321 attrs
[attrList
.count
].length
= (UInt32
) strlen(securityDomain
);
322 attrs
[attrList
.count
].data
= (void *)securityDomain
;
325 if (accountName
!= NULL
) {
326 attrs
[attrList
.count
].tag
= kSecAccountItemAttr
;
327 attrs
[attrList
.count
].length
= (UInt32
) strlen(accountName
);
328 attrs
[attrList
.count
].data
= (void *)accountName
;
332 attrs
[attrList
.count
].tag
= kSecPathItemAttr
;
333 attrs
[attrList
.count
].length
= (UInt32
) strlen(path
);
334 attrs
[attrList
.count
].data
= (void *)path
;
338 attrs
[attrList
.count
].tag
= kSecPortItemAttr
;
339 attrs
[attrList
.count
].length
= sizeof(UInt16
);
340 attrs
[attrList
.count
].data
= (UInt16
*)&port
;
343 if ((UInt32
)protocol
!= 0) {
344 attrs
[attrList
.count
].tag
= kSecProtocolItemAttr
;
345 attrs
[attrList
.count
].length
= sizeof(SecProtocolType
);
346 attrs
[attrList
.count
].data
= (SecProtocolType
*)&protocol
;
349 if ((UInt32
)authenticationType
!= 0) {
350 attrs
[attrList
.count
].tag
= kSecAuthenticationTypeItemAttr
;
351 attrs
[attrList
.count
].length
= sizeof(SecAuthenticationType
);
352 attrs
[attrList
.count
].data
= (SecAuthenticationType
*)&authenticationType
;
356 // modify attributes and password data, if provided
357 status
= SecKeychainItemModifyContent(itemRef
, &attrList
, (passwordData
) ? (UInt32
) strlen(passwordData
) : 0, passwordData
);
359 sec_error("SecKeychainItemModifyContent: %s", sec_errstr(status
));
362 // modify access, if provided
363 if (!status
&& access
) {
364 status
= modify_access(itemRef
, access
);
373 do_add_internet_password(const char *keychainName
,
374 FourCharCode itemCreator
,
375 FourCharCode itemType
,
379 const char *serverName
,
380 const char *securityDomain
,
381 const char *accountName
,
384 SecProtocolType protocol
,
385 SecAuthenticationType authenticationType
,
386 const void *passwordData
,
390 SecKeychainRef keychain
= NULL
;
391 SecKeychainItemRef itemRef
= NULL
;
394 // if update flag is specified, try to find and update an existing item
396 result
= do_update_internet_password(keychainName
,itemCreator
,itemType
,kind
,comment
,label
,serverName
,
397 securityDomain
,accountName
,path
,port
,protocol
,authenticationType
,
398 passwordData
,access
);
405 keychain
= keychain_open(keychainName
);
413 // set up attribute vector for new item (each attribute consists of {tag, length, pointer})
414 SecKeychainAttribute attrs
[] = {
415 { kSecLabelItemAttr
, label
? (UInt32
) strlen(label
) : 0, (char *)label
},
416 { kSecDescriptionItemAttr
, kind
? (UInt32
) strlen(kind
) : 0, (char *)kind
},
417 { kSecCommentItemAttr
, comment
? (UInt32
) strlen(comment
) : 0, (char *)comment
},
418 { kSecServerItemAttr
, serverName
? (UInt32
) strlen(serverName
) : 0, (char *)serverName
},
419 { kSecSecurityDomainItemAttr
, securityDomain
? (UInt32
) strlen(securityDomain
) : 0, (char *)securityDomain
},
420 { kSecAccountItemAttr
, accountName
? (UInt32
) strlen(accountName
) : 0, (char *)accountName
},
421 { kSecPathItemAttr
, path
? (UInt32
) strlen(path
) : 0, (char *)path
},
422 { kSecPortItemAttr
, sizeof(UInt16
), (UInt16
*)&port
},
423 { kSecProtocolItemAttr
, sizeof(SecProtocolType
), (SecProtocolType
*)&protocol
},
424 { kSecAuthenticationTypeItemAttr
, sizeof(SecAuthenticationType
), (SecAuthenticationType
*)&authenticationType
},
425 { (SecKeychainAttrType
)0, sizeof(FourCharCode
), NULL
}, /* placeholder */
426 { (SecKeychainAttrType
)0, sizeof(FourCharCode
), NULL
} /* placeholder */
428 SecKeychainAttributeList attributes
= { sizeof(attrs
) / sizeof(attrs
[0]), attrs
};
429 attributes
.count
-= 2;
431 if (itemCreator
!= 0)
433 attrs
[attributes
.count
].tag
= kSecCreatorItemAttr
;
434 attrs
[attributes
.count
].data
= (FourCharCode
*)&itemCreator
;
439 attrs
[attributes
.count
].tag
= kSecTypeItemAttr
;
440 attrs
[attributes
.count
].data
= (FourCharCode
*)&itemType
;
444 result
= SecKeychainItemCreateFromContent(kSecInternetPasswordItemClass
,
446 passwordData
? (UInt32
) strlen(passwordData
) : 0,
454 sec_error("SecKeychainAddInternetPassword %s: %s", keychainName
? keychainName
: "<NULL>", sec_errstr(result
));
467 do_add_certificates(const char *keychainName
, int argc
, char * const *argv
)
469 SecKeychainRef keychain
= NULL
;
474 keychain
= keychain_open(keychainName
);
482 for (ix
= 0; ix
< argc
; ++ix
)
484 CSSM_DATA certData
= {};
486 SecCertificateRef certificate
= NULL
;
488 if (read_file(argv
[ix
], &certData
))
494 status
= SecCertificateCreateFromData(&certData
, CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_UNKNOWN
, &certificate
);
497 sec_perror("SecCertificateCreateFromData", status
);
502 status
= SecCertificateAddToKeychain(certificate
, keychain
);
505 if (status
== errSecDuplicateItem
)
508 sec_error("%s: already in %s", argv
[ix
], keychainName
);
510 sec_error("%s: already in default keychain", argv
[ix
]);
514 sec_perror("SecCertificateAddToKeychain", status
);
523 CFRelease(certificate
);
533 static bool promptForPasswordData(char **returnedPasswordData
) {
534 // Caller must zero memory and free returned value.
535 // Returns true if we have data; false means the user cancelled
536 if (!returnedPasswordData
)
540 char *password
= NULL
;
543 for (tries
= 3; tries
-- > 0;) {
544 bool passwordsMatch
= false;
545 char *firstpass
= NULL
;
547 password
= getpass("password data for new item: ");
551 firstpass
= malloc(strlen(password
) + 1);
552 strcpy(firstpass
, password
);
553 password
= getpass("retype password for new item: ");
554 passwordsMatch
= password
&& (strcmp(password
, firstpass
) == 0);
555 memset(firstpass
, 0, strlen(firstpass
));
560 if (passwordsMatch
) {
565 fprintf(stderr
, "passwords don't match\n");
566 memset(password
, 0, strlen(password
));
570 *returnedPasswordData
= password
;
578 keychain_add_generic_password(int argc
, char * const *argv
)
580 char *serviceName
= NULL
, *passwordData
= NULL
, *accountName
= NULL
;
581 char *kind
= NULL
, *label
= NULL
, *value
= NULL
, *comment
= NULL
;
582 FourCharCode itemCreator
= 0, itemType
= 0;
584 const char *keychainName
= NULL
;
585 Boolean access_specified
= FALSE
;
586 Boolean always_allow
= FALSE
;
587 Boolean update_item
= FALSE
;
588 SecAccessRef access
= NULL
;
589 CFMutableArrayRef trusted_list
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
591 bool mustFreePasswordData
= false; // if we got it via user prompting
594 * " -a Specify account name (required)\n"
595 * " -c Specify item creator (optional four-character code)\n"
596 * " -C Specify item type (optional four-character code)\n"
597 * " -D Specify kind (default is \"application password\")\n"
598 * " -G Specify generic attribute (optional)\n"
599 * " -j Specify comment string (optional)\n"
600 * " -l Specify label (if omitted, service name is used as default label)\n"
601 * " -s Specify service name (required)\n"
602 * " -p Specify password to be added (legacy option, equivalent to -w)\n"
603 * " -w Specify password to be added\n"
604 * " -A Allow any application to access this item without warning (insecure, not recommended!)\n"
605 * " -T Specify an application which may access this item (multiple -T options are allowed)\n"
606 * " -U Update item if it already exists (if omitted, the item cannot already exist)\n"
609 while ((ch
= getopt(argc
, argv
, ":a:c:C:D:G:j:l:s:p:w:UAT:")) != -1)
614 accountName
= optarg
;
617 result
= parse_fourcharcode(optarg
, &itemCreator
);
618 if (result
) goto cleanup
;
621 result
= parse_fourcharcode(optarg
, &itemType
);
622 if (result
) goto cleanup
;
637 serviceName
= optarg
;
641 passwordData
= optarg
;
648 access_specified
= TRUE
;
654 SecTrustedApplicationRef app
= NULL
;
655 /* check whether the argument specifies an application group */
656 const char *groupPrefix
= "group://";
657 size_t prefixLen
= strlen(groupPrefix
);
658 if (strlen(optarg
) > prefixLen
&& !memcmp(optarg
, groupPrefix
, prefixLen
)) {
659 const char *groupName
= &optarg
[prefixLen
];
660 if ((status
= SecTrustedApplicationCreateApplicationGroup(groupName
, NULL
, &app
)) != noErr
) {
661 sec_error("SecTrustedApplicationCreateApplicationGroup %s: %s", optarg
, sec_errstr(status
));
664 if ((status
= SecTrustedApplicationCreateFromPath(optarg
, &app
)) != noErr
) {
665 sec_error("SecTrustedApplicationCreateFromPath %s: %s", optarg
, sec_errstr(status
));
674 CFArrayAppendValue(trusted_list
, app
);
677 access_specified
= TRUE
;
682 // They supplied the -p or -w but with no data, so prompt
683 // This differs from the case where no -p or -w was given, where we set the data to empty
684 if (optopt
== 'p' || optopt
== 'w') {
685 if (promptForPasswordData(&passwordData
)) {
686 mustFreePasswordData
= true;
690 goto cleanup
; /* @@@ Do not trigger usage message, but indicate failure. */
694 goto cleanup
; /* @@@ Return 2 triggers usage message. */
697 goto cleanup
; /* @@@ Return 2 triggers usage message. */
704 if (!accountName
|| !serviceName
)
711 keychainName
= argv
[0];
712 if (argc
> 1 || *keychainName
== '\0')
719 if (access_specified
)
721 const char *accessName
= (label
) ? label
: (serviceName
) ? serviceName
: (accountName
) ? accountName
: "";
722 if ((result
= create_access(accessName
, always_allow
, trusted_list
, &access
)) != 0)
726 result
= do_add_generic_password(keychainName
,
732 (label
) ? label
: serviceName
,
740 if (mustFreePasswordData
)
743 CFRelease(trusted_list
);
751 keychain_add_internet_password(int argc
, char * const *argv
)
753 char *serverName
= NULL
, *securityDomain
= NULL
, *accountName
= NULL
, *path
= NULL
, *passwordData
= NULL
;
754 char *kind
= NULL
, *comment
= NULL
, *label
= NULL
;
755 FourCharCode itemCreator
= 0, itemType
= 0;
757 SecProtocolType protocol
= 0;
758 SecAuthenticationType authenticationType
= OSSwapHostToBigInt32('dflt');
760 const char *keychainName
= NULL
;
761 Boolean access_specified
= FALSE
;
762 Boolean always_allow
= FALSE
;
763 Boolean update_item
= FALSE
;
764 SecAccessRef access
= NULL
;
765 CFMutableArrayRef trusted_list
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
767 bool mustFreePasswordData
= false; // if we got it via user prompting
770 * " -a Specify account name (required)\n"
771 * " -c Specify item creator (optional four-character code)\n"
772 * " -C Specify item type (optional four-character code)\n"
773 * " -d Specify security domain string (optional)\n"
774 * " -D Specify kind (default is \"Internet password\")\n"
775 * " -j Specify comment string (optional)\n"
776 * " -l Specify label (if omitted, server name is used as default label)\n"
777 * " -p Specify path string (optional)\n"
778 * " -P Specify port number (optional)\n"
779 * " -r Specify protocol (optional four-character SecProtocolType, e.g. \"http\", \"ftp \")\n"
780 * " -s Specify server name (required)\n"
781 * " -t Specify authentication type (as a four-character SecAuthenticationType, default is \"dflt\")\n"
782 * " -w Specify password to be added\n"
783 * " -A Allow any application to access this item without warning (insecure, not recommended!)\n"
784 * " -T Specify an application which may access this item (multiple -T options are allowed)\n"
785 * " -U Update item if it already exists (if omitted, the item cannot already exist)\n"
788 while ((ch
= getopt(argc
, argv
, ":a:c:C:d:D:j:l:p:P:r:s:t:w:UAT:h")) != -1)
793 accountName
= optarg
;
796 result
= parse_fourcharcode(optarg
, &itemCreator
);
797 if (result
) goto cleanup
;
800 result
= parse_fourcharcode(optarg
, &itemType
);
801 if (result
) goto cleanup
;
804 securityDomain
= optarg
;
822 result
= parse_fourcharcode(optarg
, &protocol
);
823 if (result
) goto cleanup
;
829 result
= parse_fourcharcode(optarg
, &authenticationType
);
830 if (result
) goto cleanup
;
831 /* auth type attribute is special */
832 authenticationType
= OSSwapHostToBigInt32(authenticationType
);
835 passwordData
= optarg
;
842 access_specified
= TRUE
;
848 SecTrustedApplicationRef app
= NULL
;
849 /* check whether the argument specifies an application group */
850 const char *groupPrefix
= "group://";
851 size_t prefixLen
= strlen(groupPrefix
);
852 if (strlen(optarg
) > prefixLen
&& !memcmp(optarg
, groupPrefix
, prefixLen
)) {
853 const char *groupName
= &optarg
[prefixLen
];
854 if ((status
= SecTrustedApplicationCreateApplicationGroup(groupName
, NULL
, &app
)) != noErr
) {
855 sec_error("SecTrustedApplicationCreateApplicationGroup %s: %s", optarg
, sec_errstr(status
));
858 if ((status
= SecTrustedApplicationCreateFromPath(optarg
, &app
)) != noErr
) {
859 sec_error("SecTrustedApplicationCreateFromPath %s: %s", optarg
, sec_errstr(status
));
868 CFArrayAppendValue(trusted_list
, app
);
871 access_specified
= TRUE
;
876 // They supplied the -p or -w but with no data, so prompt
877 // This differs from the case where no -p or -w was given, where we set the data to empty
878 if (optopt
== 'p' || optopt
== 'w') {
879 if (promptForPasswordData(&passwordData
)) {
880 mustFreePasswordData
= true;
884 goto cleanup
; /* @@@ Do not trigger usage message, but indicate failure. */
888 goto cleanup
; /* @@@ Return 2 triggers usage message. */
892 goto cleanup
; /* @@@ Return 2 triggers usage message. */
899 if (!accountName
|| !serverName
)
906 keychainName
= argv
[0];
907 if (argc
> 1 || *keychainName
== '\0')
914 if (access_specified
)
916 const char *accessName
= (label
) ? label
: (serverName
) ? serverName
: (accountName
) ? accountName
: "";
917 if ((result
= create_access(accessName
, always_allow
, trusted_list
, &access
)) != 0)
921 result
= do_add_internet_password(keychainName
,
926 (label
) ? label
: serverName
,
939 if (mustFreePasswordData
)
942 CFRelease(trusted_list
);
950 keychain_add_certificates(int argc
, char * const *argv
)
953 const char *keychainName
= NULL
;
954 while ((ch
= getopt(argc
, argv
, "hk:")) != -1)
959 keychainName
= optarg
;
960 if (*keychainName
== '\0')
965 return 2; /* @@@ Return 2 triggers usage message. */
975 result
= do_add_certificates(keychainName
, argc
, argv
);