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> 
  27 static void _set_process_hints(auth_items_t
, process_t
); 
  28 static void _set_process_immutable_hints(auth_items_t
, process_t
); 
  29 static void _set_auth_token_hints(auth_items_t
, auth_token_t
); 
  30 static OSStatus 
_evaluate_user_credential_for_rule(engine_t
, credential_t
, rule_t
, bool, bool, enum Reason 
*); 
  31 static void _engine_set_credential(engine_t
, credential_t
, bool); 
  32 static OSStatus 
_evaluate_rule(engine_t
, rule_t
, bool *); 
  35     kEngineHintsFlagTemporary 
= (1 << 30) 
  39 #pragma mark engine creation 
  42     __AUTH_BASE_STRUCT_HEADER__
; 
  48     AuthorizationFlags flags
; 
  51     auth_items_t sticky_context
; 
  52     auth_items_t immutable_hints
; 
  54     auth_rights_t grantedRights
; 
  61     credential_t sessionCredential
; 
  62     CFMutableSetRef credentials
; 
  63     CFMutableSetRef effectiveCredentials
; 
  65     CFMutableDictionaryRef mechanism_agents
; 
  67     // set only in engine_authorize 
  68     const char * currentRightName
; // weak ref 
  69     rule_t currentRule
; // weak ref 
  71     rule_t authenticateRule
; 
  77 _engine_finalizer(CFTypeRef value
) 
  79     engine_t engine 
