]> git.saurik.com Git - apple/securityd.git/blob - src/authority.cpp
securityd-55126.2.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 #include <sandbox.h>
39
40 using Authorization::AuthItemSet;
41 using Authorization::AuthItemRef;
42 using Authorization::AuthValue;
43 using Authorization::AuthValueOverlay;
44
45 //
46 // The global dictionary of extant AuthorizationTokens
47 //
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)
52
53
54
55 //
56 // Create an authorization token.
57 //
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)
64 {
65 mCreatorUid = mCreatorAuditToken.euid();
66 mCreatorGid = mCreatorAuditToken.egid();
67
68 if (sandbox_check(mCreatorPid, "authorization-right-obtain", SANDBOX_FILTER_NONE) != 0)
69 mCreatorSandboxed = true;
70 else
71 mCreatorSandboxed = false;
72
73 if (SecCodeRef code = Server::process().currentGuest())
74 MacOSError::check(SecCodeCopyStaticCode(code, kSecCSDefaultFlags, &mCreatorCode.aref()));
75
76 // link to session
77 referent(ssn);
78
79 // generate our (random) handle
80 Server::active().random(mHandle);
81
82 // register handle in the global map
83 StLock<Mutex> _(authMapLock);
84 authMap[mHandle] = this;
85
86 // all ready
87 secdebug("SSauth", "Authorization %p created using %d credentials; owner=%p",
88 this, int(mBaseCreds.size()), mCreatorCode.get());
89 }
90
91 AuthorizationToken::~AuthorizationToken()
92 {
93 // we better be clean
94 assert(mUsingProcesses.empty());
95
96 secdebug("SSauth", "Authorization %p destroyed", this);
97 }
98
99
100 Session &AuthorizationToken::session() const
101 {
102 return referent<Session>();
103 }
104
105
106 //
107 // Locate an authorization given its blob.
108 //
109 AuthorizationToken &AuthorizationToken::find(const AuthorizationBlob &blob)
110 {
111 StLock<Mutex> _(authMapLock);
112 AuthMap::iterator it = authMap.find(blob);
113 if (it == authMap.end())
114 Authorization::Error::throwMe(errAuthorizationInvalidRef);
115 return *it->second;
116 }
117
118
119 //
120 // Handle atomic deletion of AuthorizationToken objects
121 //
122 AuthorizationToken::Deleter::Deleter(const AuthorizationBlob &blob)
123 : lock(authMapLock)
124 {
125 AuthMap::iterator it = authMap.find(blob);
126 if (it == authMap.end())
127 Authorization::Error::throwMe(errAuthorizationInvalidRef);
128 mAuth = it->second;
129 }
130
131 void AuthorizationToken::Deleter::remove()
132 {
133 if (mAuth) {
134 authMap.erase(mAuth->handle());
135 mAuth = NULL;
136 }
137 }
138
139
140 //
141 // Given a set of credentials, add it to our private credentials and return the result
142 //
143 // must hold Session::mCredsLock
144 CredentialSet AuthorizationToken::effectiveCreds() const
145 {
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())
151 result.insert(*it);
152 return result;
153 }
154
155
156 //
157 // Add more credential dependencies to an authorization
158 //
159 // must hold Session::mCredsLock
160 void AuthorizationToken::mergeCredentials(const CredentialSet &add)
161 {
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);
166 }
167 secdebug("SSauth", "Authorization %p merged %d new credentials for %d total",
168 this, int(add.size()), int(mBaseCreds.size()));
169 }
170
171
172 //
173 // Register a new process that uses this authorization token.
174 // This is an idempotent operation.
175 //
176 void AuthorizationToken::addProcess(Process &proc)
177 {
178 StLock<Mutex> _(mLock);
179 mUsingProcesses.insert(&proc);
180 secdebug("SSauth", "Authorization %p added process %p(%d)", this, &proc, proc.pid());
181 }
182
183
184 //
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.
189 //
190 bool AuthorizationToken::endProcess(Process &proc)
191 {
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();
198 }
199
200
201 //
202 // Check whether internalization/externalization is allowed
203 //
204 bool AuthorizationToken::mayExternalize(Process &) const
205 {
206 return mTransferCount > 0;
207 }
208
209 bool AuthorizationToken::mayInternalize(Process &, bool countIt)
210 {
211 StLock<Mutex> _(mLock);
212 if (mTransferCount > 0) {
213 if (countIt) {
214 mTransferCount--;
215 secdebug("SSauth", "Authorization %p decrement intcount to %d", this, mTransferCount);
216 }
217 return true;
218 }
219 return false;
220 }
221
222 AuthItemSet
223 AuthorizationToken::infoSet(AuthorizationString tag)
224 {
225 StLock<Mutex> _(mLock); // consider a separate lock
226
227 AuthItemSet tempSet;
228
229 if (tag)
230 {
231 AuthItemSet::iterator found = find_if(mInfoSet.begin(), mInfoSet.end(),
232 Authorization::FindAuthItemByRightName(tag));
233 if (found != mInfoSet.end())
234 tempSet.insert(AuthItemRef(*found));
235
236 }
237 else
238 tempSet = mInfoSet;
239
240 secdebug("SSauth", "Authorization %p returning copy of context %s%s.", this, tag ? "for tag " : "", tag ? "" : tag);
241
242 return tempSet;
243 }
244
245 void
246 AuthorizationToken::setInfoSet(AuthItemSet &newInfoSet, bool savePassword)
247 {
248 StLock<Mutex> _(mLock); // consider a separate lock
249 secdebug("SSauth", "Authorization %p setting new context", this);
250
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);
257 }
258 }
259
260 if (true == savePassword)
261 newInfoSet.insert(mSavedPassword.begin(), mSavedPassword.end());
262
263 mInfoSet = newInfoSet;
264 }
265
266 // This is destructive (non-merging)
267 void
268 AuthorizationToken::setCredentialInfo(const Credential &inCred, bool savePassword)
269 {
270 AuthItemSet dstInfoSet;
271
272 uid_t uid = inCred->uid();
273 AuthItemRef uidHint("uid", AuthValueOverlay(sizeof(uid), &uid));
274 dstInfoSet.insert(uidHint);
275
276 AuthItemRef userHint("username", AuthValueOverlay(inCred->name()), 0);
277 dstInfoSet.insert(userHint);
278
279 setInfoSet(dstInfoSet, savePassword);
280 }
281
282 void
283 AuthorizationToken::clearInfoSet()
284 {
285 AuthItemSet dstInfoSet;
286 secdebug("SSauth", "Authorization %p clearing context", this);
287 setInfoSet(dstInfoSet, false);
288 }
289
290 void
291 AuthorizationToken::scrubInfoSet(bool savePassword)
292 {
293 AuthItemSet srcInfoSet = infoSet(), dstInfoSet;
294 AuthItemSet::const_iterator end = srcInfoSet.end();
295 for (AuthItemSet::const_iterator it = srcInfoSet.begin(); it != end; ++it)
296 {
297 const AuthItemRef &item = *it;
298 if (item->flags() == kAuthorizationContextFlagExtractable)
299 dstInfoSet.insert(item);
300 }
301 secdebug("SSauth", "Authorization %p scrubbing context", this);
302 setInfoSet(dstInfoSet, savePassword);
303 }