]> git.saurik.com Git - apple/security.git/blob - securityd/src/session.cpp
Security-58286.200.222.tar.gz
[apple/security.git] / securityd / src / session.cpp
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
49 using namespace CommonCriteria;
50
51
52 //
53 // The static session map
54 //
55 Session::SessionMap Session::mSessions;
56 Mutex Session::mSessionLock(Mutex::recursive);
57
58
59 const char Session::kUsername[] = "username";
60 const char Session::kRealname[] = "realname";
61
62
63 //
64 // Create a Session object from initial parameters (create)
65 //
66 Session::Session(const AuditInfo &audit, Server &server)
67 : mAudit(audit), mSecurityAgent(NULL), mKeybagState(0)
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
78 secnotice("SecServer", "%p Session %d created, uid:%d sessionId:%d", this, this->sessionId(), mAudit.uid(), mAudit.sessionId());
79 Syslog::notice("Session %d created", this->sessionId());
80 }
81
82
83 //
84 // Destroy a Session
85 //
86 Session::~Session()
87 {
88 secnotice("SecServer", "%p Session %d destroyed", this, this->sessionId());
89 Syslog::notice("Session %d destroyed", this->sessionId());
90 }
91
92
93 Server &Session::server() const
94 {
95 return parent<Server>();
96 }
97
98
99 //
100 // Locate a session object by session identifier
101 //
102 Session &Session::find(pid_t id, bool create)
103 {
104 if (id == (pid_t)callerSecuritySession)
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);
117 RefPointer<Session> session = new Session(info, Server::active());
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 //
130 void Session::destroy(SessionId id)
131 {
132 // remove session from session map
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);
141 }
142 }
143
144 if (session.get()) {
145 session->kill();
146 }
147 }
148
149
150 void Session::kill()
151 {
152 StLock<Mutex> _(*this); // do we need to take this so early?
153 secnotice("SecServer", "%p killing session %d", this, this->sessionId());
154 invalidateSessionAuthHosts();
155
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 //
169 void 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
180 // Second and third arguments defaults to false
181 void Session::verifyKeyStorePassphrase(int32_t retries, bool useForACLFallback, const char *itemname)
182 {
183 QueryKeybagPassphrase keybagQuery(*this, retries);
184 keybagQuery.inferHints(Server::process());
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
192 if (keybagQuery.query() != SecurityAgent::noReason) {
193 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
194 }
195 }
196
197 void 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
212 void 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
218 service_context_t Session::get_current_service_context()
219 {
220 service_context_t context = { sessionId(), originatorUid(), *Server::connection().auditToken(), 0 };
221 return context;
222 }
223
224 void Session::keybagClearState(int state)
225 {
226 mKeybagState &= ~state;
227 }
228
229 void Session::keybagSetState(int state)
230 {
231 mKeybagState |= state;
232 }
233
234 bool Session::keybagGetState(int state)
235 {
236 return mKeybagState & state;
237 }
238
239
240 //
241 // Manage authorization client processes
242 //
243 void 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);
250 mSecurityAgent = NULL;
251 }
252
253 void 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 //
263 void 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 //
276 void 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 //
288 RootSession::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
296 //
297 // Accessor method for setting audit session flags.
298 //
299 void 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 //
312 void Session::setupAttributes(SessionCreationFlags flags, SessionAttributeBits attrs)
313 {
314 MacOSError::throwMe(errSessionAuthorizationDenied);
315 }
316
317 uid_t Session::originatorUid()
318 {
319 if (mAudit.uid() == AU_DEFAUDITID) {
320 StLock<Mutex> _(*this);
321 updateAudit();
322 }
323 return mAudit.uid();
324 }
325
326
327 RefPointer<AuthHostInstance>
328 Session::authhost(const bool restart)
329 {
330 StLock<Mutex> _(mAuthHostLock);
331
332 if (restart || !mSecurityAgent || (mSecurityAgent->state() != Security::UnixPlusPlus::Child::alive))
333 {
334 if (mSecurityAgent)
335 PerSession::kill(*mSecurityAgent);
336 mSecurityAgent = new AuthHostInstance(*this);
337 }
338 return mSecurityAgent;
339 }
340
341
342 //
343 // Debug dumping
344 //
345 #if defined(DEBUGDUMP)
346
347 void Session::dumpNode()
348 {
349 PerSession::dumpNode();
350 Debug::dump(" auid=%d attrs=%#x securityagent=%p",
351 this->sessionId(), uint32_t(this->attributes()), mSecurityAgent);
352 }
353
354 #endif //DEBUGDUMP