= (engine_t
)value
; 
  81     CFReleaseSafe(engine
->mechanism_agents
); 
  82     CFReleaseSafe(engine
->conn
); 
  83     CFReleaseSafe(engine
->auth
); 
  84     CFReleaseSafe(engine
->hints
); 
  85     CFReleaseSafe(engine
->context
); 
  86     CFReleaseSafe(engine
->immutable_hints
); 
  87     CFReleaseSafe(engine
->sticky_context
); 
  88     CFReleaseSafe(engine
->grantedRights
); 
  89     CFReleaseSafe(engine
->sessionCredential
); 
  90     CFReleaseSafe(engine
->credentials
); 
  91     CFReleaseSafe(engine
->effectiveCredentials
); 
  92     CFReleaseSafe(engine
->authenticateRule
); 
  95 AUTH_TYPE_INSTANCE(engine
, 
  98                    .finalize 
= _engine_finalizer
, 
 101                    .copyFormattingDesc 
= NULL
, 
 102                    .copyDebugDesc 
= NULL
 
 105 static CFTypeID 
engine_get_type_id() { 
 106     static CFTypeID type_id 
= _kCFRuntimeNotATypeID
; 
 107     static dispatch_once_t onceToken
; 
 109     dispatch_once(&onceToken
, ^{ 
 110         type_id 
= _CFRuntimeRegisterClass(&_auth_type_engine
); 
 117 engine_create(connection_t conn
, auth_token_t auth
) 
 119     engine_t engine 
= NULL
; 
 120     require(conn 
!= NULL
, done
); 
 121     require(auth 
!= NULL
, done
); 
 123     engine 
= (engine_t
)_CFRuntimeCreateInstance(kCFAllocatorDefault
, engine_get_type_id(), AUTH_CLASS_SIZE(engine
), NULL
); 
 124     require(engine 
!= NULL
, done
); 
 126     engine
->conn 
= (connection_t
)CFRetain(conn
); 
 127     engine
->proc 
= connection_get_process(conn
); 
 128     engine
->auth 
= (auth_token_t
)CFRetain(auth
); 
 130     engine
->hints 
= auth_items_create(); 
 131     engine
->context 
= auth_items_create(); 
 132     engine
->immutable_hints 
= auth_items_create(); 
 133     engine
->sticky_context 
= auth_items_create(); 
 134     _set_process_hints(engine
->hints
, engine
->proc
); 
 135     _set_process_immutable_hints(engine
->immutable_hints
, engine
->proc
); 
 136     _set_auth_token_hints(engine
->hints
, auth
); 
 138     engine
->grantedRights 
= auth_rights_create(); 
 140     engine
->reason 
= noReason
; 
 142     engine
->now 
= CFAbsoluteTimeGetCurrent(); 
 144     session_update(auth_token_get_session(engine
->auth
)); 
 145     engine
->sessionCredential 
= credential_create(session_get_uid(auth_token_get_session(engine
->auth
))); 
 146     engine
->credentials 
= CFSetCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeSetCallBacks
); 
 147     engine
->effectiveCredentials 
= CFSetCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeSetCallBacks
); 
 149     session_credentials_iterate(auth_token_get_session(engine
->auth
), ^bool(credential_t cred
) { 
 150         CFSetAddValue(engine
->effectiveCredentials
, cred
); 
 154     auth_token_credentials_iterate(engine
->auth
, ^bool(credential_t cred
) { 
 155         // we added all session credentials already now just add all previously acquired credentials 
 156         if (!credential_get_shared(cred
)) { 
 157             CFSetAddValue(engine
->credentials
, cred
); 
 162     engine
->mechanism_agents 
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
 169 #pragma mark agent hints 
 172 _set_process_hints(auth_items_t hints
, process_t proc
) 
 174     // process information 
 175     RequestorType type 
= bundle
; 
 176     auth_items_set_data(hints
, AGENT_HINT_CLIENT_TYPE
, &type
, sizeof(type
)); 
 177     auth_items_set_int(hints
, AGENT_HINT_CLIENT_PID
, process_get_pid(proc
)); 
 178     auth_items_set_uint(hints
, AGENT_HINT_CLIENT_UID
, process_get_uid(proc
)); 
 182 _set_process_immutable_hints(auth_items_t immutable_hints
, process_t proc
) 
 184     // process information - immutable 
 185     auth_items_set_bool(immutable_hints
, AGENT_HINT_PROCESS_SIGNED
, process_apple_signed(proc
)); 
 189 _set_auth_token_hints(auth_items_t hints
, auth_token_t auth
) 
 191     auth_items_set_string(hints
, AGENT_HINT_CLIENT_PATH
, auth_token_get_code_url(auth
)); 
 192     auth_items_set_int(hints
, AGENT_HINT_CREATOR_PID
, auth_token_get_pid(auth
)); 
 193     const audit_info_s 
* info 
= auth_token_get_audit_info(auth
); 
 194     auth_items_set_data(hints
, AGENT_HINT_CREATOR_AUDIT_TOKEN
, &info
->opaqueToken
, sizeof(info
->opaqueToken
)); 
 198 _set_right_hints(auth_items_t hints
, const char * right
) 
 200    auth_items_set_string(hints
, AGENT_HINT_AUTHORIZE_RIGHT
, right
); 
 204 _set_rule_hints(auth_items_t hints
, rule_t rule
) 
 206     auth_items_set_string(hints
, AGENT_HINT_AUTHORIZE_RULE
, rule_get_name(rule
)); 
 207     const char * group 
= rule_get_group(rule
); 
 208     if (rule_get_class(rule
) == RC_USER 
&& group 
!= NULL
) { 
 209         auth_items_set_string(hints
, AGENT_HINT_REQUIRE_USER_IN_GROUP
, group
); 
 211         auth_items_remove(hints
, AGENT_HINT_REQUIRE_USER_IN_GROUP
); 
 216 _set_localization_hints(authdb_connection_t dbconn
, auth_items_t hints
, rule_t rule
) 
 218     char * key 
= calloc(1u, 128); 
 220     authdb_step(dbconn
, "SELECT lang,value FROM prompts WHERE r_id = ?", ^(sqlite3_stmt 
*stmt
) { 
 221         sqlite3_bind_int64(stmt
, 1, rule_get_id(rule
)); 
 222     }, ^bool(auth_items_t data
) { 
 223         snprintf(key
, 128, "%s%s", kAuthorizationRuleParameterDescription
, auth_items_get_string(data
, "lang")); 
 224         auth_items_set_string(hints
, key
, auth_items_get_string(data
, "value")); 
 225         auth_items_set_flags(hints
, key
, kEngineHintsFlagTemporary
); 
 229     authdb_step(dbconn
, "SELECT lang,value FROM buttons WHERE r_id = ?", ^(sqlite3_stmt 
*stmt
) { 
 230         sqlite3_bind_int64(stmt
, 1, rule_get_id(rule
)); 
 231     }, ^bool(auth_items_t data
) { 
 232         snprintf(key
, 128, "%s%s", kAuthorizationRuleParameterButton
, auth_items_get_string(data
, "lang")); 
 233         auth_items_set_string(hints
, key
, auth_items_get_string(data
, "value")); 
 234         auth_items_set_flags(hints
, key
, kEngineHintsFlagTemporary
); 
 242 _set_session_hints(engine_t engine
, rule_t rule
) 
 244     LOGV("engine[%i]: ** prepare agent hints for rule %s", connection_get_pid(engine
->conn
), rule_get_name(rule
)); 
 245     if (_evaluate_user_credential_for_rule(engine
, engine
->sessionCredential
, rule
, true, true, NULL
) == errAuthorizationSuccess
) { 
 246         const char * tmp 
= credential_get_name(engine
->sessionCredential
); 
 248             auth_items_set_string(engine
->hints
, AGENT_HINT_SUGGESTED_USER
, tmp
); 
 250         tmp 
= credential_get_realname(engine
->sessionCredential
); 
 252             auth_items_set_string(engine
->hints
, AGENT_HINT_SUGGESTED_USER_LONG
, tmp
); 
 255         auth_items_remove(engine
->hints
, AGENT_HINT_SUGGESTED_USER
); 
 256         auth_items_remove(engine
->hints
, AGENT_HINT_SUGGESTED_USER_LONG
); 
 261 #pragma mark right processing 
 264 _evaluate_credential_for_rule(engine_t engine
, credential_t cred
, rule_t rule
, bool ignoreShared
, bool sessionOwner
, enum Reason 
* reason
) 
 266     if (auth_token_least_privileged(engine
->auth
)) { 
 267         if (credential_is_right(cred
) && credential_get_valid(cred
) && _compare_string(engine
->currentRightName
, credential_get_name(cred
))) { 
 269                 if (!rule_get_shared(rule
) && credential_get_shared(cred
)) { 
 270                     LOGV("engine[%i]: - shared right %s (does NOT satisfy rule)", connection_get_pid(engine
->conn
), credential_get_name(cred
)); 
 271                     if (reason
) {  *reason 
= unknownReason
; } 
 272                     return errAuthorizationDenied
; 
 276             return errAuthorizationSuccess
; 
 278             if (reason
) {  *reason 
= unknownReason
; } 
 279             return errAuthorizationDenied
; 
 282         return _evaluate_user_credential_for_rule(engine
,cred
,rule
,ignoreShared
,sessionOwner
, reason
); 
 287 _evaluate_user_credential_for_rule(engine_t engine
, credential_t cred
, rule_t rule
, bool ignoreShared
, bool sessionOwner
, enum Reason 
* reason
) 
 289     const char * cred_label 
= sessionOwner 
? "session owner" : "credential"; 
 290     LOGV("engine[%i]: - validating %s%s %s (%i) for %s", connection_get_pid(engine
->conn
), 
 291          credential_get_shared(cred
) ? "shared " : "", 
 293          credential_get_name(cred
), 
 294          credential_get_uid(cred
), 
 295          rule_get_name(rule
)); 
 297     if (rule_get_class(rule
) != RC_USER
) { 
 298         LOGV("engine[%i]: - invalid rule class %i (denied)", connection_get_pid(engine
->conn
), rule_get_class(rule
)); 
 299         return errAuthorizationDenied
; 
 302     if (credential_get_valid(cred
) != true) { 
 303         LOGV("engine[%i]: - %s %i invalid (does NOT satisfy rule)", connection_get_pid(engine
->conn
), cred_label
, credential_get_uid(cred
)); 
 304         if (reason
) {  *reason 
= invalidPassphrase
; } 
 305         return errAuthorizationDenied
; 
 308     if (engine
->now 
- credential_get_creation_time(cred
) > rule_get_timeout(rule
)) { 
 309         LOGV("engine[%i]: - %s %i expired '%f > %lli' (does NOT satisfy rule)", connection_get_pid(engine
->conn
), cred_label
, credential_get_uid(cred
), 
 310              (engine
->now 
- credential_get_creation_time(cred
)), rule_get_timeout(rule
)); 
 311         if (reason
) {  *reason 
= unknownReason
; } 
 312         return errAuthorizationDenied
; 
 317         if (!rule_get_shared(rule
) && credential_get_shared(cred
)) { 
 318             LOGV("engine[%i]: - shared %s %i (does NOT satisfy rule)", connection_get_pid(engine
->conn
), cred_label
, credential_get_uid(cred
)); 
 319             if (reason
) {  *reason 
= unknownReason
; } 
 320             return errAuthorizationDenied
; 
 324     if (credential_get_uid(cred
) == 0) { 
 325         LOGV("engine[%i]: - %s %i has uid 0 (does satisfy rule)", connection_get_pid(engine
->conn
), cred_label
, credential_get_uid(cred
)); 
 326         return errAuthorizationSuccess
; 
 329     if (rule_get_session_owner(rule
)) { 
 330         if (credential_get_uid(cred
) == session_get_uid(auth_token_get_session(engine
->auth
))) { 
 331             LOGV("engine[%i]: - %s %i is session owner (does satisfy rule)", connection_get_pid(engine
->conn
), cred_label
, credential_get_uid(cred
)); 
 332             return errAuthorizationSuccess
; 
 336     if (rule_get_group(rule
) != NULL
) { 
 339             // This allows testing a group modifier without prompting the user 
 340             // When (authenticate-user = false) we are just testing the creator uid. 
 341             // If a group modifier is enabled (RuleFlagEntitledAndGroup | RuleFlagVPNEntitledAndGroup) 
 342             // we want to skip the creator uid group check. 
 343             // group modifiers are checked early during the evaluation in _check_entitlement_for_rule  
 344             if (!rule_get_authenticate_user(rule
)) { 
 345                 if (rule_check_flags(rule
, RuleFlagEntitledAndGroup 
| RuleFlagVPNEntitledAndGroup
)) { 
 350             if (credential_check_membership(cred
, rule_get_group(rule
))) { 
 351                 LOGV("engine[%i]: - %s %i is member of group %s (does satisfy rule)", connection_get_pid(engine
->conn
), cred_label
, credential_get_uid(cred
), rule_get_group(rule
)); 
 352                 return errAuthorizationSuccess
; 
 354                 if (reason
) {  *reason 
= userNotInGroup
; } 
 357     } else if (rule_get_session_owner(rule
)) { // rule asks only if user is the session owner 
 358         if (reason
) {  *reason 
= unacceptableUser
; } 
 361     LOGV("engine[%i]: - %s %i (does NOT satisfy rule)", connection_get_pid(engine
->conn
), cred_label
, credential_get_uid(cred
)); 
 362     return errAuthorizationDenied
; 
 366 _get_agent(engine_t engine
, mechanism_t mech
, bool create
, bool firstMech
) 
 368     agent_t agent 
= (agent_t
)CFDictionaryGetValue(engine
->mechanism_agents
, mech
); 
 369     if (create 
&& !agent
) { 
 370         agent 
= agent_create(engine
, mech
, engine
->auth
, engine
->proc
, firstMech
); 
 372             CFDictionaryAddValue(engine
->mechanism_agents
, mech
, agent
); 
 373             CFReleaseSafe(agent
); 
 380 _evaluate_builtin_mechanism(engine_t engine
, mechanism_t mech
) 
 382     uint64_t result 
= kAuthorizationResultDeny
; 
 384     switch (mechanism_get_type(mech
)) { 
 385         case kMechanismTypeEntitled
: 
 386             if (auth_token_has_entitlement_for_right(engine
->auth
, engine
->currentRightName
)) { 
 387                 result 
= kAuthorizationResultAllow
; 
 399 _evaluate_mechanisms(engine_t engine
, CFArrayRef mechanisms
) 
 401     uint64_t result 
= kAuthorizationResultAllow
; 
 402     ccaudit_t ccaudit 
= ccaudit_create(engine
->proc
, engine
->auth
, AUE_ssauthmech
); 
 403     auth_items_t context 
= auth_items_create(); 
 404     auth_items_t hints 
= auth_items_create(); 
 406     auth_items_copy(context
, engine
->context
); 
 407     auth_items_copy(hints
, engine
->hints
); 
 408     auth_items_copy(context
, engine
->sticky_context
); 
 410     CFIndex count 
= CFArrayGetCount(mechanisms
); 
 411     for (CFIndex i 
= 0; i 
< count
; i
++) { 
 412         mechanism_t mech 
= (mechanism_t
)CFArrayGetValueAtIndex(mechanisms
, i
); 
 414         if (mechanism_get_type(mech
)) { 
 415             LOGV("engine[%i]: running builtin mechanism %s (%li of %li)", connection_get_pid(engine
->conn
), mechanism_get_string(mech
), i
+1, count
); 
 416             result 
= _evaluate_builtin_mechanism(engine
, mech
); 
 418             agent_t agent 
= _get_agent(engine
, mech
, true, i 
== 0); 
 419             require_action(agent 
!= NULL
, done
, result 
= kAuthorizationResultUndefined
; LOGE("engine[%i]: error creating mechanism agent", connection_get_pid(engine
->conn
))); 
 421             // check if any agent has been interrupted (it necessary if interrupt will come during creation) 
 424             for (j 
= 0; j 
< i
; j
++) { 
 425                 agent1 
= _get_agent(engine
, (mechanism_t
)CFArrayGetValueAtIndex(mechanisms
, j
), false, j 
== 0); 
 426                 if(agent_get_state(agent1
) == interrupting
) { 
 431                 LOGV("engine[%i]: mechanisms interrupted", connection_get_pid(engine
->conn
)); 
 433                 asprintf(&buf
, "evaluation interrupted by %s; restarting evaluation there", mechanism_get_string(agent_get_mechanism(agent1
))); 
 434                 ccaudit_log_mechanism(ccaudit
, engine
->currentRightName
, mechanism_get_string(agent_get_mechanism(agent1
)), kAuthorizationResultAllow
, buf
); 
 436                 ccaudit_log_mechanism(ccaudit
, engine
->currentRightName
, mechanism_get_string(mech
), kAuthorizationResultAllow
, NULL
); 
 437                 const char * token_name 
= auth_items_get_string(hints
, AGENT_HINT_TOKEN_NAME
); 
 438                 if (token_name 
&& strlen(token_name
) == 0) { 
 439                     auth_items_remove(hints
, AGENT_HINT_TOKEN_NAME
); 
 441                 auth_items_copy(context
, agent_get_context(agent1
)); 
 442                 auth_items_copy(hints
, agent_get_hints(agent1
)); 
 449             LOGV("engine[%i]: running mechanism %s (%li of %li)", connection_get_pid(engine
->conn
), mechanism_get_string(agent_get_mechanism(agent
)), i
+1, count
); 
 450             result 
= agent_run(agent
, hints
, context
, engine
->immutable_hints
); 
 452             auth_items_copy(context
, agent_get_context(agent
)); 
 453             auth_items_copy(hints
, agent_get_hints(agent
)); 
 455             bool interrupted 
= false; 
 456             for (CFIndex i2 
= 0; i2 
!= i
; i2
++) { 
 457                 agent_t agent2 
= _get_agent(engine
, (mechanism_t
)CFArrayGetValueAtIndex(mechanisms
, i2
), false, i 
== 0); 
 458                 if (agent_get_state(agent2
) == interrupting
) { 
 459                     agent_deactivate(agent
); 
 463                     asprintf(&buf
, "evaluation interrupted by %s; restarting evaluation there", mechanism_get_string(agent_get_mechanism(agent2
))); 
 464                     ccaudit_log_mechanism(ccaudit
, engine
->currentRightName
, mechanism_get_string(agent_get_mechanism(agent2
)), kAuthorizationResultAllow
, buf
); 
 466                     auth_items_copy(context
, agent_get_context(agent2
)); 
 467                     auth_items_copy(hints
, agent_get_hints(agent2
)); 
 472             // Empty token name means that token doesn't exist (e.g. SC was removed). 
 473             // Remove empty token name from hints for UI drawing logic. 
 474             const char * token_name 
= auth_items_get_string(hints
, AGENT_HINT_TOKEN_NAME
); 
 475             if (token_name 
&& strlen(token_name
) == 0) { 
 476                 auth_items_remove(hints
, AGENT_HINT_TOKEN_NAME
); 
 480                 LOGV("engine[%i]: mechanisms interrupted", connection_get_pid(engine
->conn
)); 
 481                 enum Reason reason 
= worldChanged
; 
 482                 auth_items_set_data(hints
, AGENT_HINT_RETRY_REASON
, &reason
, sizeof(reason
)); 
 483                 result 
= kAuthorizationResultAllow
; 
 484                 _cf_dictionary_iterate(engine
->mechanism_agents
, ^bool(CFTypeRef key 
__attribute__((__unused__
)), CFTypeRef value
) { 
 485                     agent_t tempagent 
= (agent_t
)value
; 
 486                     agent_clear_interrupt(tempagent
); 
 492         if (result 
== kAuthorizationResultAllow
) { 
 493             ccaudit_log_mechanism(ccaudit
, engine
->currentRightName
, mechanism_get_string(mech
), kAuthorizationResultAllow
, NULL
); 
 495             ccaudit_log_mechanism(ccaudit
, engine
->currentRightName
, mechanism_get_string(mech
), (uint32_t)result
, NULL
); 
 501     if ((result 
== kAuthorizationResultUserCanceled
) || (result 
== kAuthorizationResultAllow
)) { 
 502         // only make non-sticky context values available externally 
 503         auth_items_set_flags(context
, kAuthorizationEnvironmentPassword
, kAuthorizationContextFlagVolatile
); 
 504                 // <rdar://problem/16275827> Takauthorizationenvironmentusername should always be extractable 
 505         auth_items_set_flags(context
, kAuthorizationEnvironmentUsername
, kAuthorizationContextFlagExtractable
); 
 506         auth_items_copy_with_flags(engine
->context
, context
, kAuthorizationContextFlagExtractable 
| kAuthorizationContextFlagVolatile
); 
 507     } else if (result 
== kAuthorizationResultDeny
) { 
 508         auth_items_clear(engine
->sticky_context
); 
 509         // save off sticky values in context 
 510         auth_items_copy_with_flags(engine
->sticky_context
, context
, kAuthorizationContextFlagSticky
); 
 513     CFReleaseSafe(ccaudit
); 
 514     CFReleaseSafe(context
); 
 515     CFReleaseSafe(hints
); 
 519         case kAuthorizationResultDeny
: 
 520             return errAuthorizationDenied
; 
 521         case kAuthorizationResultUserCanceled
: 
 522             return errAuthorizationCanceled
; 
 523         case kAuthorizationResultAllow
: 
 524             return errAuthorizationSuccess
; 
 525         case kAuthorizationResultUndefined
: 
 526             return errAuthorizationInternal
; 
 529             LOGV("engine[%i]: unexpected error result", connection_get_pid(engine
->conn
)); 
 530             return errAuthorizationInternal
; 
 536 _evaluate_authentication(engine_t engine
, rule_t rule
) 
 538     OSStatus status 
= errAuthorizationDenied
; 
 539     ccaudit_t ccaudit 
= ccaudit_create(engine
->proc
, engine
->auth
, AUE_ssauthint
); 
 540     LOGV("engine[%i]: evaluate authentication", connection_get_pid(engine
->conn
)); 
 541     _set_rule_hints(engine
->hints
, rule
); 
 542     _set_session_hints(engine
, rule
); 
 544     CFArrayRef mechanisms 
= rule_get_mechanisms(rule
); 
 545     if (!(CFArrayGetCount(mechanisms
) > 0)) { 
 546         mechanisms 
= rule_get_mechanisms(engine
->authenticateRule
); 
 548     require_action(CFArrayGetCount(mechanisms
) > 0, done
, LOGV("engine[%i]: error no mechanisms found", connection_get_pid(engine
->conn
))); 
 550     int64_t ruleTries 
= rule_get_tries(rule
); 
 551     for (engine
->tries 
= 0; engine
->tries 
< ruleTries
; engine
->tries
++) { 
 553         auth_items_set_data(engine
->hints
, AGENT_HINT_RETRY_REASON
, &engine
->reason
, sizeof(engine
->reason
)); 
 554         auth_items_set_int(engine
->hints
, AGENT_HINT_TRIES
, engine
->tries
); 
 556         status 
= _evaluate_mechanisms(engine
, mechanisms
); 
 558         LOGV("engine[%i]: evaluate mechanisms result %d", connection_get_pid(engine
->conn
), (int)status
); 
 560         // successfully ran mechanisms to obtain credential 
 561         if (status 
== errAuthorizationSuccess
) { 
 562             // deny is the default 
 563             status 
= errAuthorizationDenied
; 
 565             credential_t newCred 
= NULL
; 
 566             if (auth_items_exist(engine
->context
, "uid")) { 
 567                 newCred 
= credential_create(auth_items_get_uint(engine
->context
, "uid")); 
 569                 LOGV("engine[%i]: mechanism failed to return a valid uid", connection_get_pid(engine
->conn
)); 
 573                 if (credential_get_valid(newCred
)) { 
 574                     LOG("UID %u authenticated as user %s (UID %u) for right '%s'", auth_token_get_uid(engine
->auth
), credential_get_name(newCred
), credential_get_uid(newCred
), engine
->currentRightName
); 
 575                     ccaudit_log_success(ccaudit
, newCred
, engine
->currentRightName
); 
 577                     LOG("UID %u failed to authenticate as user '%s' for right '%s'", auth_token_get_uid(engine
->auth
), auth_items_get_string(engine
->context
, "username"), engine
->currentRightName
); 
 578                     ccaudit_log_failure(ccaudit
, auth_items_get_string(engine
->context
, "username"), engine
->currentRightName
); 
 581                 status 
= _evaluate_user_credential_for_rule(engine
, newCred
, rule
, true, false, &engine
->reason
); 
 583                 if (status 
== errAuthorizationSuccess
) { 
 584                     _engine_set_credential(engine
, newCred
, rule_get_shared(rule
)); 
 585                     CFReleaseSafe(newCred
); 
 587                     if (auth_token_least_privileged(engine
->auth
)) { 
 588                         credential_t rightCred 
= credential_create_with_right(engine
->currentRightName
); 
 589                         _engine_set_credential(engine
, rightCred
, rule_get_shared(rule
)); 
 590                         CFReleaseSafe(rightCred
); 
 593                     session_t session 
= auth_token_get_session(engine
->auth
); 
 594                     if (credential_get_uid(newCred
) == session_get_uid(session
)) { 
 595                         LOGV("engine[%i]: authenticated as the session owner", connection_get_pid(engine
->conn
)); 
 596                         session_set_attributes(auth_token_get_session(engine
->auth
), AU_SESSION_FLAG_HAS_AUTHENTICATED
); 
 602                 CFReleaseSafe(newCred
); 
 605         } else if (status 
== errAuthorizationCanceled 
|| status 
== errAuthorizationInternal
) { 
 607         } else if (status 
== errAuthorizationDenied
) { 
 608             engine
->reason 
= invalidPassphrase
; 
 612     if (engine
->tries 
== ruleTries
) { 
 613         engine
->reason 
= tooManyTries
; 
 614         auth_items_set_data(engine
->hints
, AGENT_HINT_RETRY_REASON
, &engine
->reason
, sizeof(engine
->reason
)); 
 615         auth_items_set_int(engine
->hints
, AGENT_HINT_TRIES
, engine
->tries
); 
 616         _evaluate_mechanisms(engine
, mechanisms
); 
 617         ccaudit_log(ccaudit
, engine
->currentRightName
, NULL
, 1113); 
 621     CFReleaseSafe(ccaudit
); 
 627 _check_entitlement_for_rule(engine_t engine
, rule_t rule
) 
 629     bool entitled 
= false; 
 630     CFTypeRef value 
= NULL
; 
 632     if (rule_check_flags(rule
, RuleFlagEntitledAndGroup
)) { 
 633         if (auth_token_has_entitlement_for_right(engine
->auth
, engine
->currentRightName
)) { 
 634             if (credential_check_membership(auth_token_get_credential(engine
->auth
), rule_get_group(rule
))) { 
 635                 LOGV("engine[%i]: creator of authorization has entitlement for right %s and is member of group '%s'", connection_get_pid(engine
->conn
), engine
->currentRightName
, rule_get_group(rule
)); 
 642     if (rule_check_flags(rule
, RuleFlagVPNEntitledAndGroup
)) { 
 643         // com.apple.networking.vpn.configuration is an array we only check for it's existence 
 644         value 
= auth_token_copy_entitlement_value(engine
->auth
, "com.apple.networking.vpn.configuration"); 
 646             if (credential_check_membership(auth_token_get_credential(engine
->auth
), rule_get_group(rule
))) { 
 647                 LOGV("engine[%i]: creator of authorization has VPN entitlement and is member of group '%s'", connection_get_pid(engine
->conn
), rule_get_group(rule
)); 
 655     CFReleaseSafe(value
); 
 660 _evaluate_class_user(engine_t engine
, rule_t rule
) 
 662     __block OSStatus status 
= errAuthorizationDenied
; 
 664     if (_check_entitlement_for_rule(engine
,rule
)) { 
 665         return errAuthorizationSuccess
; 
 668     if (rule_get_allow_root(rule
) && auth_token_get_uid(engine
->auth
) == 0) { 
 669         LOGV("engine[%i]: creator of authorization has uid == 0 granting right %s", connection_get_pid(engine
->conn
), engine
->currentRightName
); 
 670         return errAuthorizationSuccess
; 
 673     if (!rule_get_authenticate_user(rule
)) { 
 674         status 
= _evaluate_user_credential_for_rule(engine
, engine
->sessionCredential
, rule
, true, true, NULL
); 
 676         if (status 
== errAuthorizationSuccess
) { 
 677             return errAuthorizationSuccess
; 
 680         return errAuthorizationDenied
; 
 683     // First -- check all the credentials we have either acquired or currently have 
 684     _cf_set_iterate(engine
->credentials
, ^bool(CFTypeRef value
) { 
 685         credential_t cred 
= (credential_t
)value
; 
 686         // Passed-in user credentials are allowed for least-privileged mode 
 687         if (auth_token_least_privileged(engine
->auth
) && !credential_is_right(cred
) && credential_get_valid(cred
)) { 
 688             status 
= _evaluate_user_credential_for_rule(engine
, cred
, rule
, false, false, NULL
); 
 689             if (errAuthorizationSuccess 
== status
) { 
 690                 credential_t rightCred 
= credential_create_with_right(engine
->currentRightName
); 
 691                 _engine_set_credential(engine
,rightCred
,rule_get_shared(rule
)); 
 692                 CFReleaseSafe(rightCred
); 
 693                 return false; // exit loop 
 697         status 
= _evaluate_credential_for_rule(engine
, cred
, rule
, false, false, NULL
); 
 698         if (status 
== errAuthorizationSuccess
) { 
 699             return false; // exit loop 
 704     if (status 
== errAuthorizationSuccess
) { 
 708     // Second -- go through the credentials associated to the authorization token session/auth token 
 709     _cf_set_iterate(engine
->effectiveCredentials
, ^bool(CFTypeRef value
) { 
 710         credential_t cred 
= (credential_t
)value
; 
 711         status 
= _evaluate_credential_for_rule(engine
, cred
, rule
, false, false, NULL
); 
 712         if (status 
== errAuthorizationSuccess
) { 
 713             // Add the credential we used to the output set. 
 714             _engine_set_credential(engine
, cred
, false); 
 715             return false; // exit loop 
 720     if (status 
== errAuthorizationSuccess
) { 
 724     // Finally - we didn't find a credential. Obtain a new credential if our flags let us do so. 
 725     if (!(engine
->flags 
& kAuthorizationFlagExtendRights
)) { 
 726         LOGV("engine[%i]: authorization denied (kAuthorizationFlagExtendRights not set)", connection_get_pid(engine
->conn
)); 
 727         return errAuthorizationDenied
; 
 730     // authorization that timeout immediately cannot be preauthorized 
 731     if (engine
->flags 
& kAuthorizationFlagPreAuthorize 
&& rule_get_timeout(rule
) == 0) { 
 732         return errAuthorizationSuccess
; 
 735     if (!(engine
->flags 
& kAuthorizationFlagInteractionAllowed
)) { 
 736                 LOGV("engine[%i]: Interaction not allowed (kAuthorizationFlagInteractionAllowed not set)", connection_get_pid(engine
->conn
)); 
 737         return errAuthorizationInteractionNotAllowed
; 
 740     if (!(session_get_attributes(auth_token_get_session(engine
->auth
)) & AU_SESSION_FLAG_HAS_GRAPHIC_ACCESS
)) { 
 741         LOGV("engine[%i]: Interaction not allowed (session has no ui access)", connection_get_pid(engine
->conn
)); 
 742         return errAuthorizationInteractionNotAllowed
; 
 745     if (server_in_dark_wake()) { 
 746         LOGV("engine[%i]: authorization denied (in DarkWake)", connection_get_pid(engine
->conn
)); 
 747         return errAuthorizationDenied
; 
 750         return _evaluate_authentication(engine
, rule
); 
 754 _evaluate_class_rule(engine_t engine
, rule_t rule
, bool *save_pwd
) 
 756     __block OSStatus status 
= errAuthorizationDenied
; 
 757     int64_t kofn 
= rule_get_kofn(rule
); 
 759     uint32_t total 
= (uint32_t)rule_get_delegates_count(rule
); 
 760     __block 
uint32_t success_count 
= 0; 
 761     __block 
uint32_t count 
= 0; 
 762     LOGV("engine[%i]: ** rule %s has %zi delegates kofn = %lli", connection_get_pid(engine
->conn
), rule_get_name(rule
), total
, kofn
); 
 763     rule_delegates_iterator(rule
, ^bool(rule_t delegate
) { 
 766         if (kofn 
!= 0 && success_count 
== kofn
) { 
 767             status 
= errAuthorizationSuccess
; 
 771         LOGV("engine[%i]: * evaluate rule %s (%i)", connection_get_pid(engine
->conn
), rule_get_name(delegate
), count
); 
 772         status 
= _evaluate_rule(engine
, delegate
, save_pwd
); 
 774         // if status is cancel/internal error abort 
 775                 if ((status 
== errAuthorizationCanceled
) || (status 
== errAuthorizationInternal
)) 
 778         if (status 
!= errAuthorizationSuccess
) { 
 780                 // if remaining is less than required abort 
 781                 if ((total 
- count
) < (kofn 
- success_count
)) { 
 782                     LOGD("engine[%i]: rule evaluation remaining: %i, required: %lli", connection_get_pid(engine
->conn
), (total 
- count
), (kofn 
- success_count
)); 
 798 _evaluate_class_mechanism(engine_t engine
, rule_t rule
) 
 800     OSStatus status 
= errAuthorizationDenied
; 
 801     CFArrayRef mechanisms 
= NULL
; 
 803     require_action(rule_get_mechanisms_count(rule
) > 0, done
, status 
= errAuthorizationSuccess
; LOGV("engine[%i]: no mechanisms specified", connection_get_pid(engine
->conn
))); 
 805     mechanisms 
= rule_get_mechanisms(rule
); 
 807     if (server_in_dark_wake()) { 
 808         CFIndex count 
= CFArrayGetCount(mechanisms
); 
 809         for (CFIndex i 
= 0; i 
< count
; i
++) { 
 810             if (!mechanism_is_privileged((mechanism_t
)CFArrayGetValueAtIndex(mechanisms
, i
))) { 
 811                 LOGE("engine[%i]: authorization denied (in DW)", connection_get_pid(engine
->conn
)); 
 817     int64_t ruleTries 
= rule_get_tries(rule
); 
 820         auth_items_set_data(engine
->hints
, AGENT_HINT_RETRY_REASON
, &engine
->reason
, sizeof(engine
->reason
)); 
 821         auth_items_set_int(engine
->hints
, AGENT_HINT_TRIES
, engine
->tries
); 
 823         status 
= _evaluate_mechanisms(engine
, mechanisms
); 
 824         LOGV("engine[%i]: evaluate mechanisms result %d", connection_get_pid(engine
->conn
), (int)status
); 
 826                 if (status 
== errAuthorizationSuccess
) { 
 827                         credential_t newCred 
= NULL
; 
 828                         if (auth_items_exist(engine
->context
, "uid")) { 
 829                                 newCred 
= credential_create(auth_items_get_uint(engine
->context
, "uid")); 
 831                                 LOGV("engine[%i]: mechanism did not return a uid", connection_get_pid(engine
->conn
)); 
 835                                 _engine_set_credential(engine
, newCred
, rule_get_shared(rule
)); 
 837                                 if (auth_token_least_privileged(engine
->auth
)) { 
 838                                         credential_t rightCred 
= credential_create_with_right(engine
->currentRightName
); 
 839                                         _engine_set_credential(engine
, rightCred
, rule_get_shared(rule
)); 
 840                                         CFReleaseSafe(rightCred
); 
 843                                 if (strcmp(engine
->currentRightName
, "system.login.console") == 0 && !auth_items_exist(engine
->context
, AGENT_CONTEXT_AUTO_LOGIN
)) { 
 844                                         session_set_attributes(auth_token_get_session(engine
->auth
), AU_SESSION_FLAG_HAS_AUTHENTICATED
); 
 847                                 CFReleaseSafe(newCred
); 
 853     } while ( (status 
== errAuthorizationDenied
) // only if we have an expected faulure we continue 
 854              && ((ruleTries 
== 0) || ((ruleTries 
> 0) && engine
->tries 
< ruleTries
))); // ruleTries == 0 means we try forever 
 855                                                                                        // ruleTires > 0 means we try upto ruleTries times 
 861 _evaluate_rule(engine_t engine
, rule_t rule
, bool *save_pwd
) 
 863     if (rule_check_flags(rule
, RuleFlagEntitled
)) { 
 864         if (auth_token_has_entitlement_for_right(engine
->auth
, engine
->currentRightName
)) { 
 865             LOGV("engine[%i]: rule allow, creator of authorization has entitlement for right %s", connection_get_pid(engine
->conn
), engine
->currentRightName
); 
 866             return errAuthorizationSuccess
; 
 870     if (rule_check_flags(rule
, RuleFlagRequireAppleSigned
)) { 
 871         if (!auth_token_apple_signed(engine
->auth
)) { 
 872             LOGE("engine[%i]: rule deny, creator of authorization is not signed by apple", connection_get_pid(engine
->conn
)); 
 873             return errAuthorizationDenied
; 
 877         *save_pwd 
|= rule_get_extract_password(rule
); 
 879     switch (rule_get_class(rule
)) { 
 881             LOGV("engine[%i]: rule set to allow", connection_get_pid(engine
->conn
)); 
 882             return errAuthorizationSuccess
; 
 884             LOGV("engine[%i]: rule set to deny", connection_get_pid(engine
->conn
)); 
 885             return errAuthorizationDenied
; 
 887             return _evaluate_class_user(engine
, rule
); 
 889             return _evaluate_class_rule(engine
, rule
, save_pwd
); 
 891             return _evaluate_class_mechanism(engine
, rule
); 
 893             LOGE("engine[%i]: invalid class for rule or rule not found", connection_get_pid(engine
->conn
)); 
 894             return errAuthorizationInternal
; 
 899 _find_rule(engine_t engine
, authdb_connection_t dbconn
, const char * string
) 
 902     size_t sLen 
= strlen(string
); 
 904     char * buf 
= calloc(1u, sLen 
+ 1); 
 905     strlcpy(buf
, string
, sLen 
+ 1); 
 906     char * ptr 
= buf 
+ sLen
; 
 907     __block 
int64_t count 
= 0; 
 912         authdb_step(dbconn
, "SELECT COUNT(name) AS cnt FROM rules WHERE name = ? AND type = 1", 
 913         ^(sqlite3_stmt 
*stmt
) { 
 914             sqlite3_bind_text(stmt
, 1, buf
, -1, NULL
); 
 915         }, ^bool(auth_items_t data
) { 
 916             count 
= auth_items_get_int64(data
, "cnt"); 
 921             r 
= rule_create_with_string(buf
, dbconn
); 
 925         // if buf ends with a . and we didn't find a rule remove . 
 929         // find any remaining . and truncate the string 
 930         ptr 
= strrchr(buf
, '.'); 
 941     // set default if we didn't find a rule 
 943         r 
= rule_create_with_string("", dbconn
); 
 944         if (rule_get_id(r
) == 0) { 
 946             LOGE("engine[%i]: default rule lookup error (missing), using builtin defaults", connection_get_pid(engine
->conn
)); 
 947             r 
= rule_create_default(); 
 953 static void _parse_environment(engine_t engine
, auth_items_t environment
) 
 955     require(environment 
!= NULL
, done
); 
 958     LOGV("engine[%i]: Dumping Environment", connection_get_pid(engine
->conn
)); 
 959     _show_cf(environment
); 
 962     // Check if a credential was passed into the environment and we were asked to extend the rights 
 963     if (engine
->flags 
& kAuthorizationFlagExtendRights
) { 
 964         const char * user 
= auth_items_get_string(environment
, kAuthorizationEnvironmentUsername
); 
 965         const char * pass 
= auth_items_get_string(environment
, kAuthorizationEnvironmentPassword
); 
 966         bool shared 
= auth_items_exist(environment
, kAuthorizationEnvironmentShared
); 
 967         require(user 
!= NULL
, done
); 
 969         struct passwd 
*pw 
= getpwnam(user
); 
 970         require_action(pw 
!= NULL
, done
, LOGE("engine[%i]: user not found %s", connection_get_pid(engine
->conn
), user
)); 
 972         int checkpw_status 
= checkpw_internal(pw
, pass 
? pass 
: ""); 
 973         require_action(checkpw_status 
== CHECKPW_SUCCESS
, done
, LOGE("engine[%i]: checkpw() returned %d; failed to authenticate user %s (uid %u).", connection_get_pid(engine
->conn
), checkpw_status
, pw
->pw_name
, pw
->pw_uid
)); 
 975         credential_t cred 
= credential_create(pw
->pw_uid
); 
 976         if (credential_get_valid(cred
)) { 
 977             LOG("engine[%i]: checkpw() succeeded, creating credential for user %s", connection_get_pid(engine
->conn
), user
); 
 978             _engine_set_credential(engine
, cred
, shared
); 
 980             auth_items_set_string(engine
->context
, kAuthorizationEnvironmentUsername
, user
); 
 981             auth_items_set_string(engine
->context
, kAuthorizationEnvironmentPassword
, pass 
? pass 
: ""); 
 991 static bool _verify_sandbox(engine_t engine
, const char * right
) 
 993     pid_t pid 
= process_get_pid(engine
->proc
); 
 994     if (sandbox_check(pid
, "authorization-right-obtain", SANDBOX_FILTER_RIGHT_NAME
, right
)) { 
 995         LOGE("Sandbox denied authorizing right '%s' by client '%s' [%d]", right
, process_get_code_url(engine
->proc
), pid
); 
 999     pid 
= auth_token_get_pid(engine
->auth
); 
1000     if (auth_token_get_sandboxed(engine
->auth
) && sandbox_check(pid
, "authorization-right-obtain", SANDBOX_FILTER_RIGHT_NAME
, right
)) { 
1001         LOGE("Sandbox denied authorizing right '%s' for authorization created by '%s' [%d]", right
, auth_token_get_code_url(engine
->auth
), pid
); 
1009 #pragma mark engine methods 
1011 OSStatus 
engine_authorize(engine_t engine
, auth_rights_t rights
, auth_items_t environment
, AuthorizationFlags flags
) 
1013     __block OSStatus status 
= errAuthorizationSuccess
; 
1014     __block 
bool savePassword 
= false; 
1015     ccaudit_t ccaudit 
= NULL
; 
1017     require(rights 
!= NULL
, done
); 
1019     ccaudit 
= ccaudit_create(engine
->proc
, engine
->auth
, AUE_ssauthorize
); 
1020     if (auth_rights_get_count(rights
) > 0) { 
1021         ccaudit_log(ccaudit
, "begin evaluation", NULL
, 0); 
1024     engine
->flags 
= flags
; 
1027         _parse_environment(engine
, environment
); 
1028         auth_items_copy(engine
->hints
, environment
); 
1031     auth_items_copy(engine
->context
, auth_token_get_context(engine
->auth
)); 
1033     engine
->dismissed 
= false; 
1034     auth_rights_clear(engine
->grantedRights
); 
1036     auth_rights_iterate(rights
, ^bool(const char *key
) { 
1041         if (!_verify_sandbox(engine
, key
)) { // _verify_sandbox is already logging failures 
1042             status 
= errAuthorizationDenied
; 
1046         authdb_connection_t dbconn 
= authdb_connection_acquire(server_get_database()); // get db handle 
1048         LOGV("engine[%i]: evaluate right %s", connection_get_pid(engine
->conn
), key
); 
1049         rule_t rule 
= _find_rule(engine
, dbconn
, key
); 
1050         const char * rule_name 
= rule_get_name(rule
); 
1051         if (rule_name 
&& (strcasecmp(rule_name
, "") == 0)) { 
1052             rule_name 
= "default (not defined)"; 
1054         LOGV("engine[%i]: using rule %s", connection_get_pid(engine
->conn
), rule_name
); 
1056         // only need the hints & mechanisms if we are going to show ui 
1057         if (engine
->flags 
& kAuthorizationFlagInteractionAllowed
) { 
1058             _set_right_hints(engine
->hints
, key
); 
1059             _set_localization_hints(dbconn
, engine
->hints
, rule
); 
1060             if (!engine
->authenticateRule
) { 
1061                 engine
->authenticateRule 
= rule_create_with_string("authenticate", dbconn
); 
1065         authdb_connection_release(&dbconn
); // release db handle 
1067         engine
->currentRightName 
= key
; 
1068         engine
->currentRule 
= rule
; 
1070         ccaudit_log(ccaudit
, key
, rule_name
, 0); 
1072         status 
= _evaluate_rule(engine
, engine
->currentRule
, &savePassword
); 
1074             case errAuthorizationSuccess
: 
1075                 auth_rights_add(engine
->grantedRights
, key
); 
1076                 auth_rights_set_flags(engine
->grantedRights
, key
, auth_rights_get_flags(rights
,key
)); 
1078                 if ((engine
->flags 
& kAuthorizationFlagPreAuthorize
) && 
1079                     (rule_get_class(engine
->currentRule
) == RC_USER
) && 
1080                     (rule_get_timeout(engine
->currentRule
) == 0)) { 
1081                     // FIXME: kAuthorizationFlagPreAuthorize => kAuthorizationFlagCanNotPreAuthorize ??? 
1082                     auth_rights_set_flags(engine
->grantedRights
, engine
->currentRightName
, kAuthorizationFlagPreAuthorize
); 
1085                 LOG("Succeeded authorizing right '%s' by client '%s' [%d] for authorization created by '%s' [%d] (%X,%d)", 
1086                     key
, process_get_code_url(engine
->proc
), process_get_pid(engine
->proc
), 
1087                     auth_token_get_code_url(engine
->auth
), auth_token_get_pid(engine
->auth
), (unsigned int)engine
->flags
, auth_token_least_privileged(engine
->auth
)); 
1089             case errAuthorizationDenied
: 
1090             case errAuthorizationInteractionNotAllowed
: 
1091             case errAuthorizationCanceled
: 
1092                 if (engine
->flags 
& kAuthorizationFlagInteractionAllowed
) { 
1093                     LOG("Failed to authorize right '%s' by client '%s' [%d] for authorization created by '%s' [%d] (%X,%d) (%i)", 
1094                         key
, process_get_code_url(engine
->proc
), process_get_pid(engine
->proc
), 
1095                         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
); 
1097                     LOGV("Failed to authorize right '%s' by client '%s' [%d] for authorization created by '%s' [%d] (%X,%d) (%d)", 
1098                         key
, process_get_code_url(engine
->proc
), process_get_pid(engine
->proc
), 
1099                         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
); 
1103                 LOGE("engine[%i]: evaluate returned %d returning errAuthorizationInternal", connection_get_pid(engine
->conn
), (int)status
); 
1104                 status 
= errAuthorizationInternal
; 
1108         ccaudit_log_authorization(ccaudit
, engine
->currentRightName
, status
); 
1110         CFReleaseSafe(rule
); 
1111         engine
->currentRightName 
= NULL
; 
1112         engine
->currentRule 
= NULL
; 
1114         auth_items_remove_with_flags(engine
->hints
, kEngineHintsFlagTemporary
); 
1116         if (!(engine
->flags 
& kAuthorizationFlagPartialRights
) && (status 
!= errAuthorizationSuccess
)) { 
1123     if ((engine
->flags 
& kAuthorizationFlagPartialRights
) && (auth_rights_get_count(engine
->grantedRights
) > 0)) { 
1124         status 
= errAuthorizationSuccess
; 
1127     if (engine
->dismissed
) { 
1128                 LOGE("engine[%i]: engine dismissed"); 
1129         status 
= errAuthorizationDenied
; 
1132     LOGV("engine[%i]: authorize result: %d", connection_get_pid(engine
->conn
), (int)status
); 
1134     if ((engine
->flags 
& kAuthorizationFlagExtendRights
) && !(engine
->flags 
& kAuthorizationFlagDestroyRights
)) { 
1135         _cf_set_iterate(engine
->credentials
, ^bool(CFTypeRef value
) { 
1136             credential_t cred 
= (credential_t
)value
; 
1137             // skip all uid credentials when running in least privileged 
1138             if (auth_token_least_privileged(engine
->auth
) && !credential_is_right(cred
)) 
1141             session_t session 
= auth_token_get_session(engine
->auth
); 
1142             auth_token_set_credential(engine
->auth
, cred
); 
1143             if (credential_get_shared(cred
)) { 
1144                 session_set_credential(session
, cred
); 
1146             if (credential_is_right(cred
)) { 
1147                 LOGV("engine[%i]: adding least privileged %scredential %s to authorization", connection_get_pid(engine
->conn
), credential_get_shared(cred
) ? "shared " : "", credential_get_name(cred
)); 
1149                 LOGV("engine[%i]: adding %scredential %s (%i) to authorization", connection_get_pid(engine
->conn
), credential_get_shared(cred
) ? "shared " : "", credential_get_name(cred
), credential_get_uid(cred
)); 
1155     if (status 
== errAuthorizationSuccess 
&& savePassword
) { 
1156         auth_items_set_flags(engine
->context
, kAuthorizationEnvironmentPassword
, kAuthorizationContextFlagExtractable
); 
1159     if ((status 
== errAuthorizationSuccess
) || (status 
== errAuthorizationCanceled
)) { 
1160         auth_items_copy_with_flags(auth_token_get_context(engine
->auth
), engine
->context
, kAuthorizationContextFlagExtractable
); 
1163     if (auth_rights_get_count(rights
) > 0) { 
1164         ccaudit_log(ccaudit
, "end evaluation", NULL
, status
); 
1168     LOGV("engine[%i]: ********** Dumping auth->credentials **********", connection_get_pid(engine
->conn
)); 
1169     auth_token_credentials_iterate(engine
->auth
, ^bool(credential_t cred
) { 
1173     LOGV("engine[%i]: ********** Dumping session->credentials **********", connection_get_pid(engine
->conn
)); 
1174     session_credentials_iterate(auth_token_get_session(engine
->auth
), ^bool(credential_t cred
) { 
1178     LOGV("engine[%i]: ********** Dumping engine->context **********", connection_get_pid(engine
->conn
)); 
1179     _show_cf(engine
->context
); 
1180     LOGV("engine[%i]: ********** Dumping auth->context **********", connection_get_pid(engine
->conn
)); 
1181     _show_cf(auth_token_get_context(engine
->auth
)); 
1182     LOGV("engine[%i]: ********** Dumping granted rights **********", connection_get_pid(engine
->conn
)); 
1183     _show_cf(engine
->grantedRights
); 
1187     auth_items_clear(engine
->context
); 
1188     auth_items_clear(engine
->sticky_context
); 
1189     CFReleaseSafe(ccaudit
); 
1190     CFDictionaryRemoveAllValues(engine
->mechanism_agents
); 
1196 _wildcard_right_exists(engine_t engine
, const char * right
) 
1198     // checks if a wild card right exists 
1199     // ex: com.apple. system. 
1200     bool exists 
= false; 
1202     authdb_connection_t dbconn 
= authdb_connection_acquire(server_get_database()); // get db handle 
1203     require(dbconn 
!= NULL
, done
); 
1205     rule 
= _find_rule(engine
, dbconn
, right
); 
1206     require(rule 
!= NULL
, done
); 
1208     const char * ruleName 
= rule_get_name(rule
); 
1209     require(ruleName 
!= NULL
, done
); 
1210     size_t len 
= strlen(ruleName
); 
1211     require(len 
!= 0, done
); 
1213     if (ruleName
[len
-1] == '.') { 
1219     authdb_connection_release(&dbconn
); 
1220     CFReleaseSafe(rule
); 
1225 // Validate db right modification 
1227 // meta rights are constructed as follows: 
1228 // we don't allow setting of wildcard rights, so you can only be more specific 
1229 // note that you should never restrict things with a wildcard right without disallowing 
1230 // changes to the entire domain.  ie. 
1231 //              system.privilege.               -> never 
1232 //              config.add.system.privilege.    -> never 
1233 //              config.modify.system.privilege. -> never 
1234 //              config.delete.system.privilege. -> never 
1235 // For now we don't allow any configuration of configuration rules 
1236 //              config.config. -> never 
1238 OSStatus 
engine_verify_modification(engine_t engine
, rule_t rule
, bool remove
, bool force_modify
) 
1240     OSStatus status 
= errAuthorizationDenied
; 
1241     auth_rights_t checkRight 
= NULL
; 
1243     memset(buf
, 0, sizeof(buf
)); 
1245     const char * right 
= rule_get_name(rule
); 
1246     require(right 
!= NULL
, done
); 
1247     size_t len 
= strlen(right
); 
1248     require(len 
!= 0, done
); 
1250     require_action(right
[len
-1] != '.', done
, LOGE("engine[%i]: not allowed to set wild card rules", connection_get_pid(engine
->conn
))); 
1252     if (strncasecmp(right
, kConfigRight
, strlen(kConfigRight
)) == 0) { 
1253         // special handling of meta right change: 
1254                 // config.add. config.modify. config.remove. config.{}. 
1255                 // check for config.<right> (which always starts with config.config.) 
1256         strlcat(buf
, kConfigRight
, sizeof(buf
)); 
1258         bool existing 
= (rule_get_id(rule
) != 0) ? true : _wildcard_right_exists(engine
, right
); 
1260             if (existing 
|| force_modify
) { 
1261                 strlcat(buf
, kAuthorizationConfigRightModify
,sizeof(buf
)); 
1263                 strlcat(buf
, kAuthorizationConfigRightAdd
, sizeof(buf
)); 
1267                 strlcat(buf
, kAuthorizationConfigRightRemove
, sizeof(buf
)); 
1269                 status 
= errAuthorizationSuccess
; 
1275     strlcat(buf
, right
, sizeof(buf
)); 
1277     checkRight 
= auth_rights_create(); 
1278     auth_rights_add(checkRight
, buf
); 
1279     status 
= engine_authorize(engine
, checkRight
, NULL
, kAuthorizationFlagDefaults 
| kAuthorizationFlagInteractionAllowed 
| kAuthorizationFlagExtendRights
); 
1282     LOGV("engine[%i]: authorizing %s for db modification: %d", connection_get_pid(engine
->conn
), right
, (int)status
); 
1283     CFReleaseSafe(checkRight
); 
1288 _engine_set_credential(engine_t engine
, credential_t cred
, bool shared
) 
1290     LOGV("engine[%i]: adding %scredential %s (%i) to engine shared: %i", connection_get_pid(engine
->conn
), credential_get_shared(cred
) ? "shared " : "", credential_get_name(cred
), credential_get_uid(cred
), shared
); 
1291     CFSetSetValue(engine
->credentials
, cred
); 
1293         credential_t sharedCred 
= credential_create_with_credential(cred
, true); 
1294         CFSetSetValue(engine
->credentials
, sharedCred
); 
1295         CFReleaseSafe(sharedCred
); 
1300 engine_get_granted_rights(engine_t engine
) 
1302     return engine
->grantedRights
; 
1305 CFAbsoluteTime 
engine_get_time(engine_t engine
) 
1310 void engine_destroy_agents(engine_t engine
) 
1312     engine
->dismissed 
= true; 
1314     _cf_dictionary_iterate(engine
->mechanism_agents
, ^bool(CFTypeRef key 
__attribute__((__unused__
)), CFTypeRef value
) { 
1315         LOGD("engine[%i]: Destroying %s", connection_get_pid(engine
->conn
), mechanism_get_string((mechanism_t
)key
)); 
1316         agent_t agent 
= (agent_t
)value
; 
1317         agent_destroy(agent
); 
1323 void engine_interrupt_agent(engine_t engine
) 
1325     _cf_dictionary_iterate(engine
->mechanism_agents
, ^bool(CFTypeRef key 
__attribute__((__unused__
)), CFTypeRef value
) { 
1326         agent_t agent 
= (agent_t
)value
; 
1327         agent_notify_interrupt(agent
);