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_FILTER_NONE
) != 0)
69 mCreatorSandboxed
= true;
71 mCreatorSandboxed
= false;
73 if (SecCodeRef code
= Server::process().currentGuest())
74 MacOSError::check(SecCodeCopyStaticCode(code
, kSecCSDefaultFlags
, &mCreatorCode
.aref()));
79 // generate our (random) handle
80 Server::active().random(mHandle
);
82 // register handle in the global map
83 StLock
<Mutex
> _(authMapLock
);
84 authMap
[mHandle
] = this;
87 secdebug("SSauth", "Authorization %p created using %d credentials; owner=%p",
88 this, int(mBaseCreds
.size()), mCreatorCode
.get());
91 AuthorizationToken::~AuthorizationToken()
94 assert(mUsingProcesses
.empty());
96 secdebug("SSauth", "Authorization %p destroyed", this);
100 Session
&AuthorizationToken::session() const
102 return referent
<Session
>();
107 // Locate an authorization given its blob.
109 AuthorizationToken
&AuthorizationToken::find(const AuthorizationBlob
&blob
)
111 StLock
<Mutex
> _(authMapLock
);
112 AuthMap::iterator it
= authMap
.find(blob
);
113 if (it
== authMap
.end())
114 Authorization::Error::throwMe(errAuthorizationInvalidRef
);
120 // Handle atomic deletion of AuthorizationToken objects
122 AuthorizationToken::Deleter::Deleter(const AuthorizationBlob
&blob
)
125 AuthMap::iterator it
= authMap
.find(blob
);
126 if (it
== authMap
.end())
127 Authorization::Error::throwMe(errAuthorizationInvalidRef
);
131 void AuthorizationToken::Deleter::remove()
134 authMap
.erase(mAuth
->handle());
141 // Given a set of credentials, add it to our private credentials and return the result
143 // must hold Session::mCredsLock
144 CredentialSet
AuthorizationToken::effectiveCreds() const
146 secdebug("SSauth", "Authorization %p grabbing session %p creds %p",
147 this, &session(), &session().authCredentials());
148 CredentialSet result
= session().authCredentials();
149 for (CredentialSet::const_iterator it
= mBaseCreds
.begin(); it
!= mBaseCreds
.end(); it
++)
150 if (!(*it
)->isShared())
157 // Add more credential dependencies to an authorization
159 // must hold Session::mCredsLock
160 void AuthorizationToken::mergeCredentials(const CredentialSet
&add
)
162 secdebug("SSauth", "Authorization %p merge creds %p", this, &add
);
163 for (CredentialSet::const_iterator it
= add
.begin(); it
!= add
.end(); it
++) {
164 mBaseCreds
.erase(*it
);
165 mBaseCreds
.insert(*it
);
167 secdebug("SSauth", "Authorization %p merged %d new credentials for %d total",
168 this, int(add
.size()), int(mBaseCreds
.size()));
173 // Register a new process that uses this authorization token.
174 // This is an idempotent operation.
176 void AuthorizationToken::addProcess(Process
&proc
)
178 StLock
<Mutex
> _(mLock
);
179 mUsingProcesses
.insert(&proc
);
180 secdebug("SSauth", "Authorization %p added process %p(%d)", this, &proc
, proc
.pid());
185 // Completely unregister client process.
186 // It does not matter how often it was registered with addProcess before.
187 // This returns true if no more processes use this token. Presumably you
188 // would then want to clean up, though that's up to you.
190 bool AuthorizationToken::endProcess(Process
&proc
)
192 StLock
<Mutex
> _(mLock
);
193 assert(mUsingProcesses
.find(&proc
) != mUsingProcesses
.end());
194 mUsingProcesses
.erase(&proc
);
195 secdebug("SSauth", "Authorization %p removed process %p(%d)%s",
196 this, &proc
, proc
.pid(), mUsingProcesses
.empty() ? " FINAL" : "");
197 return mUsingProcesses
.empty();
202 // Check whether internalization/externalization is allowed
204 bool AuthorizationToken::mayExternalize(Process
&) const
206 return mTransferCount
> 0;
209 bool AuthorizationToken::mayInternalize(Process
&, bool countIt
)
211 StLock
<Mutex
> _(mLock
);
212 if (mTransferCount
> 0) {
215 secdebug("SSauth", "Authorization %p decrement intcount to %d", this, mTransferCount
);
223 AuthorizationToken::infoSet(AuthorizationString tag
)
225 StLock
<Mutex
> _(mLock
); // consider a separate lock
231 AuthItemSet::iterator found
= find_if(mInfoSet
.begin(), mInfoSet
.end(),
232 Authorization::FindAuthItemByRightName(tag
));
233 if (found
!= mInfoSet
.end())
234 tempSet
.insert(AuthItemRef(*found
));
240 secdebug("SSauth", "Authorization %p returning copy of context %s%s.", this, tag
? "for tag " : "", tag
? "" : tag
);
246 AuthorizationToken::setInfoSet(AuthItemSet
&newInfoSet
, bool savePassword
)
248 StLock
<Mutex
> _(mLock
); // consider a separate lock
249 secdebug("SSauth", "Authorization %p setting new context", this);
251 AuthItemSet::const_iterator end
= mInfoSet
.end();
252 for (AuthItemSet::const_iterator it
= mInfoSet
.begin(); it
!= end
; ++it
) {
253 const AuthItemRef
&item
= *it
;
254 if (0 == strcmp(item
->name(), "password")) {
255 mSavedPassword
.clear();
256 mSavedPassword
.insert(item
);
260 if (true == savePassword
)
261 newInfoSet
.insert(mSavedPassword
.begin(), mSavedPassword
.end());
263 mInfoSet
= newInfoSet
;
266 // This is destructive (non-merging)
268 AuthorizationToken::setCredentialInfo(const Credential
&inCred
, bool savePassword
)
270 AuthItemSet dstInfoSet
;
272 uid_t uid
= inCred
->uid();
273 AuthItemRef
uidHint("uid", AuthValueOverlay(sizeof(uid
), &uid
));
274 dstInfoSet
.insert(uidHint
);
276 AuthItemRef
userHint("username", AuthValueOverlay(inCred
->name()), 0);
277 dstInfoSet
.insert(userHint
);
279 setInfoSet(dstInfoSet
, savePassword
);
283 AuthorizationToken::clearInfoSet()
285 AuthItemSet dstInfoSet
;
286 secdebug("SSauth", "Authorization %p clearing context", this);
287 setInfoSet(dstInfoSet
, false);
291 AuthorizationToken::scrubInfoSet(bool savePassword
)
293 AuthItemSet srcInfoSet
= infoSet(), dstInfoSet
;
294 AuthItemSet::const_iterator end
= srcInfoSet
.end();
295 for (AuthItemSet::const_iterator it
= srcInfoSet
.begin(); it
!= end
; ++it
)
297 const AuthItemRef
&item
= *it
;
298 if (item
->flags() == kAuthorizationContextFlagExtractable
)
299 dstInfoSet
.insert(item
);
301 secdebug("SSauth", "Authorization %p scrubbing context", this);
302 setInfoSet(dstInfoSet
, savePassword
);