]> git.saurik.com Git - apple/security.git/blobdiff - SecurityTool/keychain_find.c
Security-58286.1.32.tar.gz
[apple/security.git] / SecurityTool / keychain_find.c
index 23f568591ae1ad398320155bd3086f4d0a64bc5e..a6e781a22d10dbee428a99bf9687e8df16741793 100644 (file)
 #include "keychain_find.h"
 
 #include "keychain_utilities.h"
-#include "readline.h"
-#include "security.h"
+#include "readline_cssm.h"
+#include "security_tool.h"
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <libkern/OSByteOrder.h>
+#include <Security/SecACL.h>
+#include <Security/SecItem.h>
+#include <Security/SecItemPriv.h>
 #include <Security/SecKeychainItem.h>
+#include <Security/SecKeychainItemPriv.h>
 #include <Security/SecKeychainSearch.h>
 #include <Security/SecCertificate.h>
 #include <CoreFoundation/CFString.h>
 #include <ctype.h>
+#include <utilities/SecCFRelease.h>
 
 
 // SecDigestGetData, SecKeychainSearchCreateForCertificateByEmail, SecCertificateFindByEmail
@@ -93,37 +98,37 @@ find_first_generic_password(CFTypeRef keychainOrArray,
        }
        if (kind != NULL && !primaryKey) {
                attrs[attrList.count].tag = kSecDescriptionItemAttr;
-               attrs[attrList.count].length = strlen(kind);
+               attrs[attrList.count].length = (UInt32) strlen(kind);
                attrs[attrList.count].data = (void*)kind;
                attrList.count++;
        }
        if (value != NULL && !primaryKey) {
                attrs[attrList.count].tag = kSecGenericItemAttr;
-               attrs[attrList.count].length = strlen(value);
+               attrs[attrList.count].length = (UInt32) strlen(value);
                attrs[attrList.count].data = (void*)value;
                attrList.count++;
        }
        if (comment != NULL && !primaryKey) {
                attrs[attrList.count].tag = kSecCommentItemAttr;
-               attrs[attrList.count].length = strlen(comment);
+               attrs[attrList.count].length = (UInt32) strlen(comment);
                attrs[attrList.count].data = (void*)comment;
                attrList.count++;
        }
        if (label != NULL && !primaryKey) {
                attrs[attrList.count].tag = kSecLabelItemAttr;
-               attrs[attrList.count].length = strlen(label);
+               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 = strlen(serviceName);
+               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 = strlen(accountName);
+               attrs[attrList.count].length = (UInt32) strlen(accountName);
                attrs[attrList.count].data = (void*)accountName;
                attrList.count++;
        }
@@ -200,43 +205,43 @@ find_first_internet_password(CFTypeRef keychainOrArray,
        }
        if (kind != NULL && !primaryKey) {
                attrs[attrList.count].tag = kSecDescriptionItemAttr;
-               attrs[attrList.count].length = strlen(kind);
+               attrs[attrList.count].length = (UInt32) strlen(kind);
                attrs[attrList.count].data = (void*)kind;
                attrList.count++;
        }
        if (comment != NULL && !primaryKey) {
                attrs[attrList.count].tag = kSecCommentItemAttr;
-               attrs[attrList.count].length = strlen(comment);
+               attrs[attrList.count].length = (UInt32) strlen(comment);
                attrs[attrList.count].data = (void*)comment;
                attrList.count++;
        }
        if (label != NULL && !primaryKey) {
                attrs[attrList.count].tag = kSecLabelItemAttr;
-               attrs[attrList.count].length = strlen(label);
+               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 = strlen(serverName);
+               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 = strlen(securityDomain);
+               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 = strlen(accountName);
+               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 = strlen(path);
+               attrs[attrList.count].length = (UInt32) strlen(path);
                attrs[attrList.count].data = (void *)path;
                attrList.count++;
        }
