2 * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
26 // session - authentication session domains
28 // A Session is defined by a mach_init bootstrap dictionary. These dictionaries are
29 // hierarchical and inherited, so they work well for characterization of processes
30 // that "belong" together. (Of course, if your mach_init is broken, you're in bad shape.)
32 // Sessions are multi-threaded objects.
35 #include "connection.h"
41 // The static session map
43 PortMap
<Session
> Session::mSessions
;
47 // Create a Session object from initial parameters (create)
49 Session::Session(Bootstrap bootstrap
, Port servicePort
, SessionAttributeBits attrs
)
50 : mBootstrap(bootstrap
), mServicePort(servicePort
),
51 mAttributes(attrs
), mSecurityAgent(NULL
), mAuthHost(NULL
)
53 secdebug("SSsession", "%p CREATED: handle=0x%lx bootstrap=%d service=%d attrs=0x%lx",
54 this, handle(), mBootstrap
.port(), mServicePort
.port(), mAttributes
);
63 secdebug("SSsession", "%p DESTROYED: handle=0x%lx bootstrap=%d",
64 this, handle(), mBootstrap
.port());
69 // Locate a session object by service port or (Session API) identifier
71 Session
&Session::find(Port servicePort
)
73 StLock
<Mutex
> _(mSessions
);
74 PortMap
<Session
>::const_iterator it
= mSessions
.find(servicePort
);
75 assert(it
!= mSessions
.end());
79 Session
&Session::find(SecuritySessionId id
)
82 case callerSecuritySession
:
83 return Server::session();
85 return HandleObject::find
<Session
>(id
, CSSMERR_CSSM_INVALID_ADDIN_HANDLE
);
91 // Act on a death notification for a session's (sub)bootstrap port.
92 // We may not destroy the Session outright here (due to processes that use it),
93 // but we do clear out its accumulated wealth.
95 void Session::destroy(Port servPort
)
97 // remove session from session map
98 StLock
<Mutex
> _(mSessions
);
99 PortMap
<Session
>::iterator it
= mSessions
.find(servPort
);
100 assert(it
!= mSessions
.end());
101 RefPointer
<Session
> session
= it
->second
;
108 StLock
<Mutex
> _(*this);
110 // release authorization host objects
112 StLock
<Mutex
> _(mAuthHostLock
);
113 mSecurityAgent
= NULL
;
117 // invalidate shared credentials
119 StLock
<Mutex
> _(mCredsLock
);
121 IFDEBUG(if (!mSessionCreds
.empty())
122 secdebug("SSauth", "session %p clearing %d shared credentials",
123 this, int(mSessionCreds
.size())));
124 for (CredentialSet::iterator it
= mSessionCreds
.begin(); it
!= mSessionCreds
.end(); it
++)
128 // base kill processing
134 // On system sleep, call sleepProcessing on all DbCommons of all Sessions
136 void Session::processSystemSleep()
138 StLock
<Mutex
> _(mSessions
);
139 for (PortMap
<Session
>::const_iterator it
= mSessions
.begin(); it
!= mSessions
.end(); it
++)
140 it
->second
->allReferences(&DbCommon::sleepProcessing
);
145 // On "lockAll", call sleepProcessing on all DbCommons of this session (only)
147 void Session::processLockAll()
149 allReferences(&DbCommon::lockProcessing
);
154 // The root session inherits the startup bootstrap and service port
156 RootSession::RootSession(Server
&server
, SessionAttributeBits attrs
)
157 : Session(Bootstrap(), server
.primaryServicePort(),
158 sessionIsRoot
| sessionWasInitialized
| attrs
)
160 parent(server
); // the Server is our parent
163 // self-install (no thread safety issues here)
164 mSessions
[mServicePort
] = this;
167 uid_t
RootSession::originatorUid() const
169 return 0; // it's root, obviously
172 CFDataRef
RootSession::copyUserPrefs()
178 // Dynamic sessions use the given bootstrap and re-register in it
180 DynamicSession::DynamicSession(TaskPort taskPort
)
181 : ReceivePort(Server::active().bootstrapName(), taskPort
.bootstrap()),
182 Session(taskPort
.bootstrap(), *this),
183 mOriginatorTask(taskPort
), mHaveOriginatorUid(false)
185 // link to Server as the global nexus in the object mesh
186 parent(Server::active());
188 // tell the server to listen to our port
189 Server::active().add(*this);
191 // register for port notifications
192 Server::active().notifyIfDead(bootstrapPort()); //@@@??? still needed?
193 Server::active().notifyIfUnused(*this);
196 StLock
<Mutex
> _(mSessions
);
197 assert(!mSessions
[*this]); // can't be registered already (we just made it)
198 mSessions
[*this] = this;
200 secdebug("SSsession", "%p dynamic session originator=%d (pid=%d)",
201 this, mOriginatorTask
.port(), taskPort
.pid());
204 DynamicSession::~DynamicSession()
206 // remove our service port from the server
207 Server::active().remove(*this);
211 void DynamicSession::kill()
213 StLock
<Mutex
> _(*this);
214 mBootstrap
.destroy(); // release our bootstrap port
215 Session::kill(); // continue with parent kill
220 // Set up a DynamicSession.
221 // This call must be made from a process within the session, and it must be the first
222 // such process to make the call.
224 void DynamicSession::setupAttributes(SessionCreationFlags flags
, SessionAttributeBits attrs
)
226 StLock
<Mutex
> _(*this);
227 secdebug("SSsession", "%p setup flags=0x%lx attrs=0x%lx", this, flags
, attrs
);
228 if (attrs
& ~settableAttributes
)
229 MacOSError::throwMe(errSessionInvalidAttributes
);
231 if (attribute(sessionWasInitialized
))
232 MacOSError::throwMe(errSessionAuthorizationDenied
);
233 setAttributes(attrs
| sessionWasInitialized
);
238 // Check whether the calling process is the session originator.
239 // If it's not, throw.
241 void DynamicSession::checkOriginator()
243 if (mOriginatorTask
!= Server::process().taskPort())
244 MacOSError::throwMe(errSessionAuthorizationDenied
);
249 // The "originator uid" is a uid value that can be provided by the session originator
250 // and retrieved by anyone. Securityd places no semantic meaning on this value.
252 uid_t
DynamicSession::originatorUid() const
254 if (mHaveOriginatorUid
)
255 return mOriginatorUid
;
257 MacOSError::throwMe(errSessionValueNotSet
);
261 void DynamicSession::originatorUid(uid_t uid
)
264 if (mHaveOriginatorUid
) // must not re-set this
265 MacOSError::throwMe(errSessionAuthorizationDenied
);
266 mHaveOriginatorUid
= true;
267 mOriginatorUid
= uid
;
268 secdebug("SSsession", "%p session uid set to %d", this, uid
);
273 // Authorization operations
275 OSStatus
Session::authCreate(const AuthItemSet
&rights
,
276 const AuthItemSet
&environment
,
277 AuthorizationFlags flags
,
278 AuthorizationBlob
&newHandle
,
279 const audit_token_t
&auditToken
)
281 // invoke the authorization computation engine
282 CredentialSet resultCreds
;
284 // this will acquire the object lock, so we delay acquiring it (@@@ no longer needed)
285 auto_ptr
<AuthorizationToken
> auth(new AuthorizationToken(*this, resultCreds
, auditToken
));
287 // Make a copy of the mSessionCreds
288 CredentialSet sessionCreds
;
290 StLock
<Mutex
> _(mCredsLock
);
291 sessionCreds
= mSessionCreds
;
294 AuthItemSet outRights
;
295 OSStatus result
= Server::authority().authorize(rights
, environment
, flags
,
296 &sessionCreds
, &resultCreds
, outRights
, *auth
);
297 newHandle
= auth
->handle();
299 // merge resulting creds into shared pool
300 if ((flags
& kAuthorizationFlagExtendRights
) &&
301 !(flags
& kAuthorizationFlagDestroyRights
))
303 StLock
<Mutex
> _(mCredsLock
);
304 mergeCredentials(resultCreds
);
305 auth
->mergeCredentials(resultCreds
);
308 // Make sure that this isn't done until the auth(AuthorizationToken) is guaranteed to
309 // not be destroyed anymore since it's destructor asserts it has no processes
310 Server::process().addAuthorization(auth
.get());
315 void Session::authFree(const AuthorizationBlob
&authBlob
, AuthorizationFlags flags
)
317 AuthorizationToken::Deleter
deleter(authBlob
);
318 AuthorizationToken
&auth
= deleter
;
319 Process
&process
= Server::process();
320 process
.checkAuthorization(&auth
);
322 if (flags
& kAuthorizationFlagDestroyRights
) {
323 // explicitly invalidate all shared credentials and remove them from the session
324 for (CredentialSet::const_iterator it
= auth
.begin(); it
!= auth
.end(); it
++)
325 if ((*it
)->isShared())
329 // now get rid of the authorization itself
330 if (process
.removeAuthorization(&auth
))
334 OSStatus
Session::authGetRights(const AuthorizationBlob
&authBlob
,
335 const AuthItemSet
&rights
, const AuthItemSet
&environment
,
336 AuthorizationFlags flags
,
337 AuthItemSet
&grantedRights
)
339 CredentialSet resultCreds
;
340 AuthorizationToken
&auth
= authorization(authBlob
);
341 CredentialSet effective
;
343 StLock
<Mutex
> _(mCredsLock
);
344 effective
= auth
.effectiveCreds();
346 OSStatus result
= Server::authority().authorize(rights
, environment
, flags
,
347 &effective
, &resultCreds
, grantedRights
, auth
);
349 // merge resulting creds into shared pool
350 if ((flags
& kAuthorizationFlagExtendRights
) && !(flags
& kAuthorizationFlagDestroyRights
))
352 StLock
<Mutex
> _(mCredsLock
);
353 mergeCredentials(resultCreds
);
354 auth
.mergeCredentials(resultCreds
);
357 secdebug("SSauth", "Authorization %p copyRights asked for %d got %d",
358 &authorization(authBlob
), int(rights
.size()), int(grantedRights
.size()));
362 OSStatus
Session::authGetInfo(const AuthorizationBlob
&authBlob
,
364 AuthItemSet
&contextInfo
)
366 AuthorizationToken
&auth
= authorization(authBlob
);
367 secdebug("SSauth", "Authorization %p get-info", &auth
);
368 contextInfo
= auth
.infoSet(tag
);
372 OSStatus
Session::authExternalize(const AuthorizationBlob
&authBlob
,
373 AuthorizationExternalForm
&extForm
)
375 const AuthorizationToken
&auth
= authorization(authBlob
);
376 StLock
<Mutex
> _(*this);
377 if (auth
.mayExternalize(Server::process())) {
378 memset(&extForm
, 0, sizeof(extForm
));
379 AuthorizationExternalBlob
&extBlob
=
380 reinterpret_cast<AuthorizationExternalBlob
&>(extForm
);
381 extBlob
.blob
= auth
.handle();
382 extBlob
.session
= bootstrapPort();
383 secdebug("SSauth", "Authorization %p externalized", &auth
);
386 return errAuthorizationExternalizeNotAllowed
;
389 OSStatus
Session::authInternalize(const AuthorizationExternalForm
&extForm
,
390 AuthorizationBlob
&authBlob
)
392 // interpret the external form
393 const AuthorizationExternalBlob
&extBlob
=
394 reinterpret_cast<const AuthorizationExternalBlob
&>(extForm
);
396 // locate source authorization
397 AuthorizationToken
&sourceAuth
= AuthorizationToken::find(extBlob
.blob
);
399 // check for permission and do it
400 if (sourceAuth
.mayInternalize(Server::process(), true)) {
401 StLock
<Mutex
> _(*this);
402 authBlob
= extBlob
.blob
;
403 Server::process().addAuthorization(&sourceAuth
);
404 secdebug("SSauth", "Authorization %p internalized", &sourceAuth
);
407 return errAuthorizationInternalizeNotAllowed
;
412 // The default session setup operation always fails.
413 // Subclasses can override this to support session setup calls.
415 void Session::setupAttributes(SessionCreationFlags flags
, SessionAttributeBits attrs
)
417 MacOSError::throwMe(errSessionAuthorizationDenied
);
422 // Authorization database I/O
424 OSStatus
Session::authorizationdbGet(AuthorizationString inRightName
, CFDictionaryRef
*rightDict
)
426 string
rightName(inRightName
);
427 return Server::authority().getRule(rightName
, rightDict
);
431 OSStatus
Session::authorizationdbSet(const AuthorizationBlob
&authBlob
, AuthorizationString inRightName
, CFDictionaryRef rightDict
)
433 CredentialSet resultCreds
;
434 AuthorizationToken
&auth
= authorization(authBlob
);
435 CredentialSet effective
;
438 StLock
<Mutex
> _(mCredsLock
);
439 effective
= auth
.effectiveCreds();
442 OSStatus result
= Server::authority().setRule(inRightName
, rightDict
, &effective
, &resultCreds
, auth
);
445 StLock
<Mutex
> _(mCredsLock
);
446 mergeCredentials(resultCreds
);
447 auth
.mergeCredentials(resultCreds
);
450 secdebug("SSauth", "Authorization %p authorizationdbSet %s (result=%ld)",
451 &authorization(authBlob
), inRightName
, result
);
456 OSStatus
Session::authorizationdbRemove(const AuthorizationBlob
&authBlob
, AuthorizationString inRightName
)
458 CredentialSet resultCreds
;
459 AuthorizationToken
&auth
= authorization(authBlob
);
460 CredentialSet effective
;
463 StLock
<Mutex
> _(mCredsLock
);
464 effective
= auth
.effectiveCreds();
467 OSStatus result
= Server::authority().removeRule(inRightName
, &effective
, &resultCreds
, auth
);
470 StLock
<Mutex
> _(mCredsLock
);
471 mergeCredentials(resultCreds
);
472 auth
.mergeCredentials(resultCreds
);
475 secdebug("SSauth", "Authorization %p authorizationdbRemove %s (result=%ld)",
476 &authorization(authBlob
), inRightName
, result
);
482 // Merge a set of credentials into the shared-session credential pool
484 // must hold mCredsLock
485 void Session::mergeCredentials(CredentialSet
&creds
)
487 secdebug("SSsession", "%p merge creds @%p", this, &creds
);
488 CredentialSet updatedCredentials
= creds
;
489 for (CredentialSet::const_iterator it
= creds
.begin(); it
!= creds
.end(); it
++)
490 if (((*it
)->isShared() && (*it
)->isValid())) {
491 CredentialSet::iterator old
= mSessionCreds
.find(*it
);
492 if (old
== mSessionCreds
.end()) {
493 mSessionCreds
.insert(*it
);
495 // replace "new" with "old" in input set to retain synchronization
497 updatedCredentials
.erase(*it
);
498 updatedCredentials
.insert(*old
);
501 creds
.swap(updatedCredentials
);
506 // Locate an AuthorizationToken given a blob
508 AuthorizationToken
&Session::authorization(const AuthorizationBlob
&blob
)
510 AuthorizationToken
&auth
= AuthorizationToken::find(blob
);
511 Server::process().checkAuthorization(&auth
);
515 RefPointer
<AuthHostInstance
>
516 Session::authhost(const AuthHostType hostType
, const bool restart
)
518 StLock
<Mutex
> _(mAuthHostLock
);
520 if (hostType
== privilegedAuthHost
)
522 if (restart
|| !mAuthHost
|| (mAuthHost
->state() != Security::UnixPlusPlus::Child::alive
))
525 PerSession::kill(*mAuthHost
);
526 mAuthHost
= new AuthHostInstance(*this, hostType
);
530 else /* if (hostType == securityAgent) */
532 if (restart
|| !mSecurityAgent
|| (mSecurityAgent
->state() != Security::UnixPlusPlus::Child::alive
))
535 PerSession::kill(*mSecurityAgent
);
536 mSecurityAgent
= new AuthHostInstance(*this, hostType
);
538 return mSecurityAgent
;
542 void DynamicSession::setUserPrefs(CFDataRef userPrefsDict
)
545 StLock
<Mutex
> _(*this);
546 mSessionAgentPrefs
= userPrefsDict
;
549 CFDataRef
DynamicSession::copyUserPrefs()
551 StLock
<Mutex
> _(*this);
552 if (mSessionAgentPrefs
)
553 CFRetain(mSessionAgentPrefs
);
554 return mSessionAgentPrefs
;
561 #if defined(DEBUGDUMP)
563 void Session::dumpNode()
565 PerSession::dumpNode();
566 Debug::dump(" boot=%d service=%d attrs=0x%lx authhost=%p securityagent=%p",
567 mBootstrap
.port(), mServicePort
.port(), mAttributes
, mAuthHost
, mSecurityAgent
);