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 debug("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 if (attribute(sessionHasGraphicAccess
))
95 Database::lockAllDatabases();
99 void DynamicSession::release()
101 mBootstrap
.destroy();
110 assert(mProcessCount
== 0); // can't die with processes still alive
111 debug("SSsession", "%p DESTROYED: handle=0x%lx bootstrap=%d",
112 this, handle(), mBootstrap
.port());
117 // Locate a session object by service port or (Session API) identifier
119 Session
&Session::find(Port servicePort
)
121 StLock
<Mutex
> _(sessionMapLock
);
122 SessionMap::const_iterator it
= sessionMap
.find(servicePort
);
123 assert(it
!= sessionMap
.end());
127 Session
&Session::find(SecuritySessionId id
)
130 case callerSecuritySession
:
131 return Server::connection().process
.session
;
133 return findHandle
<Session
>(id
);
139 // Act on a death notification for a session's (sub)bootstrap port.
140 // We may not destroy the Session outright here (due to processes that use it),
141 // but we do clear out its accumulated wealth.
143 void Session::eliminate(Port servPort
)
145 // remove session from session map
146 StLock
<Mutex
> _(sessionMapLock
);
147 SessionMap::iterator it
= sessionMap
.find(servPort
);
148 assert(it
!= sessionMap
.end());
149 Session
*session
= it
->second
;
150 sessionMap
.erase(it
);
152 // destroy the session service port (this releases mach_init to proceed)
156 if (session
->clearResources())
159 debug("SSsession", "session %p zombified for %d processes and %d auths",
160 session
, int(session
->mProcessCount
), int(session
->mAuthCount
));
163 bool Session::clearResources()
165 StLock
<Mutex
> _(mLock
);
167 // this session is now officially dying
170 // invalidate shared credentials
172 StLock
<Mutex
> _(mCredsLock
);
174 IFDEBUG(if (!mSessionCreds
.empty())
175 debug("SSauth", "session %p clearing %d shared credentials",
176 this, int(mSessionCreds
.size())));
177 for (CredentialSet::iterator it
= mSessionCreds
.begin(); it
!= mSessionCreds
.end(); it
++)
180 // let the caller know if we are ready to die NOW
181 return mProcessCount
== 0 && mAuthCount
== 0;
186 // Process management
188 void Session::addProcess(Process
*)
190 StLock
<Mutex
> _(mLock
);
194 bool Session::removeProcess(Process
*)
196 StLock
<Mutex
> _(mLock
);
197 assert(mProcessCount
> 0);
198 return --mProcessCount
== 0 && mDying
&& mAuthCount
== 0;
203 // Authorization retention management.
205 void Session::addAuthorization(AuthorizationToken
*)
207 StLock
<Mutex
> _(mLock
);
211 bool Session::removeAuthorization(AuthorizationToken
*)
213 StLock
<Mutex
> _(mLock
);
214 assert(mAuthCount
> 0);
215 return --mAuthCount
== 0 && mDying
&& mProcessCount
== 0;
220 // Authorization operations
222 OSStatus
Session::authCreate(const RightSet
&rights
,
223 const AuthorizationEnvironment
*environment
,
224 AuthorizationFlags flags
,
225 AuthorizationBlob
&newHandle
)
227 // invoke the authorization computation engine
228 CredentialSet resultCreds
;
230 // this will acquire mLock, so we delay acquiring it
231 auto_ptr
<AuthorizationToken
> auth(new AuthorizationToken(*this, resultCreds
));
233 // Make a copy of the mSessionCreds
234 CredentialSet sessionCreds
;
236 StLock
<Mutex
> _(mCredsLock
);
237 sessionCreds
= mSessionCreds
;
240 OSStatus result
= Server::authority().authorize(rights
, environment
, flags
,
241 &sessionCreds
, &resultCreds
, NULL
, *auth
);
242 newHandle
= auth
->handle();
244 // merge resulting creds into shared pool
245 if ((flags
& kAuthorizationFlagExtendRights
) &&
246 !(flags
& kAuthorizationFlagDestroyRights
))
248 StLock
<Mutex
> _(mCredsLock
);
249 mergeCredentials(resultCreds
);
250 auth
->mergeCredentials(resultCreds
);
253 // Make sure that this isn't done until the auth(AuthorizationToken) is guaranteed to
254 // not be destroyed anymore since it's destructor asserts it has no processes
255 Server::connection().process
.addAuthorization(auth
.get());
260 void Session::authFree(const AuthorizationBlob
&authBlob
, AuthorizationFlags flags
)
262 AuthorizationToken::Deleter
deleter(authBlob
);
263 AuthorizationToken
&auth
= deleter
;
265 if (flags
& kAuthorizationFlagDestroyRights
) {
266 // explicitly invalidate all shared credentials and remove them from the session
267 for (CredentialSet::const_iterator it
= auth
.begin(); it
!= auth
.end(); it
++)
268 if ((*it
)->isShared())
272 // now get rid of the authorization itself
273 if (Server::connection().process
.removeAuthorization(&auth
))
277 OSStatus
Session::authGetRights(const AuthorizationBlob
&authBlob
,
278 const RightSet
&rights
, const AuthorizationEnvironment
*environment
,
279 AuthorizationFlags flags
,
280 MutableRightSet
&grantedRights
)
282 CredentialSet resultCreds
;
283 AuthorizationToken
&auth
= authorization(authBlob
);
284 CredentialSet effective
;
286 StLock
<Mutex
> _(mCredsLock
);
287 effective
= auth
.effectiveCreds();
289 OSStatus result
= Server::authority().authorize(rights
, environment
, flags
,
290 &effective
, &resultCreds
, &grantedRights
, auth
);
292 // merge resulting creds into shared pool
293 if ((flags
& kAuthorizationFlagExtendRights
) && !(flags
& kAuthorizationFlagDestroyRights
))
295 StLock
<Mutex
> _(mCredsLock
);
296 mergeCredentials(resultCreds
);
297 auth
.mergeCredentials(resultCreds
);
300 IFDEBUG(debug("SSauth", "Authorization %p copyRights asked for %d got %d",
301 &authorization(authBlob
), int(rights
.size()), int(grantedRights
.size())));
305 OSStatus
Session::authGetInfo(const AuthorizationBlob
&authBlob
,
307 AuthorizationItemSet
*&contextInfo
)
309 StLock
<Mutex
> _(mLock
);
310 AuthorizationToken
&auth
= authorization(authBlob
);
311 debug("SSauth", "Authorization %p get-info", &auth
);
312 if (tag
) { // @@@ no tag support yet
313 return errAuthorizationInvalidTag
;
314 } else { // return all tags
315 contextInfo
= &auth
.infoSet();
320 OSStatus
Session::authExternalize(const AuthorizationBlob
&authBlob
,
321 AuthorizationExternalForm
&extForm
)
323 StLock
<Mutex
> _(mLock
);
324 const AuthorizationToken
&auth
= authorization(authBlob
);
325 if (auth
.mayExternalize(Server::connection().process
)) {
326 memset(&extForm
, 0, sizeof(extForm
));
327 AuthorizationExternalBlob
&extBlob
=
328 reinterpret_cast<AuthorizationExternalBlob
&>(extForm
);
329 extBlob
.blob
= auth
.handle();
330 extBlob
.session
= bootstrapPort();
331 debug("SSauth", "Authorization %p externalized", &auth
);
334 return errAuthorizationExternalizeNotAllowed
;
337 OSStatus
Session::authInternalize(const AuthorizationExternalForm
&extForm
,
338 AuthorizationBlob
&authBlob
)
340 StLock
<Mutex
> _(mLock
);
342 // interpret the external form
343 const AuthorizationExternalBlob
&extBlob
=
344 reinterpret_cast<const AuthorizationExternalBlob
&>(extForm
);
346 // locate source authorization
347 AuthorizationToken
&sourceAuth
= AuthorizationToken::find(extBlob
.blob
);
349 // check for permission and do it
350 if (sourceAuth
.mayInternalize(Server::connection().process
, true)) {
351 authBlob
= extBlob
.blob
;
352 Server::connection().process
.addAuthorization(&sourceAuth
);
354 debug("SSauth", "Authorization %p internalized", &sourceAuth
);
357 return errAuthorizationInternalizeNotAllowed
;
362 // Set up a (new-ish) Session.
363 // This call must be made from a process within the session, and it must be the first
364 // such process to make the call.
366 void Session::setup(SessionCreationFlags flags
, SessionAttributeBits attrs
)
368 // check current process object - it may have been cached before the client's bootstrap switch
369 Process
*process
= &Server::connection().process
;
371 if (process
->taskPort().bootstrap() != process
->session
.bootstrapPort())
372 process
= Server::active().resetConnection();
374 process
->session
.setupAttributes(attrs
);
378 void Session::setupAttributes(SessionAttributeBits attrs
)
380 debug("SSsession", "%p setup attrs=0x%lx", this, attrs
);
381 if (attrs
& ~settableAttributes
)
382 MacOSError::throwMe(errSessionInvalidAttributes
);
383 if (attribute(sessionWasInitialized
))
384 MacOSError::throwMe(errSessionAuthorizationDenied
);
385 setAttributes(attrs
| sessionWasInitialized
);
390 // Merge a set of credentials into the shared-session credential pool
392 // must hold mCredsLock
393 void Session::mergeCredentials(CredentialSet
&creds
)
395 debug("SSsession", "%p merge creds @%p", this, &creds
);
396 for (CredentialSet::const_iterator it
= creds
.begin(); it
!= creds
.end(); it
++)
397 if (((*it
)->isShared() && (*it
)->isValid())) {
398 CredentialSet::iterator old
= mSessionCreds
.find(*it
);
399 if (old
== mSessionCreds
.end()) {
400 mSessionCreds
.insert(*it
);
402 // replace "new" with "old" in input set to retain synchronization
412 // Locate an AuthorizationToken given a blob
414 AuthorizationToken
&Session::authorization(const AuthorizationBlob
&blob
)
416 return AuthorizationToken::find(blob
);