]> git.saurik.com Git - apple/securityd.git/blob - src/AuthorizationMechEval.cpp
securityd-55137.1.tar.gz
[apple/securityd.git] / src / AuthorizationMechEval.cpp
1 /*
2 * Copyright (c) 2003-2004,2008-2009 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 * AuthorizationMechEval.cpp
24 * securityd
25 *
26 */
27 #include "AuthorizationMechEval.h"
28 #include <security_utilities/logging.h>
29 #include <bsm/audit_uevents.h>
30 #include "ccaudit_extensions.h"
31
32 namespace Authorization {
33
34 using namespace CommonCriteria::Securityd;
35
36 AgentMechanismRef::AgentMechanismRef(const AuthHostType type, Session &session) :
37 RefPointer<QueryInvokeMechanism>(new QueryInvokeMechanism(type, session)) {}
38
39 // we need the vector<string> of mechanisms
40 AgentMechanismEvaluator::AgentMechanismEvaluator(uid_t uid, Session& session, const vector<string>& inMechanisms) :
41 mMechanisms(inMechanisms), mClientUid(uid), mSession(session)
42 {
43 //set up environment
44 }
45
46 OSStatus
47 AgentMechanismEvaluator::run(const AuthValueVector &inArguments, const AuthItemSet &inHints, const AuthorizationToken &auth)
48 {
49 AuthMechLogger logger(auth.creatorAuditToken(), AUE_ssauthmech);
50 string rightName = "<unknown right>"; // for syslog
51
52 // as of 10.6, the first item in inArguments should be the name of the
53 // requested right, for auditing
54 try
55 {
56 AuthorizationValue val = inArguments.at(0)->value();
57 string tmpstr(static_cast<const char *>(val.data), val.length);
58 logger.setRight(tmpstr);
59 rightName.clear();
60 rightName = tmpstr;
61 }
62 catch (...) { }
63
64 const AuthItemSet &inContext = const_cast<AuthorizationToken &>(auth).infoSet();
65
66 // add process specifics to context?
67
68 vector<std::string>::const_iterator currentMechanism = mMechanisms.begin();
69
70 AuthorizationResult result = kAuthorizationResultAllow;
71
72 AuthItemSet hints = inHints;
73 AuthItemSet context = inContext;
74 // add saved-off sticky context values to context for evaluation
75 context.insert(mStickyContext.begin(), mStickyContext.end());
76
77 while ( (result == kAuthorizationResultAllow) &&
78 (currentMechanism != mMechanisms.end()) ) // iterate mechanisms
79 {
80 SECURITYD_AUTH_MECH(&auth, (char *)(*currentMechanism).c_str());
81
82 // set up the audit message
83 logger.setCurrentMechanism(*currentMechanism);
84
85 // do the real work
86 ClientMap::iterator iter = mClients.find(*currentMechanism);
87 if (iter == mClients.end())
88 {
89 string::size_type extPlugin = currentMechanism->find(':');
90 if (extPlugin != string::npos)
91 {
92 // no whitespace removal
93 string pluginIn(currentMechanism->substr(0, extPlugin));
94 string mechanismIn, authhostIn;
95
96 string::size_type extMechanism = currentMechanism->rfind(',');
97 AuthHostType hostType = securityAgent;
98
99 if (extMechanism != string::npos)
100 {
101 if (extMechanism < extPlugin)
102 {
103 string auditMsg = "badly formed mechanism name; ending rule evaluation";
104 Syslog::alert("Right '%s', mech '%s': %s", rightName.c_str(), (*currentMechanism).c_str(), auditMsg.c_str());
105 logger.logFailure(auditMsg);
106 return errAuthorizationInternal;
107 }
108
109 mechanismIn = currentMechanism->substr(extPlugin + 1, extMechanism - extPlugin - 1);
110 authhostIn = currentMechanism->substr(extMechanism + 1);
111 if (authhostIn == "privileged")
112 hostType = privilegedAuthHost;
113 }
114 else
115 mechanismIn = currentMechanism->substr(extPlugin + 1);
116
117 secdebug("AuthEvalMech", "external mechanism %s:%s", pluginIn.c_str(), mechanismIn.c_str());
118
119 AgentMechanismRef client(hostType, mSession);
120 client->initialize(pluginIn, mechanismIn, inArguments);
121 mClients.insert(ClientMap::value_type(*currentMechanism, client));
122 }
123 else if (*currentMechanism == "authinternal")
124 {
125 secdebug("AuthEvalMech", "performing authentication");
126 result = authinternal(context);
127
128 if (kAuthorizationResultAllow == result)
129 {
130 logger.logSuccess();
131 }
132 else // kAuthorizationResultDeny
133 {
134 logger.logFailure();
135 }
136 }
137 else if (*currentMechanism == "push_hints_to_context")
138 {
139 secdebug("AuthEvalMech", "evaluate push_hints_to_context");
140 logger.logSuccess();
141 // doesn't block evaluation, ever
142 result = kAuthorizationResultAllow;
143 context = hints;
144 }
145 else
146 {
147 string auditMsg = "unknown mechanism; ending rule evaluation";
148 Syslog::alert("Right '%s', mech '%s': %s", rightName.c_str(), (*currentMechanism).c_str(), auditMsg.c_str());
149 logger.logFailure(auditMsg);
150 return errAuthorizationInternal;
151 }
152 }
153
154 iter = mClients.find(*currentMechanism);
155 if (iter != mClients.end())
156 {
157 try
158 {
159 AgentMechanismRef &client = iter->second;
160 client->run(inArguments, hints, context, &result);
161
162 bool interrupted = false;
163 while (client->state() == client->current)
164 {
165 // check for interruption
166 vector<std::string>::const_iterator checkMechanism = mMechanisms.begin();
167 while (*checkMechanism != *currentMechanism) {
168 ClientMap::iterator iter2 = mClients.find(*checkMechanism);
169 if (iter2->second->state() == iter2->second->interrupting)
170 {
171 client->deactivate();
172 // nothing can happen until the client mechanism returns control to us
173 while (client->state() == client->deactivating)
174 client->receive();
175
176 string auditMsg = "evaluation interrupted by ";
177 auditMsg += (iter2->first).c_str();
178 auditMsg += "; restarting evaluation there";
179 secdebug("AuthEvalMech", "%s", auditMsg.c_str());
180 logger.logInterrupt(auditMsg);
181
182 interrupted = true;
183 hints = iter2->second->inHints();
184 context = iter2->second->inContext();
185 currentMechanism = checkMechanism;
186 break;
187 }
188 else
189 checkMechanism++;
190 }
191 if (client->state() == client->current)
192 client->receive();
193 }
194
195 if (interrupted)
196 {
197 // clear reason for restart from interrupt
198 uint32_t reason = SecurityAgent::worldChanged;
199 AuthItemRef retryHint(AGENT_HINT_RETRY_REASON, AuthValueOverlay(sizeof(reason), &reason));
200 hints.erase(retryHint); hints.insert(retryHint); // replace
201
202 result = kAuthorizationResultAllow;
203 continue;
204 }
205 else
206 secdebug("AuthEvalMech", "evaluate(%s) with result: %u.", (iter->first).c_str(), (uint32_t)result);
207 }
208 catch (...) {
209 string auditMsg = "exception during evaluation of ";
210 auditMsg += (iter->first).c_str();
211 secdebug("AuthEvalMech", "%s", auditMsg.c_str());
212 logger.logFailure(auditMsg);
213 result = kAuthorizationResultUndefined;
214 }
215 }
216
217 if (result == kAuthorizationResultAllow)
218 {
219 logger.logSuccess();
220 currentMechanism++;
221 }
222 }
223
224 if ((result == kAuthorizationResultUserCanceled) ||
225 (result == kAuthorizationResultAllow))
226 {
227 mHints = hints;
228 mContext.clear();
229 // only make non-sticky context values available externally
230 AuthItemSet::const_iterator end = context.end();
231 for (AuthItemSet::const_iterator it = context.begin(); it != end; ++it) {
232 const AuthItemRef &item = *it;
233 if (item->flags() != kAuthorizationContextFlagSticky)
234 mContext.insert(item);
235 }
236 if (result == kAuthorizationResultUserCanceled)
237 logger.logFailure(NULL, errAuthorizationCanceled);
238 }
239 else if (result == kAuthorizationResultDeny)
240 {
241 // save off sticky values in context
242 mStickyContext.clear();
243 AuthItemSet::const_iterator end = context.end();
244 for (AuthItemSet::const_iterator it = context.begin(); it != end; ++it) {
245 const AuthItemRef &item = *it;
246 if (item->flags() == kAuthorizationContextFlagSticky)
247 mStickyContext.insert(item);
248 }
249 logger.logFailure();
250 }
251
252 // convert AuthorizationResult to OSStatus
253 switch(result)
254 {
255 case kAuthorizationResultDeny:
256 return errAuthorizationDenied;
257 case kAuthorizationResultUserCanceled:
258 return errAuthorizationCanceled;
259 case kAuthorizationResultAllow:
260 return errAuthorizationSuccess;
261 case kAuthorizationResultUndefined:
262 return errAuthorizationInternal;
263 default:
264 {
265 Syslog::alert("Right '%s': unexpected error result (%u)", rightName.c_str(), result);
266 logger.logFailure("unexpected error result", result);
267 return errAuthorizationInternal;
268 }
269 }
270 }
271
272 AuthorizationResult AgentMechanismEvaluator::authinternal(AuthItemSet &context)
273 {
274 secdebug("AuthEvalMech", "evaluate authinternal");
275 do {
276 AuthItemSet::iterator found = find_if(context.begin(), context.end(), FindAuthItemByRightName(kAuthorizationEnvironmentUsername) );
277 if (found == context.end())
278 break;
279 string username(static_cast<const char *>((*found)->value().data), (*found)->value().length);
280 secdebug("AuthEvalMech", "found username");
281 found = find_if(context.begin(), context.end(), FindAuthItemByRightName(kAuthorizationEnvironmentPassword) );
282 if (found == context.end())
283 break;
284 string password(static_cast<const char *>((*found)->value().data), (*found)->value().length);
285 secdebug("AuthEvalMech", "found password");
286
287 Credential newCredential(username, password, true); // create a new shared credential
288 if (newCredential->isValid())
289 return kAuthorizationResultAllow;
290
291 } while (0);
292
293 return kAuthorizationResultDeny;
294 }
295
296 /*
297 AuthItemSet &
298 AgentMechanismEvaluator::commonHints(const AuthorizationToken &auth)
299 {
300
301 }
302 */
303
304 } /* namespace Authorization */