]> git.saurik.com Git - apple/security.git/blobdiff - SecurityTests/cspxutils/acltool/aclUtils.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / cspxutils / acltool / aclUtils.cpp
diff --git a/SecurityTests/cspxutils/acltool/aclUtils.cpp b/SecurityTests/cspxutils/acltool/aclUtils.cpp
new file mode 100644 (file)
index 0000000..5e0b727
--- /dev/null
@@ -0,0 +1,509 @@
+/*
+ * Copyright (c) 2004-2006 Apple Computer, 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@
+ */
+
+/*
+ * aclUtils.cpp - ACL utility functions, copied from the SecurityTool project. 
+ */
+#include "aclUtils.h"
+#include <Security/SecTrustedApplicationPriv.h>
+#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
+
+/* Read a line from stdin into buffer as a null terminated string.  If buffer is
+   non NULL use at most buffer_size bytes and return a pointer to buffer.  Otherwise
+   return a newly malloced buffer.
+   if EOF is read this function returns NULL.  */
+char *
+readline(char *buffer, int buffer_size)
+{
+       int ix = 0, bytes_malloced = 0;
+
+       if (!buffer)
+       {
+               bytes_malloced = 64;
+               buffer = (char *)malloc(bytes_malloced);
+               buffer_size = bytes_malloced;
+       }
+
+       for (;;++ix)
+       {
+               int ch;
+
+               if (ix == buffer_size - 1)
+               {
+                       if (!bytes_malloced)
+                               break;
+                       bytes_malloced += bytes_malloced;
+                       buffer = (char *)realloc(buffer, bytes_malloced);
+                       buffer_size = bytes_malloced;
+               }
+
+               ch = getchar();
+               if (ch == EOF)
+               {
+                       if (bytes_malloced)
+                               free(buffer);
+                       return NULL;
+               }
+               if (ch == '\n')
+                       break;
+               buffer[ix] = ch;
+       }
+
+       /* 0 terminate buffer. */
+       buffer[ix] = '\0';
+
+       return buffer;
+}
+
+void
+print_buffer_hex(FILE *stream, UInt32 length, const void *data)
+{
+       unsigned i;
+       const unsigned char *cp = (const unsigned char *)data;
+       
+       printf("\n   ");
+       for(i=0; i<length; i++) {
+               fprintf(stream, "%02X ", cp[i]);
+               if((i % 24) == 23) {
+                       printf("\n   ");
+               }
+       }
+}
+
+void
+print_buffer_ascii(FILE *stream, UInt32 length, const void *data)
+{
+       uint8 *p = (uint8 *) data;
+       while (length--)
+       {
+               int ch = *p++;
+               if (ch >= ' ' && ch <= '~' && ch != '\\')
+               {
+                       fputc(ch, stream);
+               }
+               else
+               {
+                       fputc('\\', stream);
+                       fputc('0' + ((ch >> 6) & 7), stream);
+                       fputc('0' + ((ch >> 3) & 7), stream);
+                       fputc('0' + ((ch >> 0) & 7), stream);
+               }
+       }
+}
+
+void
+print_buffer(FILE *stream, UInt32 length, const void *data)
+{
+       uint8 *p = (uint8 *) data;
+       Boolean ascii = TRUE;           // unless we determine otherwise
+       UInt32 ix;
+       for (ix = 0; ix < length; ++ix) {
+               int ch = *p++;
+               if ((ch < ' ') || (ch > '~')) {
+                       if((ch == 0) && (ix == (length - 1))) {
+                               /* ignore trailing null */
+                               length--;
+                               break;
+                       }
+                       ascii = FALSE;
+                       break;
+               }
+       }
+
+       if (ascii) {
+               fputc('"', stream);
+               print_buffer_ascii(stream, length, data);
+               fputc('"', stream);
+       }
+       else {
+               print_buffer_hex(stream, length, data);
+       }
+}
+
+void
+print_cfdata(FILE *stream, CFDataRef data)
+{
+       if (data)
+               return print_buffer(stream, CFDataGetLength(data), CFDataGetBytePtr(data));
+       else
+               fprintf(stream, "<NULL>");
+}
+
+void
+print_cfstring(FILE *stream, CFStringRef string)
+{
+       if (!string)
+               fprintf(stream, "<NULL>");
+       else
+       {
+               const char *utf8 = CFStringGetCStringPtr(string, kCFStringEncodingUTF8);
+               if (utf8)
+                       fprintf(stream, "%s", utf8);
+               else
+               {
+                       CFRange rangeToProcess = CFRangeMake(0, CFStringGetLength(string));
+                       while (rangeToProcess.length > 0)
+                       {
+                               UInt8 localBuffer[256];
+                               CFIndex usedBufferLength;
+                               CFIndex numChars = CFStringGetBytes(string, rangeToProcess,
+                                       kCFStringEncodingUTF8, '?', FALSE, localBuffer,
+                                       sizeof(localBuffer), &usedBufferLength);
+                               if (numChars == 0)
+                                       break;   // Failed to convert anything...
+
+                               fprintf(stream, "%.*s", (int)usedBufferLength, localBuffer);
+                               rangeToProcess.location += numChars;
+                               rangeToProcess.length -= numChars;
+                       }
+               }
+       }
+}
+
+
+int
+print_access(FILE *stream, SecAccessRef access, Boolean interactive)
+{
+       CFArrayRef aclList = NULL;
+       CFIndex aclix, aclCount;
+       int result = 0;
+       OSStatus status;
+
+       status = SecAccessCopyACLList(access, &aclList);
+       if (status)
+       {
+               cssmPerror("SecAccessCopyACLList", status);
+               result = 1;
+               goto loser;
+       }
+
+       aclCount = CFArrayGetCount(aclList);
+       fprintf(stream, "access: %lu entries\n", aclCount);
+       for (aclix = 0; aclix < aclCount; ++aclix)
+       {
+               CFArrayRef applicationList = NULL;
+               CFStringRef description = NULL;
+               CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector = {};
+               CFIndex appix, appCount;
+
+               SecACLRef acl = (SecACLRef)CFArrayGetValueAtIndex(aclList, aclix);
+               CSSM_ACL_AUTHORIZATION_TAG tags[64]; // Pick some upper limit
+               uint32 tagix, tagCount = sizeof(tags) / sizeof(*tags);
+               status = SecACLGetAuthorizations(acl, tags, &tagCount);
+               if (status)
+               {
+                       cssmPerror("SecACLGetAuthorizations", status);
+                       result = 1;
+                       goto loser;
+               }
+
+               fprintf(stream, "    entry %lu:\n        authorizations (%lu):", aclix, (unsigned long)tagCount);
+               for (tagix = 0; tagix < tagCount; ++tagix)
+               {
+                       CSSM_ACL_AUTHORIZATION_TAG tag = tags[tagix];
+                       switch (tag)
+                       {
+                       case CSSM_ACL_AUTHORIZATION_ANY:
+                               fputs(" any", stream);
+                               break;
+                       case CSSM_ACL_AUTHORIZATION_LOGIN:
+                               fputs(" login", stream);
+                               break;
+                       case CSSM_ACL_AUTHORIZATION_GENKEY:
+                               fputs(" genkey", stream);
+                               break;
+                       case CSSM_ACL_AUTHORIZATION_DELETE:
+                               fputs(" delete", stream);
+                               break;
+                       case CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED:
+                               fputs(" export_wrapped", stream);
+                               break;
+                       case CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR:
+                               fputs(" export_clear", stream);
+                               break;
+                       case CSSM_ACL_AUTHORIZATION_IMPORT_WRAPPED:
+                               fputs(" import_wrapped", stream);
+                               break;
+                       case CSSM_ACL_AUTHORIZATION_IMPORT_CLEAR:
+                               fputs(" import_clear", stream);
+                               break;
+                       case CSSM_ACL_AUTHORIZATION_SIGN:
+                               fputs(" sign", stream);
+                               break;
+                       case CSSM_ACL_AUTHORIZATION_ENCRYPT:
+                               fputs(" encrypt", stream);
+                               break;
+                       case CSSM_ACL_AUTHORIZATION_DECRYPT:
+                               fputs(" decrypt", stream);
+                               break;
+                       case CSSM_ACL_AUTHORIZATION_MAC:
+                               fputs(" mac", stream);
+                               break;
+                       case CSSM_ACL_AUTHORIZATION_DERIVE:
+                               fputs(" derive", stream);
+                               break;
+                       case CSSM_ACL_AUTHORIZATION_DBS_CREATE:
+                               fputs(" dbs_create", stream);
+                               break;
+                       case CSSM_ACL_AUTHORIZATION_DBS_DELETE:
+                               fputs(" dbs_delete", stream);
+                               break;
+                       case CSSM_ACL_AUTHORIZATION_DB_READ:
+                               fputs(" db_read", stream);
+                               break;
+                       case CSSM_ACL_AUTHORIZATION_DB_INSERT:
+                               fputs(" db_insert", stream);
+                               break;
+                       case CSSM_ACL_AUTHORIZATION_DB_MODIFY:
+                               fputs(" db_modify", stream);
+                               break;
+                       case CSSM_ACL_AUTHORIZATION_DB_DELETE:
+                               fputs(" db_delete", stream);
+                               break;
+                       case CSSM_ACL_AUTHORIZATION_CHANGE_ACL:
+                               fputs(" change_acl", stream);
+                               break;
+                       case CSSM_ACL_AUTHORIZATION_CHANGE_OWNER:
+                               fputs(" change_owner", stream);
+                               break;
+                       default:
+                               fprintf(stream, " tag=%lu", (unsigned long)tag);
+                               break;
+                       }
+               }
+               fputc('\n', stream);
+
+               status = SecACLCopySimpleContents(acl, &applicationList, &description, &promptSelector);
+               if (status)
+               {
+                       cssmPerror("SecACLCopySimpleContents", status);
+                       continue;
+               }
+
+               if (promptSelector.flags & CSSM_ACL_KEYCHAIN_PROMPT_REQUIRE_PASSPHRASE)
+                       fputs("        require-password\n", stream);
+               else
+                       fputs("        don't-require-password\n", stream);
+
+               fputs("        description: ", stream);
+               print_cfstring(stream, description);
+               fputc('\n', stream);
+
+               if (applicationList)
+               {
+                       appCount = CFArrayGetCount(applicationList);
+                       fprintf(stream, "        applications (%lu):\n", appCount);
+               }
+               else
+               {
+                       appCount = 0;
+                       fprintf(stream, "        applications: <null>\n");
+               }
+
+               for (appix = 0; appix < appCount; ++appix)
+               {
+                       const UInt8* bytes;
+                       SecTrustedApplicationRef app = (SecTrustedApplicationRef)CFArrayGetValueAtIndex(applicationList, appix);
+                       CFDataRef data = NULL;
+                       fprintf(stream, "            %lu: ", appix);
+                       status = SecTrustedApplicationCopyData(app, &data);
+                       if (status)
+                       {
+                               cssmPerror("SecTrustedApplicationCopyData", status);
+                               continue;
+                       }
+
+                       bytes = CFDataGetBytePtr(data);
+                       if (bytes && bytes[0] == 0x2f) {
+                               fprintf(stream, "%s", (const char *)bytes);
+                               if ((status = SecTrustedApplicationValidateWithPath(app, (const char *)bytes)) == noErr) {
+                                       fprintf(stream, " (OK)");
+                               } else {
+                                       fprintf(stream, " (status %ld)", status);
+                               }
+                               fprintf(stream, "\n");
+                       } else {
+                               print_cfdata(stream, data);
+                               fputc('\n', stream);
+                       }
+                       if (data)
+                               CFRelease(data);
+               }
+
+
+               if (interactive)
+               {
+                       char buffer[10] = {};
+                       if(applicationList != NULL) {
+                               fprintf(stderr, "NULL out this application list? ");
+                               if (readline(buffer, sizeof(buffer)) && buffer[0] == 'y')
+                               {
+                                       /* 
+                                        * This makes the ops in this entry wide-open, no dialog or confirmation 
+                                        * other than requiring the keychain be open.
+                                        */
+                                       fprintf(stderr, "setting app list to NULL\n");
+                                       status = SecACLSetSimpleContents(acl, NULL, description, &promptSelector);
+                                       if (status)
+                                       {
+                                               cssmPerror("SecACLSetSimpleContents", status);
+                                               continue;
+                                       }
+                               }
+                               else {
+                                       fprintf(stderr, "Set this application list to empty array? ");
+                                       if (readline(buffer, sizeof(buffer)) && buffer[0] == 'y')
+                                       {
+                                               /* 
+                                                * This means "always get confirmation, from all apps".
+                                                */
+                                               fprintf(stderr, "setting app list to empty array\n");
+                                               status = SecACLSetSimpleContents(acl, 
+                                                       CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks), 
+                                                       description, &promptSelector);
+                                               if (status)
+                                               {
+                                                       cssmPerror("SecACLSetSimpleContents", status);
+                                                       continue;
+                                               }
+                                       }
+                               }
+                       }
+                       else {
+                               fprintf(stderr, "Remove this acl? ");
+                               if (readline(buffer, sizeof(buffer)) && buffer[0] == 'y')
+                               {
+                                       /* 
+                                        * This make ths ops in this entry completely inaccessible. 
+                                        */
+                                       fprintf(stderr, "removing acl\n");
+                                       status = SecACLRemove(acl);
+                                       if (status)
+                                       {
+                                               cssmPerror("SecACLRemove", status);
+                                               continue;
+                                       }
+                               }
+                       }
+               }
+               if (description)
+                       CFRelease(description);
+               if (applicationList)
+                       CFRelease(applicationList);
+
+       }
+
+loser:
+       if (aclList)
+               CFRelease(aclList);
+
+       return result;
+}
+
+/* Simluate what StickyRecord is trying to do.... */
+
+/* 
+ * Given an Access object:
+ *  -- extract the ACL for the specified CSSM_ACL_AUTHORIZATION_TAG. We expect there
+ *     to exactly one of these - if the form of a default ACL changes we'll have to 
+ *        revisit this.
+ *  -- set the ACL's app list to the provided CFArray, which may be NULL (meaning 
+ *     "any app can access this, no problem"), an empty array (meaning "always
+ *     prompt"), or an actual app list. 
+ *  -- set or clear the PROMPT_REQUIRE_PASSPHRASE bit per the requirePassphrase
+ *     argument
+ */
+static OSStatus srUpdateAcl(
+       SecAccessRef accessRef,
+       CSSM_ACL_AUTHORIZATION_TAG whichAcl,    // e.g. CSSM_ACL_AUTHORIZATION_DECRYPT
+       CFArrayRef appArray,
+       bool requirePassphrase)
+{
+       OSStatus ortn;
+       CFArrayRef aclList = NULL;
+       
+       ortn = SecAccessCopySelectedACLList(accessRef, whichAcl, &aclList);
+       if(ortn) {
+               cssmPerror("SecAccessCopySelectedACLList", ortn);
+               return ortn;
+       }
+       
+       if(CFArrayGetCount(aclList) != 1) {
+               printf("StickyRecord::updateAcl - unexpected ACL list count (%d)",
+                       (int)CFArrayGetCount(aclList));
+               return internalComponentErr;
+       }
+       SecACLRef acl = (SecACLRef)CFArrayGetValueAtIndex(aclList, 0);
+       
+       CFArrayRef applicationList = NULL;
+       CFStringRef description = NULL;
+       CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector = {};
+       ortn = SecACLCopySimpleContents(acl, &applicationList, &description, &promptSelector);
+       if(ortn) {
+               cssmPerror("SecACLCopySimpleContents", ortn);
+               return ortn;
+       }
+       if(applicationList != NULL) {
+               CFRelease(applicationList);
+       }
+       if(requirePassphrase) {
+               promptSelector.flags |= CSSM_ACL_KEYCHAIN_PROMPT_REQUIRE_PASSPHRASE;
+       }
+       else {
+               promptSelector.flags &= ~CSSM_ACL_KEYCHAIN_PROMPT_REQUIRE_PASSPHRASE;
+       }
+       /* update */
+       ortn = SecACLSetSimpleContents(acl, appArray, description, &promptSelector);
+       
+       /* we got this from SecACLCopySimpleContents - release it regardless */
+       if(description != NULL) {
+               CFRelease(description);
+       }
+       if(ortn) {
+               cssmPerror("SecACLSetSimpleContents", ortn);
+       }
+       if(aclList != NULL) {
+               CFRelease(aclList);
+       }
+       return ortn;
+}
+
+OSStatus stickyRecordUpdateAcl(
+       SecAccessRef accessRef)
+{
+       OSStatus ortn;
+       
+       printf("...updating ACL to simulate a StickyRecord\n");
+       
+       /* First: decrypt. Wide open (NULL app list), !REQUIRE_PASSPHRASE. */
+       ortn = srUpdateAcl(accessRef, CSSM_ACL_AUTHORIZATION_DECRYPT, NULL, false);
+       if(ortn) {
+               return ortn;
+       }
+       
+       /* encrypt: always ask (empty app list, require passphrase */
+       CFArrayRef nullArray = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
+       return srUpdateAcl(accessRef, CSSM_ACL_AUTHORIZATION_ENCRYPT, nullArray, true);
+       
+}