2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
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
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.
20 // session - authentication session domains
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.)
26 // Sessions are multi-threaded objects.
29 #include "connection.h"
34 // The static session map
36 Session::SessionMap
Session::sessionMap
;
37 Mutex
Session::sessionMapLock
;
41 // Create a Session object from initial parameters (create)
43 Session::Session(Bootstrap bootstrap
, Port servicePort
, SessionAttributeBits attrs
)
44 : mBootstrap(bootstrap
), mServicePort(servicePort
),
45 mAttributes(attrs
), mProcessCount(0), mAuthCount(0), mDying(false)
47 secdebug("SSsession", "%p CREATED: handle=0x%lx bootstrap=%d service=%d attrs=0x%lx",
48 this, handle(), mBootstrap
.port(), mServicePort
.port(), mAttributes
);
52 void Session::release()
59 // The root session inherits the startup bootstrap and service port
61 RootSession::RootSession(Port servicePort
, SessionAttributeBits attrs
)
62 : Session(Bootstrap(), servicePort
, sessionIsRoot
| sessionWasInitialized
| attrs
)
64 // self-install (no thread safety issues here)
65 sessionMap
[mServicePort
] = this;
70 // Dynamic sessions use the given bootstrap and re-register in it
72 DynamicSession::DynamicSession(const Bootstrap
&bootstrap
)
73 : ReceivePort(Server::active().bootstrapName(), bootstrap
),
74 Session(bootstrap
, *this)
76 // tell the server to listen to our port
77 Server::active().add(*this);
79 // register for port notifications
80 Server::active().notifyIfDead(bootstrapPort()); //@@@??? still needed?
81 Server::active().notifyIfUnused(*this);
84 StLock
<Mutex
> _(sessionMapLock
);
85 sessionMap
[*this] = this;
88 DynamicSession::~DynamicSession()
90 // remove our service port from the server
91 Server::active().remove(*this);
93 // if this is a (the) graphic login session, lock all databases
94 secdebug("session", "%p Locking all %ld databases",
95 this, databases().size());
96 Database::lockAllDatabases(databases());
100 void DynamicSession::release()
102 mBootstrap
.destroy();
111 assert(mProcessCount
== 0); // can't die with processes still alive
112 secdebug("SSsession", "%p DESTROYED: handle=0x%lx bootstrap=%d",
113 this, handle(), mBootstrap
.port());
118 // Locate a session object by service port or (Session API) identifier
120 Session
&Session::find(Port servicePort
)
122 StLock
<Mutex
> _(sessionMapLock
);
123 SessionMap::const_iterator it
= sessionMap
.find(servicePort
);
124 assert(it
!= sessionMap
.end());
128 Session
&Session::find(SecuritySessionId id
)
131 case callerSecuritySession
:
132 return Server::connection().process
.session
;
134 return findHandle
<Session
>(id
);
140 // Act on a death notification for a session's (sub)bootstrap port.
141 // We may not destroy the Session outright here (due to processes that use it),
142 // but we do clear out its accumulated wealth.
144 void Session::eliminate(Port servPort
)
146 // remove session from session map
147 StLock
<Mutex
> _(sessionMapLock
);
148 SessionMap::iterator it
= sessionMap
.find(servPort
);
149 assert(it
!= sessionMap
.end());
150 Session
*session
= it
->second
;
151 sessionMap
.erase(it
);
153 // destroy the session service port (this releases mach_init to proceed)
157 if (session
->clearResources())
160 secdebug("SSsession", "session %p zombified for %d processes and %d auths",
161 session
, int(session
->mProcessCount
), int(session
->mAuthCount
));
164 bool Session::clearResources()
166 StLock
<Mutex
> _(mLock
);
168 // this session is now officially dying
171 // invalidate shared credentials
173 StLock
<Mutex
> _(mCredsLock
);
175 IFDEBUG(if (!mSessionCreds
.empty())
176 secdebug("SSauth", "session %p clearing %d shared credentials",
177 this, int(mSessionCreds
.size())));
178 for (CredentialSet::iterator it
= mSessionCreds
.begin(); it
!= mSessionCreds
.end(); it
++)
181 // let the caller know if we are ready to die NOW
182 return mProcessCount
== 0 && mAuthCount
== 0;
187 // Relay lockAllDatabases to all known sessions
189 void Session::lockAllDatabases(bool forSleep
)
191 StLock
<Mutex
> _(sessionMapLock
);
192 for (SessionMap::const_iterator it
= begin(); it
!= end(); it
++) {
193 secdebug("SSdb", "locking all %d known databases %s in session %p",
194 int(it
->second
->databases().size()), forSleep
? " for sleep" : "", it
->second
);
195 Database::lockAllDatabases(it
->second
->databases(), forSleep
);
201 // Process management
203 void Session::addProcess(Process
*)
205 StLock
<Mutex
> _(mLock
);
209 bool Session::removeProcess(Process
*)
211 StLock
<Mutex
> _(mLock
);
212 assert(mProcessCount
> 0);
213 return --mProcessCount
== 0 && mDying
&& mAuthCount
== 0;
218 // Authorization retention management.
220 void Session::addAuthorization(AuthorizationToken
*)
222 StLock
<Mutex
> _(mLock
);
226 bool Session::removeAuthorization(AuthorizationToken
*)
228 StLock
<Mutex
> _(mLock
);
229 assert(mAuthCount
> 0);
230 return --mAuthCount
== 0 && mDying
&& mProcessCount
== 0;
235 // Authorization operations
237 OSStatus
Session::authCreate(const AuthItemSet
&rights
,
238 const AuthItemSet
&environment
,
239 AuthorizationFlags flags
,
240 AuthorizationBlob
&newHandle
,
241 const security_token_t
&securityToken
)
243 // invoke the authorization computation engine
244 CredentialSet resultCreds
;
246 // this will acquire mLock, so we delay acquiring it
247 auto_ptr
<AuthorizationToken
> auth(new AuthorizationToken(*this, resultCreds
, securityToken
));
249 // Make a copy of the mSessionCreds
250 CredentialSet sessionCreds
;
252 StLock
<Mutex
> _(mCredsLock
);
253 sessionCreds
= mSessionCreds
;
256 AuthItemSet outRights
;
257 OSStatus result
= Server::authority().authorize(rights
, environment
, flags
,
258 &sessionCreds
, &resultCreds
, outRights
, *auth
);
259 newHandle
= auth
->handle();
261 // merge resulting creds into shared pool
262 if ((flags
& kAuthorizationFlagExtendRights
) &&
263 !(flags
& kAuthorizationFlagDestroyRights
))
265 StLock
<Mutex
> _(mCredsLock
);
266 mergeCredentials(resultCreds
);
267 auth
->mergeCredentials(resultCreds
);
270 // Make sure that this isn't done until the auth(AuthorizationToken) is guaranteed to
271 // not be destroyed anymore since it's destructor asserts it has no processes
272 Server::connection().process
.addAuthorization(auth
.get());
277 void Session::authFree(const AuthorizationBlob
&authBlob
, AuthorizationFlags flags
)
279 AuthorizationToken::Deleter
deleter(authBlob
);
280 AuthorizationToken
&auth
= deleter
;
281 Process
&process
= Server::connection().process
;
282 process
.checkAuthorization(&auth
);
284 if (flags
& kAuthorizationFlagDestroyRights
) {
285 // explicitly invalidate all shared credentials and remove them from the session
286 for (CredentialSet::const_iterator it
= auth
.begin(); it
!= auth
.end(); it
++)
287 if ((*it
)->isShared())
291 // now get rid of the authorization itself
292 if (process
.removeAuthorization(&auth
))
296 OSStatus
Session::authGetRights(const AuthorizationBlob
&authBlob
,
297 const AuthItemSet
&rights
, const AuthItemSet
&environment
,
298 AuthorizationFlags flags
,
299 AuthItemSet
&grantedRights
)
301 CredentialSet resultCreds
;
302 AuthorizationToken
&auth
= authorization(authBlob
);
303 CredentialSet effective
;
305 StLock
<Mutex
> _(mCredsLock
);
306 effective
= auth
.effectiveCreds();
308 OSStatus result
= Server::authority().authorize(rights
, environment
, flags
,
309 &effective
, &resultCreds
, grantedRights
, auth
);
311 // merge resulting creds into shared pool
312 if ((flags
& kAuthorizationFlagExtendRights
) && !(flags
& kAuthorizationFlagDestroyRights
))
314 StLock
<Mutex
> _(mCredsLock
);
315 mergeCredentials(resultCreds
);
316 auth
.mergeCredentials(resultCreds
);
319 secdebug("SSauth", "Authorization %p copyRights asked for %d got %d",
320 &authorization(authBlob
), int(rights
.size()), int(grantedRights
.size()));
324 OSStatus
Session::authGetInfo(const AuthorizationBlob
&authBlob
,
326 AuthItemSet
&contextInfo
)
328 AuthorizationToken
&auth
= authorization(authBlob
);
329 secdebug("SSauth", "Authorization %p get-info", &auth
);
330 contextInfo
= auth
.infoSet(tag
);
334 OSStatus
Session::authExternalize(const AuthorizationBlob
&authBlob
,
335 AuthorizationExternalForm
&extForm
)
337 const AuthorizationToken
&auth
= authorization(authBlob
);
338 StLock
<Mutex
> _(mLock
);
339 if (auth
.mayExternalize(Server::connection().process
)) {
340 memset(&extForm
, 0, sizeof(extForm
));
341 AuthorizationExternalBlob
&extBlob
=
342 reinterpret_cast<AuthorizationExternalBlob
&>(extForm
);
343 extBlob
.blob
= auth
.handle();
344 extBlob
.session
= bootstrapPort();
345 secdebug("SSauth", "Authorization %p externalized", &auth
);
348 return errAuthorizationExternalizeNotAllowed
;
351 OSStatus
Session::authInternalize(const AuthorizationExternalForm
&extForm
,
352 AuthorizationBlob
&authBlob
)
354 // interpret the external form
355 const AuthorizationExternalBlob
&extBlob
=
356 reinterpret_cast<const AuthorizationExternalBlob
&>(extForm
);
358 // locate source authorization
359 AuthorizationToken
&sourceAuth
= AuthorizationToken::find(extBlob
.blob
);
361 // check for permission and do it
362 if (sourceAuth
.mayInternalize(Server::connection().process
, true)) {
363 StLock
<Mutex
> _(mLock
);
364 authBlob
= extBlob
.blob
;
365 Server::connection().process
.addAuthorization(&sourceAuth
);
367 secdebug("SSauth", "Authorization %p internalized", &sourceAuth
);
370 return errAuthorizationInternalizeNotAllowed
;
375 // Set up a (new-ish) Session.
376 // This call must be made from a process within the session, and it must be the first
377 // such process to make the call.
379 void Session::setup(SessionCreationFlags flags
, SessionAttributeBits attrs
)
381 // check current process object - it may have been cached before the client's bootstrap switch
382 Process
*process
= &Server::connection().process
;
383 process
->session
.setupAttributes(attrs
);
387 void Session::setupAttributes(SessionAttributeBits attrs
)
389 secdebug("SSsession", "%p setup attrs=0x%lx", this, attrs
);
390 if (attrs
& ~settableAttributes
)
391 MacOSError::throwMe(errSessionInvalidAttributes
);
392 if (attribute(sessionWasInitialized
))
393 MacOSError::throwMe(errSessionAuthorizationDenied
);
394 setAttributes(attrs
| sessionWasInitialized
);
398 OSStatus
Session::authorizationdbGet(AuthorizationString inRightName
, CFDictionaryRef
*rightDict
)
400 string
rightName(inRightName
);
401 return Server::authority().getRule(rightName
, rightDict
);
405 OSStatus
Session::authorizationdbSet(const AuthorizationBlob
&authBlob
, AuthorizationString inRightName
, CFDictionaryRef rightDict
)
407 CredentialSet resultCreds
;
408 AuthorizationToken
&auth
= authorization(authBlob
);
409 CredentialSet effective
;
412 StLock
<Mutex
> _(mCredsLock
);
413 effective
= auth
.effectiveCreds();
416 OSStatus result
= Server::authority().setRule(inRightName
, rightDict
, &effective
, &resultCreds
, auth
);
419 StLock
<Mutex
> _(mCredsLock
);
420 mergeCredentials(resultCreds
);
421 auth
.mergeCredentials(resultCreds
);
424 secdebug("SSauth", "Authorization %p authorizationdbSet %s (result=%ld)",
425 &authorization(authBlob
), inRightName
, result
);
430 OSStatus
Session::authorizationdbRemove(const AuthorizationBlob
&authBlob
, AuthorizationString inRightName
)
432 CredentialSet resultCreds
;
433 AuthorizationToken
&auth
= authorization(authBlob
);
434 CredentialSet effective
;
437 StLock
<Mutex
> _(mCredsLock
);
438 effective
= auth
.effectiveCreds();
441 OSStatus result
= Server::authority().removeRule(inRightName
, &effective
, &resultCreds
, auth
);
444 StLock
<Mutex
> _(mCredsLock
);
445 mergeCredentials(resultCreds
);
446 auth
.mergeCredentials(resultCreds
);
449 secdebug("SSauth", "Authorization %p authorizationdbRemove %s (result=%ld)",
450 &authorization(authBlob
), inRightName
, result
);
456 // Merge a set of credentials into the shared-session credential pool
458 // must hold mCredsLock
459 void Session::mergeCredentials(CredentialSet
&creds
)
461 secdebug("SSsession", "%p merge creds @%p", this, &creds
);
462 for (CredentialSet::const_iterator it
= creds
.begin(); it
!= creds
.end(); it
++)
463 if (((*it
)->isShared() && (*it
)->isValid())) {
464 CredentialSet::iterator old
= mSessionCreds
.find(*it
);
465 if (old
== mSessionCreds
.end()) {
466 mSessionCreds
.insert(*it
);
468 // replace "new" with "old" in input set to retain synchronization
478 // Locate an AuthorizationToken given a blob
480 AuthorizationToken
&Session::authorization(const AuthorizationBlob
&blob
)
482 AuthorizationToken
&auth
= AuthorizationToken::find(blob
);
483 Server::connection().process
.checkAuthorization(&auth
);