]> git.saurik.com Git - apple/security.git/blob - securityd/src/session.cpp
Security-57740.31.2.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("SS", "%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("SS", "%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 == 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("SS", "%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 void Session::verifyKeyStorePassphrase(int32_t retries)
181 {
182 QueryKeybagPassphrase keybagQuery(*this, retries);
183 keybagQuery.inferHints(Server::process());
184 if (keybagQuery.query() != SecurityAgent::noReason) {
185 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
186 }
187 }
188
189 void Session::changeKeyStorePassphrase()
190 {
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());
199 } else {
200 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
201 }
202 }
203
204 void Session::resetKeyStorePassphrase(const CssmData &passphrase)
205 {
206 service_context_t context = get_current_service_context();
207 service_client_kb_reset(&context, passphrase.data(), (int)passphrase.length());
208 }
209
210 service_context_t Session::get_current_service_context()
211 {
212 service_context_t context = { sessionId(), originatorUid(), *Server::connection().auditToken() };
213 return context;
214 }
215
216 void Session::keybagClearState(int state)
217 {
218 mKeybagState &= ~state;
219 }
220
221 void Session::keybagSetState(int state)
222 {
223 mKeybagState |= state;
224 }
225
226 bool Session::keybagGetState(int state)
227 {
228 return mKeybagState & state;
229 }
230
231
232 //
233 // Manage authorization client processes
234 //
235 void Session::invalidateSessionAuthHosts()
236 {
237 StLock<Mutex> _(mAuthHostLock);
238
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;
243 }
244
245 void Session::invalidateAuthHosts()
246 {
247 StLock<Mutex> _(mSessionLock);
248 for (SessionMap::const_iterator it = mSessions.begin(); it != mSessions.end(); it++)
249 it->second->invalidateSessionAuthHosts();
250 }
251
252 //
253 // On system sleep, call sleepProcessing on all DbCommons of all Sessions
254 //
255 void Session::processSystemSleep()
256 {
257 SecurityAgentXPCQuery::killAllXPCClients();
258
259 StLock<Mutex> _(mSessionLock);
260 for (SessionMap::const_iterator it = mSessions.begin(); it != mSessions.end(); it++)
261 it->second->allReferences(&DbCommon::sleepProcessing);
262 }
263
264
265 //
266 // On "lockAll", call sleepProcessing on all DbCommons of this session (only)
267 //
268 void Session::processLockAll()
269 {
270 allReferences(&DbCommon::lockProcessing);
271 }
272
273
274 //
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.
279 //
280 RootSession::RootSession(uint64_t attributes, Server &server)
281 : Session(AuditInfo::current(), server)
282 {
283 ref(); // eternalize
284 mAudit.ai_flags |= attributes; // merge imposed attributes
285 }
286
287
288 //
289 // Accessor method for setting audit session flags.
290 //
291 void Session::setAttributes(SessionAttributeBits bits)
292 {
293 StLock<Mutex> _(*this);
294 updateAudit();
295 // assert((bits & ~settableAttributes) == 0);
296 mAudit.ai_flags = bits;
297 mAudit.set();
298 }
299
300 //
301 // The default session setup operation always fails.
302 // Subclasses can override this to support session setup calls.
303 //
304 void Session::setupAttributes(SessionCreationFlags flags, SessionAttributeBits attrs)
305 {
306 MacOSError::throwMe(errSessionAuthorizationDenied);
307 }
308
309 uid_t Session::originatorUid()
310 {
311 if (mAudit.uid() == AU_DEFAUDITID) {
312 StLock<Mutex> _(*this);
313 updateAudit();
314 }
315 return mAudit.uid();
316 }
317
318
319 RefPointer<AuthHostInstance>
320 Session::authhost(const bool restart)
321 {
322 StLock<Mutex> _(mAuthHostLock);
323
324 if (restart || !mSecurityAgent || (mSecurityAgent->state() != Security::UnixPlusPlus::Child::alive))
325 {
326 if (mSecurityAgent)
327 PerSession::kill(*mSecurityAgent);
328 mSecurityAgent = new AuthHostInstance(*this);
329 }
330 return mSecurityAgent;
331 }
332
333
334 //
335 // Debug dumping
336 //
337 #if defined(DEBUGDUMP)
338
339 void Session::dumpNode()
340 {
341 PerSession::dumpNode();
342 Debug::dump(" auid=%d attrs=%#x securityagent=%p",
343 this->sessionId(), uint32_t(this->attributes()), mSecurityAgent);
344 }
345
346 #endif //DEBUGDUMP