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