]> git.saurik.com Git - apple/securityd.git/blob - src/authority.cpp
securityd-40120.tar.gz
[apple/securityd.git] / src / authority.cpp
1 /*
2 * Copyright (c) 2000-2004,2008-2009 Apple 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 //
26 // authority - authorization manager
27 //
28 #include "authority.h"
29 #include "server.h"
30 #include "connection.h"
31 #include "session.h"
32 #include "process.h"
33
34 #include <security_cdsa_utilities/AuthorizationWalkers.h>
35
36 #include <security_utilities/ccaudit.h> // AuditToken
37
38 using Authorization::AuthItemSet;
39 using Authorization::AuthItemRef;
40 using Authorization::AuthValue;
41 using Authorization::AuthValueOverlay;
42
43 //
44 // The global dictionary of extant AuthorizationTokens
45 //
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)
50
51
52
53 //
54 // Create an authorization token.
55 //
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)
62 {
63 mCreatorUid = mCreatorAuditToken.euid();
64 mCreatorGid = mCreatorAuditToken.egid();
65
66 if (SecCodeRef code = Server::process().currentGuest())
67 MacOSError::check(SecCodeCopyStaticCode(code, kSecCSDefaultFlags, &mCreatorCode.aref()));
68
69 // link to session
70 referent(ssn);
71
72 // generate our (random) handle
73 Server::active().random(mHandle);
74
75 // register handle in the global map
76 StLock<Mutex> _(authMapLock);
77 authMap[mHandle] = this;
78
79 // all ready
80 secdebug("SSauth", "Authorization %p created using %d credentials; owner=%p",
81 this, int(mBaseCreds.size()), mCreatorCode.get());
82 }
83
84 AuthorizationToken::~AuthorizationToken()
85 {
86 // we better be clean
87 assert(mUsingProcesses.empty());
88
89 secdebug("SSauth", "Authorization %p destroyed", this);
90 }
91
92
93 Session &AuthorizationToken::session() const
94 {
95 return referent<Session>();
96 }
97
98
99 //
100 // Locate an authorization given its blob.
101 //
102 AuthorizationToken &AuthorizationToken::find(const AuthorizationBlob &blob)
103 {
104 StLock<Mutex> _(authMapLock);
105 AuthMap::iterator it = authMap.find(blob);
106 if (it == authMap.end())
107 Authorization::Error::throwMe(errAuthorizationInvalidRef);
108 return *it->second;
109 }
110
111
112 //
113 // Handle atomic deletion of AuthorizationToken objects
114 //
115 AuthorizationToken::Deleter::Deleter(const AuthorizationBlob &blob)
116 : lock(authMapLock)
117 {
118 AuthMap::iterator it = authMap.find(blob);
119 if (it == authMap.end())
120 Authorization::Error::throwMe(errAuthorizationInvalidRef);
121 mAuth = it->second;
122 }
123
124 void AuthorizationToken::Deleter::remove()
125 {
126 if (mAuth) {
127 authMap.erase(mAuth->handle());
128 mAuth = NULL;
129 }
130 }
131
132
133 //
134 // Given a set of credentials, add it to our private credentials and return the result
135 //
136 // must hold Session::mCredsLock
137 CredentialSet AuthorizationToken::effectiveCreds() const
138 {
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())
144 result.insert(*it);
145 return result;
146 }
147
148
149 //
150 // Add more credential dependencies to an authorization
151 //
152 // must hold Session::mCredsLock
153 void AuthorizationToken::mergeCredentials(const CredentialSet &add)
154 {
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);
159 }
160 secdebug("SSauth", "Authorization %p merged %d new credentials for %d total",
161 this, int(add.size()), int(mBaseCreds.size()));
162 }
163
164
165 //
166 // Register a new process that uses this authorization token.
167 // This is an idempotent operation.
168 //
169 void AuthorizationToken::addProcess(Process &proc)
170 {
171 StLock<Mutex> _(mLock);
172 mUsingProcesses.insert(&proc);
173 secdebug("SSauth", "Authorization %p added process %p(%d)", this, &proc, proc.pid());
174 }
175
176
177 //
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.
182 //
183 bool AuthorizationToken::endProcess(Process &proc)
184 {
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();
191 }
192
193
194 //
195 // Check whether internalization/externalization is allowed
196 //
197 bool AuthorizationToken::mayExternalize(Process &) const
198 {
199 return mTransferCount > 0;
200 }
201
202 bool AuthorizationToken::mayInternalize(Process &, bool countIt)
203 {
204 StLock<Mutex> _(mLock);
205 if (mTransferCount > 0) {
206 if (countIt) {
207 mTransferCount--;
208 secdebug("SSauth", "Authorization %p decrement intcount to %d", this, mTransferCount);
209 }
210 return true;
211 }
212 return false;
213 }
214
215 AuthItemSet
216 AuthorizationToken::infoSet(AuthorizationString tag)
217 {
218 StLock<Mutex> _(mLock); // consider a separate lock
219
220 AuthItemSet tempSet;
221
222 if (tag)
223 {
224 AuthItemSet::iterator found = find_if(mInfoSet.begin(), mInfoSet.end(),
225 Authorization::FindAuthItemByRightName(tag));
226 if (found != mInfoSet.end())
227 tempSet.insert(AuthItemRef(*found));
228
229 }
230 else
231 tempSet = mInfoSet;
232
233 secdebug("SSauth", "Authorization %p returning copy of context %s%s.", this, tag ? "for tag " : "", tag ? "" : tag);
234
235 return tempSet;
236 }
237
238 void
239 AuthorizationToken::setInfoSet(AuthItemSet &newInfoSet)
240 {
241 StLock<Mutex> _(mLock); // consider a separate lock
242 secdebug("SSauth", "Authorization %p setting new context", this);
243 mInfoSet = newInfoSet;
244 }
245
246 // This is destructive (non-merging)
247 void
248 AuthorizationToken::setCredentialInfo(const Credential &inCred)
249 {
250 AuthItemSet dstInfoSet;
251 char uid_string[16]; // fit a uid_t(u_int32_t)
252
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);
258
259 AuthItemRef userHint("username", AuthValueOverlay(inCred->username()), 0);
260 dstInfoSet.insert(userHint);
261
262 setInfoSet(dstInfoSet);
263 }
264
265 void
266 AuthorizationToken::clearInfoSet()
267 {
268 AuthItemSet dstInfoSet;
269 secdebug("SSauth", "Authorization %p clearing context", this);
270 setInfoSet(dstInfoSet);
271 }
272
273 void
274 AuthorizationToken::scrubInfoSet()
275 {
276 AuthItemSet srcInfoSet = infoSet(), dstInfoSet;
277 AuthItemSet::const_iterator end = srcInfoSet.end();
278 for (AuthItemSet::const_iterator it = srcInfoSet.begin(); it != end; ++it)
279 {
280 const AuthItemRef &item = *it;
281 if (item->flags() == kAuthorizationContextFlagExtractable)
282 dstInfoSet.insert(item);
283 }
284 secdebug("SSauth", "Authorization %p scrubbing context", this);
285 setInfoSet(dstInfoSet);
286 }