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/AuthorizationPlugin.h> 
  25 #include <LocalAuthentication/LAPublicDefines.h> 
  26 #include <LocalAuthentication/LAPrivateDefines.h> 
  28 #include <coreauthd_spi.h> 
  32 static void _set_process_hints(auth_items_t
, process_t
); 
  33 static void _set_process_immutable_hints(auth_items_t
, process_t
); 
  34 static void _set_auth_token_hints(auth_items_t
, auth_items_t
, auth_token_t
); 
  35 static OSStatus 
_evaluate_user_credential_for_rule(engine_t
, credential_t
, rule_t
, bool, bool, enum Reason 
*); 
  36 static void _engine_set_credential(engine_t
, credential_t
, bool); 
  37 static OSStatus 
_evaluate_rule(engine_t
, rule_t
, bool *); 
  38 static bool _preevaluate_class_rule(engine_t engine
, rule_t rule
); 
  39 static bool _preevaluate_rule(engine_t engine
, rule_t rule
); 
  42     kEngineHintsFlagTemporary 
= (1 << 30) 
  46 #pragma mark engine creation 
  49     __AUTH_BASE_STRUCT_HEADER__
; 
  55     AuthorizationFlags flags
; 
  58     auth_items_t sticky_context
; 
  59     auth_items_t immutable_hints
; 
  61     auth_rights_t grantedRights
; 
  71     credential_t sessionCredential
; 
  72     CFMutableSetRef credentials
; 
  73     CFMutableSetRef effectiveCredentials
; 
  75     CFMutableDictionaryRef mechanism_agents
; 
  77     // set only in engine_authorize 
  78     const char * currentRightName
; // weak ref 
  79     rule_t currentRule
; // weak ref 
  81     rule_t authenticateRule
; 
  87 _engine_finalizer(CFTypeRef value
) 
  89     engine_t engine 
