+++ /dev/null
-/*
- * Copyright (c) 2003-2009,2011-2014 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- *
- * keychain_add.c
- */
-
-#include "keychain_add.h"
-#include "keychain_find.h"
-#include "readline_cssm.h"
-#include "security_tool.h"
-#include "access_utils.h"
-#include "keychain_utilities.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <AssertMacros.h>
-#include <libkern/OSByteOrder.h>
-#include <Security/SecAccess.h>
-#include <Security/SecCertificate.h>
-#include <Security/SecKeychain.h>
-#include <Security/SecKeychainItem.h>
-#include <Security/SecTrustedApplication.h>
-
-// SecTrustedApplicationCreateApplicationGroup
-#include <Security/SecTrustedApplicationPriv.h>
-
-
-static int
-do_update_generic_password(const char *keychainName,
- FourCharCode itemCreator,
- FourCharCode itemType,
- const char *kind,
- const char *value,
- const char *comment,
- const char *label,
- const char *serviceName,
- const char *accountName,
- const void *passwordData,
- SecAccessRef access)
-{
- OSStatus status;
- SecKeychainRef keychainRef = NULL;
- SecKeychainItemRef itemRef = NULL;
-
- if (keychainName) {
- keychainRef = keychain_open(keychainName);
- }
- itemRef = find_first_generic_password(keychainRef,itemCreator,itemType,kind,value,comment,label,serviceName,accountName);
- if (keychainRef) {
- CFRelease(keychainRef);
- }
- if (!itemRef) {
- return errSecItemNotFound;
- }
-
- // build list of attributes
- SecKeychainAttribute attrs[8]; // maximum number of attributes
- SecKeychainAttributeList attrList = { 0, attrs };
-
- if ((UInt32)itemCreator != 0) {
- attrs[attrList.count].tag = kSecCreatorItemAttr;
- attrs[attrList.count].length = sizeof(FourCharCode);
- attrs[attrList.count].data = (FourCharCode *)&itemCreator;
- attrList.count++;
- }
- if ((UInt32)itemType != 0) {
- attrs[attrList.count].tag = kSecTypeItemAttr;
- attrs[attrList.count].length = sizeof(FourCharCode);
- attrs[attrList.count].data = (FourCharCode *)&itemType;
- attrList.count++;
- }
- if (kind != NULL) {
- attrs[attrList.count].tag = kSecDescriptionItemAttr;
- attrs[attrList.count].length = (UInt32) strlen(kind);
- attrs[attrList.count].data = (void *)kind;
- attrList.count++;
- }
- if (value != NULL) {
- attrs[attrList.count].tag = kSecGenericItemAttr;
- attrs[attrList.count].length = (UInt32) strlen(value);
- attrs[attrList.count].data = (void *)value;
- attrList.count++;
- }
- if (comment != NULL) {
- attrs[attrList.count].tag = kSecCommentItemAttr;
- attrs[attrList.count].length = (UInt32) strlen(comment);
- attrs[attrList.count].data = (void *)comment;
- attrList.count++;
- }
- if (label != NULL) {
- attrs[attrList.count].tag = kSecLabelItemAttr;
- attrs[attrList.count].length = (UInt32) strlen(label);
- attrs[attrList.count].data = (void *)label;
- attrList.count++;
- }
- if (serviceName != NULL) {
- attrs[attrList.count].tag = kSecServiceItemAttr;
- attrs[attrList.count].length = (UInt32) strlen(serviceName);
- attrs[attrList.count].data = (void *)serviceName;
- attrList.count++;
- }
- if (accountName != NULL) {
- attrs[attrList.count].tag = kSecAccountItemAttr;
- attrs[attrList.count].length = (UInt32) strlen(accountName);
- attrs[attrList.count].data = (void *)accountName;
- attrList.count++;
- }
-
- // modify attributes and password data, if provided
- status = SecKeychainItemModifyContent(itemRef, &attrList, (passwordData) ? ((UInt32) strlen(passwordData)) : 0, passwordData);
- if (status) {
- sec_error("SecKeychainItemModifyContent: %s", sec_errstr(status));
- }
-
- // modify access, if provided
- if (!status && access) {
- SecAccessRef curAccess = NULL;
- // for historical reasons, we have to modify the item's existing access reference
- // (setting the item's access to a freshly created SecAccessRef instance doesn't behave as expected)
- status = SecKeychainItemCopyAccess(itemRef, &curAccess);
- if (status) {
- sec_error("SecKeychainItemCopyAccess: %s", sec_errstr(status));
- } else {
- int result = merge_access(curAccess, access); // make changes to the existing access reference
- if (result == noErr) {
- status = SecKeychainItemSetAccess(itemRef, curAccess); // will prompt
- if (status) {
- sec_error("SecKeychainItemSetAccess: %s", sec_errstr(status));
- }
- }
- }
- if (curAccess) {
- CFRelease(curAccess);
- }
- }
-
- CFRelease(itemRef);
-
- return status;
-}
-
-static int
-do_add_generic_password(const char *keychainName,
- FourCharCode itemCreator,
- FourCharCode itemType,
- const char *kind,
- const char *value,
- const char *comment,
- const char *label,
- const char *serviceName,
- const char *accountName,
- const void *passwordData,
- SecAccessRef access,
- Boolean update)
-{
- SecKeychainRef keychain = NULL;
- OSStatus result = 0;
- SecKeychainItemRef itemRef = NULL;
-
- // if update flag is specified, try to find and update an existing item
- if (update) {
- result = do_update_generic_password(keychainName,itemCreator,itemType,kind,value,comment,label,serviceName,accountName,passwordData,access);
- if (result == noErr)
- return result;
- }
-
- if (keychainName)
- {
- keychain = keychain_open(keychainName);
- if (!keychain)
- {
- result = 1;
- goto cleanup;
- }
- }
-
- // set up attribute vector for new item (each attribute consists of {tag, length, pointer})
- SecKeychainAttribute attrs[] = {
- { kSecLabelItemAttr, label ? (UInt32) strlen(label) : 0, (char *)label },
- { kSecDescriptionItemAttr, kind ? (UInt32) strlen(kind) : 0, (char *)kind },
- { kSecGenericItemAttr, value ? (UInt32) strlen(value) : 0, (char *)value },
- { kSecCommentItemAttr, comment ? (UInt32) strlen(comment) : 0, (char *)comment },
- { kSecServiceItemAttr, serviceName ? (UInt32) strlen(serviceName) : 0, (char *)serviceName },
- { kSecAccountItemAttr, accountName ? (UInt32) strlen(accountName) : 0, (char *)accountName },
- { (SecKeychainAttrType)0, sizeof(FourCharCode), NULL }, /* placeholder */
- { (SecKeychainAttrType)0, sizeof(FourCharCode), NULL } /* placeholder */
- };
- SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
- attributes.count -= 2;
-
- if (itemCreator != 0)
- {
- attrs[attributes.count].tag = kSecCreatorItemAttr;
- attrs[attributes.count].data = (FourCharCode *)&itemCreator;
- attributes.count++;
- }
- if (itemType != 0)
- {
- attrs[attributes.count].tag = kSecTypeItemAttr;
- attrs[attributes.count].data = (FourCharCode *)&itemType;
- attributes.count++;
- }
-
- result = SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass,
- &attributes,
- passwordData ? (UInt32) strlen(passwordData) : 0,
- passwordData,
- keychain,
- access,
- &itemRef);
-
- if (result)
- {
- sec_error("SecKeychainItemCreateFromContent (%s): %s", keychainName ? keychainName : "<default>", sec_errstr(result));
- }
-
-cleanup:
- if (itemRef)
- CFRelease(itemRef);
- if (keychain)
- CFRelease(keychain);
-
- return result;
-}
-
-static int
-do_update_internet_password(const char *keychainName,
- FourCharCode itemCreator,
- FourCharCode itemType,
- const char *kind,
- const char *comment,
- const char *label,
- const char *serverName,
- const char *securityDomain,
- const char *accountName,
- const char *path,
- UInt16 port,
- SecProtocolType protocol,
- SecAuthenticationType authenticationType,
- const void *passwordData,
- SecAccessRef access)
-{
- OSStatus status;
- SecKeychainRef keychainRef = NULL;
- SecKeychainItemRef itemRef = NULL;
-
- if (keychainName) {
- keychainRef = keychain_open(keychainName);
- }
- itemRef = find_first_internet_password(keychainRef,itemCreator,itemType,kind,comment,label,serverName,
- securityDomain,accountName,path,port,protocol,authenticationType);
- if (keychainRef) {
- CFRelease(keychainRef);
- }
- if (!itemRef) {
- return errSecItemNotFound;
- }
-
- // build list of attributes
- SecKeychainAttribute attrs[12]; // maximum number of attributes
- SecKeychainAttributeList attrList = { 0, attrs };
-
- if ((UInt32)itemCreator != 0) {
- attrs[attrList.count].tag = kSecCreatorItemAttr;
- attrs[attrList.count].length = sizeof(FourCharCode);
- attrs[attrList.count].data = (FourCharCode *)&itemCreator;
- attrList.count++;
- }
- if ((UInt32)itemType != 0) {
- attrs[attrList.count].tag = kSecTypeItemAttr;
- attrs[attrList.count].length = sizeof(FourCharCode);
- attrs[attrList.count].data = (FourCharCode *)&itemType;
- attrList.count++;
- }
- if (kind != NULL) {
- attrs[attrList.count].tag = kSecDescriptionItemAttr;
- attrs[attrList.count].length = (UInt32) strlen(kind);
- attrs[attrList.count].data = (void *)kind;
- attrList.count++;
- }
- if (comment != NULL) {
- attrs[attrList.count].tag = kSecCommentItemAttr;
- attrs[attrList.count].length = (UInt32) strlen(comment);
- attrs[attrList.count].data = (void *)comment;
- attrList.count++;
- }
- if (label != NULL) {
- attrs[attrList.count].tag = kSecLabelItemAttr;
- attrs[attrList.count].length = (UInt32) strlen(label);
- attrs[attrList.count].data = (void *)label;
- attrList.count++;
- }
- if (serverName != NULL) {
- attrs[attrList.count].tag = kSecServerItemAttr;
- attrs[attrList.count].length = (UInt32) strlen(serverName);
- attrs[attrList.count].data = (void *)serverName;
- attrList.count++;
- }
- if (securityDomain != NULL) {
- attrs[attrList.count].tag = kSecSecurityDomainItemAttr;
- attrs[attrList.count].length = (UInt32) strlen(securityDomain);
- attrs[attrList.count].data = (void *)securityDomain;
- attrList.count++;
- }
- if (accountName != NULL) {
- attrs[attrList.count].tag = kSecAccountItemAttr;
- attrs[attrList.count].length = (UInt32) strlen(accountName);
- attrs[attrList.count].data = (void *)accountName;
- attrList.count++;
- }
- if (path != NULL) {
- attrs[attrList.count].tag = kSecPathItemAttr;
- attrs[attrList.count].length = (UInt32) strlen(path);
- attrs[attrList.count].data = (void *)path;
- attrList.count++;
- }
- if (port != 0) {
- attrs[attrList.count].tag = kSecPortItemAttr;
- attrs[attrList.count].length = sizeof(UInt16);
- attrs[attrList.count].data = (UInt16 *)&port;
- attrList.count++;
- }
- if ((UInt32)protocol != 0) {
- attrs[attrList.count].tag = kSecProtocolItemAttr;
- attrs[attrList.count].length = sizeof(SecProtocolType);
- attrs[attrList.count].data = (SecProtocolType *)&protocol;
- attrList.count++;
- }
- if ((UInt32)authenticationType != 0) {
- attrs[attrList.count].tag = kSecAuthenticationTypeItemAttr;
- attrs[attrList.count].length = sizeof(SecAuthenticationType);
- attrs[attrList.count].data = (SecAuthenticationType *)&authenticationType;
- attrList.count++;
- }
-
- // modify attributes and password data, if provided
- status = SecKeychainItemModifyContent(itemRef, &attrList, (passwordData) ? (UInt32) strlen(passwordData) : 0, passwordData);
- if (status) {
- sec_error("SecKeychainItemModifyContent: %s", sec_errstr(status));
- }
-
- // modify access, if provided
- if (!status && access) {
- status = modify_access(itemRef, access);
- }
-
- CFRelease(itemRef);
-
- return status;
-}
-
-static int
-do_add_internet_password(const char *keychainName,
- FourCharCode itemCreator,
- FourCharCode itemType,
- const char *kind,
- const char *comment,
- const char *label,
- const char *serverName,
- const char *securityDomain,
- const char *accountName,
- const char *path,
- UInt16 port,
- SecProtocolType protocol,
- SecAuthenticationType authenticationType,
- const void *passwordData,
- SecAccessRef access,
- Boolean update)
-{
- SecKeychainRef keychain = NULL;
- SecKeychainItemRef itemRef = NULL;
- OSStatus result = 0;
-
- // if update flag is specified, try to find and update an existing item
- if (update) {
- result = do_update_internet_password(keychainName,itemCreator,itemType,kind,comment,label,serverName,
- securityDomain,accountName,path,port,protocol,authenticationType,
- passwordData,access);
- if (result == noErr)
- return result;
- }
-
- if (keychainName)
- {
- keychain = keychain_open(keychainName);
- if (!keychain)
- {
- result = 1;
- goto cleanup;
- }
- }
-
- // set up attribute vector for new item (each attribute consists of {tag, length, pointer})
- SecKeychainAttribute attrs[] = {
- { kSecLabelItemAttr, label ? (UInt32) strlen(label) : 0, (char *)label },
- { kSecDescriptionItemAttr, kind ? (UInt32) strlen(kind) : 0, (char *)kind },
- { kSecCommentItemAttr, comment ? (UInt32) strlen(comment) : 0, (char *)comment },
- { kSecServerItemAttr, serverName ? (UInt32) strlen(serverName) : 0, (char *)serverName },
- { kSecSecurityDomainItemAttr, securityDomain ? (UInt32) strlen(securityDomain) : 0, (char *)securityDomain },
- { kSecAccountItemAttr, accountName ? (UInt32) strlen(accountName) : 0, (char *)accountName },
- { kSecPathItemAttr, path ? (UInt32) strlen(path) : 0, (char *)path },
- { kSecPortItemAttr, sizeof(UInt16), (UInt16 *)&port },
- { kSecProtocolItemAttr, sizeof(SecProtocolType), (SecProtocolType *)&protocol },
- { kSecAuthenticationTypeItemAttr, sizeof(SecAuthenticationType), (SecAuthenticationType *)&authenticationType },
- { (SecKeychainAttrType)0, sizeof(FourCharCode), NULL }, /* placeholder */
- { (SecKeychainAttrType)0, sizeof(FourCharCode), NULL } /* placeholder */
- };
- SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
- attributes.count -= 2;
-
- if (itemCreator != 0)
- {
- attrs[attributes.count].tag = kSecCreatorItemAttr;
- attrs[attributes.count].data = (FourCharCode *)&itemCreator;
- attributes.count++;
- }
- if (itemType != 0)
- {
- attrs[attributes.count].tag = kSecTypeItemAttr;
- attrs[attributes.count].data = (FourCharCode *)&itemType;
- attributes.count++;
- }
-
- result = SecKeychainItemCreateFromContent(kSecInternetPasswordItemClass,
- &attributes,
- passwordData ? (UInt32) strlen(passwordData) : 0,
- passwordData,
- keychain,
- access,
- &itemRef);
-
- if (result)
- {
- sec_error("SecKeychainAddInternetPassword %s: %s", keychainName ? keychainName : "<NULL>", sec_errstr(result));
- }
-
-cleanup:
- if (itemRef)
- CFRelease(itemRef);
- if (keychain)
- CFRelease(keychain);
-
- return result;
-}
-
-static int
-do_add_certificates(const char *keychainName, int argc, char * const *argv)
-{
- SecKeychainRef keychain = NULL;
- int ix, result = 0;
-
- if (keychainName)
- {
- keychain = keychain_open(keychainName);
- if (!keychain)
- {
- result = 1;
- goto cleanup;
- }
- }
-
- for (ix = 0; ix < argc; ++ix)
- {
- CSSM_DATA certData = {};
- OSStatus status;
- SecCertificateRef certificate = NULL;
-
- if (read_file(argv[ix], &certData))
- {
- result = 1;
- continue;
- }
-
- status = SecCertificateCreateFromData(&certData, CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_UNKNOWN, &certificate);
- if (status)
- {
- sec_perror("SecCertificateCreateFromData", status);
- result = 1;
- }
- else
- {
- status = SecCertificateAddToKeychain(certificate, keychain);
- if (status)
- {
- if (status == errSecDuplicateItem)
- {
- if (keychainName)
- sec_error("%s: already in %s", argv[ix], keychainName);
- else
- sec_error("%s: already in default keychain", argv[ix]);
- }
- else
- {
- sec_perror("SecCertificateAddToKeychain", status);
- }
- result = 1;
- }
- }
-
- if (certData.Data)
- free(certData.Data);
- if (certificate)
- CFRelease(certificate);
- }
-
-cleanup:
- if (keychain)
- CFRelease(keychain);
-
- return result;
-}
-
-static bool promptForPasswordData(char **returnedPasswordData) {
- // Caller must zero memory and free returned value.
- // Returns true if we have data; false means the user canceled
- if (!returnedPasswordData)
- return false;
-
- bool result = false;
- char *password = NULL;
- int tries;
-
- for (tries = 3; tries-- > 0;) {
- bool passwordsMatch = false;
- char *firstpass = NULL;
-
- password = getpass("password data for new item: ");
- if (!password)
- break;
-
- firstpass = malloc(strlen(password) + 1);
- strcpy(firstpass, password);
- password = getpass("retype password for new item: ");
- passwordsMatch = password && (strcmp(password, firstpass) == 0);
- memset(firstpass, 0, strlen(firstpass));
- free(firstpass);
- if (!password)
- break;
-
- if (passwordsMatch) {
- result = true;
- break;
- }
-
- fprintf(stderr, "passwords don't match\n");
- memset(password, 0, strlen(password));
- }
-
- if (result) {
- *returnedPasswordData = password;
- } else {
- free(password);
- }
- return result;
-}
-
-int
-keychain_add_generic_password(int argc, char * const *argv)
-{
- char *serviceName = NULL, *passwordData = NULL, *accountName = NULL;
- char *kind = NULL, *label = NULL, *value = NULL, *comment = NULL;
- FourCharCode itemCreator = 0, itemType = 0;
- int ch, result = 0;
- const char *keychainName = NULL;
- Boolean access_specified = FALSE;
- Boolean always_allow = FALSE;
- Boolean update_item = FALSE;
- SecAccessRef access = NULL;
- CFMutableArrayRef trusted_list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
- OSStatus status;
- bool mustFreePasswordData = false; // if we got it via user prompting
-
- /*
- * " -a Specify account name (required)\n"
- * " -c Specify item creator (optional four-character code)\n"
- * " -C Specify item type (optional four-character code)\n"
- * " -D Specify kind (default is \"application password\")\n"
- * " -G Specify generic attribute (optional)\n"
- * " -j Specify comment string (optional)\n"
- * " -l Specify label (if omitted, service name is used as default label)\n"
- * " -s Specify service name (required)\n"
- * " -p Specify password to be added (legacy option, equivalent to -w)\n"
- * " -w Specify password to be added\n"
- * " -A Allow any application to access this item without warning (insecure, not recommended!)\n"
- * " -T Specify an application which may access this item (multiple -T options are allowed)\n"
- * " -U Update item if it already exists (if omitted, the item cannot already exist)\n"
- */
-
- while ((ch = getopt(argc, argv, ":a:c:C:D:G:j:l:s:p:w:UAT:")) != -1)
- {
- switch (ch)
- {
- case 'a':
- accountName = optarg;
- break;
- case 'c':
- result = parse_fourcharcode(optarg, &itemCreator);
- if (result) goto cleanup;
- break;
- case 'C':
- result = parse_fourcharcode(optarg, &itemType);
- if (result) goto cleanup;
- break;
- case 'D':
- kind = optarg;
- break;
- case 'G':
- value = optarg;
- break;
- case 'j':
- comment = optarg;
- break;
- case 'l':
- label = optarg;
- break;
- case 's':
- serviceName = optarg;
- break;
- case 'p':
- case 'w':
- passwordData = optarg;
- break;
- case 'U':
- update_item = TRUE;
- break;
- case 'A':
- always_allow = TRUE;
- access_specified = TRUE;
- break;
- case 'T':
- {
- if (optarg[0])
- {
- SecTrustedApplicationRef app = NULL;
- /* check whether the argument specifies an application group */
- const char *groupPrefix = "group://";
- size_t prefixLen = strlen(groupPrefix);
- if (strlen(optarg) > prefixLen && !memcmp(optarg, groupPrefix, prefixLen)) {
- const char *groupName = &optarg[prefixLen];
- if ((status = SecTrustedApplicationCreateApplicationGroup(groupName, NULL, &app)) != noErr) {
- sec_error("SecTrustedApplicationCreateApplicationGroup %s: %s", optarg, sec_errstr(status));
- }
- } else {
- if ((status = SecTrustedApplicationCreateFromPath(optarg, &app)) != noErr) {
- sec_error("SecTrustedApplicationCreateFromPath %s: %s", optarg, sec_errstr(status));
- }
- }
-
- if (status) {
- result = 1;
- goto cleanup;
- }
-
- CFArrayAppendValue(trusted_list, app);
- CFRelease(app);
- }
- access_specified = TRUE;
- break;
- }
- case '?':
- case ':':
- // They supplied the -p or -w but with no data, so prompt
- // This differs from the case where no -p or -w was given, where we set the data to empty
- if (optopt == 'p' || optopt == 'w') {
- if (promptForPasswordData(&passwordData)) {
- mustFreePasswordData = true;
- break;
- } else {
- result = 1;
- goto cleanup; /* @@@ Do not trigger usage message, but indicate failure. */
- }
- }
- result = 2;
- goto cleanup; /* @@@ Return 2 triggers usage message. */
- default:
- result = 2;
- goto cleanup; /* @@@ Return 2 triggers usage message. */
- }
- }
-
- argc -= optind;
- argv += optind;
-
- if (!accountName || !serviceName)
- {
- result = 2;
- goto cleanup;
- }
- else if (argc > 0)
- {
- keychainName = argv[0];
- if (argc > 1 || *keychainName == '\0')
- {
- result = 2;
- goto cleanup;
- }
- }
-
- if (access_specified)
- {
- const char *accessName = (label) ? label : (serviceName) ? serviceName : (accountName) ? accountName : "";
- if ((result = create_access(accessName, always_allow, trusted_list, &access)) != 0)
- goto cleanup;
- }
-
- result = do_add_generic_password(keychainName,
- itemCreator,
- itemType,
- kind,
- value,
- comment,
- (label) ? label : serviceName,
- serviceName,
- accountName,
- passwordData,
- access,
- update_item);
-
-cleanup:
- if (mustFreePasswordData)
- free(passwordData);
- if (trusted_list)
- CFRelease(trusted_list);
- if (access)
- CFRelease(access);
-
- return result;
-}
-
-int
-keychain_add_internet_password(int argc, char * const *argv)
-{
- char *serverName = NULL, *securityDomain = NULL, *accountName = NULL, *path = NULL, *passwordData = NULL;
- char *kind = NULL, *comment = NULL, *label = NULL;
- FourCharCode itemCreator = 0, itemType = 0;
- UInt16 port = 0;
- SecProtocolType protocol = 0;
- SecAuthenticationType authenticationType = OSSwapHostToBigInt32('dflt');
- int ch, result = 0;
- const char *keychainName = NULL;
- Boolean access_specified = FALSE;
- Boolean always_allow = FALSE;
- Boolean update_item = FALSE;
- SecAccessRef access = NULL;
- CFMutableArrayRef trusted_list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
- OSStatus status;
- bool mustFreePasswordData = false; // if we got it via user prompting
-
- /*
- * " -a Specify account name (required)\n"
- * " -c Specify item creator (optional four-character code)\n"
- * " -C Specify item type (optional four-character code)\n"
- * " -d Specify security domain string (optional)\n"
- * " -D Specify kind (default is \"Internet password\")\n"
- * " -j Specify comment string (optional)\n"
- * " -l Specify label (if omitted, server name is used as default label)\n"
- * " -p Specify path string (optional)\n"
- * " -P Specify port number (optional)\n"
- * " -r Specify protocol (optional four-character SecProtocolType, e.g. \"http\", \"ftp \")\n"
- * " -s Specify server name (required)\n"
- * " -t Specify authentication type (as a four-character SecAuthenticationType, default is \"dflt\")\n"
- * " -w Specify password to be added\n"
- * " -A Allow any application to access this item without warning (insecure, not recommended!)\n"
- * " -T Specify an application which may access this item (multiple -T options are allowed)\n"
- * " -U Update item if it already exists (if omitted, the item cannot already exist)\n"
- */
-
- while ((ch = getopt(argc, argv, ":a:c:C:d:D:j:l:p:P:r:s:t:w:UAT:h")) != -1)
- {
- switch (ch)
- {
- case 'a':
- accountName = optarg;
- break;
- case 'c':
- result = parse_fourcharcode(optarg, &itemCreator);
- if (result) goto cleanup;
- break;
- case 'C':
- result = parse_fourcharcode(optarg, &itemType);
- if (result) goto cleanup;
- break;
- case 'd':
- securityDomain = optarg;
- break;
- case 'D':
- kind = optarg;
- break;
- case 'j':
- comment = optarg;
- break;
- case 'l':
- label = optarg;
- break;
- case 'p':
- path = optarg;
- break;
- case 'P':
- port = atoi(optarg);
- break;
- case 'r':
- result = parse_fourcharcode(optarg, &protocol);
- if (result) goto cleanup;
- break;
- case 's':
- serverName = optarg;
- break;
- case 't':
- result = parse_fourcharcode(optarg, &authenticationType);
- if (result) goto cleanup;
- /* auth type attribute is special */
- authenticationType = OSSwapHostToBigInt32(authenticationType);
- break;
- case 'w':
- passwordData = optarg;
- break;
- case 'U':
- update_item = TRUE;
- break;
- case 'A':
- always_allow = TRUE;
- access_specified = TRUE;
- break;
- case 'T':
- {
- if (optarg[0])
- {
- SecTrustedApplicationRef app = NULL;
- /* check whether the argument specifies an application group */
- const char *groupPrefix = "group://";
- size_t prefixLen = strlen(groupPrefix);
- if (strlen(optarg) > prefixLen && !memcmp(optarg, groupPrefix, prefixLen)) {
- const char *groupName = &optarg[prefixLen];
- if ((status = SecTrustedApplicationCreateApplicationGroup(groupName, NULL, &app)) != noErr) {
- sec_error("SecTrustedApplicationCreateApplicationGroup %s: %s", optarg, sec_errstr(status));
- }
- } else {
- if ((status = SecTrustedApplicationCreateFromPath(optarg, &app)) != noErr) {
- sec_error("SecTrustedApplicationCreateFromPath %s: %s", optarg, sec_errstr(status));
- }
- }
-
- if (status) {
- result = 1;
- goto cleanup;
- }
-
- CFArrayAppendValue(trusted_list, app);
- CFRelease(app);
- }
- access_specified = TRUE;
- break;
- }
- case '?':
- case ':':
- // They supplied the -p or -w but with no data, so prompt
- // This differs from the case where no -p or -w was given, where we set the data to empty
- if (optopt == 'p' || optopt == 'w') {
- if (promptForPasswordData(&passwordData)) {
- mustFreePasswordData = true;
- break;
- } else {
- result = 1;
- goto cleanup; /* @@@ Do not trigger usage message, but indicate failure. */
- }
- }
- result = 2;
- goto cleanup; /* @@@ Return 2 triggers usage message. */
-
- default:
- result = 2;
- goto cleanup; /* @@@ Return 2 triggers usage message. */
- }
- }
-
- argc -= optind;
- argv += optind;
-
- if (!accountName || !serverName)
- {
- result = 2;
- goto cleanup;
- }
- else if (argc > 0)
- {
- keychainName = argv[0];
- if (argc > 1 || *keychainName == '\0')
- {
- result = 2;
- goto cleanup;
- }
- }
-
- if (access_specified)
- {
- const char *accessName = (label) ? label : (serverName) ? serverName : (accountName) ? accountName : "";
- if ((result = create_access(accessName, always_allow, trusted_list, &access)) != 0)
- goto cleanup;
- }
-
- result = do_add_internet_password(keychainName,
- itemCreator,
- itemType,
- kind,
- comment,
- (label) ? label : serverName,
- serverName,
- securityDomain,
- accountName,
- path,
- port,
- protocol,
- authenticationType,
- passwordData,
- access,
- update_item);
-
-cleanup:
- if (mustFreePasswordData)
- free(passwordData);
- if (trusted_list)
- CFRelease(trusted_list);
- if (access)
- CFRelease(access);
-
- return result;
-}
-
-int
-keychain_add_certificates(int argc, char * const *argv)
-{
- int ch, result = 0;
- const char *keychainName = NULL;
- while ((ch = getopt(argc, argv, "hk:")) != -1)
- {
- switch (ch)
- {
- case 'k':
- keychainName = optarg;
- if (*keychainName == '\0')
- return SHOW_USAGE_MESSAGE;
- break;
- case '?':
- default:
- return SHOW_USAGE_MESSAGE;
- }
- }
-
- argc -= optind;
- argv += optind;
-
- if (argc == 0)
- return SHOW_USAGE_MESSAGE;
-
- result = do_add_certificates(keychainName, argc, argv);
-
- return result;
-}