]> git.saurik.com Git - apple/security.git/blob - SecurityServer/Authorization/AuthorizationRule.cpp
Security-179.tar.gz
[apple/security.git] / SecurityServer / Authorization / AuthorizationRule.cpp
1 /*
2 * AuthorizationRule.cpp
3 * Security
4 *
5 * Created by Conrad Sauerwald on Wed Mar 19 2003.
6 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
7 *
8 */
9
10 #include "AuthorizationRule.h"
11 #include "AuthorizationTags.h"
12 #include "AuthorizationDB.h"
13 #include "AuthorizationPriv.h"
14 #include "authority.h"
15 #include "server.h"
16 #include "process.h"
17
18
19 #include <pwd.h>
20 #include <grp.h>
21 #include <unistd.h>
22
23 #include <bsm/libbsm.h>
24 #include <bsm/audit_uevents.h>
25 #include "ccaudit.h"
26
27 //
28 // Rule class
29 //
30 namespace Authorization {
31
32 CFStringRef RuleImpl::kUserGroupID = CFSTR(kAuthorizationRuleParameterGroup);
33 CFStringRef RuleImpl::kTimeoutID = CFSTR(kAuthorizationRuleParameterCredentialTimeout);
34 CFStringRef RuleImpl::kSharedID = CFSTR(kAuthorizationRuleParameterCredentialShared);
35 CFStringRef RuleImpl::kAllowRootID = CFSTR(kAuthorizationRuleParameterAllowRoot);
36 CFStringRef RuleImpl::kMechanismsID = CFSTR(kAuthorizationRuleParameterMechanisms);
37 CFStringRef RuleImpl::kSessionOwnerID = CFSTR(kAuthorizationRuleParameterCredentialSessionOwner);
38 CFStringRef RuleImpl::kKofNID = CFSTR(kAuthorizationRuleParameterKofN);
39 CFStringRef RuleImpl::kPromptID = CFSTR(kAuthorizationRuleParameterDefaultPrompt);
40
41 CFStringRef RuleImpl::kRuleClassID = CFSTR(kAuthorizationRuleClass);
42 CFStringRef RuleImpl::kRuleAllowID = CFSTR(kAuthorizationRuleClassAllow);
43 CFStringRef RuleImpl::kRuleDenyID = CFSTR(kAuthorizationRuleClassDeny);
44 CFStringRef RuleImpl::kRuleUserID = CFSTR(kAuthorizationRuleClassUser);
45 CFStringRef RuleImpl::kRuleDelegateID = CFSTR(kAuthorizationRightRule);
46 CFStringRef RuleImpl::kRuleMechanismsID = CFSTR(kAuthorizationRuleClassMechanisms);
47
48
49 string
50 RuleImpl::Attribute::getString(CFDictionaryRef config, CFStringRef key, bool required = false, char *defaultValue = NULL)
51 {
52 CFTypeRef value = CFDictionaryGetValue(config, key);
53 if (value && (CFGetTypeID(value) == CFStringGetTypeID()))
54 {
55 CFStringRef stringValue = reinterpret_cast<CFStringRef>(value);
56 char buffer[512];
57 const char *ptr = CFStringGetCStringPtr(stringValue, kCFStringEncodingUTF8);
58 if (ptr == NULL)
59 {
60 if (CFStringGetCString(stringValue, buffer, sizeof(buffer), kCFStringEncodingUTF8))
61 ptr = buffer;
62 else
63 MacOSError::throwMe(errAuthorizationInternal); // XXX/cs invalid rule
64 }
65
66 return string(ptr);
67 }
68 else
69 if (!required)
70 return string(defaultValue);
71 else
72 MacOSError::throwMe(errAuthorizationInternal); // XXX/cs invalid rule
73 }
74
75 double
76 RuleImpl::Attribute::getDouble(CFDictionaryRef config, CFStringRef key, bool required = false, double defaultValue = 0.0)
77 {
78 double doubleValue = 0;
79
80 CFTypeRef value = CFDictionaryGetValue(config, key);
81 if (value && (CFGetTypeID(value) == CFNumberGetTypeID()))
82 {
83 CFNumberGetValue(reinterpret_cast<CFNumberRef>(value), kCFNumberDoubleType, &doubleValue);
84 }
85 else
86 if (!required)
87 return defaultValue;
88 else
89 MacOSError::throwMe(errAuthorizationInternal); // XXX/cs invalid rule
90
91 return doubleValue;
92 }
93
94 bool
95 RuleImpl::Attribute::getBool(CFDictionaryRef config, CFStringRef key, bool required = false, bool defaultValue = false)
96 {
97 bool boolValue = false;
98 CFTypeRef value = CFDictionaryGetValue(config, key);
99
100 if (value && (CFGetTypeID(value) == CFBooleanGetTypeID()))
101 {
102 boolValue = CFBooleanGetValue(reinterpret_cast<CFBooleanRef>(value));
103 }
104 else
105 if (!required)
106 return defaultValue;
107 else
108 MacOSError::throwMe(errAuthorizationInternal); // XXX/cs invalid rule
109
110 return boolValue;
111 }
112
113 // add reference to string that we're modifying
114 void
115 RuleImpl::Attribute::setString(CFMutableDictionaryRef config, CFStringRef key, string &value)
116 {
117 CFStringRef cfstringValue = CFStringCreateWithCString(NULL /*allocator*/, value.c_str(), kCFStringEncodingUTF8);
118
119 if (cfstringValue)
120 {
121 CFDictionarySetValue(config, key, cfstringValue);
122 CFRelease(cfstringValue);
123 }
124 else
125 MacOSError::throwMe(errAuthorizationInternal); // XXX/cs invalid attribute
126 }
127
128 void
129 RuleImpl::Attribute::setDouble(CFMutableDictionaryRef config, CFStringRef key, double value)
130 {
131 CFNumberRef doubleValue = CFNumberCreate(NULL /*allocator*/, kCFNumberDoubleType, doubleValue);
132
133 if (doubleValue)
134 {
135 CFDictionarySetValue(config, key, doubleValue);
136 CFRelease(doubleValue);
137 }
138 else
139 MacOSError::throwMe(errAuthorizationInternal); // XXX/cs invalid attribute
140 }
141
142 void
143 RuleImpl::Attribute::setBool(CFMutableDictionaryRef config, CFStringRef key, bool value)
144 {
145 if (value)
146 CFDictionarySetValue(config, key, kCFBooleanTrue);
147 else
148 CFDictionarySetValue(config, key, kCFBooleanFalse);
149 }
150
151 vector<string>
152 RuleImpl::Attribute::getVector(CFDictionaryRef config, CFStringRef key, bool required = false)
153 {
154 vector<string> valueArray;
155
156 CFTypeRef value = CFDictionaryGetValue(config, key);
157 if (value && (CFGetTypeID(value) == CFArrayGetTypeID()))
158 {
159 CFArrayRef evalArray = reinterpret_cast<CFArrayRef>(value);
160
161 for (int index=0; index < CFArrayGetCount(evalArray); index++)
162 {
163 CFTypeRef arrayValue = CFArrayGetValueAtIndex(evalArray, index);
164 if (arrayValue && (CFGetTypeID(arrayValue) == CFStringGetTypeID()))
165 {
166 CFStringRef stringValue = reinterpret_cast<CFStringRef>(arrayValue);
167 char buffer[512];
168 const char *ptr = CFStringGetCStringPtr(stringValue, kCFStringEncodingUTF8);
169 if (ptr == NULL)
170 {
171 if (CFStringGetCString(stringValue, buffer, sizeof(buffer), kCFStringEncodingUTF8))
172 ptr = buffer;
173 else
174 MacOSError::throwMe(errAuthorizationInternal); // XXX/cs invalid rule
175 }
176 valueArray.push_back(string(ptr));
177 }
178 }
179 }
180 else
181 if (required)
182 MacOSError::throwMe(errAuthorizationInternal); // XXX/cs invalid rule
183
184 return valueArray;
185 }
186
187
188 bool RuleImpl::Attribute::getLocalizedPrompts(CFDictionaryRef config, map<string,string> &localizedPrompts)
189 {
190 CFIndex numberOfPrompts = 0;
191 CFDictionaryRef promptsDict;
192 if (CFDictionaryContainsKey(config, kPromptID))
193 {
194 promptsDict = reinterpret_cast<CFDictionaryRef>(CFDictionaryGetValue(config, kPromptID));
195 if (promptsDict && (CFGetTypeID(promptsDict) == CFDictionaryGetTypeID()))
196 numberOfPrompts = CFDictionaryGetCount(promptsDict);
197 }
198 if (numberOfPrompts == 0)
199 return false;
200
201 const void *keys[numberOfPrompts+1];
202 const void *values[numberOfPrompts+1];
203 CFDictionaryGetKeysAndValues(promptsDict, &keys[0], &values[0]);
204
205 while (numberOfPrompts-- > 0)
206 {
207 CFStringRef keyRef = reinterpret_cast<CFStringRef>(keys[numberOfPrompts]);
208 CFStringRef valueRef = reinterpret_cast<CFStringRef>(values[numberOfPrompts]);
209 if (!keyRef || (CFGetTypeID(keyRef) != CFStringGetTypeID()))
210 continue;
211 if (!valueRef || (CFGetTypeID(valueRef) != CFStringGetTypeID()))
212 continue;
213 string key = cfString(keyRef);
214 string value = cfString(valueRef);
215 localizedPrompts["description"+key] = value;
216 }
217
218 return true;
219 }
220
221
222 // default rule
223 RuleImpl::RuleImpl() :
224 mType(kUser), mGroupName("admin"), mMaxCredentialAge(300.0), mShared(true), mAllowRoot(false), mSessionOwner(false), mTries(0)
225 {
226 // XXX/cs read default descriptions from somewhere
227 // @@@ Default rule is shared admin group with 5 minute timeout
228 }
229
230 // return rule built from rule definition; throw if invalid.
231 RuleImpl::RuleImpl(const string &inRightName, CFDictionaryRef cfRight, CFDictionaryRef cfRules) : mRightName(inRightName)
232 {
233 // @@@ make sure cfRight is non mutable and never used that way
234
235 if (CFGetTypeID(cfRight) != CFDictionaryGetTypeID())
236 MacOSError::throwMe(errAuthorizationInternal); // XXX/cs invalid rule
237
238 mTries = 0;
239
240 string classTag = Attribute::getString(cfRight, kRuleClassID, false, "");
241
242 if (classTag.length())
243 {
244 if (classTag == kAuthorizationRuleClassAllow)
245 {
246 secdebug("authrule", "%s : rule allow", inRightName.c_str());
247 mType = kAllow;
248 }
249 else if (classTag == kAuthorizationRuleClassDeny)
250 {
251 secdebug("authrule", "%s : rule deny", inRightName.c_str());
252 mType = kDeny;
253 }
254 else if (classTag == kAuthorizationRuleClassUser)
255 {
256 mType = kUser;
257 mGroupName = Attribute::getString(cfRight, kUserGroupID);
258 // grab other user-in-group attributes
259 mMaxCredentialAge = Attribute::getDouble(cfRight, kTimeoutID, false, DBL_MAX);
260 mShared = Attribute::getBool(cfRight, kSharedID);
261 mAllowRoot = Attribute::getBool(cfRight, kAllowRootID);
262 mSessionOwner = Attribute::getBool(cfRight, kSessionOwnerID);
263 // authorization tags can have eval now too
264 mEvalDef = Attribute::getVector(cfRight, kMechanismsID);
265 mTries = 3;
266
267 secdebug("authrule", "%s : rule user in group \"%s\" timeout %g%s%s",
268 inRightName.c_str(),
269 mGroupName.c_str(), mMaxCredentialAge, mShared ? " shared" : "",
270 mAllowRoot ? " allow-root" : "");
271
272 }
273 else if (classTag == kAuthorizationRuleClassMechanisms)
274 {
275 secdebug("authrule", "%s : rule evaluate mechanisms", inRightName.c_str());
276 mType = kEvaluateMechanisms;
277 // mechanisms to evaluate
278 mEvalDef = Attribute::getVector(cfRight, kMechanismsID, true);
279 }
280 else if (classTag == kAuthorizationRightRule)
281 {
282 assert(cfRules); // this had better not be a rule
283 secdebug("authrule", "%s : rule delegate rule", inRightName.c_str());
284 mType = kRuleDelegation;
285
286 // string or
287 string ruleDefString = Attribute::getString(cfRight, kRuleDelegateID, false, "");
288 if (ruleDefString.length())
289 {
290 CFStringRef ruleDefRef = makeCFString(ruleDefString);
291 CFDictionaryRef cfRuleDef = reinterpret_cast<CFDictionaryRef>(CFDictionaryGetValue(cfRules, ruleDefRef));
292 if (ruleDefRef)
293 CFRelease(ruleDefRef);
294 if (!cfRuleDef || CFGetTypeID(cfRuleDef) != CFDictionaryGetTypeID())
295 MacOSError::throwMe(errAuthorizationInternal); // XXX/cs invalid rule
296 mRuleDef.push_back(Rule(ruleDefString, cfRuleDef, NULL));
297 }
298 else // array
299 {
300 vector<string> ruleDef = Attribute::getVector(cfRight, kRuleDelegateID, true);
301 for (vector<string>::const_iterator it = ruleDef.begin(); it != ruleDef.end(); it++)
302 {
303 CFStringRef ruleNameRef = makeCFString(*it);
304 CFDictionaryRef cfRuleDef = reinterpret_cast<CFDictionaryRef>(CFDictionaryGetValue(cfRules, ruleNameRef));
305 if (ruleNameRef)
306 CFRelease(ruleNameRef);
307 if (!cfRuleDef || (CFGetTypeID(cfRuleDef) != CFDictionaryGetTypeID()))
308 MacOSError::throwMe(errAuthorizationInternal); // XXX/cs invalid rule
309 mRuleDef.push_back(Rule(*it, cfRuleDef, NULL));
310 }
311 }
312
313 mKofN = int(Attribute::getDouble(cfRight, kKofNID, false, 0.0));
314 if (mKofN)
315 mType = kKofN;
316
317 }
318 else
319 {
320 secdebug("authrule", "%s : rule class unknown %s.", inRightName.c_str(), classTag.c_str());
321 MacOSError::throwMe(errAuthorizationInternal); // XXX/cs invalid rule
322 }
323 }
324 else
325 {
326 // no class tag means, this is the abbreviated specification from the API
327 // it _must_ have a definition for "rule" which will be used as a delegate
328 // it may have a comment (not extracted here)
329 // it may have a default prompt, or a whole dictionary of languages (not extracted here)
330 assert(cfRules);
331 mType = kRuleDelegation;
332 string ruleName = Attribute::getString(cfRight, kRuleDelegateID, true);
333 secdebug("authrule", "%s : rule delegate rule (1): %s", inRightName.c_str(), ruleName.c_str());
334 CFStringRef ruleNameRef = makeCFString(ruleName);
335 CFDictionaryRef cfRuleDef = reinterpret_cast<CFDictionaryRef>(CFDictionaryGetValue(cfRules, ruleNameRef));
336 if (ruleNameRef)
337 CFRelease(ruleNameRef);
338 if (!cfRuleDef || CFGetTypeID(cfRuleDef) != CFDictionaryGetTypeID())
339 MacOSError::throwMe(errAuthorizationInternal); // XXX/cs invalid rule
340 mRuleDef.push_back(Rule(ruleName, cfRuleDef, NULL));
341 }
342
343 Attribute::getLocalizedPrompts(cfRight, mLocalizedPrompts);
344 }
345
346 /*
347 RuleImpl::~Rule()
348 {
349 }
350 */
351
352 void
353 RuleImpl::setAgentHints(const AuthItemRef &inRight, const Rule &inTopLevelRule, AuthItemSet &environmentToClient, AuthorizationToken &auth) const
354 {
355 string authorizeString(inRight->name());
356 environmentToClient.insert(AuthItemRef(AGENT_HINT_AUTHORIZE_RIGHT, AuthValueOverlay(authorizeString)));
357
358 // XXX/cs pid/uid/client should only be added when we're ready to call the agent
359 pid_t cPid = Server::connection().process.pid();
360 environmentToClient.insert(AuthItemRef(AGENT_HINT_CLIENT_PID, AuthValueOverlay(sizeof(pid_t), &cPid)));
361
362 uid_t cUid = auth.creatorUid();
363 environmentToClient.insert(AuthItemRef(AGENT_HINT_CLIENT_UID, AuthValueOverlay(sizeof(uid_t), &cUid)));
364
365 pid_t creatorPid = auth.creatorPid();
366 environmentToClient.insert(AuthItemRef(AGENT_HINT_CREATOR_PID, AuthValueOverlay(sizeof(pid_t), &creatorPid)));
367
368 {
369 CodeSigning::OSXCode *osxcode = auth.creatorCode();
370 if (!osxcode)
371 MacOSError::throwMe(errAuthorizationDenied);
372
373 string encodedBundle = osxcode->encode();
374 char bundleType = (encodedBundle.c_str())[0]; // yay, no accessor
375 string bundlePath = osxcode->canonicalPath();
376
377 environmentToClient.insert(AuthItemRef(AGENT_HINT_CLIENT_TYPE, AuthValueOverlay(sizeof(bundleType), &bundleType)));
378 environmentToClient.insert(AuthItemRef(AGENT_HINT_CLIENT_PATH, AuthValueOverlay(bundlePath)));
379 }
380
381 map<string,string> defaultPrompts = inTopLevelRule->localizedPrompts();
382
383 if (defaultPrompts.empty())
384 defaultPrompts = localizedPrompts();
385
386 if (!defaultPrompts.empty())
387 {
388 map<string,string>::const_iterator it;
389 for (it = defaultPrompts.begin(); it != defaultPrompts.end(); it++)
390 {
391 const string &key = it->first;
392 const string &value = it->second;
393 environmentToClient.insert(AuthItemRef(key.c_str(), AuthValueOverlay(value)));
394 }
395 }
396
397 // add rulename as a hint
398 string ruleName = name();
399 environmentToClient.insert(AuthItemRef(AGENT_HINT_AUTHORIZE_RULE, AuthValueOverlay(ruleName)));
400 }
401
402 string
403 RuleImpl::agentNameForAuth(const AuthorizationToken &auth) const
404 {
405 uint8_t hash[20];
406 AuthorizationBlob authBlob = auth.handle();
407 CssmData hashedData = CssmData::wrap(&hash, sizeof(hash));
408 CssmData data = CssmData::wrap(&authBlob, sizeof(authBlob));
409 CssmClient::Digest ctx(Server::csp(), CSSM_ALGID_SHA1);
410 try {
411 ctx.digest(data, hashedData);
412 }
413 catch (CssmError &e)
414 {
415 secdebug("auth", "digesting authref failed (%lu)", e.cssmError());
416 return string("SecurityAgentMechanism");
417 }
418
419 uint8_t *point = static_cast<uint8_t*>(hashedData.data());
420 for (uint8_t i=0; i < hashedData.length(); point++, i++)
421 {
422 uint8 value = (*point % 62) + '0';
423 if (value > '9') value += 7;
424 if (value > 'Z') value += 6;
425 *point = value;
426 }
427 return string(static_cast<char *>(hashedData.data()), hashedData.length());
428 }
429
430 OSStatus
431 RuleImpl::evaluateMechanism(const AuthItemRef &inRight, const AuthItemSet &environment, AuthorizationToken &auth, CredentialSet &outCredentials) const
432 {
433 string agentName = agentNameForAuth(auth);
434
435 // @@@ configuration does not support arguments
436 AuthValueVector arguments;
437 // XXX/cs Move this up - we shouldn't know how to retrieve the ingoing context
438 AuthItemSet context = auth.infoSet();
439 AuthItemSet hints = environment;
440
441 CommonCriteria::AuditRecord auditrec(auth.creatorAuditToken());
442
443 AuthorizationResult result = kAuthorizationResultAllow;
444 vector<string>::const_iterator currentMechanism = mEvalDef.begin();
445
446 while ( (result == kAuthorizationResultAllow) &&
447 (currentMechanism != mEvalDef.end()) ) // iterate mechanisms
448 {
449 string::size_type extPlugin = currentMechanism->find(':');
450 if (extPlugin != string::npos)
451 {
452 // no whitespace removal
453 string pluginIn(currentMechanism->substr(0, extPlugin));
454 string mechanismIn(currentMechanism->substr(extPlugin + 1));
455 secdebug("SSevalMech", "external mech %s:%s", pluginIn.c_str(), mechanismIn.c_str());
456
457 bool mechExecOk = false; // successfully ran a mechanism
458
459 Process &cltProc = Server::active().connection().process;
460 // Authorization preserves creator's UID in setuid processes
461 uid_t cltUid = (cltProc.uid() != 0) ? cltProc.uid() : auth.creatorUid();
462 secdebug("SSevalMech", "Mechanism invocation by process %d (UID %d)", cltProc.pid(), cltUid);
463 QueryInvokeMechanism client(cltUid, auth, agentName.c_str());
464 try
465 {
466 mechExecOk = client(pluginIn, mechanismIn, arguments, hints, context, &result);
467 }
468 catch (...) {
469 secdebug("SSevalMech", "exception from mech eval or client death");
470 // various server problems, but only if it really failed
471 if (mechExecOk != true)
472 result = kAuthorizationResultUndefined;
473 }
474
475 secdebug("SSevalMech", "evaluate(plugin: %s, mechanism: %s) %s, result: %lu.", pluginIn.c_str(), mechanismIn.c_str(), (mechExecOk == true) ? "succeeded" : "failed", result);
476 }
477 else
478 {
479 // internal mechanisms - no glue
480 if (*currentMechanism == "authinternal")
481 {
482 secdebug("SSevalMech", "evaluate authinternal");
483 result = kAuthorizationResultDeny;
484 do {
485 AuthItemSet::iterator found = find_if(context.begin(), context.end(), FindAuthItemByRightName(kAuthorizationEnvironmentUsername) );
486 if (found == context.end())
487 break;
488 string username(static_cast<const char *>((*found)->value().data), (*found)->value().length);
489 secdebug("SSevalMech", "found username");
490 found = find_if(context.begin(), context.end(), FindAuthItemByRightName(kAuthorizationEnvironmentPassword) );
491 if (found == context.end())
492 break;
493 string password(static_cast<const char *>((*found)->value().data), (*found)->value().length);
494 secdebug("SSevalMech", "found password");
495 Credential newCredential(username, password, true); // create a new shared credential
496
497 if (newCredential->isValid())
498 {
499 Syslog::info("authinternal authenticated user %s (uid %lu) for right %s.", newCredential->username().c_str(), newCredential->uid(), inRight->name());
500 auditrec.submit(AUE_ssauthint, CommonCriteria::errNone, inRight->name());
501 }
502 else
503 {
504 // we can't be sure that the user actually exists so inhibit logging of uid
505 Syslog::error("authinternal failed to authenticate user %s for right %s.", newCredential->username().c_str(), inRight->name());
506
507 auditrec.submit(AUE_ssauthint, CommonCriteria::errInvalidCredential, inRight->name());
508 }
509
510 if (newCredential->isValid())
511 {
512 outCredentials.clear(); // only keep last one
513 secdebug("SSevalMech", "inserting new credential");
514 outCredentials.insert(newCredential);
515 result = kAuthorizationResultAllow;
516 } else
517 result = kAuthorizationResultDeny;
518 } while (0);
519 }
520 else
521 if (*currentMechanism == "push_hints_to_context")
522 {
523 secdebug("SSevalMech", "evaluate push_hints_to_context");
524 mTries = 1; // XXX/cs this should be set in authorization config
525 result = kAuthorizationResultAllow; // snarfcredential doesn't block evaluation, ever, it may restart
526 // create out context from input hints, no merge
527 // @@@ global copy template not being invoked...
528 context = hints;
529 }
530 else
531 if (*currentMechanism == "switch_to_user")
532 {
533 Process &cltProc = Server::active().connection().process;
534 // Authorization preserves creator's UID in setuid processes
535 uid_t cltUid = (cltProc.uid() != 0) ? cltProc.uid() : auth.creatorUid();
536 secdebug("SSevalMech", "terminating agent at request of process %d (UID %d)\n", cltProc.pid(), cltUid);
537 QueryInvokeMechanism client(cltUid, auth, agentName.c_str());
538
539 try {
540 client.terminateAgent();
541 } catch (...) {
542 // Not our agent
543 }
544 result = kAuthorizationResultAllow;
545 }
546 }
547
548 // we own outHints and outContext
549 switch(result)
550 {
551 case kAuthorizationResultAllow:
552 secdebug("SSevalMech", "result allow");
553 currentMechanism++;
554 break;
555 case kAuthorizationResultDeny:
556 secdebug("SSevalMech", "result deny");
557 break;
558 case kAuthorizationResultUndefined:
559 secdebug("SSevalMech", "result undefined");
560 break; // abort evaluation
561 case kAuthorizationResultUserCanceled:
562 secdebug("SSevalMech", "result canceled");
563 break; // stop evaluation, return some sideband
564 default:
565 break; // abort evaluation
566 }
567 }
568
569 // End of evaluation, if last step produced meaningful data, incorporate
570 if ((result == kAuthorizationResultAllow) ||
571 (result == kAuthorizationResultUserCanceled)) // @@@ can only pass back sideband through context
572 {
573 secdebug("SSevalMech", "storing new context for authorization");
574 auth.setInfoSet(context);
575 }
576
577 switch(result)
578 {
579 case kAuthorizationResultDeny:
580 return errAuthorizationDenied;
581 case kAuthorizationResultUserCanceled:
582 return errAuthorizationCanceled;
583 case kAuthorizationResultAllow:
584 return errAuthorizationSuccess;
585 default:
586 return errAuthorizationInternal;
587 }
588 }
589
590
591
592 OSStatus
593 RuleImpl::evaluateAuthorization(const AuthItemRef &inRight, const Rule &inRule,
594 AuthItemSet &environmentToClient,
595 AuthorizationFlags flags, CFAbsoluteTime now,
596 const CredentialSet *inCredentials,
597 CredentialSet &credentials, AuthorizationToken &auth) const
598 {
599 OSStatus status = errAuthorizationDenied;
600
601 string usernamehint;
602 evaluateSessionOwner(inRight, inRule, environmentToClient, now, auth, usernamehint);
603 if (usernamehint.length())
604 environmentToClient.insert(AuthItemRef(AGENT_HINT_SUGGESTED_USER, AuthValueOverlay(usernamehint)));
605
606 if ((mType == kUser) && (mGroupName.length()))
607 environmentToClient.insert(AuthItemRef(AGENT_HINT_REQUIRE_USER_IN_GROUP, AuthValueOverlay(mGroupName)));
608
609 uint32 tries;
610 SecurityAgent::Reason reason = SecurityAgent::noReason;
611
612 for (tries = 0; tries < mTries; tries++)
613 {
614 AuthItemRef retryHint(AGENT_HINT_RETRY_REASON, AuthValueOverlay(sizeof(reason), &reason));
615 environmentToClient.erase(retryHint); environmentToClient.insert(retryHint); // replace
616 AuthItemRef triesHint(AGENT_HINT_TRIES, AuthValueOverlay(sizeof(tries), &tries));
617 environmentToClient.erase(triesHint); environmentToClient.insert(triesHint); // replace
618
619 status = evaluateMechanism(inRight, environmentToClient, auth, credentials);
620
621 // successfully ran mechanisms to obtain credential
622 if (status == errAuthorizationSuccess)
623 {
624 // deny is the default
625 status = errAuthorizationDenied;
626
627 // fetch context and construct a credential to be tested
628 AuthItemSet inContext = auth.infoSet();
629 CredentialSet newCredentials = makeCredentials(inContext);
630 // clear context after extracting credentials
631 auth.clearInfoSet();
632
633 for (CredentialSet::const_iterator it = newCredentials.begin(); it != newCredentials.end(); ++it)
634 {
635 const Credential& newCredential = *it;
636 CommonCriteria::AuditRecord auditrec(auth.creatorAuditToken());
637
638 // @@@ we log the uid a process was running under when it created the authref, which is misleading in the case of loginwindow
639 if (newCredential->isValid())
640 {
641 Syslog::info("uid %lu succeeded authenticating as user %s (uid %lu) for right %s.", auth.creatorUid(), newCredential->username().c_str(), newCredential->uid(), inRight->name());
642 auditrec.submit(AUE_ssauthorize, CommonCriteria::errNone, inRight->name());
643 }
644 else
645 {
646 // we can't be sure that the user actually exists so inhibit logging of uid
647 Syslog::error("uid %lu failed to authenticate as user %s for right %s.", auth.creatorUid(), newCredential->username().c_str(), inRight->name());
648 auditrec.submit(AUE_ssauthorize, CommonCriteria::errInvalidCredential, inRight->name());
649 }
650
651 if (!newCredential->isValid())
652 {
653 reason = SecurityAgent::invalidPassphrase; //invalidPassphrase;
654 continue;
655 }
656
657 // verify that this credential authorizes right
658 status = evaluateCredentialForRight(inRight, inRule, environmentToClient, now, newCredential, true);
659
660 if (status == errAuthorizationSuccess)
661 {
662 // whack an equivalent credential, so it gets updated to a later achieved credential which must have been more stringent
663 credentials.erase(newCredential); credentials.insert(newCredential);
664 // use valid credential to set context info
665 auth.setCredentialInfo(newCredential);
666 secdebug("SSevalMech", "added valid credential for user %s", newCredential->username().c_str());
667 status = errAuthorizationSuccess;
668 break;
669 }
670 else
671 {
672 reason = SecurityAgent::userNotInGroup; //unacceptableUser; // userNotInGroup
673 // don't audit: we denied on the basis of something
674 // other than a bad user or password
675 }
676 }
677
678 if (status == errAuthorizationSuccess)
679 break;
680 }
681 else
682 if ((status == errAuthorizationCanceled) ||
683 (status == errAuthorizationInternal))
684 {
685 auth.clearInfoSet();
686 break;
687 }
688 }
689
690 // If we fell out of the loop because of too many tries, notify user
691 if (tries == mTries)
692 {
693 reason = SecurityAgent::tooManyTries;
694 AuthItemRef retryHint (AGENT_HINT_RETRY_REASON, AuthValueOverlay(sizeof(reason), &reason));
695 environmentToClient.erase(retryHint); environmentToClient.insert(retryHint); // replace
696 AuthItemRef triesHint(AGENT_HINT_TRIES, AuthValueOverlay(sizeof(tries), &tries));
697 environmentToClient.erase(triesHint); environmentToClient.insert(triesHint); // replace
698 evaluateMechanism(inRight, environmentToClient, auth, credentials);
699 auth.clearInfoSet();
700 }
701
702 Process &cltProc = Server::active().connection().process;
703 // Authorization preserves creator's UID in setuid processes
704 uid_t cltUid = (cltProc.uid() != 0) ? cltProc.uid() : auth.creatorUid();
705 secdebug("SSevalMech", "terminating agent at request of process %d (UID %d)\n", cltProc.pid(), cltUid);
706 string agentName = agentNameForAuth(auth);
707 QueryInvokeMechanism client(cltUid, auth, agentName.c_str());
708
709 try {
710 client.terminateAgent();
711 } catch (...) {
712 // Not our agent
713 }
714
715 return status;
716 }
717
718 // create externally verified credentials on the basis of
719 // mechanism-provided information
720 CredentialSet
721 RuleImpl::makeCredentials(const AuthItemSet &context) const
722 {
723 CredentialSet newCredentials;
724
725 do {
726 AuthItemSet::const_iterator found = find_if(context.begin(), context.end(), FindAuthItemByRightName(kAuthorizationEnvironmentUsername) );
727 if (found == context.end())
728 break;
729 string username = (**found).stringValue();
730 secdebug("SSevalMech", "found username");
731
732 const uid_t *uid = NULL;
733 found = find_if(context.begin(), context.end(), FindAuthItemByRightName("uid") );
734 if (found != context.end())
735 {
736 uid = static_cast<const uid_t *>((**found).value().data);
737 secdebug("SSevalMech", "found uid");
738 }
739
740 const gid_t *gid = NULL;
741 found = find_if(context.begin(), context.end(), FindAuthItemByRightName("gid") );
742 if (found != context.end())
743 {
744 gid = static_cast<const gid_t *>((**found).value().data);
745 secdebug("SSevalMech", "found gid");
746 }
747
748 if (username.length() && uid && gid)
749 {
750 // credential is valid because mechanism says so
751 newCredentials.insert(Credential(username, *uid, *gid, mShared));
752 }
753 else
754 {
755 found = find_if(context.begin(), context.end(), FindAuthItemByRightName(kAuthorizationEnvironmentPassword) );
756 if (found != context.end())
757 {
758 secdebug("SSevalMech", "found password");
759 string password = (**found).stringValue();
760 secdebug("SSevalMech", "falling back on username/password credential if valid");
761 newCredentials.insert(Credential(username, password, mShared));
762 }
763 }
764 } while(0);
765
766 return newCredentials;
767 }
768
769 // evaluate whether a good credential of the current session owner would authorize a right
770 OSStatus
771 RuleImpl::evaluateSessionOwner(const AuthItemRef &inRight, const Rule &inRule,
772 const AuthItemSet &environment,
773 const CFAbsoluteTime now,
774 const AuthorizationToken &auth,
775 string& usernamehint) const
776 {
777 // username hint is taken from the user who created the authorization, unless it's clearly ineligible
778 OSStatus status = noErr;
779 // @@@ we have no access to current requester uid here and the process uid is only taken when the authorization is created
780 // meaning that a process like loginwindow that drops privs later is screwed.
781 uid_t uid = auth.creatorUid();
782
783 Server::active().longTermActivity();
784 struct passwd *pw = getpwuid(uid);
785 if (pw != NULL)
786 {
787 // avoid hinting a locked account (ie. root)
788 if ( (pw->pw_passwd == NULL) ||
789 strcmp(pw->pw_passwd, "*") ) {
790 // Check if username will authorize the request and set username to
791 // be used as a hint to the user if so
792 status = evaluateCredentialForRight(inRight, inRule, environment, now, Credential(pw->pw_name, pw->pw_uid, pw->pw_gid, mShared), true);
793
794 if (status == errAuthorizationSuccess)
795 usernamehint = pw->pw_name;
796 } //fi
797 endpwent();
798 }
799 return status;
800 }
801
802
803
804 // Return errAuthorizationSuccess if this rule allows access based on the specified credential,
805 // return errAuthorizationDenied otherwise.
806 OSStatus
807 RuleImpl::evaluateCredentialForRight(const AuthItemRef &inRight, const Rule &inRule, const AuthItemSet &environment, CFAbsoluteTime now, const Credential &credential, bool ignoreShared) const
808 {
809 assert(mType == kUser);
810
811 // Get the username from the credential
812 const char *user = credential->username().c_str();
813
814 // If the credential is not valid or it's age is more than the allowed maximum age
815 // for a credential, deny.
816 if (!credential->isValid())
817 {
818 secdebug("autheval", "credential for user %s is invalid, denying right %s", user, inRight->name());
819 return errAuthorizationDenied;
820 }
821
822 if (now - credential->creationTime() > mMaxCredentialAge)
823 {
824 secdebug("autheval", "credential for user %s has expired, denying right %s", user, inRight->name());
825 return errAuthorizationDenied;
826 }
827
828 if (!ignoreShared && !mShared && credential->isShared())
829 {
830 secdebug("autheval", "shared credential for user %s cannot be used, denying right %s", user, inRight->name());
831 return errAuthorizationDenied;
832 }
833
834 // A root (uid == 0) user can do anything
835 if (credential->uid() == 0)
836 {
837 secdebug("autheval", "user %s has uid 0, granting right %s", user, inRight->name());
838 return errAuthorizationSuccess;
839 }
840
841 // XXX/cs replace with remembered session-owner once that functionality is added to SecurityServer
842 if (mSessionOwner)
843 {
844 uid_t console_user;
845 struct stat console_stat;
846 if (!lstat("/dev/console", &console_stat))
847 {
848 console_user = console_stat.st_uid;
849 if (credential->uid() == console_user)
850 {
851 secdebug("autheval", "user %s is session-owner(uid: %d), granting right %s", user, console_user, inRight->name());
852 return errAuthorizationSuccess;
853 }
854 }
855 else
856 secdebug("autheval", "session-owner check failed.");
857 }
858
859 if (mGroupName.length())
860 {
861 const char *groupname = mGroupName.c_str();
862 Server::active().longTermActivity();
863 struct group *gr = getgrnam(groupname);
864 if (!gr)
865 return errAuthorizationDenied;
866
867 // Is this the default group of this user?
868 // PR-2875126 <grp.h> declares gr_gid int, as opposed to advertised (getgrent(3)) gid_t
869 // When this is fixed this warning should go away.
870 if (credential->gid() == gr->gr_gid)
871 {
872 secdebug("autheval", "user %s has group %s(%d) as default group, granting right %s",
873 user, groupname, gr->gr_gid, inRight->name());
874 endgrent();
875 return errAuthorizationSuccess;
876 }
877
878 for (char **group = gr->gr_mem; *group; ++group)
879 {
880 if (!strcmp(*group, user))
881 {
882 secdebug("autheval", "user %s is a member of group %s, granting right %s",
883 user, groupname, inRight->name());
884 endgrent();
885 return errAuthorizationSuccess;
886 }
887 }
888
889 secdebug("autheval", "user %s is not a member of group %s, denying right %s",
890 user, groupname, inRight->name());
891 endgrent();
892 }
893
894 return errAuthorizationDenied;
895 }
896
897 OSStatus
898 RuleImpl::evaluateUser(const AuthItemRef &inRight, const Rule &inRule,
899 AuthItemSet &environmentToClient, AuthorizationFlags flags,
900 CFAbsoluteTime now, const CredentialSet *inCredentials, CredentialSet &credentials,
901 AuthorizationToken &auth) const
902 {
903 // If we got here, this is a kUser type rule, let's start looking for a
904 // credential that is satisfactory
905
906 // Zeroth -- Here is an extra special saucy ugly hack to allow authorizations
907 // created by a proccess running as root to automatically get a right.
908 if (mAllowRoot && auth.creatorUid() == 0)
909 {
910 secdebug("autheval", "creator of authorization has uid == 0 granting right %s",
911 inRight->name());
912 return errAuthorizationSuccess;
913 }
914
915 // if this is a "is-admin" rule check that and return
916 // XXX/cs add way to specify is-admin class of rule: if (mNoVerify)
917 if (name() == kAuthorizationRuleIsAdmin)
918 {
919 string username;
920 if (!evaluateSessionOwner(inRight, inRule, environmentToClient, now, auth, username))
921 return errAuthorizationSuccess;
922 }
923
924 // First -- go though the credentials we either already used or obtained during this authorize operation.
925 for (CredentialSet::const_iterator it = credentials.begin(); it != credentials.end(); ++it)
926 {
927 OSStatus status = evaluateCredentialForRight(inRight, inRule, environmentToClient, now, *it, true);
928 if (status != errAuthorizationDenied)
929 {
930 // add credential to authinfo
931 auth.setCredentialInfo(*it);
932 return status;
933 }
934 }
935
936 // Second -- go though the credentials passed in to this authorize operation by the state management layer.
937 if (inCredentials)
938 {
939 for (CredentialSet::const_iterator it = inCredentials->begin(); it != inCredentials->end(); ++it)
940 {
941 OSStatus status = evaluateCredentialForRight(inRight, inRule, environmentToClient, now, *it, false);
942 if (status == errAuthorizationSuccess)
943 {
944 // Add the credential we used to the output set.
945 // whack an equivalent credential, so it gets updated to a later achieved credential which must have been more stringent
946 credentials.erase(*it); credentials.insert(*it);
947 // add credential to authinfo
948 auth.setCredentialInfo(*it);
949
950 return status;
951 }
952 else if (status != errAuthorizationDenied)
953 return status;
954 }
955 }
956
957 // Finally -- We didn't find the credential in our passed in credential lists. Obtain a new credential if
958 // our flags let us do so.
959 if (!(flags & kAuthorizationFlagExtendRights))
960 return errAuthorizationDenied;
961
962 // authorizations that timeout immediately cannot be preauthorized
963 if ((flags & kAuthorizationFlagPreAuthorize) &&
964 (mMaxCredentialAge == 0.0))
965 {
966 inRight->setFlags(inRight->flags() | kAuthorizationFlagCanNotPreAuthorize);
967 return errAuthorizationSuccess;
968 }
969
970 if (!(flags & kAuthorizationFlagInteractionAllowed))
971 return errAuthorizationInteractionNotAllowed;
972
973 setAgentHints(inRight, inRule, environmentToClient, auth);
974
975 // If a different evaluation is prescribed,
976 // we'll run that and validate the credentials from there
977 // we fall back on a default configuration
978 if (mEvalDef.size() == 0)
979 return evaluateAuthorizationOld(inRight, inRule, environmentToClient, flags, now, inCredentials, credentials, auth);
980 else
981 return evaluateAuthorization(inRight, inRule, environmentToClient, flags, now, inCredentials, credentials, auth);
982 }
983
984 // XXX/cs insert a mechanism that let's the agent live (keep-alive) only in loginwindow's case
985 OSStatus
986 RuleImpl::evaluateMechanismOnly(const AuthItemRef &inRight, const Rule &inRule, AuthItemSet &environmentToClient, AuthorizationToken &auth, CredentialSet &outCredentials) const
987 {
988 uint32 tries = 0;
989 OSStatus status;
990
991 do
992 {
993 setAgentHints(inRight, inRule, environmentToClient, auth);
994 AuthItemRef triesHint(AGENT_HINT_TRIES, AuthValueOverlay(sizeof(tries), &tries));
995 environmentToClient.erase(triesHint); environmentToClient.insert(triesHint); // replace
996
997 status = evaluateMechanism(inRight, environmentToClient, auth, outCredentials);
998 tries++;
999 }
1000 while ((status == errAuthorizationDenied) // only if we have an expected failure we continue
1001 && ((mTries == 0) // mTries == 0 means we try forever
1002 || ((mTries > 0) // mTries > 0 means we try up to mTries times
1003 && (tries < mTries))));
1004
1005 if (name() != "system.login.console")
1006 {
1007 // terminate agent
1008 string agentName = agentNameForAuth(auth);
1009 Process &cltProc = Server::active().connection().process;
1010 // Authorization preserves creator's UID in setuid processes
1011 uid_t cltUid = (cltProc.uid() != 0) ? cltProc.uid() : auth.creatorUid();
1012 secdebug("SSevalMech", "terminating agent at request of process %d (UID %d)\n", cltProc.pid(), cltUid);
1013
1014 QueryInvokeMechanism client(cltUid, auth, agentName.c_str());
1015
1016 try
1017 {
1018 client.terminateAgent();
1019 } catch (...) {
1020 // Not our agent
1021 }
1022 }
1023 return status;
1024 }
1025
1026 OSStatus
1027 RuleImpl::evaluateRules(const AuthItemRef &inRight, const Rule &inRule,
1028 AuthItemSet &environmentToClient, AuthorizationFlags flags,
1029 CFAbsoluteTime now, const CredentialSet *inCredentials, CredentialSet &credentials,
1030 AuthorizationToken &auth) const
1031 {
1032 // line up the rules to try
1033 if (!mRuleDef.size())
1034 return errAuthorizationSuccess;
1035
1036 uint32_t count = 0;
1037 OSStatus status = errAuthorizationSuccess;
1038 vector<Rule>::const_iterator it;
1039
1040 for (it = mRuleDef.begin();it != mRuleDef.end(); it++)
1041 {
1042 // are we at k yet?
1043 if ((mType == kKofN) && (count == mKofN))
1044 return errAuthorizationSuccess;
1045
1046 // get a rule and try it
1047 status = (*it)->evaluate(inRight, inRule, environmentToClient, flags, now, inCredentials, credentials, auth);
1048
1049 // if status is cancel/internal error abort
1050 if ((status == errAuthorizationCanceled) || (status == errAuthorizationInternal))
1051 return status;
1052
1053 if (status != errAuthorizationSuccess)
1054 {
1055 // continue if we're only looking for k of n
1056 if (mType == kKofN)
1057 continue;
1058
1059 break;
1060 }
1061 else
1062 count++;
1063 }
1064
1065 return status; // return the last failure
1066 }
1067
1068
1069 OSStatus
1070 RuleImpl::evaluate(const AuthItemRef &inRight, const Rule &inRule,
1071 AuthItemSet &environmentToClient, AuthorizationFlags flags,
1072 CFAbsoluteTime now, const CredentialSet *inCredentials, CredentialSet &credentials,
1073 AuthorizationToken &auth) const
1074 {
1075 switch (mType)
1076 {
1077 case kAllow:
1078 secdebug("autheval", "rule is always allow");
1079 return errAuthorizationSuccess;
1080 case kDeny:
1081 secdebug("autheval", "rule is always deny");
1082 return errAuthorizationDenied;
1083 case kUser:
1084 secdebug("autheval", "rule is user");
1085 return evaluateUser(inRight, inRule, environmentToClient, flags, now, inCredentials, credentials, auth);
1086 case kRuleDelegation:
1087 secdebug("autheval", "rule evaluates rules");
1088 return evaluateRules(inRight, inRule, environmentToClient, flags, now, inCredentials, credentials, auth);
1089 case kKofN:
1090 secdebug("autheval", "rule evaluates k-of-n rules");
1091 return evaluateRules(inRight, inRule, environmentToClient, flags, now, inCredentials, credentials, auth);
1092 case kEvaluateMechanisms:
1093 secdebug("autheval", "rule evaluates mechanisms");
1094 return evaluateMechanismOnly(inRight, inRule, environmentToClient, auth, credentials);
1095 default:
1096 MacOSError::throwMe(errAuthorizationInternal); // XXX/cs invalid rule
1097 }
1098 }
1099
1100
1101
1102
1103 // This is slated to be removed when the new auth panel is fixed up
1104 OSStatus
1105 RuleImpl::evaluateAuthorizationOld(const AuthItemRef &inRight, const Rule &inRule,
1106 AuthItemSet &environmentToClient,
1107 AuthorizationFlags flags, CFAbsoluteTime now,
1108 const CredentialSet *inCredentials,
1109 CredentialSet &credentials, AuthorizationToken &auth) const
1110 {
1111 Process &cltProc = Server::active().connection().process;
1112 // Authorization preserves creator's UID in setuid processes
1113 uid_t cltUid = (cltProc.uid() != 0) ? cltProc.uid() : auth.creatorUid();
1114 secdebug("autheval", "Auth query from process %d (UID %d)", cltProc.pid(), cltUid);
1115 QueryAuthorizeByGroup query(cltUid, auth);
1116
1117 string usernamehint;
1118
1119 evaluateSessionOwner(inRight, inRule, environmentToClient, now, auth, usernamehint);
1120
1121 Credential newCredential;
1122 // @@@ Keep the default reason the same, so the agent only gets userNotInGroup or invalidPassphrase
1123 SecurityAgent::Reason reason = SecurityAgent::userNotInGroup;
1124
1125 CommonCriteria::AuditRecord auditrec(auth.creatorAuditToken());
1126
1127 // @@@ Hardcoded 3 tries to avoid infinite loops.
1128 for (uint32_t tryCount = 0; tryCount < mTries; ++tryCount)
1129 {
1130 // Obtain a new credential. Anything but success is considered an error.
1131 OSStatus status = obtainCredential(query, inRight, environmentToClient, usernamehint.c_str(), newCredential, reason);
1132 if (status)
1133 return status;
1134
1135 // Now we have successfully obtained a credential we need to make sure it authorizes the requested right
1136 if (!newCredential->isValid())
1137 {
1138 reason = SecurityAgent::invalidPassphrase;
1139 auditrec.submit(AUE_ssauthorize, CommonCriteria::errInvalidCredential, inRight->name());
1140 }
1141 else {
1142 status = evaluateCredentialForRight(inRight, inRule, environmentToClient, now, newCredential, true);
1143 if (status == errAuthorizationSuccess)
1144 {
1145 // Add the new credential we obtained to the output set.
1146 // whack an equivalent credential, so it gets updated to a later achieved credential which must have been more stringent
1147 credentials.erase(newCredential); credentials.insert(newCredential);
1148 query.done();
1149
1150 // add credential to authinfo
1151 auth.setCredentialInfo(newCredential);
1152
1153 auditrec.submit(AUE_ssauthorize, CommonCriteria::errNone, inRight->name());
1154 return errAuthorizationSuccess;
1155 }
1156 else if (status != errAuthorizationDenied)
1157 {
1158 if (status == errAuthorizationCanceled)
1159 auditrec.submit(AUE_ssauthorize, CommonCriteria::errUserCanceled, inRight->name());
1160 // else don't audit--error not due to bad
1161 // username or password
1162 return status;
1163 }
1164 }
1165 reason = SecurityAgent::userNotInGroup;
1166 }
1167 query.cancel(SecurityAgent::tooManyTries);
1168
1169 auditrec.submit(AUE_ssauthorize, CommonCriteria::errTooManyTries, inRight->name());
1170 return errAuthorizationDenied;
1171 }
1172
1173 OSStatus
1174 RuleImpl::obtainCredential(QueryAuthorizeByGroup &query, const AuthItemRef &inRight,
1175 AuthItemSet &environmentToClient, const char *usernameHint, Credential &outCredential, SecurityAgent::Reason reason) const
1176 {
1177 char nameBuffer[SecurityAgent::maxUsernameLength];
1178 char passphraseBuffer[SecurityAgent::maxPassphraseLength];
1179 OSStatus status = errAuthorizationDenied;
1180
1181 try {
1182 if (query(mGroupName.c_str(), usernameHint, nameBuffer, passphraseBuffer, reason))
1183 status = noErr;
1184 } catch (const CssmCommonError &err) {
1185 status = err.osStatus();
1186 } catch (...) {
1187 status = errAuthorizationInternal;
1188 }
1189 if (status == CSSM_ERRCODE_USER_CANCELED)
1190 {
1191 secdebug("auth", "canceled obtaining credential for user in group %s", mGroupName.c_str());
1192 return errAuthorizationCanceled;
1193 }
1194 if (status == CSSM_ERRCODE_NO_USER_INTERACTION)
1195 {
1196 secdebug("auth", "user interaction not possible obtaining credential for user in group %s", mGroupName.c_str());
1197 return errAuthorizationInteractionNotAllowed;
1198 }
1199
1200 if (status != noErr)
1201 {
1202 secdebug("auth", "failed obtaining credential for user in group %s", mGroupName.c_str());
1203 return status;
1204 }
1205
1206 secdebug("auth", "obtained credential for user %s", nameBuffer);
1207 string username(nameBuffer);
1208 string password(passphraseBuffer);
1209 outCredential = Credential(username, password, mShared);
1210 return errAuthorizationSuccess;
1211 }
1212
1213
1214 Rule::Rule() : RefPointer<RuleImpl>(new RuleImpl()) {}
1215 Rule::Rule(const string &inRightName, CFDictionaryRef cfRight, CFDictionaryRef cfRules) : RefPointer<RuleImpl>(new RuleImpl(inRightName, cfRight, cfRules)) {}
1216
1217
1218 } // end namespace Authorization