]> git.saurik.com Git - apple/security.git/blame - securityd/src/session.cpp
Security-58286.70.7.tar.gz
[apple/security.git] / securityd / src / session.cpp
CommitLineData
d8f41ccd
A
1/*
2 * Copyright (c) 2000-2009,2011-2013 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25//
26// session - authentication session domains
27//
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
31// up to date.
32//
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.
38//
39#include <pwd.h>
40#include <signal.h> // SIGTERM
41#include <Security/AuthorizationPriv.h> // kAuthorizationFlagLeastPrivileged
42#include "session.h"
43#include "connection.h"
44#include "database.h"
45#include "server.h"
46#include <security_utilities/logging.h>
47#include <agentquery.h>
48
49using namespace CommonCriteria;
50
51
52//
53// The static session map
54//
55Session::SessionMap Session::mSessions;
56Mutex Session::mSessionLock(Mutex::recursive);
57
58
59const char Session::kUsername[] = "username";
60const char Session::kRealname[] = "realname";
61
62
63//
64// Create a Session object from initial parameters (create)
65//
66Session::Session(const AuditInfo &audit, Server &server)
fa7225c8 67 : mAudit(audit), mSecurityAgent(NULL), mKeybagState(0)
d8f41ccd
A
68{
69 // link to Server as the global nexus in the object mesh
70 parent(server);
71
72 // self-register
73 StLock<Mutex> _(mSessionLock);
74 assert(!mSessions[audit.sessionId()]);
75 mSessions[audit.sessionId()] = this;
76
77 // log it
fa7225c8 78 secnotice("SS", "%p Session %d created, uid:%d sessionId:%d", this, this->sessionId(), mAudit.uid(), mAudit.sessionId());
d8f41ccd
A
79 Syslog::notice("Session %d created", this->sessionId());
80}
81
82
83//
84// Destroy a Session
85//
86Session::~Session()
87{
fa7225c8 88 secnotice("SS", "%p Session %d destroyed", this, this->sessionId());
d8f41ccd
A
89 Syslog::notice("Session %d destroyed", this->sessionId());
90}
91
92
93Server &Session::server() const
94{
95 return parent<Server>();
96}
97
98
99//
100// Locate a session object by session identifier
101//
102Session &Session::find(pid_t id, bool create)
103{
6b200bc3 104 if (id == (pid_t)callerSecuritySession)
d8f41ccd
A
105 return Server::session();
106 StLock<Mutex> _(mSessionLock);
107 SessionMap::iterator it = mSessions.find(id);
108 if (it != mSessions.end())
109 return *it->second;
110
111 // new session
112 if (!create)
113 CssmError::throwMe(errSessionInvalidId);
114 AuditInfo info;
115 info.get(id);
116 assert(info.sessionId() == id);
fa7225c8 117 RefPointer<Session> session = new Session(info, Server::active());
d8f41ccd
A
118 mSessions.insert(make_pair(id, session));
119 return *session;
120}
121
122
123//
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.
129//
130void Session::destroy(SessionId id)
131{
132 // remove session from session map
d8f41ccd
A
133 RefPointer<Session> session = NULL;
134 {
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);
140 mSessions.erase(it);
d8f41ccd
A
141 }
142 }
143
144 if (session.get()) {
d8f41ccd
A
145 session->kill();
146 }
147}
148
149
150void Session::kill()
151{
152 StLock<Mutex> _(*this); // do we need to take this so early?
fa7225c8 153 secnotice("SS", "%p killing session %d", this, this->sessionId());
d8f41ccd
A
154 invalidateSessionAuthHosts();
155
d8f41ccd
A
156 // base kill processing
157 PerSession::kill();
158}
159
160
161//
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.
168//
169void Session::updateAudit() const
170{
171 CommonCriteria::AuditInfo info;
172 try {
173 info.get(mAudit.sessionId());
174 } catch (...) {
175 return;
176 }
177 mAudit = info;
178}
179
dd5fb164
A
180// Second and third arguments defaults to false
181void Session::verifyKeyStorePassphrase(int32_t retries, bool useForACLFallback, const char *itemname)
d8f41ccd
A
182{
183 QueryKeybagPassphrase keybagQuery(*this, retries);
184 keybagQuery.inferHints(Server::process());
dd5fb164
A
185
186 // Parasitic takeover to enable user confirmation when ACL validation ends up without a database
187 if (useForACLFallback) {
188 keybagQuery.addHint("acl-fallback", &useForACLFallback, sizeof(useForACLFallback));
189 keybagQuery.addHint("keychain-item-name", itemname, itemname ? (uint32_t)strlen(itemname) : 0, 0);
190 }
191
d8f41ccd
A
192 if (keybagQuery.query() != SecurityAgent::noReason) {
193 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
194 }
195}
196
197void Session::changeKeyStorePassphrase()
198{
199 service_context_t context = get_current_service_context();
200 QueryKeybagNewPassphrase keybagQuery(*this);
201 keybagQuery.inferHints(Server::process());
202 CssmAutoData pass(Allocator::standard(Allocator::sensitive));
203 CssmAutoData oldPass(Allocator::standard(Allocator::sensitive));
204 SecurityAgent::Reason queryReason = keybagQuery.query(oldPass, pass);
205 if (queryReason == SecurityAgent::noReason) {
206 service_client_kb_change_secret(&context, oldPass.data(), (int)oldPass.length(), pass.data(), (int)pass.length());
207 } else {
208 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
209 }
210}
211
212void Session::resetKeyStorePassphrase(const CssmData &passphrase)
213{
214 service_context_t context = get_current_service_context();
215 service_client_kb_reset(&context, passphrase.data(), (int)passphrase.length());
216}
217
218service_context_t Session::get_current_service_context()
219{
5c19dc3a 220 service_context_t context = { sessionId(), originatorUid(), *Server::connection().auditToken() };
d8f41ccd
A
221 return context;
222}
223
224void Session::keybagClearState(int state)
225{
226 mKeybagState &= ~state;
227}
228
229void Session::keybagSetState(int state)
230{
231 mKeybagState |= state;
232}
233
234bool Session::keybagGetState(int state)
235{
236 return mKeybagState & state;
237}
238
239
240//
241// Manage authorization client processes
242//
243void Session::invalidateSessionAuthHosts()
244{
245 StLock<Mutex> _(mAuthHostLock);
246
247 // if you got here, we don't care about pending operations: the auth hosts die
248 Syslog::warning("Killing auth hosts");
249 if (mSecurityAgent) mSecurityAgent->UnixPlusPlus::Child::kill(SIGTERM);
d8f41ccd 250 mSecurityAgent = NULL;
d8f41ccd
A
251}
252
253void Session::invalidateAuthHosts()
254{
255 StLock<Mutex> _(mSessionLock);
256 for (SessionMap::const_iterator it = mSessions.begin(); it != mSessions.end(); it++)
257 it->second->invalidateSessionAuthHosts();
258}
259
260//
261// On system sleep, call sleepProcessing on all DbCommons of all Sessions
262//
263void Session::processSystemSleep()
264{
265 SecurityAgentXPCQuery::killAllXPCClients();
266
267 StLock<Mutex> _(mSessionLock);
268 for (SessionMap::const_iterator it = mSessions.begin(); it != mSessions.end(); it++)
269 it->second->allReferences(&DbCommon::sleepProcessing);
270}
271
272
273//
274// On "lockAll", call sleepProcessing on all DbCommons of this session (only)
275//
276void Session::processLockAll()
277{
278 allReferences(&DbCommon::lockProcessing);
279}
280
281
282//
283// The root session corresponds to the audit session that security is running in.
284// This is usually the initial system session; but in debug scenarios it may be
285// an "ordinary" graphic login session. In such a debug case, we may add attribute
286// flags to the session to make our (debugging) life easier.
287//
288RootSession::RootSession(uint64_t attributes, Server &server)
289 : Session(AuditInfo::current(), server)
290{
291 ref(); // eternalize
292 mAudit.ai_flags |= attributes; // merge imposed attributes
293}
294
295
d8f41ccd
A
296//
297// Accessor method for setting audit session flags.
298//
299void Session::setAttributes(SessionAttributeBits bits)
300{
301 StLock<Mutex> _(*this);
302 updateAudit();
303// assert((bits & ~settableAttributes) == 0);
304 mAudit.ai_flags = bits;
305 mAudit.set();
306}
307
308//
309// The default session setup operation always fails.
310// Subclasses can override this to support session setup calls.
311//
312void Session::setupAttributes(SessionCreationFlags flags, SessionAttributeBits attrs)
313{
314 MacOSError::throwMe(errSessionAuthorizationDenied);
315}
316
317uid_t Session::originatorUid()
318{
319 if (mAudit.uid() == AU_DEFAUDITID) {
320 StLock<Mutex> _(*this);
321 updateAudit();
322 }
323 return mAudit.uid();
324}
325
d8f41ccd
A
326
327RefPointer<AuthHostInstance>
fa7225c8 328Session::authhost(const bool restart)
d8f41ccd
A
329{
330 StLock<Mutex> _(mAuthHostLock);
331
fa7225c8 332 if (restart || !mSecurityAgent || (mSecurityAgent->state() != Security::UnixPlusPlus::Child::alive))
d8f41ccd 333 {
fa7225c8
A
334 if (mSecurityAgent)
335 PerSession::kill(*mSecurityAgent);
336 mSecurityAgent = new AuthHostInstance(*this);
d8f41ccd 337 }
fa7225c8 338 return mSecurityAgent;
d8f41ccd
A
339}
340
341
342//
343// Debug dumping
344//
345#if defined(DEBUGDUMP)
346
347void Session::dumpNode()
348{
349 PerSession::dumpNode();
fa7225c8
A
350 Debug::dump(" auid=%d attrs=%#x securityagent=%p",
351 this->sessionId(), uint32_t(this->attributes()), mSecurityAgent);
d8f41ccd
A
352}
353
354#endif //DEBUGDUMP