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
);
44 static uint64_t global_engine_count
;
47 kEngineHintsFlagTemporary
= (1 << 30)
51 #pragma mark engine creation
54 __AUTH_BASE_STRUCT_HEADER__
;
60 AuthorizationFlags flags
;
63 auth_items_t sticky_context
;
64 auth_items_t immutable_hints
;
66 auth_rights_t grantedRights
;
76 credential_t sessionCredential
;
77 CFMutableSetRef credentials
;
78 CFMutableSetRef effectiveCredentials
;
80 CFMutableDictionaryRef mechanism_agents
;
82 // set only in engine_authorize
83 const char * currentRightName
; // weak ref
84 rule_t currentRule
; // weak ref
86 rule_t authenticateRule
;
90 uint64_t engine_index
;
94 _engine_finalizer(CFTypeRef value
)
96 engine_t engine
= (engine_t
)value
;
98 CFReleaseNull(engine
->mechanism_agents
);
99 CFReleaseNull(engine
->conn
);
100 CFReleaseNull(engine
->auth
);
101 CFReleaseNull(engine
->hints
);
102 CFReleaseNull(engine
->context
);
103 CFReleaseNull(engine
->immutable_hints
);
104 CFReleaseNull(engine
->sticky_context
);
105 CFReleaseNull(engine
->grantedRights
);
106 CFReleaseNull(engine
->sessionCredential
);
107 CFReleaseNull(engine
->credentials
);
108 CFReleaseNull(engine
->effectiveCredentials
);
109 CFReleaseNull(engine
->authenticateRule
);
110 CFReleaseNull(engine
->la_context
);
113 AUTH_TYPE_INSTANCE(engine
,
116 .finalize
= _engine_finalizer
,
119 .copyFormattingDesc
= NULL
,
120 .copyDebugDesc
= NULL
123 static CFTypeID
engine_get_type_id() {
124 static CFTypeID type_id
= _kCFRuntimeNotATypeID
;
125 static dispatch_once_t onceToken
;
127 dispatch_once(&onceToken
, ^{
128 type_id
= _CFRuntimeRegisterClass(&_auth_type_engine
);
135 engine_create(connection_t conn
, auth_token_t auth
)
137 engine_t engine
= NULL
;
138 require(conn
!= NULL
, done
);
139 require(auth
!= NULL
, done
);
141 engine
= (engine_t
)_CFRuntimeCreateInstance(kCFAllocatorDefault
, engine_get_type_id(), AUTH_CLASS_SIZE(engine
), NULL
);
142 require(engine
!= NULL
, done
);
144 engine
->conn
= (connection_t
)CFRetain(conn
);
145 engine
->proc
= connection_get_process(conn
);
146 engine
->auth
= (auth_token_t
)CFRetain(auth
);
148 engine
->hints
= auth_items_create();
149 engine
->context
= auth_items_create();
150 engine
->immutable_hints
= auth_items_create();
151 engine
->sticky_context
= auth_items_create();
152 _set_process_hints(engine
->hints
, engine
->proc
);
153 _set_process_immutable_hints(engine
->immutable_hints
, engine
->proc
);
154 _set_auth_token_hints(engine
->hints
, engine
->immutable_hints
, auth
);
156 engine
->grantedRights
= auth_rights_create();
158 engine
->reason
= noReason
;
160 engine
->preauthorizing
= false;
162 engine
->la_context
= NULL
;
164 engine
->now
= CFAbsoluteTimeGetCurrent();
166 session_update(auth_token_get_session(engine
->auth
));
167 engine
->sessionCredential
= credential_create(session_get_uid(auth_token_get_session(engine
->auth
)));
168 engine
->credentials
= CFSetCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeSetCallBacks
);
169 engine
->effectiveCredentials
= CFSetCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeSetCallBacks
);
171 session_credentials_iterate(auth_token_get_session(engine
->auth
), ^bool(credential_t cred
) {
172 CFSetAddValue(engine
->effectiveCredentials
, cred
);
176 auth_token_credentials_iterate(engine
->auth
, ^bool(credential_t cred
) {
177 // we added all session credentials already now just add all previously acquired credentials
178 if (!credential_get_shared(cred
)) {
179 CFSetAddValue(engine
->credentials
, cred
);
184 engine
->mechanism_agents
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
186 engine
->engine_index
= global_engine_count
++;
192 #pragma mark agent hints
195 _set_process_hints(auth_items_t hints
, process_t proc
)
197 // process information
198 RequestorType type
= bundle
;
199 auth_items_set_data(hints
, AGENT_HINT_CLIENT_TYPE
, &type
, sizeof(type
));
200 auth_items_set_int(hints
, AGENT_HINT_CLIENT_PID
, process_get_pid(proc
));
201 auth_items_set_uint(hints
, AGENT_HINT_CLIENT_UID
, process_get_uid(proc
));
205 _set_process_immutable_hints(auth_items_t immutable_hints
, process_t proc
)
207 // process information - immutable
208 auth_items_set_bool(immutable_hints
, AGENT_HINT_CLIENT_SIGNED
, process_apple_signed(proc
));
209 auth_items_set_bool(immutable_hints
, AGENT_HINT_CLIENT_FROM_APPLE
, process_firstparty_signed(proc
));
213 _set_auth_token_hints(auth_items_t hints
, auth_items_t immutable_hints
, auth_token_t auth
)
215 auth_items_set_string(hints
, AGENT_HINT_CLIENT_PATH
, auth_token_get_code_url(auth
));
216 auth_items_set_int(hints
, AGENT_HINT_CREATOR_PID
, auth_token_get_pid(auth
));
217 const audit_info_s
* info
= auth_token_get_audit_info(auth
);
218 auth_items_set_data(hints
, AGENT_HINT_CREATOR_AUDIT_TOKEN
, &info
->opaqueToken
, sizeof(info
->opaqueToken
));
220 process_t proc
= process_create(info
, auth_token_get_session(auth
));
222 auth_items_set_bool(immutable_hints
, AGENT_HINT_CREATOR_SIGNED
, process_apple_signed(proc
));
223 auth_items_set_bool(immutable_hints
, AGENT_HINT_CREATOR_FROM_APPLE
, process_firstparty_signed(proc
));
229 _set_right_hints(auth_items_t hints
, const char * right
)
231 auth_items_set_string(hints
, AGENT_HINT_AUTHORIZE_RIGHT
, right
);
235 _set_rule_hints(auth_items_t hints
, rule_t rule
)
237 auth_items_set_string(hints
, AGENT_HINT_AUTHORIZE_RULE
, rule_get_name(rule
));
238 const char * group
= rule_get_group(rule
);
239 if (rule_get_class(rule
) == RC_USER
&& group
!= NULL
) {
240 auth_items_set_string(hints
, AGENT_HINT_REQUIRE_USER_IN_GROUP
, group
);
242 auth_items_remove(hints
, AGENT_HINT_REQUIRE_USER_IN_GROUP
);
247 _set_localization_hints(authdb_connection_t dbconn
, auth_items_t hints
, rule_t rule
)
249 char * key
= calloc(1u, 128);
251 authdb_step(dbconn
, "SELECT lang,value FROM prompts WHERE r_id = ?", ^(sqlite3_stmt
*stmt
) {
252 sqlite3_bind_int64(stmt
, 1, rule_get_id(rule
));
253 }, ^bool(auth_items_t data
) {
254 snprintf(key
, 128, "%s%s", kAuthorizationRuleParameterDescription
, auth_items_get_string(data
, "lang"));
255 auth_items_set_string(hints
, key
, auth_items_get_string(data
, "value"));
256 auth_items_set_flags(hints
, key
, kEngineHintsFlagTemporary
);
260 authdb_step(dbconn
, "SELECT lang,value FROM buttons WHERE r_id = ?", ^(sqlite3_stmt
*stmt
) {
261 sqlite3_bind_int64(stmt
, 1, rule_get_id(rule
));
262 }, ^bool(auth_items_t data
) {
263 snprintf(key
, 128, "%s%s", kAuthorizationRuleParameterButton
, auth_items_get_string(data
, "lang"));
264 auth_items_set_string(hints
, key
, auth_items_get_string(data
, "value"));
265 auth_items_set_flags(hints
, key
, kEngineHintsFlagTemporary
);
273 _set_session_hints(engine_t engine
, rule_t rule
)
275 os_log_debug(AUTHD_LOG
, "engine %lld: ** prepare agent hints for rule %{public}s", engine
->engine_index
, rule_get_name(rule
));
276 if (_evaluate_user_credential_for_rule(engine
, engine
->sessionCredential
, rule
, true, true, NULL
) == errAuthorizationSuccess
) {
277 const char * tmp
= credential_get_name(engine
->sessionCredential
);
279 auth_items_set_string(engine
->hints
, AGENT_HINT_SUGGESTED_USER
, tmp
);
281 tmp
= credential_get_realname(engine
->sessionCredential
);
283 auth_items_set_string(engine
->hints
, AGENT_HINT_SUGGESTED_USER_LONG
, tmp
);
286 auth_items_remove(engine
->hints
, AGENT_HINT_SUGGESTED_USER
);
287 auth_items_remove(engine
->hints
, AGENT_HINT_SUGGESTED_USER_LONG
);
292 #pragma mark right processing
295 _evaluate_credential_for_rule(engine_t engine
, credential_t cred
, rule_t rule
, bool ignoreShared
, bool sessionOwner
, enum Reason
* reason
)
297 if (auth_token_least_privileged(engine
->auth
)) {
298 if (credential_is_right(cred
) && credential_get_valid(cred
) && _compare_string(engine
->currentRightName
, credential_get_name(cred
))) {
300 if (!rule_get_shared(rule
) && credential_get_shared(cred
)) {
301 os_log_error(AUTHD_LOG
, "Shared right %{public}s (does NOT satisfy rule) (engine %lld)", credential_get_name(cred
), engine
->engine_index
);
302 if (reason
) { *reason
= unknownReason
; }
303 return errAuthorizationDenied
;
307 return errAuthorizationSuccess
;
309 if (reason
) { *reason
= unknownReason
; }
310 return errAuthorizationDenied
;
313 return _evaluate_user_credential_for_rule(engine
,cred
,rule
,ignoreShared
,sessionOwner
, reason
);
318 _evaluate_user_credential_for_rule(engine_t engine
, credential_t cred
, rule_t rule
, bool ignoreShared
, bool sessionOwner
, enum Reason
* reason
)
320 const char * cred_label
= sessionOwner
? "session owner" : "credential";
321 os_log(AUTHD_LOG
, "Validating %{public}s%{public}s %{public}s (%i) for %{public}s (engine %lld)", credential_get_shared(cred
) ? "shared " : "",
323 credential_get_name(cred
),
324 credential_get_uid(cred
),
326 engine
->engine_index
);
328 if (rule_get_class(rule
) != RC_USER
) {
329 os_log(AUTHD_LOG
, "Invalid rule class %i (engine %lld)", rule_get_class(rule
), engine
->engine_index
);
330 return errAuthorizationDenied
;
333 if (credential_get_valid(cred
) != true) {
334 os_log(AUTHD_LOG
, "%{public}s %i invalid (does NOT satisfy rule) (engine %lld)", cred_label
, credential_get_uid(cred
), engine
->engine_index
);
335 if (reason
) { *reason
= invalidPassphrase
; }
336 return errAuthorizationDenied
;
339 if (engine
->now
- credential_get_creation_time(cred
) > rule_get_timeout(rule
)) {
340 os_log(AUTHD_LOG
, "%{public}s %i expired '%f > %lli' (does NOT satisfy rule) (engine %lld)", cred_label
, credential_get_uid(cred
),
341 (engine
->now
- credential_get_creation_time(cred
)), rule_get_timeout(rule
), engine
->engine_index
);
342 if (reason
) { *reason
= unknownReason
; }
343 return errAuthorizationDenied
;
347 if (!rule_get_shared(rule
) && credential_get_shared(cred
)) {
348 os_log(AUTHD_LOG
, "Shared %{public}s %i (does NOT satisfy rule) (engine %lld)", cred_label
, credential_get_uid(cred
), engine
->engine_index
);
349 if (reason
) { *reason
= unknownReason
; }
350 return errAuthorizationDenied
;
354 if (credential_get_uid(cred
) == 0) {
355 os_log(AUTHD_LOG
, "%{public}s %i has uid 0 (does satisfy rule) (engine %lld)", cred_label
, credential_get_uid(cred
), engine
->engine_index
);
356 return errAuthorizationSuccess
;
359 if (rule_get_session_owner(rule
)) {
360 if (credential_get_uid(cred
) == session_get_uid(auth_token_get_session(engine
->auth
))) {
361 os_log(AUTHD_LOG
, "%{public}s %i is session owner (does satisfy rule) (engine %lld)", cred_label
, credential_get_uid(cred
), engine
->engine_index
);
362 return errAuthorizationSuccess
;
366 if (rule_get_group(rule
) != NULL
) {
369 // This allows testing a group modifier without prompting the user
370 // When (authenticate-user = false) we are just testing the creator uid.
371 // If a group modifier is enabled (RuleFlagEntitledAndGroup | RuleFlagVPNEntitledAndGroup)
372 // we want to skip the creator uid group check.
373 // group modifiers are checked early during the evaluation in _check_entitlement_for_rule
374 if (!rule_get_authenticate_user(rule
)) {
375 if (rule_check_flags(rule
, RuleFlagEntitledAndGroup
| RuleFlagVPNEntitledAndGroup
)) {
380 if (credential_check_membership(cred
, rule_get_group(rule
))) {
381 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
);
382 return errAuthorizationSuccess
;
384 if (reason
) { *reason
= userNotInGroup
; }
387 } else if (rule_get_session_owner(rule
)) { // rule asks only if user is the session owner
388 if (reason
) { *reason
= unacceptableUser
; }
391 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
);
392 return errAuthorizationDenied
;
396 _get_agent(engine_t engine
, mechanism_t mech
, bool create
, bool firstMech
)
398 agent_t agent
= (agent_t
)CFDictionaryGetValue(engine
->mechanism_agents
, mech
);
399 if (create
&& !agent
) {
400 agent
= agent_create(engine
, mech
, engine
->auth
, engine
->proc
, firstMech
);
402 CFDictionaryAddValue(engine
->mechanism_agents
, mech
, agent
);
403 CFReleaseSafe(agent
);
410 _evaluate_builtin_mechanism(engine_t engine
, mechanism_t mech
)
412 uint64_t result
= kAuthorizationResultDeny
;
414 switch (mechanism_get_type(mech
)) {
415 case kMechanismTypeEntitled
:
416 if (auth_token_has_entitlement_for_right(engine
->auth
, engine
->currentRightName
)) {
417 result
= kAuthorizationResultAllow
;
429 _extract_password_from_la(engine_t engine
)
433 if (!engine
->la_context
) {
437 // try to retrieve secret
438 CFDataRef passdata
= LACopyCredential(engine
->la_context
, kLACredentialTypeExtractablePasscode
, NULL
);
440 if (CFDataGetBytePtr(passdata
)) {
441 os_log_debug(AUTHD_LOG
, "engine %lld: LA credentials retrieved", engine
->engine_index
);
442 auth_items_set_data(engine
->context
, kAuthorizationEnvironmentPassword
, CFDataGetBytePtr(passdata
), CFDataGetLength(passdata
));
444 const char *empty_pass
= "\0"; // authd code is unable to process empty strings so passing empty string as terminator only
445 os_log_debug(AUTHD_LOG
, "engine %lld: LA credentials empty", engine
->engine_index
);
446 auth_items_set_data(engine
->context
, kAuthorizationEnvironmentPassword
, empty_pass
, 1);
454 _evaluate_mechanisms(engine_t engine
, CFArrayRef mechanisms
)
456 uint64_t result
= kAuthorizationResultAllow
;
457 ccaudit_t ccaudit
= ccaudit_create(engine
->proc
, engine
->auth
, AUE_ssauthmech
);
458 auth_items_t context
= auth_items_create();
459 auth_items_t hints
= auth_items_create();
461 auth_items_copy(context
, engine
->context
);
462 auth_items_copy(hints
, engine
->hints
);
463 auth_items_copy(context
, engine
->sticky_context
);
465 CFDictionaryRef la_result
= NULL
;
467 CFIndex count
= CFArrayGetCount(mechanisms
);
468 bool sheet_evaluation
= false;
469 if (engine
->la_context
) {
470 int tmp
= kLAOptionNotInteractive
;
471 CFNumberRef key
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &tmp
);
473 CFNumberRef value
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &tmp
);
475 CFMutableDictionaryRef options
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
476 CFDictionarySetValue(options
, key
, value
);
477 la_result
= LACopyResultOfPolicyEvaluation(engine
->la_context
, kLAPolicyDeviceOwnerAuthentication
, options
, NULL
);
478 os_log_debug(AUTHD_LOG
, "engine %lld: Retrieve LA evaluate result: %d", engine
->engine_index
, la_result
!= NULL
);
479 CFReleaseSafe(options
);
482 CFReleaseSafe(value
);
485 for (CFIndex i
= 0; i
< count
; i
++) {
486 mechanism_t mech
= (mechanism_t
)CFArrayGetValueAtIndex(mechanisms
, i
);
488 if (mechanism_get_type(mech
)) {
489 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
);
490 result
= _evaluate_builtin_mechanism(engine
, mech
);
492 bool shoud_run_agent
= true; // evaluate comes from sheet -> we may not want to run standard SecurityAgent or authhost
493 if (engine
->la_context
) {
494 // sheet variant in progress
495 if (strcmp(mechanism_get_string(mech
), "builtin:authenticate") == 0) {
496 // set the UID the same way as SecurityAgent would
497 if (auth_items_exist(engine
->context
, "sheet-uid")) {
498 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"));
499 auth_items_set_uint(engine
->context
, "uid", auth_items_get_uint(engine
->context
, "sheet-uid"));
502 // find out if sheet just provided credentials or did real authentication
503 // if password is provided or PAM service name exists, it means authd has to evaluate credentials
504 // otherwise we need to check la_result
505 if (auth_items_exist(engine
->context
, AGENT_CONTEXT_AP_PAM_SERVICE_NAME
) || auth_items_exist(engine
->context
, kAuthorizationEnvironmentPassword
)) {
506 // do not try to get credentials as it has been already passed by sheet
507 os_log_debug(AUTHD_LOG
, "engine %lld: ignoring builtin sheet authenticate", engine
->engine_index
);
509 // sheet itself did the authenticate the user
510 os_log_debug(AUTHD_LOG
, "engine %lld: running builtin sheet authenticate", engine
->engine_index
);
511 sheet_evaluation
= true;
512 if (!la_result
|| TKGetSmartcardSetting(kTKEnforceSmartcard
) != 0) {
513 result
= kAuthorizationResultDeny
; // no la_result => evaluate did not pass for sheet method. Enforced smartcard => no way to use sheet based evaluation
516 shoud_run_agent
= false; // SecurityAgent should not be run for builtin:authenticate
517 } else if (strcmp(mechanism_get_string(mech
), "builtin:authenticate,privileged") == 0) {
518 if (sheet_evaluation
) {
519 os_log_debug(AUTHD_LOG
, "engine %lld: running builtin sheet privileged authenticate", engine
->engine_index
);
520 shoud_run_agent
= false;
521 if (!la_result
|| TKGetSmartcardSetting(kTKEnforceSmartcard
) != 0) { // should not get here under normal circumstances but we need to handle this case as well
522 result
= kAuthorizationResultDeny
; // no la_result => evaluate did not pass. Enforced smartcard => no way to use sheet based evaluation
525 // should_run_agent has to be set to true because we want authorizationhost to verify the credentials
526 os_log_debug(AUTHD_LOG
, "engine %lld: running sheet privileged authenticate", engine
->engine_index
);
531 if (shoud_run_agent
) {
532 agent_t agent
= _get_agent(engine
, mech
, true, i
== 0);
533 require_action(agent
!= NULL
, done
, result
= kAuthorizationResultUndefined
; os_log_error(AUTHD_LOG
, "Error creating mechanism agent (engine %lld)", engine
->engine_index
));
535 // check if any agent has been interrupted (it necessary if interrupt will come during creation)
538 for (j
= 0; j
< i
; j
++) {
539 agent1
= _get_agent(engine
, (mechanism_t
)CFArrayGetValueAtIndex(mechanisms
, j
), false, j
== 0);
540 if(agent1
&& agent_get_state(agent1
) == interrupting
) {
545 os_log(AUTHD_LOG
, "engine %lld: mechanisms interrupted", engine
->engine_index
);
547 asprintf(&buf
, "evaluation interrupted by %s; restarting evaluation there", mechanism_get_string(agent_get_mechanism(agent1
)));
548 ccaudit_log_mechanism(ccaudit
, engine
->currentRightName
, mechanism_get_string(agent_get_mechanism(agent1
)), kAuthorizationResultAllow
, buf
);
550 ccaudit_log_mechanism(ccaudit
, engine
->currentRightName
, mechanism_get_string(mech
), kAuthorizationResultAllow
, NULL
);
551 const char * token_name
= auth_items_get_string(hints
, AGENT_HINT_TOKEN_NAME
);
552 if (token_name
&& strlen(token_name
) == 0) {
553 auth_items_remove(hints
, AGENT_HINT_TOKEN_NAME
);
555 auth_items_copy(context
, agent_get_context(agent1
));
556 auth_items_copy(hints
, agent_get_hints(agent1
));
563 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
);
565 result
= agent_run(agent
, hints
, context
, engine
->immutable_hints
);
567 auth_items_copy(context
, agent_get_context(agent
));
568 auth_items_copy(hints
, agent_get_hints(agent
));
570 bool interrupted
= false;
571 for (CFIndex i2
= 0; i2
!= i
; i2
++) {
572 agent_t agent2
= _get_agent(engine
, (mechanism_t
)CFArrayGetValueAtIndex(mechanisms
, i2
), false, i
== 0);
573 if (agent2
&& agent_get_state(agent2
) == interrupting
) {
574 agent_deactivate(agent
);
578 asprintf(&buf
, "evaluation interrupted by %s; restarting evaluation there", mechanism_get_string(agent_get_mechanism(agent2
)));
579 ccaudit_log_mechanism(ccaudit
, engine
->currentRightName
, mechanism_get_string(agent_get_mechanism(agent2
)), kAuthorizationResultAllow
, buf
);
581 auth_items_copy(context
, agent_get_context(agent2
));
582 auth_items_copy(hints
, agent_get_hints(agent2
));
587 // Empty token name means that token doesn't exist (e.g. SC was removed).
588 // Remove empty token name from hints for UI drawing logic.
589 const char * token_name
= auth_items_get_string(hints
, AGENT_HINT_TOKEN_NAME
);
590 if (token_name
&& strlen(token_name
) == 0) {
591 auth_items_remove(hints
, AGENT_HINT_TOKEN_NAME
);
595 os_log_info(AUTHD_LOG
, "Mechanisms interrupted (engine %lld)", engine
->engine_index
);
596 enum Reason reason
= worldChanged
;
597 auth_items_set_data(hints
, AGENT_HINT_RETRY_REASON
, &reason
, sizeof(reason
));
598 result
= kAuthorizationResultAllow
;
599 _cf_dictionary_iterate(engine
->mechanism_agents
, ^bool(CFTypeRef key
__attribute__((__unused__
)), CFTypeRef value
) {
600 agent_t tempagent
= (agent_t
)value
;
601 agent_clear_interrupt(tempagent
);
608 if (result
== kAuthorizationResultAllow
) {
609 ccaudit_log_mechanism(ccaudit
, engine
->currentRightName
, mechanism_get_string(mech
), kAuthorizationResultAllow
, NULL
);
611 ccaudit_log_mechanism(ccaudit
, engine
->currentRightName
, mechanism_get_string(mech
), (uint32_t)result
, NULL
);
617 if ((result
== kAuthorizationResultUserCanceled
) || (result
== kAuthorizationResultAllow
)) {
618 // only make non-sticky context values available externally
619 auth_items_set_flags(context
, kAuthorizationEnvironmentPassword
, kAuthorizationContextFlagVolatile
);
620 // <rdar://problem/16275827> Takauthorizationenvironmentusername should always be extractable
621 auth_items_set_flags(context
, kAuthorizationEnvironmentUsername
, kAuthorizationContextFlagExtractable
);
622 auth_items_copy_with_flags(engine
->context
, context
, kAuthorizationContextFlagExtractable
| kAuthorizationContextFlagVolatile
);
623 } else if (result
== kAuthorizationResultDeny
) {
624 auth_items_clear(engine
->sticky_context
);
625 // save off sticky values in context
626 auth_items_copy_with_flags(engine
->sticky_context
, context
, kAuthorizationContextFlagSticky
);
629 CFReleaseSafe(ccaudit
);
630 CFReleaseSafe(context
);
631 CFReleaseSafe(hints
);
632 CFReleaseSafe(la_result
);
636 case kAuthorizationResultDeny
:
637 return errAuthorizationDenied
;
638 case kAuthorizationResultUserCanceled
:
639 return errAuthorizationCanceled
;
640 case kAuthorizationResultAllow
:
641 return errAuthorizationSuccess
;
642 case kAuthorizationResultUndefined
:
643 return errAuthorizationInternal
;
646 os_log_error(AUTHD_LOG
, "Evaluate - unexpected result %llu (engine %lld)", result
, engine
->engine_index
);
647 return errAuthorizationInternal
;
653 _evaluate_authentication(engine_t engine
, rule_t rule
)
655 OSStatus status
= errAuthorizationDenied
;
656 ccaudit_t ccaudit
= ccaudit_create(engine
->proc
, engine
->auth
, AUE_ssauthint
);
657 os_log_debug(AUTHD_LOG
, "engine %lld: evaluate authentication", engine
->engine_index
);
658 _set_rule_hints(engine
->hints
, rule
);
659 _set_session_hints(engine
, rule
);
661 CFArrayRef mechanisms
= rule_get_mechanisms(rule
);
662 if (!(CFArrayGetCount(mechanisms
) > 0)) {
663 mechanisms
= rule_get_mechanisms(engine
->authenticateRule
);
665 require_action(CFArrayGetCount(mechanisms
) > 0, done
, os_log_debug(AUTHD_LOG
, "engine %lld: error - no mechanisms found", engine
->engine_index
));
667 int64_t ruleTries
= rule_get_tries(rule
);
669 if (engine
->la_context
) {
671 os_log_debug(AUTHD_LOG
, "engine %lld: sheet authentication in progress, one try is enough", engine
->engine_index
);
674 for (engine
->tries
= 0; engine
->tries
< ruleTries
; engine
->tries
++) {
676 auth_items_set_data(engine
->hints
, AGENT_HINT_RETRY_REASON
, &engine
->reason
, sizeof(engine
->reason
));
677 auth_items_set_int(engine
->hints
, AGENT_HINT_TRIES
, engine
->tries
);
678 status
= _evaluate_mechanisms(engine
, mechanisms
);
680 os_log_debug(AUTHD_LOG
, "engine %lld: evaluate mechanisms result %d", engine
->engine_index
, (int)status
);
682 // successfully ran mechanisms to obtain credential
683 if (status
== errAuthorizationSuccess
) {
684 // deny is the default
685 status
= errAuthorizationDenied
;
687 credential_t newCred
= NULL
;
688 if (auth_items_exist(engine
->context
, "uid")) {
689 newCred
= credential_create(auth_items_get_uint(engine
->context
, "uid"));
691 os_log_info(AUTHD_LOG
, "Mechanism failed to return a valid uid (engine %lld)", engine
->engine_index
);
692 if (engine
->la_context
) {
693 // sheet failed so remove sheet reference and next time, standard dialog will be displayed
694 CFReleaseNull(engine
->la_context
);
699 if (credential_get_valid(newCred
)) {
700 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
);
701 ccaudit_log_success(ccaudit
, newCred
, engine
->currentRightName
);
703 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
);
704 ccaudit_log_failure(ccaudit
, auth_items_get_string(engine
->context
, "username"), engine
->currentRightName
);
707 status
= _evaluate_user_credential_for_rule(engine
, newCred
, rule
, true, false, &engine
->reason
);
709 if (status
== errAuthorizationSuccess
) {
710 _engine_set_credential(engine
, newCred
, rule_get_shared(rule
));
711 CFReleaseSafe(newCred
);
713 if (auth_token_least_privileged(engine
->auth
)) {
714 credential_t rightCred
= credential_create_with_right(engine
->currentRightName
);
715 _engine_set_credential(engine
, rightCred
, rule_get_shared(rule
));
716 CFReleaseSafe(rightCred
);
719 session_t session
= auth_token_get_session(engine
->auth
);
720 if (credential_get_uid(newCred
) == session_get_uid(session
)) {
721 os_log_debug(AUTHD_LOG
, "engine %lld: authenticated as the session owner", engine
->engine_index
);
722 session_set_attributes(auth_token_get_session(engine
->auth
), AU_SESSION_FLAG_HAS_AUTHENTICATED
);
727 os_log_error(AUTHD_LOG
, "User credential for rule failed (%d) (engine %lld)", (int)status
, engine
->engine_index
);
730 CFReleaseSafe(newCred
);
733 } else if (status
== errAuthorizationCanceled
|| status
== errAuthorizationInternal
) {
734 os_log_error(AUTHD_LOG
, "Evaluate cancelled or failed %d (engine %lld)", (int)status
, engine
->engine_index
);
736 } else if (status
== errAuthorizationDenied
) {
737 os_log_error(AUTHD_LOG
, "Evaluate denied (engine %lld)", engine
->engine_index
);
738 engine
->reason
= invalidPassphrase
;
742 if (engine
->tries
== ruleTries
) {
743 engine
->reason
= tooManyTries
;
744 auth_items_set_data(engine
->hints
, AGENT_HINT_RETRY_REASON
, &engine
->reason
, sizeof(engine
->reason
));
745 auth_items_set_int(engine
->hints
, AGENT_HINT_TRIES
, engine
->tries
);
746 ccaudit_log(ccaudit
, engine
->currentRightName
, NULL
, 1113);
750 CFReleaseSafe(ccaudit
);
756 _check_entitlement_for_rule(engine_t engine
, rule_t rule
)
758 bool entitled
= false;
759 CFTypeRef value
= NULL
;
761 if (rule_check_flags(rule
, RuleFlagEntitledAndGroup
)) {
762 if (auth_token_has_entitlement_for_right(engine
->auth
, engine
->currentRightName
)) {
763 if (credential_check_membership(auth_token_get_credential(engine
->auth
), rule_get_group(rule
))) {
764 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
);
771 if (rule_check_flags(rule
, RuleFlagVPNEntitledAndGroup
)) {
772 // com.apple.networking.vpn.configuration is an array we only check for it's existence
773 value
= auth_token_copy_entitlement_value(engine
->auth
, "com.apple.networking.vpn.configuration");
775 if (credential_check_membership(auth_token_get_credential(engine
->auth
), rule_get_group(rule
))) {
776 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
);
784 CFReleaseSafe(value
);
789 _evaluate_class_user(engine_t engine
, rule_t rule
)
791 __block OSStatus status
= errAuthorizationDenied
;
793 if (_check_entitlement_for_rule(engine
,rule
)) {
794 return errAuthorizationSuccess
;
797 if (rule_get_allow_root(rule
) && auth_token_get_uid(engine
->auth
) == 0) {
798 os_log_info(AUTHD_LOG
, "Creator of authorization has uid == 0, granting right %{public}s (engine %lld)", engine
->currentRightName
, engine
->engine_index
);
799 return errAuthorizationSuccess
;
802 if (!rule_get_authenticate_user(rule
)) {
803 status
= _evaluate_user_credential_for_rule(engine
, engine
->sessionCredential
, rule
, true, true, NULL
);
805 if (status
== errAuthorizationSuccess
) {
806 return errAuthorizationSuccess
;
809 return errAuthorizationDenied
;
812 // First -- check all the credentials we have either acquired or currently have
813 _cf_set_iterate(engine
->credentials
, ^bool(CFTypeRef value
) {
814 credential_t cred
= (credential_t
)value
;
815 // Passed-in user credentials are allowed for least-privileged mode
816 if (auth_token_least_privileged(engine
->auth
) && !credential_is_right(cred
) && credential_get_valid(cred
)) {
817 status
= _evaluate_user_credential_for_rule(engine
, cred
, rule
, false, false, NULL
);
818 if (errAuthorizationSuccess
== status
) {
819 credential_t rightCred
= credential_create_with_right(engine
->currentRightName
);
820 _engine_set_credential(engine
,rightCred
,rule_get_shared(rule
));
821 CFReleaseSafe(rightCred
);
822 return false; // exit loop
826 status
= _evaluate_credential_for_rule(engine
, cred
, rule
, false, false, NULL
);
827 if (status
== errAuthorizationSuccess
) {
828 return false; // exit loop
833 if (status
== errAuthorizationSuccess
) {
837 // Second -- go through the credentials associated to the authorization token session/auth token
838 _cf_set_iterate(engine
->effectiveCredentials
, ^bool(CFTypeRef value
) {
839 credential_t cred
= (credential_t
)value
;
840 status
= _evaluate_credential_for_rule(engine
, cred
, rule
, false, false, NULL
);
841 if (status
== errAuthorizationSuccess
) {
842 // Add the credential we used to the output set.
843 _engine_set_credential(engine
, cred
, false);
844 return false; // exit loop
849 if (status
== errAuthorizationSuccess
) {
853 // Finally - we didn't find a credential. Obtain a new credential if our flags let us do so.
854 if (!(engine
->flags
& kAuthorizationFlagExtendRights
)) {
855 os_log_error(AUTHD_LOG
, "Fatal: authorization denied (kAuthorizationFlagExtendRights not set) (engine %lld)", engine
->engine_index
);
856 return errAuthorizationDenied
;
859 // authorization that timeout immediately cannot be preauthorized
860 if (engine
->flags
& kAuthorizationFlagPreAuthorize
&& rule_get_timeout(rule
) == 0) {
861 return errAuthorizationSuccess
;
864 if (!engine
->preauthorizing
) {
865 if (!(engine
->flags
& kAuthorizationFlagInteractionAllowed
)) {
866 os_log_error(AUTHD_LOG
, "Fatal: interaction not allowed (kAuthorizationFlagInteractionAllowed not set) (engine %lld)", engine
->engine_index
);
867 return errAuthorizationInteractionNotAllowed
;
870 if (!(session_get_attributes(auth_token_get_session(engine
->auth
)) & AU_SESSION_FLAG_HAS_GRAPHIC_ACCESS
)) {
871 os_log_error(AUTHD_LOG
, "Fatal: interaction not allowed (session has no ui access) (engine %lld)", engine
->engine_index
);
872 return errAuthorizationInteractionNotAllowed
;
875 if (server_in_dark_wake()) {
876 os_log_error(AUTHD_LOG
, "Fatal: authorization denied (DW) (engine %lld)", engine
->engine_index
);
877 return errAuthorizationDenied
;
881 return _evaluate_authentication(engine
, rule
);
885 _evaluate_class_rule(engine_t engine
, rule_t rule
, bool *save_pwd
)
887 __block OSStatus status
= errAuthorizationDenied
;
888 int64_t kofn
= rule_get_kofn(rule
);
890 uint32_t total
= (uint32_t)rule_get_delegates_count(rule
);
891 __block
uint32_t success_count
= 0;
892 __block
uint32_t count
= 0;
893 os_log_debug(AUTHD_LOG
, "engine %lld: ** rule %{public}s has %u delegates kofn = %lli", engine
->engine_index
, rule_get_name(rule
), total
, kofn
);
894 rule_delegates_iterator(rule
, ^bool(rule_t delegate
) {
897 if (kofn
!= 0 && success_count
== kofn
) {
898 status
= errAuthorizationSuccess
;
902 os_log_debug(AUTHD_LOG
, "engine %lld: * evaluate rule %{public}s (%i)", engine
->engine_index
, rule_get_name(delegate
), count
);
903 status
= _evaluate_rule(engine
, delegate
, save_pwd
);
905 // if status is cancel/internal error abort
906 if ((status
== errAuthorizationCanceled
) || (status
== errAuthorizationInternal
))
909 if (status
!= errAuthorizationSuccess
) {
911 // if remaining is less than required abort
912 if ((total
- count
) < (kofn
- success_count
)) {
913 os_log_debug(AUTHD_LOG
, "engine %lld: rule evaluation remaining: %i, required: %lli", engine
->engine_index
, (total
- count
), (kofn
- success_count
));
929 _preevaluate_class_rule(engine_t engine
, rule_t rule
)
931 os_log_debug(AUTHD_LOG
, "engine %lld: _preevaluate_class_rule %{public}s", engine
->engine_index
, rule_get_name(rule
));
933 __block
bool password_only
= false;
934 rule_delegates_iterator(rule
, ^bool(rule_t delegate
) {
935 if (_preevaluate_rule(engine
, delegate
)) {
936 password_only
= true;
942 return password_only
;
946 _evaluate_class_mechanism(engine_t engine
, rule_t rule
)
948 OSStatus status
= errAuthorizationDenied
;
949 CFArrayRef mechanisms
= NULL
;
951 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
));
953 mechanisms
= rule_get_mechanisms(rule
);
955 if (server_in_dark_wake()) {
956 CFIndex count
= CFArrayGetCount(mechanisms
);
957 for (CFIndex i
= 0; i
< count
; i
++) {
958 if (!mechanism_is_privileged((mechanism_t
)CFArrayGetValueAtIndex(mechanisms
, i
))) {
959 os_log_error(AUTHD_LOG
, "Fatal: authorization denied (in DW) (engine %lld)", engine
->engine_index
);
965 int64_t ruleTries
= rule_get_tries(rule
);
968 auth_items_set_data(engine
->hints
, AGENT_HINT_RETRY_REASON
, &engine
->reason
, sizeof(engine
->reason
));
969 auth_items_set_int(engine
->hints
, AGENT_HINT_TRIES
, engine
->tries
);
971 status
= _evaluate_mechanisms(engine
, mechanisms
);
972 os_log_debug(AUTHD_LOG
, "engine %lld: evaluate mechanisms result %d", engine
->engine_index
, (int)status
);
974 if (status
== errAuthorizationSuccess
) {
975 credential_t newCred
= NULL
;
976 if (auth_items_exist(engine
->context
, "uid")) {
977 newCred
= credential_create(auth_items_get_uint(engine
->context
, "uid"));
979 os_log_info(AUTHD_LOG
, "Mechanism did not return a uid (engine %lld)", engine
->engine_index
);
983 _engine_set_credential(engine
, newCred
, rule_get_shared(rule
));
985 if (auth_token_least_privileged(engine
->auth
)) {
986 credential_t rightCred
= credential_create_with_right(engine
->currentRightName
);
987 _engine_set_credential(engine
, rightCred
, rule_get_shared(rule
));
988 CFReleaseSafe(rightCred
);
991 if (strcmp(engine
->currentRightName
, "system.login.console") == 0 && !auth_items_exist(engine
->context
, AGENT_CONTEXT_AUTO_LOGIN
)) {
992 session_set_attributes(auth_token_get_session(engine
->auth
), AU_SESSION_FLAG_HAS_AUTHENTICATED
);
995 CFReleaseSafe(newCred
);
1001 } while ( (status
== errAuthorizationDenied
) // only if we have an expected faulure we continue
1002 && ((ruleTries
== 0) || ((ruleTries
> 0) && engine
->tries
< ruleTries
))); // ruleTries == 0 means we try forever
1003 // ruleTires > 0 means we try upto ruleTries times
1008 // TODO: Remove when all clients have adopted entitlement
1010 enforced_entitlement(void)
1012 bool enforced_enabled
= false;
1013 //sudo defaults write /Library/Preferences/com.apple.authd enforceEntitlement -bool true
1014 CFTypeRef enforce
= (CFNumberRef
)CFPreferencesCopyValue(CFSTR("enforceEntitlement"), CFSTR(SECURITY_AUTH_NAME
), kCFPreferencesAnyUser
, kCFPreferencesCurrentHost
);
1015 if (enforce
&& CFGetTypeID(enforce
) == CFBooleanGetTypeID()) {
1016 enforced_enabled
= CFBooleanGetValue((CFBooleanRef
)enforce
);
1017 os_log_debug(AUTHD_LOG
, "enforceEntitlement for extract password: %{public}s", enforced_enabled
? "enabled" : "disabled");
1019 CFReleaseSafe(enforce
);
1021 return enforced_enabled
;
1025 _evaluate_rule(engine_t engine
, rule_t rule
, bool *save_pwd
)
1027 if (rule_check_flags(rule
, RuleFlagEntitled
)) {
1028 if (auth_token_has_entitlement_for_right(engine
->auth
, engine
->currentRightName
)) {
1029 os_log_debug(AUTHD_LOG
, "engine %lld: rule allow, creator of authorization has entitlement for right %{public}s", engine
->engine_index
, engine
->currentRightName
);
1030 return errAuthorizationSuccess
;
1034 // check apple signature also for every sheet authorization + disable this check for debug builds
1035 if (engine
->la_context
|| rule_check_flags(rule
, RuleFlagRequireAppleSigned
)) {
1036 if (!auth_token_apple_signed(engine
->auth
)) {
1038 os_log_error(AUTHD_LOG
, "Rule deny, creator of authorization is not signed by Apple (engine %lld)", engine
->engine_index
);
1039 return errAuthorizationDenied
;
1041 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
);
1046 if (rule_get_extract_password(rule
)) {
1047 // check if process is entitled to extract password
1048 CFTypeRef extract_password_entitlement
= auth_token_copy_entitlement_value(engine
->auth
, "com.apple.authorization.extract-password");
1049 if (extract_password_entitlement
&& (CFGetTypeID(extract_password_entitlement
) == CFBooleanGetTypeID()) && extract_password_entitlement
== kCFBooleanTrue
) {
1051 os_log_debug(AUTHD_LOG
, "engine %lld: authorization allowed to extract password", engine
->engine_index
);
1053 os_log_debug(AUTHD_LOG
, "engine %lld: authorization NOT allowed to extract password", engine
->engine_index
);
1055 CFReleaseSafe(extract_password_entitlement
);
1058 // TODO: Remove when all clients have adopted entitlement
1059 if (!enforced_entitlement()) {
1060 *save_pwd
|= rule_get_extract_password(rule
);
1063 switch (rule_get_class(rule
)) {
1065 os_log(AUTHD_LOG
, "Rule set to allow (engine %lld)", engine
->engine_index
);
1066 return errAuthorizationSuccess
;
1068 os_log(AUTHD_LOG
, "Rule set to deny (engine %lld)", engine
->engine_index
);
1069 return errAuthorizationDenied
;
1071 return _evaluate_class_user(engine
, rule
);
1073 return _evaluate_class_rule(engine
, rule
, save_pwd
);
1075 return _evaluate_class_mechanism(engine
, rule
);
1077 os_log_error(AUTHD_LOG
, "Invalid class for rule or rule not found: %{public}s (engine %lld)", rule_get_name(rule
), engine
->engine_index
);
1078 return errAuthorizationInternal
;
1082 // returns true if this rule or its children contain RC_USER rule with password_only==true
1084 _preevaluate_rule(engine_t engine
, rule_t rule
)
1086 os_log_debug(AUTHD_LOG
, "engine %lld: _preevaluate_rule %{public}s", engine
->engine_index
, rule_get_name(rule
));
1088 switch (rule_get_class(rule
)) {
1093 return rule_get_password_only(rule
);
1095 return _preevaluate_class_rule(engine
, rule
);
1104 _find_rule(engine_t engine
, authdb_connection_t dbconn
, const char * string
)
1107 size_t sLen
= strlen(string
);
1109 char * buf
= calloc(1u, sLen
+ 1);
1110 strlcpy(buf
, string
, sLen
+ 1);
1111 char * ptr
= buf
+ sLen
;
1112 __block
int64_t count
= 0;
1117 authdb_step(dbconn
, "SELECT COUNT(name) AS cnt FROM rules WHERE name = ? AND type = 1",
1118 ^(sqlite3_stmt
*stmt
) {
1119 sqlite3_bind_text(stmt
, 1, buf
, -1, NULL
);
1120 }, ^bool(auth_items_t data
) {
1121 count
= auth_items_get_int64(data
, "cnt");
1126 r
= rule_create_with_string(buf
, dbconn
);
1130 // if buf ends with a . and we didn't find a rule remove .
1134 // find any remaining . and truncate the string
1135 ptr
= strrchr(buf
, '.');
1146 // set default if we didn't find a rule
1148 r
= rule_create_with_string("", dbconn
);
1149 if (rule_get_id(r
) == 0) {
1151 os_log_error(AUTHD_LOG
, "Default rule lookup error (missing), using builtin defaults (engine %lld)", engine
->engine_index
);
1152 r
= rule_create_default();
1158 static void _parse_environment(engine_t engine
, auth_items_t environment
)
1160 require(environment
!= NULL
, done
);
1163 os_log_debug(AUTHD_LOG
, "engine %lld: Dumping Environment: %@", engine
->engine_index
, environment
);
1166 // Check if a credential was passed into the environment and we were asked to extend the rights
1167 if (engine
->flags
& kAuthorizationFlagExtendRights
&& !(engine
->flags
& kAuthorizationFlagSheet
)) {
1168 const char * user
= auth_items_get_string(environment
, kAuthorizationEnvironmentUsername
);
1169 const char * pass
= auth_items_get_string(environment
, kAuthorizationEnvironmentPassword
);
1170 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
1171 require(password_was_used
== true, done
);
1173 bool shared
= auth_items_exist(environment
, kAuthorizationEnvironmentShared
);
1174 require_action(user
!= NULL
, done
, os_log_debug(AUTHD_LOG
, "engine %lld: user not used password", engine
->engine_index
));
1176 struct passwd
*pw
= getpwnam(user
);
1177 require_action(pw
!= NULL
, done
, os_log_error(AUTHD_LOG
, "User not found %{public}s (engine %lld)", user
, engine
->engine_index
));
1179 int checkpw_status
= checkpw_internal(pw
, pass
? pass
: "");
1180 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
));
1182 credential_t cred
= credential_create(pw
->pw_uid
);
1183 if (credential_get_valid(cred
)) {
1184 os_log_info(AUTHD_LOG
, "checkpw() succeeded, creating credential for user %{public}s (engine %lld)", user
, engine
->engine_index
);
1185 _engine_set_credential(engine
, cred
, shared
);
1187 auth_items_set_string(engine
->context
, kAuthorizationEnvironmentUsername
, user
);
1188 auth_items_set_string(engine
->context
, kAuthorizationEnvironmentPassword
, pass
? pass
: "");
1190 CFReleaseSafe(cred
);
1198 static bool _verify_sandbox(engine_t engine
, const char * right
)
1200 pid_t pid
= process_get_pid(engine
->proc
);
1201 if (sandbox_check(pid
, "authorization-right-obtain", SANDBOX_FILTER_RIGHT_NAME
, right
)) {
1202 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
);
1206 pid
= auth_token_get_pid(engine
->auth
);
1207 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
)) {
1208 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
);
1216 #pragma mark engine methods
1218 OSStatus
engine_preauthorize(engine_t engine
, auth_items_t credentials
)
1220 os_log(AUTHD_LOG
, "engine %lld: preauthorizing", engine
->engine_index
);
1222 OSStatus status
= errAuthorizationDenied
;
1223 bool save_password
= false;
1224 CFTypeRef extract_password_entitlement
= auth_token_copy_entitlement_value(engine
->auth
, "com.apple.authorization.extract-password");
1225 if (extract_password_entitlement
&& (CFGetTypeID(extract_password_entitlement
) == CFBooleanGetTypeID()) && extract_password_entitlement
== kCFBooleanTrue
) {
1226 save_password
= true;
1227 os_log_debug(AUTHD_LOG
, "engine %lld: authorization allowed to extract password", engine
->engine_index
);
1229 os_log_debug(AUTHD_LOG
, "engine %lld: authorization NOT allowed to extract password", engine
->engine_index
);
1231 CFReleaseSafe(extract_password_entitlement
);
1233 // TODO: Remove when all clients have adopted entitlement
1234 if (!enforced_entitlement()) {
1235 save_password
= true;
1238 engine
->flags
= kAuthorizationFlagExtendRights
;
1239 engine
->preauthorizing
= true;
1240 CFAssignRetained(engine
->la_context
, engine_copy_context(engine
, credentials
));
1241 _extract_password_from_la(engine
);
1243 const char *user
= auth_items_get_string(credentials
, kAuthorizationEnvironmentUsername
);
1244 require(user
, done
);
1246 auth_items_set_string(engine
->context
, kAuthorizationEnvironmentUsername
, user
);
1247 struct passwd
*pwd
= getpwnam(user
);
1250 auth_items_set_int(engine
->context
, AGENT_CONTEXT_UID
, pwd
->pw_uid
);
1252 const char *service
= auth_items_get_string(credentials
, AGENT_CONTEXT_AP_PAM_SERVICE_NAME
);
1255 auth_items_set_string(engine
->context
, AGENT_CONTEXT_AP_USER_NAME
, user
);
1256 auth_items_set_string(engine
->context
, AGENT_CONTEXT_AP_PAM_SERVICE_NAME
, service
);
1259 if (auth_items_exist(credentials
, AGENT_CONTEXT_AP_TOKEN
)) {
1261 const void *data
= auth_items_get_data(credentials
, AGENT_CONTEXT_AP_TOKEN
, &datalen
);
1263 auth_items_set_data(engine
->context
, AGENT_CONTEXT_AP_TOKEN
, data
, datalen
);
1267 auth_items_t decrypted_items
= auth_items_create();
1268 require_action(decrypted_items
!= NULL
, done
, os_log_error(AUTHD_LOG
, "Unable to create items (engine %lld)", engine
->engine_index
));
1269 auth_items_content_copy(decrypted_items
, auth_token_get_context(engine
->auth
));
1270 auth_items_decrypt(decrypted_items
, auth_token_get_encryption_key(engine
->auth
));
1271 auth_items_copy(engine
->context
, decrypted_items
);
1272 CFReleaseSafe(decrypted_items
);
1274 engine
->dismissed
= false;
1275 auth_rights_clear(engine
->grantedRights
);
1277 rule_t rule
= rule_create_preauthorization();
1278 engine
->currentRightName
= rule_get_name(rule
);
1279 engine
->currentRule
= rule
;
1280 status
= _evaluate_rule(engine
, rule
, &save_password
);
1282 case errAuthorizationSuccess
:
1283 os_log(AUTHD_LOG
, "Succeeded preauthorizing client '%{public}s' [%d] for authorization created by '%{public}s' [%d] (%X,%d) (engine %lld)",
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
), engine
->engine_index
);
1286 status
= errAuthorizationSuccess
;
1288 case errAuthorizationDenied
:
1289 case errAuthorizationInteractionNotAllowed
:
1290 case errAuthorizationCanceled
:
1291 os_log(AUTHD_LOG
, "Failed to preauthorize client '%{public}s' [%d] for authorization created by '%{public}s' [%d] (%X,%d) (%i) (engine %lld)",
1292 process_get_code_url(engine
->proc
), process_get_pid(engine
->proc
),
1293 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
);
1296 os_log_error(AUTHD_LOG
, "Preauthorize returned %d => returning errAuthorizationInternal (engine %lld)", (int)status
, engine
->engine_index
);
1297 status
= errAuthorizationInternal
;
1301 CFReleaseSafe(rule
);
1303 if (engine
->dismissed
) {
1304 os_log_error(AUTHD_LOG
, "Engine dismissed (engine %lld)", engine
->engine_index
);
1305 status
= errAuthorizationDenied
;
1308 os_log_debug(AUTHD_LOG
, "engine %lld: preauthorize result: %d", engine
->engine_index
, (int)status
);
1310 _cf_set_iterate(engine
->credentials
, ^bool(CFTypeRef value
) {
1311 credential_t cred
= (credential_t
)value
;
1312 // skip all uid credentials when running in least privileged
1313 if (auth_token_least_privileged(engine
->auth
) && !credential_is_right(cred
))
1316 session_t session
= auth_token_get_session(engine
->auth
);
1317 auth_token_set_credential(engine
->auth
, cred
);
1318 if (credential_get_shared(cred
)) {
1319 session_set_credential(session
, cred
);
1321 if (credential_is_right(cred
)) {
1322 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
));
1324 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
));
1330 if (status
== errAuthorizationSuccess
&& save_password
) {
1331 auth_items_set_flags(engine
->context
, kAuthorizationEnvironmentPassword
, kAuthorizationContextFlagExtractable
);
1334 if ((status
== errAuthorizationSuccess
) || (status
== errAuthorizationCanceled
)) {
1335 auth_items_t encrypted_items
= auth_items_create();
1336 require_action(encrypted_items
!= NULL
, done
, os_log_error(AUTHD_LOG
, "Unable to create items (engine %lld)", engine
->engine_index
));
1337 auth_items_content_copy_with_flags(encrypted_items
, engine
->context
, kAuthorizationContextFlagExtractable
);
1339 os_log_debug(AUTHD_LOG
, "engine %lld: ********** Dumping preauthorized context for encryption **********", engine
->engine_index
);
1340 os_log_debug(AUTHD_LOG
, "%@", encrypted_items
);
1342 auth_items_encrypt(encrypted_items
, auth_token_get_encryption_key(engine
->auth
));
1343 auth_items_copy_with_flags(auth_token_get_context(engine
->auth
), encrypted_items
, kAuthorizationContextFlagExtractable
);
1344 os_log_debug(AUTHD_LOG
, "engine %lld: encrypted preauthorization context data", engine
->engine_index
);
1345 CFReleaseSafe(encrypted_items
);
1349 engine
->preauthorizing
= false;
1350 auth_items_clear(engine
->context
);
1351 auth_items_clear(engine
->sticky_context
);
1352 CFDictionaryRemoveAllValues(engine
->mechanism_agents
);
1356 OSStatus
engine_authorize(engine_t engine
, auth_rights_t rights
, auth_items_t environment
, AuthorizationFlags flags
)
1358 __block OSStatus status
= errAuthorizationSuccess
;
1359 __block
bool save_password
= false;
1360 __block
bool password_only
= false;
1361 CFIndex rights_count
= auth_rights_get_count(rights
);
1362 ccaudit_t ccaudit
= NULL
;
1364 require(rights
!= NULL
, done
);
1366 ccaudit
= ccaudit_create(engine
->proc
, engine
->auth
, AUE_ssauthorize
);
1367 if (auth_rights_get_count(rights
) > 0) {
1368 ccaudit_log(ccaudit
, "begin evaluation", NULL
, 0);
1372 __block CFMutableArrayRef rights_list
= NULL
;
1373 rights_list
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1374 auth_rights_iterate(rights
, ^bool(const char *key
) {
1378 CFStringRef tmp
= CFStringCreateWithCString(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
);
1380 CFArrayAppendValue(rights_list
, tmp
);
1383 os_log_error(AUTHD_LOG
, "Unable to get details for right %{public}s", key
);
1388 os_log_info(AUTHD_LOG
, "Process %{public}s (PID %d) evaluates %ld rights (engine %lld): %{public}@", process_get_code_url(engine
->proc
), process_get_pid(engine
->proc
), (long)rights_count
, engine
->engine_index
, rights_list
);
1389 CFReleaseNull(rights_list
);
1392 if (!auth_token_apple_signed(engine
->auth
)) {
1394 flags
&= ~kAuthorizationFlagSheet
;
1396 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
);
1400 engine
->flags
= flags
;
1403 _parse_environment(engine
, environment
);
1404 auth_items_copy(engine
->hints
, environment
);
1407 // Restore all context values from the AuthorizationRef
1408 auth_items_t decrypted_items
= auth_items_create();
1409 require_action(decrypted_items
!= NULL
, done
, os_log_error(AUTHD_LOG
, "Unable to create items (engine %lld)", engine
->engine_index
));
1410 auth_items_content_copy(decrypted_items
, auth_token_get_context(engine
->auth
));
1411 auth_items_decrypt(decrypted_items
, auth_token_get_encryption_key(engine
->auth
));
1412 auth_items_copy(engine
->context
, decrypted_items
);
1413 CFReleaseSafe(decrypted_items
);
1415 if (engine
->flags
& kAuthorizationFlagSheet
) {
1416 CFTypeRef extract_password_entitlement
= auth_token_copy_entitlement_value(engine
->auth
, "com.apple.authorization.extract-password");
1417 if (extract_password_entitlement
&& (CFGetTypeID(extract_password_entitlement
) == CFBooleanGetTypeID()) && extract_password_entitlement
== kCFBooleanTrue
) {
1418 save_password
= true;
1419 os_log_debug(AUTHD_LOG
, "engine %lld: authorization allowed to extract password", engine
->engine_index
);
1421 os_log_debug(AUTHD_LOG
, "engine %lld: authorization NOT allowed to extract password", engine
->engine_index
);
1423 CFReleaseSafe(extract_password_entitlement
);
1425 // TODO: Remove when all clients have adopted entitlement
1426 if (!enforced_entitlement()) {
1427 save_password
= true;
1430 // Try to use/update fresh context values from the environment
1431 require_action(environment
, done
, os_log_error(AUTHD_LOG
, "Missing environment for sheet authorization (engine %lld)", engine
->engine_index
); status
= errAuthorizationDenied
);
1433 const char *user
= auth_items_get_string(environment
, kAuthorizationEnvironmentUsername
);
1434 require_action(user
, done
, os_log_error(AUTHD_LOG
, "Missing username (engine %lld)", engine
->engine_index
); status
= errAuthorizationDenied
);
1436 auth_items_set_string(engine
->context
, kAuthorizationEnvironmentUsername
, user
);
1437 struct passwd
*pwd
= getpwnam(user
);
1438 require_action(pwd
, done
, os_log_error(AUTHD_LOG
, "Invalid username %s (engine %lld)", user
, engine
->engine_index
); status
= errAuthorizationDenied
);
1439 auth_items_set_uint(engine
->context
, "sheet-uid", pwd
->pw_uid
);
1441 // move sheet-specific items from hints to context
1442 const char *service
= auth_items_get_string(engine
->hints
, AGENT_CONTEXT_AP_PAM_SERVICE_NAME
);
1444 if (auth_items_exist(engine
->hints
, AGENT_CONTEXT_AP_USER_NAME
)) {
1445 auth_items_set_string(engine
->context
, AGENT_CONTEXT_AP_USER_NAME
, auth_items_get_string(engine
->hints
, AGENT_CONTEXT_AP_USER_NAME
));
1446 auth_items_remove(engine
->hints
, AGENT_CONTEXT_AP_USER_NAME
);
1448 auth_items_set_string(engine
->context
, AGENT_CONTEXT_AP_USER_NAME
, user
);
1451 auth_items_set_string(engine
->context
, AGENT_CONTEXT_AP_PAM_SERVICE_NAME
, service
);
1452 auth_items_remove(engine
->hints
, AGENT_CONTEXT_AP_PAM_SERVICE_NAME
);
1455 if (auth_items_exist(environment
, AGENT_CONTEXT_AP_TOKEN
)) {
1457 const void *data
= auth_items_get_data(engine
->hints
, AGENT_CONTEXT_AP_TOKEN
, &datalen
);
1459 auth_items_set_data(engine
->context
, AGENT_CONTEXT_AP_TOKEN
, data
, datalen
);
1461 auth_items_remove(engine
->hints
, AGENT_CONTEXT_AP_TOKEN
);
1464 engine_acquire_sheet_data(engine
);
1465 _extract_password_from_la(engine
);
1466 engine
->preauthorizing
= true;
1469 engine
->dismissed
= false;
1470 auth_rights_clear(engine
->grantedRights
);
1472 if (!(engine
->flags
& kAuthorizationFlagIgnorePasswordOnly
))
1474 // first check if any of rights uses rule with password-only set to true
1475 // if so, set appropriate hint so SecurityAgent won't use alternate authentication methods like smartcard etc.
1476 authdb_connection_t dbconn
= authdb_connection_acquire(server_get_database()); // get db handle
1477 auth_rights_iterate(rights
, ^bool(const char *key
) {
1480 os_log_debug(AUTHD_LOG
, "engine %lld: checking if rule %{public}s contains password-only item", engine
->engine_index
, key
);
1482 rule_t rule
= _find_rule(engine
, dbconn
, key
);
1484 if (rule
&& _preevaluate_rule(engine
, rule
)) {
1485 password_only
= true;
1486 CFReleaseSafe(rule
);
1489 CFReleaseSafe(rule
);
1492 authdb_connection_release(&dbconn
); // release db handle
1494 os_log_info(AUTHD_LOG
, "Password-only flag ignored (engine %lld)", engine
->engine_index
);
1497 if (password_only
) {
1498 os_log_debug(AUTHD_LOG
, "engine %lld: password-only item found, forcing SecurityAgent to use password-only UI", engine
->engine_index
);
1499 auth_items_set_bool(engine
->immutable_hints
, AGENT_HINT_PASSWORD_ONLY
, true);
1502 auth_rights_iterate(rights
, ^bool(const char *key
) {
1507 if (!_verify_sandbox(engine
, key
)) { // _verify_sandbox is already logging failures
1508 status
= errAuthorizationDenied
;
1512 authdb_connection_t dbconn
= authdb_connection_acquire(server_get_database()); // get db handle
1514 os_log_debug(AUTHD_LOG
, "engine %lld: evaluate right %{public}s", engine
->engine_index
, key
);
1515 rule_t rule
= _find_rule(engine
, dbconn
, key
);
1516 const char * rule_name
= rule_get_name(rule
);
1517 if (rule_name
&& (strcasecmp(rule_name
, "") == 0)) {
1518 rule_name
= "default (not defined)";
1520 os_log_debug(AUTHD_LOG
, "engine %lld: using rule %{public}s", engine
->engine_index
, rule_name
);
1522 // only need the hints & mechanisms if we are going to show ui
1523 if (engine
->flags
& kAuthorizationFlagInteractionAllowed
) {
1524 _set_right_hints(engine
->hints
, key
);
1525 _set_localization_hints(dbconn
, engine
->hints
, rule
);
1526 if (!engine
->authenticateRule
) {
1527 engine
->authenticateRule
= rule_create_with_string("authenticate", dbconn
);
1531 authdb_connection_release(&dbconn
); // release db handle
1533 engine
->currentRightName
= key
;
1534 engine
->currentRule
= rule
;
1536 ccaudit_log(ccaudit
, key
, rule_name
, 0);
1538 status
= _evaluate_rule(engine
, engine
->currentRule
, &save_password
);
1540 case errAuthorizationSuccess
:
1541 auth_rights_add(engine
->grantedRights
, key
);
1542 auth_rights_set_flags(engine
->grantedRights
, key
, auth_rights_get_flags(rights
,key
));
1544 if ((engine
->flags
& kAuthorizationFlagPreAuthorize
) &&
1545 (rule_get_class(engine
->currentRule
) == RC_USER
) &&
1546 (rule_get_timeout(engine
->currentRule
) == 0)) {
1547 // FIXME: kAuthorizationFlagPreAuthorize => kAuthorizationFlagCanNotPreAuthorize ???
1548 auth_rights_set_flags(engine
->grantedRights
, engine
->currentRightName
, kAuthorizationFlagPreAuthorize
);
1551 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)",
1552 key
, process_get_code_url(engine
->proc
), process_get_pid(engine
->proc
),
1553 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
);
1555 case errAuthorizationDenied
:
1556 case errAuthorizationInteractionNotAllowed
:
1557 case errAuthorizationCanceled
:
1558 if (engine
->flags
& kAuthorizationFlagInteractionAllowed
) {
1559 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)",
1560 key
, process_get_code_url(engine
->proc
), process_get_pid(engine
->proc
),
1561 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
,
1562 engine
->engine_index
);
1564 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)",
1565 key
, process_get_code_url(engine
->proc
), process_get_pid(engine
->proc
),
1566 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
,
1567 engine
->engine_index
);
1571 os_log_error(AUTHD_LOG
, "Evaluate returned %d, returning errAuthorizationInternal (engine %lld)", (int)status
, engine
->engine_index
);
1572 status
= errAuthorizationInternal
;
1576 ccaudit_log_authorization(ccaudit
, engine
->currentRightName
, status
);
1578 CFReleaseSafe(rule
);
1579 engine
->currentRightName
= NULL
;
1580 engine
->currentRule
= NULL
;
1582 auth_items_remove_with_flags(engine
->hints
, kEngineHintsFlagTemporary
);
1584 if (!(engine
->flags
& kAuthorizationFlagPartialRights
) && (status
!= errAuthorizationSuccess
)) {
1591 if (password_only
) {
1592 os_log_debug(AUTHD_LOG
, "engine %lld: removing password-only flag", engine
->engine_index
);
1593 auth_items_remove(engine
->immutable_hints
, AGENT_HINT_PASSWORD_ONLY
);
1596 if ((engine
->flags
& kAuthorizationFlagPartialRights
) && (auth_rights_get_count(engine
->grantedRights
) > 0)) {
1597 status
= errAuthorizationSuccess
;
1600 if (engine
->dismissed
) {
1601 os_log_error(AUTHD_LOG
, "Dismissed (engine %lld)", engine
->engine_index
);
1602 status
= errAuthorizationDenied
;
1605 os_log_debug(AUTHD_LOG
, "engine %lld: authorize result: %d", engine
->engine_index
, (int)status
);
1607 if (engine
->flags
& kAuthorizationFlagSheet
) {
1608 engine
->preauthorizing
= false;
1611 if ((engine
->flags
& kAuthorizationFlagExtendRights
) && !(engine
->flags
& kAuthorizationFlagDestroyRights
)) {
1612 _cf_set_iterate(engine
->credentials
, ^bool(CFTypeRef value
) {
1613 credential_t cred
= (credential_t
)value
;
1614 // skip all uid credentials when running in least privileged
1615 if (auth_token_least_privileged(engine
->auth
) && !credential_is_right(cred
))
1618 session_t session
= auth_token_get_session(engine
->auth
);
1619 auth_token_set_credential(engine
->auth
, cred
);
1620 if (credential_get_shared(cred
)) {
1621 session_set_credential(session
, cred
);
1623 if (credential_is_right(cred
)) {
1624 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
));
1626 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
));
1632 if (status
== errAuthorizationSuccess
&& save_password
) {
1633 auth_items_set_flags(engine
->context
, kAuthorizationEnvironmentPassword
, kAuthorizationContextFlagExtractable
);
1636 if ((status
== errAuthorizationSuccess
) || (status
== errAuthorizationCanceled
)) {
1637 auth_items_t encrypted_items
= auth_items_create();
1638 require_action(encrypted_items
!= NULL
, done
, os_log_error(AUTHD_LOG
, "Unable to create items (engine %lld)", engine
->engine_index
));
1639 auth_items_content_copy_with_flags(encrypted_items
, engine
->context
, kAuthorizationContextFlagExtractable
);
1641 os_log_debug(AUTHD_LOG
,"engine %lld: ********** Dumping context for encryption **********", engine
->engine_index
);
1642 os_log_debug(AUTHD_LOG
, "%@", encrypted_items
);
1644 auth_items_encrypt(encrypted_items
, auth_token_get_encryption_key(engine
->auth
));
1645 auth_items_copy_with_flags(auth_token_get_context(engine
->auth
), encrypted_items
, kAuthorizationContextFlagExtractable
);
1646 os_log_debug(AUTHD_LOG
, "engine %lld: encrypted authorization context data", engine
->engine_index
);
1647 CFReleaseSafe(encrypted_items
);
1650 if (auth_rights_get_count(rights
) > 0) {
1651 ccaudit_log(ccaudit
, "end evaluation", NULL
, status
);
1655 os_log_debug(AUTHD_LOG
, "engine %lld: ********** Dumping auth->credentials **********", engine
->engine_index
);
1656 auth_token_credentials_iterate(engine
->auth
, ^bool(credential_t cred
) {
1657 os_log_debug(AUTHD_LOG
, "%@", cred
);
1660 os_log_debug(AUTHD_LOG
, "engine %lld: ********** Dumping session->credentials **********", engine
->engine_index
);
1661 session_credentials_iterate(auth_token_get_session(engine
->auth
), ^bool(credential_t cred
) {
1662 os_log_debug(AUTHD_LOG
, "%@", cred
);
1665 os_log_debug(AUTHD_LOG
, "engine %lld: ********** Dumping engine->context **********", engine
->engine_index
);
1666 os_log_debug(AUTHD_LOG
, "%@", engine
->context
);
1667 os_log_debug(AUTHD_LOG
, "engine %lld: ********** Dumping auth->context **********", engine
->engine_index
);
1668 os_log_debug(AUTHD_LOG
, "%@", engine
->auth
);
1669 os_log_debug(AUTHD_LOG
, "engine %lld: ********** Dumping granted rights **********", engine
->engine_index
);
1670 os_log_debug(AUTHD_LOG
, "%@", engine
->grantedRights
);
1674 auth_items_clear(engine
->context
);
1675 auth_items_clear(engine
->sticky_context
);
1676 CFReleaseSafe(ccaudit
);
1677 CFDictionaryRemoveAllValues(engine
->mechanism_agents
);
1683 _wildcard_right_exists(engine_t engine
, const char * right
)
1685 // checks if a wild card right exists
1686 // ex: com.apple. system.
1687 bool exists
= false;
1689 authdb_connection_t dbconn
= authdb_connection_acquire(server_get_database()); // get db handle
1690 require(dbconn
!= NULL
, done
);
1692 rule
= _find_rule(engine
, dbconn
, right
);
1693 require(rule
!= NULL
, done
);
1695 const char * ruleName
= rule_get_name(rule
);
1696 require(ruleName
!= NULL
, done
);
1697 size_t len
= strlen(ruleName
);
1698 require(len
!= 0, done
);
1700 if (ruleName
[len
-1] == '.') {
1706 authdb_connection_release(&dbconn
);
1707 CFReleaseSafe(rule
);
1712 // Validate db right modification
1714 // meta rights are constructed as follows:
1715 // we don't allow setting of wildcard rights, so you can only be more specific
1716 // note that you should never restrict things with a wildcard right without disallowing
1717 // changes to the entire domain. ie.
1718 // system.privilege. -> never
1719 // config.add.system.privilege. -> never
1720 // config.modify.system.privilege. -> never
1721 // config.delete.system.privilege. -> never
1722 // For now we don't allow any configuration of configuration rules
1723 // config.config. -> never
1725 OSStatus
engine_verify_modification(engine_t engine
, rule_t rule
, bool remove
, bool force_modify
)
1727 OSStatus status
= errAuthorizationDenied
;
1728 auth_rights_t checkRight
= NULL
;
1730 memset(buf
, 0, sizeof(buf
));
1732 const char * right
= rule_get_name(rule
);
1733 require(right
!= NULL
, done
);
1734 size_t len
= strlen(right
);
1735 require(len
!= 0, done
);
1737 require_action(right
[len
-1] != '.', done
, os_log_error(AUTHD_LOG
, "Not allowed to set wild card rules (engine %lld)", engine
->engine_index
));
1739 if (strncasecmp(right
, kConfigRight
, strlen(kConfigRight
)) == 0) {
1740 // special handling of meta right change:
1741 // config.add. config.modify. config.remove. config.{}.
1742 // check for config.<right> (which always starts with config.config.)
1743 strlcat(buf
, kConfigRight
, sizeof(buf
));
1745 bool existing
= (rule_get_id(rule
) != 0) ? true : _wildcard_right_exists(engine
, right
);
1747 if (existing
|| force_modify
) {
1748 strlcat(buf
, kAuthorizationConfigRightModify
,sizeof(buf
));
1750 strlcat(buf
, kAuthorizationConfigRightAdd
, sizeof(buf
));
1754 strlcat(buf
, kAuthorizationConfigRightRemove
, sizeof(buf
));
1756 status
= errAuthorizationSuccess
;
1762 strlcat(buf
, right
, sizeof(buf
));
1764 checkRight
= auth_rights_create();
1765 auth_rights_add(checkRight
, buf
);
1766 status
= engine_authorize(engine
, checkRight
, kAuthorizationEmptyEnvironment
, kAuthorizationFlagDefaults
| kAuthorizationFlagInteractionAllowed
| kAuthorizationFlagExtendRights
);
1769 os_log_debug(AUTHD_LOG
, "engine %lld: authorizing %{public}s for db modification: %d", engine
->engine_index
, right
, (int)status
);
1770 CFReleaseSafe(checkRight
);
1775 _engine_set_credential(engine_t engine
, credential_t cred
, bool shared
)
1777 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
);
1778 CFSetSetValue(engine
->credentials
, cred
);
1780 credential_t sharedCred
= credential_create_with_credential(cred
, true);
1781 CFSetSetValue(engine
->credentials
, sharedCred
);
1782 CFReleaseSafe(sharedCred
);
1787 engine_get_granted_rights(engine_t engine
)
1789 return engine
->grantedRights
;
1792 CFAbsoluteTime
engine_get_time(engine_t engine
)
1797 void engine_destroy_agents(engine_t engine
)
1799 engine
->dismissed
= true;
1801 _cf_dictionary_iterate(engine
->mechanism_agents
, ^bool(CFTypeRef key
__attribute__((__unused__
)), CFTypeRef value
) {
1802 os_log_debug(AUTHD_LOG
, "engine %lld: Destroying %{public}s", engine
->engine_index
, mechanism_get_string((mechanism_t
)key
));
1803 agent_t agent
= (agent_t
)value
;
1804 agent_destroy(agent
);
1810 void engine_interrupt_agent(engine_t engine
)
1812 _cf_dictionary_iterate(engine
->mechanism_agents
, ^bool(CFTypeRef key
__attribute__((__unused__
)), CFTypeRef value
) {
1813 agent_t agent
= (agent_t
)value
;
1814 agent_notify_interrupt(agent
);
1819 CFTypeRef
engine_copy_context(engine_t engine
, auth_items_t source
)
1821 CFTypeRef retval
= NULL
;
1823 process_t proc
= connection_get_process(engine
->conn
);
1825 os_log_error(AUTHD_LOG
, "No client process (engine %lld)", engine
->engine_index
);
1829 uid_t client_uid
= process_get_uid(proc
);
1831 os_log_error(AUTHD_LOG
, "No client UID (engine %lld)", engine
->engine_index
);
1836 const void *data
= auth_items_get_data(source
, AGENT_HINT_SHEET_CONTEXT
, &dataLen
);
1838 CFDataRef externalized
= CFDataCreate(kCFAllocatorDefault
, data
, dataLen
);
1840 os_log_debug(AUTHD_LOG
, "engine %lld: going to get LA context for UID %d", engine
->engine_index
, client_uid
);
1841 retval
= LACreateNewContextWithACMContextInSession(client_uid
, externalized
, NULL
);
1842 CFRelease(externalized
);
1849 bool engine_acquire_sheet_data(engine_t engine
)
1851 if (!auth_items_exist(engine
->context
, "sheet-uid"))
1854 uid_t uid
= auth_items_get_uint(engine
->context
, "sheet-uid");
1856 CFReleaseSafe(engine
->la_context
);
1857 engine
->la_context
= engine_copy_context(engine
, engine
->hints
);
1858 if (engine
->la_context
) {
1859 os_log_debug(AUTHD_LOG
, "engine %lld: Sheet UID %d", engine
->engine_index
, uid
);
1862 // this is not real failure as no LA context in authorization context is very valid scenario
1863 os_log_debug(AUTHD_LOG
, "engine %lld: Failed to get LA context", engine
->engine_index
);