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
, SessionAttributeBits attrs
)
44 : mBootstrap(bootstrap
), mAttributes(attrs
), mProcessCount(0), mAuthCount(0), mDying(false)
46 debug("SSsession", "%p CREATED: handle=0x%lx bootstrap=%d attrs=0x%lx",
47 this, handle(), mBootstrap
.port(), mAttributes
);
50 RootSession::RootSession()
51 : Session(Bootstrap(), sessionIsRoot
| sessionWasInitialized
)
54 sessionMap
[mBootstrap
] = this;
57 DynamicSession::DynamicSession(Bootstrap bootstrap
) : Session(bootstrap
)
59 Server::active().notifyIfDead(bootstrapPort());
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());
76 // Retrieve or create a session object
78 Session
&Session::find(Bootstrap bootstrap
, bool makeNew
)
80 StLock
<Mutex
> _(sessionMapLock
);
81 Session
* &slot
= sessionMap
[bootstrap
];
84 slot
= new DynamicSession(bootstrap
);
86 Authorization::Error::throwMe(errAuthorizationInvalidRef
);
90 Session
&Session::find(SecuritySessionId id
)
93 case callerSecuritySession
:
94 return Server::connection().process
.session
;
96 return findHandle
<Session
>(id
);
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.
106 void Session::eliminate(Bootstrap bootstrap
)
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
);
116 if (session
->clearResources())
119 debug("SSsession", "session %p zombified for %d processes and %d auths",
120 session
, int(session
->mProcessCount
), int(session
->mAuthCount
));
123 bool Session::clearResources()
125 StLock
<Mutex
> _(mLock
);
127 // this session is now officially dying
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
++)
137 // let the caller know if we are ready to die NOW
138 return mProcessCount
== 0 && mAuthCount
== 0;
143 // Process management
145 void Session::addProcess(Process
*)
147 StLock
<Mutex
> _(mLock
);
151 bool Session::removeProcess(Process
*)
153 StLock
<Mutex
> _(mLock
);
154 assert(mProcessCount
> 0);
155 return --mProcessCount
== 0 && mDying
&& mAuthCount
== 0;
160 // Authorization retention management.
162 void Session::addAuthorization(AuthorizationToken
*)
164 StLock
<Mutex
> _(mLock
);
168 bool Session::removeAuthorization(AuthorizationToken
*)
170 StLock
<Mutex
> _(mLock
);
171 assert(mAuthCount
> 0);
172 return --mAuthCount
== 0 && mDying
&& mProcessCount
== 0;
177 // Authorization operations
179 OSStatus
Session::authCreate(const RightSet
&rights
,
180 const AuthorizationEnvironment
*environment
,
181 AuthorizationFlags flags
,
182 AuthorizationBlob
&newHandle
)
184 // invoke the authorization computation engine
185 CredentialSet resultCreds
;
187 // this will acquire mLock, so we delay acquiring it
188 auto_ptr
<AuthorizationToken
> auth(new AuthorizationToken(*this, resultCreds
));
190 OSStatus result
= Server::authority().authorize(rights
, environment
, flags
,
191 &mSessionCreds
, &resultCreds
, NULL
, *auth
);
192 newHandle
= auth
->handle();
195 StLock
<Mutex
> _(mLock
);
197 // merge resulting creds into shared pool
198 if ((flags
& kAuthorizationFlagExtendRights
) &&
199 !(flags
& kAuthorizationFlagDestroyRights
)) {
200 mergeCredentials(resultCreds
);
201 auth
->mergeCredentials(resultCreds
);
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());
212 void Session::authFree(const AuthorizationBlob
&authBlob
, AuthorizationFlags flags
)
214 AuthorizationToken::Deleter
deleter(authBlob
);
215 AuthorizationToken
&auth
= deleter
;
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())
224 // now get rid of the authorization itself
225 if (Server::connection().process
.removeAuthorization(&auth
))
229 OSStatus
Session::authGetRights(const AuthorizationBlob
&authBlob
,
230 const RightSet
&rights
, const AuthorizationEnvironment
*environment
,
231 AuthorizationFlags flags
,
232 MutableRightSet
&grantedRights
)
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
);
241 // merge resulting creds into shared pool
242 if ((flags
& kAuthorizationFlagExtendRights
) && !(flags
& kAuthorizationFlagDestroyRights
)) {
243 mergeCredentials(resultCreds
);
244 auth
.mergeCredentials(resultCreds
);
247 IFDEBUG(debug("SSauth", "Authorization %p copyRights asked for %d got %d",
248 &authorization(authBlob
), int(rights
.size()), int(grantedRights
.size())));
252 OSStatus
Session::authGetInfo(const AuthorizationBlob
&authBlob
,
254 MutableRightSet
&grantedRights
)
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
267 OSStatus
Session::authExternalize(const AuthorizationBlob
&authBlob
,
268 AuthorizationExternalForm
&extForm
)
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
);
281 return errAuthorizationExternalizeNotAllowed
;
284 OSStatus
Session::authInternalize(const AuthorizationExternalForm
&extForm
,
285 AuthorizationBlob
&authBlob
)
287 StLock
<Mutex
> _(mLock
);
289 // interpret the external form
290 const AuthorizationExternalBlob
&extBlob
=
291 reinterpret_cast<const AuthorizationExternalBlob
&>(extForm
);
293 // locate source authorization
294 AuthorizationToken
&sourceAuth
= AuthorizationToken::find(extBlob
.blob
);
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
);
301 debug("SSauth", "Authorization %p internalized", &sourceAuth
);
304 return errAuthorizationInternalizeNotAllowed
;
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.
313 void Session::setup(SessionCreationFlags flags
, SessionAttributeBits attrs
)
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
);
323 void Session::setupAttributes(SessionAttributeBits attrs
)
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
);
335 // Merge a set of credentials into the shared-session credential pool
337 void Session::mergeCredentials(CredentialSet
&creds
)
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
);
345 // replace "new" with "old" in input set to retain synchronization
355 // Locate an AuthorizationToken given a blob
357 AuthorizationToken
&Session::authorization(const AuthorizationBlob
&blob
)
359 return AuthorizationToken::find(blob
);