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