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
38 using Authorization::AuthItemSet
;
39 using Authorization::AuthItemRef
;
40 using Authorization::AuthValue
;
41 using Authorization::AuthValueOverlay
;
44 // The global dictionary of extant AuthorizationTokens
46 //AuthorizationToken::AuthMap AuthorizationToken::authMap; // set of extant authorizations
47 //@@@ Workaround ONLY! Don't destruct this map on termination
48 AuthorizationToken::AuthMap
&AuthorizationToken::authMap
= *new AuthMap
; // set of extant authorizations
49 Mutex
AuthorizationToken::authMapLock
; // lock for mAuthorizations (only)
54 // Create an authorization token.
56 AuthorizationToken::AuthorizationToken(Session
&ssn
, const CredentialSet
&base
,
57 const audit_token_t
&auditToken
, bool operateAsLeastPrivileged
)
58 : mBaseCreds(base
), mTransferCount(INT_MAX
),
59 mCreatorPid(Server::process().pid()),
60 mCreatorAuditToken(auditToken
),
61 mOperatesAsLeastPrivileged(operateAsLeastPrivileged
)
63 mCreatorUid
= mCreatorAuditToken
.euid();
64 mCreatorGid
= mCreatorAuditToken
.egid();
66 if (SecCodeRef code
= Server::process().currentGuest())
67 MacOSError::check(SecCodeCopyStaticCode(code
, kSecCSDefaultFlags
, &mCreatorCode
.aref()));
72 // generate our (random) handle
73 Server::active().random(mHandle
);
75 // register handle in the global map
76 StLock
<Mutex
> _(authMapLock
);
77 authMap
[mHandle
] = this;
80 secdebug("SSauth", "Authorization %p created using %d credentials; owner=%p",
81 this, int(mBaseCreds
.size()), mCreatorCode
.get());
84 AuthorizationToken::~AuthorizationToken()
87 assert(mUsingProcesses
.empty());
89 secdebug("SSauth", "Authorization %p destroyed", this);
93 Session
&AuthorizationToken::session() const
95 return referent
<Session
>();
100 // Locate an authorization given its blob.
102 AuthorizationToken
&AuthorizationToken::find(const AuthorizationBlob
&blob
)
104 StLock
<Mutex
> _(authMapLock
);
105 AuthMap::iterator it
= authMap
.find(blob
);
106 if (it
== authMap
.end())
107 Authorization::Error::throwMe(errAuthorizationInvalidRef
);
113 // Handle atomic deletion of AuthorizationToken objects
115 AuthorizationToken::Deleter::Deleter(const AuthorizationBlob
&blob
)
118 AuthMap::iterator it
= authMap
.find(blob
);
119 if (it
== authMap
.end())
120 Authorization::Error::throwMe(errAuthorizationInvalidRef
);
124 void AuthorizationToken::Deleter::remove()
127 authMap
.erase(mAuth
->handle());
134 // Given a set of credentials, add it to our private credentials and return the result
136 // must hold Session::mCredsLock
137 CredentialSet
AuthorizationToken::effectiveCreds() const
139 secdebug("SSauth", "Authorization %p grabbing session %p creds %p",
140 this, &session(), &session().authCredentials());
141 CredentialSet result
= session().authCredentials();
142 for (CredentialSet::const_iterator it
= mBaseCreds
.begin(); it
!= mBaseCreds
.end(); it
++)
143 if (!(*it
)->isShared())
150 // Add more credential dependencies to an authorization
152 // must hold Session::mCredsLock
153 void AuthorizationToken::mergeCredentials(const CredentialSet
&add
)
155 secdebug("SSauth", "Authorization %p merge creds %p", this, &add
);
156 for (CredentialSet::const_iterator it
= add
.begin(); it
!= add
.end(); it
++) {
157 mBaseCreds
.erase(*it
);
158 mBaseCreds
.insert(*it
);
160 secdebug("SSauth", "Authorization %p merged %d new credentials for %d total",
161 this, int(add
.size()), int(mBaseCreds
.size()));
166 // Register a new process that uses this authorization token.
167 // This is an idempotent operation.
169 void AuthorizationToken::addProcess(Process
&proc
)
171 StLock
<Mutex
> _(mLock
);
172 mUsingProcesses
.insert(&proc
);
173 secdebug("SSauth", "Authorization %p added process %p(%d)", this, &proc
, proc
.pid());
178 // Completely unregister client process.
179 // It does not matter how often it was registered with addProcess before.
180 // This returns true if no more processes use this token. Presumably you
181 // would then want to clean up, though that's up to you.
183 bool AuthorizationToken::endProcess(Process
&proc
)
185 StLock
<Mutex
> _(mLock
);
186 assert(mUsingProcesses
.find(&proc
) != mUsingProcesses
.end());
187 mUsingProcesses
.erase(&proc
);
188 secdebug("SSauth", "Authorization %p removed process %p(%d)%s",
189 this, &proc
, proc
.pid(), mUsingProcesses
.empty() ? " FINAL" : "");
190 return mUsingProcesses
.empty();
195 // Check whether internalization/externalization is allowed
197 bool AuthorizationToken::mayExternalize(Process
&) const
199 return mTransferCount
> 0;
202 bool AuthorizationToken::mayInternalize(Process
&, bool countIt
)
204 StLock
<Mutex
> _(mLock
);
205 if (mTransferCount
> 0) {
208 secdebug("SSauth", "Authorization %p decrement intcount to %d", this, mTransferCount
);
216 AuthorizationToken::infoSet(AuthorizationString tag
)
218 StLock
<Mutex
> _(mLock
); // consider a separate lock
224 AuthItemSet::iterator found
= find_if(mInfoSet
.begin(), mInfoSet
.end(),
225 Authorization::FindAuthItemByRightName(tag
));
226 if (found
!= mInfoSet
.end())
227 tempSet
.insert(AuthItemRef(*found
));
233 secdebug("SSauth", "Authorization %p returning copy of context %s%s.", this, tag
? "for tag " : "", tag
? "" : tag
);
239 AuthorizationToken::setInfoSet(AuthItemSet
&newInfoSet
)
241 StLock
<Mutex
> _(mLock
); // consider a separate lock
242 secdebug("SSauth", "Authorization %p setting new context", this);
243 mInfoSet
= newInfoSet
;
246 // This is destructive (non-merging)
248 AuthorizationToken::setCredentialInfo(const Credential
&inCred
)
250 AuthItemSet dstInfoSet
;
251 char uid_string
[16]; // fit a uid_t(u_int32_t)
253 if (snprintf(uid_string
, sizeof(uid_string
), "%u", inCred
->uid()) >=
254 int(sizeof(uid_string
)))
255 uid_string
[0] = '\0';
256 AuthItemRef
uidHint("uid", AuthValueOverlay(uid_string
[0] ? strlen(uid_string
) + 1 : 0, uid_string
), 0);
257 dstInfoSet
.insert(uidHint
);
259 AuthItemRef
userHint("username", AuthValueOverlay(inCred
->username()), 0);
260 dstInfoSet
.insert(userHint
);
262 setInfoSet(dstInfoSet
);
266 AuthorizationToken::clearInfoSet()
268 AuthItemSet dstInfoSet
;
269 secdebug("SSauth", "Authorization %p clearing context", this);
270 setInfoSet(dstInfoSet
);
274 AuthorizationToken::scrubInfoSet()
276 AuthItemSet srcInfoSet
= infoSet(), dstInfoSet
;
277 AuthItemSet::const_iterator end
= srcInfoSet
.end();
278 for (AuthItemSet::const_iterator it
= srcInfoSet
.begin(); it
!= end
; ++it
)
280 const AuthItemRef
&item
= *it
;
281 if (item
->flags() == kAuthorizationContextFlagExtractable
)
282 dstInfoSet
.insert(item
);
284 secdebug("SSauth", "Authorization %p scrubbing context", this);
285 setInfoSet(dstInfoSet
);