SecACL.cpp
1 /* 2 * Copyright (c) 2002-2004,2011-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 24 #include <Security/SecACL.h> 25 #include <security_keychain/ACL.h> 26 #include <security_keychain/Access.h> 27 #include <security_keychain/SecAccessPriv.h> 28 29 #include <os/activity.h> 30 31 #include "SecBridge.h" 32 33 #include "LegacyAPICounts.h" 34 35 // Forward reference 36 /*! 37 @function GetACLAuthorizationTagFromString 38 @abstract Get the CSSM ACL item from the CFString 39 @param aclStr The String name of the ACL 40 @result The CSSM ACL value 41 */ 42 sint32 GetACLAuthorizationTagFromString(CFStringRef aclStr); 43 44 CFStringRef GetAuthStringFromACLAuthorizationTag(sint32 tag); 45 46 // 47 // Local functions 48 // 49 static void setApplications(ACL *acl, CFArrayRef applicationList); 50 51 CFTypeID 52 SecACLGetTypeID(void) 53 { 54 BEGIN_SECAPI 55 56 return gTypes().ACL.typeID; 57 58 END_SECAPI1(_kCFRuntimeNotATypeID) 59 } 60 61 62 /*! 63 */ 64 OSStatus SecACLCreateFromSimpleContents(SecAccessRef accessRef, 65 CFArrayRef applicationList, 66 CFStringRef description, const CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR *promptSelector, 67 SecACLRef *newAcl) 68 { 69 BEGIN_SECAPI 70 os_activity_t activity = os_activity_create("SecACLCreateFromSimpleContents", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 71 os_activity_scope(activity); 72 os_release(activity); 73 SecPointer<Access> access = Access::required(accessRef); 74 SecPointer<ACL> acl = new ACL(cfString(description), *promptSelector); 75 if (applicationList) { 76 // application-list + prompt 77 acl->form(ACL::appListForm); 78 setApplications(acl, applicationList); 79 } else { 80 // allow-any 81 acl->form(ACL::allowAllForm); 82 } 83 access->add(acl.get()); 84 Required(newAcl) = acl->handle(); 85 END_SECAPI 86 } 87 88 OSStatus SecACLCreateWithSimpleContents(SecAccessRef access, 89 CFArrayRef applicationList, 90 CFStringRef description, 91 SecKeychainPromptSelector promptSelector, 92 SecACLRef *newAcl) 93 { 94 COUNTLEGACYAPI 95 CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR cdsaPromptSelector; 96 cdsaPromptSelector.version = CSSM_ACL_KEYCHAIN_PROMPT_CURRENT_VERSION; 97 cdsaPromptSelector.flags = promptSelector; 98 return SecACLCreateFromSimpleContents(access, applicationList, description, &cdsaPromptSelector, newAcl); 99 } 100 101 102 /*! 103 */ 104 OSStatus SecACLRemove(SecACLRef aclRef) 105 { 106 BEGIN_SECAPI 107 os_activity_t activity = os_activity_create("SecACLRemove", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 108 os_activity_scope(activity); 109 os_release(activity); 110 ACL::required(aclRef)->remove(); 111 END_SECAPI 112 } 113 114 115 static SecTrustedApplicationRef 116 convert(const SecPointer<TrustedApplication> &trustedApplication) 117 { 118 return *trustedApplication; 119 } 120 121 /*! 122 */ 123 OSStatus SecACLCopySimpleContents(SecACLRef aclRef, 124 CFArrayRef *applicationList, 125 CFStringRef *promptDescription, CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR *promptSelector) 126 { 127 BEGIN_SECAPI 128 SecPointer<ACL> acl = ACL::required(aclRef); 129 switch (acl->form()) { 130 case ACL::allowAllForm: 131 Required(applicationList) = NULL; 132 Required(promptDescription) = 133 acl->promptDescription().empty() ? NULL 134 : makeCFString(acl->promptDescription()); 135 Required(promptSelector) = acl->promptSelector(); 136 break; 137 case ACL::appListForm: 138 Required(applicationList) = 139 makeCFArrayFrom(convert, acl->applications()); 140 Required(promptDescription) = makeCFString(acl->promptDescription()); 141 Required(promptSelector) = acl->promptSelector(); 142 break; 143 case ACL::integrityForm: 144 Required(applicationList) = NULL; 145 Required(promptDescription) = makeCFString(acl->integrity().toHex()); 146 147 // We don't have a prompt selector. Nullify. 148 Required(promptSelector).version = CSSM_ACL_KEYCHAIN_PROMPT_CURRENT_VERSION; 149 Required(promptSelector).flags = 0; 150 break; 151 default: 152 return errSecACLNotSimple; // custom or unknown 153 } 154 END_SECAPI 155 } 156 157 OSStatus SecACLCopyContents(SecACLRef acl, 158 CFArrayRef *applicationList, 159 CFStringRef *description, 160 SecKeychainPromptSelector *promptSelector) 161 { 162 COUNTLEGACYAPI 163 CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR cdsaPromptSelector; 164 memset(&cdsaPromptSelector, 0, sizeof(cdsaPromptSelector)); 165 OSStatus err = errSecSuccess; 166 167 err = SecACLCopySimpleContents(acl, applicationList, description, &cdsaPromptSelector); 168 *promptSelector = cdsaPromptSelector.flags; 169 return err; 170 } 171 172 OSStatus SecACLSetSimpleContents(SecACLRef aclRef, 173 CFArrayRef applicationList, 174 CFStringRef description, const CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR *promptSelector) 175 { 176 BEGIN_SECAPI 177 os_activity_t activity = os_activity_create("SecACLSetSimpleContents", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 178 os_activity_scope(activity); 179 os_release(activity); 180 SecPointer<ACL> acl = ACL::required(aclRef); 181 if(acl->form() == ACL::integrityForm) { 182 // If this is an integrity ACL, route the (unhexified) promptDescription into the right place 183 string hex = cfString(description); 184 if(hex.length() %2 == 0) { 185 // might be a valid hex string, try to set 186 CssmAutoData data(Allocator::standard()); 187 data.malloc(hex.length() / 2); 188 data.get().fromHex(hex.c_str()); 189 acl->setIntegrity(data); 190 } 191 } else { 192 // Otherwise, put it in the promptDescription where it belongs 193 acl->promptDescription() = description ? cfString(description) : ""; 194 } 195 acl->promptSelector() = promptSelector ? *promptSelector : ACL::defaultSelector; 196 if(acl->form() != ACL::integrityForm) { 197 if (applicationList) { 198 // application-list + prompt 199 acl->form(ACL::appListForm); 200 setApplications(acl, applicationList); 201 } else { 202 // allow-any 203 acl->form(ACL::allowAllForm); 204 } 205 } 206 acl->modify(); 207 END_SECAPI 208 } 209 210 OSStatus SecACLSetContents(SecACLRef acl, 211 CFArrayRef applicationList, 212 CFStringRef description, 213 SecKeychainPromptSelector promptSelector) 214 { 215 COUNTLEGACYAPI 216 CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR cdsaPromptSelector; 217 cdsaPromptSelector.version = CSSM_ACL_PROCESS_SELECTOR_CURRENT_VERSION; 218 cdsaPromptSelector.flags = promptSelector; 219 return SecACLSetSimpleContents(acl, applicationList, description, &cdsaPromptSelector); 220 } 221 222 // 223 // Stuff a CFArray-of-SecTrustedApplications into an ACL object 224 // 225 static void setApplications(ACL *acl, CFArrayRef applicationList) 226 { 227 ACL::ApplicationList &appList = acl->applications(); 228 appList.clear(); 229 //@@@ should really use STL iterator overlay on CFArray. By hand... 230 CFIndex count = CFArrayGetCount(applicationList); 231 for (CFIndex n = 0; n < count; n++) 232 appList.push_back(TrustedApplication::required( 233 SecTrustedApplicationRef(CFArrayGetValueAtIndex(applicationList, n)))); 234 } 235 236 237 // 238 // Set and get the authorization tags of an ACL entry 239 // 240 OSStatus SecACLGetAuthorizations(SecACLRef acl, 241 CSSM_ACL_AUTHORIZATION_TAG *tags, uint32 *tagCount) 242 { 243 BEGIN_SECAPI 244 AclAuthorizationSet auths = ACL::required(acl)->authorizations(); 245 if (Required(tagCount) < auths.size()) { // overflow 246 *tagCount = (uint32)auths.size(); // report size required 247 CssmError::throwMe(errSecParam); 248 } 249 *tagCount = (uint32)auths.size(); 250 copy(auths.begin(), auths.end(), tags); 251 END_SECAPI 252 } 253 254 CFArrayRef SecACLCopyAuthorizations(SecACLRef acl) 255 { 256 COUNTLEGACYAPI 257 CFArrayRef result = NULL; 258 if (NULL == acl) 259 { 260 return result; 261 } 262 263 AclAuthorizationSet auths = ACL::required(acl)->authorizations(); 264 uint32 numAuths = (uint32)auths.size(); 265 266 CSSM_ACL_AUTHORIZATION_TAG* tags = new CSSM_ACL_AUTHORIZATION_TAG[numAuths]; 267 int i; 268 for (i = 0; i < numAuths; ++i) 269 { 270 tags[i] = NULL; 271 } 272 273 OSStatus err = SecACLGetAuthorizations(acl, tags, &numAuths); 274 if (errSecSuccess != err) 275 { 276 277 return result; 278 } 279 280 CFTypeRef* strings = new CFTypeRef[numAuths]; 281 for (i = 0; i < numAuths; ++i) 282 { 283 strings[i] = NULL; 284 } 285 286 for (size_t iCnt = 0; iCnt < numAuths; iCnt++) 287 { 288 strings[iCnt] = (CFTypeRef)GetAuthStringFromACLAuthorizationTag(tags[iCnt]); 289 } 290 291 result = CFArrayCreate(kCFAllocatorDefault, (const void **)strings, numAuths, &kCFTypeArrayCallBacks); 292 293 delete[] strings; 294 delete[] tags; 295 296 return result; 297 298 } 299 300 OSStatus SecACLSetAuthorizations(SecACLRef aclRef, 301 CSSM_ACL_AUTHORIZATION_TAG *tags, uint32 tagCount) 302 { 303 BEGIN_SECAPI 304 os_activity_t activity = os_activity_create("SecACLSetAuthorizations", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 305 os_activity_scope(activity); 306 os_release(activity); 307 SecPointer<ACL> acl = ACL::required(aclRef); 308 if (acl->isOwner()) // can't change rights of the owner ACL 309 MacOSError::throwMe(errSecInvalidOwnerEdit); 310 AclAuthorizationSet &auths = acl->authorizations(); 311 auths.clear(); 312 copy(tags, tags + tagCount, insert_iterator<AclAuthorizationSet>(auths, auths.begin())); 313 acl->modify(); 314 END_SECAPI 315 } 316 317 OSStatus SecACLUpdateAuthorizations(SecACLRef acl, CFArrayRef authorizations) 318 { 319 COUNTLEGACYAPI 320 if (NULL == acl || NULL == authorizations) 321 { 322 return errSecParam; 323 } 324 uint32 tagCount = (uint32)CFArrayGetCount(authorizations); 325 326 size_t tagSize = (tagCount * sizeof(CSSM_ACL_AUTHORIZATION_TAG)); 327 328 CSSM_ACL_AUTHORIZATION_TAG* tags = (CSSM_ACL_AUTHORIZATION_TAG*)malloc(tagSize); 329 memset(tags, 0, tagSize); 330 for (uint32 iCnt = 0; iCnt < tagCount; iCnt++) 331 { 332 tags[iCnt] = GetACLAuthorizationTagFromString((CFStringRef)CFArrayGetValueAtIndex(authorizations, iCnt)); 333 } 334 335 OSStatus result = SecACLSetAuthorizations(acl, tags, tagCount); 336 free(tags); 337 return result; 338 }