]> git.saurik.com Git - apple/securityd.git/blob - src/authority.cpp
securityd-26674.tar.gz
[apple/securityd.git] / src / authority.cpp
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, 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)
58 : mBaseCreds(base), mTransferCount(INT_MAX),
59 mCreatorCode(Server::process().clientCode()),
60 mCreatorPid(Server::process().pid()),
61 mCreatorAuditToken(auditToken)
62 {
63 mCreatorUid = mCreatorAuditToken.euid();
64 mCreatorGid = mCreatorAuditToken.egid();
65
66 // link to session
67 referent(ssn);
68
69 // generate our (random) handle
70 Server::active().random(mHandle);
71
72 // register handle in the global map
73 StLock<Mutex> _(authMapLock);
74 authMap[mHandle] = this;
75
76 // all ready
77 secdebug("SSauth", "Authorization %p created using %d credentials; owner=%s",
78 this, int(mBaseCreds.size()),
79 mCreatorCode ? mCreatorCode->encode().c_str() : "unknown");
80 }
81
82 AuthorizationToken::~AuthorizationToken()
83 {
84 // we better be clean
85 assert(mUsingProcesses.empty());
86
87 secdebug("SSauth", "Authorization %p destroyed", this);
88 }
89
90
91 Session &AuthorizationToken::session() const
92 {
93 return referent<Session>();
94 }
95
96
97 //
98 // Locate an authorization given its blob.
99 //
100 AuthorizationToken &AuthorizationToken::find(const AuthorizationBlob &blob)
101 {
102 StLock<Mutex> _(authMapLock);
103 AuthMap::iterator it = authMap.find(blob);
104 if (it == authMap.end())
105 Authorization::Error::throwMe(errAuthorizationInvalidRef);
106 return *it->second;
107 }
108
109
110 //
111 // Handle atomic deletion of AuthorizationToken objects
112 //
113 AuthorizationToken::Deleter::Deleter(const AuthorizationBlob &blob)
114 : lock(authMapLock)
115 {
116 AuthMap::iterator it = authMap.find(blob);
117 if (it == authMap.end())
118 Authorization::Error::throwMe(errAuthorizationInvalidRef);
119 mAuth = it->second;
120 }
121
122 void AuthorizationToken::Deleter::remove()
123 {
124 if (mAuth) {
125 authMap.erase(mAuth->handle());
126 mAuth = NULL;
127 }
128 }
129
130
131 //
132 // Given a set of credentials, add it to our private credentials and return the result
133 //
134 // must hold Session::mCredsLock
135 CredentialSet AuthorizationToken::effectiveCreds() const
136 {
137 secdebug("SSauth", "Authorization %p grabbing session %p creds %p",
138 this, &session(), &session().authCredentials());
139 CredentialSet result = session().authCredentials();
140 for (CredentialSet::const_iterator it = mBaseCreds.begin(); it != mBaseCreds.end(); it++)
141 if (!(*it)->isShared())
142 result.insert(*it);
143 return result;
144 }
145
146
147 //
148 // Add more credential dependencies to an authorization
149 //
150 // must hold Session::mCredsLock
151 void AuthorizationToken::mergeCredentials(const CredentialSet &add)
152 {
153 secdebug("SSauth", "Authorization %p merge creds %p", this, &add);
154 for (CredentialSet::const_iterator it = add.begin(); it != add.end(); it++) {
155 mBaseCreds.erase(*it);
156 mBaseCreds.insert(*it);
157 }
158 secdebug("SSauth", "Authorization %p merged %d new credentials for %d total",
159 this, int(add.size()), int(mBaseCreds.size()));
160 }
161
162
163 //
164 // Register a new process that uses this authorization token.
165 // This is an idempotent operation.
166 //
167 void AuthorizationToken::addProcess(Process &proc)
168 {
169 StLock<Mutex> _(mLock);
170 mUsingProcesses.insert(&proc);
171 secdebug("SSauth", "Authorization %p added process %p(%d)", this, &proc, proc.pid());
172 }
173
174
175 //
176 // Completely unregister client process.
177 // It does not matter how often it was registered with addProcess before.
178 // This returns true if no more processes use this token. Presumably you
179 // would then want to clean up, though that's up to you.
180 //
181 bool AuthorizationToken::endProcess(Process &proc)
182 {
183 StLock<Mutex> _(mLock);
184 assert(mUsingProcesses.find(&proc) != mUsingProcesses.end());
185 mUsingProcesses.erase(&proc);
186 secdebug("SSauth", "Authorization %p removed process %p(%d)%s",
187 this, &proc, proc.pid(), mUsingProcesses.empty() ? " FINAL" : "");
188 return mUsingProcesses.empty();
189 }
190
191
192 //
193 // Check whether internalization/externalization is allowed
194 //
195 bool AuthorizationToken::mayExternalize(Process &) const
196 {
197 return mTransferCount > 0;
198 }
199
200 bool AuthorizationToken::mayInternalize(Process &, bool countIt)
201 {
202 StLock<Mutex> _(mLock);
203 if (mTransferCount > 0) {
204 if (countIt) {
205 mTransferCount--;
206 secdebug("SSauth", "Authorization %p decrement intcount to %d", this, mTransferCount);
207 }
208 return true;
209 }
210 return false;
211 }
212
213 AuthItemSet
214 AuthorizationToken::infoSet(AuthorizationString tag)
215 {
216 StLock<Mutex> _(mLock); // consider a separate lock
217
218 AuthItemSet tempSet;
219
220 if (tag)
221 {
222 AuthItemSet::iterator found = find_if(mInfoSet.begin(), mInfoSet.end(),
223 Authorization::FindAuthItemByRightName(tag));
224 if (found != mInfoSet.end())
225 tempSet.insert(AuthItemRef(*found));
226
227 }
228 else
229 tempSet = mInfoSet;
230
231 secdebug("SSauth", "Authorization %p returning copy of context %s%s.", this, tag ? "for tag " : "", tag ? "" : tag);
232
233 return tempSet;
234 }
235
236 void
237 AuthorizationToken::setInfoSet(AuthItemSet &newInfoSet)
238 {
239 StLock<Mutex> _(mLock); // consider a separate lock
240 secdebug("SSauth", "Authorization %p setting new context", this);
241 mInfoSet = newInfoSet;
242 }
243
244 // This is destructive (non-merging)
245 void
246 AuthorizationToken::setCredentialInfo(const Credential &inCred)
247 {
248 AuthItemSet dstInfoSet;
249 char uid_string[16]; // fit a uid_t(u_int32_t)
250
251 if (snprintf(uid_string, sizeof(uid_string), "%u", inCred->uid()) >=
252 int(sizeof(uid_string)))
253 uid_string[0] = '\0';
254 AuthItemRef uidHint("uid", AuthValueOverlay(uid_string ? strlen(uid_string) + 1 : 0, uid_string), 0);
255 dstInfoSet.insert(uidHint);
256
257 AuthItemRef userHint("username", AuthValueOverlay(inCred->username()), 0);
258 dstInfoSet.insert(userHint);
259
260 setInfoSet(dstInfoSet);
261 }
262
263 void
264 AuthorizationToken::clearInfoSet()
265 {
266 AuthItemSet dstInfoSet;
267 secdebug("SSauth", "Authorization %p clearing context", this);
268 setInfoSet(dstInfoSet);
269 }
270
271 void
272 AuthorizationToken::scrubInfoSet()
273 {
274 AuthItemSet srcInfoSet = infoSet(), dstInfoSet;
275 AuthItemSet::const_iterator end = srcInfoSet.end();
276 for (AuthItemSet::const_iterator it = srcInfoSet.begin(); it != end; ++it)
277 {
278 const AuthItemRef &item = *it;
279 if (item->flags() == kAuthorizationContextFlagExtractable)
280 dstInfoSet.insert(item);
281 }
282 secdebug("SSauth", "Authorization %p scrubbing context", this);
283 setInfoSet(dstInfoSet);
284 }