+++ /dev/null
-/*
- * Copyright (c) 2008-2009,2012,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@
- *
- * access_utils.c
- */
-
-#include "access_utils.h"
-#include "security_tool.h"
-#include <stdio.h>
-#include <Security/SecKeychainItem.h>
-#include <Security/SecAccess.h>
-#include <Security/SecACL.h>
-
-// create_access
-//
-// This function creates a SecAccessRef with an array of trusted applications.
-//
-int
-create_access(const char *accessName, Boolean allowAny, CFArrayRef trustedApps, SecAccessRef *access)
-{
- int result = 0;
- CFArrayRef appList = NULL;
- CFArrayRef aclList = NULL;
- CFStringRef description = NULL;
- const char *descriptionLabel = (accessName) ? accessName : "<unlabeled key>";
- CFStringRef promptDescription = NULL;
- CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector;
- SecACLRef aclRef;
- OSStatus status;
-
- if (accessName) {
- description = CFStringCreateWithCString(NULL, descriptionLabel, kCFStringEncodingUTF8);
- }
-
- status = SecAccessCreate(description, trustedApps, access);
- if (status)
- {
- sec_perror("SecAccessCreate", status);
- result = 1;
- goto cleanup;
- }
-
- // get the access control list for decryption operations (this controls access to an item's data)
- status = SecAccessCopySelectedACLList(*access, CSSM_ACL_AUTHORIZATION_DECRYPT, &aclList);
- if (status)
- {
- sec_perror("SecAccessCopySelectedACLList", status);
- result = 1;
- goto cleanup;
- }
-
- // get the first entry in the access control list
- aclRef = (SecACLRef)CFArrayGetValueAtIndex(aclList, 0);
- status = SecACLCopySimpleContents(aclRef, &appList, &promptDescription, &promptSelector);
- if (status)
- {
- sec_perror("SecACLCopySimpleContents", status);
- result = 1;
- goto cleanup;
- }
-
- if (allowAny) // "allow all applications to access this item"
- {
- // change the decryption ACL to not require the passphrase, and have a nil application list.
- promptSelector.flags &= ~CSSM_ACL_KEYCHAIN_PROMPT_REQUIRE_PASSPHRASE;
- status = SecACLSetSimpleContents(aclRef, NULL, promptDescription, &promptSelector);
- }
- else // "allow access by these applications"
- {
- // modify the application list
- status = SecACLSetSimpleContents(aclRef, trustedApps, promptDescription, &promptSelector);
- }
- if (status)
- {
- sec_perror("SecACLSetSimpleContents", status);
- result = 1;
- goto cleanup;
- }
-
-cleanup:
- if (description)
- CFRelease(description);
- if (promptDescription)
- CFRelease(promptDescription);
- if (appList)
- CFRelease(appList);
- if (aclList)
- CFRelease(aclList);
-
- return result;
-}
-
-// merge_access
-//
-// This function merges the contents of otherAccess into access.
-// Simple ACL contents are assumed, and only the standard ACL
-// for decryption operations is currently processed.
-//
-int
-merge_access(SecAccessRef access, SecAccessRef otherAccess)
-{
- OSStatus status;
- CFArrayRef aclList, newAclList;
-
- // get existing access control list for decryption operations (this controls access to an item's data)
- status = SecAccessCopySelectedACLList(access, CSSM_ACL_AUTHORIZATION_DECRYPT, &aclList);
- if (status) {
- return status;
- }
- // get desired access control list for decryption operations
- status = SecAccessCopySelectedACLList(otherAccess, CSSM_ACL_AUTHORIZATION_DECRYPT, &newAclList);
- if (status) {
- newAclList = nil;
- } else {
- SecACLRef aclRef=(SecACLRef)CFArrayGetValueAtIndex(aclList, 0);
- SecACLRef newAclRef=(SecACLRef)CFArrayGetValueAtIndex(newAclList, 0);
- CFArrayRef appList=nil;
- CFArrayRef newAppList=nil;
- CFMutableArrayRef mergedAppList = nil;
- CFStringRef promptDescription=nil;
- CFStringRef newPromptDescription=nil;
- CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector;
- CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR newPromptSelector;
-
- status = SecACLCopySimpleContents(aclRef, &appList, &promptDescription, &promptSelector);
- if (!status) {
- status = SecACLCopySimpleContents(newAclRef, &newAppList, &newPromptDescription, &newPromptSelector);
- }
- if (!status) {
- if (appList) {
- mergedAppList = CFArrayCreateMutableCopy(NULL, 0, appList);
- }
- if (newAppList) {
- if (mergedAppList) {
- CFArrayAppendArray(mergedAppList, newAppList, CFRangeMake(0, CFArrayGetCount(newAppList)));
- } else {
- mergedAppList = CFArrayCreateMutableCopy(NULL, 0, newAppList);
- }
- }
- promptSelector.flags = newPromptSelector.flags;
- status = SecACLSetSimpleContents(aclRef, mergedAppList, newPromptDescription, &newPromptSelector);
- }
-
- if (appList) CFRelease(appList);
- if (newAppList) CFRelease(newAppList);
- if (mergedAppList) CFRelease(mergedAppList);
- if (promptDescription) CFRelease(promptDescription);
- if (newPromptDescription) CFRelease(newPromptDescription);
- }
- if (aclList) CFRelease(aclList);
- if (newAclList) CFRelease(newAclList);
-
- return status;
-}
-
-// modify_access
-//
-// This function updates the access for an existing item.
-// The provided access is merged with the item's existing access.
-//
-int
-modify_access(SecKeychainItemRef itemRef, SecAccessRef access)
-{
- OSStatus status;
- 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 {
- status = merge_access(curAccess, access); // make changes to the existing access reference
- if (!status) {
- status = SecKeychainItemSetAccess(itemRef, curAccess); // will prompt!
- if (status) {
- sec_error("SecKeychainItemSetAccess: %s", sec_errstr(status));
- }
- }
- }
- if (curAccess) {
- CFRelease(curAccess);
- }
- return status;
-}