2  * Copyright (c) 2000-2004,2008-2009 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   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 
  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. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  26 // authority - authorization manager 
  28 #include "authority.h" 
  30 #include "connection.h" 
  34 #include <security_cdsa_utilities/AuthorizationWalkers.h> 
  36 #include <security_utilities/ccaudit.h>         // AuditToken 
  40 using Authorization::AuthItemSet
; 
  41 using Authorization::AuthItemRef
; 
  42 using Authorization::AuthValue
; 
  43 using Authorization::AuthValueOverlay
; 
  46 // The global dictionary of extant AuthorizationTokens 
  48 //AuthorizationToken::AuthMap AuthorizationToken::authMap; // set of extant authorizations 
  49 //@@@ Workaround ONLY! Don't destruct this map on termination 
  50 AuthorizationToken::AuthMap 
&AuthorizationToken::authMap 
= *new AuthMap
; // set of extant authorizations 
  51 Mutex 
AuthorizationToken::authMapLock
; // lock for mAuthorizations (only) 
  56 // Create an authorization token. 
  58 AuthorizationToken::AuthorizationToken(Session 
&ssn
, const CredentialSet 
&base
,  
  59 const audit_token_t 
&auditToken
, bool operateAsLeastPrivileged
) 
  60         : mBaseCreds(base
), mTransferCount(INT_MAX
),  
  61         mCreatorPid(Server::process().pid()),  
  62         mCreatorAuditToken(auditToken
), 
  63         mOperatesAsLeastPrivileged(operateAsLeastPrivileged
) 
  65         mCreatorUid 
= mCreatorAuditToken
.euid(); 
  66         mCreatorGid 
= mCreatorAuditToken
.egid(); 
  68         if (sandbox_check(mCreatorPid
, "authorization-right-obtain", SANDBOX_CHECK_NO_REPORT
) != 0) 
  69                 mCreatorSandboxed 
= true; 
  71                 mCreatorSandboxed 
= false; 
  74                 Process 
&thisProcess 
= Server::process(); 
  75                 StLock
<Mutex
> _(thisProcess
); 
  76                 if (SecCodeRef code 
= thisProcess
.currentGuest()) 
  77                         MacOSError::check(SecCodeCopyStaticCode(code
, kSecCSDefaultFlags
, &mCreatorCode
.aref())); 
  83     // generate our (random) handle 
  84     Server::active().random(mHandle
); 
  86     // register handle in the global map 
  87     StLock
<Mutex
> _(authMapLock
); 
  88     authMap
[mHandle
] = this; 
  91         secdebug("SSauth", "Authorization %p created using %d credentials; owner=%p", 
  92                 this, int(mBaseCreds
.size()), mCreatorCode
.get()); 
  95 AuthorizationToken::~AuthorizationToken() 
  98         assert(mUsingProcesses
.empty()); 
 100         secdebug("SSauth", "Authorization %p destroyed", this); 
 104 Session 
&AuthorizationToken::session() const 
 106         return referent
<Session
>(); 
 110 std::string 
AuthorizationToken::creatorPath() const 
 113                 StLock
<Mutex
> _(mLock
); 
 114                 CFRef
<CFURLRef
> path
; 
 115                 if (SecCodeCopyPath(mCreatorCode
, kSecCSDefaultFlags
, &path
.aref()) == noErr
) 
 116                         return cfString(path
); 
 123 // Locate an authorization given its blob. 
 125 AuthorizationToken 
&AuthorizationToken::find(const AuthorizationBlob 
&blob
) 
 127     StLock
<Mutex
> _(authMapLock
); 
 128         AuthMap::iterator it 
= authMap
.find(blob
); 
 129         if (it 
== authMap
.end()) 
 130                 Authorization::Error::throwMe(errAuthorizationInvalidRef
); 
 136 // Handle atomic deletion of AuthorizationToken objects 
 138 AuthorizationToken::Deleter::Deleter(const AuthorizationBlob 
&blob
) 
 141     AuthMap::iterator it 
= authMap
.find(blob
); 
 142     if (it 
== authMap
.end()) 
 143         Authorization::Error::throwMe(errAuthorizationInvalidRef
); 
 147 void AuthorizationToken::Deleter::remove() 
 150         authMap
.erase(mAuth
->handle()); 
 157 // Given a set of credentials, add it to our private credentials and return the result 
 159 // must hold Session::mCredsLock 
 160 CredentialSet 
AuthorizationToken::effectiveCreds() const 
 162     secdebug("SSauth", "Authorization %p grabbing session %p creds %p", 
 163                 this, &session(), &session().authCredentials()); 
 164     CredentialSet result 
