]> git.saurik.com Git - apple/security.git/blob - OSX/authd/engine.c
Security-58286.20.16.tar.gz
[apple/security.git] / OSX / authd / engine.c
1 /* Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. */
2
3 #include "engine.h"
4 #include "rule.h"
5 #include "authitems.h"
6 #include "authtoken.h"
7 #include "agent.h"
8 #include "process.h"
9 #include "debugging.h"
10 #include "server.h"
11 #include "credential.h"
12 #include "session.h"
13 #include "mechanism.h"
14 #include "authutilities.h"
15 #include "ccaudit.h"
16 #include "connection.h"
17
18 #include <pwd.h>
19 #include <Security/checkpw.h>
20 int checkpw_internal( const struct passwd *pw, const char* password );
21
22 #include <Security/AuthorizationTags.h>
23 #include <Security/AuthorizationTagsPriv.h>
24 #include <Security/AuthorizationPlugin.h>
25 #include <LocalAuthentication/LAPublicDefines.h>
26 #include <LocalAuthentication/LAPrivateDefines.h>
27 #include <sandbox.h>
28 #include <coreauthd_spi.h>
29
30 AUTHD_DEFINE_LOG
31
32 static void _set_process_hints(auth_items_t, process_t);
33 static void _set_process_immutable_hints(auth_items_t, process_t);
34 static void _set_auth_token_hints(auth_items_t, auth_items_t, auth_token_t);
35 static OSStatus _evaluate_user_credential_for_rule(engine_t, credential_t, rule_t, bool, bool, enum Reason *);
36 static void _engine_set_credential(engine_t, credential_t, bool);
37 static OSStatus _evaluate_rule(engine_t, rule_t, bool *);
38 static bool _preevaluate_class_rule(engine_t engine, rule_t rule);
39 static bool _preevaluate_rule(engine_t engine, rule_t rule);
40
41 enum {
42 kEngineHintsFlagTemporary = (1 << 30)
43 };
44
45 #pragma mark -
46 #pragma mark engine creation
47
48 struct _engine_s {
49 __AUTH_BASE_STRUCT_HEADER__;
50
51 connection_t conn;
52 process_t proc;
53 auth_token_t auth;
54
55 AuthorizationFlags flags;
56 auth_items_t hints;
57 auth_items_t context;
58 auth_items_t sticky_context;
59 auth_items_t immutable_hints;
60
61 auth_rights_t grantedRights;
62
63 CFTypeRef la_context;
64 bool preauthorizing;
65
66 enum Reason reason;
67 int32_t tries;
68
69 CFAbsoluteTime now;
70
71 credential_t sessionCredential;
72 CFMutableSetRef credentials;
73 CFMutableSetRef effectiveCredentials;
74
75 CFMutableDictionaryRef mechanism_agents;
76
77 // set only in engine_authorize
78 const char * currentRightName; // weak ref
79 rule_t currentRule; // weak ref
80
81 rule_t authenticateRule;
82
83 bool dismissed;
84 };
85
86 static void
87 _engine_finalizer(CFTypeRef value)
88 {
89 engine_t engine = (engine_t)value;
90
91 CFReleaseNull(engine->mechanism_agents);
92 CFReleaseNull(engine->conn);
93 CFReleaseNull(engine->auth);
94 CFReleaseNull(engine->hints);
95 CFReleaseNull(engine->context);
96 CFReleaseNull(engine->immutable_hints);
97 CFReleaseNull(engine->sticky_context);
98 CFReleaseNull(engine->grantedRights);
99 CFReleaseNull(engine->sessionCredential);
100 CFReleaseNull(engine->credentials);
101 CFReleaseNull(engine->effectiveCredentials);
102 CFReleaseNull(engine->authenticateRule);
103 }
104
105 AUTH_TYPE_INSTANCE(engine,
106 .init = NULL,
107 .copy = NULL,
108 .finalize = _engine_finalizer,
109 .equal = NULL,
110 .hash = NULL,
111 .copyFormattingDesc = NULL,
112 .copyDebugDesc = NULL
113 );
114
115 static CFTypeID engine_get_type_id() {
116 static CFTypeID type_id = _kCFRuntimeNotATypeID;
117 static dispatch_once_t onceToken;
118
119 dispatch_once(&onceToken, ^{
120 type_id = _CFRuntimeRegisterClass(&_auth_type_engine);
121 });
122
123 return type_id;
124 }
125
126 engine_t
127 engine_create(connection_t conn, auth_token_t auth)
128 {
129 engine_t engine = NULL;
130 require(conn != NULL, done);
131 require(auth != NULL, done);
132
133 engine = (engine_t)_CFRuntimeCreateInstance(kCFAllocatorDefault, engine_get_type_id(), AUTH_CLASS_SIZE(engine), NULL);
134 require(engine != NULL, done);
135
136 engine->conn = (connection_t)CFRetain(conn);
137 engine->proc = connection_get_process(conn);
138 engine->auth = (auth_token_t)CFRetain(auth);
139
140 engine->hints = auth_items_create();
141 engine->context = auth_items_create();
142 engine->immutable_hints = auth_items_create();
143 engine->sticky_context = auth_items_create();
144 _set_process_hints(engine->hints, engine->proc);
145 _set_process_immutable_hints(engine->immutable_hints, engine->proc);
146 _set_auth_token_hints(engine->hints, engine->immutable_hints, auth);
147
148 engine->grantedRights = auth_rights_create();
149
150 engine->reason = noReason;
151
152 engine->preauthorizing = false;
153
154 engine->la_context = NULL;
155
156 engine->now = CFAbsoluteTimeGetCurrent();
157
158 session_update(auth_token_get_session(engine->auth));
159 engine->sessionCredential = credential_create(session_get_uid(auth_token_get_session(engine->auth)));
160 engine->credentials = CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks);
161 engine->effectiveCredentials = CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks);
162
163 session_credentials_iterate(auth_token_get_session(engine->auth), ^bool(credential_t cred) {
164 CFSetAddValue(engine->effectiveCredentials, cred);
165 return true;
166 });
167
168 auth_token_credentials_iterate(engine->auth, ^bool(credential_t cred) {
169 // we added all session credentials already now just add all previously acquired credentials
170 if (!credential_get_shared(cred)) {
171 CFSetAddValue(engine->credentials, cred);
172 }
173 return true;
174 });
175
176 engine->mechanism_agents = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
177
178 done:
179 return engine;
180 }
181
182 #pragma mark -
183 #pragma mark agent hints
184
185 void
186 _set_process_hints(auth_items_t hints, process_t proc)
187 {
188 // process information
189 RequestorType type = bundle;
190 auth_items_set_data(hints, AGENT_HINT_CLIENT_TYPE, &type, sizeof(type));
191 auth_items_set_int(hints, AGENT_HINT_CLIENT_PID, process_get_pid(proc));
192 auth_items_set_uint(hints, AGENT_HINT_CLIENT_UID, process_get_uid(proc));
193 }
194
195 void
196 _set_process_immutable_hints(auth_items_t immutable_hints, process_t proc)
197 {
198 // process information - immutable
199 auth_items_set_bool(immutable_hints, AGENT_HINT_CLIENT_SIGNED, process_apple_signed(proc));
200 auth_items_set_bool(immutable_hints, AGENT_HINT_CLIENT_FROM_APPLE, process_firstparty_signed(proc));
201 }
202
203 void
204 _set_auth_token_hints(auth_items_t hints, auth_items_t immutable_hints, auth_token_t auth)
205 {
206 auth_items_set_string(hints, AGENT_HINT_CLIENT_PATH, auth_token_get_code_url(auth));
207 auth_items_set_int(hints, AGENT_HINT_CREATOR_PID, auth_token_get_pid(auth));
208 const audit_info_s * info = auth_token_get_audit_info(auth);
209 auth_items_set_data(hints, AGENT_HINT_CREATOR_AUDIT_TOKEN, &info->opaqueToken, sizeof(info->opaqueToken));
210
211 process_t proc = process_create(info, auth_token_get_session(auth));
212 if (proc) {
213 auth_items_set_bool(immutable_hints, AGENT_HINT_CREATOR_SIGNED, process_apple_signed(proc));
214 auth_items_set_bool(immutable_hints, AGENT_HINT_CREATOR_FROM_APPLE, process_firstparty_signed(proc));
215 }
216 CFReleaseSafe(proc);
217 }
218
219 static void
220 _set_right_hints(auth_items_t hints, const char * right)
221 {
222 auth_items_set_string(hints, AGENT_HINT_AUTHORIZE_RIGHT, right);
223 }
224
225 static void
226 _set_rule_hints(auth_items_t hints, rule_t rule)
227 {
228 auth_items_set_string(hints, AGENT_HINT_AUTHORIZE_RULE, rule_get_name(rule));
229 const char * group = rule_get_group(rule);
230 if (rule_get_class(rule) == RC_USER && group != NULL) {
231 auth_items_set_string(hints, AGENT_HINT_REQUIRE_USER_IN_GROUP, group);
232 } else {
233 auth_items_remove(hints, AGENT_HINT_REQUIRE_USER_IN_GROUP);
234 }
235 }
236
237 static void
238 _set_localization_hints(authdb_connection_t dbconn, auth_items_t hints, rule_t rule)
239 {
240 char * key = calloc(1u, 128);
241
242 authdb_step(dbconn, "SELECT lang,value FROM prompts WHERE r_id = ?", ^(sqlite3_stmt *stmt) {
243 sqlite3_bind_int64(stmt, 1, rule_get_id(rule));
244 }, ^bool(auth_items_t data) {
245 snprintf(key, 128, "%s%s", kAuthorizationRuleParameterDescription, auth_items_get_string(data, "lang"));
246 auth_items_set_string(hints, key, auth_items_get_string(data, "value"));
247 auth_items_set_flags(hints, key, kEngineHintsFlagTemporary);
248 return true;
249 });
250
251 authdb_step(dbconn, "SELECT lang,value FROM buttons WHERE r_id = ?", ^(sqlite3_stmt *stmt) {
252 sqlite3_bind_int64(stmt, 1, rule_get_id(rule));
253 }, ^bool(auth_items_t data) {
254 snprintf(key, 128, "%s%s", kAuthorizationRuleParameterButton, auth_items_get_string(data, "lang"));
255 auth_items_set_string(hints, key, auth_items_get_string(data, "value"));
256 auth_items_set_flags(hints, key, kEngineHintsFlagTemporary);
257 return true;
258 });
259
260 free_safe(key);
261 }
262
263 static void
264 _set_session_hints(engine_t engine, rule_t rule)
265 {
266 os_log_debug(AUTHD_LOG, "engine: ** prepare agent hints for rule %{public}s", rule_get_name(rule));
267 if (_evaluate_user_credential_for_rule(engine, engine->sessionCredential, rule, true, true, NULL) == errAuthorizationSuccess) {
268 const char * tmp = credential_get_name(engine->sessionCredential);
269 if (tmp != NULL) {
270 auth_items_set_string(engine->hints, AGENT_HINT_SUGGESTED_USER, tmp);
271 }
272 tmp = credential_get_realname(engine->sessionCredential);
273 if (tmp != NULL) {
274 auth_items_set_string(engine->hints, AGENT_HINT_SUGGESTED_USER_LONG, tmp);
275 }
276 } else {
277 auth_items_remove(engine->hints, AGENT_HINT_SUGGESTED_USER);
278 auth_items_remove(engine->hints, AGENT_HINT_SUGGESTED_USER_LONG);
279 }
280 }
281
282 #pragma mark -
283 #pragma mark right processing
284
285 static OSStatus
286 _evaluate_credential_for_rule(engine_t engine, credential_t cred, rule_t rule, bool ignoreShared, bool sessionOwner, enum Reason * reason)
287 {
288 if (auth_token_least_privileged(engine->auth)) {
289 if (credential_is_right(cred) && credential_get_valid(cred) && _compare_string(engine->currentRightName, credential_get_name(cred))) {
290 if (!ignoreShared) {
291 if (!rule_get_shared(rule) && credential_get_shared(cred)) {
292 os_log_error(AUTHD_LOG, "engine: - shared right %{public}s (does NOT satisfy rule)", credential_get_name(cred));
293 if (reason) { *reason = unknownReason; }
294 return errAuthorizationDenied;
295 }
296 }
297
298 return errAuthorizationSuccess;
299 } else {
300 if (reason) { *reason = unknownReason; }
301 return errAuthorizationDenied;
302 }
303 } else {
304 return _evaluate_user_credential_for_rule(engine,cred,rule,ignoreShared,sessionOwner, reason);
305 }
306 }
307
308 static OSStatus
309 _evaluate_user_credential_for_rule(engine_t engine, credential_t cred, rule_t rule, bool ignoreShared, bool sessionOwner, enum Reason * reason)
310 {
311 const char * cred_label = sessionOwner ? "session owner" : "credential";
312 os_log(AUTHD_LOG, "engine: - validating %{public}s%{public}s %{public}s (%i) for %{public}s", credential_get_shared(cred) ? "shared " : "",
313 cred_label,
314 credential_get_name(cred),
315 credential_get_uid(cred),
316 rule_get_name(rule));
317
318 if (rule_get_class(rule) != RC_USER) {
319 os_log(AUTHD_LOG, "engine: - invalid rule class %i (denied)", rule_get_class(rule));
320 return errAuthorizationDenied;
321 }
322
323 if (credential_get_valid(cred) != true) {
324 os_log(AUTHD_LOG, "engine: - %{public}s %i invalid (does NOT satisfy rule)", cred_label, credential_get_uid(cred));
325 if (reason) { *reason = invalidPassphrase; }
326 return errAuthorizationDenied;
327 }
328
329 if (engine->now - credential_get_creation_time(cred) > rule_get_timeout(rule)) {
330 os_log(AUTHD_LOG, "engine: - %{public}s %i expired '%f > %lli' (does NOT satisfy rule)", cred_label, credential_get_uid(cred),
331 (engine->now - credential_get_creation_time(cred)), rule_get_timeout(rule));
332 if (reason) { *reason = unknownReason; }
333 return errAuthorizationDenied;
334 }
335
336
337 if (!ignoreShared) {
338 if (!rule_get_shared(rule) && credential_get_shared(cred)) {
339 os_log(AUTHD_LOG, "engine: - shared %{public}s %i (does NOT satisfy rule)", cred_label, credential_get_uid(cred));
340 if (reason) { *reason = unknownReason; }
341 return errAuthorizationDenied;
342 }
343 }
344
345 if (credential_get_uid(cred) == 0) {
346 os_log(AUTHD_LOG, "engine: - %{public}s %i has uid 0 (does satisfy rule)", cred_label, credential_get_uid(cred));
347 return errAuthorizationSuccess;
348 }
349
350 if (rule_get_session_owner(rule)) {
351 if (credential_get_uid(cred) == session_get_uid(auth_token_get_session(engine->auth))) {
352 os_log(AUTHD_LOG, "engine: - %{public}s %i is session owner (does satisfy rule)", cred_label, credential_get_uid(cred));
353 return errAuthorizationSuccess;
354 }
355 }
356
357 if (rule_get_group(rule) != NULL) {
358 do
359 {
360 // This allows testing a group modifier without prompting the user
361 // When (authenticate-user = false) we are just testing the creator uid.
362 // If a group modifier is enabled (RuleFlagEntitledAndGroup | RuleFlagVPNEntitledAndGroup)
363 // we want to skip the creator uid group check.
364 // group modifiers are checked early during the evaluation in _check_entitlement_for_rule
365 if (!rule_get_authenticate_user(rule)) {
366 if (rule_check_flags(rule, RuleFlagEntitledAndGroup | RuleFlagVPNEntitledAndGroup)) {
367 break;
368 }
369 }
370
371 if (credential_check_membership(cred, rule_get_group(rule))) {
372 os_log(AUTHD_LOG, "engine: - %{public}s %i is member of group %{public}s (does satisfy rule)", cred_label, credential_get_uid(cred), rule_get_group(rule));
373 return errAuthorizationSuccess;
374 } else {
375 if (reason) { *reason = userNotInGroup; }
376 }
377 } while (0);
378 } else if (rule_get_session_owner(rule)) { // rule asks only if user is the session owner
379 if (reason) { *reason = unacceptableUser; }
380 }
381
382 os_log(AUTHD_LOG, "engine: - %{public}s %i (does NOT satisfy rule), reason %d", cred_label, credential_get_uid(cred), reason ? *reason : -1);
383 return errAuthorizationDenied;
384 }
385
386 static agent_t
387 _get_agent(engine_t engine, mechanism_t mech, bool create, bool firstMech)
388 {
389 agent_t agent = (agent_t)CFDictionaryGetValue(engine->mechanism_agents, mech);
390 if (create && !agent) {
391 agent = agent_create(engine, mech, engine->auth, engine->proc, firstMech);
392 if (agent) {
393 CFDictionaryAddValue(engine->mechanism_agents, mech, agent);
394 CFReleaseSafe(agent);
395 }
396 }
397 return agent;
398 }
399
400 static uint64_t
401 _evaluate_builtin_mechanism(engine_t engine, mechanism_t mech)
402 {
403 uint64_t result = kAuthorizationResultDeny;
404
405 switch (mechanism_get_type(mech)) {
406 case kMechanismTypeEntitled:
407 if (auth_token_has_entitlement_for_right(engine->auth, engine->currentRightName)) {
408 result = kAuthorizationResultAllow;
409 }
410 break;
411 default:
412 break;
413 }
414
415 return result;
416 }
417
418
419 static bool
420 _extract_password_from_la(engine_t engine, CFTypeRef la_context)
421 {
422 bool retval = false;
423 // try to retrieve secret
424 CFDataRef passdata = LACopyCredential(la_context, kLACredentialTypeExtractablePasscode, NULL);
425 if (passdata) {
426 if (CFDataGetBytePtr(passdata)) {
427 auth_items_set_data(engine->context, kAuthorizationEnvironmentPassword, CFDataGetBytePtr(passdata), CFDataGetLength(passdata));
428 } else {
429 char nulChar = 0;
430 auth_items_set_data(engine->context, kAuthorizationEnvironmentPassword, &nulChar, 1);
431 }
432 CFRelease(passdata);
433 }
434 return retval;
435 }
436
437 static OSStatus
438 _evaluate_mechanisms(engine_t engine, CFArrayRef mechanisms)
439 {
440 uint64_t result = kAuthorizationResultAllow;
441 ccaudit_t ccaudit = ccaudit_create(engine->proc, engine->auth, AUE_ssauthmech);
442 auth_items_t context = auth_items_create();
443 auth_items_t hints = auth_items_create();
444
445 auth_items_copy(context, engine->context);
446 auth_items_copy(hints, engine->hints);
447 auth_items_copy(context, engine->sticky_context);
448
449 CFDictionaryRef la_result = NULL;
450
451 CFIndex count = CFArrayGetCount(mechanisms);
452 for (CFIndex i = 0; i < count; i++) {
453 mechanism_t mech = (mechanism_t)CFArrayGetValueAtIndex(mechanisms, i);
454
455 if (mechanism_get_type(mech)) {
456 os_log_debug(AUTHD_LOG, "engine: running builtin mechanism %{public}s (%li of %li)", mechanism_get_string(mech), i+1, count);
457 result = _evaluate_builtin_mechanism(engine, mech);
458 } else {
459 bool sheet_variant_used = false;
460 if (engine->la_context) {
461
462 if (!la_result) {
463 int tmp = kLAOptionNotInteractive;
464 CFNumberRef key = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &tmp);
465 tmp = 1;
466 CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &tmp);
467 if (key && value) {
468 CFMutableDictionaryRef options = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
469 CFDictionarySetValue(options, key, value);
470 la_result = LACopyResultOfPolicyEvaluation(engine->la_context, kLAPolicyDeviceOwnerAuthentication, options, NULL);
471 CFReleaseSafe(options);
472 }
473 CFReleaseSafe(key);
474 CFReleaseSafe(value);
475 }
476
477 // sheet variant in progress
478 if (strcmp(mechanism_get_string(mech), "builtin:authenticate") == 0) {
479 // instead of running SecurityAgent, get uid from the authorization
480 os_log(AUTHD_LOG, "engine: running builtin sheet authenticate");
481 if (!la_result) {
482 result = kAuthorizationResultDeny; // no la_result => was evaluate did not pass
483 }
484 sheet_variant_used = true;
485 } else if (strcmp(mechanism_get_string(mech), "builtin:authenticate,privileged") == 0) {
486 os_log(AUTHD_LOG, "engine: running builtin sheet privileged authenticate");
487 if (!la_result) {
488 result = kAuthorizationResultDeny; // no la_result => was evaluate did not pass
489 } else {
490 if (!_extract_password_from_la(engine, engine->la_context)) {
491 os_log_debug(AUTHD_LOG, "engine: cannot extract cred");
492 }
493 }
494 sheet_variant_used = true;
495 }
496 }
497
498 if (!sheet_variant_used) {
499 agent_t agent = _get_agent(engine, mech, true, i == 0);
500 require_action(agent != NULL, done, result = kAuthorizationResultUndefined; os_log_error(AUTHD_LOG, "engine: error creating mechanism agent"));
501
502 // check if any agent has been interrupted (it necessary if interrupt will come during creation)
503 CFIndex j;
504 agent_t agent1;
505 for (j = 0; j < i; j++) {
506 agent1 = _get_agent(engine, (mechanism_t)CFArrayGetValueAtIndex(mechanisms, j), false, j == 0);
507 if(agent1 && agent_get_state(agent1) == interrupting) {
508 break;
509 }
510 }
511 if (j < i) {
512 os_log(AUTHD_LOG, "engine: mechanisms interrupted");
513 char * buf = NULL;
514 asprintf(&buf, "evaluation interrupted by %s; restarting evaluation there", mechanism_get_string(agent_get_mechanism(agent1)));
515 ccaudit_log_mechanism(ccaudit, engine->currentRightName, mechanism_get_string(agent_get_mechanism(agent1)), kAuthorizationResultAllow, buf);
516 free_safe(buf);
517 ccaudit_log_mechanism(ccaudit, engine->currentRightName, mechanism_get_string(mech), kAuthorizationResultAllow, NULL);
518 const char * token_name = auth_items_get_string(hints, AGENT_HINT_TOKEN_NAME);
519 if (token_name && strlen(token_name) == 0) {
520 auth_items_remove(hints, AGENT_HINT_TOKEN_NAME);
521 }
522 auth_items_copy(context, agent_get_context(agent1));
523 auth_items_copy(hints, agent_get_hints(agent1));
524
525 i = j - 1;
526
527 continue;
528 }
529
530 os_log(AUTHD_LOG, "engine: running mechanism %{public}s (%li of %li)", mechanism_get_string(agent_get_mechanism(agent)), i+1, count);
531
532 result = agent_run(agent, hints, context, engine->immutable_hints);
533
534 auth_items_copy(context, agent_get_context(agent));
535 auth_items_copy(hints, agent_get_hints(agent));
536
537 bool interrupted = false;
538 for (CFIndex i2 = 0; i2 != i; i2++) {
539 agent_t agent2 = _get_agent(engine, (mechanism_t)CFArrayGetValueAtIndex(mechanisms, i2), false, i == 0);
540 if (agent2 && agent_get_state(agent2) == interrupting) {
541 agent_deactivate(agent);
542 interrupted = true;
543 i = i2 - 1;
544 char * buf = NULL;
545 asprintf(&buf, "evaluation interrupted by %s; restarting evaluation there", mechanism_get_string(agent_get_mechanism(agent2)));
546 ccaudit_log_mechanism(ccaudit, engine->currentRightName, mechanism_get_string(agent_get_mechanism(agent2)), kAuthorizationResultAllow, buf);
547 free_safe(buf);
548 auth_items_copy(context, agent_get_context(agent2));
549 auth_items_copy(hints, agent_get_hints(agent2));
550 break;
551 }
552 }
553
554 // Empty token name means that token doesn't exist (e.g. SC was removed).
555 // Remove empty token name from hints for UI drawing logic.
556 const char * token_name = auth_items_get_string(hints, AGENT_HINT_TOKEN_NAME);
557 if (token_name && strlen(token_name) == 0) {
558 auth_items_remove(hints, AGENT_HINT_TOKEN_NAME);
559 }
560
561 if (interrupted) {
562 os_log(AUTHD_LOG, "engine: mechanisms interrupted");
563 enum Reason reason = worldChanged;
564 auth_items_set_data(hints, AGENT_HINT_RETRY_REASON, &reason, sizeof(reason));
565 result = kAuthorizationResultAllow;
566 _cf_dictionary_iterate(engine->mechanism_agents, ^bool(CFTypeRef key __attribute__((__unused__)), CFTypeRef value) {
567 agent_t tempagent = (agent_t)value;
568 agent_clear_interrupt(tempagent);
569 return true;
570 });
571 }
572 }
573 }
574
575 if (result == kAuthorizationResultAllow) {
576 ccaudit_log_mechanism(ccaudit, engine->currentRightName, mechanism_get_string(mech), kAuthorizationResultAllow, NULL);
577 } else {
578 ccaudit_log_mechanism(ccaudit, engine->currentRightName, mechanism_get_string(mech), (uint32_t)result, NULL);
579 break;
580 }
581 }
582
583 done:
584 if ((result == kAuthorizationResultUserCanceled) || (result == kAuthorizationResultAllow)) {
585 // only make non-sticky context values available externally
586 auth_items_set_flags(context, kAuthorizationEnvironmentPassword, kAuthorizationContextFlagVolatile);
587 // <rdar://problem/16275827> Takauthorizationenvironmentusername should always be extractable
588 auth_items_set_flags(context, kAuthorizationEnvironmentUsername, kAuthorizationContextFlagExtractable);
589 auth_items_copy_with_flags(engine->context, context, kAuthorizationContextFlagExtractable | kAuthorizationContextFlagVolatile);
590 } else if (result == kAuthorizationResultDeny) {
591 auth_items_clear(engine->sticky_context);
592 // save off sticky values in context
593 auth_items_copy_with_flags(engine->sticky_context, context, kAuthorizationContextFlagSticky);
594 }
595
596 CFReleaseSafe(ccaudit);
597 CFReleaseSafe(context);
598 CFReleaseSafe(hints);
599 CFReleaseSafe(la_result);
600
601 switch(result)
602 {
603 case kAuthorizationResultDeny:
604 return errAuthorizationDenied;
605 case kAuthorizationResultUserCanceled:
606 return errAuthorizationCanceled;
607 case kAuthorizationResultAllow:
608 return errAuthorizationSuccess;
609 case kAuthorizationResultUndefined:
610 return errAuthorizationInternal;
611 default:
612 {
613 os_log_error(AUTHD_LOG, "engine: unexpected error result");
614 return errAuthorizationInternal;
615 }
616 }
617 }
618
619 static OSStatus
620 _evaluate_authentication(engine_t engine, rule_t rule)
621 {
622 OSStatus status = errAuthorizationDenied;
623 ccaudit_t ccaudit = ccaudit_create(engine->proc, engine->auth, AUE_ssauthint);
624 os_log_debug(AUTHD_LOG, "engine: evaluate authentication");
625 _set_rule_hints(engine->hints, rule);
626 _set_session_hints(engine, rule);
627
628 CFArrayRef mechanisms = rule_get_mechanisms(rule);
629 if (!(CFArrayGetCount(mechanisms) > 0)) {
630 mechanisms = rule_get_mechanisms(engine->authenticateRule);
631 }
632 require_action(CFArrayGetCount(mechanisms) > 0, done, os_log_debug(AUTHD_LOG, "engine: error no mechanisms found"));
633
634 int64_t ruleTries = rule_get_tries(rule);
635 for (engine->tries = 0; engine->tries < ruleTries; engine->tries++) {
636
637 auth_items_set_data(engine->hints, AGENT_HINT_RETRY_REASON, &engine->reason, sizeof(engine->reason));
638 auth_items_set_int(engine->hints, AGENT_HINT_TRIES, engine->tries);
639 status = _evaluate_mechanisms(engine, mechanisms);
640
641 os_log_debug(AUTHD_LOG, "engine: evaluate mechanisms result %d", (int)status);
642
643 // successfully ran mechanisms to obtain credential
644 if (status == errAuthorizationSuccess) {
645 // deny is the default
646 status = errAuthorizationDenied;
647
648 credential_t newCred = NULL;
649 if (auth_items_exist(engine->context, "uid")) {
650 newCred = credential_create(auth_items_get_uint(engine->context, "uid"));
651 } else {
652 os_log_error(AUTHD_LOG, "engine: mechanism failed to return a valid uid");
653 if (engine->la_context) {
654 // sheet failed so remove sheet reference and next time, standard dialog will be displayed
655 CFReleaseNull(engine->la_context);
656 }
657 }
658
659 if (newCred) {
660 if (credential_get_valid(newCred)) {
661 os_log(AUTHD_LOG, "UID %u authenticated as user %{public}s (UID %u) for right '%{public}s'", auth_token_get_uid(engine->auth), credential_get_name(newCred), credential_get_uid(newCred), engine->currentRightName);
662 ccaudit_log_success(ccaudit, newCred, engine->currentRightName);
663 } else {
664 os_log(AUTHD_LOG, "UID %u failed to authenticate as user '%{public}s' for right '%{public}s'", auth_token_get_uid(engine->auth), auth_items_get_string(engine->context, "username"), engine->currentRightName);
665 ccaudit_log_failure(ccaudit, auth_items_get_string(engine->context, "username"), engine->currentRightName);
666 }
667
668 status = _evaluate_user_credential_for_rule(engine, newCred, rule, true, false, &engine->reason);
669
670 if (status == errAuthorizationSuccess) {
671 _engine_set_credential(engine, newCred, rule_get_shared(rule));
672 CFReleaseSafe(newCred);
673
674 if (auth_token_least_privileged(engine->auth)) {
675 credential_t rightCred = credential_create_with_right(engine->currentRightName);
676 _engine_set_credential(engine, rightCred, rule_get_shared(rule));
677 CFReleaseSafe(rightCred);
678 }
679
680 session_t session = auth_token_get_session(engine->auth);
681 if (credential_get_uid(newCred) == session_get_uid(session)) {
682 os_log_debug(AUTHD_LOG, "engine: authenticated as the session owner");
683 session_set_attributes(auth_token_get_session(engine->auth), AU_SESSION_FLAG_HAS_AUTHENTICATED);
684 }
685
686 break;
687 } else {
688 os_log_error(AUTHD_LOG, "engine: user credential for rule failed (%d)", (int)status);
689 }
690
691 CFReleaseSafe(newCred);
692 }
693
694 } else if (status == errAuthorizationCanceled || status == errAuthorizationInternal) {
695 os_log_error(AUTHD_LOG, "engine: evaluate cancelled or failed %d", (int)status);
696 break;
697 } else if (status == errAuthorizationDenied) {
698 os_log_error(AUTHD_LOG, "engine: evaluate denied");
699 engine->reason = invalidPassphrase;
700 if (engine->la_context) {
701 // for sheet authorizations do not retry with sheet as there is no new sheet UI
702 CFReleaseNull(engine->la_context);
703 auth_items_remove(engine->context, AGENT_CONTEXT_UID);
704 }
705 }
706 }
707
708 if (engine->tries == ruleTries) {
709 engine->reason = tooManyTries;
710 auth_items_set_data(engine->hints, AGENT_HINT_RETRY_REASON, &engine->reason, sizeof(engine->reason));
711 auth_items_set_int(engine->hints, AGENT_HINT_TRIES, engine->tries);
712 // TODO: determine why evaluate_mechanism is run once again and possibly remove this call
713 _evaluate_mechanisms(engine, mechanisms);
714 ccaudit_log(ccaudit, engine->currentRightName, NULL, 1113);
715 }
716
717 done:
718 CFReleaseSafe(ccaudit);
719
720 return status;
721 }
722
723 static bool
724 _check_entitlement_for_rule(engine_t engine, rule_t rule)
725 {
726 bool entitled = false;
727 CFTypeRef value = NULL;
728
729 if (rule_check_flags(rule, RuleFlagEntitledAndGroup)) {
730 if (auth_token_has_entitlement_for_right(engine->auth, engine->currentRightName)) {
731 if (credential_check_membership(auth_token_get_credential(engine->auth), rule_get_group(rule))) {
732 os_log_debug(AUTHD_LOG, "engine: creator of authorization has entitlement for right %{public}s and is member of group '%{public}s'", engine->currentRightName, rule_get_group(rule));
733 entitled = true;
734 goto done;
735 }
736 }
737 }
738
739 if (rule_check_flags(rule, RuleFlagVPNEntitledAndGroup)) {
740 // com.apple.networking.vpn.configuration is an array we only check for it's existence
741 value = auth_token_copy_entitlement_value(engine->auth, "com.apple.networking.vpn.configuration");
742 if (value) {
743 if (credential_check_membership(auth_token_get_credential(engine->auth), rule_get_group(rule))) {
744 os_log_debug(AUTHD_LOG, "engine: creator of authorization has VPN entitlement and is member of group '%{public}s'", rule_get_group(rule));
745 entitled = true;
746 goto done;
747 }
748 }
749 }
750
751 done:
752 CFReleaseSafe(value);
753 return entitled;
754 }
755
756 static OSStatus
757 _evaluate_class_user(engine_t engine, rule_t rule)
758 {
759 __block OSStatus status = errAuthorizationDenied;
760
761 if (_check_entitlement_for_rule(engine,rule)) {
762 return errAuthorizationSuccess;
763 }
764
765 if (rule_get_allow_root(rule) && auth_token_get_uid(engine->auth) == 0) {
766 os_log_debug(AUTHD_LOG, "engine: creator of authorization has uid == 0 granting right %{public}s", engine->currentRightName);
767 return errAuthorizationSuccess;
768 }
769
770 if (!rule_get_authenticate_user(rule)) {
771 status = _evaluate_user_credential_for_rule(engine, engine->sessionCredential, rule, true, true, NULL);
772
773 if (status == errAuthorizationSuccess) {
774 return errAuthorizationSuccess;
775 }
776
777 return errAuthorizationDenied;
778 }
779
780 // First -- check all the credentials we have either acquired or currently have
781 _cf_set_iterate(engine->credentials, ^bool(CFTypeRef value) {
782 credential_t cred = (credential_t)value;
783 // Passed-in user credentials are allowed for least-privileged mode
784 if (auth_token_least_privileged(engine->auth) && !credential_is_right(cred) && credential_get_valid(cred)) {
785 status = _evaluate_user_credential_for_rule(engine, cred, rule, false, false, NULL);
786 if (errAuthorizationSuccess == status) {
787 credential_t rightCred = credential_create_with_right(engine->currentRightName);
788 _engine_set_credential(engine,rightCred,rule_get_shared(rule));
789 CFReleaseSafe(rightCred);
790 return false; // exit loop
791 }
792 }
793
794 status = _evaluate_credential_for_rule(engine, cred, rule, false, false, NULL);
795 if (status == errAuthorizationSuccess) {
796 return false; // exit loop
797 }
798 return true;
799 });
800
801 if (status == errAuthorizationSuccess) {
802 return status;
803 }
804
805 // Second -- go through the credentials associated to the authorization token session/auth token
806 _cf_set_iterate(engine->effectiveCredentials, ^bool(CFTypeRef value) {
807 credential_t cred = (credential_t)value;
808 status = _evaluate_credential_for_rule(engine, cred, rule, false, false, NULL);
809 if (status == errAuthorizationSuccess) {
810 // Add the credential we used to the output set.
811 _engine_set_credential(engine, cred, false);
812 return false; // exit loop
813 }
814 return true;
815 });
816
817 if (status == errAuthorizationSuccess) {
818 return status;
819 }
820
821 // Finally - we didn't find a credential. Obtain a new credential if our flags let us do so.
822 if (!(engine->flags & kAuthorizationFlagExtendRights)) {
823 os_log_error(AUTHD_LOG, "engine: authorization denied (kAuthorizationFlagExtendRights not set)");
824 return errAuthorizationDenied;
825 }
826
827 // authorization that timeout immediately cannot be preauthorized
828 if (engine->flags & kAuthorizationFlagPreAuthorize && rule_get_timeout(rule) == 0) {
829 return errAuthorizationSuccess;
830 }
831
832 if (!engine->preauthorizing) {
833 if (!(engine->flags & kAuthorizationFlagInteractionAllowed)) {
834 os_log_error(AUTHD_LOG, "engine: Interaction not allowed (kAuthorizationFlagInteractionAllowed not set)");
835 return errAuthorizationInteractionNotAllowed;
836 }
837
838 if (!(session_get_attributes(auth_token_get_session(engine->auth)) & AU_SESSION_FLAG_HAS_GRAPHIC_ACCESS)) {
839 os_log_error(AUTHD_LOG, "engine: Interaction not allowed (session has no ui access)");
840 return errAuthorizationInteractionNotAllowed;
841 }
842
843 if (server_in_dark_wake()) {
844 os_log_error(AUTHD_LOG, "engine: authorization denied (DW)");
845 return errAuthorizationDenied;
846 }
847 }
848
849 return _evaluate_authentication(engine, rule);
850 }
851
852 static OSStatus
853 _evaluate_class_rule(engine_t engine, rule_t rule, bool *save_pwd)
854 {
855 __block OSStatus status = errAuthorizationDenied;
856 int64_t kofn = rule_get_kofn(rule);
857
858 uint32_t total = (uint32_t)rule_get_delegates_count(rule);
859 __block uint32_t success_count = 0;
860 __block uint32_t count = 0;
861 os_log_debug(AUTHD_LOG, "engine: ** rule %{public}s has %zi delegates kofn = %lli",rule_get_name(rule), total, kofn);
862 rule_delegates_iterator(rule, ^bool(rule_t delegate) {
863 count++;
864
865 if (kofn != 0 && success_count == kofn) {
866 status = errAuthorizationSuccess;
867 return false;
868 }
869
870 os_log_debug(AUTHD_LOG, "engine: * evaluate rule %{public}s (%i)", rule_get_name(delegate), count);
871 status = _evaluate_rule(engine, delegate, save_pwd);
872
873 // if status is cancel/internal error abort
874 if ((status == errAuthorizationCanceled) || (status == errAuthorizationInternal))
875 return false;
876
877 if (status != errAuthorizationSuccess) {
878 if (kofn != 0) {
879 // if remaining is less than required abort
880 if ((total - count) < (kofn - success_count)) {
881 os_log_debug(AUTHD_LOG, "engine: rule evaluation remaining: %i, required: %lli", (total - count), (kofn - success_count));
882 return false;
883 }
884 return true;
885 }
886 return false;
887 } else {
888 success_count++;
889 return true;
890 }
891 });
892
893 return status;
894 }
895
896 static bool
897 _preevaluate_class_rule(engine_t engine, rule_t rule)
898 {
899 os_log_debug(AUTHD_LOG, "engine: _preevaluate_class_rule %{public}s", rule_get_name(rule));
900
901 __block bool password_only = false;
902 rule_delegates_iterator(rule, ^bool(rule_t delegate) {
903 if (_preevaluate_rule(engine, delegate)) {
904 password_only = true;
905 return false;
906 }
907 return true;
908 });
909
910 return password_only;
911 }
912
913 static OSStatus
914 _evaluate_class_mechanism(engine_t engine, rule_t rule)
915 {
916 OSStatus status = errAuthorizationDenied;
917 CFArrayRef mechanisms = NULL;
918
919 require_action(rule_get_mechanisms_count(rule) > 0, done, status = errAuthorizationSuccess; os_log_error(AUTHD_LOG, "engine: no mechanisms specified"));
920
921 mechanisms = rule_get_mechanisms(rule);
922
923 if (server_in_dark_wake()) {
924 CFIndex count = CFArrayGetCount(mechanisms);
925 for (CFIndex i = 0; i < count; i++) {
926 if (!mechanism_is_privileged((mechanism_t)CFArrayGetValueAtIndex(mechanisms, i))) {
927 os_log_error(AUTHD_LOG, "engine: authorization denied (in DW)");
928 goto done;
929 }
930 }
931 }
932
933 int64_t ruleTries = rule_get_tries(rule);
934 engine->tries = 0;
935 do {
936 auth_items_set_data(engine->hints, AGENT_HINT_RETRY_REASON, &engine->reason, sizeof(engine->reason));
937 auth_items_set_int(engine->hints, AGENT_HINT_TRIES, engine->tries);
938
939 status = _evaluate_mechanisms(engine, mechanisms);
940 os_log_debug(AUTHD_LOG, "engine: evaluate mechanisms result %d", (int)status);
941
942 if (status == errAuthorizationSuccess) {
943 credential_t newCred = NULL;
944 if (auth_items_exist(engine->context, "uid")) {
945 newCred = credential_create(auth_items_get_uint(engine->context, "uid"));
946 } else {
947 os_log(AUTHD_LOG, "engine: mechanism did not return a uid");
948 }
949
950 if (newCred) {
951 _engine_set_credential(engine, newCred, rule_get_shared(rule));
952
953 if (auth_token_least_privileged(engine->auth)) {
954 credential_t rightCred = credential_create_with_right(engine->currentRightName);
955 _engine_set_credential(engine, rightCred, rule_get_shared(rule));
956 CFReleaseSafe(rightCred);
957 }
958
959 if (strcmp(engine->currentRightName, "system.login.console") == 0 && !auth_items_exist(engine->context, AGENT_CONTEXT_AUTO_LOGIN)) {
960 session_set_attributes(auth_token_get_session(engine->auth), AU_SESSION_FLAG_HAS_AUTHENTICATED);
961 }
962
963 CFReleaseSafe(newCred);
964 }
965 }
966
967 engine->tries++;
968
969 } while ( (status == errAuthorizationDenied) // only if we have an expected faulure we continue
970 && ((ruleTries == 0) || ((ruleTries > 0) && engine->tries < ruleTries))); // ruleTries == 0 means we try forever
971 // ruleTires > 0 means we try upto ruleTries times
972 done:
973 return status;
974 }
975
976 // TODO: Remove when all clients have adopted entitlement
977 static bool
978 enforced_entitlement(void)
979 {
980 bool enforced_enabled = false;
981 //sudo defaults write /Library/Preferences/com.apple.authd enforceEntitlement -bool true
982 CFTypeRef enforce = (CFNumberRef)CFPreferencesCopyValue(CFSTR("enforceEntitlement"), CFSTR(SECURITY_AUTH_NAME), kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
983 if (enforce && CFGetTypeID(enforce) == CFBooleanGetTypeID()) {
984 enforced_enabled = CFBooleanGetValue((CFBooleanRef)enforce);
985 os_log_debug(AUTHD_LOG, "enforceEntitlement for extract password: %{public}s", enforced_enabled ? "enabled" : "disabled");
986 }
987 CFReleaseSafe(enforce);
988
989 return enforced_enabled;
990 }
991
992 static OSStatus
993 _evaluate_rule(engine_t engine, rule_t rule, bool *save_pwd)
994 {
995 if (rule_check_flags(rule, RuleFlagEntitled)) {
996 if (auth_token_has_entitlement_for_right(engine->auth, engine->currentRightName)) {
997 os_log_debug(AUTHD_LOG, "engine: rule allow, creator of authorization has entitlement for right %{public}s", engine->currentRightName);
998 return errAuthorizationSuccess;
999 }
1000 }
1001
1002 // check apple signature also for every sheet authorization + disable this check for debug builds
1003 if (engine->la_context || rule_check_flags(rule, RuleFlagRequireAppleSigned)) {
1004 if (!auth_token_apple_signed(engine->auth)) {
1005 #ifdef NDEBUG
1006 os_log_error(AUTHD_LOG, "engine: rule deny, creator of authorization is not signed by Apple");
1007 return errAuthorizationDenied;
1008 #else
1009 os_log_debug(AUTHD_LOG, "engine: in release mode, this rule would be denied because creator of authorization is not signed by Apple");
1010 #endif
1011 }
1012 }
1013
1014 if (rule_get_extract_password(rule)) {
1015 // check if process is entitled to extract password
1016 CFTypeRef extract_password_entitlement = auth_token_copy_entitlement_value(engine->auth, "com.apple.authorization.extract-password");
1017 if (extract_password_entitlement && (CFGetTypeID(extract_password_entitlement) == CFBooleanGetTypeID()) && extract_password_entitlement == kCFBooleanTrue) {
1018 *save_pwd = TRUE;
1019 os_log_debug(AUTHD_LOG, "engine: authorization allowed to extract password");
1020 } else {
1021 os_log_debug(AUTHD_LOG, "engine: authorization NOT allowed to extract password");
1022 }
1023 CFReleaseSafe(extract_password_entitlement);
1024 }
1025
1026 // TODO: Remove when all clients have adopted entitlement
1027 if (!enforced_entitlement()) {
1028 *save_pwd |= rule_get_extract_password(rule);
1029 }
1030
1031 switch (rule_get_class(rule)) {
1032 case RC_ALLOW:
1033 os_log(AUTHD_LOG, "engine: rule set to allow");
1034 return errAuthorizationSuccess;
1035 case RC_DENY:
1036 os_log(AUTHD_LOG, "engine: rule set to deny");
1037 return errAuthorizationDenied;
1038 case RC_USER:
1039 return _evaluate_class_user(engine, rule);
1040 case RC_RULE:
1041 return _evaluate_class_rule(engine, rule, save_pwd);
1042 case RC_MECHANISM:
1043 return _evaluate_class_mechanism(engine, rule);
1044 default:
1045 os_log_error(AUTHD_LOG, "engine: invalid class for rule or rule not found: %{public}s", rule_get_name(rule));
1046 return errAuthorizationInternal;
1047 }
1048 }
1049
1050 // returns true if this rule or its children contain RC_USER rule with password_only==true
1051 static bool
1052 _preevaluate_rule(engine_t engine, rule_t rule)
1053 {
1054 os_log_debug(AUTHD_LOG, "engine: _preevaluate_rule %{public}s", rule_get_name(rule));
1055
1056 switch (rule_get_class(rule)) {
1057 case RC_ALLOW:
1058 case RC_DENY:
1059 return false;
1060 case RC_USER:
1061 return rule_get_password_only(rule);
1062 case RC_RULE:
1063 return _preevaluate_class_rule(engine, rule);
1064 case RC_MECHANISM:
1065 return false;
1066 default:
1067 return false;
1068 }
1069 }
1070
1071 static rule_t
1072 _find_rule(engine_t engine, authdb_connection_t dbconn, const char * string)
1073 {
1074 rule_t r = NULL;
1075 size_t sLen = strlen(string);
1076
1077 char * buf = calloc(1u, sLen + 1);
1078 strlcpy(buf, string, sLen + 1);
1079 char * ptr = buf + sLen;
1080 __block int64_t count = 0;
1081
1082 for (;;) {
1083
1084 // lookup rule
1085 authdb_step(dbconn, "SELECT COUNT(name) AS cnt FROM rules WHERE name = ? AND type = 1",
1086 ^(sqlite3_stmt *stmt) {
1087 sqlite3_bind_text(stmt, 1, buf, -1, NULL);
1088 }, ^bool(auth_items_t data) {
1089 count = auth_items_get_int64(data, "cnt");
1090 return false;
1091 });
1092
1093 if (count > 0) {
1094 r = rule_create_with_string(buf, dbconn);
1095 goto done;
1096 }
1097
1098 // if buf ends with a . and we didn't find a rule remove .
1099 if (*ptr == '.') {
1100 *ptr = '\0';
1101 }
1102 // find any remaining . and truncate the string
1103 ptr = strrchr(buf, '.');
1104 if (ptr) {
1105 *(ptr+1) = '\0';
1106 } else {
1107 break;
1108 }
1109 }
1110
1111 done:
1112 free_safe(buf);
1113
1114 // set default if we didn't find a rule
1115 if (r == NULL) {
1116 r = rule_create_with_string("", dbconn);
1117 if (rule_get_id(r) == 0) {
1118 CFReleaseNull(r);
1119 os_log_error(AUTHD_LOG, "engine: default rule lookup error (missing), using builtin defaults");
1120 r = rule_create_default();
1121 }
1122 }
1123 return r;
1124 }
1125
1126 static void _parse_environment(engine_t engine, auth_items_t environment)
1127 {
1128 require(environment != NULL, done);
1129
1130 #if DEBUG
1131 os_log_debug(AUTHD_LOG, "engine: Dumping Environment: %@", environment);
1132 #endif
1133
1134 // Check if a credential was passed into the environment and we were asked to extend the rights
1135 if (engine->flags & kAuthorizationFlagExtendRights) {
1136 const char * user = auth_items_get_string(environment, kAuthorizationEnvironmentUsername);
1137 const char * pass = auth_items_get_string(environment, kAuthorizationEnvironmentPassword);
1138 const bool password_was_used = auth_items_get_string(environment, AGENT_CONTEXT_AP_PAM_SERVICE_NAME) == nil; // AGENT_CONTEXT_AP_PAM_SERVICE_NAME in the context means alternative PAM was used
1139 require(password_was_used == true, done);
1140
1141 bool shared = auth_items_exist(environment, kAuthorizationEnvironmentShared);
1142 require_action(user != NULL, done, os_log_debug(AUTHD_LOG, "engine: user not used password"));
1143
1144 struct passwd *pw = getpwnam(user);
1145 require_action(pw != NULL, done, os_log_error(AUTHD_LOG, "engine: user not found %{public}s", user));
1146
1147 int checkpw_status = checkpw_internal(pw, pass ? pass : "");
1148 require_action(checkpw_status == CHECKPW_SUCCESS, done, os_log_error(AUTHD_LOG, "engine: checkpw() returned %d; failed to authenticate user %{public}s (uid %u).", checkpw_status, pw->pw_name, pw->pw_uid));
1149
1150 credential_t cred = credential_create(pw->pw_uid);
1151 if (credential_get_valid(cred)) {
1152 os_log(AUTHD_LOG, "engine: checkpw() succeeded, creating credential for user %{public}s", user);
1153 _engine_set_credential(engine, cred, shared);
1154
1155 auth_items_set_string(engine->context, kAuthorizationEnvironmentUsername, user);
1156 auth_items_set_string(engine->context, kAuthorizationEnvironmentPassword, pass ? pass : "");
1157 }
1158 CFReleaseSafe(cred);
1159 }
1160
1161 done:
1162 endpwent();
1163 return;
1164 }
1165
1166 static bool _verify_sandbox(engine_t engine, const char * right)
1167 {
1168 pid_t pid = process_get_pid(engine->proc);
1169 if (sandbox_check(pid, "authorization-right-obtain", SANDBOX_FILTER_RIGHT_NAME, right)) {
1170 os_log_error(AUTHD_LOG, "Sandbox denied authorizing right '%{public}s' by client '%{public}s' [%d]", right, process_get_code_url(engine->proc), pid);
1171 return false;
1172 }
1173
1174 pid = auth_token_get_pid(engine->auth);
1175 if (auth_token_get_sandboxed(engine->auth) && sandbox_check_by_audit_token(auth_token_get_audit_info(engine->auth)->opaqueToken, "authorization-right-obtain", SANDBOX_FILTER_RIGHT_NAME, right)) {
1176 os_log_error(AUTHD_LOG, "Sandbox denied authorizing right '%{public}s' for authorization created by '%{public}s' [%d]", right, auth_token_get_code_url(engine->auth), pid);
1177 return false;
1178 }
1179
1180 return true;
1181 }
1182
1183 #pragma mark -
1184 #pragma mark engine methods
1185
1186 OSStatus engine_preauthorize(engine_t engine, auth_items_t credentials)
1187 {
1188 os_log(AUTHD_LOG, "engine: preauthorizing");
1189
1190 OSStatus status = errAuthorizationDenied;
1191 bool save_password = false;
1192 CFTypeRef extract_password_entitlement = auth_token_copy_entitlement_value(engine->auth, "com.apple.authorization.extract-password");
1193 if (extract_password_entitlement && (CFGetTypeID(extract_password_entitlement) == CFBooleanGetTypeID()) && extract_password_entitlement == kCFBooleanTrue) {
1194 save_password = true;
1195 os_log_debug(AUTHD_LOG, "engine: authorization allowed to extract password");
1196 } else {
1197 os_log_debug(AUTHD_LOG, "engine: authorization NOT allowed to extract password");
1198 }
1199 CFReleaseSafe(extract_password_entitlement);
1200
1201 // TODO: Remove when all clients have adopted entitlement
1202 if (!enforced_entitlement()) {
1203 save_password = true;
1204 }
1205
1206 engine->flags = kAuthorizationFlagExtendRights;
1207 engine->preauthorizing = true;
1208 CFTypeRef la_context = engine_copy_context(engine, credentials);
1209 if (la_context) {
1210 _extract_password_from_la(engine, la_context);
1211 CFRelease(la_context);
1212 }
1213
1214 const char *user = auth_items_get_string(credentials, kAuthorizationEnvironmentUsername);
1215 require(user, done);
1216
1217 auth_items_set_string(engine->context, kAuthorizationEnvironmentUsername, user);
1218 struct passwd *pwd = getpwnam(user);
1219 require(pwd, done);
1220
1221 auth_items_set_int(engine->context, AGENT_CONTEXT_UID, pwd->pw_uid);
1222
1223 const char *service = auth_items_get_string(credentials, AGENT_CONTEXT_AP_PAM_SERVICE_NAME);
1224
1225 if (service) {
1226 auth_items_set_string(engine->context, AGENT_CONTEXT_AP_USER_NAME, user);
1227 auth_items_set_string(engine->context, AGENT_CONTEXT_AP_PAM_SERVICE_NAME, service);
1228 }
1229
1230 if (auth_items_exist(credentials, AGENT_CONTEXT_AP_TOKEN)) {
1231 size_t datalen = 0;
1232 const void *data = auth_items_get_data(credentials, AGENT_CONTEXT_AP_TOKEN, &datalen);
1233 if (data) {
1234 auth_items_set_data(engine->context, AGENT_CONTEXT_AP_TOKEN, data, datalen);
1235 }
1236 }
1237
1238 auth_items_t decrypted_items = auth_items_create();
1239 require_action(decrypted_items != NULL, done, os_log_error(AUTHD_LOG, "engine: unable to create items"));
1240 auth_items_content_copy(decrypted_items, auth_token_get_context(engine->auth));
1241 auth_items_decrypt(decrypted_items, auth_token_get_encryption_key(engine->auth));
1242 auth_items_copy(engine->context, decrypted_items);
1243 CFReleaseSafe(decrypted_items);
1244
1245 engine->dismissed = false;
1246 auth_rights_clear(engine->grantedRights);
1247
1248 rule_t rule = rule_create_preauthorization();
1249 engine->currentRightName = rule_get_name(rule);
1250 engine->currentRule = rule;
1251 status = _evaluate_rule(engine, rule, &save_password);
1252 switch (status) {
1253 case errAuthorizationSuccess:
1254 os_log(AUTHD_LOG, "Succeeded preauthorizing client '%{public}s' [%d] for authorization created by '%{public}s' [%d] (%X,%d)",
1255 process_get_code_url(engine->proc), process_get_pid(engine->proc),
1256 auth_token_get_code_url(engine->auth), auth_token_get_pid(engine->auth), (unsigned int)engine->flags, auth_token_least_privileged(engine->auth));
1257 status = errAuthorizationSuccess;
1258 break;
1259 case errAuthorizationDenied:
1260 case errAuthorizationInteractionNotAllowed:
1261 case errAuthorizationCanceled:
1262 os_log(AUTHD_LOG, "Failed to preauthorize client '%{public}s' [%d] for authorization created by '%{public}s' [%d] (%X,%d) (%i)",
1263 process_get_code_url(engine->proc), process_get_pid(engine->proc),
1264 auth_token_get_code_url(engine->auth), auth_token_get_pid(engine->auth), (unsigned int)engine->flags, auth_token_least_privileged(engine->auth), (int)status);
1265 break;
1266 default:
1267 os_log_error(AUTHD_LOG, "engine: preauthorize returned %d => returning errAuthorizationInternal", (int)status);
1268 status = errAuthorizationInternal;
1269 break;
1270 }
1271
1272 CFReleaseSafe(rule);
1273
1274 if (engine->dismissed) {
1275 os_log_error(AUTHD_LOG, "engine: engine dismissed");
1276 status = errAuthorizationDenied;
1277 }
1278
1279 os_log_debug(AUTHD_LOG, "engine: preauthorize result: %d", (int)status);
1280
1281 _cf_set_iterate(engine->credentials, ^bool(CFTypeRef value) {
1282 credential_t cred = (credential_t)value;
1283 // skip all uid credentials when running in least privileged
1284 if (auth_token_least_privileged(engine->auth) && !credential_is_right(cred))
1285 return true;
1286
1287 session_t session = auth_token_get_session(engine->auth);
1288 auth_token_set_credential(engine->auth, cred);
1289 if (credential_get_shared(cred)) {
1290 session_set_credential(session, cred);
1291 }
1292 if (credential_is_right(cred)) {
1293 os_log(AUTHD_LOG, "engine: adding least privileged %{public}scredential %{public}s to authorization", credential_get_shared(cred) ? "shared " : "", credential_get_name(cred));
1294 } else {
1295 os_log(AUTHD_LOG, "engine: adding %{public}scredential %{public}s (%i) to authorization", credential_get_shared(cred) ? "shared " : "", credential_get_name(cred), credential_get_uid(cred));
1296 }
1297 return true;
1298 });
1299
1300
1301 if (status == errAuthorizationSuccess && save_password) {
1302 auth_items_set_flags(engine->context, kAuthorizationEnvironmentPassword, kAuthorizationContextFlagExtractable);
1303 }
1304
1305 if ((status == errAuthorizationSuccess) || (status == errAuthorizationCanceled)) {
1306 auth_items_t encrypted_items = auth_items_create();
1307 require_action(encrypted_items != NULL, done, os_log_error(AUTHD_LOG, "engine: unable to create items"));
1308 auth_items_content_copy_with_flags(encrypted_items, engine->context, kAuthorizationContextFlagExtractable);
1309 #if DEBUG
1310 os_log_debug(AUTHD_LOG, "engine: ********** Dumping preauthorized context for encryption **********");
1311 os_log_debug(AUTHD_LOG, "%@", encrypted_items);
1312 #endif
1313 auth_items_encrypt(encrypted_items, auth_token_get_encryption_key(engine->auth));
1314 auth_items_copy_with_flags(auth_token_get_context(engine->auth), encrypted_items, kAuthorizationContextFlagExtractable);
1315 os_log_debug(AUTHD_LOG, "engine: encrypted preauthorization context data");
1316 CFReleaseSafe(encrypted_items);
1317 }
1318
1319 done:
1320 engine->preauthorizing = false;
1321 auth_items_clear(engine->context);
1322 auth_items_clear(engine->sticky_context);
1323 CFDictionaryRemoveAllValues(engine->mechanism_agents);
1324 return status;
1325 }
1326
1327 OSStatus engine_authorize(engine_t engine, auth_rights_t rights, auth_items_t environment, AuthorizationFlags flags)
1328 {
1329 __block OSStatus status = errAuthorizationSuccess;
1330 __block bool save_password = false;
1331 __block bool password_only = false;
1332
1333 ccaudit_t ccaudit = NULL;
1334
1335 require(rights != NULL, done);
1336
1337 ccaudit = ccaudit_create(engine->proc, engine->auth, AUE_ssauthorize);
1338 if (auth_rights_get_count(rights) > 0) {
1339 ccaudit_log(ccaudit, "begin evaluation", NULL, 0);
1340 }
1341
1342 engine->flags = flags;
1343
1344 if (environment) {
1345 _parse_environment(engine, environment);
1346 auth_items_copy(engine->hints, environment);
1347 engine_acquire_sheet_data(engine);
1348 }
1349
1350 auth_items_t decrypted_items = auth_items_create();
1351 require_action(decrypted_items != NULL, done, os_log_error(AUTHD_LOG, "engine: enable to create items"));
1352 auth_items_content_copy(decrypted_items, auth_token_get_context(engine->auth));
1353 auth_items_decrypt(decrypted_items, auth_token_get_encryption_key(engine->auth));
1354 auth_items_copy(engine->context, decrypted_items);
1355 CFReleaseSafe(decrypted_items);
1356
1357 engine->dismissed = false;
1358 auth_rights_clear(engine->grantedRights);
1359
1360 {
1361 // first check if any of rights uses rule with password-only set to true
1362 // if so, set appropriate hint so SecurityAgent won't use alternate authentication methods like smartcard etc.
1363 authdb_connection_t dbconn = authdb_connection_acquire(server_get_database()); // get db handle
1364 auth_rights_iterate(rights, ^bool(const char *key) {
1365 if (!key)
1366 return true;
1367 os_log_debug(AUTHD_LOG, "engine: checking if rule %{public}s contains password-only item", key);
1368
1369 rule_t rule = _find_rule(engine, dbconn, key);
1370
1371 if (rule && _preevaluate_rule(engine, rule)) {
1372 password_only = true;
1373 CFReleaseSafe(rule);
1374 return false;
1375 }
1376 CFReleaseSafe(rule);
1377 return true;
1378 });
1379 authdb_connection_release(&dbconn); // release db handle
1380 }
1381
1382 if (password_only) {
1383 os_log_debug(AUTHD_LOG, "engine: password-only item found, forcing SecurityAgent to use password-only UI");
1384 auth_items_set_bool(engine->immutable_hints, AGENT_HINT_PASSWORD_ONLY, true);
1385 }
1386
1387 auth_rights_iterate(rights, ^bool(const char *key) {
1388 if (!key)
1389 return true;
1390
1391
1392 if (!_verify_sandbox(engine, key)) { // _verify_sandbox is already logging failures
1393 status = errAuthorizationDenied;
1394 return false;
1395 }
1396
1397 authdb_connection_t dbconn = authdb_connection_acquire(server_get_database()); // get db handle
1398
1399 os_log_debug(AUTHD_LOG, "engine: evaluate right %{public}s", key);
1400 rule_t rule = _find_rule(engine, dbconn, key);
1401 const char * rule_name = rule_get_name(rule);
1402 if (rule_name && (strcasecmp(rule_name, "") == 0)) {
1403 rule_name = "default (not defined)";
1404 }
1405 os_log_debug(AUTHD_LOG, "engine: using rule %{public}s", rule_name);
1406
1407 // only need the hints & mechanisms if we are going to show ui
1408 if (engine->flags & kAuthorizationFlagInteractionAllowed) {
1409 _set_right_hints(engine->hints, key);
1410 _set_localization_hints(dbconn, engine->hints, rule);
1411 if (!engine->authenticateRule) {
1412 engine->authenticateRule = rule_create_with_string("authenticate", dbconn);
1413 }
1414 }
1415
1416 authdb_connection_release(&dbconn); // release db handle
1417
1418 engine->currentRightName = key;
1419 engine->currentRule = rule;
1420
1421 ccaudit_log(ccaudit, key, rule_name, 0);
1422
1423 status = _evaluate_rule(engine, engine->currentRule, &save_password);
1424 switch (status) {
1425 case errAuthorizationSuccess:
1426 auth_rights_add(engine->grantedRights, key);
1427 auth_rights_set_flags(engine->grantedRights, key, auth_rights_get_flags(rights,key));
1428
1429 if ((engine->flags & kAuthorizationFlagPreAuthorize) &&
1430 (rule_get_class(engine->currentRule) == RC_USER) &&
1431 (rule_get_timeout(engine->currentRule) == 0)) {
1432 // FIXME: kAuthorizationFlagPreAuthorize => kAuthorizationFlagCanNotPreAuthorize ???
1433 auth_rights_set_flags(engine->grantedRights, engine->currentRightName, kAuthorizationFlagPreAuthorize);
1434 }
1435
1436 os_log(AUTHD_LOG, "Succeeded authorizing right '%{public}s' by client '%{public}s' [%d] for authorization created by '%{public}s' [%d] (%X,%d)",
1437 key, process_get_code_url(engine->proc), process_get_pid(engine->proc),
1438 auth_token_get_code_url(engine->auth), auth_token_get_pid(engine->auth), (unsigned int)engine->flags, auth_token_least_privileged(engine->auth));
1439 break;
1440 case errAuthorizationDenied:
1441 case errAuthorizationInteractionNotAllowed:
1442 case errAuthorizationCanceled:
1443 if (engine->flags & kAuthorizationFlagInteractionAllowed) {
1444 os_log(AUTHD_LOG, "Failed to authorize right '%{public}s' by client '%{public}s' [%d] for authorization created by '%{public}s' [%d] (%X,%d) (%i)",
1445 key, process_get_code_url(engine->proc), process_get_pid(engine->proc),
1446 auth_token_get_code_url(engine->auth), auth_token_get_pid(engine->auth), (unsigned int)engine->flags, auth_token_least_privileged(engine->auth), (int)status);
1447 } else {
1448 os_log_debug(AUTHD_LOG, "Failed to authorize right '%{public}s' by client '%{public}s' [%d] for authorization created by '%{public}s' [%d] (%X,%d) (%d)",
1449 key, process_get_code_url(engine->proc), process_get_pid(engine->proc),
1450 auth_token_get_code_url(engine->auth), auth_token_get_pid(engine->auth), (unsigned int)engine->flags, auth_token_least_privileged(engine->auth), (int)status);
1451 }
1452 break;
1453 default:
1454 os_log_error(AUTHD_LOG, "engine: evaluate returned %d returning errAuthorizationInternal", (int)status);
1455 status = errAuthorizationInternal;
1456 break;
1457 }
1458
1459 ccaudit_log_authorization(ccaudit, engine->currentRightName, status);
1460
1461 CFReleaseSafe(rule);
1462 engine->currentRightName = NULL;
1463 engine->currentRule = NULL;
1464
1465 auth_items_remove_with_flags(engine->hints, kEngineHintsFlagTemporary);
1466
1467 if (!(engine->flags & kAuthorizationFlagPartialRights) && (status != errAuthorizationSuccess)) {
1468 return false;
1469 }
1470
1471 return true;
1472 });
1473
1474 if (password_only) {
1475 os_log_debug(AUTHD_LOG, "engine: removing password-only flag");
1476 auth_items_remove(engine->immutable_hints, AGENT_HINT_PASSWORD_ONLY);
1477 }
1478
1479 if ((engine->flags & kAuthorizationFlagPartialRights) && (auth_rights_get_count(engine->grantedRights) > 0)) {
1480 status = errAuthorizationSuccess;
1481 }
1482
1483 if (engine->dismissed) {
1484 os_log_error(AUTHD_LOG, "engine: dismissed");
1485 status = errAuthorizationDenied;
1486 }
1487
1488 os_log_debug(AUTHD_LOG, "engine: authorize result: %d", (int)status);
1489
1490 if ((engine->flags & kAuthorizationFlagExtendRights) && !(engine->flags & kAuthorizationFlagDestroyRights)) {
1491 _cf_set_iterate(engine->credentials, ^bool(CFTypeRef value) {
1492 credential_t cred = (credential_t)value;
1493 // skip all uid credentials when running in least privileged
1494 if (auth_token_least_privileged(engine->auth) && !credential_is_right(cred))
1495 return true;
1496
1497 session_t session = auth_token_get_session(engine->auth);
1498 auth_token_set_credential(engine->auth, cred);
1499 if (credential_get_shared(cred)) {
1500 session_set_credential(session, cred);
1501 }
1502 if (credential_is_right(cred)) {
1503 os_log_debug(AUTHD_LOG, "engine: adding least privileged %{public}scredential %{public}s to authorization", credential_get_shared(cred) ? "shared " : "", credential_get_name(cred));
1504 } else {
1505 os_log_debug(AUTHD_LOG, "engine: adding %{public}scredential %{public}s (%i) to authorization", credential_get_shared(cred) ? "shared " : "", credential_get_name(cred), credential_get_uid(cred));
1506 }
1507 return true;
1508 });
1509 }
1510
1511 if (status == errAuthorizationSuccess && save_password) {
1512 auth_items_set_flags(engine->context, kAuthorizationEnvironmentPassword, kAuthorizationContextFlagExtractable);
1513 }
1514
1515 if ((status == errAuthorizationSuccess) || (status == errAuthorizationCanceled)) {
1516 auth_items_t encrypted_items = auth_items_create();
1517 require_action(encrypted_items != NULL, done, os_log_error(AUTHD_LOG, "engine: unable to create items"));
1518 auth_items_content_copy_with_flags(encrypted_items, engine->context, kAuthorizationContextFlagExtractable);
1519 #if DEBUG
1520 os_log_debug(AUTHD_LOG,"engine: ********** Dumping context for encryption **********");
1521 os_log_debug(AUTHD_LOG, "%@", encrypted_items);
1522 #endif
1523 auth_items_encrypt(encrypted_items, auth_token_get_encryption_key(engine->auth));
1524 auth_items_copy_with_flags(auth_token_get_context(engine->auth), encrypted_items, kAuthorizationContextFlagExtractable);
1525 os_log_debug(AUTHD_LOG, "engine: encrypted authorization context data");
1526 CFReleaseSafe(encrypted_items);
1527 }
1528
1529 if (auth_rights_get_count(rights) > 0) {
1530 ccaudit_log(ccaudit, "end evaluation", NULL, status);
1531 }
1532
1533 #if DEBUG
1534 os_log_debug(AUTHD_LOG, "engine: ********** Dumping auth->credentials **********");
1535 auth_token_credentials_iterate(engine->auth, ^bool(credential_t cred) {
1536 os_log_debug(AUTHD_LOG, "%@", cred);
1537 return true;
1538 });
1539 os_log_debug(AUTHD_LOG, "engine: ********** Dumping session->credentials **********");
1540 session_credentials_iterate(auth_token_get_session(engine->auth), ^bool(credential_t cred) {
1541 os_log_debug(AUTHD_LOG, "%@", cred);
1542 return true;
1543 });
1544 os_log_debug(AUTHD_LOG, "engine: ********** Dumping engine->context **********");
1545 os_log_debug(AUTHD_LOG, "%@", engine->context);
1546 os_log_debug(AUTHD_LOG, "engine: ********** Dumping auth->context **********");
1547 os_log_debug(AUTHD_LOG, "%@", engine->auth);
1548 os_log_debug(AUTHD_LOG, "engine: ********** Dumping granted rights **********");
1549 os_log_debug(AUTHD_LOG, "%@", engine->grantedRights);
1550 #endif
1551
1552 done:
1553 auth_items_clear(engine->context);
1554 auth_items_clear(engine->sticky_context);
1555 CFReleaseSafe(ccaudit);
1556 CFDictionaryRemoveAllValues(engine->mechanism_agents);
1557
1558 return status;
1559 }
1560
1561 static bool
1562 _wildcard_right_exists(engine_t engine, const char * right)
1563 {
1564 // checks if a wild card right exists
1565 // ex: com.apple. system.
1566 bool exists = false;
1567 rule_t rule = NULL;
1568 authdb_connection_t dbconn = authdb_connection_acquire(server_get_database()); // get db handle
1569 require(dbconn != NULL, done);
1570
1571 rule = _find_rule(engine, dbconn, right);
1572 require(rule != NULL, done);
1573
1574 const char * ruleName = rule_get_name(rule);
1575 require(ruleName != NULL, done);
1576 size_t len = strlen(ruleName);
1577 require(len != 0, done);
1578
1579 if (ruleName[len-1] == '.') {
1580 exists = true;
1581 goto done;
1582 }
1583
1584 done:
1585 authdb_connection_release(&dbconn);
1586 CFReleaseSafe(rule);
1587
1588 return exists;
1589 }
1590
1591 // Validate db right modification
1592
1593 // meta rights are constructed as follows:
1594 // we don't allow setting of wildcard rights, so you can only be more specific
1595 // note that you should never restrict things with a wildcard right without disallowing
1596 // changes to the entire domain. ie.
1597 // system.privilege. -> never
1598 // config.add.system.privilege. -> never
1599 // config.modify.system.privilege. -> never
1600 // config.delete.system.privilege. -> never
1601 // For now we don't allow any configuration of configuration rules
1602 // config.config. -> never
1603
1604 OSStatus engine_verify_modification(engine_t engine, rule_t rule, bool remove, bool force_modify)
1605 {
1606 OSStatus status = errAuthorizationDenied;
1607 auth_rights_t checkRight = NULL;
1608 char buf[BUFSIZ];
1609 memset(buf, 0, sizeof(buf));
1610
1611 const char * right = rule_get_name(rule);
1612 require(right != NULL, done);
1613 size_t len = strlen(right);
1614 require(len != 0, done);
1615
1616 require_action(right[len-1] != '.', done, os_log_error(AUTHD_LOG, "engine: not allowed to set wild card rules"));
1617
1618 if (strncasecmp(right, kConfigRight, strlen(kConfigRight)) == 0) {
1619 // special handling of meta right change:
1620 // config.add. config.modify. config.remove. config.{}.
1621 // check for config.<right> (which always starts with config.config.)
1622 strlcat(buf, kConfigRight, sizeof(buf));
1623 } else {
1624 bool existing = (rule_get_id(rule) != 0) ? true : _wildcard_right_exists(engine, right);
1625 if (!remove) {
1626 if (existing || force_modify) {
1627 strlcat(buf, kAuthorizationConfigRightModify,sizeof(buf));
1628 } else {
1629 strlcat(buf, kAuthorizationConfigRightAdd, sizeof(buf));
1630 }
1631 } else {
1632 if (existing) {
1633 strlcat(buf, kAuthorizationConfigRightRemove, sizeof(buf));
1634 } else {
1635 status = errAuthorizationSuccess;
1636 goto done;
1637 }
1638 }
1639 }
1640
1641 strlcat(buf, right, sizeof(buf));
1642
1643 checkRight = auth_rights_create();
1644 auth_rights_add(checkRight, buf);
1645 status = engine_authorize(engine, checkRight, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights);
1646
1647 done:
1648 os_log_debug(AUTHD_LOG, "engine: authorizing %{public}s for db modification: %d", right, (int)status);
1649 CFReleaseSafe(checkRight);
1650 return status;
1651 }
1652
1653 void
1654 _engine_set_credential(engine_t engine, credential_t cred, bool shared)
1655 {
1656 os_log_debug(AUTHD_LOG, "engine: adding %{public}scredential %{public}s (%i) to engine shared: %i", credential_get_shared(cred) ? "shared " : "", credential_get_name(cred), credential_get_uid(cred), shared);
1657 CFSetSetValue(engine->credentials, cred);
1658 if (shared) {
1659 credential_t sharedCred = credential_create_with_credential(cred, true);
1660 CFSetSetValue(engine->credentials, sharedCred);
1661 CFReleaseSafe(sharedCred);
1662 }
1663 }
1664
1665 auth_rights_t
1666 engine_get_granted_rights(engine_t engine)
1667 {
1668 return engine->grantedRights;
1669 }
1670
1671 CFAbsoluteTime engine_get_time(engine_t engine)
1672 {
1673 return engine->now;
1674 }
1675
1676 void engine_destroy_agents(engine_t engine)
1677 {
1678 engine->dismissed = true;
1679
1680 _cf_dictionary_iterate(engine->mechanism_agents, ^bool(CFTypeRef key __attribute__((__unused__)), CFTypeRef value) {
1681 os_log_debug(AUTHD_LOG, "engine: Destroying %{public}s", mechanism_get_string((mechanism_t)key));
1682 agent_t agent = (agent_t)value;
1683 agent_destroy(agent);
1684
1685 return true;
1686 });
1687 }
1688
1689 void engine_interrupt_agent(engine_t engine)
1690 {
1691 _cf_dictionary_iterate(engine->mechanism_agents, ^bool(CFTypeRef key __attribute__((__unused__)), CFTypeRef value) {
1692 agent_t agent = (agent_t)value;
1693 agent_notify_interrupt(agent);
1694 return true;
1695 });
1696 }
1697
1698 CFTypeRef engine_copy_context(engine_t engine, auth_items_t source)
1699 {
1700 CFTypeRef retval = NULL;
1701
1702 process_t proc = connection_get_process(engine->conn);
1703 if (!proc) {
1704 os_log_error(AUTHD_LOG, "engine: No client process");
1705 return retval;
1706 }
1707
1708 uid_t client_uid = process_get_uid(proc);
1709 if (!client_uid) {
1710 os_log_error(AUTHD_LOG, "engine: No client UID");
1711 return retval;
1712 }
1713
1714 size_t dataLen = 0;
1715 const void *data = auth_items_get_data(source, AGENT_HINT_SHEET_CONTEXT, &dataLen);
1716 if (data) {
1717 CFDataRef externalized = CFDataCreate(kCFAllocatorDefault, data, dataLen);
1718 if (externalized) {
1719 os_log_debug(AUTHD_LOG, "engine: Going to get LA context for UID %d", client_uid);
1720 retval = LACreateNewContextWithACMContextInSession(client_uid, externalized, NULL);
1721 CFRelease(externalized);
1722 }
1723 }
1724
1725 return retval;
1726 }
1727
1728 bool engine_acquire_sheet_data(engine_t engine)
1729 {
1730 uid_t uid = auth_items_get_int(engine->hints, AGENT_CONTEXT_UID);
1731 if (!uid)
1732 return false;
1733
1734 CFReleaseSafe(engine->la_context);
1735 engine->la_context = engine_copy_context(engine, engine->hints);
1736 if (engine->la_context) {
1737 // copy UID to the context of the authorization
1738 os_log_debug(AUTHD_LOG, "engine: Sheet user UID %d", uid);
1739 auth_items_set_int(engine->context, AGENT_CONTEXT_UID, uid);
1740 struct passwd *pwd = getpwuid(uid);
1741 if (pwd) {
1742 auth_items_set_string(engine->context, kAuthorizationEnvironmentUsername, pwd->pw_name);
1743 }
1744 return true;
1745 } else {
1746 // this is not real failure as no LA context in authorization context is very valid scenario
1747 os_log_debug(AUTHD_LOG, "engine: Failed to get LA context");
1748 }
1749 return false;
1750 }