]> git.saurik.com Git - apple/security.git/blob - SecurityTool/macOS/access_utils.c
Security-59754.80.3.tar.gz
[apple/security.git] / SecurityTool / macOS / access_utils.c
1 /*
2 * Copyright (c) 2008-2009,2012,2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 *
23 * access_utils.c
24 */
25
26 #include "access_utils.h"
27 #include "security_tool.h"
28 #include <stdio.h>
29 #include <Security/SecKeychainItem.h>
30 #include <Security/SecAccess.h>
31 #include <Security/SecACL.h>
32
33 // create_access
34 //
35 // This function creates a SecAccessRef with an array of trusted applications.
36 //
37 int
38 create_access(const char *accessName, Boolean allowAny, CFArrayRef trustedApps, SecAccessRef *access)
39 {
40 int result = 0;
41 CFArrayRef appList = NULL;
42 CFArrayRef aclList = NULL;
43 CFStringRef description = NULL;
44 const char *descriptionLabel = (accessName) ? accessName : "<unlabeled key>";
45 CFStringRef promptDescription = NULL;
46 CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector;
47 SecACLRef aclRef;
48 OSStatus status;
49
50 if (accessName) {
51 description = CFStringCreateWithCString(NULL, descriptionLabel, kCFStringEncodingUTF8);
52 }
53
54 status = SecAccessCreate(description, trustedApps, access);
55 if (status)
56 {
57 sec_perror("SecAccessCreate", status);
58 result = 1;
59 goto cleanup;
60 }
61
62 // get the access control list for decryption operations (this controls access to an item's data)
63 status = SecAccessCopySelectedACLList(*access, CSSM_ACL_AUTHORIZATION_DECRYPT, &aclList);
64 if (status)
65 {
66 sec_perror("SecAccessCopySelectedACLList", status);
67 result = 1;
68 goto cleanup;
69 }
70
71 // get the first entry in the access control list
72 aclRef = (SecACLRef)CFArrayGetValueAtIndex(aclList, 0);
73 status = SecACLCopySimpleContents(aclRef, &appList, &promptDescription, &promptSelector);
74 if (status)
75 {
76 sec_perror("SecACLCopySimpleContents", status);
77 result = 1;
78 goto cleanup;
79 }
80
81 if (allowAny) // "allow all applications to access this item"
82 {
83 // change the decryption ACL to not require the passphrase, and have a nil application list.
84 promptSelector.flags &= ~CSSM_ACL_KEYCHAIN_PROMPT_REQUIRE_PASSPHRASE;
85 status = SecACLSetSimpleContents(aclRef, NULL, promptDescription, &promptSelector);
86 }
87 else // "allow access by these applications"
88 {
89 // modify the application list
90 status = SecACLSetSimpleContents(aclRef, trustedApps, promptDescription, &promptSelector);
91 }
92 if (status)
93 {
94 sec_perror("SecACLSetSimpleContents", status);
95 result = 1;
96 goto cleanup;
97 }
98
99 cleanup:
100 if (description)
101 CFRelease(description);
102 if (promptDescription)
103 CFRelease(promptDescription);
104 if (appList)
105 CFRelease(appList);
106 if (aclList)
107 CFRelease(aclList);
108
109 return result;
110 }
111
112 // merge_access
113 //
114 // This function merges the contents of otherAccess into access.
115 // Simple ACL contents are assumed, and only the standard ACL
116 // for decryption operations is currently processed.
117 //
118 int
119 merge_access(SecAccessRef access, SecAccessRef otherAccess)
120 {
121 OSStatus status;
122 CFArrayRef aclList, newAclList;
123
124 // get existing access control list for decryption operations (this controls access to an item's data)
125 status = SecAccessCopySelectedACLList(access, CSSM_ACL_AUTHORIZATION_DECRYPT, &aclList);
126 if (status) {
127 return status;
128 }
129 // get desired access control list for decryption operations
130 status = SecAccessCopySelectedACLList(otherAccess, CSSM_ACL_AUTHORIZATION_DECRYPT, &newAclList);
131 if (status) {
132 newAclList = nil;
133 } else {
134 SecACLRef aclRef=(SecACLRef)CFArrayGetValueAtIndex(aclList, 0);
135 SecACLRef newAclRef=(SecACLRef)CFArrayGetValueAtIndex(newAclList, 0);
136 CFArrayRef appList=nil;
137 CFArrayRef newAppList=nil;
138 CFMutableArrayRef mergedAppList = nil;
139 CFStringRef promptDescription=nil;
140 CFStringRef newPromptDescription=nil;
141 CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector;
142 CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR newPromptSelector;
143
144 status = SecACLCopySimpleContents(aclRef, &appList, &promptDescription, &promptSelector);
145 if (!status) {
146 status = SecACLCopySimpleContents(newAclRef, &newAppList, &newPromptDescription, &newPromptSelector);
147 }
148 if (!status) {
149 if (appList) {
150 mergedAppList = CFArrayCreateMutableCopy(NULL, 0, appList);
151 }
152 if (newAppList) {
153 if (mergedAppList) {
154 CFArrayAppendArray(mergedAppList, newAppList, CFRangeMake(0, CFArrayGetCount(newAppList)));
155 } else {
156 mergedAppList = CFArrayCreateMutableCopy(NULL, 0, newAppList);
157 }
158 }
159 promptSelector.flags = newPromptSelector.flags;
160 status = SecACLSetSimpleContents(aclRef, mergedAppList, newPromptDescription, &newPromptSelector);
161 }
162
163 if (appList) CFRelease(appList);
164 if (newAppList) CFRelease(newAppList);
165 if (mergedAppList) CFRelease(mergedAppList);
166 if (promptDescription) CFRelease(promptDescription);
167 if (newPromptDescription) CFRelease(newPromptDescription);
168 }
169 if (aclList) CFRelease(aclList);
170 if (newAclList) CFRelease(newAclList);
171
172 return status;
173 }
174
175 // modify_access
176 //
177 // This function updates the access for an existing item.
178 // The provided access is merged with the item's existing access.
179 //
180 int
181 modify_access(SecKeychainItemRef itemRef, SecAccessRef access)
182 {
183 OSStatus status;
184 SecAccessRef curAccess = NULL;
185 // for historical reasons, we have to modify the item's existing access reference
186 // (setting the item's access to a freshly created SecAccessRef instance doesn't behave as expected)
187 status = SecKeychainItemCopyAccess(itemRef, &curAccess);
188 if (status) {
189 sec_error("SecKeychainItemCopyAccess: %s", sec_errstr(status));
190 } else {
191 status = merge_access(curAccess, access); // make changes to the existing access reference
192 if (!status) {
193 status = SecKeychainItemSetAccess(itemRef, curAccess); // will prompt!
194 if (status) {
195 sec_error("SecKeychainItemSetAccess: %s", sec_errstr(status));
196 }
197 }
198 }
199 if (curAccess) {
200 CFRelease(curAccess);
201 }
202 return status;
203 }