1/* 2 * Copyright (c) 2002-2004 Apple Computer, 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// 25// Access.cpp 26// 27#include <security_keychain/Access.h> 28#include <Security/SecBase.h> 29#include "SecBridge.h" 30#include <security_utilities/devrandom.h> 31#include <security_cdsa_utilities/uniformrandom.h> 32#include <security_cdsa_client/aclclient.h> 33#include <vector> 34#include <SecBase.h> 35using namespace KeychainCore; 36using namespace CssmClient; 37 38 39// 40// Access static constants 41// 42const CSSM_ACL_HANDLE Access::ownerHandle; 43 44 45// 46// Create a completely open Access (anyone can do anything) 47// Note that this means anyone can *change* the ACL at will, too. 48// These ACL entries contain no descriptor names. 49// 50Access::Access() : mMutex(Mutex::recursive) 51{ 52 SecPointer<ACL> owner = new ACL(*this); 53 owner->setAuthorization(CSSM_ACL_AUTHORIZATION_CHANGE_ACL); 54 addOwner(owner); 55 56 SecPointer<ACL> any = new ACL(*this); 57 add(any); 58} 59 60 61// 62// Create a default Access object. 63// This construct an Access with "default form", whatever that happens to be 64// in this release. 65// 66Access::Access(const string &descriptor, const ACL::ApplicationList &trusted) : mMutex(Mutex::recursive) 67{ 68 makeStandard(descriptor, trusted); 69} 70 71Access::Access(const string &descriptor) : mMutex(Mutex::recursive) 72{ 73 ACL::ApplicationList trusted; 74 trusted.push_back(new TrustedApplication); 75 makeStandard(descriptor, trusted); 76} 77 78Access::Access(const string &descriptor, const ACL::ApplicationList &trusted, 79 const AclAuthorizationSet &limitedRights, const AclAuthorizationSet &freeRights) : mMutex(Mutex::recursive) 80{ 81 makeStandard(descriptor, trusted, limitedRights, freeRights); 82} 83 84void Access::makeStandard(const string &descriptor, const ACL::ApplicationList &trusted, 85 const AclAuthorizationSet &limitedRights, const AclAuthorizationSet &freeRights) 86{ 87 StLock<Mutex>_(mMutex); 88 89 // owner "entry" 90 SecPointer<ACL> owner = new ACL(*this, descriptor, ACL::defaultSelector); 91 owner->setAuthorization(CSSM_ACL_AUTHORIZATION_CHANGE_ACL); 92 addOwner(owner); 93 94 // unlimited entry 95 SecPointer<ACL> unlimited = new ACL(*this, descriptor, ACL::defaultSelector); 96 if (freeRights.empty()) { 97 unlimited->authorizations().clear(); 98 unlimited->authorizations().insert(CSSM_ACL_AUTHORIZATION_ENCRYPT); 99 } else 100 unlimited->authorizations() = freeRights; 101 unlimited->form(ACL::allowAllForm); 102 add(unlimited); 103 104 // limited entry 105 SecPointer<ACL> limited = new ACL(*this, descriptor, ACL::defaultSelector); 106 if (limitedRights.empty()) { 107 limited->authorizations().clear(); 108 limited->authorizations().insert(CSSM_ACL_AUTHORIZATION_DECRYPT); 109 limited->authorizations().insert(CSSM_ACL_AUTHORIZATION_SIGN); 110 limited->authorizations().insert(CSSM_ACL_AUTHORIZATION_MAC); 111 limited->authorizations().insert(CSSM_ACL_AUTHORIZATION_DERIVE); 112 limited->authorizations().insert(CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR); 113 limited->authorizations().insert(CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED); 114 } else 115 limited->authorizations() = limitedRights; 116 limited->applications() = trusted; 117 add(limited); 118} 119 120 121// 122// Create an Access object whose initial value is taken 123// from a CSSM ACL bearing object. 124// 125Access::Access(AclBearer &source) : mMutex(Mutex::recursive) 126{ 127 // retrieve and set 128 AutoAclOwnerPrototype owner; 129 source.getOwner(owner); 130 AutoAclEntryInfoList acls; 131 source.getAcl(acls); 132 compile(*owner, acls.count(), acls.entries()); 133} 134 135 136// 137// Create an Access object from CSSM-layer access controls 138// 139Access::Access(const CSSM_ACL_OWNER_PROTOTYPE &owner, 140 uint32 aclCount, const CSSM_ACL_ENTRY_INFO *acls) : mMutex(Mutex::recursive) 141{ 142 compile(owner, aclCount, acls); 143} 144 145 146Access::~Access() 147{ 148} 149 150 151// Convert a SecPointer to a SecACLRef. 152static SecACLRef 153convert(const SecPointer<ACL> &acl) 154{ 155 return *acl; 156} 157 158// 159// Return all ACL components in a newly-made CFArray. 160// 161CFArrayRef Access::copySecACLs() const 162{ 163 return makeCFArray(convert, mAcls); 164} 165 166CFArrayRef Access::copySecACLs(CSSM_ACL_AUTHORIZATION_TAG action) const 167{ 168 list<ACL *> choices; 169 for (Map::const_iterator it = mAcls.begin(); it != mAcls.end(); it++) 170 if (it->second->authorizes(action)) 171 choices.push_back(it->second); 172 return choices.empty() ? NULL : makeCFArray(convert, choices); 173} 174 175 176// 177// Enter the complete access configuration into a AclBearer. 178// If update, skip any part marked unchanged. (If not update, skip 179// any part marked deleted.) 180// 181void Access::setAccess(AclBearer &target, bool update /* = false */) 182{ 183 StLock<Mutex>_(mMutex); 184 AclFactory factory; 185 editAccess(target, update, factory.promptCred()); 186} 187 188void Access::setAccess(AclBearer &target, Maker &maker) 189{ 190 StLock<Mutex>_(mMutex); 191 if (maker.makerType() == Maker::kStandardMakerType) 192 { 193 // remove initial-setup ACL 194 target.deleteAcl(Maker::creationEntryTag, maker.cred()); 195 196 // insert our own ACL entries 197 editAccess(target, false, maker.cred()); 198 } 199} 200 201void Access::editAccess(AclBearer &target, bool update, const AccessCredentials *cred) 202{ 203 StLock<Mutex>_(mMutex); 204 assert(mAcls[ownerHandle]); // have owner 205 206 // apply all non-owner ACLs first 207 for (Map::iterator it = mAcls.begin(); it != mAcls.end(); it++) 208 if (!it->second->isOwner()) 209 it->second->setAccess(target, update, cred); 210 211 // finally, apply owner 212 mAcls[ownerHandle]->setAccess(target, update, cred); 213} 214 215 216// 217// A convenience function to add one application to a standard ("simple") form 218// ACL entry. This will only work if 219// -- there is exactly one ACL entry authorizing the right 220// -- that entry is in simple form 221// 222void Access::addApplicationToRight(AclAuthorization right, TrustedApplication *app) 223{ 224 StLock<Mutex>_(mMutex); 225 vector<ACL *> acls; 226 findAclsForRight(right, acls); 227 if (acls.size() != 1) 228 MacOSError::throwMe(errSecACLNotSimple); // let's not guess here... 229 (*acls.begin())->addApplication(app); 230} 231 232 233// 234// Yield new (copied) CSSM level owner and acls values, presumably 235// for use at CSSM layer operations. 236// Caller is responsible for releasing the beasties when done. 237// 238void Access::copyOwnerAndAcl(CSSM_ACL_OWNER_PROTOTYPE * &ownerResult, 239 uint32 &aclCount, CSSM_ACL_ENTRY_INFO * &aclsResult) 240{ 241 StLock<Mutex>_(mMutex); 242 Allocator& alloc = Allocator::standard(); 243 unsigned long count = mAcls.size() - 1; // one will be owner, others are acls 244 AclOwnerPrototype owner; 245 CssmAutoPtr<AclEntryInfo> acls = new(alloc) AclEntryInfo[count]; 246 AclEntryInfo *aclp = acls; // -> next unfilled acl element 247 for (Map::const_iterator it = mAcls.begin(); it != mAcls.end(); it++) { 248 SecPointer<ACL> acl = it->second; 249 if (acl->isOwner()) { 250 acl->copyAclOwner(owner, alloc); 251 } else { 252 aclp->handle() = acl->entryHandle(); 253 acl->copyAclEntry(*aclp, alloc); 254 ++aclp; 255 } 256 } 257 assert((aclp - acls) == count); // all ACL elements filled 258 259 // commit output 260 ownerResult = new(alloc) AclOwnerPrototype(owner); 261 aclCount = (uint32)count; 262 aclsResult = acls.release(); 263} 264 265 266// 267// Retrieve the description from a randomly chosen ACL within this Access. 268// In the conventional case where all ACLs have the same descriptor, this 269// is deterministic. But you have been warned. 270// 271string Access::promptDescription() const 272{ 273 for (Map::const_iterator it = mAcls.begin(); it != mAcls.end(); it++) { 274 ACL *acl = it->second; 275 switch (acl->form()) { 276 case ACL::allowAllForm: 277 case ACL::appListForm: 278 { 279 string descr = acl->promptDescription(); 280 if (!descr.empty()) 281 return descr; 282 } 283 default: 284 break; 285 } 286 } 287 // couldn't find suitable ACL (no description anywhere) 288 CssmError::throwMe(errSecACLNotSimple); 289} 290 291 292// 293// Add a new ACL to the resident set. The ACL must have been 294// newly made for this Access. 295// 296void Access::add(ACL *newAcl) 297{ 298 StLock<Mutex>_(mMutex); 299 if (&newAcl->access != this) 300 MacOSError::throwMe(errSecParam); 301 assert(!mAcls[newAcl->entryHandle()]); 302 mAcls[newAcl->entryHandle()] = newAcl; 303} 304 305 306// 307// Add the owner ACL to the resident set. The ACL must have been 308// newly made for this Access. 309// Since an Access must have exactly one owner ACL, this call 310// should only be made (exactly once) for a newly created Access. 311// 312void Access::addOwner(ACL *newAcl) 313{ 314 StLock<Mutex>_(mMutex); 315 newAcl->makeOwner(); 316 assert(mAcls.find(ownerHandle) == mAcls.end()); // no owner yet 317 add(newAcl); 318} 319 320 321// 322// Compile a set of ACL entries and owner into internal form. 323// 324void Access::compile(const CSSM_ACL_OWNER_PROTOTYPE &owner, 325 uint32 aclCount, const CSSM_ACL_ENTRY_INFO *acls) 326{ 327 StLock<Mutex>_(mMutex); 328 // add owner acl 329 mAcls[ownerHandle] = new ACL(*this, AclOwnerPrototype::overlay(owner)); 330 331 // add acl entries 332 const AclEntryInfo *acl = AclEntryInfo::overlay(acls); 333 for (uint32 n = 0; n < aclCount; n++) { 334 secdebug("SecAccess", "%p compiling entry %ld", this, acl[n].handle()); 335 mAcls[acl[n].handle()] = new ACL(*this, acl[n]); 336 } 337 secdebug("SecAccess", "%p %ld entries compiled", this, mAcls.size()); 338} 339 340 341// 342// Creation helper objects 343// 344const char Access::Maker::creationEntryTag[] = "___setup___"; 345 346Access::Maker::Maker(Allocator &alloc, MakerType makerType) 347 : allocator(alloc), mKey(alloc), mCreds(allocator), mMakerType(makerType) 348{ 349 if (makerType == kStandardMakerType) 350 { 351 // generate random key 352 mKey.malloc(keySize); 353 UniformRandomBlobs<DevRandomGenerator>().random(mKey.get()); 354 355 // create entry info for resource creation 356 mInput = AclEntryPrototype(TypedList(allocator, CSSM_ACL_SUBJECT_TYPE_PASSWORD, 357 new(allocator) ListElement(mKey.get()))); 358 mInput.proto().tag(creationEntryTag); 359 360 // create credential sample for access 361 mCreds += TypedList(allocator, CSSM_SAMPLE_TYPE_PASSWORD, new(allocator) ListElement(mKey.get())); 362 } 363 else 364 { 365 // just make it an CSSM_ACL_SUBJECT_TYPE_ANY list 366 mInput = AclEntryPrototype(TypedList(allocator, CSSM_ACL_SUBJECT_TYPE_ANY)); 367 } 368} 369 370void Access::Maker::initialOwner(ResourceControlContext &ctx, const AccessCredentials *creds) 371{ 372 //@@@ make up ctx.entry-info 373 ctx.input() = mInput; 374 ctx.credentials(creds); 375} 376 377const AccessCredentials *Access::Maker::cred() 378{ 379 return &mCreds; 380} 381