2 * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
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
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.
23 * @APPLE_LICENSE_HEADER_END@
28 // session - authentication session domains
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.)
34 // Sessions are multi-threaded objects.
37 #include "connection.h"
43 // The static session map
45 PortMap
<Session
> Session::mSessions
;
49 // Create a Session object from initial parameters (create)
51 Session::Session(Bootstrap bootstrap
, Port servicePort
, SessionAttributeBits attrs
)
52 : mBootstrap(bootstrap
), mServicePort(servicePort
),
53 mAttributes(attrs
), mDying(false)
55 secdebug("SSsession", "%p CREATED: handle=0x%lx bootstrap=%d service=%d attrs=0x%lx",
56 this, handle(), mBootstrap
.port(), mServicePort
.port(), mAttributes
);
60 void Session::release()
67 // The root session inherits the startup bootstrap and service port
69 RootSession::RootSession(Port servicePort
, SessionAttributeBits attrs
)
70 : Session(Bootstrap(), servicePort
, sessionIsRoot
| sessionWasInitialized
| attrs
)
74 // self-install (no thread safety issues here)
75 mSessions
[mServicePort
] = this;
80 // Dynamic sessions use the given bootstrap and re-register in it
82 DynamicSession::DynamicSession(const Bootstrap
&bootstrap
)
83 : ReceivePort(Server::active().bootstrapName(), bootstrap
),
84 Session(bootstrap
, *this)
86 // tell the server to listen to our port
87 Server::active().add(*this);
89 // register for port notifications
90 Server::active().notifyIfDead(bootstrapPort()); //@@@??? still needed?
91 Server::active().notifyIfUnused(*this);
94 StLock
<Mutex
> _(mSessions
);
95 assert(!mSessions
[*this]); // can't be registered already (we just made it)
96 mSessions
[*this] = this;
99 DynamicSession::~DynamicSession()
101 // remove our service port from the server
102 Server::active().remove(*this);
106 void DynamicSession::release()
108 mBootstrap
.destroy();
117 secdebug("SSsession", "%p DESTROYED: handle=0x%lx bootstrap=%d",
118 this, handle(), mBootstrap
.port());
123 // Locate a session object by service port or (Session API) identifier
125 Session
&Session::find(Port servicePort
)
127 StLock
<Mutex
> _(mSessions
);
128 PortMap
<Session
>::const_iterator it
= mSessions
.find(servicePort
);
129 assert(it
!= mSessions
.end());
133 Session
&Session::find(SecuritySessionId id
)
136 case callerSecuritySession
:
137 return Server::session();
139 return HandleObject::find
<Session
>(id
, CSSMERR_CSSM_INVALID_ADDIN_HANDLE
);
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.
149 void Session::destroy(Port servPort
)
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
;
164 StLock
<Mutex
> _(mLock
);
166 // this session is now officially dying
169 // invalidate shared credentials
171 StLock
<Mutex
> _(mCredsLock
);
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
++)
180 // base kill processing
186 // Relay lockAllDatabases to all known sessions
188 void Session::processSystemSleep()
190 StLock
<Mutex
> _(mSessions
);
191 for (PortMap
<Session
>::const_iterator it
= mSessions
.begin(); it
!= mSessions
.end(); it
++)
192 it
->second
->allReferences
<DbCommon
>(&DbCommon::sleepProcessing
);
197 // Authorization operations
199 OSStatus
Session::authCreate(const AuthItemSet
&rights
,
200 const AuthItemSet
&environment
,
201 AuthorizationFlags flags
,
202 AuthorizationBlob
&newHandle
,
203 const security_token_t
&securityToken
)
205 // invoke the authorization computation engine
206 CredentialSet resultCreds
;
208 // this will acquire mLock, so we delay acquiring it
209 auto_ptr
<AuthorizationToken
> auth(new AuthorizationToken(*this, resultCreds
, securityToken
));
211 // Make a copy of the mSessionCreds
212 CredentialSet sessionCreds
;
214 StLock
<Mutex
> _(mCredsLock
);
215 sessionCreds
= mSessionCreds
;
218 AuthItemSet outRights
;
219 OSStatus result
= Server::authority().authorize(rights
, environment
, flags
,
220 &sessionCreds
, &resultCreds
, outRights
, *auth
);
221 newHandle
= auth
->handle();
223 // merge resulting creds into shared pool
224 if ((flags
& kAuthorizationFlagExtendRights
) &&
225 !(flags
& kAuthorizationFlagDestroyRights
))
227 StLock
<Mutex
> _(mCredsLock
);
228 mergeCredentials(resultCreds
);
229 auth
->mergeCredentials(resultCreds
);
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());
239 void Session::authFree(const AuthorizationBlob
&authBlob
, AuthorizationFlags flags
)
241 AuthorizationToken::Deleter
deleter(authBlob
);
242 AuthorizationToken
&auth
= deleter
;
243 Process
&process
= Server::process();
244 process
.checkAuthorization(&auth
);
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())
253 // now get rid of the authorization itself
254 if (process
.removeAuthorization(&auth
))
258 OSStatus
Session::authGetRights(const AuthorizationBlob
&authBlob
,
259 const AuthItemSet
&rights
, const AuthItemSet
&environment
,
260 AuthorizationFlags flags
,
261 AuthItemSet
&grantedRights
)
263 CredentialSet resultCreds
;
264 AuthorizationToken
&auth
= authorization(authBlob
);
265 CredentialSet effective
;
267 StLock
<Mutex
> _(mCredsLock
);
268 effective
= auth
.effectiveCreds();
270 OSStatus result
= Server::authority().authorize(rights
, environment
, flags
,
271 &effective
, &resultCreds
, grantedRights
, auth
);
273 // merge resulting creds into shared pool
274 if ((flags
& kAuthorizationFlagExtendRights
) && !(flags
& kAuthorizationFlagDestroyRights
))
276 StLock
<Mutex
> _(mCredsLock
);
277 mergeCredentials(resultCreds
);
278 auth
.mergeCredentials(resultCreds
);
281 secdebug("SSauth", "Authorization %p copyRights asked for %d got %d",
282 &authorization(authBlob
), int(rights
.size()), int(grantedRights
.size()));
286 OSStatus
Session::authGetInfo(const AuthorizationBlob
&authBlob
,
288 AuthItemSet
&contextInfo
)
290 AuthorizationToken
&auth
= authorization(authBlob
);
291 secdebug("SSauth", "Authorization %p get-info", &auth
);
292 contextInfo
= auth
.infoSet(tag
);
296 OSStatus
Session::authExternalize(const AuthorizationBlob
&authBlob
,
297 AuthorizationExternalForm
&extForm
)
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
);
310 return errAuthorizationExternalizeNotAllowed
;
313 OSStatus
Session::authInternalize(const AuthorizationExternalForm
&extForm
,
314 AuthorizationBlob
&authBlob
)
316 // interpret the external form
317 const AuthorizationExternalBlob
&extBlob
=
318 reinterpret_cast<const AuthorizationExternalBlob
&>(extForm
);
320 // locate source authorization
321 AuthorizationToken
&sourceAuth
= AuthorizationToken::find(extBlob
.blob
);
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
);
331 return errAuthorizationInternalizeNotAllowed
;
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.
340 void Session::setup(SessionCreationFlags flags
, SessionAttributeBits attrs
)
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
);
348 void Session::setupAttributes(SessionAttributeBits attrs
)
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
);
359 OSStatus
Session::authorizationdbGet(AuthorizationString inRightName
, CFDictionaryRef
*rightDict
)
361 string
rightName(inRightName
);
362 return Server::authority().getRule(rightName
, rightDict
);
366 OSStatus
Session::authorizationdbSet(const AuthorizationBlob
&authBlob
, AuthorizationString inRightName
, CFDictionaryRef rightDict
)
368 CredentialSet resultCreds
;
369 AuthorizationToken
&auth
= authorization(authBlob
);
370 CredentialSet effective
;
373 StLock
<Mutex
> _(mCredsLock
);
374 effective
= auth
.effectiveCreds();
377 OSStatus result
= Server::authority().setRule(inRightName
, rightDict
, &effective
, &resultCreds
, auth
);
380 StLock
<Mutex
> _(mCredsLock
);
381 mergeCredentials(resultCreds
);
382 auth
.mergeCredentials(resultCreds
);
385 secdebug("SSauth", "Authorization %p authorizationdbSet %s (result=%ld)",
386 &authorization(authBlob
), inRightName
, result
);
391 OSStatus
Session::authorizationdbRemove(const AuthorizationBlob
&authBlob
, AuthorizationString inRightName
)
393 CredentialSet resultCreds
;
394 AuthorizationToken
&auth
= authorization(authBlob
);
395 CredentialSet effective
;
398 StLock
<Mutex
> _(mCredsLock
);
399 effective
= auth
.effectiveCreds();
402 OSStatus result
= Server::authority().removeRule(inRightName
, &effective
, &resultCreds
, auth
);
405 StLock
<Mutex
> _(mCredsLock
);
406 mergeCredentials(resultCreds
);
407 auth
.mergeCredentials(resultCreds
);
410 secdebug("SSauth", "Authorization %p authorizationdbRemove %s (result=%ld)",
411 &authorization(authBlob
), inRightName
, result
);
417 // Merge a set of credentials into the shared-session credential pool
419 // must hold mCredsLock
420 void Session::mergeCredentials(CredentialSet
&creds
)
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
);
429 // replace "new" with "old" in input set to retain synchronization
439 // Locate an AuthorizationToken given a blob
441 AuthorizationToken
&Session::authorization(const AuthorizationBlob
&blob
)
443 AuthorizationToken
&auth
= AuthorizationToken::find(blob
);
444 Server::process().checkAuthorization(&auth
);
452 #if defined(DEBUGDUMP)
454 void Session::dumpNode()
456 PerSession::dumpNode();
458 Debug::dump(" DYING");
459 Debug::dump(" boot=%d service=%d attrs=0x%lx",
460 mBootstrap
.port(), mServicePort
.port(), mAttributes
);