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 <Security/AuthorizationPriv.h> // kAuthorizationFlagLeastPrivileged
38 #include "connection.h"
43 // The static session map
45 PortMap
<Session
> Session::mSessions
;
47 std::string
Session::kUsername
= "username";
48 std::string
Session::kRealname
= "realname";
51 // Create a Session object from initial parameters (create)
53 Session::Session(Bootstrap bootstrap
, Port servicePort
, SessionAttributeBits attrs
)
54 : mBootstrap(bootstrap
), mServicePort(servicePort
),
55 mAttributes(attrs
), mSecurityAgent(NULL
), mAuthHost(NULL
)
57 secdebug("SSsession", "%p CREATED: handle=0x%lx bootstrap=%d service=%d attrs=0x%lx",
58 this, handle(), mBootstrap
.port(), mServicePort
.port(), mAttributes
);
67 secdebug("SSsession", "%p DESTROYED: handle=0x%lx bootstrap=%d",
68 this, handle(), mBootstrap
.port());
73 // Locate a session object by service port or (Session API) identifier
75 Session
&Session::find(Port servicePort
)
77 StLock
<Mutex
> _(mSessions
);
78 PortMap
<Session
>::const_iterator it
= mSessions
.find(servicePort
);
79 assert(it
!= mSessions
.end());
83 Session
&Session::find(SecuritySessionId id
)
86 case callerSecuritySession
:
87 return Server::session();
89 return HandleObject::find
<Session
>(id
, CSSMERR_CSSM_INVALID_ADDIN_HANDLE
);
95 // Act on a death notification for a session's (sub)bootstrap port.
96 // We may not destroy the Session outright here (due to processes that use it),
97 // but we do clear out its accumulated wealth.
99 void Session::destroy(Port servPort
)
101 // remove session from session map
102 StLock
<Mutex
> _(mSessions
);
103 PortMap
<Session
>::iterator it
= mSessions
.find(servPort
);
104 assert(it
!= mSessions
.end());
105 RefPointer
<Session
> session
= it
->second
;
112 StLock
<Mutex
> _(*this);
114 // release authorization host objects
116 StLock
<Mutex
> _(mAuthHostLock
);
117 mSecurityAgent
= NULL
;
121 // invalidate shared credentials
123 StLock
<Mutex
> _(mCredsLock
);
125 IFDEBUG(if (!mSessionCreds
.empty())
126 secdebug("SSauth", "session %p clearing %d shared credentials",
127 this, int(mSessionCreds
.size())));
128 for (CredentialSet::iterator it
= mSessionCreds
.begin(); it
!= mSessionCreds
.end(); it
++)
132 // base kill processing
138 // On system sleep, call sleepProcessing on all DbCommons of all Sessions
140 void Session::processSystemSleep()
142 StLock
<Mutex
> _(mSessions
);
143 for (PortMap
<Session
>::const_iterator it
= mSessions
.begin(); it
!= mSessions
.end(); it
++)
144 it
->second
->allReferences(&DbCommon::sleepProcessing
);
149 // On "lockAll", call sleepProcessing on all DbCommons of this session (only)
151 void Session::processLockAll()
153 allReferences(&DbCommon::lockProcessing
);
158 // The root session inherits the startup bootstrap and service port
160 RootSession::RootSession(Server
&server
, SessionAttributeBits attrs
)
161 : Session(Bootstrap(), server
.primaryServicePort(),
162 sessionIsRoot
| sessionWasInitialized
| attrs
)
164 parent(server
); // the Server is our parent
167 // self-install (no thread safety issues here)
168 mSessions
[mServicePort
] = this;
172 // Dynamic sessions use the given bootstrap and re-register in it
174 DynamicSession::DynamicSession(TaskPort taskPort
)
175 : ReceivePort(Server::active().bootstrapName(), taskPort
.bootstrap(), false),
176 Session(taskPort
.bootstrap(), *this),
177 mOriginatorTask(taskPort
), mHaveOriginatorUid(false)
179 // link to Server as the global nexus in the object mesh
180 parent(Server::active());
182 // tell the server to listen to our port
183 Server::active().add(*this);
185 // register for port notifications
186 Server::active().notifyIfDead(bootstrapPort()); //@@@??? still needed?
187 Server::active().notifyIfUnused(*this);
190 StLock
<Mutex
> _(mSessions
);
191 assert(!mSessions
[*this]); // can't be registered already (we just made it)
192 mSessions
[*this] = this;
194 secdebug("SSsession", "%p dynamic session originator=%d (pid=%d)",
195 this, mOriginatorTask
.port(), taskPort
.pid());
198 DynamicSession::~DynamicSession()
200 // remove our service port from the server
201 Server::active().remove(*this);
205 void DynamicSession::kill()
207 StLock
<Mutex
> _(*this);
208 mBootstrap
.destroy(); // release our bootstrap port
209 Session::kill(); // continue with parent kill
214 // Set up a DynamicSession.
215 // This call must be made from a process within the session, and it must be the first
216 // such process to make the call.
218 void DynamicSession::setupAttributes(SessionCreationFlags flags
, SessionAttributeBits attrs
)
220 StLock
<Mutex
> _(*this);
221 secdebug("SSsession", "%p setup flags=0x%lx attrs=0x%lx", this, flags
, attrs
);
222 if (attrs
& ~settableAttributes
)
223 MacOSError::throwMe(errSessionInvalidAttributes
);
225 if (attribute(sessionWasInitialized
))
226 MacOSError::throwMe(errSessionAuthorizationDenied
);
227 setAttributes(attrs
| sessionWasInitialized
);
232 // Check whether the calling process is the session originator.
233 // If it's not, throw.
235 void DynamicSession::checkOriginator()
237 if (mOriginatorTask
!= Server::process().taskPort())
238 MacOSError::throwMe(errSessionAuthorizationDenied
);
243 // The "originator uid" is a uid value that can be provided by the session originator
244 // and retrieved by anyone. Securityd places no semantic meaning on this value.
246 uid_t
DynamicSession::originatorUid() const
248 if (mHaveOriginatorUid
)
249 return mOriginatorUid
;
251 MacOSError::throwMe(errSessionValueNotSet
);
255 void DynamicSession::originatorUid(uid_t uid
)
258 if (mHaveOriginatorUid
) // must not re-set this
259 MacOSError::throwMe(errSessionAuthorizationDenied
);
260 mHaveOriginatorUid
= true;
261 mOriginatorUid
= uid
;
263 Server::active().longTermActivity();
264 struct passwd
*pw
= getpwuid(uid
);
268 mOriginatorCredential
= Credential(uid
, pw
->pw_name
? pw
->pw_name
: "", pw
->pw_gecos
? pw
->pw_gecos
: "", true/*shared*/);
272 secdebug("SSsession", "%p session uid set to %d", this, uid
);
276 // Authorization operations
278 OSStatus
Session::authCreate(const AuthItemSet
&rights
,
279 const AuthItemSet
&environment
,
280 AuthorizationFlags flags
,
281 AuthorizationBlob
&newHandle
,
282 const audit_token_t
&auditToken
)
284 // invoke the authorization computation engine
285 CredentialSet resultCreds
;
287 // this will acquire the object lock, so we delay acquiring it (@@@ no longer needed)
288 auto_ptr
<AuthorizationToken
> auth(new AuthorizationToken(*this, resultCreds
, auditToken
, (flags
&kAuthorizationFlagLeastPrivileged
)));
290 // Make a copy of the mSessionCreds
291 CredentialSet sessionCreds
;
293 StLock
<Mutex
> _(mCredsLock
);
294 sessionCreds
= mSessionCreds
;
297 AuthItemSet outRights
;
298 OSStatus result
= Server::authority().authorize(rights
, environment
, flags
,
299 &sessionCreds
, &resultCreds
, outRights
, *auth
);
300 newHandle
= auth
->handle();
302 // merge resulting creds into shared pool
303 if ((flags
& kAuthorizationFlagExtendRights
) &&
304 !(flags
& kAuthorizationFlagDestroyRights
))
306 StLock
<Mutex
> _(mCredsLock
);
307 mergeCredentials(resultCreds
);
308 auth
->mergeCredentials(resultCreds
);
311 // Make sure that this isn't done until the auth(AuthorizationToken) is guaranteed to
312 // not be destroyed anymore since it's destructor asserts it has no processes
313 Server::process().addAuthorization(auth
.get());
318 void Session::authFree(const AuthorizationBlob
&authBlob
, AuthorizationFlags flags
)
320 AuthorizationToken::Deleter
deleter(authBlob
);
321 AuthorizationToken
&auth
= deleter
;
322 Process
&process
= Server::process();
323 process
.checkAuthorization(&auth
);
325 if (flags
& kAuthorizationFlagDestroyRights
) {
326 // explicitly invalidate all shared credentials and remove them from the session
327 for (CredentialSet::const_iterator it
= auth
.begin(); it
!= auth
.end(); it
++)
328 if ((*it
)->isShared())
332 // now get rid of the authorization itself
333 if (process
.removeAuthorization(&auth
))
337 OSStatus
Session::authGetRights(const AuthorizationBlob
&authBlob
,
338 const AuthItemSet
&rights
, const AuthItemSet
&environment
,
339 AuthorizationFlags flags
,
340 AuthItemSet
&grantedRights
)
342 AuthorizationToken
&auth
= authorization(authBlob
);
343 return auth
.session().authGetRights(auth
, rights
, environment
, flags
, grantedRights
);
346 OSStatus
Session::authGetRights(AuthorizationToken
&auth
,
347 const AuthItemSet
&rights
, const AuthItemSet
&environment
,
348 AuthorizationFlags flags
,
349 AuthItemSet
&grantedRights
)
351 CredentialSet resultCreds
;
352 CredentialSet effective
;
354 StLock
<Mutex
> _(mCredsLock
);
355 effective
= auth
.effectiveCreds();
357 OSStatus result
= Server::authority().authorize(rights
, environment
, flags
,
358 &effective
, &resultCreds
, grantedRights
, auth
);
360 // merge resulting creds into shared pool
361 if ((flags
& kAuthorizationFlagExtendRights
) && !(flags
& kAuthorizationFlagDestroyRights
))
363 StLock
<Mutex
> _(mCredsLock
);
364 mergeCredentials(resultCreds
);
365 auth
.mergeCredentials(resultCreds
);
368 secdebug("SSauth", "Authorization %p copyRights asked for %d got %d",
369 &auth
, int(rights
.size()), int(grantedRights
.size()));
373 OSStatus
Session::authGetInfo(const AuthorizationBlob
&authBlob
,
375 AuthItemSet
&contextInfo
)
377 AuthorizationToken
&auth
= authorization(authBlob
);
378 secdebug("SSauth", "Authorization %p get-info", &auth
);
379 contextInfo
= auth
.infoSet(tag
);
383 OSStatus
Session::authExternalize(const AuthorizationBlob
&authBlob
,
384 AuthorizationExternalForm
&extForm
)
386 const AuthorizationToken
&auth
= authorization(authBlob
);
387 StLock
<Mutex
> _(*this);
388 if (auth
.mayExternalize(Server::process())) {
389 memset(&extForm
, 0, sizeof(extForm
));
390 AuthorizationExternalBlob
&extBlob
=
391 reinterpret_cast<AuthorizationExternalBlob
&>(extForm
);
392 extBlob
.blob
= auth
.handle();
393 extBlob
.session
= bootstrapPort();
394 secdebug("SSauth", "Authorization %p externalized", &auth
);
397 return errAuthorizationExternalizeNotAllowed
;
400 OSStatus
Session::authInternalize(const AuthorizationExternalForm
&extForm
,
401 AuthorizationBlob
&authBlob
)
403 // interpret the external form
404 const AuthorizationExternalBlob
&extBlob
=
405 reinterpret_cast<const AuthorizationExternalBlob
&>(extForm
);
407 // locate source authorization
408 AuthorizationToken
&sourceAuth
= AuthorizationToken::find(extBlob
.blob
);
410 // check for permission and do it
411 if (sourceAuth
.mayInternalize(Server::process(), true)) {
412 StLock
<Mutex
> _(*this);
413 authBlob
= extBlob
.blob
;
414 Server::process().addAuthorization(&sourceAuth
);
415 secdebug("SSauth", "Authorization %p internalized", &sourceAuth
);
418 return errAuthorizationInternalizeNotAllowed
;
423 // The default session setup operation always fails.
424 // Subclasses can override this to support session setup calls.
426 void Session::setupAttributes(SessionCreationFlags flags
, SessionAttributeBits attrs
)
428 MacOSError::throwMe(errSessionAuthorizationDenied
);
433 // Authorization database I/O
435 OSStatus
Session::authorizationdbGet(AuthorizationString inRightName
, CFDictionaryRef
*rightDict
)
437 string
rightName(inRightName
);
438 return Server::authority().getRule(rightName
, rightDict
);
442 OSStatus
Session::authorizationdbSet(const AuthorizationBlob
&authBlob
, AuthorizationString inRightName
, CFDictionaryRef rightDict
)
444 CredentialSet resultCreds
;
445 AuthorizationToken
&auth
= authorization(authBlob
);
446 CredentialSet effective
;
449 StLock
<Mutex
> _(mCredsLock
);
450 effective
= auth
.effectiveCreds();
453 OSStatus result
= Server::authority().setRule(inRightName
, rightDict
, &effective
, &resultCreds
, auth
);
456 StLock
<Mutex
> _(mCredsLock
);
457 mergeCredentials(resultCreds
);
458 auth
.mergeCredentials(resultCreds
);
461 secdebug("SSauth", "Authorization %p authorizationdbSet %s (result=%ld)",
462 &authorization(authBlob
), inRightName
, result
);
467 OSStatus
Session::authorizationdbRemove(const AuthorizationBlob
&authBlob
, AuthorizationString inRightName
)
469 CredentialSet resultCreds
;
470 AuthorizationToken
&auth
= authorization(authBlob
);
471 CredentialSet effective
;
474 StLock
<Mutex
> _(mCredsLock
);
475 effective
= auth
.effectiveCreds();
478 OSStatus result
= Server::authority().removeRule(inRightName
, &effective
, &resultCreds
, auth
);
481 StLock
<Mutex
> _(mCredsLock
);
482 mergeCredentials(resultCreds
);
483 auth
.mergeCredentials(resultCreds
);
486 secdebug("SSauth", "Authorization %p authorizationdbRemove %s (result=%ld)",
487 &authorization(authBlob
), inRightName
, result
);
493 // Merge a set of credentials into the shared-session credential pool
495 // must hold mCredsLock
496 void Session::mergeCredentials(CredentialSet
&creds
)
498 secdebug("SSsession", "%p merge creds @%p", this, &creds
);
499 CredentialSet updatedCredentials
= creds
;
500 for (CredentialSet::const_iterator it
= creds
.begin(); it
!= creds
.end(); it
++)
501 if ((*it
)->isShared() && (*it
)->isValid()) {
502 CredentialSet::iterator old
= mSessionCreds
.find(*it
);
503 if (old
== mSessionCreds
.end()) {
504 mSessionCreds
.insert(*it
);
506 // replace "new" with "old" in input set to retain synchronization
508 updatedCredentials
.erase(*it
);
509 updatedCredentials
.insert(*old
);
512 creds
.swap(updatedCredentials
);
517 // Locate an AuthorizationToken given a blob
519 AuthorizationToken
&Session::authorization(const AuthorizationBlob
&blob
)
521 AuthorizationToken
&auth
= AuthorizationToken::find(blob
);
522 Server::process().checkAuthorization(&auth
);
526 RefPointer
<AuthHostInstance
>
527 Session::authhost(const AuthHostType hostType
, const bool restart
)
529 StLock
<Mutex
> _(mAuthHostLock
);
531 if (hostType
== privilegedAuthHost
)
533 if (restart
|| !mAuthHost
|| (mAuthHost
->state() != Security::UnixPlusPlus::Child::alive
))
536 PerSession::kill(*mAuthHost
);
537 mAuthHost
= new AuthHostInstance(*this, hostType
);
541 else /* if (hostType == securityAgent) */
543 if (restart
|| !mSecurityAgent
|| (mSecurityAgent
->state() != Security::UnixPlusPlus::Child::alive
))
546 PerSession::kill(*mSecurityAgent
);
547 mSecurityAgent
= new AuthHostInstance(*this, hostType
);
549 return mSecurityAgent
;
553 void DynamicSession::setUserPrefs(CFDataRef userPrefsDict
)
556 if (Server::process().uid() != 0)
557 MacOSError::throwMe(errSessionAuthorizationDenied
);
558 StLock
<Mutex
> _(*this);
559 mSessionAgentPrefs
= userPrefsDict
;
562 CFDataRef
DynamicSession::copyUserPrefs()
564 StLock
<Mutex
> _(*this);
565 if (mSessionAgentPrefs
)
566 CFRetain(mSessionAgentPrefs
);
567 return mSessionAgentPrefs
;
574 #if defined(DEBUGDUMP)
576 void Session::dumpNode()
578 PerSession::dumpNode();
579 Debug::dump(" boot=%d service=%d attrs=0x%lx authhost=%p securityagent=%p",
580 mBootstrap
.port(), mServicePort
.port(), mAttributes
, mAuthHost
, mSecurityAgent
);