]> git.saurik.com Git - apple/security.git/blob - SecurityServer/session.cpp
Security-29.tar.gz
[apple/security.git] / SecurityServer / session.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19 //
20 // session - authentication session domains
21 //
22 // A Session is defined by a mach_init bootstrap dictionary. These dictionaries are
23 // hierarchical and inherited, so they work well for characterization of processes
24 // that "belong" together. (Of course, if your mach_init is broken, you're in bad shape.)
25 //
26 // Sessions are multi-threaded objects.
27 //
28 #include "session.h"
29 #include "connection.h"
30 #include "server.h"
31
32
33 //
34 // The static session map
35 //
36 Session::SessionMap Session::sessionMap;
37 Mutex Session::sessionMapLock;
38
39
40 //
41 // Create a Session object from initial parameters (create)
42 //
43 Session::Session(Bootstrap bootstrap, SessionAttributeBits attrs)
44 : mBootstrap(bootstrap), mAttributes(attrs), mProcessCount(0), mAuthCount(0), mDying(false)
45 {
46 debug("SSsession", "%p CREATED: handle=0x%lx bootstrap=%d attrs=0x%lx",
47 this, handle(), mBootstrap.port(), mAttributes);
48 }
49
50 RootSession::RootSession()
51 : Session(Bootstrap(), sessionIsRoot | sessionWasInitialized)
52 {
53 // self-install
54 sessionMap[mBootstrap] = this;
55 }
56
57 DynamicSession::DynamicSession(Bootstrap bootstrap) : Session(bootstrap)
58 {
59 Server::active().notifyIfDead(bootstrapPort());
60 }
61
62
63 //
64 // Destroy a Session
65 //
66 Session::~Session()
67 {
68 assert(mProcessCount == 0); // can't die with processes still alive
69 Database::lockAllDatabases();
70 debug("SSsession", "%p DESTROYED: handle=0x%lx bootstrap=%d",
71 this, handle(), mBootstrap.port());
72 }
73
74
75 //
76 // Retrieve or create a session object
77 //
78 Session &Session::find(Bootstrap bootstrap, bool makeNew)
79 {
80 StLock<Mutex> _(sessionMapLock);
81 Session * &slot = sessionMap[bootstrap];
82 if (slot == NULL)
83 if (makeNew)
84 slot = new DynamicSession(bootstrap);
85 else
86 Authorization::Error::throwMe(errAuthorizationInvalidRef);
87 return *slot;
88 }
89
90 Session &Session::find(SecuritySessionId id)
91 {
92 switch (id) {
93 case callerSecuritySession:
94 return Server::connection().process.session;
95 default:
96 return findHandle<Session>(id);
97 }
98 }
99
100
101 //
102 // Act on a death notification for a session's (sub)bootstrap port.
103 // We may not destroy the Session outright here (due to processes that use it),
104 // but we do clear out its accumulated wealth.
105 //
106 void Session::eliminate(Bootstrap bootstrap)
107 {
108 // remove session from session map
109 StLock<Mutex> _(sessionMapLock);
110 SessionMap::iterator it = sessionMap.find(bootstrap);
111 assert(it != sessionMap.end());
112 Session *session = it->second;
113 sessionMap.erase(it);
114
115 // clear resources
116 if (session->clearResources())
117 delete session;
118 else
119 debug("SSsession", "session %p zombified for %d processes and %d auths",
120 session, int(session->mProcessCount), int(session->mAuthCount));
121 }
122
123 bool Session::clearResources()
124 {
125 StLock<Mutex> _(mLock);
126
127 // this session is now officially dying
128 mDying = true;
129
130 // invalidate shared credentials
131 IFDEBUG(if (!mSessionCreds.empty())
132 debug("SSauth", "session %p clearing %d shared credentials",
133 this, int(mSessionCreds.size())));
134 for (CredentialSet::iterator it = mSessionCreds.begin(); it != mSessionCreds.end(); it++)
135 (*it)->invalidate();
136
137 // let the caller know if we are ready to die NOW
138 return mProcessCount == 0 && mAuthCount == 0;
139 }
140
141
142 //
143 // Process management
144 //
145 void Session::addProcess(Process *)
146 {
147 StLock<Mutex> _(mLock);
148 mProcessCount++;
149 }
150
151 bool Session::removeProcess(Process *)
152 {
153 StLock<Mutex> _(mLock);
154 assert(mProcessCount > 0);
155 return --mProcessCount == 0 && mDying && mAuthCount == 0;
156 }
157
158
159 //
160 // Authorization retention management.
161 //
162 void Session::addAuthorization(AuthorizationToken *)
163 {
164 StLock<Mutex> _(mLock);
165 mAuthCount++;
166 }
167
168 bool Session::removeAuthorization(AuthorizationToken *)
169 {
170 StLock<Mutex> _(mLock);
171 assert(mAuthCount > 0);
172 return --mAuthCount == 0 && mDying && mProcessCount == 0;
173 }
174
175
176 //
177 // Authorization operations
178 //
179 OSStatus Session::authCreate(const RightSet &rights,
180 const AuthorizationEnvironment *environment,
181 AuthorizationFlags flags,
182 AuthorizationBlob &newHandle)
183 {
184 // invoke the authorization computation engine
185 CredentialSet resultCreds;
186
187 // this will acquire mLock, so we delay acquiring it
188 auto_ptr<AuthorizationToken> auth(new AuthorizationToken(*this, resultCreds));
189
190 OSStatus result = Server::authority().authorize(rights, environment, flags,
191 &mSessionCreds, &resultCreds, NULL, *auth);
192 newHandle = auth->handle();
193
194 {
195 StLock<Mutex> _(mLock);
196
197 // merge resulting creds into shared pool
198 if ((flags & kAuthorizationFlagExtendRights) &&
199 !(flags & kAuthorizationFlagDestroyRights)) {
200 mergeCredentials(resultCreds);
201 auth->mergeCredentials(resultCreds);
202 }
203 }
204
205 // Make sure that this isn't done until the auth(AuthorizationToken) is guaranteed to
206 // not be destroyed anymore since it's destructor asserts it has no processes
207 Server::connection().process.addAuthorization(auth.get());
208 auth.release();
209 return result;
210 }
211
212 void Session::authFree(const AuthorizationBlob &authBlob, AuthorizationFlags flags)
213 {
214 AuthorizationToken::Deleter deleter(authBlob);
215 AuthorizationToken &auth = deleter;
216
217 if (flags & kAuthorizationFlagDestroyRights) {
218 // explicitly invalidate all shared credentials and remove them from the session
219 for (CredentialSet::const_iterator it = auth.begin(); it != auth.end(); it++)
220 if ((*it)->isShared())
221 (*it)->invalidate();
222 }
223
224 // now get rid of the authorization itself
225 if (Server::connection().process.removeAuthorization(&auth))
226 deleter.remove();
227 }
228
229 OSStatus Session::authGetRights(const AuthorizationBlob &authBlob,
230 const RightSet &rights, const AuthorizationEnvironment *environment,
231 AuthorizationFlags flags,
232 MutableRightSet &grantedRights)
233 {
234 StLock<Mutex> _(mLock);
235 CredentialSet resultCreds;
236 AuthorizationToken &auth = authorization(authBlob);
237 CredentialSet effective = auth.effectiveCreds();
238 OSStatus result = Server::authority().authorize(rights, environment, flags,
239 &effective, &resultCreds, &grantedRights, auth);
240
241 // merge resulting creds into shared pool
242 if ((flags & kAuthorizationFlagExtendRights) && !(flags & kAuthorizationFlagDestroyRights)) {
243 mergeCredentials(resultCreds);
244 auth.mergeCredentials(resultCreds);
245 }
246
247 IFDEBUG(debug("SSauth", "Authorization %p copyRights asked for %d got %d",
248 &authorization(authBlob), int(rights.size()), int(grantedRights.size())));
249 return result;
250 }
251
252 OSStatus Session::authGetInfo(const AuthorizationBlob &authBlob,
253 const char *tag,
254 MutableRightSet &grantedRights)
255 {
256 StLock<Mutex> _(mLock);
257 AuthorizationToken &auth = authorization(authBlob);
258 debug("SSauth", "Authorization %p get-info not implemented", &auth);
259 if (tag) { // no such tag (no info support)
260 return errAuthorizationInvalidTag;
261 } else { // return no tags (no info support)
262 grantedRights = RightSet(); // return no entries
263 return noErr;
264 }
265 }
266
267 OSStatus Session::authExternalize(const AuthorizationBlob &authBlob,
268 AuthorizationExternalForm &extForm)
269 {
270 StLock<Mutex> _(mLock);
271 const AuthorizationToken &auth = authorization(authBlob);
272 if (auth.mayExternalize(Server::connection().process)) {
273 memset(&extForm, 0, sizeof(extForm));
274 AuthorizationExternalBlob &extBlob =
275 reinterpret_cast<AuthorizationExternalBlob &>(extForm);
276 extBlob.blob = auth.handle();
277 extBlob.session = bootstrapPort();
278 debug("SSauth", "Authorization %p externalized", &auth);
279 return noErr;
280 } else
281 return errAuthorizationExternalizeNotAllowed;
282 }
283
284 OSStatus Session::authInternalize(const AuthorizationExternalForm &extForm,
285 AuthorizationBlob &authBlob)
286 {
287 StLock<Mutex> _(mLock);
288
289 // interpret the external form
290 const AuthorizationExternalBlob &extBlob =
291 reinterpret_cast<const AuthorizationExternalBlob &>(extForm);
292
293 // locate source authorization
294 AuthorizationToken &sourceAuth = AuthorizationToken::find(extBlob.blob);
295
296 // check for permission and do it
297 if (sourceAuth.mayInternalize(Server::connection().process, true)) {
298 authBlob = extBlob.blob;
299 Server::connection().process.addAuthorization(&sourceAuth);
300 mAuthCount++;
301 debug("SSauth", "Authorization %p internalized", &sourceAuth);
302 return noErr;
303 } else
304 return errAuthorizationInternalizeNotAllowed;
305 }
306
307
308 //
309 // Set up a (new-ish) Session.
310 // This call must be made from a process within the session, and it must be the first
311 // such process to make the call.
312 //
313 void Session::setup(SessionCreationFlags flags, SessionAttributeBits attrs)
314 {
315 // check current process object - it may have been cached before the client's bootstrap switch
316 Process *process = &Server::connection().process;
317 if (process->taskPort().bootstrap() != process->session.bootstrapPort())
318 process = Server::active().resetConnection();
319 process->session.setupAttributes(attrs);
320 }
321
322
323 void Session::setupAttributes(SessionAttributeBits attrs)
324 {
325 debug("SSsession", "%p setup attrs=0x%lx", this, attrs);
326 if (attrs & ~settableAttributes)
327 MacOSError::throwMe(errSessionInvalidAttributes);
328 if (attribute(sessionWasInitialized))
329 MacOSError::throwMe(errSessionAuthorizationDenied);
330 setAttributes(attrs | sessionWasInitialized);
331 }
332
333
334 //
335 // Merge a set of credentials into the shared-session credential pool
336 //
337 void Session::mergeCredentials(CredentialSet &creds)
338 {
339 for (CredentialSet::const_iterator it = creds.begin(); it != creds.end(); it++)
340 if (((*it)->isShared() && (*it)->isValid())) {
341 CredentialSet::iterator old = mSessionCreds.find(*it);
342 if (old == mSessionCreds.end()) {
343 mSessionCreds.insert(*it);
344 } else {
345 // replace "new" with "old" in input set to retain synchronization
346 (*old)->merge(**it);
347 creds.erase(it);
348 creds.insert(*old);
349 }
350 }
351 }
352
353
354 //
355 // Locate an AuthorizationToken given a blob
356 //
357 AuthorizationToken &Session::authorization(const AuthorizationBlob &blob)
358 {
359 return AuthorizationToken::find(blob);
360 }