]> git.saurik.com Git - apple/security.git/blame - securityd/src/session.cpp
Security-59306.101.1.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
79b9da22 78 secnotice("SecServer", "%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{
79b9da22 88 secnotice("SecServer", "%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
d8f41ccd
A
98//
99// Locate a session object by session identifier
100//
101Session &Session::find(pid_t id, bool create)
102{
6b200bc3 103 if (id == (pid_t)callerSecuritySession)
d8f41ccd
A
104 return Server::session();
105 StLock<Mutex> _(mSessionLock);
106 SessionMap::iterator it = mSessions.find(id);
107 if (it != mSessions.end())
108 return *it->second;
109
110 // new session
111 if (!create)
112 CssmError::throwMe(errSessionInvalidId);
113 AuditInfo info;
114 info.get(id);
115 assert(info.sessionId() == id);
fa7225c8 116 RefPointer<Session> session = new Session(info, Server::active());
d8f41ccd
A
117 mSessions.insert(make_pair(id, session));
118 return *session;
119}
120
121
122//
123// Act on a death notification for a session's underlying audit session object.
124// We may not destroy the Session outright here (due to processes that use it),
125// but we do clear out its accumulated wealth.
126// Note that we may get spurious death notifications for audit sessions that we
127// never learned about. Ignore those.
128//
129void Session::destroy(SessionId id)
130{
131 // remove session from session map
d8f41ccd
A
132 RefPointer<Session> session = NULL;
133 {
134 StLock<Mutex> _(mSessionLock);
135 SessionMap::iterator it = mSessions.find(id);
136 if (it != mSessions.end()) {
137 session = it->second;
138 assert(session->sessionId() == id);
139 mSessions.erase(it);
d8f41ccd
A
140 }
141 }
142
143 if (session.get()) {
d8f41ccd
A
144 session->kill();
145 }
146}
147
148
149void Session::kill()
150{
151 StLock<Mutex> _(*this); // do we need to take this so early?
79b9da22 152 secnotice("SecServer", "%p killing session %d", this, this->sessionId());
d8f41ccd
A
153 invalidateSessionAuthHosts();
154
d8f41ccd
A
155 // base kill processing
156 PerSession::kill();
157}
158
159
160//
161// Refetch audit session data for the current audit session (to catch outside updates
162// to the audit record). This is the price we're paying for not requiring an IPC to
163// securityd when audit session data changes (this is desirable for delayering the
164// software layer cake).
165// If we ever disallow changes to (parts of the) audit session record in the kernel,
166// we can loosen up on this continual re-fetching.
167//
168void Session::updateAudit() const
169{
170 CommonCriteria::AuditInfo info;
171 try {
172 info.get(mAudit.sessionId());
173 } catch (...) {
174 return;
175 }
176 mAudit = info;
177}
178
dd5fb164
A
179// Second and third arguments defaults to false
180void Session::verifyKeyStorePassphrase(int32_t retries, bool useForACLFallback, const char *itemname)
d8f41ccd
A
181{
182 QueryKeybagPassphrase keybagQuery(*this, retries);
183 keybagQuery.inferHints(Server::process());
dd5fb164
A
184
185 // Parasitic takeover to enable user confirmation when ACL validation ends up without a database
186 if (useForACLFallback) {
187 keybagQuery.addHint("acl-fallback", &useForACLFallback, sizeof(useForACLFallback));
188 keybagQuery.addHint("keychain-item-name", itemname, itemname ? (uint32_t)strlen(itemname) : 0, 0);
189 }
190
d8f41ccd
A
191 if (keybagQuery.query() != SecurityAgent::noReason) {
192 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
193 }
194}
195
196void Session::changeKeyStorePassphrase()
197{
198 service_context_t context = get_current_service_context();
199 QueryKeybagNewPassphrase keybagQuery(*this);
200 keybagQuery.inferHints(Server::process());
201 CssmAutoData pass(Allocator::standard(Allocator::sensitive));
202 CssmAutoData oldPass(Allocator::standard(Allocator::sensitive));
203 SecurityAgent::Reason queryReason = keybagQuery.query(oldPass, pass);
204 if (queryReason == SecurityAgent::noReason) {
205 service_client_kb_change_secret(&context, oldPass.data(), (int)oldPass.length(), pass.data(), (int)pass.length());
206 } else {
207 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
208 }
209}
210
211void Session::resetKeyStorePassphrase(const CssmData &passphrase)
212{
213 service_context_t context = get_current_service_context();
214 service_client_kb_reset(&context, passphrase.data(), (int)passphrase.length());
215}
216
217service_context_t Session::get_current_service_context()
218{
79b9da22 219 service_context_t context = { sessionId(), originatorUid(), *Server::connection().auditToken(), 0 };
d8f41ccd
A
220 return context;
221}
222
223void Session::keybagClearState(int state)
224{
225 mKeybagState &= ~state;
226}
227
228void Session::keybagSetState(int state)
229{
230 mKeybagState |= state;
231}
232
233bool Session::keybagGetState(int state)
234{
235 return mKeybagState & state;
236}
237
238
239//
240// Manage authorization client processes
241//
242void Session::invalidateSessionAuthHosts()
243{
244 StLock<Mutex> _(mAuthHostLock);
245
246 // if you got here, we don't care about pending operations: the auth hosts die
b54c578e
A
247 Syslog::warning("Killing auth hosts for session %d", this->sessionId());
248 if (mSecurityAgent) {
249 secnotice("shutdown", "SIGTERMing child in state %d, pid %d", mSecurityAgent->UnixPlusPlus::Child::state(), mSecurityAgent->UnixPlusPlus::Child::pid());
250 mSecurityAgent->UnixPlusPlus::Child::kill(SIGTERM);
251 } else {
252 secnotice("shutdown", "No securityagent for session %d", this->sessionId());
253 }
d8f41ccd 254 mSecurityAgent = NULL;
d8f41ccd
A
255}
256
257void Session::invalidateAuthHosts()
258{
259 StLock<Mutex> _(mSessionLock);
b54c578e 260 for (SessionMap::const_iterator it = mSessions.begin(); it != mSessions.end(); it++) {
d8f41ccd 261 it->second->invalidateSessionAuthHosts();
b54c578e 262 }
d8f41ccd
A
263}
264
265//
266// On system sleep, call sleepProcessing on all DbCommons of all Sessions
267//
268void Session::processSystemSleep()
269{
270 SecurityAgentXPCQuery::killAllXPCClients();
271
272 StLock<Mutex> _(mSessionLock);
273 for (SessionMap::const_iterator it = mSessions.begin(); it != mSessions.end(); it++)
274 it->second->allReferences(&DbCommon::sleepProcessing);
275}
276
277
278//
279// On "lockAll", call sleepProcessing on all DbCommons of this session (only)
280//
281void Session::processLockAll()
282{
283 allReferences(&DbCommon::lockProcessing);
284}
285
286
287//
288// The root session corresponds to the audit session that security is running in.
289// This is usually the initial system session; but in debug scenarios it may be
290// an "ordinary" graphic login session. In such a debug case, we may add attribute
291// flags to the session to make our (debugging) life easier.
292//
293RootSession::RootSession(uint64_t attributes, Server &server)
294 : Session(AuditInfo::current(), server)
295{
296 ref(); // eternalize
297 mAudit.ai_flags |= attributes; // merge imposed attributes
298}
299
300
d8f41ccd
A
301//
302// Accessor method for setting audit session flags.
303//
304void Session::setAttributes(SessionAttributeBits bits)
305{
306 StLock<Mutex> _(*this);
307 updateAudit();
308// assert((bits & ~settableAttributes) == 0);
309 mAudit.ai_flags = bits;
310 mAudit.set();
311}
312
313//
314// The default session setup operation always fails.
315// Subclasses can override this to support session setup calls.
316//
317void Session::setupAttributes(SessionCreationFlags flags, SessionAttributeBits attrs)
318{
319 MacOSError::throwMe(errSessionAuthorizationDenied);
320}
321
322uid_t Session::originatorUid()
323{
324 if (mAudit.uid() == AU_DEFAUDITID) {
325 StLock<Mutex> _(*this);
326 updateAudit();
327 }
328 return mAudit.uid();
329}
330
d8f41ccd
A
331
332RefPointer<AuthHostInstance>
fa7225c8 333Session::authhost(const bool restart)
d8f41ccd
A
334{
335 StLock<Mutex> _(mAuthHostLock);
336
fa7225c8 337 if (restart || !mSecurityAgent || (mSecurityAgent->state() != Security::UnixPlusPlus::Child::alive))
d8f41ccd 338 {
fa7225c8
A
339 if (mSecurityAgent)
340 PerSession::kill(*mSecurityAgent);
341 mSecurityAgent = new AuthHostInstance(*this);
d8f41ccd 342 }
fa7225c8 343 return mSecurityAgent;
d8f41ccd
A
344}
345
346
347//
348// Debug dumping
349//
350#if defined(DEBUGDUMP)
351
352void Session::dumpNode()
353{
354 PerSession::dumpNode();
fa7225c8
A
355 Debug::dump(" auid=%d attrs=%#x securityagent=%p",
356 this->sessionId(), uint32_t(this->attributes()), mSecurityAgent);
d8f41ccd
A
357}
358
359#endif //DEBUGDUMP