1 /* Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. */
11 #include "credential.h"
13 #include "mechanism.h"
14 #include "authutilities.h"
16 #include "connection.h"
19 #include <Security/checkpw.h>
20 int checkpw_internal( const struct passwd
*pw
, const char* password
);
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>
29 #include <coreauthd_spi.h>
30 #include <ctkloginhelper.h>
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
);
45 kEngineHintsFlagTemporary
= (1 << 30)
49 #pragma mark engine creation
52 __AUTH_BASE_STRUCT_HEADER__
;
58 AuthorizationFlags flags
;
61 auth_items_t sticky_context
;
62 auth_items_t immutable_hints
;
64 auth_rights_t grantedRights
;
74 credential_t sessionCredential
;
75 CFMutableSetRef credentials
;
76 CFMutableSetRef effectiveCredentials
;
78 CFMutableDictionaryRef mechanism_agents
;
80 // set only in engine_authorize
81 const char * currentRightName
; // weak ref
82 rule_t currentRule
; // weak ref
84 rule_t authenticateRule
;
90 _engine_finalizer(CFTypeRef value
)
92 engine_t engine
= (engine_t
)value
;
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
);
109 AUTH_TYPE_INSTANCE(engine
,
112 .finalize
= _engine_finalizer
,
115 .copyFormattingDesc
= NULL
,
116 .copyDebugDesc
= NULL
119 static CFTypeID
engine_get_type_id() {
120 static CFTypeID type_id
= _kCFRuntimeNotATypeID
;
121 static dispatch_once_t onceToken
;
123 dispatch_once(&onceToken
, ^{
124 type_id
= _CFRuntimeRegisterClass(&_auth_type_engine
);
131 engine_create(connection_t conn
, auth_token_t auth
)
133 engine_t engine
= NULL
;
134 require(conn
!= NULL
, done
);
135 require(auth
!= NULL
, done
);
137 engine
= (engine_t
)_CFRuntimeCreateInstance(kCFAllocatorDefault
, engine_get_type_id(), AUTH_CLASS_SIZE(engine
), NULL
);
138 require(engine
!= NULL
, done
);
140 engine
->conn
= (connection_t
)CFRetain(conn
);
141 engine
->proc
= connection_get_process(conn
);
142 engine
->auth
= (auth_token_t
)CFRetain(auth
);
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
);
152 engine
->grantedRights
= auth_rights_create();
154 engine
->reason
= noReason
;
156 engine
->preauthorizing
= false;
158 engine
->la_context
= NULL
;
160 engine
->now
= CFAbsoluteTimeGetCurrent();
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
);
167 session_credentials_iterate(auth_token_get_session(engine
->auth
), ^bool(credential_t cred
) {
168 CFSetAddValue(engine
->effectiveCredentials
, cred
);
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
);
180 engine
->mechanism_agents
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
187 #pragma mark agent hints
190 _set_process_hints(auth_items_t hints
, process_t proc
)
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
));
200 _set_process_immutable_hints(auth_items_t immutable_hints
, process_t proc
)
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
));
208 _set_auth_token_hints(auth_items_t hints
, auth_items_t immutable_hints
, auth_token_t auth
)
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
));
215 process_t proc
= process_create(info
, auth_token_get_session(auth
));
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
));
224 _set_right_hints(auth_items_t hints
, const char * right
)
226 auth_items_set_string(hints
, AGENT_HINT_AUTHORIZE_RIGHT
, right
);
230 _set_rule_hints(auth_items_t hints
, rule_t rule
)
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
);
237 auth_items_remove(hints
, AGENT_HINT_REQUIRE_USER_IN_GROUP
);
242 _set_localization_hints(authdb_connection_t dbconn
, auth_items_t hints
, rule_t rule
)
244 char * key
= calloc(1u, 128);
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
);
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
);
268 _set_session_hints(engine_t engine
, rule_t rule
)
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
);
274 auth_items_set_string(engine
->hints
, AGENT_HINT_SUGGESTED_USER
, tmp
);
276 tmp
= credential_get_realname(engine
->sessionCredential
);
278 auth_items_set_string(engine
->hints
, AGENT_HINT_SUGGESTED_USER_LONG
, tmp
);
281 auth_items_remove(engine
->hints
, AGENT_HINT_SUGGESTED_USER
);
282 auth_items_remove(engine
->hints
, AGENT_HINT_SUGGESTED_USER_LONG
);
287 #pragma mark right processing
290 _evaluate_credential_for_rule(engine_t engine
, credential_t cred
, rule_t rule
, bool ignoreShared
, bool sessionOwner
, enum Reason
* reason
)
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
))) {
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
;
302 return errAuthorizationSuccess
;
304 if (reason
) { *reason
= unknownReason
; }
305 return errAuthorizationDenied
;
308 return _evaluate_user_credential_for_rule(engine
,cred
,rule
,ignoreShared
,sessionOwner
, reason
);
313 _evaluate_user_credential_for_rule(engine_t engine
, credential_t cred
, rule_t rule
, bool ignoreShared
, bool sessionOwner
, enum Reason
* reason
)
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 " : "",
318 credential_get_name(cred
),
319 credential_get_uid(cred
),
320 rule_get_name(rule
));
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
;
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
;
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
;
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
;
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
;
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
;
361 if (rule_get_group(rule
) != NULL
) {
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
)) {
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
;
379 if (reason
) { *reason
= userNotInGroup
; }
382 } else if (rule_get_session_owner(rule
)) { // rule asks only if user is the session owner
383 if (reason
) { *reason
= unacceptableUser
; }
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
;
391 _get_agent(engine_t engine
, mechanism_t mech
, bool create
, bool firstMech
)
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
);
397 CFDictionaryAddValue(engine
->mechanism_agents
, mech
, agent
);
398 CFReleaseSafe(agent
);
405 _evaluate_builtin_mechanism(engine_t engine
, mechanism_t mech
)
407 uint64_t result
= kAuthorizationResultDeny
;
409 switch (mechanism_get_type(mech
)) {
410 case kMechanismTypeEntitled
:
411 if (auth_token_has_entitlement_for_right(engine
->auth
, engine
->currentRightName
)) {
412 result
= kAuthorizationResultAllow
;
424 _extract_password_from_la(engine_t engine
)
428 if (!engine
->la_context
) {
432 // try to retrieve secret
433 CFDataRef passdata
= LACopyCredential(engine
->la_context
, kLACredentialTypeExtractablePasscode
, NULL
);
435 if (CFDataGetBytePtr(passdata
)) {
436 auth_items_set_data(engine
->context
, kAuthorizationEnvironmentPassword
, CFDataGetBytePtr(passdata
), CFDataGetLength(passdata
));
438 const char *empty_pass
= "\0"; // authd code is unable to process empty strings so passing empty string as terminator only
439 auth_items_set_data(engine
->context
, kAuthorizationEnvironmentPassword
, empty_pass
, 1);
447 _evaluate_mechanisms(engine_t engine
, CFArrayRef mechanisms
)
449 uint64_t result
= kAuthorizationResultAllow
;
450 ccaudit_t ccaudit
= ccaudit_create(engine
->proc
, engine
->auth
, AUE_ssauthmech
);
451 auth_items_t context
= auth_items_create();
452 auth_items_t hints
= auth_items_create();
454 auth_items_copy(context
, engine
->context
);
455 auth_items_copy(hints
, engine
->hints
);
456 auth_items_copy(context
, engine
->sticky_context
);
458 CFDictionaryRef la_result
= NULL
;
460 CFIndex count
= CFArrayGetCount(mechanisms
);
461 bool sheet_evaluation
= false;
462 if (engine
->la_context
) {
463 int tmp
= kLAOptionNotInteractive
;
464 CFNumberRef key
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &tmp
);
466 CFNumberRef value
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &tmp
);
468 CFMutableDictionaryRef options
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
469 CFDictionarySetValue(options
, key
, value
);
470 la_result
= LACopyResultOfPolicyEvaluation(engine
->la_context
, kLAPolicyDeviceOwnerAuthentication
, options
, NULL
);
471 CFReleaseSafe(options
);
474 CFReleaseSafe(value
);
477 for (CFIndex i
= 0; i
< count
; i
++) {
478 mechanism_t mech
= (mechanism_t
)CFArrayGetValueAtIndex(mechanisms
, i
);
480 if (mechanism_get_type(mech
)) {
481 os_log_debug(AUTHD_LOG
, "engine: running builtin mechanism %{public}s (%li of %li)", mechanism_get_string(mech
), i
+1, count
);
482 result
= _evaluate_builtin_mechanism(engine
, mech
);
484 bool shoud_run_agent
= true; // evaluate comes from sheet -> we may not want to run standard SecurityAgent or authhost
485 if (engine
->la_context
) {
486 // sheet variant in progress
487 if (strcmp(mechanism_get_string(mech
), "builtin:authenticate") == 0) {
488 // set the UID the same way as SecurityAgent would
489 if (auth_items_exist(engine
->context
, "sheet-uid")) {
490 os_log_debug(AUTHD_LOG
, "engine: setting sheet UID %d to the context", auth_items_get_uint(engine
->context
, "sheet-uid"));
491 auth_items_set_uint(engine
->context
, "uid", auth_items_get_uint(engine
->context
, "sheet-uid"));
494 // find out if sheet just provided credentials or did real authentication
495 // if password is provided or PAM service name exists, it means authd has to evaluate credentials
496 // otherwise we need to check la_result
497 if (auth_items_exist(engine
->context
, AGENT_CONTEXT_AP_PAM_SERVICE_NAME
) || auth_items_exist(engine
->context
, kAuthorizationEnvironmentPassword
)) {
498 // do not try to get credentials as it has been already passed by sheet
499 os_log(AUTHD_LOG
, "engine: ignoring builtin sheet authenticate");
501 // sheet itself did the authenticate the user
502 os_log(AUTHD_LOG
, "engine: running builtin sheet authenticate");
503 sheet_evaluation
= true;
504 if (!la_result
|| TKGetSmartcardSetting(kTKEnforceSmartcard
) != 0) {
505 result
= kAuthorizationResultDeny
; // no la_result => evaluate did not pass for sheet method. Enforced smartcard => no way to use sheet based evaluation
508 shoud_run_agent
= false; // SecurityAgent should not be run for builtin:authenticate
509 } else if (strcmp(mechanism_get_string(mech
), "builtin:authenticate,privileged") == 0) {
510 if (sheet_evaluation
) {
511 os_log(AUTHD_LOG
, "engine: running builtin sheet privileged authenticate");
512 shoud_run_agent
= false;
513 if (!la_result
|| TKGetSmartcardSetting(kTKEnforceSmartcard
) != 0) { // should not get here under normal circumstances but we need to handle this case as well
514 result
= kAuthorizationResultDeny
; // no la_result => evaluate did not pass. Enforced smartcard => no way to use sheet based evaluation
517 // should_run_agent has to be set to true because we want authorizationhost to verify the credentials
518 os_log(AUTHD_LOG
, "engine: running sheet privileged authenticate");
523 if (shoud_run_agent
) {
524 agent_t agent
= _get_agent(engine
, mech
, true, i
== 0);
525 require_action(agent
!= NULL
, done
, result
= kAuthorizationResultUndefined
; os_log_error(AUTHD_LOG
, "engine: error creating mechanism agent"));
527 // check if any agent has been interrupted (it necessary if interrupt will come during creation)
530 for (j
= 0; j
< i
; j
++) {
531 agent1
= _get_agent(engine
, (mechanism_t
)CFArrayGetValueAtIndex(mechanisms
, j
), false, j
== 0);
532 if(agent1
&& agent_get_state(agent1
) == interrupting
) {
537 os_log(AUTHD_LOG
, "engine: mechanisms interrupted");
539 asprintf(&buf
, "evaluation interrupted by %s; restarting evaluation there", mechanism_get_string(agent_get_mechanism(agent1
)));
540 ccaudit_log_mechanism(ccaudit
, engine
->currentRightName
, mechanism_get_string(agent_get_mechanism(agent1
)), kAuthorizationResultAllow
, buf
);
542 ccaudit_log_mechanism(ccaudit
, engine
->currentRightName
, mechanism_get_string(mech
), kAuthorizationResultAllow
, NULL
);
543 const char * token_name
= auth_items_get_string(hints
, AGENT_HINT_TOKEN_NAME
);
544 if (token_name
&& strlen(token_name
) == 0) {
545 auth_items_remove(hints
, AGENT_HINT_TOKEN_NAME
);
547 auth_items_copy(context
, agent_get_context(agent1
));
548 auth_items_copy(hints
, agent_get_hints(agent1
));
555 os_log(AUTHD_LOG
, "engine: running mechanism %{public}s (%li of %li)", mechanism_get_string(agent_get_mechanism(agent
)), i
+1, count
);
557 result
= agent_run(agent
, hints
, context
, engine
->immutable_hints
);
559 auth_items_copy(context
, agent_get_context(agent
));
560 auth_items_copy(hints
, agent_get_hints(agent
));
562 bool interrupted
= false;
563 for (CFIndex i2
= 0; i2
!= i
; i2
++) {
564 agent_t agent2
= _get_agent(engine
, (mechanism_t
)CFArrayGetValueAtIndex(mechanisms
, i2
), false, i
== 0);
565 if (agent2
&& agent_get_state(agent2
) == interrupting
) {
566 agent_deactivate(agent
);
570 asprintf(&buf
, "evaluation interrupted by %s; restarting evaluation there", mechanism_get_string(agent_get_mechanism(agent2
)));
571 ccaudit_log_mechanism(ccaudit
, engine
->currentRightName
, mechanism_get_string(agent_get_mechanism(agent2
)), kAuthorizationResultAllow
, buf
);
573 auth_items_copy(context
, agent_get_context(agent2
));
574 auth_items_copy(hints
, agent_get_hints(agent2
));
579 // Empty token name means that token doesn't exist (e.g. SC was removed).
580 // Remove empty token name from hints for UI drawing logic.
581 const char * token_name
= auth_items_get_string(hints
, AGENT_HINT_TOKEN_NAME
);
582 if (token_name
&& strlen(token_name
) == 0) {
583 auth_items_remove(hints
, AGENT_HINT_TOKEN_NAME
);
587 os_log(AUTHD_LOG
, "engine: mechanisms interrupted");
588 enum Reason reason
= worldChanged
;
589 auth_items_set_data(hints
, AGENT_HINT_RETRY_REASON
, &reason
, sizeof(reason
));
590 result
= kAuthorizationResultAllow
;
591 _cf_dictionary_iterate(engine
->mechanism_agents
, ^bool(CFTypeRef key
__attribute__((__unused__
)), CFTypeRef value
) {
592 agent_t tempagent
= (agent_t
)value
;
593 agent_clear_interrupt(tempagent
);
600 if (result
== kAuthorizationResultAllow
) {
601 ccaudit_log_mechanism(ccaudit
, engine
->currentRightName
, mechanism_get_string(mech
), kAuthorizationResultAllow
, NULL
);
603 ccaudit_log_mechanism(ccaudit
, engine
->currentRightName
, mechanism_get_string(mech
), (uint32_t)result
, NULL
);
609 if ((result
== kAuthorizationResultUserCanceled
) || (result
== kAuthorizationResultAllow
)) {
610 // only make non-sticky context values available externally
611 auth_items_set_flags(context
, kAuthorizationEnvironmentPassword
, kAuthorizationContextFlagVolatile
);
612 // <rdar://problem/16275827> Takauthorizationenvironmentusername should always be extractable
613 auth_items_set_flags(context
, kAuthorizationEnvironmentUsername
, kAuthorizationContextFlagExtractable
);
614 auth_items_copy_with_flags(engine
->context
, context
, kAuthorizationContextFlagExtractable
| kAuthorizationContextFlagVolatile
);
615 } else if (result
== kAuthorizationResultDeny
) {
616 auth_items_clear(engine
->sticky_context
);
617 // save off sticky values in context
618 auth_items_copy_with_flags(engine
->sticky_context
, context
, kAuthorizationContextFlagSticky
);
621 CFReleaseSafe(ccaudit
);
622 CFReleaseSafe(context
);
623 CFReleaseSafe(hints
);
624 CFReleaseSafe(la_result
);
628 case kAuthorizationResultDeny
:
629 return errAuthorizationDenied
;
630 case kAuthorizationResultUserCanceled
:
631 return errAuthorizationCanceled
;
632 case kAuthorizationResultAllow
:
633 return errAuthorizationSuccess
;
634 case kAuthorizationResultUndefined
:
635 return errAuthorizationInternal
;
638 os_log_error(AUTHD_LOG
, "engine: unexpected error result");
639 return errAuthorizationInternal
;
645 _evaluate_authentication(engine_t engine
, rule_t rule
)
647 OSStatus status
= errAuthorizationDenied
;
648 ccaudit_t ccaudit
= ccaudit_create(engine
->proc
, engine
->auth
, AUE_ssauthint
);
649 os_log_debug(AUTHD_LOG
, "engine: evaluate authentication");
650 _set_rule_hints(engine
->hints
, rule
);
651 _set_session_hints(engine
, rule
);
653 CFArrayRef mechanisms
= rule_get_mechanisms(rule
);
654 if (!(CFArrayGetCount(mechanisms
) > 0)) {
655 mechanisms
= rule_get_mechanisms(engine
->authenticateRule
);
657 require_action(CFArrayGetCount(mechanisms
) > 0, done
, os_log_debug(AUTHD_LOG
, "engine: error no mechanisms found"));
659 int64_t ruleTries
= rule_get_tries(rule
);
661 if (engine
->la_context
) {
663 os_log_debug(AUTHD_LOG
, "Sheet authentication in progress, one try is enough");
666 for (engine
->tries
= 0; engine
->tries
< ruleTries
; engine
->tries
++) {
668 auth_items_set_data(engine
->hints
, AGENT_HINT_RETRY_REASON
, &engine
->reason
, sizeof(engine
->reason
));
669 auth_items_set_int(engine
->hints
, AGENT_HINT_TRIES
, engine
->tries
);
670 status
= _evaluate_mechanisms(engine
, mechanisms
);
672 os_log_debug(AUTHD_LOG
, "engine: evaluate mechanisms result %d", (int)status
);
674 // successfully ran mechanisms to obtain credential
675 if (status
== errAuthorizationSuccess
) {
676 // deny is the default
677 status
= errAuthorizationDenied
;
679 credential_t newCred
= NULL
;
680 if (auth_items_exist(engine
->context
, "uid")) {
681 newCred
= credential_create(auth_items_get_uint(engine
->context
, "uid"));
683 os_log_error(AUTHD_LOG
, "engine: mechanism failed to return a valid uid");
684 if (engine
->la_context
) {
685 // sheet failed so remove sheet reference and next time, standard dialog will be displayed
686 CFReleaseNull(engine
->la_context
);
691 if (credential_get_valid(newCred
)) {
692 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
);
693 ccaudit_log_success(ccaudit
, newCred
, engine
->currentRightName
);
695 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
);
696 ccaudit_log_failure(ccaudit
, auth_items_get_string(engine
->context
, "username"), engine
->currentRightName
);
699 status
= _evaluate_user_credential_for_rule(engine
, newCred
, rule
, true, false, &engine
->reason
);
701 if (status
== errAuthorizationSuccess
) {
702 _engine_set_credential(engine
, newCred
, rule_get_shared(rule
));
703 CFReleaseSafe(newCred
);
705 if (auth_token_least_privileged(engine
->auth
)) {
706 credential_t rightCred
= credential_create_with_right(engine
->currentRightName
);
707 _engine_set_credential(engine
, rightCred
, rule_get_shared(rule
));
708 CFReleaseSafe(rightCred
);
711 session_t session
= auth_token_get_session(engine
->auth
);
712 if (credential_get_uid(newCred
) == session_get_uid(session
)) {
713 os_log_debug(AUTHD_LOG
, "engine: authenticated as the session owner");
714 session_set_attributes(auth_token_get_session(engine
->auth
), AU_SESSION_FLAG_HAS_AUTHENTICATED
);
719 os_log_error(AUTHD_LOG
, "engine: user credential for rule failed (%d)", (int)status
);
722 CFReleaseSafe(newCred
);
725 } else if (status
== errAuthorizationCanceled
|| status
== errAuthorizationInternal
) {
726 os_log_error(AUTHD_LOG
, "engine: evaluate cancelled or failed %d", (int)status
);
728 } else if (status
== errAuthorizationDenied
) {
729 os_log_error(AUTHD_LOG
, "engine: evaluate denied");
730 engine
->reason
= invalidPassphrase
;
734 if (engine
->tries
== ruleTries
) {
735 engine
->reason
= tooManyTries
;
736 auth_items_set_data(engine
->hints
, AGENT_HINT_RETRY_REASON
, &engine
->reason
, sizeof(engine
->reason
));
737 auth_items_set_int(engine
->hints
, AGENT_HINT_TRIES
, engine
->tries
);
738 ccaudit_log(ccaudit
, engine
->currentRightName
, NULL
, 1113);
742 CFReleaseSafe(ccaudit
);
748 _check_entitlement_for_rule(engine_t engine
, rule_t rule
)
750 bool entitled
= false;
751 CFTypeRef value
= NULL
;
753 if (rule_check_flags(rule
, RuleFlagEntitledAndGroup
)) {
754 if (auth_token_has_entitlement_for_right(engine
->auth
, engine
->currentRightName
)) {
755 if (credential_check_membership(auth_token_get_credential(engine
->auth
), rule_get_group(rule
))) {
756 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
));
763 if (rule_check_flags(rule
, RuleFlagVPNEntitledAndGroup
)) {
764 // com.apple.networking.vpn.configuration is an array we only check for it's existence
765 value
= auth_token_copy_entitlement_value(engine
->auth
, "com.apple.networking.vpn.configuration");
767 if (credential_check_membership(auth_token_get_credential(engine
->auth
), rule_get_group(rule
))) {
768 os_log_debug(AUTHD_LOG
, "engine: creator of authorization has VPN entitlement and is member of group '%{public}s'", rule_get_group(rule
));
776 CFReleaseSafe(value
);
781 _evaluate_class_user(engine_t engine
, rule_t rule
)
783 __block OSStatus status
= errAuthorizationDenied
;
785 if (_check_entitlement_for_rule(engine
,rule
)) {
786 return errAuthorizationSuccess
;
789 if (rule_get_allow_root(rule
) && auth_token_get_uid(engine
->auth
) == 0) {
790 os_log_debug(AUTHD_LOG
, "engine: creator of authorization has uid == 0 granting right %{public}s", engine
->currentRightName
);
791 return errAuthorizationSuccess
;
794 if (!rule_get_authenticate_user(rule
)) {
795 status
= _evaluate_user_credential_for_rule(engine
, engine
->sessionCredential
, rule
, true, true, NULL
);
797 if (status
== errAuthorizationSuccess
) {
798 return errAuthorizationSuccess
;
801 return errAuthorizationDenied
;
804 // First -- check all the credentials we have either acquired or currently have
805 _cf_set_iterate(engine
->credentials
, ^bool(CFTypeRef value
) {
806 credential_t cred
= (credential_t
)value
;
807 // Passed-in user credentials are allowed for least-privileged mode
808 if (auth_token_least_privileged(engine
->auth
) && !credential_is_right(cred
) && credential_get_valid(cred
)) {
809 status
= _evaluate_user_credential_for_rule(engine
, cred
, rule
, false, false, NULL
);
810 if (errAuthorizationSuccess
== status
) {
811 credential_t rightCred
= credential_create_with_right(engine
->currentRightName
);
812 _engine_set_credential(engine
,rightCred
,rule_get_shared(rule
));
813 CFReleaseSafe(rightCred
);
814 return false; // exit loop
818 status
= _evaluate_credential_for_rule(engine
, cred
, rule
, false, false, NULL
);
819 if (status
== errAuthorizationSuccess
) {
820 return false; // exit loop
825 if (status
== errAuthorizationSuccess
) {
829 // Second -- go through the credentials associated to the authorization token session/auth token
830 _cf_set_iterate(engine
->effectiveCredentials
, ^bool(CFTypeRef value
) {
831 credential_t cred
= (credential_t
)value
;
832 status
= _evaluate_credential_for_rule(engine
, cred
, rule
, false, false, NULL
);
833 if (status
== errAuthorizationSuccess
) {
834 // Add the credential we used to the output set.
835 _engine_set_credential(engine
, cred
, false);
836 return false; // exit loop
841 if (status
== errAuthorizationSuccess
) {
845 // Finally - we didn't find a credential. Obtain a new credential if our flags let us do so.
846 if (!(engine
->flags
& kAuthorizationFlagExtendRights
)) {
847 os_log_error(AUTHD_LOG
, "engine: authorization denied (kAuthorizationFlagExtendRights not set)");
848 return errAuthorizationDenied
;
851 // authorization that timeout immediately cannot be preauthorized
852 if (engine
->flags
& kAuthorizationFlagPreAuthorize
&& rule_get_timeout(rule
) == 0) {
853 return errAuthorizationSuccess
;
856 if (!engine
->preauthorizing
) {
857 if (!(engine
->flags
& kAuthorizationFlagInteractionAllowed
)) {
858 os_log_error(AUTHD_LOG
, "engine: Interaction not allowed (kAuthorizationFlagInteractionAllowed not set)");
859 return errAuthorizationInteractionNotAllowed
;
862 if (!(session_get_attributes(auth_token_get_session(engine
->auth
)) & AU_SESSION_FLAG_HAS_GRAPHIC_ACCESS
)) {
863 os_log_error(AUTHD_LOG
, "engine: Interaction not allowed (session has no ui access)");
864 return errAuthorizationInteractionNotAllowed
;
867 if (server_in_dark_wake()) {
868 os_log_error(AUTHD_LOG
, "engine: authorization denied (DW)");
869 return errAuthorizationDenied
;
873 return _evaluate_authentication(engine
, rule
);
877 _evaluate_class_rule(engine_t engine
, rule_t rule
, bool *save_pwd
)
879 __block OSStatus status
= errAuthorizationDenied
;
880 int64_t kofn
= rule_get_kofn(rule
);
882 uint32_t total
= (uint32_t)rule_get_delegates_count(rule
);
883 __block
uint32_t success_count
= 0;
884 __block
uint32_t count
= 0;
885 os_log_debug(AUTHD_LOG
, "engine: ** rule %{public}s has %u delegates kofn = %lli",rule_get_name(rule
), total
, kofn
);
886 rule_delegates_iterator(rule
, ^bool(rule_t delegate
) {
889 if (kofn
!= 0 && success_count
== kofn
) {
890 status
= errAuthorizationSuccess
;
894 os_log_debug(AUTHD_LOG
, "engine: * evaluate rule %{public}s (%i)", rule_get_name(delegate
), count
);
895 status
= _evaluate_rule(engine
, delegate
, save_pwd
);
897 // if status is cancel/internal error abort
898 if ((status
== errAuthorizationCanceled
) || (status
== errAuthorizationInternal
))
901 if (status
!= errAuthorizationSuccess
) {
903 // if remaining is less than required abort
904 if ((total
- count
) < (kofn
- success_count
)) {
905 os_log_debug(AUTHD_LOG
, "engine: rule evaluation remaining: %i, required: %lli", (total
- count
), (kofn
- success_count
));
921 _preevaluate_class_rule(engine_t engine
, rule_t rule
)
923 os_log_debug(AUTHD_LOG
, "engine: _preevaluate_class_rule %{public}s", rule_get_name(rule
));
925 __block
bool password_only
= false;
926 rule_delegates_iterator(rule
, ^bool(rule_t delegate
) {
927 if (_preevaluate_rule(engine
, delegate
)) {
928 password_only
= true;
934 return password_only
;
938 _evaluate_class_mechanism(engine_t engine
, rule_t rule
)
940 OSStatus status
= errAuthorizationDenied
;
941 CFArrayRef mechanisms
= NULL
;
943 require_action(rule_get_mechanisms_count(rule
) > 0, done
, status
= errAuthorizationSuccess
; os_log_error(AUTHD_LOG
, "engine: no mechanisms specified"));
945 mechanisms
= rule_get_mechanisms(rule
);
947 if (server_in_dark_wake()) {
948 CFIndex count
= CFArrayGetCount(mechanisms
);
949 for (CFIndex i
= 0; i
< count
; i
++) {
950 if (!mechanism_is_privileged((mechanism_t
)CFArrayGetValueAtIndex(mechanisms
, i
))) {
951 os_log_error(AUTHD_LOG
, "engine: authorization denied (in DW)");
957 int64_t ruleTries
= rule_get_tries(rule
);
960 auth_items_set_data(engine
->hints
, AGENT_HINT_RETRY_REASON
, &engine
->reason
, sizeof(engine
->reason
));
961 auth_items_set_int(engine
->hints
, AGENT_HINT_TRIES
, engine
->tries
);
963 status
= _evaluate_mechanisms(engine
, mechanisms
);
964 os_log_debug(AUTHD_LOG
, "engine: evaluate mechanisms result %d", (int)status
);
966 if (status
== errAuthorizationSuccess
) {
967 credential_t newCred
= NULL
;
968 if (auth_items_exist(engine
->context
, "uid")) {
969 newCred
= credential_create(auth_items_get_uint(engine
->context
, "uid"));
971 os_log(AUTHD_LOG
, "engine: mechanism did not return a uid");
975 _engine_set_credential(engine
, newCred
, rule_get_shared(rule
));
977 if (auth_token_least_privileged(engine
->auth
)) {
978 credential_t rightCred
= credential_create_with_right(engine
->currentRightName
);
979 _engine_set_credential(engine
, rightCred
, rule_get_shared(rule
));
980 CFReleaseSafe(rightCred
);
983 if (strcmp(engine
->currentRightName
, "system.login.console") == 0 && !auth_items_exist(engine
->context
, AGENT_CONTEXT_AUTO_LOGIN
)) {
984 session_set_attributes(auth_token_get_session(engine
->auth
), AU_SESSION_FLAG_HAS_AUTHENTICATED
);
987 CFReleaseSafe(newCred
);
993 } while ( (status
== errAuthorizationDenied
) // only if we have an expected faulure we continue
994 && ((ruleTries
== 0) || ((ruleTries
> 0) && engine
->tries
< ruleTries
))); // ruleTries == 0 means we try forever
995 // ruleTires > 0 means we try upto ruleTries times
1000 // TODO: Remove when all clients have adopted entitlement
1002 enforced_entitlement(void)
1004 bool enforced_enabled
= false;
1005 //sudo defaults write /Library/Preferences/com.apple.authd enforceEntitlement -bool true
1006 CFTypeRef enforce
= (CFNumberRef
)CFPreferencesCopyValue(CFSTR("enforceEntitlement"), CFSTR(SECURITY_AUTH_NAME
), kCFPreferencesAnyUser
, kCFPreferencesCurrentHost
);
1007 if (enforce
&& CFGetTypeID(enforce
) == CFBooleanGetTypeID()) {
1008 enforced_enabled
= CFBooleanGetValue((CFBooleanRef
)enforce
);
1009 os_log_debug(AUTHD_LOG
, "enforceEntitlement for extract password: %{public}s", enforced_enabled
? "enabled" : "disabled");
1011 CFReleaseSafe(enforce
);
1013 return enforced_enabled
;
1017 _evaluate_rule(engine_t engine
, rule_t rule
, bool *save_pwd
)
1019 if (rule_check_flags(rule
, RuleFlagEntitled
)) {
1020 if (auth_token_has_entitlement_for_right(engine
->auth
, engine
->currentRightName
)) {
1021 os_log_debug(AUTHD_LOG
, "engine: rule allow, creator of authorization has entitlement for right %{public}s", engine
->currentRightName
);
1022 return errAuthorizationSuccess
;
1026 // check apple signature also for every sheet authorization + disable this check for debug builds
1027 if (engine
->la_context
|| rule_check_flags(rule
, RuleFlagRequireAppleSigned
)) {
1028 if (!auth_token_apple_signed(engine
->auth
)) {
1030 os_log_error(AUTHD_LOG
, "engine: rule deny, creator of authorization is not signed by Apple");
1031 return errAuthorizationDenied
;
1033 os_log_debug(AUTHD_LOG
, "engine: in release mode, this rule would be denied because creator of authorization is not signed by Apple");
1038 if (rule_get_extract_password(rule
)) {
1039 // check if process is entitled to extract password
1040 CFTypeRef extract_password_entitlement
= auth_token_copy_entitlement_value(engine
->auth
, "com.apple.authorization.extract-password");
1041 if (extract_password_entitlement
&& (CFGetTypeID(extract_password_entitlement
) == CFBooleanGetTypeID()) && extract_password_entitlement
== kCFBooleanTrue
) {
1043 os_log_debug(AUTHD_LOG
, "engine: authorization allowed to extract password");
1045 os_log_debug(AUTHD_LOG
, "engine: authorization NOT allowed to extract password");
1047 CFReleaseSafe(extract_password_entitlement
);
1050 // TODO: Remove when all clients have adopted entitlement
1051 if (!enforced_entitlement()) {
1052 *save_pwd
|= rule_get_extract_password(rule
);
1055 switch (rule_get_class(rule
)) {
1057 os_log(AUTHD_LOG
, "engine: rule set to allow");
1058 return errAuthorizationSuccess
;
1060 os_log(AUTHD_LOG
, "engine: rule set to deny");
1061 return errAuthorizationDenied
;
1063 return _evaluate_class_user(engine
, rule
);
1065 return _evaluate_class_rule(engine
, rule
, save_pwd
);
1067 return _evaluate_class_mechanism(engine
, rule
);
1069 os_log_error(AUTHD_LOG
, "engine: invalid class for rule or rule not found: %{public}s", rule_get_name(rule
));
1070 return errAuthorizationInternal
;
1074 // returns true if this rule or its children contain RC_USER rule with password_only==true
1076 _preevaluate_rule(engine_t engine
, rule_t rule
)
1078 os_log_debug(AUTHD_LOG
, "engine: _preevaluate_rule %{public}s", rule_get_name(rule
));
1080 switch (rule_get_class(rule
)) {
1085 return rule_get_password_only(rule
);
1087 return _preevaluate_class_rule(engine
, rule
);
1096 _find_rule(engine_t engine
, authdb_connection_t dbconn
, const char * string
)
1099 size_t sLen
= strlen(string
);
1101 char * buf
= calloc(1u, sLen
+ 1);
1102 strlcpy(buf
, string
, sLen
+ 1);
1103 char * ptr
= buf
+ sLen
;
1104 __block
int64_t count
= 0;
1109 authdb_step(dbconn
, "SELECT COUNT(name) AS cnt FROM rules WHERE name = ? AND type = 1",
1110 ^(sqlite3_stmt
*stmt
) {
1111 sqlite3_bind_text(stmt
, 1, buf
, -1, NULL
);
1112 }, ^bool(auth_items_t data
) {
1113 count
= auth_items_get_int64(data
, "cnt");
1118 r
= rule_create_with_string(buf
, dbconn
);
1122 // if buf ends with a . and we didn't find a rule remove .
1126 // find any remaining . and truncate the string
1127 ptr
= strrchr(buf
, '.');
1138 // set default if we didn't find a rule
1140 r
= rule_create_with_string("", dbconn
);
1141 if (rule_get_id(r
) == 0) {
1143 os_log_error(AUTHD_LOG
, "engine: default rule lookup error (missing), using builtin defaults");
1144 r
= rule_create_default();
1150 static void _parse_environment(engine_t engine
, auth_items_t environment
)
1152 require(environment
!= NULL
, done
);
1155 os_log_debug(AUTHD_LOG
, "engine: Dumping Environment: %@", environment
);
1158 // Check if a credential was passed into the environment and we were asked to extend the rights
1159 if (engine
->flags
& kAuthorizationFlagExtendRights
&& !(engine
->flags
& kAuthorizationFlagSheet
)) {
1160 const char * user
= auth_items_get_string(environment
, kAuthorizationEnvironmentUsername
);
1161 const char * pass
= auth_items_get_string(environment
, kAuthorizationEnvironmentPassword
);
1162 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
1163 require(password_was_used
== true, done
);
1165 bool shared
= auth_items_exist(environment
, kAuthorizationEnvironmentShared
);
1166 require_action(user
!= NULL
, done
, os_log_debug(AUTHD_LOG
, "engine: user not used password"));
1168 struct passwd
*pw
= getpwnam(user
);
1169 require_action(pw
!= NULL
, done
, os_log_error(AUTHD_LOG
, "engine: user not found %{public}s", user
));
1171 int checkpw_status
= checkpw_internal(pw
, pass
? pass
: "");
1172 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
));
1174 credential_t cred
= credential_create(pw
->pw_uid
);
1175 if (credential_get_valid(cred
)) {
1176 os_log(AUTHD_LOG
, "engine: checkpw() succeeded, creating credential for user %{public}s", user
);
1177 _engine_set_credential(engine
, cred
, shared
);
1179 auth_items_set_string(engine
->context
, kAuthorizationEnvironmentUsername
, user
);
1180 auth_items_set_string(engine
->context
, kAuthorizationEnvironmentPassword
, pass
? pass
: "");
1182 CFReleaseSafe(cred
);
1190 static bool _verify_sandbox(engine_t engine
, const char * right
)
1192 pid_t pid
= process_get_pid(engine
->proc
);
1193 if (sandbox_check(pid
, "authorization-right-obtain", SANDBOX_FILTER_RIGHT_NAME
, right
)) {
1194 os_log_error(AUTHD_LOG
, "Sandbox denied authorizing right '%{public}s' by client '%{public}s' [%d]", right
, process_get_code_url(engine
->proc
), pid
);
1198 pid
= auth_token_get_pid(engine
->auth
);
1199 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
)) {
1200 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
);
1208 #pragma mark engine methods
1210 OSStatus
engine_preauthorize(engine_t engine
, auth_items_t credentials
)
1212 os_log(AUTHD_LOG
, "engine: preauthorizing");
1214 OSStatus status
= errAuthorizationDenied
;
1215 bool save_password
= false;
1216 CFTypeRef extract_password_entitlement
= auth_token_copy_entitlement_value(engine
->auth
, "com.apple.authorization.extract-password");
1217 if (extract_password_entitlement
&& (CFGetTypeID(extract_password_entitlement
) == CFBooleanGetTypeID()) && extract_password_entitlement
== kCFBooleanTrue
) {
1218 save_password
= true;
1219 os_log_debug(AUTHD_LOG
, "engine: authorization allowed to extract password");
1221 os_log_debug(AUTHD_LOG
, "engine: authorization NOT allowed to extract password");
1223 CFReleaseSafe(extract_password_entitlement
);
1225 // TODO: Remove when all clients have adopted entitlement
1226 if (!enforced_entitlement()) {
1227 save_password
= true;
1230 engine
->flags
= kAuthorizationFlagExtendRights
;
1231 engine
->preauthorizing
= true;
1232 CFAssignRetained(engine
->la_context
, engine_copy_context(engine
, credentials
));
1233 _extract_password_from_la(engine
);
1235 const char *user
= auth_items_get_string(credentials
, kAuthorizationEnvironmentUsername
);
1236 require(user
, done
);
1238 auth_items_set_string(engine
->context
, kAuthorizationEnvironmentUsername
, user
);
1239 struct passwd
*pwd
= getpwnam(user
);
1242 auth_items_set_int(engine
->context
, AGENT_CONTEXT_UID
, pwd
->pw_uid
);
1244 const char *service
= auth_items_get_string(credentials
, AGENT_CONTEXT_AP_PAM_SERVICE_NAME
);
1247 auth_items_set_string(engine
->context
, AGENT_CONTEXT_AP_USER_NAME
, user
);
1248 auth_items_set_string(engine
->context
, AGENT_CONTEXT_AP_PAM_SERVICE_NAME
, service
);
1251 if (auth_items_exist(credentials
, AGENT_CONTEXT_AP_TOKEN
)) {
1253 const void *data
= auth_items_get_data(credentials
, AGENT_CONTEXT_AP_TOKEN
, &datalen
);
1255 auth_items_set_data(engine
->context
, AGENT_CONTEXT_AP_TOKEN
, data
, datalen
);
1259 auth_items_t decrypted_items
= auth_items_create();
1260 require_action(decrypted_items
!= NULL
, done
, os_log_error(AUTHD_LOG
, "engine: unable to create items"));
1261 auth_items_content_copy(decrypted_items
, auth_token_get_context(engine
->auth
));
1262 auth_items_decrypt(decrypted_items
, auth_token_get_encryption_key(engine
->auth
));
1263 auth_items_copy(engine
->context
, decrypted_items
);
1264 CFReleaseSafe(decrypted_items
);
1266 engine
->dismissed
= false;
1267 auth_rights_clear(engine
->grantedRights
);
1269 rule_t rule
= rule_create_preauthorization();
1270 engine
->currentRightName
= rule_get_name(rule
);
1271 engine
->currentRule
= rule
;
1272 status
= _evaluate_rule(engine
, rule
, &save_password
);
1274 case errAuthorizationSuccess
:
1275 os_log(AUTHD_LOG
, "Succeeded preauthorizing client '%{public}s' [%d] for authorization created by '%{public}s' [%d] (%X,%d)",
1276 process_get_code_url(engine
->proc
), process_get_pid(engine
->proc
),
1277 auth_token_get_code_url(engine
->auth
), auth_token_get_pid(engine
->auth
), (unsigned int)engine
->flags
, auth_token_least_privileged(engine
->auth
));
1278 status
= errAuthorizationSuccess
;
1280 case errAuthorizationDenied
:
1281 case errAuthorizationInteractionNotAllowed
:
1282 case errAuthorizationCanceled
:
1283 os_log(AUTHD_LOG
, "Failed to preauthorize client '%{public}s' [%d] for authorization created by '%{public}s' [%d] (%X,%d) (%i)",
1284 process_get_code_url(engine
->proc
), process_get_pid(engine
->proc
),
1285 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
);
1288 os_log_error(AUTHD_LOG
, "engine: preauthorize returned %d => returning errAuthorizationInternal", (int)status
);
1289 status
= errAuthorizationInternal
;
1293 CFReleaseSafe(rule
);
1295 if (engine
->dismissed
) {
1296 os_log_error(AUTHD_LOG
, "engine: engine dismissed");
1297 status
= errAuthorizationDenied
;
1300 os_log_debug(AUTHD_LOG
, "engine: preauthorize result: %d", (int)status
);
1302 _cf_set_iterate(engine
->credentials
, ^bool(CFTypeRef value
) {
1303 credential_t cred
= (credential_t
)value
;
1304 // skip all uid credentials when running in least privileged
1305 if (auth_token_least_privileged(engine
->auth
) && !credential_is_right(cred
))
1308 session_t session
= auth_token_get_session(engine
->auth
);
1309 auth_token_set_credential(engine
->auth
, cred
);
1310 if (credential_get_shared(cred
)) {
1311 session_set_credential(session
, cred
);
1313 if (credential_is_right(cred
)) {
1314 os_log(AUTHD_LOG
, "engine: adding least privileged %{public}scredential %{public}s to authorization", credential_get_shared(cred
) ? "shared " : "", credential_get_name(cred
));
1316 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
));
1322 if (status
== errAuthorizationSuccess
&& save_password
) {
1323 auth_items_set_flags(engine
->context
, kAuthorizationEnvironmentPassword
, kAuthorizationContextFlagExtractable
);
1326 if ((status
== errAuthorizationSuccess
) || (status
== errAuthorizationCanceled
)) {
1327 auth_items_t encrypted_items
= auth_items_create();
1328 require_action(encrypted_items
!= NULL
, done
, os_log_error(AUTHD_LOG
, "engine: unable to create items"));
1329 auth_items_content_copy_with_flags(encrypted_items
, engine
->context
, kAuthorizationContextFlagExtractable
);
1331 os_log_debug(AUTHD_LOG
, "engine: ********** Dumping preauthorized context for encryption **********");
1332 os_log_debug(AUTHD_LOG
, "%@", encrypted_items
);
1334 auth_items_encrypt(encrypted_items
, auth_token_get_encryption_key(engine
->auth
));
1335 auth_items_copy_with_flags(auth_token_get_context(engine
->auth
), encrypted_items
, kAuthorizationContextFlagExtractable
);
1336 os_log_debug(AUTHD_LOG
, "engine: encrypted preauthorization context data");
1337 CFReleaseSafe(encrypted_items
);
1341 engine
->preauthorizing
= false;
1342 auth_items_clear(engine
->context
);
1343 auth_items_clear(engine
->sticky_context
);
1344 CFDictionaryRemoveAllValues(engine
->mechanism_agents
);
1348 OSStatus
engine_authorize(engine_t engine
, auth_rights_t rights
, auth_items_t environment
, AuthorizationFlags flags
)
1350 __block OSStatus status
= errAuthorizationSuccess
;
1351 __block
bool save_password
= false;
1352 __block
bool password_only
= false;
1354 ccaudit_t ccaudit
= NULL
;
1356 require(rights
!= NULL
, done
);
1358 ccaudit
= ccaudit_create(engine
->proc
, engine
->auth
, AUE_ssauthorize
);
1359 if (auth_rights_get_count(rights
) > 0) {
1360 ccaudit_log(ccaudit
, "begin evaluation", NULL
, 0);
1363 if (!auth_token_apple_signed(engine
->auth
)) {
1365 flags
&= ~kAuthorizationFlagIgnorePasswordOnly
;
1366 flags
&= ~kAuthorizationFlagSheet
;
1368 os_log_debug(AUTHD_LOG
, "engine: in release mode, extra flags would be ommited as creator is not signed by Apple");
1372 engine
->flags
= flags
;
1375 _parse_environment(engine
, environment
);
1376 auth_items_copy(engine
->hints
, environment
);
1379 // First restore all context values from the AuthorizationRef
1380 auth_items_t decrypted_items
= auth_items_create();
1381 require_action(decrypted_items
!= NULL
, done
, os_log_error(AUTHD_LOG
, "engine: enable to create items"));
1382 auth_items_content_copy(decrypted_items
, auth_token_get_context(engine
->auth
));
1383 auth_items_decrypt(decrypted_items
, auth_token_get_encryption_key(engine
->auth
));
1384 auth_items_copy(engine
->context
, decrypted_items
);
1385 CFReleaseSafe(decrypted_items
);
1387 if (engine
->flags
& kAuthorizationFlagSheet
) {
1388 CFTypeRef extract_password_entitlement
= auth_token_copy_entitlement_value(engine
->auth
, "com.apple.authorization.extract-password");
1389 if (extract_password_entitlement
&& (CFGetTypeID(extract_password_entitlement
) == CFBooleanGetTypeID()) && extract_password_entitlement
== kCFBooleanTrue
) {
1390 save_password
= true;
1391 os_log_debug(AUTHD_LOG
, "engine: authorization allowed to extract password");
1393 os_log_debug(AUTHD_LOG
, "engine: authorization NOT allowed to extract password");
1395 CFReleaseSafe(extract_password_entitlement
);
1397 // TODO: Remove when all clients have adopted entitlement
1398 if (!enforced_entitlement()) {
1399 save_password
= true;
1402 // Try to use/update fresh context values from the environment
1403 require_action(environment
, done
, os_log_debug(AUTHD_LOG
, "engine: Missing environment for sheet authorization"); status
= errAuthorizationDenied
);
1405 const char *user
= auth_items_get_string(environment
, kAuthorizationEnvironmentUsername
);
1406 require_action(user
, done
, os_log_debug(AUTHD_LOG
, "engine: Missing username"); status
= errAuthorizationDenied
);
1408 auth_items_set_string(engine
->context
, kAuthorizationEnvironmentUsername
, user
);
1409 struct passwd
*pwd
= getpwnam(user
);
1410 require_action(pwd
, done
, os_log_debug(AUTHD_LOG
, "engine: Invalid username %s", user
); status
= errAuthorizationDenied
);
1411 auth_items_set_uint(engine
->context
, "sheet-uid", pwd
->pw_uid
);
1413 // move sheet-specific items from hints to context
1414 const char *service
= auth_items_get_string(engine
->hints
, AGENT_CONTEXT_AP_PAM_SERVICE_NAME
);
1416 if (auth_items_exist(engine
->hints
, AGENT_CONTEXT_AP_USER_NAME
)) {
1417 auth_items_set_string(engine
->context
, AGENT_CONTEXT_AP_USER_NAME
, auth_items_get_string(engine
->hints
, AGENT_CONTEXT_AP_USER_NAME
));
1418 auth_items_remove(engine
->hints
, AGENT_CONTEXT_AP_USER_NAME
);
1420 auth_items_set_string(engine
->context
, AGENT_CONTEXT_AP_USER_NAME
, user
);
1423 auth_items_set_string(engine
->context
, AGENT_CONTEXT_AP_PAM_SERVICE_NAME
, service
);
1424 auth_items_remove(engine
->hints
, AGENT_CONTEXT_AP_PAM_SERVICE_NAME
);
1427 if (auth_items_exist(environment
, AGENT_CONTEXT_AP_TOKEN
)) {
1429 const void *data
= auth_items_get_data(engine
->hints
, AGENT_CONTEXT_AP_TOKEN
, &datalen
);
1431 auth_items_set_data(engine
->context
, AGENT_CONTEXT_AP_TOKEN
, data
, datalen
);
1433 auth_items_remove(engine
->hints
, AGENT_CONTEXT_AP_TOKEN
);
1436 engine_acquire_sheet_data(engine
);
1437 _extract_password_from_la(engine
);
1438 engine
->preauthorizing
= true;
1441 engine
->dismissed
= false;
1442 auth_rights_clear(engine
->grantedRights
);
1444 if (!(engine
->flags
& kAuthorizationFlagIgnorePasswordOnly
))
1446 // first check if any of rights uses rule with password-only set to true
1447 // if so, set appropriate hint so SecurityAgent won't use alternate authentication methods like smartcard etc.
1448 authdb_connection_t dbconn
= authdb_connection_acquire(server_get_database()); // get db handle
1449 auth_rights_iterate(rights
, ^bool(const char *key
) {
1452 os_log_debug(AUTHD_LOG
, "engine: checking if rule %{public}s contains password-only item", key
);
1454 rule_t rule
= _find_rule(engine
, dbconn
, key
);
1456 if (rule
&& _preevaluate_rule(engine
, rule
)) {
1457 password_only
= true;
1458 CFReleaseSafe(rule
);
1461 CFReleaseSafe(rule
);
1464 authdb_connection_release(&dbconn
); // release db handle
1466 os_log_info(AUTHD_LOG
, "engine: password-only ignored");
1469 if (password_only
) {
1470 os_log_debug(AUTHD_LOG
, "engine: password-only item found, forcing SecurityAgent to use password-only UI");
1471 auth_items_set_bool(engine
->immutable_hints
, AGENT_HINT_PASSWORD_ONLY
, true);
1474 auth_rights_iterate(rights
, ^bool(const char *key
) {
1479 if (!_verify_sandbox(engine
, key
)) { // _verify_sandbox is already logging failures
1480 status
= errAuthorizationDenied
;
1484 authdb_connection_t dbconn
= authdb_connection_acquire(server_get_database()); // get db handle
1486 os_log_debug(AUTHD_LOG
, "engine: evaluate right %{public}s", key
);
1487 rule_t rule
= _find_rule(engine
, dbconn
, key
);
1488 const char * rule_name
= rule_get_name(rule
);
1489 if (rule_name
&& (strcasecmp(rule_name
, "") == 0)) {
1490 rule_name
= "default (not defined)";
1492 os_log_debug(AUTHD_LOG
, "engine: using rule %{public}s", rule_name
);
1494 // only need the hints & mechanisms if we are going to show ui
1495 if (engine
->flags
& kAuthorizationFlagInteractionAllowed
) {
1496 _set_right_hints(engine
->hints
, key
);
1497 _set_localization_hints(dbconn
, engine
->hints
, rule
);
1498 if (!engine
->authenticateRule
) {
1499 engine
->authenticateRule
= rule_create_with_string("authenticate", dbconn
);
1503 authdb_connection_release(&dbconn
); // release db handle
1505 engine
->currentRightName
= key
;
1506 engine
->currentRule
= rule
;
1508 ccaudit_log(ccaudit
, key
, rule_name
, 0);
1510 status
= _evaluate_rule(engine
, engine
->currentRule
, &save_password
);
1512 case errAuthorizationSuccess
:
1513 auth_rights_add(engine
->grantedRights
, key
);
1514 auth_rights_set_flags(engine
->grantedRights
, key
, auth_rights_get_flags(rights
,key
));
1516 if ((engine
->flags
& kAuthorizationFlagPreAuthorize
) &&
1517 (rule_get_class(engine
->currentRule
) == RC_USER
) &&
1518 (rule_get_timeout(engine
->currentRule
) == 0)) {
1519 // FIXME: kAuthorizationFlagPreAuthorize => kAuthorizationFlagCanNotPreAuthorize ???
1520 auth_rights_set_flags(engine
->grantedRights
, engine
->currentRightName
, kAuthorizationFlagPreAuthorize
);
1523 os_log(AUTHD_LOG
, "Succeeded authorizing right '%{public}s' by client '%{public}s' [%d] for authorization created by '%{public}s' [%d] (%X,%d)",
1524 key
, process_get_code_url(engine
->proc
), process_get_pid(engine
->proc
),
1525 auth_token_get_code_url(engine
->auth
), auth_token_get_pid(engine
->auth
), (unsigned int)engine
->flags
, auth_token_least_privileged(engine
->auth
));
1527 case errAuthorizationDenied
:
1528 case errAuthorizationInteractionNotAllowed
:
1529 case errAuthorizationCanceled
:
1530 if (engine
->flags
& kAuthorizationFlagInteractionAllowed
) {
1531 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)",
1532 key
, process_get_code_url(engine
->proc
), process_get_pid(engine
->proc
),
1533 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
);
1535 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)",
1536 key
, process_get_code_url(engine
->proc
), process_get_pid(engine
->proc
),
1537 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
);
1541 os_log_error(AUTHD_LOG
, "engine: evaluate returned %d returning errAuthorizationInternal", (int)status
);
1542 status
= errAuthorizationInternal
;
1546 ccaudit_log_authorization(ccaudit
, engine
->currentRightName
, status
);
1548 CFReleaseSafe(rule
);
1549 engine
->currentRightName
= NULL
;
1550 engine
->currentRule
= NULL
;
1552 auth_items_remove_with_flags(engine
->hints
, kEngineHintsFlagTemporary
);
1554 if (!(engine
->flags
& kAuthorizationFlagPartialRights
) && (status
!= errAuthorizationSuccess
)) {
1561 if (password_only
) {
1562 os_log_debug(AUTHD_LOG
, "engine: removing password-only flag");
1563 auth_items_remove(engine
->immutable_hints
, AGENT_HINT_PASSWORD_ONLY
);
1566 if ((engine
->flags
& kAuthorizationFlagPartialRights
) && (auth_rights_get_count(engine
->grantedRights
) > 0)) {
1567 status
= errAuthorizationSuccess
;
1570 if (engine
->dismissed
) {
1571 os_log_error(AUTHD_LOG
, "engine: dismissed");
1572 status
= errAuthorizationDenied
;
1575 os_log_debug(AUTHD_LOG
, "engine: authorize result: %d", (int)status
);
1577 if (engine
->flags
& kAuthorizationFlagSheet
) {
1578 engine
->preauthorizing
= false;
1581 if ((engine
->flags
& kAuthorizationFlagExtendRights
) && !(engine
->flags
& kAuthorizationFlagDestroyRights
)) {
1582 _cf_set_iterate(engine
->credentials
, ^bool(CFTypeRef value
) {
1583 credential_t cred
= (credential_t
)value
;
1584 // skip all uid credentials when running in least privileged
1585 if (auth_token_least_privileged(engine
->auth
) && !credential_is_right(cred
))
1588 session_t session
= auth_token_get_session(engine
->auth
);
1589 auth_token_set_credential(engine
->auth
, cred
);
1590 if (credential_get_shared(cred
)) {
1591 session_set_credential(session
, cred
);
1593 if (credential_is_right(cred
)) {
1594 os_log_debug(AUTHD_LOG
, "engine: adding least privileged %{public}scredential %{public}s to authorization", credential_get_shared(cred
) ? "shared " : "", credential_get_name(cred
));
1596 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
));
1602 if (status
== errAuthorizationSuccess
&& save_password
) {
1603 auth_items_set_flags(engine
->context
, kAuthorizationEnvironmentPassword
, kAuthorizationContextFlagExtractable
);
1606 if ((status
== errAuthorizationSuccess
) || (status
== errAuthorizationCanceled
)) {
1607 auth_items_t encrypted_items
= auth_items_create();
1608 require_action(encrypted_items
!= NULL
, done
, os_log_error(AUTHD_LOG
, "engine: unable to create items"));
1609 auth_items_content_copy_with_flags(encrypted_items
, engine
->context
, kAuthorizationContextFlagExtractable
);
1611 os_log_debug(AUTHD_LOG
,"engine: ********** Dumping context for encryption **********");
1612 os_log_debug(AUTHD_LOG
, "%@", encrypted_items
);
1614 auth_items_encrypt(encrypted_items
, auth_token_get_encryption_key(engine
->auth
));
1615 auth_items_copy_with_flags(auth_token_get_context(engine
->auth
), encrypted_items
, kAuthorizationContextFlagExtractable
);
1616 os_log_debug(AUTHD_LOG
, "engine: encrypted authorization context data");
1617 CFReleaseSafe(encrypted_items
);
1620 if (auth_rights_get_count(rights
) > 0) {
1621 ccaudit_log(ccaudit
, "end evaluation", NULL
, status
);
1625 os_log_debug(AUTHD_LOG
, "engine: ********** Dumping auth->credentials **********");
1626 auth_token_credentials_iterate(engine
->auth
, ^bool(credential_t cred
) {
1627 os_log_debug(AUTHD_LOG
, "%@", cred
);
1630 os_log_debug(AUTHD_LOG
, "engine: ********** Dumping session->credentials **********");
1631 session_credentials_iterate(auth_token_get_session(engine
->auth
), ^bool(credential_t cred
) {
1632 os_log_debug(AUTHD_LOG
, "%@", cred
);
1635 os_log_debug(AUTHD_LOG
, "engine: ********** Dumping engine->context **********");
1636 os_log_debug(AUTHD_LOG
, "%@", engine
->context
);
1637 os_log_debug(AUTHD_LOG
, "engine: ********** Dumping auth->context **********");
1638 os_log_debug(AUTHD_LOG
, "%@", engine
->auth
);
1639 os_log_debug(AUTHD_LOG
, "engine: ********** Dumping granted rights **********");
1640 os_log_debug(AUTHD_LOG
, "%@", engine
->grantedRights
);
1644 auth_items_clear(engine
->context
);
1645 auth_items_clear(engine
->sticky_context
);
1646 CFReleaseSafe(ccaudit
);
1647 CFDictionaryRemoveAllValues(engine
->mechanism_agents
);
1653 _wildcard_right_exists(engine_t engine
, const char * right
)
1655 // checks if a wild card right exists
1656 // ex: com.apple. system.
1657 bool exists
= false;
1659 authdb_connection_t dbconn
= authdb_connection_acquire(server_get_database()); // get db handle
1660 require(dbconn
!= NULL
, done
);
1662 rule
= _find_rule(engine
, dbconn
, right
);
1663 require(rule
!= NULL
, done
);
1665 const char * ruleName
= rule_get_name(rule
);
1666 require(ruleName
!= NULL
, done
);
1667 size_t len
= strlen(ruleName
);
1668 require(len
!= 0, done
);
1670 if (ruleName
[len
-1] == '.') {
1676 authdb_connection_release(&dbconn
);
1677 CFReleaseSafe(rule
);
1682 // Validate db right modification
1684 // meta rights are constructed as follows:
1685 // we don't allow setting of wildcard rights, so you can only be more specific
1686 // note that you should never restrict things with a wildcard right without disallowing
1687 // changes to the entire domain. ie.
1688 // system.privilege. -> never
1689 // config.add.system.privilege. -> never
1690 // config.modify.system.privilege. -> never
1691 // config.delete.system.privilege. -> never
1692 // For now we don't allow any configuration of configuration rules
1693 // config.config. -> never
1695 OSStatus
engine_verify_modification(engine_t engine
, rule_t rule
, bool remove
, bool force_modify
)
1697 OSStatus status
= errAuthorizationDenied
;
1698 auth_rights_t checkRight
= NULL
;
1700 memset(buf
, 0, sizeof(buf
));
1702 const char * right
= rule_get_name(rule
);
1703 require(right
!= NULL
, done
);
1704 size_t len
= strlen(right
);
1705 require(len
!= 0, done
);
1707 require_action(right
[len
-1] != '.', done
, os_log_error(AUTHD_LOG
, "engine: not allowed to set wild card rules"));
1709 if (strncasecmp(right
, kConfigRight
, strlen(kConfigRight
)) == 0) {
1710 // special handling of meta right change:
1711 // config.add. config.modify. config.remove. config.{}.
1712 // check for config.<right> (which always starts with config.config.)
1713 strlcat(buf
, kConfigRight
, sizeof(buf
));
1715 bool existing
= (rule_get_id(rule
) != 0) ? true : _wildcard_right_exists(engine
, right
);
1717 if (existing
|| force_modify
) {
1718 strlcat(buf
, kAuthorizationConfigRightModify
,sizeof(buf
));
1720 strlcat(buf
, kAuthorizationConfigRightAdd
, sizeof(buf
));
1724 strlcat(buf
, kAuthorizationConfigRightRemove
, sizeof(buf
));
1726 status
= errAuthorizationSuccess
;
1732 strlcat(buf
, right
, sizeof(buf
));
1734 checkRight
= auth_rights_create();
1735 auth_rights_add(checkRight
, buf
);
1736 status
= engine_authorize(engine
, checkRight
, kAuthorizationEmptyEnvironment
, kAuthorizationFlagDefaults
| kAuthorizationFlagInteractionAllowed
| kAuthorizationFlagExtendRights
);
1739 os_log_debug(AUTHD_LOG
, "engine: authorizing %{public}s for db modification: %d", right
, (int)status
);
1740 CFReleaseSafe(checkRight
);
1745 _engine_set_credential(engine_t engine
, credential_t cred
, bool shared
)
1747 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
);
1748 CFSetSetValue(engine
->credentials
, cred
);
1750 credential_t sharedCred
= credential_create_with_credential(cred
, true);
1751 CFSetSetValue(engine
->credentials
, sharedCred
);
1752 CFReleaseSafe(sharedCred
);
1757 engine_get_granted_rights(engine_t engine
)
1759 return engine
->grantedRights
;
1762 CFAbsoluteTime
engine_get_time(engine_t engine
)
1767 void engine_destroy_agents(engine_t engine
)
1769 engine
->dismissed
= true;
1771 _cf_dictionary_iterate(engine
->mechanism_agents
, ^bool(CFTypeRef key
__attribute__((__unused__
)), CFTypeRef value
) {
1772 os_log_debug(AUTHD_LOG
, "engine: Destroying %{public}s", mechanism_get_string((mechanism_t
)key
));
1773 agent_t agent
= (agent_t
)value
;
1774 agent_destroy(agent
);
1780 void engine_interrupt_agent(engine_t engine
)
1782 _cf_dictionary_iterate(engine
->mechanism_agents
, ^bool(CFTypeRef key
__attribute__((__unused__
)), CFTypeRef value
) {
1783 agent_t agent
= (agent_t
)value
;
1784 agent_notify_interrupt(agent
);
1789 CFTypeRef
engine_copy_context(engine_t engine
, auth_items_t source
)
1791 CFTypeRef retval
= NULL
;
1793 process_t proc
= connection_get_process(engine
->conn
);
1795 os_log_error(AUTHD_LOG
, "engine: No client process");
1799 uid_t client_uid
= process_get_uid(proc
);
1801 os_log_error(AUTHD_LOG
, "engine: No client UID");
1806 const void *data
= auth_items_get_data(source
, AGENT_HINT_SHEET_CONTEXT
, &dataLen
);
1808 CFDataRef externalized
= CFDataCreate(kCFAllocatorDefault
, data
, dataLen
);
1810 os_log_debug(AUTHD_LOG
, "engine: Going to get LA context for UID %d", client_uid
);
1811 retval
= LACreateNewContextWithACMContextInSession(client_uid
, externalized
, NULL
);
1812 CFRelease(externalized
);
1819 bool engine_acquire_sheet_data(engine_t engine
)
1821 if (!auth_items_exist(engine
->context
, "sheet-uid"))
1824 uid_t uid
= auth_items_get_uint(engine
->context
, "sheet-uid");
1826 CFReleaseSafe(engine
->la_context
);
1827 engine
->la_context
= engine_copy_context(engine
, engine
->hints
);
1828 if (engine
->la_context
) {
1829 os_log_debug(AUTHD_LOG
, "engine: Sheet user UID %d", uid
);
1832 // this is not real failure as no LA context in authorization context is very valid scenario
1833 os_log_debug(AUTHD_LOG
, "engine: Failed to get LA context");