+++ /dev/null
-//
-//
-//
-//
-
-
-
-#include <CoreFoundation/CoreFoundation.h>
-
-#include <Security/SecItem.h>
-
-#include <SecurityTool/tool_errors.h>
-#include <SecurityTool/readline.h>
-
-#include <utilities/SecCFWrappers.h>
-
-#include "SecurityCommands.h"
-
-//
-// Craptastic hacks.
-
-typedef uint32_t SecProtocolType;
-typedef uint32_t SecAuthenticationType;
-
-/* Parse a string of the form attr=value,attr=value,attr=value */
-static void
-keychain_query_parse_string(CFMutableDictionaryRef q, CFStringRef s) {
- bool inkey = true;
- bool escaped = false;
- CFStringRef key = NULL;
- CFMutableStringRef str = CFStringCreateMutable(0, 0);
- CFRange rng = { .location = 0, .length = CFStringGetLength(s) };
- CFCharacterSetRef cs_key = CFCharacterSetCreateWithCharactersInString(0, CFSTR("=\\"));
- CFCharacterSetRef cs_value = CFCharacterSetCreateWithCharactersInString(0, CFSTR(",\\"));
- while (rng.length) {
- CFRange r;
- CFStringRef sub;
- bool complete = false;
- if (escaped) {
- r.location = rng.location;
- r.length = 1;
- sub = CFStringCreateWithSubstring(0, s, r);
- escaped = false;
- } else if (CFStringFindCharacterFromSet(s, inkey ? cs_key : cs_value, rng, 0, &r)) {
- if (CFStringGetCharacterAtIndex(s, r.location) == '\\') {
- escaped = true;
- } else {
- complete = true;
- }
- CFIndex next = r.location + 1;
- r.length = r.location - rng.location;
- r.location = rng.location;
- sub = CFStringCreateWithSubstring(0, s, r);
- rng.length -= next - rng.location;
- rng.location = next;
- } else {
- sub = CFStringCreateWithSubstring(0, s, rng);
- rng.location += rng.length;
- rng.length = 0;
- complete = true;
- }
- CFStringAppend(str, sub);
- CFRelease(sub);
- if (complete) {
- CFStringRef value = CFStringCreateCopy(0, str);
- CFStringReplaceAll(str, CFSTR(""));
- if (inkey) {
- key = value;
- } else {
- CFDictionarySetValue(q, key, value);
- CFReleaseNull(value);
- CFReleaseNull(key);
- }
- inkey = !inkey;
- }
- }
- if (key) {
- /* Dangeling key value is true?. */
- CFDictionarySetValue(q, key, kCFBooleanTrue);
- CFRelease(key);
- }
-
- CFRelease(str);
- CFReleaseSafe(cs_key);
- CFReleaseSafe(cs_value);
-}
-
-static void
-keychain_query_parse_cstring(CFMutableDictionaryRef q, const char *query) {
- CFStringRef s;
- s = CFStringCreateWithCStringNoCopy(0, query, kCFStringEncodingUTF8, kCFAllocatorNull);
- keychain_query_parse_string(q, s);
- CFRelease(s);
-}
-
-static CFMutableDictionaryRef
-keychain_create_query_from_string(const char *query) {
- CFMutableDictionaryRef q;
-
- q = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- keychain_query_parse_cstring(q, query);
- return q;
-}
-
-static void add_key(const void *key, const void *value, void *context) {
- CFArrayAppendValue(context, key);
-}
-
-static void display_item(const void *v_item, void *context) {
- CFDictionaryRef item = (CFDictionaryRef)v_item;
- CFIndex dict_count, key_ix, key_count;
- CFMutableArrayRef keys = NULL;
- CFIndex maxWidth = 10; /* Maybe precompute this or grab from context? */
-
- dict_count = CFDictionaryGetCount(item);
- keys = CFArrayCreateMutable(kCFAllocatorDefault, dict_count,
- &kCFTypeArrayCallBacks);
- CFDictionaryApplyFunction(item, add_key, keys);
- key_count = CFArrayGetCount(keys);
- CFArraySortValues(keys, CFRangeMake(0, key_count),
- (CFComparatorFunction)CFStringCompare, 0);
-
- for (key_ix = 0; key_ix < key_count; ++key_ix) {
- CFStringRef key = (CFStringRef)CFArrayGetValueAtIndex(keys, key_ix);
- CFTypeRef value = CFDictionaryGetValue(item, key);
- CFMutableStringRef line = CFStringCreateMutable(NULL, 0);
-
- CFStringAppend(line, key);
- CFIndex jx;
- for (jx = CFStringGetLength(key);
- jx < maxWidth; ++jx) {
- CFStringAppend(line, CFSTR(" "));
- }
- CFStringAppend(line, CFSTR(" : "));
- if (CFStringGetTypeID() == CFGetTypeID(value)) {
- CFStringAppend(line, (CFStringRef)value);
- } else if (CFNumberGetTypeID() == CFGetTypeID(value)) {
- CFNumberRef v_n = (CFNumberRef)value;
- CFStringAppendFormat(line, NULL, CFSTR("%@"), v_n);
- } else if (CFDateGetTypeID() == CFGetTypeID(value)) {
- CFDateRef v_d = (CFDateRef)value;
- CFStringAppendFormat(line, NULL, CFSTR("%@"), v_d);
- } else if (CFDataGetTypeID() == CFGetTypeID(value)) {
- CFDataRef v_d = (CFDataRef)value;
- CFStringRef v_s = CFStringCreateFromExternalRepresentation(
- kCFAllocatorDefault, v_d, kCFStringEncodingUTF8);
- if (v_s) {
- CFStringAppend(line, CFSTR("/"));
- CFStringAppend(line, v_s);
- CFStringAppend(line, CFSTR("/ "));
- CFRelease(v_s);
- }
- const uint8_t *bytes = CFDataGetBytePtr(v_d);
- CFIndex len = CFDataGetLength(v_d);
- for (jx = 0; jx < len; ++jx) {
- CFStringAppendFormat(line, NULL, CFSTR("%.02X"), bytes[jx]);
- }
- } else {
- CFStringAppendFormat(line, NULL, CFSTR("%@"), value);
- }
-
- CFStringWriteToFileWithNewline(line, stdout);
-
- CFRelease(line);
- }
- CFRelease(keys);
-
- CFStringWriteToFileWithNewline(CFSTR("===="), stdout);
-
- //CFShow(item);
-}
-
-
-static void display_results(CFTypeRef results) {
- if (CFGetTypeID(results) == CFArrayGetTypeID()) {
- CFArrayRef r_a = (CFArrayRef)results;
- CFArrayApplyFunction(r_a, CFRangeMake(0, CFArrayGetCount(r_a)),
- display_item, NULL);
- } else if (CFGetTypeID(results) == CFArrayGetTypeID()) {
- display_item(results, NULL);
- } else {
- fprintf(stderr, "SecItemCopyMatching returned unexpected results:");
- CFShow(results);
- }
-}
-
-static OSStatus do_find_or_delete(CFDictionaryRef query, bool do_delete) {
- OSStatus result;
- if (do_delete) {
- result = SecItemDelete(query);
- if (result) {
- sec_perror("SecItemDelete", result);
- }
- } else {
- CFTypeRef results = NULL;
- result = SecItemCopyMatching(query, &results);
- if (result) {
- sec_perror("SecItemCopyMatching", result);
- } else {
- display_results(results);
- }
- CFReleaseSafe(results);
- }
- return result;
-}
-
-static int
-do_keychain_find_or_delete_internet_password(Boolean do_delete,
- const char *serverName, const char *securityDomain,
- const char *accountName, const char *path, UInt16 port,
- SecProtocolType protocol, SecAuthenticationType authenticationType,
- Boolean get_password)
- {
- OSStatus result;
- CFDictionaryRef query = NULL;
- const void *keys[11], *values[11];
- CFIndex ix = 0;
-
- keys[ix] = kSecClass;
- values[ix++] = kSecClassInternetPassword;
- if (serverName) {
- keys[ix] = kSecAttrServer;
- values[ix++] = CFStringCreateWithCStringNoCopy(NULL, serverName,
- kCFStringEncodingUTF8, kCFAllocatorNull);
- }
- if (securityDomain) {
- keys[ix] = kSecAttrSecurityDomain;
- values[ix++] = CFStringCreateWithCStringNoCopy(NULL, securityDomain,
- kCFStringEncodingUTF8, kCFAllocatorNull);
- }
- if (accountName) {
- keys[ix] = kSecAttrAccount;
- values[ix++] = CFStringCreateWithCStringNoCopy(NULL, accountName,
- kCFStringEncodingUTF8, kCFAllocatorNull);
- }
- if (path) {
- keys[ix] = kSecAttrPath;
- values[ix++] = CFStringCreateWithCStringNoCopy(NULL, path,
- kCFStringEncodingUTF8, kCFAllocatorNull);
- }
- if (port != 0) {
- keys[ix] = kSecAttrPort;
- values[ix++] = CFNumberCreate(NULL, kCFNumberSInt16Type, &port);
- }
- if (protocol != 0) {
- /* Protocol is a 4 char code, perhaps we should use a string rep
- instead. */
- keys[ix] = kSecAttrProtocol;
- values[ix++] = CFNumberCreate(NULL, kCFNumberSInt32Type, &protocol);
- }
- if (authenticationType != 0) {
- keys[ix] = kSecAttrAuthenticationType;
- values[ix++] = CFNumberCreate(NULL, kCFNumberSInt32Type,
- &authenticationType);
- }
- if (get_password) {
- /* Only ask for the data if so required. */
- keys[ix] = kSecReturnData;
- values[ix++] = kCFBooleanTrue;
- }
- keys[ix] = kSecReturnAttributes;
- values[ix++] = kCFBooleanTrue;
- if (!do_delete) {
- /* If we aren't deleting ask for all items. */
- keys[ix] = kSecMatchLimit;
- values[ix++] = kSecMatchLimitAll;
- }
-
- query = CFDictionaryCreate(NULL, keys, values, ix,
- &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- result = do_find_or_delete(query, do_delete);
- CFReleaseSafe(query);
-
- return result;
-}
-
-static int
-parse_fourcharcode(const char *name, uint32_t *code)
-{
- /* @@@ Check for errors. */
- char *p = (char *)code;
- strncpy(p, name, 4);
- return 0;
-}
-
-static int
-keychain_find_or_delete_internet_password(Boolean do_delete, int argc, char * const *argv)
-{
- char *serverName = NULL, *securityDomain = NULL, *accountName = NULL, *path = NULL;
- UInt16 port = 0;
- SecProtocolType protocol = 0;
- SecAuthenticationType authenticationType = 0;
- int ch, result = 0;
- Boolean get_password = FALSE;
-
- while ((ch = getopt(argc, argv, "a:d:hgp:P:r:s:t:")) != -1)
- {
- switch (ch)
- {
- case 'a':
- accountName = optarg;
- break;
- case 'd':
- securityDomain = optarg;
- break;
- case 'g':
- if (do_delete)
- return 2;
- get_password = TRUE;
- break;
- case 'p':
- path = optarg;
- break;
- case 'P':
- port = atoi(optarg);
- break;
- case 'r':
- result = parse_fourcharcode(optarg, &protocol);
- if (result)
- goto loser;
- break;
- case 's':
- serverName = optarg;
- break;
- case 't':
- result = parse_fourcharcode(optarg, &authenticationType);
- if (result)
- goto loser;
- break;
- case '?':
- default:
- return 2; /* @@@ Return 2 triggers usage message. */
- }
- }
-
- argc -= optind;
- argv += optind;
-
- result = do_keychain_find_or_delete_internet_password(do_delete, serverName, securityDomain,
- accountName, path, port, protocol,authenticationType, get_password);
-
-
-loser:
-
- return result;
-}
-
-int
-keychain_find_internet_password(int argc, char * const *argv) {
- return keychain_find_or_delete_internet_password(0, argc, argv);
-}
-
-int
-keychain_delete_internet_password(int argc, char * const *argv) {
- return keychain_find_or_delete_internet_password(1, argc, argv);
-}
-
-static int
-do_keychain_find_or_delete_generic_password(Boolean do_delete,
- const char *serviceName, const char *accountName,
- Boolean get_password)
- {
- OSStatus result;
- CFDictionaryRef query = NULL;
- const void *keys[6], *values[6];
- CFIndex ix = 0;
-
- keys[ix] = kSecClass;
- values[ix++] = kSecClassGenericPassword;
- if (serviceName) {
- keys[ix] = kSecAttrService;
- values[ix++] = CFStringCreateWithCStringNoCopy(NULL, serviceName,
- kCFStringEncodingUTF8, kCFAllocatorNull);
- }
- if (accountName) {
- keys[ix] = kSecAttrAccount;
- values[ix++] = CFStringCreateWithCStringNoCopy(NULL, accountName,
- kCFStringEncodingUTF8, kCFAllocatorNull);
- }
- if (get_password) {
- /* Only ask for the data if so required. */
- keys[ix] = kSecReturnData;
- values[ix++] = kCFBooleanTrue;
- }
- keys[ix] = kSecReturnAttributes;
- values[ix++] = kCFBooleanTrue;
- if (!do_delete) {
- /* If we aren't deleting ask for all items. */
- keys[ix] = kSecMatchLimit;
- values[ix++] = kSecMatchLimitAll;
- }
-
- query = CFDictionaryCreate(NULL, keys, values, ix,
- &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-
- result = do_find_or_delete(query, do_delete);
-
- CFReleaseSafe(query);
-
- return result;
-}
-
-int keychain_item(int argc, char * const *argv) {
- int ch, result = 0;
- CFMutableDictionaryRef query, update = NULL;
- bool get_password = false;
- bool do_delete = false;
- bool do_add = false;
- bool verbose = false;
- int limit = 0;
-
- query = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- while ((ch = getopt(argc, argv, "ad:Df:gq:u:vl:")) != -1)
- {
- switch (ch)
- {
- case 'a':
- do_add = true;
- break;
- case 'D':
- do_delete = true;
- break;
- case 'd':
- {
- CFStringRef data = CFStringCreateWithCString(0, optarg, kCFStringEncodingUTF8);
- if (data) {
- CFDictionarySetValue(update ? update : query, kSecValueData, data);
- CFRelease(data);
- } else {
- result = 1;
- goto out;
- }
- break;
- }
- case 'f':
- {
- CFDataRef data = copyFileContents(optarg);
- CFDictionarySetValue(update ? update : query, kSecValueData, data);
- CFRelease(data);
- break;
- }
- case 'g':
- get_password = true;
- break;
- case 'q':
- keychain_query_parse_cstring(query, optarg);
- break;
- case 'u':
- if (!update)
- update = keychain_create_query_from_string(optarg);
- else
- keychain_query_parse_cstring(update, optarg);
- break;
- case 'v':
- verbose = true;
- break;
- case 'l':
- limit = atoi(optarg);
- break;
- case '?':
- default:
- /* Return 2 triggers usage message. */
- result = 2;
- goto out;
- }
- }
-
- if (((do_add || do_delete) && (get_password || update)) || !query) {
- result = 2;
- goto out;
- }
-
- argc -= optind;
- argv += optind;
-
- int ix;
- for (ix = 0; ix < argc; ++ix) {
- keychain_query_parse_cstring(query, argv[ix]);
- }
-
- if (!update && !do_add && !do_delete) {
- CFDictionarySetValue(query, kSecReturnAttributes, kCFBooleanTrue);
- if(limit) {
- CFNumberRef cfLimit = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &limit);
- CFDictionarySetValue(query, kSecMatchLimit, cfLimit);
- CFReleaseSafe(cfLimit);
- } else {
- CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll);
- }
- if (get_password)
- CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
- }
-
- if (verbose)
- CFShow(query);
-
- OSStatus error;
- if (do_add) {
- error = SecItemAdd(query, NULL);
- if (error) {
- sec_perror("SecItemAdd", error);
- result = 1;
- }
- } else if (update) {
- error = SecItemUpdate(query, update);
- if (error) {
- sec_perror("SecItemUpdate", error);
- result = 1;
- }
- } else if (do_delete) {
- error = SecItemDelete(query);
- if (error) {
- sec_perror("SecItemDelete", error);
- result = 1;
- }
- } else {
- do_find_or_delete(query, do_delete);
- }
-
-out:
- CFReleaseSafe(query);
- CFReleaseSafe(update);
- return result;
-}
-
-static int
-keychain_find_or_delete_generic_password(Boolean do_delete,
- int argc, char * const *argv)
-{
- char *serviceName = NULL, *accountName = NULL;
- int ch, result = 0;
- Boolean get_password = FALSE;
-
- while ((ch = getopt(argc, argv, "a:s:g")) != -1)
- {
- switch (ch)
- {
- case 'a':
- accountName = optarg;
- break;
- case 'g':
- if (do_delete)
- return 2;
- get_password = TRUE;
- break;
- case 's':
- serviceName = optarg;
- break;
- case '?':
- default:
- return 2; /* @@@ Return 2 triggers usage message. */
- }
- }
-
- argc -= optind;
- argv += optind;
-
- result = do_keychain_find_or_delete_generic_password(do_delete,
- serviceName, accountName, get_password);
-
- return result;
-}
-
-int
-keychain_find_generic_password(int argc, char * const *argv) {
- return keychain_find_or_delete_generic_password(0, argc, argv);
-}
-
-int
-keychain_delete_generic_password(int argc, char * const *argv) {
- return keychain_find_or_delete_generic_password(1, argc, argv);
-}