= (engine_t
)value
; 
  91     CFReleaseNull(engine
->mechanism_agents
); 
  92     CFReleaseNull(engine
->conn
); 
  93     CFReleaseNull(engine
->auth
); 
  94     CFReleaseNull(engine
->hints
); 
  95     CFReleaseNull(engine
->context
); 
  96     CFReleaseNull(engine
->immutable_hints
); 
  97     CFReleaseNull(engine
->sticky_context
); 
  98     CFReleaseNull(engine
->grantedRights
); 
  99     CFReleaseNull(engine
->sessionCredential
); 
 100     CFReleaseNull(engine
->credentials
); 
 101     CFReleaseNull(engine
->effectiveCredentials
); 
 102     CFReleaseNull(engine
->authenticateRule
); 
 105 AUTH_TYPE_INSTANCE(engine
, 
 108                    .finalize 
= _engine_finalizer
, 
 111                    .copyFormattingDesc 
= NULL
, 
 112                    .copyDebugDesc 
= NULL
 
 115 static CFTypeID 
engine_get_type_id() { 
 116     static CFTypeID type_id 
= _kCFRuntimeNotATypeID
; 
 117     static dispatch_once_t onceToken
; 
 119     dispatch_once(&onceToken
, ^{ 
 120         type_id 
= _CFRuntimeRegisterClass(&_auth_type_engine
); 
 127 engine_create(connection_t conn
, auth_token_t auth
) 
 129     engine_t engine 
= NULL
; 
 130     require(conn 
!= NULL
, done
); 
 131     require(auth 
!= NULL
, done
); 
 133     engine 
= (engine_t
)_CFRuntimeCreateInstance(kCFAllocatorDefault
, engine_get_type_id(), AUTH_CLASS_SIZE(engine
), NULL
); 
 134     require(engine 
!= NULL
, done
); 
 136     engine
->conn 
= (connection_t
)CFRetain(conn
); 
 137     engine
->proc 
= connection_get_process(conn
); 
 138     engine
->auth 
= (auth_token_t
)CFRetain(auth
); 
 140     engine
->hints 
= auth_items_create(); 
 141     engine
->context 
= auth_items_create(); 
 142     engine
->immutable_hints 
= auth_items_create(); 
 143     engine
->sticky_context 
= auth_items_create(); 
 144     _set_process_hints(engine
->hints
, engine
->proc
); 
 145     _set_process_immutable_hints(engine
->immutable_hints
, engine
->proc
); 
 146         _set_auth_token_hints(engine
->hints
, engine
->immutable_hints
, auth
); 
 148     engine
->grantedRights 
= auth_rights_create(); 
 150     engine
->reason 
= noReason
; 
 152         engine
->preauthorizing 
= false; 
 154         engine
->la_context 
= NULL
; 
 156     engine
->now 
= CFAbsoluteTimeGetCurrent(); 
 158     session_update(auth_token_get_session(engine
->auth
)); 
 159     engine
->sessionCredential 
= credential_create(session_get_uid(auth_token_get_session(engine
->auth
))); 
 160     engine
->credentials 
= CFSetCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeSetCallBacks
); 
 161     engine
->effectiveCredentials 
= CFSetCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeSetCallBacks
); 
 163     session_credentials_iterate(auth_token_get_session(engine
->auth
), ^bool(credential_t cred
) { 
 164         CFSetAddValue(engine
->effectiveCredentials
, cred
); 
 168     auth_token_credentials_iterate(engine
->auth
, ^bool(credential_t cred
) { 
 169         // we added all session credentials already now just add all previously acquired credentials 
 170         if (!credential_get_shared(cred
)) { 
 171             CFSetAddValue(engine
->credentials
, cred
); 
 176     engine
->mechanism_agents 
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
 183 #pragma mark agent hints 
 186 _set_process_hints(auth_items_t hints
, process_t proc
) 
 188     // process information 
 189     RequestorType type 
= bundle
; 
 190     auth_items_set_data(hints
, AGENT_HINT_CLIENT_TYPE
, &type
, sizeof(type
)); 
 191     auth_items_set_int(hints
, AGENT_HINT_CLIENT_PID
, process_get_pid(proc
)); 
 192     auth_items_set_uint(hints
, AGENT_HINT_CLIENT_UID
, process_get_uid(proc
)); 
 196 _set_process_immutable_hints(auth_items_t immutable_hints
, process_t proc
) 
 198     // process information - immutable 
 199     auth_items_set_bool(immutable_hints
, AGENT_HINT_CLIENT_SIGNED
, process_apple_signed(proc
)); 
 200         auth_items_set_bool(immutable_hints
, AGENT_HINT_CLIENT_FROM_APPLE
, process_firstparty_signed(proc
)); 
 204 _set_auth_token_hints(auth_items_t hints
, auth_items_t immutable_hints
, auth_token_t auth
) 
 206     auth_items_set_string(hints
, AGENT_HINT_CLIENT_PATH
, auth_token_get_code_url(auth
)); 
 207     auth_items_set_int(hints
, AGENT_HINT_CREATOR_PID
, auth_token_get_pid(auth
)); 
 208     const audit_info_s 
* info 
= auth_token_get_audit_info(auth
); 
 209     auth_items_set_data(hints
, AGENT_HINT_CREATOR_AUDIT_TOKEN
, &info
->opaqueToken
, sizeof(info
->opaqueToken
)); 
 211         process_t proc 
= process_create(info
, auth_token_get_session(auth
)); 
 213                 auth_items_set_bool(immutable_hints
, AGENT_HINT_CREATOR_SIGNED
, process_apple_signed(proc
)); 
 214                 auth_items_set_bool(immutable_hints
, AGENT_HINT_CREATOR_FROM_APPLE
, process_firstparty_signed(proc
)); 
 220 _set_right_hints(auth_items_t hints
, const char * right
) 
 222    auth_items_set_string(hints
, AGENT_HINT_AUTHORIZE_RIGHT
, right
); 
 226 _set_rule_hints(auth_items_t hints
, rule_t rule
) 
 228     auth_items_set_string(hints
, AGENT_HINT_AUTHORIZE_RULE
, rule_get_name(rule
)); 
 229     const char * group 
= rule_get_group(rule
); 
 230     if (rule_get_class(rule
) == RC_USER 
&& group 
!= NULL
) { 
 231         auth_items_set_string(hints
, AGENT_HINT_REQUIRE_USER_IN_GROUP
, group
); 
 233         auth_items_remove(hints
, AGENT_HINT_REQUIRE_USER_IN_GROUP
); 
 238 _set_localization_hints(authdb_connection_t dbconn
, auth_items_t hints
, rule_t rule
) 
 240     char * key 
= calloc(1u, 128); 
 242     authdb_step(dbconn
, "SELECT lang,value FROM prompts WHERE r_id = ?", ^(sqlite3_stmt 
*stmt
) { 
 243         sqlite3_bind_int64(stmt
, 1, rule_get_id(rule
)); 
 244     }, ^bool(auth_items_t data
) { 
 245         snprintf(key
, 128, "%s%s", kAuthorizationRuleParameterDescription
, auth_items_get_string(data
, "lang")); 
 246         auth_items_set_string(hints
, key
, auth_items_get_string(data
, "value")); 
 247         auth_items_set_flags(hints
, key
, kEngineHintsFlagTemporary
); 
 251     authdb_step(dbconn
, "SELECT lang,value FROM buttons WHERE r_id = ?", ^(sqlite3_stmt 
*stmt
) { 
 252         sqlite3_bind_int64(stmt
, 1, rule_get_id(rule
)); 
 253     }, ^bool(auth_items_t data
) { 
 254         snprintf(key
, 128, "%s%s", kAuthorizationRuleParameterButton
, auth_items_get_string(data
, "lang")); 
 255         auth_items_set_string(hints
, key
, auth_items_get_string(data
, "value")); 
 256         auth_items_set_flags(hints
, key
, kEngineHintsFlagTemporary
); 
 264 _set_session_hints(engine_t engine
, rule_t rule
) 
 266     os_log_debug(AUTHD_LOG
, "engine: ** prepare agent hints for rule %{public}s", rule_get_name(rule
)); 
 267     if (_evaluate_user_credential_for_rule(engine
, engine
->sessionCredential
, rule
, true, true, NULL
) == errAuthorizationSuccess
) { 
 268         const char * tmp 
= credential_get_name(engine
->sessionCredential
); 
 270             auth_items_set_string(engine
->hints
, AGENT_HINT_SUGGESTED_USER
, tmp
); 
 272         tmp 
= credential_get_realname(engine
->sessionCredential
); 
 274             auth_items_set_string(engine
->hints
, AGENT_HINT_SUGGESTED_USER_LONG
, tmp
); 
 277         auth_items_remove(engine
->hints
, AGENT_HINT_SUGGESTED_USER
); 
 278         auth_items_remove(engine
->hints
, AGENT_HINT_SUGGESTED_USER_LONG
); 
 283 #pragma mark right processing 
 286 _evaluate_credential_for_rule(engine_t engine
, credential_t cred
, rule_t rule
, bool ignoreShared
, bool sessionOwner
, enum Reason 
* reason
) 
 288     if (auth_token_least_privileged(engine
->auth
)) { 
 289         if (credential_is_right(cred
) && credential_get_valid(cred
) && _compare_string(engine
->currentRightName
, credential_get_name(cred
))) { 
 291                 if (!rule_get_shared(rule
) && credential_get_shared(cred
)) { 
 292                     os_log_error(AUTHD_LOG
, "engine: - shared right %{public}s (does NOT satisfy rule)", credential_get_name(cred
)); 
 293                     if (reason
) {  *reason 
= unknownReason
; } 
 294                     return errAuthorizationDenied
; 
 298             return errAuthorizationSuccess
; 
 300             if (reason
) {  *reason 
= unknownReason
; } 
 301             return errAuthorizationDenied
; 
 304         return _evaluate_user_credential_for_rule(engine
,cred
,rule
,ignoreShared
,sessionOwner
, reason
); 
 309 _evaluate_user_credential_for_rule(engine_t engine
, credential_t cred
, rule_t rule
, bool ignoreShared
, bool sessionOwner
, enum Reason 
* reason
) 
 311     const char * cred_label 
= sessionOwner 
? "session owner" : "credential"; 
 312     os_log(AUTHD_LOG
, "engine: - validating %{public}s%{public}s %{public}s (%i) for %{public}s", credential_get_shared(cred
) ? "shared " : "", 
 314          credential_get_name(cred
), 
 315          credential_get_uid(cred
), 
 316          rule_get_name(rule
)); 
 318     if (rule_get_class(rule
) != RC_USER
) { 
 319         os_log(AUTHD_LOG
, "engine: - invalid rule class %i (denied)", rule_get_class(rule
)); 
 320         return errAuthorizationDenied
; 
 323     if (credential_get_valid(cred
) != true) { 
 324         os_log(AUTHD_LOG
, "engine: - %{public}s %i invalid (does NOT satisfy rule)", cred_label
, credential_get_uid(cred
)); 
 325         if (reason
) {  *reason 
= invalidPassphrase
; } 
 326         return errAuthorizationDenied
; 
 329     if (engine
->now 
- credential_get_creation_time(cred
) > rule_get_timeout(rule
)) { 
 330         os_log(AUTHD_LOG
, "engine: - %{public}s %i expired '%f > %lli' (does NOT satisfy rule)", cred_label
, credential_get_uid(cred
), 
 331              (engine
->now 
- credential_get_creation_time(cred
)), rule_get_timeout(rule
)); 
 332         if (reason
) {  *reason 
= unknownReason
; } 
 333         return errAuthorizationDenied
; 
 338         if (!rule_get_shared(rule
) && credential_get_shared(cred
)) { 
 339             os_log(AUTHD_LOG
, "engine: - shared %{public}s %i (does NOT satisfy rule)", cred_label
, credential_get_uid(cred
)); 
 340             if (reason
) {  *reason 
= unknownReason
; } 
 341             return errAuthorizationDenied
; 
 345     if (credential_get_uid(cred
) == 0) { 
 346         os_log(AUTHD_LOG
, "engine: - %{public}s %i has uid 0 (does satisfy rule)", cred_label
, credential_get_uid(cred
)); 
 347         return errAuthorizationSuccess
; 
 350     if (rule_get_session_owner(rule
)) { 
 351         if (credential_get_uid(cred
) == session_get_uid(auth_token_get_session(engine
->auth
))) { 
 352             os_log(AUTHD_LOG
, "engine: - %{public}s %i is session owner (does satisfy rule)", cred_label
, credential_get_uid(cred
)); 
 353             return errAuthorizationSuccess
; 
 357     if (rule_get_group(rule
) != NULL
) { 
 360             // This allows testing a group modifier without prompting the user 
 361             // When (authenticate-user = false) we are just testing the creator uid. 
 362             // If a group modifier is enabled (RuleFlagEntitledAndGroup | RuleFlagVPNEntitledAndGroup) 
 363             // we want to skip the creator uid group check. 
 364             // group modifiers are checked early during the evaluation in _check_entitlement_for_rule  
 365             if (!rule_get_authenticate_user(rule
)) { 
 366                 if (rule_check_flags(rule
, RuleFlagEntitledAndGroup 
| RuleFlagVPNEntitledAndGroup
)) { 
 371             if (credential_check_membership(cred
, rule_get_group(rule
))) { 
 372                 os_log(AUTHD_LOG
, "engine: - %{public}s %i is member of group %{public}s (does satisfy rule)", cred_label
, credential_get_uid(cred
), rule_get_group(rule
)); 
 373                 return errAuthorizationSuccess
; 
 375                 if (reason
) {  *reason 
= userNotInGroup
; } 
 378     } else if (rule_get_session_owner(rule
)) { // rule asks only if user is the session owner 
 379         if (reason
) {  *reason 
= unacceptableUser
; } 
 382         os_log(AUTHD_LOG
, "engine: - %{public}s %i (does NOT satisfy rule), reason %d", cred_label
, credential_get_uid(cred
), reason 
? *reason 
: -1); 
 383     return errAuthorizationDenied
; 
 387 _get_agent(engine_t engine
, mechanism_t mech
, bool create
, bool firstMech
) 
 389     agent_t agent 
= (agent_t
)CFDictionaryGetValue(engine
->mechanism_agents
, mech
); 
 390     if (create 
&& !agent
) { 
 391         agent 
= agent_create(engine
, mech
, engine
->auth
, engine
->proc
, firstMech
); 
 393             CFDictionaryAddValue(engine
->mechanism_agents
, mech
, agent
); 
 394             CFReleaseSafe(agent
); 
 401 _evaluate_builtin_mechanism(engine_t engine
, mechanism_t mech
) 
 403     uint64_t result 
= kAuthorizationResultDeny
; 
 405     switch (mechanism_get_type(mech
)) { 
 406         case kMechanismTypeEntitled
: 
 407             if (auth_token_has_entitlement_for_right(engine
->auth
, engine
->currentRightName
)) { 
 408                 result 
= kAuthorizationResultAllow
; 
 420 _extract_password_from_la(engine_t engine
, CFTypeRef la_context
) 
 423         // try to retrieve secret 
 424         CFDataRef passdata 
= LACopyCredential(la_context
, kLACredentialTypeExtractablePasscode
, NULL
); 
 426                 if (CFDataGetBytePtr(passdata
)) { 
 427                         auth_items_set_data(engine
->context
, kAuthorizationEnvironmentPassword
, CFDataGetBytePtr(passdata
), CFDataGetLength(passdata
)); 
 430                         auth_items_set_data(engine
->context
, kAuthorizationEnvironmentPassword
, &nulChar
, 1); 
 438 _evaluate_mechanisms(engine_t engine
, CFArrayRef mechanisms
) 
 440     uint64_t result 
= kAuthorizationResultAllow
; 
 441     ccaudit_t ccaudit 
= ccaudit_create(engine
->proc
, engine
->auth
, AUE_ssauthmech
); 
 442     auth_items_t context 
= auth_items_create(); 
 443     auth_items_t hints 
= auth_items_create(); 
 445     auth_items_copy(context
, engine
->context
); 
 446     auth_items_copy(hints
, engine
->hints
); 
 447     auth_items_copy(context
, engine
->sticky_context
); 
 449         CFDictionaryRef la_result 
= NULL
; 
 451     CFIndex count 
= CFArrayGetCount(mechanisms
); 
 452     for (CFIndex i 
= 0; i 
< count
; i
++) { 
 453         mechanism_t mech 
= (mechanism_t
)CFArrayGetValueAtIndex(mechanisms
, i
); 
 455         if (mechanism_get_type(mech
)) { 
 456             os_log_debug(AUTHD_LOG
, "engine: running builtin mechanism %{public}s (%li of %li)", mechanism_get_string(mech
), i
+1, count
); 
 457             result 
= _evaluate_builtin_mechanism(engine
, mech
); 
 459                         bool sheet_variant_used 
= false; 
 460                         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                                 // sheet variant in progress 
 478                                 if (strcmp(mechanism_get_string(mech
), "builtin:authenticate") == 0) { 
 479                                         // instead of running SecurityAgent, get uid from the authorization 
 480                                         os_log(AUTHD_LOG
, "engine: running builtin sheet authenticate"); 
 482                                                 result 
= kAuthorizationResultDeny
; // no la_result => was evaluate did not pass 
 484                                         sheet_variant_used 
= true; 
 485                                 } else if (strcmp(mechanism_get_string(mech
), "builtin:authenticate,privileged") == 0) { 
 486                                         os_log(AUTHD_LOG
, "engine: running builtin sheet privileged authenticate"); 
 488                                                 result 
= kAuthorizationResultDeny
; // no la_result => was evaluate did not pass 
 490                                                 if (!_extract_password_from_la(engine
, engine
->la_context
)) { 
 491                                                         os_log_debug(AUTHD_LOG
, "engine: cannot extract cred"); 
 494                                         sheet_variant_used 
= true; 
 498                         if (!sheet_variant_used
) { 
 499                                 agent_t agent 
= _get_agent(engine
, mech
, true, i 
== 0); 
 500                                 require_action(agent 
!= NULL
, done
, result 
= kAuthorizationResultUndefined
; os_log_error(AUTHD_LOG
, "engine: error creating mechanism agent")); 
 502                                 // check if any agent has been interrupted (it necessary if interrupt will come during creation) 
 505                                 for (j 
= 0; j 
< i
; j
++) { 
 506                                         agent1 
= _get_agent(engine
, (mechanism_t
)CFArrayGetValueAtIndex(mechanisms
, j
), false, j 
== 0); 
 507                                         if(agent1 
&& agent_get_state(agent1
) == interrupting
) { 
 512                                         os_log(AUTHD_LOG
, "engine: mechanisms interrupted"); 
 514                                         asprintf(&buf
, "evaluation interrupted by %s; restarting evaluation there", mechanism_get_string(agent_get_mechanism(agent1
))); 
 515                                         ccaudit_log_mechanism(ccaudit
, engine
->currentRightName
, mechanism_get_string(agent_get_mechanism(agent1
)), kAuthorizationResultAllow
, buf
); 
 517                                         ccaudit_log_mechanism(ccaudit
, engine
->currentRightName
, mechanism_get_string(mech
), kAuthorizationResultAllow
, NULL
); 
 518                                         const char * token_name 
= auth_items_get_string(hints
, AGENT_HINT_TOKEN_NAME
); 
 519                                         if (token_name 
&& strlen(token_name
) == 0) { 
 520                                                 auth_items_remove(hints
, AGENT_HINT_TOKEN_NAME
); 
 522                                         auth_items_copy(context
, agent_get_context(agent1
)); 
 523                                         auth_items_copy(hints
, agent_get_hints(agent1
)); 
 530                                 os_log(AUTHD_LOG
, "engine: running mechanism %{public}s (%li of %li)", mechanism_get_string(agent_get_mechanism(agent
)), i
+1, count
); 
 532                                 result 
= agent_run(agent
, hints
, context
, engine
->immutable_hints
); 
 534                                 auth_items_copy(context
, agent_get_context(agent
)); 
 535                                 auth_items_copy(hints
, agent_get_hints(agent
)); 
 537                                 bool interrupted 
= false; 
 538                                 for (CFIndex i2 
= 0; i2 
!= i
; i2
++) { 
 539                                         agent_t agent2 
= _get_agent(engine
, (mechanism_t
)CFArrayGetValueAtIndex(mechanisms
, i2
), false, i 
== 0); 
 540                                         if (agent2 
&& agent_get_state(agent2
) == interrupting
) { 
 541                                                 agent_deactivate(agent
); 
 545                                                 asprintf(&buf
, "evaluation interrupted by %s; restarting evaluation there", mechanism_get_string(agent_get_mechanism(agent2
))); 
 546                                                 ccaudit_log_mechanism(ccaudit
, engine
->currentRightName
, mechanism_get_string(agent_get_mechanism(agent2
)), kAuthorizationResultAllow
, buf
); 
 548                                                 auth_items_copy(context
, agent_get_context(agent2
)); 
 549                                                 auth_items_copy(hints
, agent_get_hints(agent2
)); 
 554                                 // Empty token name means that token doesn't exist (e.g. SC was removed). 
 555                                 // Remove empty token name from hints for UI drawing logic. 
 556                                 const char * token_name 
= auth_items_get_string(hints
, AGENT_HINT_TOKEN_NAME
); 
 557                                 if (token_name 
&& strlen(token_name
) == 0) { 
 558                                         auth_items_remove(hints
, AGENT_HINT_TOKEN_NAME
); 
 562                                         os_log(AUTHD_LOG
, "engine: mechanisms interrupted"); 
 563                                         enum Reason reason 
= worldChanged
; 
 564                                         auth_items_set_data(hints
, AGENT_HINT_RETRY_REASON
, &reason
, sizeof(reason
)); 
 565                                         result 
= kAuthorizationResultAllow
; 
 566                                         _cf_dictionary_iterate(engine
->mechanism_agents
, ^bool(CFTypeRef key 
__attribute__((__unused__
)), CFTypeRef value
) { 
 567                                                 agent_t tempagent 
= (agent_t
)value
; 
 568                                                 agent_clear_interrupt(tempagent
); 
 575         if (result 
== kAuthorizationResultAllow
) { 
 576             ccaudit_log_mechanism(ccaudit
, engine
->currentRightName
, mechanism_get_string(mech
), kAuthorizationResultAllow
, NULL
); 
 578             ccaudit_log_mechanism(ccaudit
, engine
->currentRightName
, mechanism_get_string(mech
), (uint32_t)result
, NULL
); 
 584     if ((result 
== kAuthorizationResultUserCanceled
) || (result 
== kAuthorizationResultAllow
)) { 
 585         // only make non-sticky context values available externally 
 586         auth_items_set_flags(context
, kAuthorizationEnvironmentPassword
, kAuthorizationContextFlagVolatile
); 
 587                 // <rdar://problem/16275827> Takauthorizationenvironmentusername should always be extractable 
 588         auth_items_set_flags(context
, kAuthorizationEnvironmentUsername
, kAuthorizationContextFlagExtractable
); 
 589         auth_items_copy_with_flags(engine
->context
, context
, kAuthorizationContextFlagExtractable 
| kAuthorizationContextFlagVolatile
); 
 590     } else if (result 
== kAuthorizationResultDeny
) { 
 591         auth_items_clear(engine
->sticky_context
); 
 592         // save off sticky values in context 
 593         auth_items_copy_with_flags(engine
->sticky_context
, context
, kAuthorizationContextFlagSticky
); 
 596     CFReleaseSafe(ccaudit
); 
 597     CFReleaseSafe(context
); 
 598     CFReleaseSafe(hints
); 
 599         CFReleaseSafe(la_result
); 
 603         case kAuthorizationResultDeny
: 
 604             return errAuthorizationDenied
; 
 605         case kAuthorizationResultUserCanceled
: 
 606             return errAuthorizationCanceled
; 
 607         case kAuthorizationResultAllow
: 
 608             return errAuthorizationSuccess
; 
 609         case kAuthorizationResultUndefined
: 
 610             return errAuthorizationInternal
; 
 613             os_log_error(AUTHD_LOG
, "engine: unexpected error result"); 
 614             return errAuthorizationInternal
; 
 620 _evaluate_authentication(engine_t engine
, rule_t rule
) 
 622     OSStatus status 
= errAuthorizationDenied
; 
 623     ccaudit_t ccaudit 
= ccaudit_create(engine
->proc
, engine
->auth
, AUE_ssauthint
); 
 624     os_log_debug(AUTHD_LOG
, "engine: evaluate authentication"); 
 625     _set_rule_hints(engine
->hints
, rule
); 
 626     _set_session_hints(engine
, rule
); 
 628     CFArrayRef mechanisms 
= rule_get_mechanisms(rule
); 
 629     if (!(CFArrayGetCount(mechanisms
) > 0)) { 
 630         mechanisms 
= rule_get_mechanisms(engine
->authenticateRule
); 
 632     require_action(CFArrayGetCount(mechanisms
) > 0, done
, os_log_debug(AUTHD_LOG
, "engine: error no mechanisms found")); 
 634     int64_t ruleTries 
= rule_get_tries(rule
); 
 635     for (engine
->tries 
= 0; engine
->tries 
< ruleTries
; engine
->tries
++) { 
 637         auth_items_set_data(engine
->hints
, AGENT_HINT_RETRY_REASON
, &engine
->reason
, sizeof(engine
->reason
)); 
 638         auth_items_set_int(engine
->hints
, AGENT_HINT_TRIES
, engine
->tries
); 
 639         status 
= _evaluate_mechanisms(engine
, mechanisms
); 
 641         os_log_debug(AUTHD_LOG
, "engine: evaluate mechanisms result %d", (int)status
); 
 643         // successfully ran mechanisms to obtain credential 
 644         if (status 
== errAuthorizationSuccess
) { 
 645             // deny is the default 
 646             status 
= errAuthorizationDenied
; 
 648             credential_t newCred 
= NULL
; 
 649             if (auth_items_exist(engine
->context
, "uid")) { 
 650                 newCred 
= credential_create(auth_items_get_uint(engine
->context
, "uid")); 
 652                 os_log_error(AUTHD_LOG
, "engine: mechanism failed to return a valid uid"); 
 653                                 if (engine
->la_context
) { 
 654                                         // sheet failed so remove sheet reference and next time, standard dialog will be displayed 
 655                                         CFReleaseNull(engine
->la_context
); 
 660                 if (credential_get_valid(newCred
)) { 
 661                     os_log(AUTHD_LOG
, "UID %u authenticated as user %{public}s (UID %u) for right '%{public}s'", auth_token_get_uid(engine
->auth
), credential_get_name(newCred
), credential_get_uid(newCred
), engine
->currentRightName
); 
 662                     ccaudit_log_success(ccaudit
, newCred
, engine
->currentRightName
); 
 664                     os_log(AUTHD_LOG
, "UID %u failed to authenticate as user '%{public}s' for right '%{public}s'", auth_token_get_uid(engine
->auth
), auth_items_get_string(engine
->context
, "username"), engine
->currentRightName
); 
 665                     ccaudit_log_failure(ccaudit
, auth_items_get_string(engine
->context
, "username"), engine
->currentRightName
); 
 668                 status 
= _evaluate_user_credential_for_rule(engine
, newCred
, rule
, true, false, &engine
->reason
); 
 670                 if (status 
== errAuthorizationSuccess
) { 
 671                     _engine_set_credential(engine
, newCred
, rule_get_shared(rule
)); 
 672                     CFReleaseSafe(newCred
); 
 674                     if (auth_token_least_privileged(engine
->auth
)) { 
 675                         credential_t rightCred 
= credential_create_with_right(engine
->currentRightName
); 
 676                         _engine_set_credential(engine
, rightCred
, rule_get_shared(rule
)); 
 677                         CFReleaseSafe(rightCred
); 
 680                     session_t session 
= auth_token_get_session(engine
->auth
); 
 681                     if (credential_get_uid(newCred
) == session_get_uid(session
)) { 
 682                         os_log_debug(AUTHD_LOG
, "engine: authenticated as the session owner"); 
 683                         session_set_attributes(auth_token_get_session(engine
->auth
), AU_SESSION_FLAG_HAS_AUTHENTICATED
); 
 688                                         os_log_error(AUTHD_LOG
, "engine: user credential for rule failed (%d)", (int)status
); 
 691                 CFReleaseSafe(newCred
); 
 694         } else if (status 
== errAuthorizationCanceled 
|| status 
== errAuthorizationInternal
) { 
 695                         os_log_error(AUTHD_LOG
, "engine: evaluate cancelled or failed %d", (int)status
); 
 697         } else if (status 
== errAuthorizationDenied
) { 
 698                         os_log_error(AUTHD_LOG
, "engine: evaluate denied"); 
 699                         engine
->reason 
= invalidPassphrase
; 
 700                         if (engine
->la_context
) { 
 701                                 // for sheet authorizations do not retry with sheet as there is no new sheet UI 
 702                                 CFReleaseNull(engine
->la_context
); 
 703                                 auth_items_remove(engine
->context
, AGENT_CONTEXT_UID
); 
 708     if (engine
->tries 
== ruleTries
) { 
 709         engine
->reason 
= tooManyTries
; 
 710         auth_items_set_data(engine
->hints
, AGENT_HINT_RETRY_REASON
, &engine
->reason
, sizeof(engine
->reason
)); 
 711         auth_items_set_int(engine
->hints
, AGENT_HINT_TRIES
, engine
->tries
); 
 712                 // TODO: determine why evaluate_mechanism is run once again and possibly remove this call 
 713         _evaluate_mechanisms(engine
, mechanisms
); 
 714         ccaudit_log(ccaudit
, engine
->currentRightName
, NULL
, 1113); 
 718     CFReleaseSafe(ccaudit
); 
 724 _check_entitlement_for_rule(engine_t engine
, rule_t rule
) 
 726     bool entitled 
= false; 
 727     CFTypeRef value 
= NULL
; 
 729     if (rule_check_flags(rule
, RuleFlagEntitledAndGroup
)) { 
 730         if (auth_token_has_entitlement_for_right(engine
->auth
, engine
->currentRightName
)) { 
 731             if (credential_check_membership(auth_token_get_credential(engine
->auth
), rule_get_group(rule
))) { 
 732                 os_log_debug(AUTHD_LOG
, "engine: creator of authorization has entitlement for right %{public}s and is member of group '%{public}s'", engine
->currentRightName
, rule_get_group(rule
)); 
 739     if (rule_check_flags(rule
, RuleFlagVPNEntitledAndGroup
)) { 
 740         // com.apple.networking.vpn.configuration is an array we only check for it's existence 
 741         value 
= auth_token_copy_entitlement_value(engine
->auth
, "com.apple.networking.vpn.configuration"); 
 743             if (credential_check_membership(auth_token_get_credential(engine
->auth
), rule_get_group(rule
))) { 
 744                 os_log_debug(AUTHD_LOG
, "engine: creator of authorization has VPN entitlement and is member of group '%{public}s'", rule_get_group(rule
)); 
 752     CFReleaseSafe(value
); 
 757 _evaluate_class_user(engine_t engine
, rule_t rule
) 
 759     __block OSStatus status 
= errAuthorizationDenied
; 
 761     if (_check_entitlement_for_rule(engine
,rule
)) { 
 762         return errAuthorizationSuccess
; 
 765     if (rule_get_allow_root(rule
) && auth_token_get_uid(engine
->auth
) == 0) { 
 766         os_log_debug(AUTHD_LOG
, "engine: creator of authorization has uid == 0 granting right %{public}s", engine
->currentRightName
); 
 767         return errAuthorizationSuccess
; 
 770     if (!rule_get_authenticate_user(rule
)) { 
 771         status 
= _evaluate_user_credential_for_rule(engine
, engine
->sessionCredential
, rule
, true, true, NULL
); 
 773         if (status 
== errAuthorizationSuccess
) { 
 774             return errAuthorizationSuccess
; 
 777         return errAuthorizationDenied
; 
 780     // First -- check all the credentials we have either acquired or currently have 
 781     _cf_set_iterate(engine
->credentials
, ^bool(CFTypeRef value
) { 
 782         credential_t cred 
= (credential_t
)value
; 
 783         // Passed-in user credentials are allowed for least-privileged mode 
 784         if (auth_token_least_privileged(engine
->auth
) && !credential_is_right(cred
) && credential_get_valid(cred
)) { 
 785             status 
= _evaluate_user_credential_for_rule(engine
, cred
, rule
, false, false, NULL
); 
 786             if (errAuthorizationSuccess 
== status
) { 
 787                 credential_t rightCred 
= credential_create_with_right(engine
->currentRightName
); 
 788                 _engine_set_credential(engine
,rightCred
,rule_get_shared(rule
)); 
 789                 CFReleaseSafe(rightCred
); 
 790                 return false; // exit loop 
 794         status 
= _evaluate_credential_for_rule(engine
, cred
, rule
, false, false, NULL
); 
 795         if (status 
== errAuthorizationSuccess
) { 
 796             return false; // exit loop 
 801     if (status 
== errAuthorizationSuccess
) { 
 805     // Second -- go through the credentials associated to the authorization token session/auth token 
 806     _cf_set_iterate(engine
->effectiveCredentials
, ^bool(CFTypeRef value
) { 
 807         credential_t cred 
= (credential_t
)value
; 
 808         status 
= _evaluate_credential_for_rule(engine
, cred
, rule
, false, false, NULL
); 
 809         if (status 
== errAuthorizationSuccess
) { 
 810             // Add the credential we used to the output set. 
 811             _engine_set_credential(engine
, cred
, false); 
 812             return false; // exit loop 
 817     if (status 
== errAuthorizationSuccess
) { 
 821     // Finally - we didn't find a credential. Obtain a new credential if our flags let us do so. 
 822     if (!(engine
->flags 
& kAuthorizationFlagExtendRights
)) { 
 823         os_log_error(AUTHD_LOG
, "engine: authorization denied (kAuthorizationFlagExtendRights not set)"); 
 824         return errAuthorizationDenied
; 
 827     // authorization that timeout immediately cannot be preauthorized 
 828     if (engine
->flags 
& kAuthorizationFlagPreAuthorize 
&& rule_get_timeout(rule
) == 0) { 
 829         return errAuthorizationSuccess
; 
 832         if (!engine
->preauthorizing
) { 
 833                 if (!(engine
->flags 
& kAuthorizationFlagInteractionAllowed
)) { 
 834                         os_log_error(AUTHD_LOG
, "engine: Interaction not allowed (kAuthorizationFlagInteractionAllowed not set)"); 
 835                         return errAuthorizationInteractionNotAllowed
; 
 838                 if (!(session_get_attributes(auth_token_get_session(engine
->auth
)) & AU_SESSION_FLAG_HAS_GRAPHIC_ACCESS
)) { 
 839                         os_log_error(AUTHD_LOG
, "engine: Interaction not allowed (session has no ui access)"); 
 840                         return errAuthorizationInteractionNotAllowed
; 
 843                 if (server_in_dark_wake()) { 
 844                         os_log_error(AUTHD_LOG
, "engine: authorization denied (DW)"); 
 845                         return errAuthorizationDenied
; 
 849         return _evaluate_authentication(engine
, rule
); 
 853 _evaluate_class_rule(engine_t engine
, rule_t rule
, bool *save_pwd
) 
 855     __block OSStatus status 
= errAuthorizationDenied
; 
 856     int64_t kofn 
= rule_get_kofn(rule
); 
 858     uint32_t total 
= (uint32_t)rule_get_delegates_count(rule
); 
 859     __block 
uint32_t success_count 
= 0; 
 860     __block 
uint32_t count 
= 0; 
 861     os_log_debug(AUTHD_LOG
, "engine: ** rule %{public}s has %zi delegates kofn = %lli",rule_get_name(rule
), total
, kofn
); 
 862     rule_delegates_iterator(rule
, ^bool(rule_t delegate
) { 
 865         if (kofn 
!= 0 && success_count 
== kofn
) { 
 866             status 
= errAuthorizationSuccess
; 
 870         os_log_debug(AUTHD_LOG
, "engine: * evaluate rule %{public}s (%i)", rule_get_name(delegate
), count
); 
 871         status 
= _evaluate_rule(engine
, delegate
, save_pwd
); 
 873         // if status is cancel/internal error abort 
 874                 if ((status 
== errAuthorizationCanceled
) || (status 
== errAuthorizationInternal
)) 
 877         if (status 
!= errAuthorizationSuccess
) { 
 879                 // if remaining is less than required abort 
 880                 if ((total 
- count
) < (kofn 
- success_count
)) { 
 881                     os_log_debug(AUTHD_LOG
, "engine: rule evaluation remaining: %i, required: %lli", (total 
- count
), (kofn 
- success_count
)); 
 897 _preevaluate_class_rule(engine_t engine
, rule_t rule
) 
 899         os_log_debug(AUTHD_LOG
, "engine: _preevaluate_class_rule %{public}s", rule_get_name(rule
)); 
 901         __block 
bool password_only 
= false; 
 902         rule_delegates_iterator(rule
, ^bool(rule_t delegate
) { 
 903                 if (_preevaluate_rule(engine
, delegate
)) { 
 904                                 password_only 
= true; 
 910         return password_only
; 
 914 _evaluate_class_mechanism(engine_t engine
, rule_t rule
) 
 916     OSStatus status 
= errAuthorizationDenied
; 
 917     CFArrayRef mechanisms 
= NULL
; 
 919     require_action(rule_get_mechanisms_count(rule
) > 0, done
, status 
= errAuthorizationSuccess
; os_log_error(AUTHD_LOG
, "engine: no mechanisms specified")); 
 921     mechanisms 
= rule_get_mechanisms(rule
); 
 923     if (server_in_dark_wake()) { 
 924         CFIndex count 
= CFArrayGetCount(mechanisms
); 
 925         for (CFIndex i 
= 0; i 
< count
; i
++) { 
 926             if (!mechanism_is_privileged((mechanism_t
)CFArrayGetValueAtIndex(mechanisms
, i
))) { 
 927                 os_log_error(AUTHD_LOG
, "engine: authorization denied (in DW)"); 
 933     int64_t ruleTries 
= rule_get_tries(rule
); 
 936         auth_items_set_data(engine
->hints
, AGENT_HINT_RETRY_REASON
, &engine
->reason
, sizeof(engine
->reason
)); 
 937         auth_items_set_int(engine
->hints
, AGENT_HINT_TRIES
, engine
->tries
); 
 939         status 
= _evaluate_mechanisms(engine
, mechanisms
); 
 940         os_log_debug(AUTHD_LOG
, "engine: evaluate mechanisms result %d", (int)status
); 
 942                 if (status 
== errAuthorizationSuccess
) { 
 943                         credential_t newCred 
= NULL
; 
 944                         if (auth_items_exist(engine
->context
, "uid")) { 
 945                                 newCred 
= credential_create(auth_items_get_uint(engine
->context
, "uid")); 
 947                                 os_log(AUTHD_LOG
, "engine: mechanism did not return a uid"); 
 951                                 _engine_set_credential(engine
, newCred
, rule_get_shared(rule
)); 
 953                                 if (auth_token_least_privileged(engine
->auth
)) { 
 954                                         credential_t rightCred 
= credential_create_with_right(engine
->currentRightName
); 
 955                                         _engine_set_credential(engine
, rightCred
, rule_get_shared(rule
)); 
 956                                         CFReleaseSafe(rightCred
); 
 959                                 if (strcmp(engine
->currentRightName
, "system.login.console") == 0 && !auth_items_exist(engine
->context
, AGENT_CONTEXT_AUTO_LOGIN
)) { 
 960                                         session_set_attributes(auth_token_get_session(engine
->auth
), AU_SESSION_FLAG_HAS_AUTHENTICATED
); 
 963                                 CFReleaseSafe(newCred
); 
 969     } while ( (status 
== errAuthorizationDenied
) // only if we have an expected faulure we continue 
 970              && ((ruleTries 
== 0) || ((ruleTries 
> 0) && engine
->tries 
< ruleTries
))); // ruleTries == 0 means we try forever 
 971                                                                                        // ruleTires > 0 means we try upto ruleTries times 
 976 // TODO: Remove when all clients have adopted entitlement 
 978 enforced_entitlement(void) 
 980         bool enforced_enabled 
= false; 
 981         //sudo defaults write /Library/Preferences/com.apple.authd enforceEntitlement -bool true 
 982         CFTypeRef enforce 
= (CFNumberRef
)CFPreferencesCopyValue(CFSTR("enforceEntitlement"), CFSTR(SECURITY_AUTH_NAME
), kCFPreferencesAnyUser
, kCFPreferencesCurrentHost
); 
 983         if (enforce 
&& CFGetTypeID(enforce
) == CFBooleanGetTypeID()) { 
 984                 enforced_enabled 
= CFBooleanGetValue((CFBooleanRef
)enforce
); 
 985                 os_log_debug(AUTHD_LOG
, "enforceEntitlement for extract password: %{public}s", enforced_enabled 
? "enabled" : "disabled"); 
 987         CFReleaseSafe(enforce
); 
 989         return enforced_enabled
; 
 993 _evaluate_rule(engine_t engine
, rule_t rule
, bool *save_pwd
) 
 995     if (rule_check_flags(rule
, RuleFlagEntitled
)) { 
 996         if (auth_token_has_entitlement_for_right(engine
->auth
, engine
->currentRightName
)) { 
 997             os_log_debug(AUTHD_LOG
, "engine: rule allow, creator of authorization has entitlement for right %{public}s", engine
->currentRightName
); 
 998             return errAuthorizationSuccess
; 
1002         // check apple signature also for every sheet authorization + disable this check for debug builds 
1003     if (engine
->la_context 
|| rule_check_flags(rule
, RuleFlagRequireAppleSigned
)) { 
1004         if (!auth_token_apple_signed(engine
->auth
)) { 
1006             os_log_error(AUTHD_LOG
, "engine: rule deny, creator of authorization is not signed by Apple"); 
1007             return errAuthorizationDenied
; 
1009                         os_log_debug(AUTHD_LOG
, "engine: in release mode, this rule would be denied because creator of authorization is not signed by Apple"); 
1014         if (rule_get_extract_password(rule
)) { 
1015                 // check if process is entitled to extract password 
1016                 CFTypeRef extract_password_entitlement 
= auth_token_copy_entitlement_value(engine
->auth
, "com.apple.authorization.extract-password"); 
1017                 if (extract_password_entitlement 
&& (CFGetTypeID(extract_password_entitlement
) == CFBooleanGetTypeID()) && extract_password_entitlement 
== kCFBooleanTrue
) { 
1019                         os_log_debug(AUTHD_LOG
, "engine: authorization allowed to extract password"); 
1021                         os_log_debug(AUTHD_LOG
, "engine: authorization NOT allowed to extract password"); 
1023                 CFReleaseSafe(extract_password_entitlement
); 
1026         // TODO: Remove when all clients have adopted entitlement 
1027         if (!enforced_entitlement()) { 
1028                 *save_pwd 
|= rule_get_extract_password(rule
); 
1031         switch (rule_get_class(rule
)) { 
1033             os_log(AUTHD_LOG
, "engine: rule set to allow"); 
1034             return errAuthorizationSuccess
; 
1036             os_log(AUTHD_LOG
, "engine: rule set to deny"); 
1037             return errAuthorizationDenied
; 
1039             return _evaluate_class_user(engine
, rule
); 
1041             return _evaluate_class_rule(engine
, rule
, save_pwd
); 
1043             return _evaluate_class_mechanism(engine
, rule
); 
1045             os_log_error(AUTHD_LOG
, "engine: invalid class for rule or rule not found: %{public}s", rule_get_name(rule
)); 
1046             return errAuthorizationInternal
; 
1050 // returns true if this rule or its children contain RC_USER rule with password_only==true 
1052 _preevaluate_rule(engine_t engine
, rule_t rule
) 
1054         os_log_debug(AUTHD_LOG
, "engine: _preevaluate_rule %{public}s", rule_get_name(rule
)); 
1056         switch (rule_get_class(rule
)) { 
1061                         return rule_get_password_only(rule
); 
1063                         return _preevaluate_class_rule(engine
, rule
); 
1072 _find_rule(engine_t engine
, authdb_connection_t dbconn
, const char * string
) 
1075     size_t sLen 
= strlen(string
); 
1077     char * buf 
= calloc(1u, sLen 
+ 1); 
1078     strlcpy(buf
, string
, sLen 
+ 1); 
1079     char * ptr 
= buf 
+ sLen
; 
1080     __block 
int64_t count 
= 0; 
1085         authdb_step(dbconn
, "SELECT COUNT(name) AS cnt FROM rules WHERE name = ? AND type = 1", 
1086         ^(sqlite3_stmt 
*stmt
) { 
1087             sqlite3_bind_text(stmt
, 1, buf
, -1, NULL
); 
1088         }, ^bool(auth_items_t data
) { 
1089             count 
= auth_items_get_int64(data
, "cnt"); 
1094             r 
= rule_create_with_string(buf
, dbconn
); 
1098         // if buf ends with a . and we didn't find a rule remove . 
1102         // find any remaining . and truncate the string 
1103         ptr 
= strrchr(buf
, '.'); 
1114     // set default if we didn't find a rule 
1116         r 
= rule_create_with_string("", dbconn
); 
1117         if (rule_get_id(r
) == 0) { 
1119             os_log_error(AUTHD_LOG
, "engine: default rule lookup error (missing), using builtin defaults"); 
1120             r 
= rule_create_default(); 
1126 static void _parse_environment(engine_t engine
, auth_items_t environment
) 
1128     require(environment 
!= NULL
, done
); 
1131     os_log_debug(AUTHD_LOG
, "engine: Dumping Environment: %@", environment
); 
1134     // Check if a credential was passed into the environment and we were asked to extend the rights 
1135     if (engine
->flags 
& kAuthorizationFlagExtendRights
) { 
1136         const char * user 
= auth_items_get_string(environment
, kAuthorizationEnvironmentUsername
); 
1137         const char * pass 
= auth_items_get_string(environment
, kAuthorizationEnvironmentPassword
); 
1138                 const bool password_was_used 
= auth_items_get_string(environment
, AGENT_CONTEXT_AP_PAM_SERVICE_NAME
) == nil
; // AGENT_CONTEXT_AP_PAM_SERVICE_NAME in the context means alternative PAM was used 
1139                 require(password_was_used 
== true, done
); 
1141         bool shared 
= auth_items_exist(environment
, kAuthorizationEnvironmentShared
); 
1142         require_action(user 
!= NULL
, done
, os_log_debug(AUTHD_LOG
, "engine: user not used password")); 
1144         struct passwd 
*pw 
= getpwnam(user
); 
1145         require_action(pw 
!= NULL
, done
, os_log_error(AUTHD_LOG
, "engine: user not found %{public}s", user
)); 
1147         int checkpw_status 
= checkpw_internal(pw
, pass 
? pass 
: ""); 
1148         require_action(checkpw_status 
== CHECKPW_SUCCESS
, done
, os_log_error(AUTHD_LOG
, "engine: checkpw() returned %d; failed to authenticate user %{public}s (uid %u).", checkpw_status
, pw
->pw_name
, pw
->pw_uid
)); 
1150         credential_t cred 
= credential_create(pw
->pw_uid
); 
1151         if (credential_get_valid(cred
)) { 
1152             os_log(AUTHD_LOG
, "engine: checkpw() succeeded, creating credential for user %{public}s", user
); 
1153             _engine_set_credential(engine
, cred
, shared
); 
1155             auth_items_set_string(engine
->context
, kAuthorizationEnvironmentUsername
, user
); 
1156             auth_items_set_string(engine
->context
, kAuthorizationEnvironmentPassword
, pass 
? pass 
: ""); 
1158         CFReleaseSafe(cred
); 
1166 static bool _verify_sandbox(engine_t engine
, const char * right
) 
1168     pid_t pid 
= process_get_pid(engine
->proc
); 
1169     if (sandbox_check(pid
, "authorization-right-obtain", SANDBOX_FILTER_RIGHT_NAME
, right
)) { 
1170         os_log_error(AUTHD_LOG
, "Sandbox denied authorizing right '%{public}s' by client '%{public}s' [%d]", right
, process_get_code_url(engine
->proc
), pid
); 
1174     pid 
= auth_token_get_pid(engine
->auth
); 
1175     if (auth_token_get_sandboxed(engine
->auth
) && sandbox_check_by_audit_token(auth_token_get_audit_info(engine
->auth
)->opaqueToken
, "authorization-right-obtain", SANDBOX_FILTER_RIGHT_NAME
, right
)) { 
1176         os_log_error(AUTHD_LOG
, "Sandbox denied authorizing right '%{public}s' for authorization created by '%{public}s' [%d]", right
, auth_token_get_code_url(engine
->auth
), pid
); 
1184 #pragma mark engine methods 
1186 OSStatus 
engine_preauthorize(engine_t engine
, auth_items_t credentials
) 
1188         os_log(AUTHD_LOG
, "engine: preauthorizing"); 
1190         OSStatus status 
= errAuthorizationDenied
; 
1191         bool save_password 
= false; 
1192         CFTypeRef extract_password_entitlement 
= auth_token_copy_entitlement_value(engine
->auth
, "com.apple.authorization.extract-password"); 
1193         if (extract_password_entitlement 
&& (CFGetTypeID(extract_password_entitlement
) == CFBooleanGetTypeID()) && extract_password_entitlement 
== kCFBooleanTrue
) { 
1194                 save_password 
= true; 
1195                 os_log_debug(AUTHD_LOG
, "engine: authorization allowed to extract password"); 
1197                 os_log_debug(AUTHD_LOG
, "engine: authorization NOT allowed to extract password"); 
1199         CFReleaseSafe(extract_password_entitlement
); 
1201         // TODO: Remove when all clients have adopted entitlement 
1202         if (!enforced_entitlement()) { 
1203                 save_password 
= true; 
1206         engine
->flags 
= kAuthorizationFlagExtendRights
; 
1207         engine
->preauthorizing 
= true; 
1208         CFTypeRef la_context 
= engine_copy_context(engine
, credentials
); 
1210                 _extract_password_from_la(engine
, la_context
); 
1211                 CFRelease(la_context
); 
1214         const char *user 
= auth_items_get_string(credentials
, kAuthorizationEnvironmentUsername
); 
1215         require(user
, done
); 
1217         auth_items_set_string(engine
->context
, kAuthorizationEnvironmentUsername
, user
); 
1218         struct passwd 
*pwd 
= getpwnam(user
); 
1221         auth_items_set_int(engine
->context
, AGENT_CONTEXT_UID
, pwd
->pw_uid
); 
1223         const char *service 
= auth_items_get_string(credentials
, AGENT_CONTEXT_AP_PAM_SERVICE_NAME
); 
1226                 auth_items_set_string(engine
->context
, AGENT_CONTEXT_AP_USER_NAME
, user
); 
1227                 auth_items_set_string(engine
->context
, AGENT_CONTEXT_AP_PAM_SERVICE_NAME
, service
); 
1230         if (auth_items_exist(credentials
, AGENT_CONTEXT_AP_TOKEN
)) { 
1232                 const void *data 
= auth_items_get_data(credentials
, AGENT_CONTEXT_AP_TOKEN
, &datalen
); 
1234                         auth_items_set_data(engine
->context
, AGENT_CONTEXT_AP_TOKEN
, data
, datalen
); 
1238         auth_items_t decrypted_items 
= auth_items_create(); 
1239         require_action(decrypted_items 
!= NULL
, done
, os_log_error(AUTHD_LOG
, "engine: unable to create items")); 
1240         auth_items_content_copy(decrypted_items
, auth_token_get_context(engine
->auth
)); 
1241         auth_items_decrypt(decrypted_items
, auth_token_get_encryption_key(engine
->auth
)); 
1242         auth_items_copy(engine
->context
, decrypted_items
); 
1243         CFReleaseSafe(decrypted_items
); 
1245         engine
->dismissed 
= false; 
1246         auth_rights_clear(engine
->grantedRights
); 
1248         rule_t rule 
= rule_create_preauthorization(); 
1249         engine
->currentRightName 
= rule_get_name(rule
); 
1250         engine
->currentRule 
= rule
; 
1251         status 
= _evaluate_rule(engine
, rule
, &save_password
); 
1253                         case errAuthorizationSuccess
: 
1254                                 os_log(AUTHD_LOG
, "Succeeded preauthorizing client '%{public}s' [%d] for authorization created by '%{public}s' [%d] (%X,%d)", 
1255                                         process_get_code_url(engine
->proc
), process_get_pid(engine
->proc
), 
1256                                         auth_token_get_code_url(engine
->auth
), auth_token_get_pid(engine
->auth
), (unsigned int)engine
->flags
, auth_token_least_privileged(engine
->auth
)); 
1257                                 status 
= errAuthorizationSuccess
; 
1259                         case errAuthorizationDenied
: 
1260                         case errAuthorizationInteractionNotAllowed
: 
1261                         case errAuthorizationCanceled
: 
1262                                 os_log(AUTHD_LOG
, "Failed to preauthorize client '%{public}s' [%d] for authorization created by '%{public}s' [%d] (%X,%d) (%i)", 
1263                                         process_get_code_url(engine
->proc
), process_get_pid(engine
->proc
), 
1264                                         auth_token_get_code_url(engine
->auth
), auth_token_get_pid(engine
->auth
), (unsigned int)engine
->flags
, auth_token_least_privileged(engine
->auth
), (int)status
); 
1267                                 os_log_error(AUTHD_LOG
, "engine: preauthorize returned %d => returning errAuthorizationInternal", (int)status
); 
1268                                 status 
= errAuthorizationInternal
; 
1272                 CFReleaseSafe(rule
); 
1274         if (engine
->dismissed
) { 
1275                 os_log_error(AUTHD_LOG
, "engine: engine dismissed"); 
1276                 status 
= errAuthorizationDenied
; 
1279         os_log_debug(AUTHD_LOG
, "engine: preauthorize result: %d", (int)status
); 
1281                 _cf_set_iterate(engine
->credentials
, ^bool(CFTypeRef value
) { 
1282                         credential_t cred 
= (credential_t
)value
; 
1283                         // skip all uid credentials when running in least privileged 
1284                         if (auth_token_least_privileged(engine
->auth
) && !credential_is_right(cred
)) 
1287                         session_t session 
= auth_token_get_session(engine
->auth
); 
1288                         auth_token_set_credential(engine
->auth
, cred
); 
1289                         if (credential_get_shared(cred
)) { 
1290                                 session_set_credential(session
, cred
); 
1292                         if (credential_is_right(cred
)) { 
1293                                 os_log(AUTHD_LOG
, "engine: adding least privileged %{public}scredential %{public}s to authorization", credential_get_shared(cred
) ? "shared " : "", credential_get_name(cred
)); 
1295                                 os_log(AUTHD_LOG
, "engine: adding %{public}scredential %{public}s (%i) to authorization", credential_get_shared(cred
) ? "shared " : "", credential_get_name(cred
), credential_get_uid(cred
)); 
1301         if (status 
== errAuthorizationSuccess 
&& save_password
) { 
1302                 auth_items_set_flags(engine
->context
, kAuthorizationEnvironmentPassword
, kAuthorizationContextFlagExtractable
); 
1305         if ((status 
== errAuthorizationSuccess
) || (status 
== errAuthorizationCanceled
)) { 
1306                 auth_items_t encrypted_items 
= auth_items_create(); 
1307                 require_action(encrypted_items 
!= NULL
, done
, os_log_error(AUTHD_LOG
, "engine: unable to create items")); 
1308                 auth_items_content_copy_with_flags(encrypted_items
, engine
->context
, kAuthorizationContextFlagExtractable
); 
1310                 os_log_debug(AUTHD_LOG
, "engine: ********** Dumping preauthorized context for encryption **********"); 
1311                 os_log_debug(AUTHD_LOG
, "%@", encrypted_items
); 
1313                 auth_items_encrypt(encrypted_items
, auth_token_get_encryption_key(engine
->auth
)); 
1314                 auth_items_copy_with_flags(auth_token_get_context(engine
->auth
), encrypted_items
, kAuthorizationContextFlagExtractable
); 
1315                 os_log_debug(AUTHD_LOG
, "engine: encrypted preauthorization context data"); 
1316                 CFReleaseSafe(encrypted_items
); 
1320         engine
->preauthorizing 
= false; 
1321         auth_items_clear(engine
->context
); 
1322         auth_items_clear(engine
->sticky_context
); 
1323         CFDictionaryRemoveAllValues(engine
->mechanism_agents
); 
1327 OSStatus 
engine_authorize(engine_t engine
, auth_rights_t rights
, auth_items_t environment
, AuthorizationFlags flags
) 
1329     __block OSStatus status 
= errAuthorizationSuccess
; 
1330     __block 
bool save_password 
= false; 
1331         __block 
bool password_only 
= false; 
1333     ccaudit_t ccaudit 
= NULL
; 
1335     require(rights 
!= NULL
, done
); 
1337     ccaudit 
= ccaudit_create(engine
->proc
, engine
->auth
, AUE_ssauthorize
); 
1338     if (auth_rights_get_count(rights
) > 0) { 
1339         ccaudit_log(ccaudit
, "begin evaluation", NULL
, 0); 
1342     engine
->flags 
= flags
; 
1345         _parse_environment(engine
, environment
); 
1346         auth_items_copy(engine
->hints
, environment
); 
1347                 engine_acquire_sheet_data(engine
); 
1350         auth_items_t decrypted_items 
= auth_items_create(); 
1351         require_action(decrypted_items 
!= NULL
, done
, os_log_error(AUTHD_LOG
, "engine: enable to create items")); 
1352         auth_items_content_copy(decrypted_items
, auth_token_get_context(engine
->auth
)); 
1353         auth_items_decrypt(decrypted_items
, auth_token_get_encryption_key(engine
->auth
)); 
1354         auth_items_copy(engine
->context
, decrypted_items
); 
1355         CFReleaseSafe(decrypted_items
); 
1357     engine
->dismissed 
= false; 
1358     auth_rights_clear(engine
->grantedRights
); 
1361                 // first check if any of rights uses rule with password-only set to true 
1362                 // if so, set appropriate hint so SecurityAgent won't use alternate authentication methods like smartcard etc. 
1363                 authdb_connection_t dbconn 
= authdb_connection_acquire(server_get_database()); // get db handle 
1364                 auth_rights_iterate(rights
, ^bool(const char *key
) { 
1367                         os_log_debug(AUTHD_LOG
, "engine: checking if rule %{public}s contains password-only item", key
); 
1369                         rule_t rule 
= _find_rule(engine
, dbconn
, key
); 
1371                         if (rule 
&& _preevaluate_rule(engine
, rule
)) { 
1372                                 password_only 
= true; 
1373                 CFReleaseSafe(rule
); 
1376             CFReleaseSafe(rule
); 
1379                 authdb_connection_release(&dbconn
); // release db handle 
1382         if (password_only
) { 
1383                 os_log_debug(AUTHD_LOG
, "engine: password-only item found, forcing SecurityAgent to use password-only UI"); 
1384                 auth_items_set_bool(engine
->immutable_hints
, AGENT_HINT_PASSWORD_ONLY
, true); 
1387     auth_rights_iterate(rights
, ^bool(const char *key
) { 
1392         if (!_verify_sandbox(engine
, key
)) { // _verify_sandbox is already logging failures 
1393             status 
= errAuthorizationDenied
; 
1397         authdb_connection_t dbconn 
= authdb_connection_acquire(server_get_database()); // get db handle 
1399         os_log_debug(AUTHD_LOG
, "engine: evaluate right %{public}s", key
); 
1400         rule_t rule 
= _find_rule(engine
, dbconn
, key
); 
1401         const char * rule_name 
= rule_get_name(rule
); 
1402         if (rule_name 
&& (strcasecmp(rule_name
, "") == 0)) { 
1403             rule_name 
= "default (not defined)"; 
1405         os_log_debug(AUTHD_LOG
, "engine: using rule %{public}s", rule_name
); 
1407         // only need the hints & mechanisms if we are going to show ui 
1408         if (engine
->flags 
& kAuthorizationFlagInteractionAllowed
) { 
1409             _set_right_hints(engine
->hints
, key
); 
1410             _set_localization_hints(dbconn
, engine
->hints
, rule
); 
1411             if (!engine
->authenticateRule
) { 
1412                 engine
->authenticateRule 
= rule_create_with_string("authenticate", dbconn
); 
1416         authdb_connection_release(&dbconn
); // release db handle 
1418         engine
->currentRightName 
= key
; 
1419         engine
->currentRule 
= rule
; 
1421         ccaudit_log(ccaudit
, key
, rule_name
, 0); 
1423         status 
= _evaluate_rule(engine
, engine
->currentRule
, &save_password
); 
1425             case errAuthorizationSuccess
: 
1426                 auth_rights_add(engine
->grantedRights
, key
); 
1427                 auth_rights_set_flags(engine
->grantedRights
, key
, auth_rights_get_flags(rights
,key
)); 
1429                 if ((engine
->flags 
& kAuthorizationFlagPreAuthorize
) && 
1430                     (rule_get_class(engine
->currentRule
) == RC_USER
) && 
1431                     (rule_get_timeout(engine
->currentRule
) == 0)) { 
1432                     // FIXME: kAuthorizationFlagPreAuthorize => kAuthorizationFlagCanNotPreAuthorize ??? 
1433                     auth_rights_set_flags(engine
->grantedRights
, engine
->currentRightName
, kAuthorizationFlagPreAuthorize
); 
1436                 os_log(AUTHD_LOG
, "Succeeded authorizing right '%{public}s' by client '%{public}s' [%d] for authorization created by '%{public}s' [%d] (%X,%d)", 
1437                     key
, process_get_code_url(engine
->proc
), process_get_pid(engine
->proc
), 
1438                     auth_token_get_code_url(engine
->auth
), auth_token_get_pid(engine
->auth
), (unsigned int)engine
->flags
, auth_token_least_privileged(engine
->auth
)); 
1440             case errAuthorizationDenied
: 
1441             case errAuthorizationInteractionNotAllowed
: 
1442             case errAuthorizationCanceled
: 
1443                 if (engine
->flags 
& kAuthorizationFlagInteractionAllowed
) { 
1444                     os_log(AUTHD_LOG
, "Failed to authorize right '%{public}s' by client '%{public}s' [%d] for authorization created by '%{public}s' [%d] (%X,%d) (%i)", 
1445                         key
, process_get_code_url(engine
->proc
), process_get_pid(engine
->proc
), 
1446                         auth_token_get_code_url(engine
->auth
), auth_token_get_pid(engine
->auth
), (unsigned int)engine
->flags
, auth_token_least_privileged(engine
->auth
), (int)status
); 
1448                     os_log_debug(AUTHD_LOG
, "Failed to authorize right '%{public}s' by client '%{public}s' [%d] for authorization created by '%{public}s' [%d] (%X,%d) (%d)", 
1449                         key
, process_get_code_url(engine
->proc
), process_get_pid(engine
->proc
), 
1450                         auth_token_get_code_url(engine
->auth
), auth_token_get_pid(engine
->auth
), (unsigned int)engine
->flags
, auth_token_least_privileged(engine
->auth
), (int)status
); 
1454                 os_log_error(AUTHD_LOG
, "engine: evaluate returned %d returning errAuthorizationInternal", (int)status
); 
1455                 status 
= errAuthorizationInternal
; 
1459         ccaudit_log_authorization(ccaudit
, engine
->currentRightName
, status
); 
1461         CFReleaseSafe(rule
); 
1462         engine
->currentRightName 
= NULL
; 
1463         engine
->currentRule 
= NULL
; 
1465         auth_items_remove_with_flags(engine
->hints
, kEngineHintsFlagTemporary
); 
1467         if (!(engine
->flags 
& kAuthorizationFlagPartialRights
) && (status 
!= errAuthorizationSuccess
)) { 
1474         if (password_only
) { 
1475                 os_log_debug(AUTHD_LOG
, "engine: removing password-only flag"); 
1476                 auth_items_remove(engine
->immutable_hints
, AGENT_HINT_PASSWORD_ONLY
); 
1479     if ((engine
->flags 
& kAuthorizationFlagPartialRights
) && (auth_rights_get_count(engine
->grantedRights
) > 0)) { 
1480         status 
= errAuthorizationSuccess
; 
1483     if (engine
->dismissed
) { 
1484                 os_log_error(AUTHD_LOG
, "engine: dismissed"); 
1485         status 
= errAuthorizationDenied
; 
1488     os_log_debug(AUTHD_LOG
, "engine: authorize result: %d", (int)status
); 
1490     if ((engine
->flags 
& kAuthorizationFlagExtendRights
) && !(engine
->flags 
& kAuthorizationFlagDestroyRights
)) { 
1491         _cf_set_iterate(engine
->credentials
, ^bool(CFTypeRef value
) { 
1492             credential_t cred 
= (credential_t
)value
; 
1493             // skip all uid credentials when running in least privileged 
1494             if (auth_token_least_privileged(engine
->auth
) && !credential_is_right(cred
)) 
1497             session_t session 
= auth_token_get_session(engine
->auth
); 
1498             auth_token_set_credential(engine
->auth
, cred
); 
1499             if (credential_get_shared(cred
)) { 
1500                 session_set_credential(session
, cred
); 
1502             if (credential_is_right(cred
)) { 
1503                 os_log_debug(AUTHD_LOG
, "engine: adding least privileged %{public}scredential %{public}s to authorization", credential_get_shared(cred
) ? "shared " : "", credential_get_name(cred
)); 
1505                 os_log_debug(AUTHD_LOG
, "engine: adding %{public}scredential %{public}s (%i) to authorization", credential_get_shared(cred
) ? "shared " : "", credential_get_name(cred
), credential_get_uid(cred
)); 
1511     if (status 
== errAuthorizationSuccess 
&& save_password
) { 
1512         auth_items_set_flags(engine
->context
, kAuthorizationEnvironmentPassword
, kAuthorizationContextFlagExtractable
); 
1515     if ((status 
== errAuthorizationSuccess
) || (status 
== errAuthorizationCanceled
)) { 
1516                 auth_items_t encrypted_items 
= auth_items_create(); 
1517                 require_action(encrypted_items 
!= NULL
, done
, os_log_error(AUTHD_LOG
, "engine: unable to create items")); 
1518                 auth_items_content_copy_with_flags(encrypted_items
, engine
->context
, kAuthorizationContextFlagExtractable
); 
1520                 os_log_debug(AUTHD_LOG
,"engine: ********** Dumping context for encryption **********"); 
1521                 os_log_debug(AUTHD_LOG
, "%@", encrypted_items
); 
1523                 auth_items_encrypt(encrypted_items
, auth_token_get_encryption_key(engine
->auth
)); 
1524                 auth_items_copy_with_flags(auth_token_get_context(engine
->auth
), encrypted_items
, kAuthorizationContextFlagExtractable
); 
1525                 os_log_debug(AUTHD_LOG
, "engine: encrypted authorization context data"); 
1526                 CFReleaseSafe(encrypted_items
); 
1529     if (auth_rights_get_count(rights
) > 0) { 
1530         ccaudit_log(ccaudit
, "end evaluation", NULL
, status
); 
1534     os_log_debug(AUTHD_LOG
, "engine: ********** Dumping auth->credentials **********"); 
1535     auth_token_credentials_iterate(engine
->auth
, ^bool(credential_t cred
) { 
1536                 os_log_debug(AUTHD_LOG
, "%@", cred
); 
1539     os_log_debug(AUTHD_LOG
, "engine: ********** Dumping session->credentials **********"); 
1540     session_credentials_iterate(auth_token_get_session(engine
->auth
), ^bool(credential_t cred
) { 
1541                 os_log_debug(AUTHD_LOG
, "%@", cred
); 
1544     os_log_debug(AUTHD_LOG
, "engine: ********** Dumping engine->context **********"); 
1545         os_log_debug(AUTHD_LOG
, "%@", engine
->context
); 
1546     os_log_debug(AUTHD_LOG
, "engine: ********** Dumping auth->context **********"); 
1547         os_log_debug(AUTHD_LOG
, "%@", engine
->auth
); 
1548     os_log_debug(AUTHD_LOG
, "engine: ********** Dumping granted rights **********"); 
1549         os_log_debug(AUTHD_LOG
, "%@", engine
->grantedRights
); 
1553     auth_items_clear(engine
->context
); 
1554     auth_items_clear(engine
->sticky_context
); 
1555     CFReleaseSafe(ccaudit
); 
1556     CFDictionaryRemoveAllValues(engine
->mechanism_agents
); 
1562 _wildcard_right_exists(engine_t engine
, const char * right
) 
1564     // checks if a wild card right exists 
1565     // ex: com.apple. system. 
1566     bool exists 
= false; 
1568     authdb_connection_t dbconn 
= authdb_connection_acquire(server_get_database()); // get db handle 
1569     require(dbconn 
!= NULL
, done
); 
1571     rule 
= _find_rule(engine
, dbconn
, right
); 
1572     require(rule 
!= NULL
, done
); 
1574     const char * ruleName 
= rule_get_name(rule
); 
1575     require(ruleName 
!= NULL
, done
); 
1576     size_t len 
= strlen(ruleName
); 
1577     require(len 
!= 0, done
); 
1579     if (ruleName
[len
-1] == '.') { 
1585     authdb_connection_release(&dbconn
); 
1586     CFReleaseSafe(rule
); 
1591 // Validate db right modification 
1593 // meta rights are constructed as follows: 
1594 // we don't allow setting of wildcard rights, so you can only be more specific 
1595 // note that you should never restrict things with a wildcard right without disallowing 
1596 // changes to the entire domain.  ie. 
1597 //              system.privilege.               -> never 
1598 //              config.add.system.privilege.    -> never 
1599 //              config.modify.system.privilege. -> never 
1600 //              config.delete.system.privilege. -> never 
1601 // For now we don't allow any configuration of configuration rules 
1602 //              config.config. -> never 
1604 OSStatus 
engine_verify_modification(engine_t engine
, rule_t rule
, bool remove
, bool force_modify
) 
1606     OSStatus status 
= errAuthorizationDenied
; 
1607     auth_rights_t checkRight 
= NULL
; 
1609     memset(buf
, 0, sizeof(buf
)); 
1611     const char * right 
= rule_get_name(rule
); 
1612     require(right 
!= NULL
, done
); 
1613     size_t len 
= strlen(right
); 
1614     require(len 
!= 0, done
); 
1616     require_action(right
[len
-1] != '.', done
, os_log_error(AUTHD_LOG
, "engine: not allowed to set wild card rules")); 
1618     if (strncasecmp(right
, kConfigRight
, strlen(kConfigRight
)) == 0) { 
1619         // special handling of meta right change: 
1620                 // config.add. config.modify. config.remove. config.{}. 
1621                 // check for config.<right> (which always starts with config.config.) 
1622         strlcat(buf
, kConfigRight
, sizeof(buf
)); 
1624         bool existing 
= (rule_get_id(rule
) != 0) ? true : _wildcard_right_exists(engine
, right
); 
1626             if (existing 
|| force_modify
) { 
1627                 strlcat(buf
, kAuthorizationConfigRightModify
,sizeof(buf
)); 
1629                 strlcat(buf
, kAuthorizationConfigRightAdd
, sizeof(buf
)); 
1633                 strlcat(buf
, kAuthorizationConfigRightRemove
, sizeof(buf
)); 
1635                 status 
= errAuthorizationSuccess
; 
1641     strlcat(buf
, right
, sizeof(buf
)); 
1643     checkRight 
= auth_rights_create(); 
1644     auth_rights_add(checkRight
, buf
); 
1645     status 
= engine_authorize(engine
, checkRight
, kAuthorizationEmptyEnvironment
, kAuthorizationFlagDefaults 
| kAuthorizationFlagInteractionAllowed 
| kAuthorizationFlagExtendRights
); 
1648     os_log_debug(AUTHD_LOG
, "engine: authorizing %{public}s for db modification: %d", right
, (int)status
); 
1649     CFReleaseSafe(checkRight
); 
1654 _engine_set_credential(engine_t engine
, credential_t cred
, bool shared
) 
1656     os_log_debug(AUTHD_LOG
, "engine: adding %{public}scredential %{public}s (%i) to engine shared: %i", credential_get_shared(cred
) ? "shared " : "", credential_get_name(cred
), credential_get_uid(cred
), shared
); 
1657     CFSetSetValue(engine
->credentials
, cred
); 
1659         credential_t sharedCred 
= credential_create_with_credential(cred
, true); 
1660         CFSetSetValue(engine
->credentials
, sharedCred
); 
1661         CFReleaseSafe(sharedCred
); 
1666 engine_get_granted_rights(engine_t engine
) 
1668     return engine
->grantedRights
; 
1671 CFAbsoluteTime 
engine_get_time(engine_t engine
) 
1676 void engine_destroy_agents(engine_t engine
) 
1678     engine
->dismissed 
= true; 
1680     _cf_dictionary_iterate(engine
->mechanism_agents
, ^bool(CFTypeRef key 
__attribute__((__unused__
)), CFTypeRef value
) { 
1681         os_log_debug(AUTHD_LOG
, "engine: Destroying %{public}s", mechanism_get_string((mechanism_t
)key
)); 
1682         agent_t agent 
= (agent_t
)value
; 
1683         agent_destroy(agent
); 
1689 void engine_interrupt_agent(engine_t engine
) 
1691     _cf_dictionary_iterate(engine
->mechanism_agents
, ^bool(CFTypeRef key 
__attribute__((__unused__
)), CFTypeRef value
) { 
1692         agent_t agent 
= (agent_t
)value
; 
1693         agent_notify_interrupt(agent
); 
1698 CFTypeRef 
engine_copy_context(engine_t engine
, auth_items_t source
) 
1700         CFTypeRef retval 
= NULL
; 
1702         process_t proc 
= connection_get_process(engine
->conn
); 
1704                 os_log_error(AUTHD_LOG
, "engine: No client process"); 
1708         uid_t client_uid 
= process_get_uid(proc
); 
1710                 os_log_error(AUTHD_LOG
, "engine: No client UID"); 
1715         const void *data 
= auth_items_get_data(source
, AGENT_HINT_SHEET_CONTEXT
, &dataLen
); 
1717                 CFDataRef externalized 
= CFDataCreate(kCFAllocatorDefault
, data
, dataLen
); 
1719                         os_log_debug(AUTHD_LOG
, "engine: Going to get LA context for UID %d", client_uid
); 
1720                         retval 
= LACreateNewContextWithACMContextInSession(client_uid
, externalized
, NULL
); 
1721                         CFRelease(externalized
); 
1728 bool engine_acquire_sheet_data(engine_t engine
) 
1730         uid_t uid 
= auth_items_get_int(engine
->hints
, AGENT_CONTEXT_UID
); 
1734         CFReleaseSafe(engine
->la_context
); 
1735         engine
->la_context 
= engine_copy_context(engine
, engine
->hints
); 
1736         if (engine
->la_context
) { 
1737                 // copy UID to the context of the authorization 
1738                 os_log_debug(AUTHD_LOG
, "engine: Sheet user UID %d", uid
); 
1739                 auth_items_set_int(engine
->context
, AGENT_CONTEXT_UID
, uid
); 
1740                 struct passwd 
*pwd 
= getpwuid(uid
); 
1742                         auth_items_set_string(engine
->context
, kAuthorizationEnvironmentUsername
, pwd
->pw_name
); 
1746                 // this is not real failure as no LA context in authorization context is very valid scenario 
1747                 os_log_debug(AUTHD_LOG
, "engine: Failed to get LA context");