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
);