= session().authCredentials(); 
 165         for (CredentialSet::const_iterator it 
= mBaseCreds
.begin(); it 
!= mBaseCreds
.end(); it
++) 
 166                 if (!(*it
)->isShared()) 
 173 // Add more credential dependencies to an authorization 
 175 // must hold Session::mCredsLock 
 176 void AuthorizationToken::mergeCredentials(const CredentialSet 
&add
) 
 178     secdebug("SSauth", "Authorization %p merge creds %p", this, &add
); 
 179         for (CredentialSet::const_iterator it 
= add
.begin(); it 
!= add
.end(); it
++) { 
 180         mBaseCreds
.erase(*it
); 
 181         mBaseCreds
.insert(*it
); 
 183     secdebug("SSauth", "Authorization %p merged %d new credentials for %d total", 
 184                 this, int(add
.size()), int(mBaseCreds
.size())); 
 189 // Register a new process that uses this authorization token. 
 190 // This is an idempotent operation. 
 192 void AuthorizationToken::addProcess(Process 
&proc
) 
 194         StLock
<Mutex
> _(mLock
); 
 195         mUsingProcesses
.insert(&proc
); 
 196         secdebug("SSauth", "Authorization %p added process %p(%d)", this, &proc
, proc
.pid()); 
 201 // Completely unregister client process. 
 202 // It does not matter how often it was registered with addProcess before. 
 203 // This returns true if no more processes use this token. Presumably you 
 204 // would then want to clean up, though that's up to you. 
 206 bool AuthorizationToken::endProcess(Process 
&proc
) 
 208         StLock
<Mutex
> _(mLock
); 
 209         assert(mUsingProcesses
.find(&proc
) != mUsingProcesses
.end()); 
 210         mUsingProcesses
.erase(&proc
); 
 211         secdebug("SSauth", "Authorization %p removed process %p(%d)%s", 
 212                 this, &proc
, proc
.pid(), mUsingProcesses
.empty() ? " FINAL" : ""); 
 213         return mUsingProcesses
.empty(); 
 218 // Check whether internalization/externalization is allowed 
 220 bool AuthorizationToken::mayExternalize(Process 
&) const 
 222         return mTransferCount 
> 0; 
 225 bool AuthorizationToken::mayInternalize(Process 
&, bool countIt
) 
 227         StLock
<Mutex
> _(mLock
); 
 228         if (mTransferCount 
> 0) { 
 231                         secdebug("SSauth", "Authorization %p decrement intcount to %d", this, mTransferCount
); 
 239 AuthorizationToken::infoSet(AuthorizationString tag
) 
 241     StLock
<Mutex
> _(mLock
); // consider a separate lock 
 247                 AuthItemSet::iterator found 
= find_if(mInfoSet
.begin(), mInfoSet
.end(),  
 248                                         Authorization::FindAuthItemByRightName(tag
)); 
 249                 if (found 
!= mInfoSet
.end()) 
 250                         tempSet
.insert(AuthItemRef(*found
)); 
 256         secdebug("SSauth", "Authorization %p returning copy of context %s%s.", this, tag 
? "for tag " : "", tag 
? "" : tag
); 
 262 AuthorizationToken::setInfoSet(AuthItemSet 
&newInfoSet
, bool savePassword
) 
 264         StLock
<Mutex
> _(mLock
); // consider a separate lock 
 265     secdebug("SSauth", "Authorization %p setting new context", this); 
 267         AuthItemSet::const_iterator end 
= mInfoSet
.end(); 
 268         for (AuthItemSet::const_iterator it 
= mInfoSet
.begin(); it 
!= end
; ++it
) { 
 269                 const AuthItemRef 
&item 
= *it
; 
 270                 if (0 == strcmp(item
->name(), "password")) { 
 271                         mSavedPassword
.clear(); 
 272                         mSavedPassword
.insert(item
); 
 276         if (true == savePassword
) 
 277                 newInfoSet
.insert(mSavedPassword
.begin(), mSavedPassword
.end()); 
 279     mInfoSet 
= newInfoSet
; 
 282 // This is destructive (non-merging) 
 284 AuthorizationToken::setCredentialInfo(const Credential 
&inCred
, bool savePassword
) 
 286     AuthItemSet dstInfoSet
; 
 288     uid_t uid 
= inCred
->uid(); 
 289     AuthItemRef 
uidHint("uid", AuthValueOverlay(sizeof(uid
), &uid
)); 
 290     dstInfoSet
.insert(uidHint
); 
 292     AuthItemRef 
userHint("username", AuthValueOverlay(inCred
->name()), 0); 
 293     dstInfoSet
.insert(userHint
); 
 295         setInfoSet(dstInfoSet
, savePassword
); 
 299 AuthorizationToken::clearInfoSet() 
 301     AuthItemSet dstInfoSet
; 
 302     secdebug("SSauth", "Authorization %p clearing context", this); 
 303     setInfoSet(dstInfoSet
, false); 
 307 AuthorizationToken::scrubInfoSet(bool savePassword
) 
 309         AuthItemSet srcInfoSet 
= infoSet(), dstInfoSet
; 
 310         AuthItemSet::const_iterator end 
= srcInfoSet
.end(); 
 311         for (AuthItemSet::const_iterator it 
= srcInfoSet
.begin(); it 
!= end
; ++it
) 
 313                 const AuthItemRef 
&item 
= *it
; 
 314                 if (item
->flags() == kAuthorizationContextFlagExtractable
) 
 315                         dstInfoSet
.insert(item
); 
 317     secdebug("SSauth", "Authorization %p scrubbing context", this); 
 318     setInfoSet(dstInfoSet
, savePassword
);