]>
Commit | Line | Data |
---|---|---|
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 | ||
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), mAuthHost(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 | SECURITYD_SESSION_CREATE(this, this->sessionId(), &mAudit, sizeof(mAudit)); | |
79 | Syslog::notice("Session %d created", this->sessionId()); | |
80 | } | |
81 | ||
82 | ||
83 | // | |
84 | // Destroy a Session | |
85 | // | |
86 | Session::~Session() | |
87 | { | |
88 | SECURITYD_SESSION_DESTROY(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 DynamicSession(info); | |
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 | bool unlocked = false; | |
134 | RefPointer<Session> session = NULL; | |
135 | { | |
136 | StLock<Mutex> _(mSessionLock); | |
137 | SessionMap::iterator it = mSessions.find(id); | |
138 | if (it != mSessions.end()) { | |
139 | session = it->second; | |
140 | assert(session->sessionId() == id); | |
141 | mSessions.erase(it); | |
142 | ||
143 | for (SessionMap::iterator kb_it = mSessions.begin(); kb_it != mSessions.end(); kb_it++) { | |
144 | RefPointer<Session> kb_session = kb_it->second; | |
145 | if (kb_session->originatorUid() == session->originatorUid()) { | |
146 | if (kb_session->keybagGetState(session_keybag_unlocked)) unlocked = true; | |
147 | } | |
148 | } | |
149 | } | |
150 | } | |
151 | ||
152 | if (session.get()) { | |
153 | if (!unlocked) { | |
5c19dc3a A |
154 | // sessions are destroy outside of a process request session->get_current_service_context() |
155 | service_context_t context = { session->sessionId(), session->originatorUid(), {} }; | |
d8f41ccd A |
156 | service_client_kb_lock(&context); |
157 | } | |
158 | session->kill(); | |
159 | } | |
160 | } | |
161 | ||
162 | ||
163 | void Session::kill() | |
164 | { | |
165 | StLock<Mutex> _(*this); // do we need to take this so early? | |
166 | SECURITYD_SESSION_KILL(this, this->sessionId()); | |
167 | invalidateSessionAuthHosts(); | |
168 | ||
169 | // invalidate shared credentials | |
170 | { | |
171 | StLock<Mutex> _(mCredsLock); | |
172 | ||
173 | IFDEBUG(if (!mSessionCreds.empty()) | |
174 | secdebug("SSauth", "session %p clearing %d shared credentials", | |
175 | this, int(mSessionCreds.size()))); | |
176 | for (CredentialSet::iterator it = mSessionCreds.begin(); it != mSessionCreds.end(); it++) | |
177 | (*it)->invalidate(); | |
178 | } | |
179 | ||
180 | // base kill processing | |
181 | PerSession::kill(); | |
182 | } | |
183 | ||
184 | ||
185 | // | |
186 | // Refetch audit session data for the current audit session (to catch outside updates | |
187 | // to the audit record). This is the price we're paying for not requiring an IPC to | |
188 | // securityd when audit session data changes (this is desirable for delayering the | |
189 | // software layer cake). | |
190 | // If we ever disallow changes to (parts of the) audit session record in the kernel, | |
191 | // we can loosen up on this continual re-fetching. | |
192 | // | |
193 | void Session::updateAudit() const | |
194 | { | |
195 | CommonCriteria::AuditInfo info; | |
196 | try { | |
197 | info.get(mAudit.sessionId()); | |
198 | } catch (...) { | |
199 | return; | |
200 | } | |
201 | mAudit = info; | |
202 | } | |
203 | ||
204 | void Session::verifyKeyStorePassphrase(int32_t retries) | |
205 | { | |
206 | QueryKeybagPassphrase keybagQuery(*this, retries); | |
207 | keybagQuery.inferHints(Server::process()); | |
208 | if (keybagQuery.query() != SecurityAgent::noReason) { | |
209 | CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED); | |
210 | } | |
211 | } | |
212 | ||
213 | void Session::changeKeyStorePassphrase() | |
214 | { | |
215 | service_context_t context = get_current_service_context(); | |
216 | QueryKeybagNewPassphrase keybagQuery(*this); | |
217 | keybagQuery.inferHints(Server::process()); | |
218 | CssmAutoData pass(Allocator::standard(Allocator::sensitive)); | |
219 | CssmAutoData oldPass(Allocator::standard(Allocator::sensitive)); | |
220 | SecurityAgent::Reason queryReason = keybagQuery.query(oldPass, pass); | |
221 | if (queryReason == SecurityAgent::noReason) { | |
222 | service_client_kb_change_secret(&context, oldPass.data(), (int)oldPass.length(), pass.data(), (int)pass.length()); | |
223 | } else { | |
224 | CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED); | |
225 | } | |
226 | } | |
227 | ||
228 | void Session::resetKeyStorePassphrase(const CssmData &passphrase) | |
229 | { | |
230 | service_context_t context = get_current_service_context(); | |
231 | service_client_kb_reset(&context, passphrase.data(), (int)passphrase.length()); | |
232 | } | |
233 | ||
234 | service_context_t Session::get_current_service_context() | |
235 | { | |
5c19dc3a | 236 | service_context_t context = { sessionId(), originatorUid(), *Server::connection().auditToken() }; |
d8f41ccd A |
237 | return context; |
238 | } | |
239 | ||
240 | void Session::keybagClearState(int state) | |
241 | { | |
242 | mKeybagState &= ~state; | |
243 | } | |
244 | ||
245 | void Session::keybagSetState(int state) | |
246 | { | |
247 | mKeybagState |= state; | |
248 | } | |
249 | ||
250 | bool Session::keybagGetState(int state) | |
251 | { | |
252 | return mKeybagState & state; | |
253 | } | |
254 | ||
255 | ||
256 | // | |
257 | // Manage authorization client processes | |
258 | // | |
259 | void Session::invalidateSessionAuthHosts() | |
260 | { | |
261 | StLock<Mutex> _(mAuthHostLock); | |
262 | ||
263 | // if you got here, we don't care about pending operations: the auth hosts die | |
264 | Syslog::warning("Killing auth hosts"); | |
265 | if (mSecurityAgent) mSecurityAgent->UnixPlusPlus::Child::kill(SIGTERM); | |
266 | if (mAuthHost) mAuthHost->UnixPlusPlus::Child::kill(SIGTERM); | |
267 | mSecurityAgent = NULL; | |
268 | mAuthHost = NULL; | |
269 | } | |
270 | ||
271 | void Session::invalidateAuthHosts() | |
272 | { | |
273 | StLock<Mutex> _(mSessionLock); | |
274 | for (SessionMap::const_iterator it = mSessions.begin(); it != mSessions.end(); it++) | |
275 | it->second->invalidateSessionAuthHosts(); | |
276 | } | |
277 | ||
278 | // | |
279 | // On system sleep, call sleepProcessing on all DbCommons of all Sessions | |
280 | // | |
281 | void Session::processSystemSleep() | |
282 | { | |
283 | SecurityAgentXPCQuery::killAllXPCClients(); | |
284 | ||
285 | StLock<Mutex> _(mSessionLock); | |
286 | for (SessionMap::const_iterator it = mSessions.begin(); it != mSessions.end(); it++) | |
287 | it->second->allReferences(&DbCommon::sleepProcessing); | |
288 | } | |
289 | ||
290 | ||
291 | // | |
292 | // On "lockAll", call sleepProcessing on all DbCommons of this session (only) | |
293 | // | |
294 | void Session::processLockAll() | |
295 | { | |
296 | allReferences(&DbCommon::lockProcessing); | |
297 | } | |
298 | ||
299 | ||
300 | // | |
301 | // The root session corresponds to the audit session that security is running in. | |
302 | // This is usually the initial system session; but in debug scenarios it may be | |
303 | // an "ordinary" graphic login session. In such a debug case, we may add attribute | |
304 | // flags to the session to make our (debugging) life easier. | |
305 | // | |
306 | RootSession::RootSession(uint64_t attributes, Server &server) | |
307 | : Session(AuditInfo::current(), server) | |
308 | { | |
309 | ref(); // eternalize | |
310 | mAudit.ai_flags |= attributes; // merge imposed attributes | |
311 | } | |
312 | ||
313 | ||
314 | // | |
315 | // Dynamic sessions use the audit session context of the first-contact client caller. | |
316 | // | |
317 | DynamicSession::DynamicSession(const AuditInfo &audit) | |
318 | : Session(audit, Server::active()) | |
319 | { | |
320 | } | |
321 | ||
322 | ||
323 | // | |
324 | // Authorization operations | |
325 | // | |
326 | OSStatus Session::authCreate(const AuthItemSet &rights, | |
327 | const AuthItemSet &environment, | |
328 | AuthorizationFlags flags, | |
329 | AuthorizationBlob &newHandle, | |
330 | const audit_token_t &auditToken) | |
331 | { | |
332 | // invoke the authorization computation engine | |
333 | CredentialSet resultCreds; | |
334 | ||
335 | // this will acquire the object lock, so we delay acquiring it (@@@ no longer needed) | |
336 | auto_ptr<AuthorizationToken> auth(new AuthorizationToken(*this, resultCreds, auditToken, (flags&kAuthorizationFlagLeastPrivileged))); | |
337 | ||
338 | SECURITYD_AUTH_CREATE(this, auth.get()); | |
339 | ||
340 | // Make a copy of the mSessionCreds | |
341 | CredentialSet sessionCreds; | |
342 | { | |
343 | StLock<Mutex> _(mCredsLock); | |
344 | sessionCreds = mSessionCreds; | |
345 | } | |
346 | ||
347 | AuthItemSet outRights; | |
348 | OSStatus result = Server::authority().authorize(rights, environment, flags, | |
349 | &sessionCreds, &resultCreds, outRights, *auth); | |
350 | newHandle = auth->handle(); | |
351 | ||
352 | // merge resulting creds into shared pool | |
353 | if ((flags & kAuthorizationFlagExtendRights) && | |
354 | !(flags & kAuthorizationFlagDestroyRights)) | |
355 | { | |
356 | StLock<Mutex> _(mCredsLock); | |
357 | mergeCredentials(resultCreds); | |
358 | auth->mergeCredentials(resultCreds); | |
359 | } | |
360 | ||
361 | // Make sure that this isn't done until the auth(AuthorizationToken) is guaranteed to | |
362 | // not be destroyed anymore since it's destructor asserts it has no processes | |
363 | Server::process().addAuthorization(auth.get()); | |
364 | auth.release(); | |
365 | return result; | |
366 | } | |
367 | ||
368 | void Session::authFree(const AuthorizationBlob &authBlob, AuthorizationFlags flags) | |
369 | { | |
370 | AuthorizationToken::Deleter deleter(authBlob); | |
371 | AuthorizationToken &auth = deleter; | |
372 | Process &process = Server::process(); | |
373 | process.checkAuthorization(&auth); | |
374 | ||
375 | if (flags & kAuthorizationFlagDestroyRights) { | |
376 | // explicitly invalidate all shared credentials and remove them from the session | |
377 | for (CredentialSet::const_iterator it = auth.begin(); it != auth.end(); it++) | |
378 | if ((*it)->isShared()) | |
379 | (*it)->invalidate(); | |
380 | } | |
381 | ||
382 | // now get rid of the authorization itself | |
383 | if (process.removeAuthorization(&auth)) | |
384 | deleter.remove(); | |
385 | } | |
386 | ||
387 | OSStatus Session::authGetRights(const AuthorizationBlob &authBlob, | |
388 | const AuthItemSet &rights, const AuthItemSet &environment, | |
389 | AuthorizationFlags flags, | |
390 | AuthItemSet &grantedRights) | |
391 | { | |
392 | AuthorizationToken &auth = authorization(authBlob); | |
393 | return auth.session().authGetRights(auth, rights, environment, flags, grantedRights); | |
394 | } | |
395 | ||
396 | OSStatus Session::authGetRights(AuthorizationToken &auth, | |
397 | const AuthItemSet &rights, const AuthItemSet &environment, | |
398 | AuthorizationFlags flags, | |
399 | AuthItemSet &grantedRights) | |
400 | { | |
401 | CredentialSet resultCreds; | |
402 | CredentialSet effective; | |
403 | { | |
404 | StLock<Mutex> _(mCredsLock); | |
405 | effective = auth.effectiveCreds(); | |
406 | } | |
407 | OSStatus result = Server::authority().authorize(rights, environment, flags, | |
408 | &effective, &resultCreds, grantedRights, auth); | |
409 | ||
410 | // merge resulting creds into shared pool | |
411 | if ((flags & kAuthorizationFlagExtendRights) && !(flags & kAuthorizationFlagDestroyRights)) | |
412 | { | |
413 | StLock<Mutex> _(mCredsLock); | |
414 | mergeCredentials(resultCreds); | |
415 | auth.mergeCredentials(resultCreds); | |
416 | } | |
417 | ||
418 | secdebug("SSauth", "Authorization %p copyRights asked for %d got %d", | |
419 | &auth, int(rights.size()), int(grantedRights.size())); | |
420 | return result; | |
421 | } | |
422 | ||
423 | OSStatus Session::authGetInfo(const AuthorizationBlob &authBlob, | |
424 | const char *tag, | |
425 | AuthItemSet &contextInfo) | |
426 | { | |
427 | AuthorizationToken &auth = authorization(authBlob); | |
428 | secdebug("SSauth", "Authorization %p get-info", &auth); | |
429 | contextInfo = auth.infoSet(tag); | |
430 | return noErr; | |
431 | } | |
432 | ||
433 | OSStatus Session::authExternalize(const AuthorizationBlob &authBlob, | |
434 | AuthorizationExternalForm &extForm) | |
435 | { | |
436 | const AuthorizationToken &auth = authorization(authBlob); | |
437 | StLock<Mutex> _(*this); | |
438 | if (auth.mayExternalize(Server::process())) { | |
439 | memset(&extForm, 0, sizeof(extForm)); | |
440 | AuthorizationExternalBlob &extBlob = | |
441 | reinterpret_cast<AuthorizationExternalBlob &>(extForm); | |
442 | extBlob.blob = auth.handle(); | |
443 | extBlob.session = this->sessionId(); | |
444 | secdebug("SSauth", "Authorization %p externalized", &auth); | |
445 | return noErr; | |
446 | } else | |
447 | return errAuthorizationExternalizeNotAllowed; | |
448 | } | |
449 | ||
450 | OSStatus Session::authInternalize(const AuthorizationExternalForm &extForm, | |
451 | AuthorizationBlob &authBlob) | |
452 | { | |
453 | // interpret the external form | |
454 | const AuthorizationExternalBlob &extBlob = | |
455 | reinterpret_cast<const AuthorizationExternalBlob &>(extForm); | |
456 | ||
457 | // locate source authorization | |
458 | AuthorizationToken &sourceAuth = AuthorizationToken::find(extBlob.blob); | |
459 | ||
460 | // check for permission and do it | |
461 | if (sourceAuth.mayInternalize(Server::process(), true)) { | |
462 | StLock<Mutex> _(*this); | |
463 | authBlob = extBlob.blob; | |
464 | Server::process().addAuthorization(&sourceAuth); | |
465 | secdebug("SSauth", "Authorization %p internalized", &sourceAuth); | |
466 | return noErr; | |
467 | } else | |
468 | return errAuthorizationInternalizeNotAllowed; | |
469 | } | |
470 | ||
471 | ||
472 | // | |
473 | // Accessor method for setting audit session flags. | |
474 | // | |
475 | void Session::setAttributes(SessionAttributeBits bits) | |
476 | { | |
477 | StLock<Mutex> _(*this); | |
478 | updateAudit(); | |
479 | // assert((bits & ~settableAttributes) == 0); | |
480 | mAudit.ai_flags = bits; | |
481 | mAudit.set(); | |
482 | } | |
483 | ||
484 | // | |
485 | // The default session setup operation always fails. | |
486 | // Subclasses can override this to support session setup calls. | |
487 | // | |
488 | void Session::setupAttributes(SessionCreationFlags flags, SessionAttributeBits attrs) | |
489 | { | |
490 | MacOSError::throwMe(errSessionAuthorizationDenied); | |
491 | } | |
492 | ||
493 | uid_t Session::originatorUid() | |
494 | { | |
495 | if (mAudit.uid() == AU_DEFAUDITID) { | |
496 | StLock<Mutex> _(*this); | |
497 | updateAudit(); | |
498 | } | |
499 | return mAudit.uid(); | |
500 | } | |
501 | ||
502 | // | |
503 | // Authorization database I/O | |
504 | // | |
505 | OSStatus Session::authorizationdbGet(AuthorizationString inRightName, CFDictionaryRef *rightDict) | |
506 | { | |
507 | string rightName(inRightName); | |
508 | return Server::authority().getRule(rightName, rightDict); | |
509 | } | |
510 | ||
511 | ||
512 | OSStatus Session::authorizationdbSet(const AuthorizationBlob &authBlob, AuthorizationString inRightName, CFDictionaryRef rightDict) | |
513 | { | |
514 | CredentialSet resultCreds; | |
515 | AuthorizationToken &auth = authorization(authBlob); | |
516 | CredentialSet effective; | |
517 | ||
518 | { | |
519 | StLock<Mutex> _(mCredsLock); | |
520 | effective = auth.effectiveCreds(); | |
521 | } | |
522 | ||
523 | OSStatus result = Server::authority().setRule(inRightName, rightDict, &effective, &resultCreds, auth); | |
524 | ||
525 | { | |
526 | StLock<Mutex> _(mCredsLock); | |
527 | mergeCredentials(resultCreds); | |
528 | auth.mergeCredentials(resultCreds); | |
529 | } | |
530 | ||
531 | secdebug("SSauth", "Authorization %p authorizationdbSet %s (result=%d)", | |
532 | &authorization(authBlob), inRightName, int32_t(result)); | |
533 | return result; | |
534 | } | |
535 | ||
536 | ||
537 | OSStatus Session::authorizationdbRemove(const AuthorizationBlob &authBlob, AuthorizationString inRightName) | |
538 | { | |
539 | CredentialSet resultCreds; | |
540 | AuthorizationToken &auth = authorization(authBlob); | |
541 | CredentialSet effective; | |
542 | ||
543 | { | |
544 | StLock<Mutex> _(mCredsLock); | |
545 | effective = auth.effectiveCreds(); | |
546 | } | |
547 | ||
548 | OSStatus result = Server::authority().removeRule(inRightName, &effective, &resultCreds, auth); | |
549 | ||
550 | { | |
551 | StLock<Mutex> _(mCredsLock); | |
552 | mergeCredentials(resultCreds); | |
553 | auth.mergeCredentials(resultCreds); | |
554 | } | |
555 | ||
556 | secdebug("SSauth", "Authorization %p authorizationdbRemove %s (result=%d)", | |
557 | &authorization(authBlob), inRightName, int32_t(result)); | |
558 | return result; | |
559 | } | |
560 | ||
561 | ||
562 | // | |
563 | // Merge a set of credentials into the shared-session credential pool | |
564 | // | |
565 | // must hold mCredsLock | |
566 | void Session::mergeCredentials(CredentialSet &creds) | |
567 | { | |
568 | secdebug("SSsession", "%p merge creds @%p", this, &creds); | |
569 | CredentialSet updatedCredentials = creds; | |
570 | for (CredentialSet::const_iterator it = creds.begin(); it != creds.end(); it++) | |
571 | if ((*it)->isShared() && (*it)->isValid()) { | |
572 | CredentialSet::iterator old = mSessionCreds.find(*it); | |
573 | if (old == mSessionCreds.end()) { | |
574 | mSessionCreds.insert(*it); | |
575 | } else { | |
576 | // replace "new" with "old" in input set to retain synchronization | |
577 | (*old)->merge(**it); | |
578 | updatedCredentials.erase(*it); | |
579 | updatedCredentials.insert(*old); | |
580 | } | |
581 | } | |
582 | creds.swap(updatedCredentials); | |
583 | } | |
584 | ||
585 | ||
586 | // | |
587 | // Locate an AuthorizationToken given a blob | |
588 | // | |
589 | AuthorizationToken &Session::authorization(const AuthorizationBlob &blob) | |
590 | { | |
591 | AuthorizationToken &auth = AuthorizationToken::find(blob); | |
592 | Server::process().checkAuthorization(&auth); | |
593 | return auth; | |
594 | } | |
595 | ||
596 | // | |
597 | // Run the Authorization engine to check if a given right has been authorized, | |
598 | // independent of an external client request. | |
599 | // | |
600 | OSStatus Session::authCheckRight(string &rightName, Connection &connection, bool allowUI) | |
601 | { | |
602 | // dummy up the arguments for authCreate() | |
603 | AuthorizationItem rightItem = { rightName.c_str(), 0, NULL, 0 }; | |
604 | AuthorizationItemSet rightItemSet = { 1, &rightItem }; | |
605 | AuthItemSet rightAuthItemSet(&rightItemSet); | |
606 | AuthItemSet envAuthItemSet(kAuthorizationEmptyEnvironment); | |
607 | AuthorizationFlags flags = kAuthorizationFlagDefaults | kAuthorizationFlagExtendRights; | |
608 | if (true == allowUI) | |
609 | flags |= kAuthorizationFlagInteractionAllowed; | |
610 | AuthorizationBlob dummyHandle; | |
611 | const audit_token_t *at = connection.auditToken(); | |
612 | ||
613 | return authCreate(rightAuthItemSet, envAuthItemSet, flags, dummyHandle, *at); | |
614 | } | |
615 | ||
616 | // for places within securityd that don't want to #include | |
617 | // <libsecurity_authorization/Authorization.h> or to fuss about exceptions | |
618 | bool Session::isRightAuthorized(string &rightName, Connection &connection, bool allowUI) | |
619 | { | |
620 | bool isAuthorized = false; | |
621 | ||
622 | try { | |
623 | OSStatus status = authCheckRight(rightName, connection, allowUI); | |
624 | if (errAuthorizationSuccess == status) | |
625 | isAuthorized = true; | |
626 | } | |
627 | catch (...) { | |
628 | } | |
629 | return isAuthorized; | |
630 | } | |
631 | ||
632 | RefPointer<AuthHostInstance> | |
633 | Session::authhost(const AuthHostType hostType, const bool restart) | |
634 | { | |
635 | StLock<Mutex> _(mAuthHostLock); | |
636 | ||
637 | if (hostType == privilegedAuthHost) | |
638 | { | |
639 | if (restart || !mAuthHost || (mAuthHost->state() != Security::UnixPlusPlus::Child::alive)) | |
640 | { | |
641 | if (mAuthHost) | |
642 | PerSession::kill(*mAuthHost); | |
643 | mAuthHost = new AuthHostInstance(*this, hostType); | |
644 | } | |
645 | return mAuthHost; | |
646 | } | |
647 | else /* if (hostType == securityAgent) */ | |
648 | { | |
649 | if (restart || !mSecurityAgent || (mSecurityAgent->state() != Security::UnixPlusPlus::Child::alive)) | |
650 | { | |
651 | if (mSecurityAgent) | |
652 | PerSession::kill(*mSecurityAgent); | |
653 | mSecurityAgent = new AuthHostInstance(*this, hostType); | |
654 | } | |
655 | return mSecurityAgent; | |
656 | } | |
657 | } | |
658 | ||
659 | void DynamicSession::setUserPrefs(CFDataRef userPrefsDict) | |
660 | { | |
661 | if (Server::process().uid() != 0) | |
662 | MacOSError::throwMe(errSessionAuthorizationDenied); | |
663 | StLock<Mutex> _(*this); | |
664 | mSessionAgentPrefs = userPrefsDict; | |
665 | } | |
666 | ||
667 | CFDataRef DynamicSession::copyUserPrefs() | |
668 | { | |
669 | StLock<Mutex> _(*this); | |
670 | if (mSessionAgentPrefs) | |
671 | CFRetain(mSessionAgentPrefs); | |
672 | return mSessionAgentPrefs; | |
673 | } | |
674 | ||
675 | ||
676 | // | |
677 | // Debug dumping | |
678 | // | |
679 | #if defined(DEBUGDUMP) | |
680 | ||
681 | void Session::dumpNode() | |
682 | { | |
683 | PerSession::dumpNode(); | |
684 | Debug::dump(" auid=%d attrs=%#x authhost=%p securityagent=%p", | |
685 | this->sessionId(), uint32_t(this->attributes()), mAuthHost, mSecurityAgent); | |
686 | } | |
687 | ||
688 | #endif //DEBUGDUMP |