2 * Copyright (c) 2000-2009,2011-2013 Apple 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 // Security sessions are now by definition congruent to audit subsystem sessions.
29 // We represent these sessions within securityd as subclasses of class Session,
30 // but we reach for the kernel's data whenever we're not sure if our data is
33 // Modifications to session state are made from client space using system calls.
34 // We discover them when we see changes in audit records as they come in with
35 // new requests. We cannot use system notifications for such changes because
36 // securityd is fully symmetrically multi-threaded, and thus may process new
37 // requests from clients before it gets those notifications.
40 #include <signal.h> // SIGTERM
41 #include <Security/AuthorizationPriv.h> // kAuthorizationFlagLeastPrivileged
43 #include "connection.h"
46 #include <security_utilities/logging.h>
47 #include <agentquery.h>
49 using namespace CommonCriteria
;
53 // The static session map
55 Session::SessionMap
Session::mSessions
;
56 Mutex
Session::mSessionLock(Mutex::recursive
);
59 const char Session::kUsername
[] = "username";
60 const char Session::kRealname
[] = "realname";
64 // Create a Session object from initial parameters (create)
66 Session::Session(const AuditInfo
&audit
, Server
&server
)
67 : mAudit(audit
), mSecurityAgent(NULL
), mKeybagState(0)
69 // link to Server as the global nexus in the object mesh
73 StLock
<Mutex
> _(mSessionLock
);
74 assert(!mSessions
[audit
.sessionId()]);
75 mSessions
[audit
.sessionId()] = this;
78 secnotice("SS", "%p Session %d created, uid:%d sessionId:%d", this, this->sessionId(), mAudit
.uid(), mAudit
.sessionId());
79 Syslog::notice("Session %d created", this->sessionId());
88 secnotice("SS", "%p Session %d destroyed", this, this->sessionId());
89 Syslog::notice("Session %d destroyed", this->sessionId());
93 Server
&Session::server() const
95 return parent
<Server
>();
100 // Locate a session object by session identifier
102 Session
&Session::find(pid_t id
, bool create
)
104 if (id
== callerSecuritySession
)
105 return Server::session();
106 StLock
<Mutex
> _(mSessionLock
);
107 SessionMap::iterator it
= mSessions
.find(id
);
108 if (it
!= mSessions
.end())
113 CssmError::throwMe(errSessionInvalidId
);
116 assert(info
.sessionId() == id
);
117 RefPointer
<Session
> session
= new Session(info
, Server::active());
118 mSessions
.insert(make_pair(id
, session
));
124 // Act on a death notification for a session's underlying audit session object.
125 // We may not destroy the Session outright here (due to processes that use it),
126 // but we do clear out its accumulated wealth.
127 // Note that we may get spurious death notifications for audit sessions that we
128 // never learned about. Ignore those.
130 void Session::destroy(SessionId id
)
132 // remove session from session map
133 RefPointer
<Session
> session
= NULL
;
135 StLock
<Mutex
> _(mSessionLock
);
136 SessionMap::iterator it
= mSessions
.find(id
);
137 if (it
!= mSessions
.end()) {
138 session
= it
->second
;
139 assert(session
->sessionId() == id
);
152 StLock
<Mutex
> _(*this); // do we need to take this so early?
153 secnotice("SS", "%p killing session %d", this, this->sessionId());
154 invalidateSessionAuthHosts();
156 // base kill processing
162 // Refetch audit session data for the current audit session (to catch outside updates
163 // to the audit record). This is the price we're paying for not requiring an IPC to
164 // securityd when audit session data changes (this is desirable for delayering the
165 // software layer cake).
166 // If we ever disallow changes to (parts of the) audit session record in the kernel,
167 // we can loosen up on this continual re-fetching.
169 void Session::updateAudit() const
171 CommonCriteria::AuditInfo info
;
173 info
.get(mAudit
.sessionId());
180 void Session::verifyKeyStorePassphrase(int32_t retries
)
182 QueryKeybagPassphrase
keybagQuery(*this, retries
);
183 keybagQuery
.inferHints(Server::process());
184 if (keybagQuery
.query() != SecurityAgent::noReason
) {
185 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
189 void Session::changeKeyStorePassphrase()
191 service_context_t context
= get_current_service_context();
192 QueryKeybagNewPassphrase
keybagQuery(*this);
193 keybagQuery
.inferHints(Server::process());
194 CssmAutoData
pass(Allocator::standard(Allocator::sensitive
));
195 CssmAutoData
oldPass(Allocator::standard(Allocator::sensitive
));
196 SecurityAgent::Reason queryReason
= keybagQuery
.query(oldPass
, pass
);
197 if (queryReason
== SecurityAgent::noReason
) {
198 service_client_kb_change_secret(&context
, oldPass
.data(), (int)oldPass
.length(), pass
.data(), (int)pass
.length());
200 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
204 void Session::resetKeyStorePassphrase(const CssmData
&passphrase
)
206 service_context_t context
= get_current_service_context();
207 service_client_kb_reset(&context
, passphrase
.data(), (int)passphrase
.length());
210 service_context_t
Session::get_current_service_context()
212 service_context_t context
= { sessionId(), originatorUid(), *Server::connection().auditToken() };
216 void Session::keybagClearState(int state
)
218 mKeybagState
&= ~state
;
221 void Session::keybagSetState(int state
)
223 mKeybagState
|= state
;
226 bool Session::keybagGetState(int state
)
228 return mKeybagState
& state
;
233 // Manage authorization client processes
235 void Session::invalidateSessionAuthHosts()
237 StLock
<Mutex
> _(mAuthHostLock
);
239 // if you got here, we don't care about pending operations: the auth hosts die
240 Syslog::warning("Killing auth hosts");
241 if (mSecurityAgent
) mSecurityAgent
->UnixPlusPlus::Child::kill(SIGTERM
);
242 mSecurityAgent
= NULL
;
245 void Session::invalidateAuthHosts()
247 StLock
<Mutex
> _(mSessionLock
);
248 for (SessionMap::const_iterator it
= mSessions
.begin(); it
!= mSessions
.end(); it
++)
249 it
->second
->invalidateSessionAuthHosts();
253 // On system sleep, call sleepProcessing on all DbCommons of all Sessions
255 void Session::processSystemSleep()
257 SecurityAgentXPCQuery::killAllXPCClients();
259 StLock
<Mutex
> _(mSessionLock
);
260 for (SessionMap::const_iterator it
= mSessions
.begin(); it
!= mSessions
.end(); it
++)
261 it
->second
->allReferences(&DbCommon::sleepProcessing
);
266 // On "lockAll", call sleepProcessing on all DbCommons of this session (only)
268 void Session::processLockAll()
270 allReferences(&DbCommon::lockProcessing
);
275 // The root session corresponds to the audit session that security is running in.
276 // This is usually the initial system session; but in debug scenarios it may be
277 // an "ordinary" graphic login session. In such a debug case, we may add attribute
278 // flags to the session to make our (debugging) life easier.
280 RootSession::RootSession(uint64_t attributes
, Server
&server
)
281 : Session(AuditInfo::current(), server
)
284 mAudit
.ai_flags
|= attributes
; // merge imposed attributes
289 // Accessor method for setting audit session flags.
291 void Session::setAttributes(SessionAttributeBits bits
)
293 StLock
<Mutex
> _(*this);
295 // assert((bits & ~settableAttributes) == 0);
296 mAudit
.ai_flags
= bits
;
301 // The default session setup operation always fails.
302 // Subclasses can override this to support session setup calls.
304 void Session::setupAttributes(SessionCreationFlags flags
, SessionAttributeBits attrs
)
306 MacOSError::throwMe(errSessionAuthorizationDenied
);
309 uid_t
Session::originatorUid()
311 if (mAudit
.uid() == AU_DEFAUDITID
) {
312 StLock
<Mutex
> _(*this);
319 RefPointer
<AuthHostInstance
>
320 Session::authhost(const bool restart
)
322 StLock
<Mutex
> _(mAuthHostLock
);
324 if (restart
|| !mSecurityAgent
|| (mSecurityAgent
->state() != Security::UnixPlusPlus::Child::alive
))
327 PerSession::kill(*mSecurityAgent
);
328 mSecurityAgent
= new AuthHostInstance(*this);
330 return mSecurityAgent
;
337 #if defined(DEBUGDUMP)
339 void Session::dumpNode()
341 PerSession::dumpNode();
342 Debug::dump(" auid=%d attrs=%#x securityagent=%p",
343 this->sessionId(), uint32_t(this->attributes()), mSecurityAgent
);