@@ -420,11 +425,11 @@ do_password_item_printing(        SecKeychainItemRef itemRef,
     } else {
         char *password = (char *) passwordData;
         int doHex = 0;
-        for(int i=0; i<passwordLength; i++) if(!isprint(password[i])) doHex = 1;
+        for(uint32_t i=0; i<passwordLength; i++) if(!isprint(password[i])) doHex = 1;
         if(doHex) {
-            for(int i=0; i<passwordLength; i++) printf("%02x", password[i]);
+            for(uint32_t i=0; i<passwordLength; i++) printf("%02x", password[i]);
         } else {
-            for(int i=0; i<passwordLength; i++) putchar(password[i]);
+            for(uint32_t i=0; i<passwordLength; i++) putchar(password[i]);
         }
         putchar('\n');
     }
@@ -723,7 +728,7 @@ do_keychain_find_certificate(CFTypeRef keychainOrArray,
                        if ((SecCertificateGetData(certificateRef, &data) == noErr) &&
                                (SecDigestGetData(CSSM_ALGID_SHA1, &digest, &data) == CSSM_OK)) {
                                unsigned int i;
-                               uint32 len = digest.Length;
+                               size_t len = digest.Length;
                                uint8 *cp = digest.Data;
                                fprintf(stdout, "SHA-1 hash: ");
                                for(i=0; i<len; i++) {
@@ -1185,6 +1190,611 @@ cleanup:
        return result;
 }
 
+#define SetKeyToString(dict, key, arg) \
+{ \
+    CFStringRef str = CFStringCreateWithCStringNoCopy(NULL, arg, kCFStringEncodingUTF8, kCFAllocatorNull); \
+    CFDictionarySetValue(dict, key, str); \
+    CFReleaseNull(str); \
+}
+
+int
+keychain_find_key(int argc, char * const *argv) {
+    /*
+     *  "    -a  Match \"application label\" string\n"
+     *  "    -c  Match \"creator\" (four-character code)\n"
+     *  "    -d  Match keys that can decrypt\n"
+     *  "    -D  Match \"description\" string\n"
+     *  "    -e  Match keys that can encrypt\n"
+     *  "    -j  Match \"comment\" string\n"
+     *  "    -l  Match \"label\" string\n"
+     *  "    -r  Match keys that can derive\n"
+     *  "    -s  Match keys that can sign\n"
+     *  "    -t  Type of key to find: one of \"symmetric\", \"public\", or \"private\"\n"
+     *  "    -u  Match keys that can unwrap\n"
+     *  "    -v  Match keys that can verify\n"
+     *  "    -w  Match keys that can wrap\n"
+     */
+
+    CFMutableDictionaryRef query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+    CFDictionarySetValue(query, kSecClass, kSecClassKey);
+    CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll);
+
+    CFTypeRef results = NULL;
+
+    int ch, result = 0;
+    while ((ch = getopt(argc, argv, "a:c:dD:ej:l:rst:uvw")) != -1)
+    {
+        switch  (ch)
+        {
+            case 'a':
+                SetKeyToString(query, kSecAttrApplicationLabel, optarg);
+                break;
+            case 'c':
+                SetKeyToString(query, kSecAttrCreator, optarg);
+                break;
+            case 'd':
+                CFDictionarySetValue(query, kSecAttrCanDecrypt, kCFBooleanTrue);
+                break;
+            case 'D':
+                SetKeyToString(query, kSecAttrDescription, optarg);
+                break;
+            case 'e':
+                CFDictionarySetValue(query, kSecAttrCanEncrypt, kCFBooleanTrue);
+                break;
+            case 'j':
+                SetKeyToString(query, kSecAttrComment, optarg);
+                break;
+            case 'l':
+                SetKeyToString(query, kSecAttrLabel, optarg);
+                break;
+            case 'r':
+                CFDictionarySetValue(query, kSecAttrCanDerive, kCFBooleanTrue);
+                break;
+            case 's':
+                CFDictionarySetValue(query, kSecAttrCanSign, kCFBooleanTrue);
+                break;
+            case 't':
+                if(strcmp(optarg, "symmetric") == 0) {
+                    CFDictionarySetValue(query, kSecAttrKeyClass, kSecAttrKeyClassSymmetric);
+                } else if(strcmp(optarg, "public") == 0) {
+                    CFDictionarySetValue(query, kSecAttrKeyClass, kSecAttrKeyClassPublic);
+                } else if(strcmp(optarg, "private") == 0) {
+                    CFDictionarySetValue(query, kSecAttrKeyClass, kSecAttrKeyClassPrivate);
+                } else {
+                    result = 2;
+                    goto cleanup;
+                }
+                break;
+            case 'u':
+                CFDictionarySetValue(query, kSecAttrCanUnwrap, kCFBooleanTrue);
+                break;
+            case 'v':
+                CFDictionarySetValue(query, kSecAttrCanVerify, kCFBooleanTrue);
+                break;
+            case 'w':
+                CFDictionarySetValue(query, kSecAttrCanWrap, kCFBooleanTrue);
+                break;
+            case '?':
+            default:
+                result = 2;
+                goto cleanup;
+        }
+    }
+
+    argc -= optind;
+    argv += optind;
+
+    CFTypeRef keychainOrArray = keychain_create_array(argc, argv);
+
+    if(keychainOrArray && CFGetTypeID(keychainOrArray) == CFArrayGetTypeID()) {
+        CFDictionarySetValue(query, kSecMatchSearchList, keychainOrArray);
+    } else if(keychainOrArray) {
+        // if it's not an array (but is something), it's a keychain. Put it in an array.
+        CFMutableArrayRef searchList = (CFMutableArrayRef) CFArrayCreateMutable(kCFAllocatorDefault, 1, &kCFTypeArrayCallBacks);
+        CFArrayAppendValue((CFMutableArrayRef)searchList, keychainOrArray);
+        CFDictionarySetValue(query, kSecMatchSearchList, searchList);
+        CFRelease(searchList);
+    }
+    CFReleaseNull(keychainOrArray);
+
+    OSStatus status = SecItemCopyMatching(query, &results);
+    if(status) {
+        sec_perror("SecItemCopyMatching", status);
+        result = 1;
+        goto cleanup;
+    }
+
+    if (CFGetTypeID(results) == CFArrayGetTypeID()) {
+        for(int i = 0; i < CFArrayGetCount(results); i++) {
+            SecKeychainItemRef item = (SecKeychainItemRef) CFArrayGetValueAtIndex(results, i);
+
+            print_keychain_item_attributes(stdout, item, FALSE, FALSE, FALSE, FALSE);
+        }
+    }
+
+cleanup:
+    safe_CFRelease(&results);
+    safe_CFRelease(&query);
+    return result;
+}
+
+// Declare here to use later.
+int keychain_set_partition_list(SecKeychainRef kc, CFDictionaryRef query, CFStringRef password, CFStringRef partitionlist);
+int keychain_parse_args_and_set_partition_list(int argc, char * const *argv, CFMutableDictionaryRef query, CFStringRef partitionidsinput, CFStringRef password);
+
+int keychain_set_internet_password_partition_list(int argc, char * const *argv) {
+    /*
+     *  "    -a  Match \"account\" string\n"
+     *  "    -c  Match \"creator\" (four-character code)\n"
+     *  "    -C  Match \"type\" (four-character code)\n"
+     *  "    -d  Match \"securityDomain\" string\n"
+     *  "    -D  Match \"kind\" string\n"
+     *  "    -j  Match \"comment\" string\n"
+     *  "    -l  Match \"label\" string\n"
+     *  "    -p  Match \"path\" string\n"
+     *  "    -P  Match port number\n"
+     *  "    -r  Match \"protocol\" (four-character code)\n"
+     *  "    -s  Match \"server\" string\n"
+     *  "    -t  Match \"authenticationType\" (four-character code)\n"
+     *  "    -S  Comma-separated list of allowed partition IDs"
+     *  "    -k  password for keychain"
+     */
+
+    CFMutableDictionaryRef query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+    CFDictionarySetValue(query, kSecClass, kSecClassInternetPassword);
+    CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll);
+
+    CFStringRef partitionidsinput = NULL;
+    CFStringRef password = NULL;
+
+    int ch, result = 0;
+    while ((ch = getopt(argc, argv, "a:c:C:d:D:j:l:p:P:r:s:S:t:k:")) != -1)
+    {
+        switch  (ch)
+        {
+            case 'a':
+                SetKeyToString(query, kSecAttrAccount, optarg);
+                break;
+            case 'c':
+                SetKeyToString(query, kSecAttrCreator, optarg);
+                break;
+            case 'C':
+                SetKeyToString(query, kSecAttrType, optarg);
+                break;
+            case 'd':
+                SetKeyToString(query, kSecAttrSecurityDomain, optarg);
+                break;
+            case 'D':
+                SetKeyToString(query, kSecAttrDescription, optarg);
+                break;
+            case 'j':
+                SetKeyToString(query, kSecAttrComment, optarg);
+                break;
+            case 'l':
+                SetKeyToString(query, kSecAttrLabel, optarg);
+                break;
+            case 'p':
+                SetKeyToString(query, kSecAttrPath, optarg);
+                break;
+            case 'P':
+                SetKeyToString(query, kSecAttrPort, optarg);
+                break;
+            case 'r':
+                SetKeyToString(query, kSecAttrProtocol, optarg);
+                break;
+            case 's':
+                SetKeyToString(query, kSecAttrService, optarg);
+                break;
+            case 't':
+                SetKeyToString(query, kSecAttrAuthenticationType, optarg);
+                break;
+            case 'S':
+                CFReleaseNull(partitionidsinput);
+                partitionidsinput = CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull);
+                break;
+            case 'k':
+                CFReleaseNull(password);
+                password = CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull);
+                break;
+            case '?':
+            default:
+                result = 2;
+                goto cleanup;
+        }
+    }
+
+    argc -= optind;
+    argv += optind;
+
+    result = keychain_parse_args_and_set_partition_list(argc, argv, query, partitionidsinput, password);
+
+cleanup:
+    safe_CFRelease(&password);
+    safe_CFRelease(&partitionidsinput);
+    safe_CFRelease(&query);
+    return result;
+}
+
+int
+keychain_set_generic_password_partition_list(int argc, char * const *argv) {
+    CFMutableDictionaryRef query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+
+    //        -a  Match \"account\" string
+    //        -c  Match \"creator\" (four-character code)
+    //        -C  Match \"type\" (four-character code)
+    //        -D  Match \"kind\" string
+    //        -G  Match \"value\" string (generic attribute)
+    //        -j  Match \"comment\" string
+    //        -l  Match \"label\" string
+    //        -s  Match \"service\" string
+    //        -S  Comma-separated list of allowed partition IDs
+    //        -k  password for keychain
+
+    CFDictionarySetValue(query, kSecClass, kSecClassGenericPassword);
+    CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll);
+
+    CFStringRef partitionidsinput = NULL;
+    CFStringRef password = NULL;
+
+    int ch, result = 0;
+    while ((ch = getopt(argc, argv, ":a:c:C:D:G:j:l:s:S:k:")) != -1)
+    {
+        switch  (ch)
+        {
+            case 'a':
+                SetKeyToString(query, kSecAttrAccount, optarg);
+                break;
+            case 'c':
+                SetKeyToString(query, kSecAttrCreator, optarg);
+                break;
+            case 'C':
+                SetKeyToString(query, kSecAttrType, optarg);
+                break;
+            case 'D':
+                SetKeyToString(query, kSecAttrDescription, optarg);
+                break;
+            case 'G':
+                SetKeyToString(query, kSecAttrGeneric, optarg);
+                break;
+            case 'j':
+                SetKeyToString(query, kSecAttrComment, optarg);
+                break;
+            case 'l':
+                SetKeyToString(query, kSecAttrLabel, optarg);
+                break;
+            case 's':
+                SetKeyToString(query, kSecAttrService, optarg);
+                break;
+            case 'S':
+                CFReleaseNull(partitionidsinput);
+                partitionidsinput = CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull);
+                break;
+            case 'k':
+                CFReleaseNull(password);
+                password = CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull);
+                break;
+            case '?':
+            case ':':
+                // They supplied the -k but with no data
+                // Leaving it null will cause prompt below
+                if (optopt == 'k') {
+                    break;
+                }
+                result = 2;
+                goto cleanup; /* @@@ Return 2 triggers usage message. */
+            default:
+                result = 2;
+                goto cleanup;
+        }
+    }
+
+    argc -= optind;
+    argv += optind;
+
+    result = keychain_parse_args_and_set_partition_list(argc, argv, query, partitionidsinput, password);
+
+cleanup:
+    safe_CFRelease(&password);
+    safe_CFRelease(&partitionidsinput);
+    safe_CFRelease(&query);
+    return result;
+}
+
+int
+keychain_set_key_partition_list(int argc, char * const *argv) {
+    /*
+     *  "    -a  Match \"application label\" string\n"
+     *  "    -c  Match \"creator\" (four-character code)\n"
+     *  "    -d  Match keys that can decrypt\n"
+     *  "    -D  Match \"description\" string\n"
+     *  "    -e  Match keys that can encrypt\n"
+     *  "    -j  Match \"comment\" string\n"
+     *  "    -l  Match \"label\" string\n"
+     *  "    -r  Match keys that can derive\n"
+     *  "    -s  Match keys that can sign\n"
+     *  "    -t  Type of key to find: one of \"symmetric\", \"public\", or \"private\"\n"
+     *  "    -u  Match keys that can unwrap\n"
+     *  "    -v  Match keys that can verify\n"
+     *  "    -w  Match keys that can wrap\n"
+     *  "    -S  Comma-separated list of allowed partition IDs
+     *  "    -k  password for keychain (required)
+     */
+
+    CFMutableDictionaryRef query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+    CFDictionarySetValue(query, kSecClass, kSecClassKey);
+    CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll);
+
+    CFStringRef partitionidsinput = NULL;
+    CFStringRef password = NULL;
+
+    int ch, result = 0;
+    while ((ch = getopt(argc, argv, ":a:c:dD:ej:k:l:rsS:t:uvw")) != -1)
+    {
+        switch  (ch)
+        {
+            case 'a':
+                SetKeyToString(query, kSecAttrApplicationLabel, optarg);
+                break;
+            case 'c':
+                SetKeyToString(query, kSecAttrCreator, optarg);
+                break;
+            case 'd':
+                SetKeyToString(query, kSecAttrCanDecrypt, optarg);
+                CFDictionarySetValue(query, kSecAttrCanDecrypt, kCFBooleanTrue);
+                break;
+            case 'D':
+                SetKeyToString(query, kSecAttrDescription, optarg);
+                break;
+            case 'e':
+                CFDictionarySetValue(query, kSecAttrCanEncrypt, kCFBooleanTrue);
+                break;
+            case 'j':
+                SetKeyToString(query, kSecAttrComment, optarg);
+                break;
+            case 'l':
+                SetKeyToString(query, kSecAttrLabel, optarg);
+                break;
+            case 'r':
+                CFDictionarySetValue(query, kSecAttrCanDerive, kCFBooleanTrue);
+            case 's':
+                CFDictionarySetValue(query, kSecAttrCanSign, kCFBooleanTrue);
+                break;
+            case 't':
+                if(strcmp(optarg, "symmetric") == 0) {
+                    CFDictionarySetValue(query, kSecAttrKeyClass, kSecAttrKeyClassSymmetric);
+                } else if(strcmp(optarg, "public") == 0) {
+                    CFDictionarySetValue(query, kSecAttrKeyClass, kSecAttrKeyClassPublic);
+                } else if(strcmp(optarg, "private") == 0) {
+                    CFDictionarySetValue(query, kSecAttrKeyClass, kSecAttrKeyClassPrivate);
+                } else {
+                    result = 2;
+                    goto cleanup;
+                }
+                break;
+            case 'u':
+                CFDictionarySetValue(query, kSecAttrCanUnwrap, kCFBooleanTrue);
+                break;
+            case 'v':
+                CFDictionarySetValue(query, kSecAttrCanVerify, kCFBooleanTrue);
+                break;
+            case 'w':
+                CFDictionarySetValue(query, kSecAttrCanWrap, kCFBooleanTrue);
+                break;
+            case 'S':
+                CFReleaseNull(partitionidsinput);
+                partitionidsinput = CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull);
+                break;
+            case 'k':
+                CFReleaseNull(password);
+                password = CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull);
+                break;
+            case '?':
+            case ':':
+                // They supplied the -k but with no data
+                // Leaving it null will cause prompt below
+                if (optopt == 'k') {
+                    break;
+                }
+                result = 2;
+                goto cleanup; /* @@@ Return 2 triggers usage message. */
+            default:
+                result = 2;
+                goto cleanup;
+        }
+    }
+
+    argc -= optind;
+    argv += optind;
+
+    result = keychain_parse_args_and_set_partition_list(argc, argv, query, partitionidsinput, password);
+
+cleanup:
+    CFReleaseNull(partitionidsinput);
+    CFReleaseNull(password);
+    safe_CFRelease(&query);
+    return result;
+}
+
+
+int keychain_parse_args_and_set_partition_list(int argc, char * const *argv, CFMutableDictionaryRef query, CFStringRef partitionidsinput, CFStringRef password) {
+    int result = 0;
+    const char *keychainName = NULL;
+    SecKeychainRef kc = NULL;
+    CFStringRef localPassword = NULL;
+
+    // if we were given a keychain, use it
+    if (argc == 1)
+    {
+        keychainName = argv[0];
+        if (*keychainName == '\0')
+        {
+            result = 2;
+            goto cleanup;
+        }
+
+        kc = keychain_open(keychainName);
+        if(!kc) {
+            sec_error("couldn't open \"%s\"", keychainName);
+            result = 1;
+            goto cleanup;
+        }
+
+        CFMutableArrayRef searchList = (CFMutableArrayRef) CFArrayCreateMutable(kCFAllocatorDefault, 1, &kCFTypeArrayCallBacks);
+        CFArrayAppendValue((CFMutableArrayRef)searchList, kc);
+        CFDictionarySetValue(query, kSecMatchSearchList, searchList);
+    } else if (argc != 0) {
+        result = 2;
+        goto cleanup;
+    }
+
+    if(!partitionidsinput) {
+        result = 2;
+        goto cleanup;
+    }
+
+    if(!password) {
+        char* cpassword = prompt_password(keychainName);
+        if (!cpassword) {
+            result = -1;
+            goto cleanup;
+        }
+        localPassword = CFStringCreateWithCString(NULL, cpassword, kCFStringEncodingUTF8);
+        password = localPassword;
+        free(cpassword);
+    }
+
+    result = keychain_set_partition_list(kc, query, password, partitionidsinput);
+
+cleanup:
+    CFReleaseNull(localPassword);
+    return result;
+}
+
+
+int keychain_set_partition_list(SecKeychainRef kc, CFDictionaryRef query, CFStringRef password, CFStringRef partitionlist) {
+    int result = 0;
+
+    char *passwordBuf = NULL;
+    size_t passwordLen;
+    GetCStringFromCFString(password, &passwordBuf, &passwordLen);
+
+    OSStatus status;
+    CFTypeRef results = NULL;
+
+    // Unlock the keychain with the given password, since we'll be fetching ACLs
+    status = SecKeychainUnlock(kc, (UInt32) passwordLen, passwordBuf, true);
+    if(status) {
+        sec_perror("SecKeychainUnlock", status);
+        result = 1;
+        goto cleanup;
+    }
+
+    status = SecItemCopyMatching(query, &results);
+    if(status) {
+        sec_perror("SecItemCopyMatching", status);
+        result = 1;
+        goto cleanup;
+    }
+
+    if(!results) {
+        result = 0;
+        goto cleanup;
+    }
+
+    if (CFGetTypeID(results) == CFArrayGetTypeID()) {
+        for(int i = 0; i < CFArrayGetCount(results); i++) {
+            SecKeychainItemRef item = (SecKeychainItemRef) CFArrayGetValueAtIndex(results, i);
+            SecAccessRef access = NULL;
+
+            do_password_item_printing(item, false, false);
+
+            status = SecKeychainItemCopyAccess(item, &access);
+            if (status == errSecNoAccessForItem) {
+                continue;
+            }
+            if(status) {
+                sec_perror("SecKeychainItemCopyAccess", status);
+                result = 1;
+                goto cleanup;
+            }
+
+            CFArrayRef aclList = NULL;
+            status = SecAccessCopyACLList(access, &aclList);
+            if (status)
+            {
+                sec_perror("SecAccessCopyACLList", status);
+                result = 1;
+                goto cleanup;
+            }
+
+            CFIndex size = CFArrayGetCount(aclList);
+            for(CFIndex i = 0; i < size; i++) {
+                SecACLRef acl = (SecACLRef) CFArrayGetValueAtIndex(aclList, i);
+                CSSM_ACL_AUTHORIZATION_TAG tags[64]; // Pick some upper limit
+                uint32 tagix, tagCount = sizeof(tags) / sizeof(*tags);
+                status = SecACLGetAuthorizations(acl, tags, &tagCount);
+
+                if (status)
+                {
+                    sec_perror("SecACLGetAuthorizations", status);
+                    result = 1;
+                    goto cleanup;
+                }
+
+                CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector = {};
+
+                for (tagix = 0; tagix < tagCount; ++tagix)
+                {
+                    CSSM_ACL_AUTHORIZATION_TAG tag = tags[tagix];
+                    if(tag == CSSM_ACL_AUTHORIZATION_PARTITION_ID) {
+
+                        CFArrayRef applicationList;
+                        CFStringRef promptDescription;
+
+                        status = SecACLCopySimpleContents(acl, &applicationList, &promptDescription, &promptSelector);
+                        if(status) {
+                            sec_perror("SecACLCopySimpleContents", status);
+                            result = 1;
+                            goto cleanup;
+                        }
+
+                        CFArrayRef partitionIDs = CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault, partitionlist, CFSTR(","));
+                        CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+                        CFDictionarySetValue(dict, CFSTR("Partitions"), partitionIDs);
+                        CFDataRef xml = CFPropertyListCreateXMLData(NULL, dict);
+                        CFStringRef xmlstr = cfToHex(xml);
+
+                        SecACLSetSimpleContents(acl, applicationList, xmlstr, &promptSelector);
+
+                        safe_CFRelease(&xmlstr);
+                        safe_CFRelease(&xml);
+                        safe_CFRelease(&dict);
+                        safe_CFRelease(&partitionIDs);
+                    }
+                }
+            }
+
+            status = SecKeychainItemSetAccessWithPassword(item, access, (UInt32) passwordLen, passwordBuf);
+            if(status) {
+                sec_perror("SecKeychainItemSetAccessWithPassword", status);
+                result = 1;
+                goto cleanup;
+            }
+        }
+    }
+
+    result = 0;
+
+cleanup:
+    if(passwordBuf) {
+        free(passwordBuf);
+    }
+    safe_CFRelease(&results);
+
+    return result;
+}
+
+
 
 int
 keychain_find_certificate(int argc, char * const *argv)