]> git.saurik.com Git - apple/securityd.git/blob - src/session.cpp
securityd-16.tar.gz
[apple/securityd.git] / src / session.cpp
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25
26
27 //
28 // session - authentication session domains
29 //
30 // A Session is defined by a mach_init bootstrap dictionary. These dictionaries are
31 // hierarchical and inherited, so they work well for characterization of processes
32 // that "belong" together. (Of course, if your mach_init is broken, you're in bad shape.)
33 //
34 // Sessions are multi-threaded objects.
35 //
36 #include "session.h"
37 #include "connection.h"
38 #include "database.h"
39 #include "server.h"
40
41
42 //
43 // The static session map
44 //
45 PortMap<Session> Session::mSessions;
46
47
48 //
49 // Create a Session object from initial parameters (create)
50 //
51 Session::Session(Bootstrap bootstrap, Port servicePort, SessionAttributeBits attrs)
52 : mBootstrap(bootstrap), mServicePort(servicePort),
53 mAttributes(attrs), mDying(false)
54 {
55 secdebug("SSsession", "%p CREATED: handle=0x%lx bootstrap=%d service=%d attrs=0x%lx",
56 this, handle(), mBootstrap.port(), mServicePort.port(), mAttributes);
57 }
58
59
60 void Session::release()
61 {
62 // nothing by default
63 }
64
65
66 //
67 // The root session inherits the startup bootstrap and service port
68 //
69 RootSession::RootSession(Port servicePort, SessionAttributeBits attrs)
70 : Session(Bootstrap(), servicePort, sessionIsRoot | sessionWasInitialized | attrs)
71 {
72 ref(); // eternalize
73
74 // self-install (no thread safety issues here)
75 mSessions[mServicePort] = this;
76 }
77
78
79 //
80 // Dynamic sessions use the given bootstrap and re-register in it
81 //
82 DynamicSession::DynamicSession(const Bootstrap &bootstrap)
83 : ReceivePort(Server::active().bootstrapName(), bootstrap),
84 Session(bootstrap, *this)
85 {
86 // tell the server to listen to our port
87 Server::active().add(*this);
88
89 // register for port notifications
90 Server::active().notifyIfDead(bootstrapPort()); //@@@??? still needed?
91 Server::active().notifyIfUnused(*this);
92
93 // self-register
94 StLock<Mutex> _(mSessions);
95 assert(!mSessions[*this]); // can't be registered already (we just made it)
96 mSessions[*this] = this;
97 }
98
99 DynamicSession::~DynamicSession()
100 {
101 // remove our service port from the server
102 Server::active().remove(*this);
103 }
104
105
106 void DynamicSession::release()
107 {
108 mBootstrap.destroy();
109 }
110
111
112 //
113 // Destroy a Session
114 //
115 Session::~Session()
116 {
117 secdebug("SSsession", "%p DESTROYED: handle=0x%lx bootstrap=%d",
118 this, handle(), mBootstrap.port());
119 }
120
121
122 //
123 // Locate a session object by service port or (Session API) identifier
124 //
125 Session &Session::find(Port servicePort)
126 {
127 StLock<Mutex> _(mSessions);
128 PortMap<Session>::const_iterator it = mSessions.find(servicePort);
129 assert(it != mSessions.end());
130 return *it->second;
131 }
132
133 Session &Session::find(SecuritySessionId id)
134 {
135 switch (id) {
136 case callerSecuritySession:
137 return Server::session();
138 default:
139 return HandleObject::find<Session>(id, CSSMERR_CSSM_INVALID_ADDIN_HANDLE);
140 }
141 }
142
143
144 //
145 // Act on a death notification for a session's (sub)bootstrap port.
146 // We may not destroy the Session outright here (due to processes that use it),
147 // but we do clear out its accumulated wealth.
148 //
149 void Session::destroy(Port servPort)
150 {
151 // remove session from session map
152 StLock<Mutex> _(mSessions);
153 PortMap<Session>::iterator it = mSessions.find(servPort);
154 assert(it != mSessions.end());
155 Session *session = it->second;
156 session->kill();
157 mSessions.erase(it);
158 }
159
160 void Session::kill()
161 {
162 release();
163
164 StLock<Mutex> _(mLock);
165
166 // this session is now officially dying
167 mDying = true;
168
169 // invalidate shared credentials
170 {
171 StLock<Mutex> _(mCredsLock);
172
173 IFDEBUG(if (!mSessionCreds.empty())
174 secdebug("SSauth", "session %p clearing %d shared credentials",
175 this, int(mSessionCreds.size())));
176 for (CredentialSet::iterator it = mSessionCreds.begin(); it != mSessionCreds.end(); it++)
177 (*it)->invalidate();
178 }
179
180 // base kill processing
181 PerSession::kill();
182 }
183
184
185 //
186 // Relay lockAllDatabases to all known sessions
187 //
188 void Session::processSystemSleep()
189 {
190 StLock<Mutex> _(mSessions);
191 for (PortMap<Session>::const_iterator it = mSessions.begin(); it != mSessions.end(); it++)
192 it->second->allReferences<DbCommon>(&DbCommon::sleepProcessing);
193 }
194
195
196 //
197 // Authorization operations
198 //
199 OSStatus Session::authCreate(const AuthItemSet &rights,
200 const AuthItemSet &environment,
201 AuthorizationFlags flags,
202 AuthorizationBlob &newHandle,
203 const security_token_t &securityToken)
204 {
205 // invoke the authorization computation engine
206 CredentialSet resultCreds;
207
208 // this will acquire mLock, so we delay acquiring it
209 auto_ptr<AuthorizationToken> auth(new AuthorizationToken(*this, resultCreds, securityToken));
210
211 // Make a copy of the mSessionCreds
212 CredentialSet sessionCreds;
213 {
214 StLock<Mutex> _(mCredsLock);
215 sessionCreds = mSessionCreds;
216 }
217
218 AuthItemSet outRights;
219 OSStatus result = Server::authority().authorize(rights, environment, flags,
220 &sessionCreds, &resultCreds, outRights, *auth);
221 newHandle = auth->handle();
222
223 // merge resulting creds into shared pool
224 if ((flags & kAuthorizationFlagExtendRights) &&
225 !(flags & kAuthorizationFlagDestroyRights))
226 {
227 StLock<Mutex> _(mCredsLock);
228 mergeCredentials(resultCreds);
229 auth->mergeCredentials(resultCreds);
230 }
231
232 // Make sure that this isn't done until the auth(AuthorizationToken) is guaranteed to
233 // not be destroyed anymore since it's destructor asserts it has no processes
234 Server::process().addAuthorization(auth.get());
235 auth.release();
236 return result;
237 }
238
239 void Session::authFree(const AuthorizationBlob &authBlob, AuthorizationFlags flags)
240 {
241 AuthorizationToken::Deleter deleter(authBlob);
242 AuthorizationToken &auth = deleter;
243 Process &process = Server::process();
244 process.checkAuthorization(&auth);
245
246 if (flags & kAuthorizationFlagDestroyRights) {
247 // explicitly invalidate all shared credentials and remove them from the session
248 for (CredentialSet::const_iterator it = auth.begin(); it != auth.end(); it++)
249 if ((*it)->isShared())
250 (*it)->invalidate();
251 }
252
253 // now get rid of the authorization itself
254 if (process.removeAuthorization(&auth))
255 deleter.remove();
256 }
257
258 OSStatus Session::authGetRights(const AuthorizationBlob &authBlob,
259 const AuthItemSet &rights, const AuthItemSet &environment,
260 AuthorizationFlags flags,
261 AuthItemSet &grantedRights)
262 {
263 CredentialSet resultCreds;
264 AuthorizationToken &auth = authorization(authBlob);
265 CredentialSet effective;
266 {
267 StLock<Mutex> _(mCredsLock);
268 effective = auth.effectiveCreds();
269 }
270 OSStatus result = Server::authority().authorize(rights, environment, flags,
271 &effective, &resultCreds, grantedRights, auth);
272
273 // merge resulting creds into shared pool
274 if ((flags & kAuthorizationFlagExtendRights) && !(flags & kAuthorizationFlagDestroyRights))
275 {
276 StLock<Mutex> _(mCredsLock);
277 mergeCredentials(resultCreds);
278 auth.mergeCredentials(resultCreds);
279 }
280
281 secdebug("SSauth", "Authorization %p copyRights asked for %d got %d",
282 &authorization(authBlob), int(rights.size()), int(grantedRights.size()));
283 return result;
284 }
285
286 OSStatus Session::authGetInfo(const AuthorizationBlob &authBlob,
287 const char *tag,
288 AuthItemSet &contextInfo)
289 {
290 AuthorizationToken &auth = authorization(authBlob);
291 secdebug("SSauth", "Authorization %p get-info", &auth);
292 contextInfo = auth.infoSet(tag);
293 return noErr;
294 }
295
296 OSStatus Session::authExternalize(const AuthorizationBlob &authBlob,
297 AuthorizationExternalForm &extForm)
298 {
299 const AuthorizationToken &auth = authorization(authBlob);
300 StLock<Mutex> _(mLock);
301 if (auth.mayExternalize(Server::process())) {
302 memset(&extForm, 0, sizeof(extForm));
303 AuthorizationExternalBlob &extBlob =
304 reinterpret_cast<AuthorizationExternalBlob &>(extForm);
305 extBlob.blob = auth.handle();
306 extBlob.session = bootstrapPort();
307 secdebug("SSauth", "Authorization %p externalized", &auth);
308 return noErr;
309 } else
310 return errAuthorizationExternalizeNotAllowed;
311 }
312
313 OSStatus Session::authInternalize(const AuthorizationExternalForm &extForm,
314 AuthorizationBlob &authBlob)
315 {
316 // interpret the external form
317 const AuthorizationExternalBlob &extBlob =
318 reinterpret_cast<const AuthorizationExternalBlob &>(extForm);
319
320 // locate source authorization
321 AuthorizationToken &sourceAuth = AuthorizationToken::find(extBlob.blob);
322
323 // check for permission and do it
324 if (sourceAuth.mayInternalize(Server::process(), true)) {
325 StLock<Mutex> _(mLock);
326 authBlob = extBlob.blob;
327 Server::process().addAuthorization(&sourceAuth);
328 secdebug("SSauth", "Authorization %p internalized", &sourceAuth);
329 return noErr;
330 } else
331 return errAuthorizationInternalizeNotAllowed;
332 }
333
334
335 //
336 // Set up a (new-ish) Session.
337 // This call must be made from a process within the session, and it must be the first
338 // such process to make the call.
339 //
340 void Session::setup(SessionCreationFlags flags, SessionAttributeBits attrs)
341 {
342 // check current process object - it may have been cached before the client's bootstrap switch
343 Process *process = &Server::process();
344 process->session().setupAttributes(attrs);
345 }
346
347
348 void Session::setupAttributes(SessionAttributeBits attrs)
349 {
350 secdebug("SSsession", "%p setup attrs=0x%lx", this, attrs);
351 if (attrs & ~settableAttributes)
352 MacOSError::throwMe(errSessionInvalidAttributes);
353 if (attribute(sessionWasInitialized))
354 MacOSError::throwMe(errSessionAuthorizationDenied);
355 setAttributes(attrs | sessionWasInitialized);
356 }
357
358
359 OSStatus Session::authorizationdbGet(AuthorizationString inRightName, CFDictionaryRef *rightDict)
360 {
361 string rightName(inRightName);
362 return Server::authority().getRule(rightName, rightDict);
363 }
364
365
366 OSStatus Session::authorizationdbSet(const AuthorizationBlob &authBlob, AuthorizationString inRightName, CFDictionaryRef rightDict)
367 {
368 CredentialSet resultCreds;
369 AuthorizationToken &auth = authorization(authBlob);
370 CredentialSet effective;
371
372 {
373 StLock<Mutex> _(mCredsLock);
374 effective = auth.effectiveCreds();
375 }
376
377 OSStatus result = Server::authority().setRule(inRightName, rightDict, &effective, &resultCreds, auth);
378
379 {
380 StLock<Mutex> _(mCredsLock);
381 mergeCredentials(resultCreds);
382 auth.mergeCredentials(resultCreds);
383 }
384
385 secdebug("SSauth", "Authorization %p authorizationdbSet %s (result=%ld)",
386 &authorization(authBlob), inRightName, result);
387 return result;
388 }
389
390
391 OSStatus Session::authorizationdbRemove(const AuthorizationBlob &authBlob, AuthorizationString inRightName)
392 {
393 CredentialSet resultCreds;
394 AuthorizationToken &auth = authorization(authBlob);
395 CredentialSet effective;
396
397 {
398 StLock<Mutex> _(mCredsLock);
399 effective = auth.effectiveCreds();
400 }
401
402 OSStatus result = Server::authority().removeRule(inRightName, &effective, &resultCreds, auth);
403
404 {
405 StLock<Mutex> _(mCredsLock);
406 mergeCredentials(resultCreds);
407 auth.mergeCredentials(resultCreds);
408 }
409
410 secdebug("SSauth", "Authorization %p authorizationdbRemove %s (result=%ld)",
411 &authorization(authBlob), inRightName, result);
412 return result;
413 }
414
415
416 //
417 // Merge a set of credentials into the shared-session credential pool
418 //
419 // must hold mCredsLock
420 void Session::mergeCredentials(CredentialSet &creds)
421 {
422 secdebug("SSsession", "%p merge creds @%p", this, &creds);
423 for (CredentialSet::const_iterator it = creds.begin(); it != creds.end(); it++)
424 if (((*it)->isShared() && (*it)->isValid())) {
425 CredentialSet::iterator old = mSessionCreds.find(*it);
426 if (old == mSessionCreds.end()) {
427 mSessionCreds.insert(*it);
428 } else {
429 // replace "new" with "old" in input set to retain synchronization
430 (*old)->merge(**it);
431 creds.erase(it);
432 creds.insert(*old);
433 }
434 }
435 }
436
437
438 //
439 // Locate an AuthorizationToken given a blob
440 //
441 AuthorizationToken &Session::authorization(const AuthorizationBlob &blob)
442 {
443 AuthorizationToken &auth = AuthorizationToken::find(blob);
444 Server::process().checkAuthorization(&auth);
445 return auth;
446 }
447
448
449 //
450 // Debug dumping
451 //
452 #if defined(DEBUGDUMP)
453
454 void Session::dumpNode()
455 {
456 PerSession::dumpNode();
457 if (mDying)
458 Debug::dump(" DYING");
459 Debug::dump(" boot=%d service=%d attrs=0x%lx",
460 mBootstrap.port(), mServicePort.port(), mAttributes);
461 }
462
463 #endif //DEBUGDUMP