]> git.saurik.com Git - apple/security.git/blob - securityd/src/authority.cpp
Security-57337.40.85.tar.gz
[apple/security.git] / securityd / src / authority.cpp
1 /*
2 * Copyright (c) 2000-2012 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_CHECK_NO_REPORT) != 0)
69 mCreatorSandboxed = true;
70 else
71 mCreatorSandboxed = false;
72
73 {
74 Process &thisProcess = Server::process();
75 StLock<Mutex> _(thisProcess);
76 if (SecCodeRef code = thisProcess.currentGuest())
77 MacOSError::check(SecCodeCopyStaticCode(code, kSecCSDefaultFlags, &mCreatorCode.aref()));
78 }
79
80 // link to session
81 referent(ssn);
82
83 // generate our (random) handle
84 Server::active().random(mHandle);
85
86 // register handle in the global map
87 StLock<Mutex> _(authMapLock);
88 authMap[mHandle] = this;
89
90 // all ready
91 secdebug("SSauth", "Authorization %p created using %d credentials; owner=%p",
92 this, int(mBaseCreds.size()), mCreatorCode.get());
93 }
94
95 AuthorizationToken::~AuthorizationToken()
96 {
97 // we better be clean
98 assert(mUsingProcesses.empty());
99
100 secdebug("SSauth", "Authorization %p destroyed", this);
101 }
102
103
104 Session &AuthorizationToken::session() const
105 {
106 return referent<Session>();
107 }
108
109
110 std::string AuthorizationToken::creatorPath() const
111 {
112 if (mCreatorCode) {
113 StLock<Mutex> _(mLock);
114 CFRef<CFURLRef> path;
115 if (SecCodeCopyPath(mCreatorCode, kSecCSDefaultFlags, &path.aref()) == noErr)
116 return cfString(path);
117 }
118 return "unknown";
119 }
120
121
122 //
123 // Locate an authorization given its blob.
124 //
125 AuthorizationToken &AuthorizationToken::find(const AuthorizationBlob &blob)
126 {
127 StLock<Mutex> _(authMapLock);
128 AuthMap::iterator it = authMap.find(blob);
129 if (it == authMap.end())
130 Authorization::Error::throwMe(errAuthorizationInvalidRef);
131 return *it->second;
132 }
133
134
135 //
136 // Handle atomic deletion of AuthorizationToken objects
137 //
138 AuthorizationToken::Deleter::Deleter(const AuthorizationBlob &blob)
139 : lock(authMapLock)
140 {
141 AuthMap::iterator it = authMap.find(blob);
142 if (it == authMap.end())
143 Authorization::Error::throwMe(errAuthorizationInvalidRef);
144 mAuth = it->second;
145 }
146
147 void AuthorizationToken::Deleter::remove()
148 {
149 if (mAuth) {
150 authMap.erase(mAuth->handle());
151 mAuth = NULL;
152 }
153 }
154
155
156 //
157 // Given a set of credentials, add it to our private credentials and return the result
158 //
159 // must hold Session::mCredsLock
160 CredentialSet AuthorizationToken::effectiveCreds() const
161 {
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())
167 result.insert(*it);
168 return result;
169 }
170
171
172 //
173 // Add more credential dependencies to an authorization
174 //
175 // must hold Session::mCredsLock
176 void AuthorizationToken::mergeCredentials(const CredentialSet &add)
177 {
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);
182 }
183 secdebug("SSauth", "Authorization %p merged %d new credentials for %d total",
184 this, int(add.size()), int(mBaseCreds.size()));
185 }
186
187
188 //
189 // Register a new process that uses this authorization token.
190 // This is an idempotent operation.
191 //
192 void AuthorizationToken::addProcess(Process &proc)
193 {
194 StLock<Mutex> _(mLock);
195 mUsingProcesses.insert(&proc);
196 secdebug("SSauth", "Authorization %p added process %p(%d)", this, &proc, proc.pid());
197 }
198
199
200 //
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.
205 //
206 bool AuthorizationToken::endProcess(Process &proc)
207 {
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();
214 }
215
216
217 //
218 // Check whether internalization/externalization is allowed
219 //
220 bool AuthorizationToken::mayExternalize(Process &) const
221 {
222 return mTransferCount > 0;
223 }
224
225 bool AuthorizationToken::mayInternalize(Process &, bool countIt)
226 {
227 StLock<Mutex> _(mLock);
228 if (mTransferCount > 0) {
229 if (countIt) {
230 mTransferCount--;
231 secdebug("SSauth", "Authorization %p decrement intcount to %d", this, mTransferCount);
232 }
233 return true;
234 }
235 return false;
236 }
237
238 AuthItemSet
239 AuthorizationToken::infoSet(AuthorizationString tag)
240 {
241 StLock<Mutex> _(mLock); // consider a separate lock
242
243 AuthItemSet tempSet;
244
245 if (tag)
246 {
247 AuthItemSet::iterator found = find_if(mInfoSet.begin(), mInfoSet.end(),
248 Authorization::FindAuthItemByRightName(tag));
249 if (found != mInfoSet.end())
250 tempSet.insert(AuthItemRef(*found));
251
252 }
253 else
254 tempSet = mInfoSet;
255
256 secdebug("SSauth", "Authorization %p returning copy of context %s%s.", this, tag ? "for tag " : "", tag ? "" : tag);
257
258 return tempSet;
259 }
260
261 void
262 AuthorizationToken::setInfoSet(AuthItemSet &newInfoSet, bool savePassword)
263 {
264 StLock<Mutex> _(mLock); // consider a separate lock
265 secdebug("SSauth", "Authorization %p setting new context", this);
266
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);
273 }
274 }
275
276 if (true == savePassword)
277 newInfoSet.insert(mSavedPassword.begin(), mSavedPassword.end());
278
279 mInfoSet = newInfoSet;
280 }
281
282 // This is destructive (non-merging)
283 void
284 AuthorizationToken::setCredentialInfo(const Credential &inCred, bool savePassword)
285 {
286 AuthItemSet dstInfoSet;
287
288 uid_t uid = inCred->uid();
289 AuthItemRef uidHint("uid", AuthValueOverlay(sizeof(uid), &uid));
290 dstInfoSet.insert(uidHint);
291
292 AuthItemRef userHint("username", AuthValueOverlay(inCred->name()), 0);
293 dstInfoSet.insert(userHint);
294
295 setInfoSet(dstInfoSet, savePassword);
296 }
297
298 void
299 AuthorizationToken::clearInfoSet()
300 {
301 AuthItemSet dstInfoSet;
302 secdebug("SSauth", "Authorization %p clearing context", this);
303 setInfoSet(dstInfoSet, false);
304 }
305
306 void
307 AuthorizationToken::scrubInfoSet(bool savePassword)
308 {
309 AuthItemSet srcInfoSet = infoSet(), dstInfoSet;
310 AuthItemSet::const_iterator end = srcInfoSet.end();
311 for (AuthItemSet::const_iterator it = srcInfoSet.begin(); it != end; ++it)
312 {
313 const AuthItemRef &item = *it;
314 if (item->flags() == kAuthorizationContextFlagExtractable)
315 dstInfoSet.insert(item);
316 }
317 secdebug("SSauth", "Authorization %p scrubbing context", this);
318 setInfoSet(dstInfoSet, savePassword);
319 }