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 *);
33 static bool _preevaluate_class_rule(engine_t engine
, rule_t rule
);
34 static bool _preevaluate_rule(engine_t engine
, rule_t rule
);
37 kEngineHintsFlagTemporary
= (1 << 30)
41 #pragma mark engine creation
44 __AUTH_BASE_STRUCT_HEADER__
;
50 AuthorizationFlags flags
;
53 auth_items_t sticky_context
;
54 auth_items_t immutable_hints
;
56 auth_rights_t grantedRights
;
63 credential_t sessionCredential
;
64 CFMutableSetRef credentials
;
65 CFMutableSetRef effectiveCredentials
;
67 CFMutableDictionaryRef mechanism_agents
;
69 // set only in engine_authorize
70 const char * currentRightName
; // weak ref
71 rule_t currentRule
; // weak ref
73 rule_t authenticateRule
;
79 _engine_finalizer(CFTypeRef value
)
81 engine_t engine
= (engine_t
)value
;
83 CFReleaseSafe(engine
->mechanism_agents
);
84 CFReleaseSafe(engine
->conn
);
85 CFReleaseSafe(engine
->auth
);
86 CFReleaseSafe(engine
->hints
);
87 CFReleaseSafe(engine
->context
);
88 CFReleaseSafe(engine
->immutable_hints
);
89 CFReleaseSafe(engine
->sticky_context
);
90 CFReleaseSafe(engine
->grantedRights
);
91 CFReleaseSafe(engine
->sessionCredential
);
92 CFReleaseSafe(engine
->credentials
);
93 CFReleaseSafe(engine
->effectiveCredentials
);
94 CFReleaseSafe(engine
->authenticateRule
);
97 AUTH_TYPE_INSTANCE(engine
,
100 .finalize
= _engine_finalizer
,
103 .copyFormattingDesc
= NULL
,
104 .copyDebugDesc
= NULL
107 static CFTypeID
engine_get_type_id() {
108 static CFTypeID type_id
= _kCFRuntimeNotATypeID
;
109 static dispatch_once_t onceToken
;
111 dispatch_once(&onceToken
, ^{
112 type_id
= _CFRuntimeRegisterClass(&_auth_type_engine
);
119 engine_create(connection_t conn
, auth_token_t auth
)
121 engine_t engine
= NULL
;
122 require(conn
!= NULL
, done
);
123 require(auth
!= NULL
, done
);
125 engine
= (engine_t
)_CFRuntimeCreateInstance(kCFAllocatorDefault
, engine_get_type_id(), AUTH_CLASS_SIZE(engine
), NULL
);
126 require(engine
!= NULL
, done
);
128 engine
->conn
= (connection_t
)CFRetain(conn
);
129 engine
->proc
= connection_get_process(conn
);
130 engine
->auth
= (auth_token_t
)CFRetain(auth
);
132 engine
->hints
= auth_items_create();
133 engine
->context
= auth_items_create();
134 engine
->immutable_hints
= auth_items_create();
135 engine
->sticky_context
= auth_items_create();
136 _set_process_hints(engine
->hints
, engine
->proc
);
137 _set_process_immutable_hints(engine
->immutable_hints
, engine
->proc
);
138 _set_auth_token_hints(engine
->hints
, auth
);
140 engine
->grantedRights
= auth_rights_create();
142 engine
->reason
= noReason
;
144 engine
->now
= CFAbsoluteTimeGetCurrent();
146 session_update(auth_token_get_session(engine
->auth
));
147 engine
->sessionCredential
= credential_create(session_get_uid(auth_token_get_session(engine
->auth
)));
148 engine
->credentials
= CFSetCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeSetCallBacks
);
149 engine
->effectiveCredentials
= CFSetCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeSetCallBacks
);
151 session_credentials_iterate(auth_token_get_session(engine
->auth
), ^bool(credential_t cred
) {
152 CFSetAddValue(engine
->effectiveCredentials
, cred
);
156 auth_token_credentials_iterate(engine
->auth
, ^bool(credential_t cred
) {
157 // we added all session credentials already now just add all previously acquired credentials
158 if (!credential_get_shared(cred
)) {
159 CFSetAddValue(engine
->credentials
, cred
);
164 engine
->mechanism_agents
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
171 #pragma mark agent hints
174 _set_process_hints(auth_items_t hints
, process_t proc
)
176 // process information
177 RequestorType type
= bundle
;
178 auth_items_set_data(hints
, AGENT_HINT_CLIENT_TYPE
, &type
, sizeof(type
));
179 auth_items_set_int(hints
, AGENT_HINT_CLIENT_PID
, process_get_pid(proc
));
180 auth_items_set_uint(hints
, AGENT_HINT_CLIENT_UID
, process_get_uid(proc
));
184 _set_process_immutable_hints(auth_items_t immutable_hints
, process_t proc
)
186 // process information - immutable
187 auth_items_set_bool(immutable_hints
, AGENT_HINT_PROCESS_SIGNED
, process_apple_signed(proc
));
188 auth_items_set_bool(immutable_hints
, AGENT_HINT_PROCESS_FROM_APPLE
, process_firstparty_signed(proc
));
192 _set_auth_token_hints(auth_items_t hints
, auth_token_t auth
)
194 auth_items_set_string(hints
, AGENT_HINT_CLIENT_PATH
, auth_token_get_code_url(auth
));
195 auth_items_set_int(hints
, AGENT_HINT_CREATOR_PID
, auth_token_get_pid(auth
));
196 const audit_info_s
* info
= auth_token_get_audit_info(auth
);
197 auth_items_set_data(hints
, AGENT_HINT_CREATOR_AUDIT_TOKEN
, &info
->opaqueToken
, sizeof(info
->opaqueToken
));
201 _set_right_hints(auth_items_t hints
, const char * right
)
203 auth_items_set_string(hints
, AGENT_HINT_AUTHORIZE_RIGHT
, right
);
207 _set_rule_hints(auth_items_t hints
, rule_t rule
)
209 auth_items_set_string(hints
, AGENT_HINT_AUTHORIZE_RULE
, rule_get_name(rule
));
210 const char * group
= rule_get_group(rule
);
211 if (rule_get_class(rule
) == RC_USER
&& group
!= NULL
) {
212 auth_items_set_string(hints
, AGENT_HINT_REQUIRE_USER_IN_GROUP
, group
);
214 auth_items_remove(hints
, AGENT_HINT_REQUIRE_USER_IN_GROUP
);
219 _set_localization_hints(authdb_connection_t dbconn
, auth_items_t hints
, rule_t rule
)
221 char * key
= calloc(1u, 128);
223 authdb_step(dbconn
, "SELECT lang,value FROM prompts WHERE r_id = ?", ^(sqlite3_stmt
*stmt
) {
224 sqlite3_bind_int64(stmt
, 1, rule_get_id(rule
));
225 }, ^bool(auth_items_t data
) {
226 snprintf(key
, 128, "%s%s", kAuthorizationRuleParameterDescription
, auth_items_get_string(data
, "lang"));
227 auth_items_set_string(hints
, key
, auth_items_get_string(data
, "value"));
228 auth_items_set_flags(hints
, key
, kEngineHintsFlagTemporary
);
232 authdb_step(dbconn
, "SELECT lang,value FROM buttons WHERE r_id = ?", ^(sqlite3_stmt
*stmt
) {
233 sqlite3_bind_int64(stmt
, 1, rule_get_id(rule
));
234 }, ^bool(auth_items_t data
) {
235 snprintf(key
, 128, "%s%s", kAuthorizationRuleParameterButton
, auth_items_get_string(data
, "lang"));
236 auth_items_set_string(hints
, key
, auth_items_get_string(data
, "value"));
237 auth_items_set_flags(hints
, key
, kEngineHintsFlagTemporary
);
245 _set_session_hints(engine_t engine
, rule_t rule
)
247 LOGV("engine[%i]: ** prepare agent hints for rule %s", connection_get_pid(engine
->conn
), rule_get_name(rule
));
248 if (_evaluate_user_credential_for_rule(engine
, engine
->sessionCredential
, rule
, true, true, NULL
) == errAuthorizationSuccess
) {
249 const char * tmp
= credential_get_name(engine
->sessionCredential
);
251 auth_items_set_string(engine
->hints
, AGENT_HINT_SUGGESTED_USER
, tmp
);
253 tmp
= credential_get_realname(engine
->sessionCredential
);
255 auth_items_set_string(engine
->hints
, AGENT_HINT_SUGGESTED_USER_LONG
, tmp
);
258 auth_items_remove(engine
->hints
, AGENT_HINT_SUGGESTED_USER
);
259 auth_items_remove(engine
->hints
, AGENT_HINT_SUGGESTED_USER_LONG
);
264 #pragma mark right processing
267 _evaluate_credential_for_rule(engine_t engine
, credential_t cred
, rule_t rule
, bool ignoreShared
, bool sessionOwner
, enum Reason
* reason
)
269 if (auth_token_least_privileged(engine
->auth
)) {
270 if (credential_is_right(cred
) && credential_get_valid(cred
) && _compare_string(engine
->currentRightName
, credential_get_name(cred
))) {
272 if (!rule_get_shared(rule
) && credential_get_shared(cred
)) {
273 LOGV("engine[%i]: - shared right %s (does NOT satisfy rule)", connection_get_pid(engine
->conn
), credential_get_name(cred
));
274 if (reason
) { *reason
= unknownReason
; }
275 return errAuthorizationDenied
;
279 return errAuthorizationSuccess
;
281 if (reason
) { *reason
= unknownReason
; }
282 return errAuthorizationDenied
;
285 return _evaluate_user_credential_for_rule(engine
,cred
,rule
,ignoreShared
,sessionOwner
, reason
);
290 _evaluate_user_credential_for_rule(engine_t engine
, credential_t cred
, rule_t rule
, bool ignoreShared
, bool sessionOwner
, enum Reason
* reason
)
292 const char * cred_label
= sessionOwner
? "session owner" : "credential";
293 LOGV("engine[%i]: - validating %s%s %s (%i) for %s", connection_get_pid(engine
->conn
),
294 credential_get_shared(cred
) ? "shared " : "",
296 credential_get_name(cred
),
297 credential_get_uid(cred
),
298 rule_get_name(rule
));
300 if (rule_get_class(rule
) != RC_USER
) {
301 LOGV("engine[%i]: - invalid rule class %i (denied)", connection_get_pid(engine
->conn
), rule_get_class(rule
));
302 return errAuthorizationDenied
;
305 if (credential_get_valid(cred
) != true) {
306 LOGV("engine[%i]: - %s %i invalid (does NOT satisfy rule)", connection_get_pid(engine
->conn
), cred_label
, credential_get_uid(cred
));
307 if (reason
) { *reason
= invalidPassphrase
; }
308 return errAuthorizationDenied
;
311 if (engine
->now
- credential_get_creation_time(cred
) > rule_get_timeout(rule
)) {
312 LOGV("engine[%i]: - %s %i expired '%f > %lli' (does NOT satisfy rule)", connection_get_pid(engine
->conn
), cred_label
, credential_get_uid(cred
),
313 (engine
->now
- credential_get_creation_time(cred
)), rule_get_timeout(rule
));
314 if (reason
) { *reason
= unknownReason
; }
315 return errAuthorizationDenied
;
320 if (!rule_get_shared(rule
) && credential_get_shared(cred
)) {
321 LOGV("engine[%i]: - shared %s %i (does NOT satisfy rule)", connection_get_pid(engine
->conn
), cred_label
, credential_get_uid(cred
));
322 if (reason
) { *reason
= unknownReason
; }
323 return errAuthorizationDenied
;
327 if (credential_get_uid(cred
) == 0) {
328 LOGV("engine[%i]: - %s %i has uid 0 (does satisfy rule)", connection_get_pid(engine
->conn
), cred_label
, credential_get_uid(cred
));
329 return errAuthorizationSuccess
;
332 if (rule_get_session_owner(rule
)) {
333 if (credential_get_uid(cred
) == session_get_uid(auth_token_get_session(engine
->auth
))) {
334 LOGV("engine[%i]: - %s %i is session owner (does satisfy rule)", connection_get_pid(engine
->conn
), cred_label
, credential_get_uid(cred
));
335 return errAuthorizationSuccess
;
339 if (rule_get_group(rule
) != NULL
) {
342 // This allows testing a group modifier without prompting the user
343 // When (authenticate-user = false) we are just testing the creator uid.
344 // If a group modifier is enabled (RuleFlagEntitledAndGroup | RuleFlagVPNEntitledAndGroup)
345 // we want to skip the creator uid group check.
346 // group modifiers are checked early during the evaluation in _check_entitlement_for_rule
347 if (!rule_get_authenticate_user(rule
)) {
348 if (rule_check_flags(rule
, RuleFlagEntitledAndGroup
| RuleFlagVPNEntitledAndGroup
)) {
353 if (credential_check_membership(cred
, rule_get_group(rule
))) {
354 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
));
355 return errAuthorizationSuccess
;
357 if (reason
) { *reason
= userNotInGroup
; }
360 } else if (rule_get_session_owner(rule
)) { // rule asks only if user is the session owner
361 if (reason
) { *reason
= unacceptableUser
; }
364 LOGV("engine[%i]: - %s %i (does NOT satisfy rule)", connection_get_pid(engine
->conn
), cred_label
, credential_get_uid(cred
));
365 return errAuthorizationDenied
;
369 _get_agent(engine_t engine
, mechanism_t mech
, bool create
, bool firstMech
)
371 agent_t agent
= (agent_t
)CFDictionaryGetValue(engine
->mechanism_agents
, mech
);
372 if (create
&& !agent
) {
373 agent
= agent_create(engine
, mech
, engine
->auth
, engine
->proc
, firstMech
);
375 CFDictionaryAddValue(engine
->mechanism_agents
, mech
, agent
);
376 CFReleaseSafe(agent
);
383 _evaluate_builtin_mechanism(engine_t engine
, mechanism_t mech
)
385 uint64_t result
= kAuthorizationResultDeny
;
387 switch (mechanism_get_type(mech
)) {
388 case kMechanismTypeEntitled
:
389 if (auth_token_has_entitlement_for_right(engine
->auth
, engine
->currentRightName
)) {
390 result
= kAuthorizationResultAllow
;
402 _evaluate_mechanisms(engine_t engine
, CFArrayRef mechanisms
)
404 uint64_t result
= kAuthorizationResultAllow
;
405 ccaudit_t ccaudit
= ccaudit_create(engine
->proc
, engine
->auth
, AUE_ssauthmech
);
406 auth_items_t context
= auth_items_create();
407 auth_items_t hints
= auth_items_create();
409 auth_items_copy(context
, engine
->context
);
410 auth_items_copy(hints
, engine
->hints
);
411 auth_items_copy(context
, engine
->sticky_context
);
413 CFIndex count
= CFArrayGetCount(mechanisms
);
414 for (CFIndex i
= 0; i
< count
; i
++) {
415 mechanism_t mech
= (mechanism_t
)CFArrayGetValueAtIndex(mechanisms
, i
);
417 if (mechanism_get_type(mech
)) {
418 LOGV("engine[%i]: running builtin mechanism %s (%li of %li)", connection_get_pid(engine
->conn
), mechanism_get_string(mech
), i
+1, count
);
419 result
= _evaluate_builtin_mechanism(engine
, mech
);
421 agent_t agent
= _get_agent(engine
, mech
, true, i
== 0);
422 require_action(agent
!= NULL
, done
, result
= kAuthorizationResultUndefined
; LOGE("engine[%i]: error creating mechanism agent", connection_get_pid(engine
->conn
)));
424 // check if any agent has been interrupted (it necessary if interrupt will come during creation)
427 for (j
= 0; j
< i
; j
++) {
428 agent1
= _get_agent(engine
, (mechanism_t
)CFArrayGetValueAtIndex(mechanisms
, j
), false, j
== 0);
429 if(agent_get_state(agent1
) == interrupting
) {
434 LOGV("engine[%i]: mechanisms interrupted", connection_get_pid(engine
->conn
));
436 asprintf(&buf
, "evaluation interrupted by %s; restarting evaluation there", mechanism_get_string(agent_get_mechanism(agent1
)));
437 ccaudit_log_mechanism(ccaudit
, engine
->currentRightName
, mechanism_get_string(agent_get_mechanism(agent1
)), kAuthorizationResultAllow
, buf
);
439 ccaudit_log_mechanism(ccaudit
, engine
->currentRightName
, mechanism_get_string(mech
), kAuthorizationResultAllow
, NULL
);
440 const char * token_name
= auth_items_get_string(hints
, AGENT_HINT_TOKEN_NAME
);
441 if (token_name
&& strlen(token_name
) == 0) {
442 auth_items_remove(hints
, AGENT_HINT_TOKEN_NAME
);
444 auth_items_copy(context
, agent_get_context(agent1
));
445 auth_items_copy(hints
, agent_get_hints(agent1
));
452 LOGV("engine[%i]: running mechanism %s (%li of %li)", connection_get_pid(engine
->conn
), mechanism_get_string(agent_get_mechanism(agent
)), i
+1, count
);
453 result
= agent_run(agent
, hints
, context
, engine
->immutable_hints
);
455 auth_items_copy(context
, agent_get_context(agent
));
456 auth_items_copy(hints
, agent_get_hints(agent
));
458 bool interrupted
= false;
459 for (CFIndex i2
= 0; i2
!= i
; i2
++) {
460 agent_t agent2
= _get_agent(engine
, (mechanism_t
)CFArrayGetValueAtIndex(mechanisms
, i2
), false, i
== 0);
461 if (agent_get_state(agent2
) == interrupting
) {
462 agent_deactivate(agent
);
466 asprintf(&buf
, "evaluation interrupted by %s; restarting evaluation there", mechanism_get_string(agent_get_mechanism(agent2
)));
467 ccaudit_log_mechanism(ccaudit
, engine
->currentRightName
, mechanism_get_string(agent_get_mechanism(agent2
)), kAuthorizationResultAllow
, buf
);
469 auth_items_copy(context
, agent_get_context(agent2
));
470 auth_items_copy(hints
, agent_get_hints(agent2
));
475 // Empty token name means that token doesn't exist (e.g. SC was removed).
476 // Remove empty token name from hints for UI drawing logic.
477 const char * token_name
= auth_items_get_string(hints
, AGENT_HINT_TOKEN_NAME
);
478 if (token_name
&& strlen(token_name
) == 0) {
479 auth_items_remove(hints
, AGENT_HINT_TOKEN_NAME
);
483 LOGV("engine[%i]: mechanisms interrupted", connection_get_pid(engine
->conn
));
484 enum Reason reason
= worldChanged
;
485 auth_items_set_data(hints
, AGENT_HINT_RETRY_REASON
, &reason
, sizeof(reason
));
486 result
= kAuthorizationResultAllow
;
487 _cf_dictionary_iterate(engine
->mechanism_agents
, ^bool(CFTypeRef key
__attribute__((__unused__
)), CFTypeRef value
) {
488 agent_t tempagent
= (agent_t
)value
;
489 agent_clear_interrupt(tempagent
);
495 if (result
== kAuthorizationResultAllow
) {
496 ccaudit_log_mechanism(ccaudit
, engine
->currentRightName
, mechanism_get_string(mech
), kAuthorizationResultAllow
, NULL
);
498 ccaudit_log_mechanism(ccaudit
, engine
->currentRightName
, mechanism_get_string(mech
), (uint32_t)result
, NULL
);
504 if ((result
== kAuthorizationResultUserCanceled
) || (result
== kAuthorizationResultAllow
)) {
505 // only make non-sticky context values available externally
506 auth_items_set_flags(context
, kAuthorizationEnvironmentPassword
, kAuthorizationContextFlagVolatile
);
507 // <rdar://problem/16275827> Takauthorizationenvironmentusername should always be extractable
508 auth_items_set_flags(context
, kAuthorizationEnvironmentUsername
, kAuthorizationContextFlagExtractable
);
509 auth_items_copy_with_flags(engine
->context
, context
, kAuthorizationContextFlagExtractable
| kAuthorizationContextFlagVolatile
);
510 } else if (result
== kAuthorizationResultDeny
) {
511 auth_items_clear(engine
->sticky_context
);
512 // save off sticky values in context
513 auth_items_copy_with_flags(engine
->sticky_context
, context
, kAuthorizationContextFlagSticky
);
516 CFReleaseSafe(ccaudit
);
517 CFReleaseSafe(context
);
518 CFReleaseSafe(hints
);
522 case kAuthorizationResultDeny
:
523 return errAuthorizationDenied
;
524 case kAuthorizationResultUserCanceled
:
525 return errAuthorizationCanceled
;
526 case kAuthorizationResultAllow
:
527 return errAuthorizationSuccess
;
528 case kAuthorizationResultUndefined
:
529 return errAuthorizationInternal
;
532 LOGV("engine[%i]: unexpected error result", connection_get_pid(engine
->conn
));
533 return errAuthorizationInternal
;
539 _evaluate_authentication(engine_t engine
, rule_t rule
)
541 OSStatus status
= errAuthorizationDenied
;
542 ccaudit_t ccaudit
= ccaudit_create(engine
->proc
, engine
->auth
, AUE_ssauthint
);
543 LOGV("engine[%i]: evaluate authentication", connection_get_pid(engine
->conn
));
544 _set_rule_hints(engine
->hints
, rule
);
545 _set_session_hints(engine
, rule
);
547 CFArrayRef mechanisms
= rule_get_mechanisms(rule
);
548 if (!(CFArrayGetCount(mechanisms
) > 0)) {
549 mechanisms
= rule_get_mechanisms(engine
->authenticateRule
);
551 require_action(CFArrayGetCount(mechanisms
) > 0, done
, LOGV("engine[%i]: error no mechanisms found", connection_get_pid(engine
->conn
)));
553 int64_t ruleTries
= rule_get_tries(rule
);
554 for (engine
->tries
= 0; engine
->tries
< ruleTries
; engine
->tries
++) {
556 auth_items_set_data(engine
->hints
, AGENT_HINT_RETRY_REASON
, &engine
->reason
, sizeof(engine
->reason
));
557 auth_items_set_int(engine
->hints
, AGENT_HINT_TRIES
, engine
->tries
);
558 status
= _evaluate_mechanisms(engine
, mechanisms
);
560 LOGV("engine[%i]: evaluate mechanisms result %d", connection_get_pid(engine
->conn
), (int)status
);
562 // successfully ran mechanisms to obtain credential
563 if (status
== errAuthorizationSuccess
) {
564 // deny is the default
565 status
= errAuthorizationDenied
;
567 credential_t newCred
= NULL
;
568 if (auth_items_exist(engine
->context
, "uid")) {
569 newCred
= credential_create(auth_items_get_uint(engine
->context
, "uid"));
571 LOGV("engine[%i]: mechanism failed to return a valid uid", connection_get_pid(engine
->conn
));
575 if (credential_get_valid(newCred
)) {
576 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
);
577 ccaudit_log_success(ccaudit
, newCred
, engine
->currentRightName
);
579 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
);
580 ccaudit_log_failure(ccaudit
, auth_items_get_string(engine
->context
, "username"), engine
->currentRightName
);
583 status
= _evaluate_user_credential_for_rule(engine
, newCred
, rule
, true, false, &engine
->reason
);
585 if (status
== errAuthorizationSuccess
) {
586 _engine_set_credential(engine
, newCred
, rule_get_shared(rule
));
587 CFReleaseSafe(newCred
);
589 if (auth_token_least_privileged(engine
->auth
)) {
590 credential_t rightCred
= credential_create_with_right(engine
->currentRightName
);
591 _engine_set_credential(engine
, rightCred
, rule_get_shared(rule
));
592 CFReleaseSafe(rightCred
);
595 session_t session
= auth_token_get_session(engine
->auth
);
596 if (credential_get_uid(newCred
) == session_get_uid(session
)) {
597 LOGV("engine[%i]: authenticated as the session owner", connection_get_pid(engine
->conn
));
598 session_set_attributes(auth_token_get_session(engine
->auth
), AU_SESSION_FLAG_HAS_AUTHENTICATED
);
604 CFReleaseSafe(newCred
);
607 } else if (status
== errAuthorizationCanceled
|| status
== errAuthorizationInternal
) {
609 } else if (status
== errAuthorizationDenied
) {
610 engine
->reason
= invalidPassphrase
;
614 if (engine
->tries
== ruleTries
) {
615 engine
->reason
= tooManyTries
;
616 auth_items_set_data(engine
->hints
, AGENT_HINT_RETRY_REASON
, &engine
->reason
, sizeof(engine
->reason
));
617 auth_items_set_int(engine
->hints
, AGENT_HINT_TRIES
, engine
->tries
);
618 _evaluate_mechanisms(engine
, mechanisms
);
619 ccaudit_log(ccaudit
, engine
->currentRightName
, NULL
, 1113);
623 CFReleaseSafe(ccaudit
);
629 _check_entitlement_for_rule(engine_t engine
, rule_t rule
)
631 bool entitled
= false;
632 CFTypeRef value
= NULL
;
634 if (rule_check_flags(rule
, RuleFlagEntitledAndGroup
)) {
635 if (auth_token_has_entitlement_for_right(engine
->auth
, engine
->currentRightName
)) {
636 if (credential_check_membership(auth_token_get_credential(engine
->auth
), rule_get_group(rule
))) {
637 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
));
644 if (rule_check_flags(rule
, RuleFlagVPNEntitledAndGroup
)) {
645 // com.apple.networking.vpn.configuration is an array we only check for it's existence
646 value
= auth_token_copy_entitlement_value(engine
->auth
, "com.apple.networking.vpn.configuration");
648 if (credential_check_membership(auth_token_get_credential(engine
->auth
), rule_get_group(rule
))) {
649 LOGV("engine[%i]: creator of authorization has VPN entitlement and is member of group '%s'", connection_get_pid(engine
->conn
), rule_get_group(rule
));
657 CFReleaseSafe(value
);
662 _evaluate_class_user(engine_t engine
, rule_t rule
)
664 __block OSStatus status
= errAuthorizationDenied
;
666 if (_check_entitlement_for_rule(engine
,rule
)) {
667 return errAuthorizationSuccess
;
670 if (rule_get_allow_root(rule
) && auth_token_get_uid(engine
->auth
) == 0) {
671 LOGV("engine[%i]: creator of authorization has uid == 0 granting right %s", connection_get_pid(engine
->conn
), engine
->currentRightName
);
672 return errAuthorizationSuccess
;
675 if (!rule_get_authenticate_user(rule
)) {
676 status
= _evaluate_user_credential_for_rule(engine
, engine
->sessionCredential
, rule
, true, true, NULL
);
678 if (status
== errAuthorizationSuccess
) {
679 return errAuthorizationSuccess
;
682 return errAuthorizationDenied
;
685 // First -- check all the credentials we have either acquired or currently have
686 _cf_set_iterate(engine
->credentials
, ^bool(CFTypeRef value
) {
687 credential_t cred
= (credential_t
)value
;
688 // Passed-in user credentials are allowed for least-privileged mode
689 if (auth_token_least_privileged(engine
->auth
) && !credential_is_right(cred
) && credential_get_valid(cred
)) {
690 status
= _evaluate_user_credential_for_rule(engine
, cred
, rule
, false, false, NULL
);
691 if (errAuthorizationSuccess
== status
) {
692 credential_t rightCred
= credential_create_with_right(engine
->currentRightName
);
693 _engine_set_credential(engine
,rightCred
,rule_get_shared(rule
));
694 CFReleaseSafe(rightCred
);
695 return false; // exit loop
699 status
= _evaluate_credential_for_rule(engine
, cred
, rule
, false, false, NULL
);
700 if (status
== errAuthorizationSuccess
) {
701 return false; // exit loop
706 if (status
== errAuthorizationSuccess
) {
710 // Second -- go through the credentials associated to the authorization token session/auth token
711 _cf_set_iterate(engine
->effectiveCredentials
, ^bool(CFTypeRef value
) {
712 credential_t cred
= (credential_t
)value
;
713 status
= _evaluate_credential_for_rule(engine
, cred
, rule
, false, false, NULL
);
714 if (status
== errAuthorizationSuccess
) {
715 // Add the credential we used to the output set.
716 _engine_set_credential(engine
, cred
, false);
717 return false; // exit loop
722 if (status
== errAuthorizationSuccess
) {
726 // Finally - we didn't find a credential. Obtain a new credential if our flags let us do so.
727 if (!(engine
->flags
& kAuthorizationFlagExtendRights
)) {
728 LOGV("engine[%i]: authorization denied (kAuthorizationFlagExtendRights not set)", connection_get_pid(engine
->conn
));
729 return errAuthorizationDenied
;
732 // authorization that timeout immediately cannot be preauthorized
733 if (engine
->flags
& kAuthorizationFlagPreAuthorize
&& rule_get_timeout(rule
) == 0) {
734 return errAuthorizationSuccess
;
737 if (!(engine
->flags
& kAuthorizationFlagInteractionAllowed
)) {
738 LOGV("engine[%i]: Interaction not allowed (kAuthorizationFlagInteractionAllowed not set)", connection_get_pid(engine
->conn
));
739 return errAuthorizationInteractionNotAllowed
;
742 if (!(session_get_attributes(auth_token_get_session(engine
->auth
)) & AU_SESSION_FLAG_HAS_GRAPHIC_ACCESS
)) {
743 LOGV("engine[%i]: Interaction not allowed (session has no ui access)", connection_get_pid(engine
->conn
));
744 return errAuthorizationInteractionNotAllowed
;
747 if (server_in_dark_wake()) {
748 LOGV("engine[%i]: authorization denied (in DarkWake)", connection_get_pid(engine
->conn
));
749 return errAuthorizationDenied
;
752 return _evaluate_authentication(engine
, rule
);
756 _evaluate_class_rule(engine_t engine
, rule_t rule
, bool *save_pwd
)
758 __block OSStatus status
= errAuthorizationDenied
;
759 int64_t kofn
= rule_get_kofn(rule
);
761 uint32_t total
= (uint32_t)rule_get_delegates_count(rule
);
762 __block
uint32_t success_count
= 0;
763 __block
uint32_t count
= 0;
764 LOGV("engine[%i]: ** rule %s has %zi delegates kofn = %lli", connection_get_pid(engine
->conn
), rule_get_name(rule
), total
, kofn
);
765 rule_delegates_iterator(rule
, ^bool(rule_t delegate
) {
768 if (kofn
!= 0 && success_count
== kofn
) {
769 status
= errAuthorizationSuccess
;
773 LOGV("engine[%i]: * evaluate rule %s (%i)", connection_get_pid(engine
->conn
), rule_get_name(delegate
), count
);
774 status
= _evaluate_rule(engine
, delegate
, save_pwd
);
776 // if status is cancel/internal error abort
777 if ((status
== errAuthorizationCanceled
) || (status
== errAuthorizationInternal
))
780 if (status
!= errAuthorizationSuccess
) {
782 // if remaining is less than required abort
783 if ((total
- count
) < (kofn
- success_count
)) {
784 LOGD("engine[%i]: rule evaluation remaining: %i, required: %lli", connection_get_pid(engine
->conn
), (total
- count
), (kofn
- success_count
));
800 _preevaluate_class_rule(engine_t engine
, rule_t rule
)
802 LOGV("engine[%i]: _preevaluate_class_rule %s", connection_get_pid(engine
->conn
), rule_get_name(rule
));
804 __block
bool password_only
= false;
805 rule_delegates_iterator(rule
, ^bool(rule_t delegate
) {
806 if (_preevaluate_rule(engine
, delegate
)) {
807 password_only
= true;
813 return password_only
;
817 _evaluate_class_mechanism(engine_t engine
, rule_t rule
)
819 OSStatus status
= errAuthorizationDenied
;
820 CFArrayRef mechanisms
= NULL
;
822 require_action(rule_get_mechanisms_count(rule
) > 0, done
, status
= errAuthorizationSuccess
; LOGV("engine[%i]: no mechanisms specified", connection_get_pid(engine
->conn
)));
824 mechanisms
= rule_get_mechanisms(rule
);
826 if (server_in_dark_wake()) {
827 CFIndex count
= CFArrayGetCount(mechanisms
);
828 for (CFIndex i
= 0; i
< count
; i
++) {
829 if (!mechanism_is_privileged((mechanism_t
)CFArrayGetValueAtIndex(mechanisms
, i
))) {
830 LOGE("engine[%i]: authorization denied (in DW)", connection_get_pid(engine
->conn
));
836 int64_t ruleTries
= rule_get_tries(rule
);
839 auth_items_set_data(engine
->hints
, AGENT_HINT_RETRY_REASON
, &engine
->reason
, sizeof(engine
->reason
));
840 auth_items_set_int(engine
->hints
, AGENT_HINT_TRIES
, engine
->tries
);
842 status
= _evaluate_mechanisms(engine
, mechanisms
);
843 LOGV("engine[%i]: evaluate mechanisms result %d", connection_get_pid(engine
->conn
), (int)status
);
845 if (status
== errAuthorizationSuccess
) {
846 credential_t newCred
= NULL
;
847 if (auth_items_exist(engine
->context
, "uid")) {
848 newCred
= credential_create(auth_items_get_uint(engine
->context
, "uid"));
850 LOGV("engine[%i]: mechanism did not return a uid", connection_get_pid(engine
->conn
));
854 _engine_set_credential(engine
, newCred
, rule_get_shared(rule
));
856 if (auth_token_least_privileged(engine
->auth
)) {
857 credential_t rightCred
= credential_create_with_right(engine
->currentRightName
);
858 _engine_set_credential(engine
, rightCred
, rule_get_shared(rule
));
859 CFReleaseSafe(rightCred
);
862 if (strcmp(engine
->currentRightName
, "system.login.console") == 0 && !auth_items_exist(engine
->context
, AGENT_CONTEXT_AUTO_LOGIN
)) {
863 session_set_attributes(auth_token_get_session(engine
->auth
), AU_SESSION_FLAG_HAS_AUTHENTICATED
);
866 CFReleaseSafe(newCred
);
872 } while ( (status
== errAuthorizationDenied
) // only if we have an expected faulure we continue
873 && ((ruleTries
== 0) || ((ruleTries
> 0) && engine
->tries
< ruleTries
))); // ruleTries == 0 means we try forever
874 // ruleTires > 0 means we try upto ruleTries times
880 _evaluate_rule(engine_t engine
, rule_t rule
, bool *save_pwd
)
882 if (rule_check_flags(rule
, RuleFlagEntitled
)) {
883 if (auth_token_has_entitlement_for_right(engine
->auth
, engine
->currentRightName
)) {
884 LOGV("engine[%i]: rule allow, creator of authorization has entitlement for right %s", connection_get_pid(engine
->conn
), engine
->currentRightName
);
885 return errAuthorizationSuccess
;
889 if (rule_check_flags(rule
, RuleFlagRequireAppleSigned
)) {
890 if (!auth_token_apple_signed(engine
->auth
)) {
891 LOGE("engine[%i]: rule deny, creator of authorization is not signed by apple", connection_get_pid(engine
->conn
));
892 return errAuthorizationDenied
;
896 *save_pwd
|= rule_get_extract_password(rule
);
898 switch (rule_get_class(rule
)) {
900 LOGV("engine[%i]: rule set to allow", connection_get_pid(engine
->conn
));
901 return errAuthorizationSuccess
;
903 LOGV("engine[%i]: rule set to deny", connection_get_pid(engine
->conn
));
904 return errAuthorizationDenied
;
906 return _evaluate_class_user(engine
, rule
);
908 return _evaluate_class_rule(engine
, rule
, save_pwd
);
910 return _evaluate_class_mechanism(engine
, rule
);
912 LOGE("engine[%i]: invalid class for rule or rule not found: %s", connection_get_pid(engine
->conn
), rule_get_name(rule
));
913 return errAuthorizationInternal
;
917 // returns true if this rule or its children contain RC_USER rule with password_only==true
919 _preevaluate_rule(engine_t engine
, rule_t rule
)
921 LOGV("engine[%i]: _preevaluate_rule %s", connection_get_pid(engine
->conn
), rule_get_name(rule
));
923 switch (rule_get_class(rule
)) {
928 return rule_get_password_only(rule
);
930 return _preevaluate_class_rule(engine
, rule
);
939 _find_rule(engine_t engine
, authdb_connection_t dbconn
, const char * string
)
942 size_t sLen
= strlen(string
);
944 char * buf
= calloc(1u, sLen
+ 1);
945 strlcpy(buf
, string
, sLen
+ 1);
946 char * ptr
= buf
+ sLen
;
947 __block
int64_t count
= 0;
952 authdb_step(dbconn
, "SELECT COUNT(name) AS cnt FROM rules WHERE name = ? AND type = 1",
953 ^(sqlite3_stmt
*stmt
) {
954 sqlite3_bind_text(stmt
, 1, buf
, -1, NULL
);
955 }, ^bool(auth_items_t data
) {
956 count
= auth_items_get_int64(data
, "cnt");
961 r
= rule_create_with_string(buf
, dbconn
);
965 // if buf ends with a . and we didn't find a rule remove .
969 // find any remaining . and truncate the string
970 ptr
= strrchr(buf
, '.');
981 // set default if we didn't find a rule
983 r
= rule_create_with_string("", dbconn
);
984 if (rule_get_id(r
) == 0) {
986 LOGE("engine[%i]: default rule lookup error (missing), using builtin defaults", connection_get_pid(engine
->conn
));
987 r
= rule_create_default();
993 static void _parse_environment(engine_t engine
, auth_items_t environment
)
995 require(environment
!= NULL
, done
);
998 LOGV("engine[%i]: Dumping Environment", connection_get_pid(engine
->conn
));
999 _show_cf(environment
);
1002 // Check if a credential was passed into the environment and we were asked to extend the rights
1003 if (engine
->flags
& kAuthorizationFlagExtendRights
) {
1004 const char * user
= auth_items_get_string(environment
, kAuthorizationEnvironmentUsername
);
1005 const char * pass
= auth_items_get_string(environment
, kAuthorizationEnvironmentPassword
);
1006 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
1007 require(password_was_used
== true, done
);
1009 bool shared
= auth_items_exist(environment
, kAuthorizationEnvironmentShared
);
1010 require_action(user
!= NULL
, done
, LOGV("engine[%i]: user not used password", connection_get_pid(engine
->conn
)));
1012 struct passwd
*pw
= getpwnam(user
);
1013 require_action(pw
!= NULL
, done
, LOGE("engine[%i]: user not found %s", connection_get_pid(engine
->conn
), user
));
1015 int checkpw_status
= checkpw_internal(pw
, pass
? pass
: "");
1016 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
));
1018 credential_t cred
= credential_create(pw
->pw_uid
);
1019 if (credential_get_valid(cred
)) {
1020 LOG("engine[%i]: checkpw() succeeded, creating credential for user %s", connection_get_pid(engine
->conn
), user
);
1021 _engine_set_credential(engine
, cred
, shared
);
1023 auth_items_set_string(engine
->context
, kAuthorizationEnvironmentUsername
, user
);
1024 auth_items_set_string(engine
->context
, kAuthorizationEnvironmentPassword
, pass
? pass
: "");
1026 CFReleaseSafe(cred
);
1034 static bool _verify_sandbox(engine_t engine
, const char * right
)
1036 pid_t pid
= process_get_pid(engine
->proc
);
1037 if (sandbox_check(pid
, "authorization-right-obtain", SANDBOX_FILTER_RIGHT_NAME
, right
)) {
1038 LOGE("Sandbox denied authorizing right '%s' by client '%s' [%d]", right
, process_get_code_url(engine
->proc
), pid
);
1042 pid
= auth_token_get_pid(engine
->auth
);
1043 if (auth_token_get_sandboxed(engine
->auth
) && sandbox_check(pid
, "authorization-right-obtain", SANDBOX_FILTER_RIGHT_NAME
, right
)) {
1044 LOGE("Sandbox denied authorizing right '%s' for authorization created by '%s' [%d]", right
, auth_token_get_code_url(engine
->auth
), pid
);
1052 #pragma mark engine methods
1054 OSStatus
engine_authorize(engine_t engine
, auth_rights_t rights
, auth_items_t environment
, AuthorizationFlags flags
)
1056 __block OSStatus status
= errAuthorizationSuccess
;
1057 __block
bool savePassword
= false;
1058 __block
bool password_only
= false;
1060 ccaudit_t ccaudit
= NULL
;
1062 require(rights
!= NULL
, done
);
1064 ccaudit
= ccaudit_create(engine
->proc
, engine
->auth
, AUE_ssauthorize
);
1065 if (auth_rights_get_count(rights
) > 0) {
1066 ccaudit_log(ccaudit
, "begin evaluation", NULL
, 0);
1069 engine
->flags
= flags
;
1072 _parse_environment(engine
, environment
);
1073 auth_items_copy(engine
->hints
, environment
);
1076 auth_items_copy(engine
->context
, auth_token_get_context(engine
->auth
));
1078 engine
->dismissed
= false;
1079 auth_rights_clear(engine
->grantedRights
);
1082 // first check if any of rights uses rule with password-only set to true
1083 // if so, set appropriate hint so SecurityAgent won't use alternate authentication methods like smartcard etc.
1084 authdb_connection_t dbconn
= authdb_connection_acquire(server_get_database()); // get db handle
1085 auth_rights_iterate(rights
, ^bool(const char *key
) {
1088 LOGV("engine[%i]: checking if rule %s contains password-only item", connection_get_pid(engine
->conn
), key
);
1090 rule_t rule
= _find_rule(engine
, dbconn
, key
);
1092 if (rule
&& _preevaluate_rule(engine
, rule
)) {
1093 password_only
= true;
1094 CFReleaseSafe(rule
);
1097 CFReleaseSafe(rule
);
1100 authdb_connection_release(&dbconn
); // release db handle
1103 if (password_only
) {
1104 LOGV("engine[%i]: password-only item found, forcing SecurityAgent to use password-only UI", connection_get_pid(engine
->conn
));
1105 auth_items_set_bool(engine
->immutable_hints
, AGENT_HINT_PASSWORD_ONLY
, true);
1108 auth_rights_iterate(rights
, ^bool(const char *key
) {
1113 if (!_verify_sandbox(engine
, key
)) { // _verify_sandbox is already logging failures
1114 status
= errAuthorizationDenied
;
1118 authdb_connection_t dbconn
= authdb_connection_acquire(server_get_database()); // get db handle
1120 LOGV("engine[%i]: evaluate right %s", connection_get_pid(engine
->conn
), key
);
1121 rule_t rule
= _find_rule(engine
, dbconn
, key
);
1122 const char * rule_name
= rule_get_name(rule
);
1123 if (rule_name
&& (strcasecmp(rule_name
, "") == 0)) {
1124 rule_name
= "default (not defined)";
1126 LOGV("engine[%i]: using rule %s", connection_get_pid(engine
->conn
), rule_name
);
1128 // only need the hints & mechanisms if we are going to show ui
1129 if (engine
->flags
& kAuthorizationFlagInteractionAllowed
) {
1130 _set_right_hints(engine
->hints
, key
);
1131 _set_localization_hints(dbconn
, engine
->hints
, rule
);
1132 if (!engine
->authenticateRule
) {
1133 engine
->authenticateRule
= rule_create_with_string("authenticate", dbconn
);
1137 authdb_connection_release(&dbconn
); // release db handle
1139 engine
->currentRightName
= key
;
1140 engine
->currentRule
= rule
;
1142 ccaudit_log(ccaudit
, key
, rule_name
, 0);
1144 status
= _evaluate_rule(engine
, engine
->currentRule
, &savePassword
);
1146 case errAuthorizationSuccess
:
1147 auth_rights_add(engine
->grantedRights
, key
);
1148 auth_rights_set_flags(engine
->grantedRights
, key
, auth_rights_get_flags(rights
,key
));
1150 if ((engine
->flags
& kAuthorizationFlagPreAuthorize
) &&
1151 (rule_get_class(engine
->currentRule
) == RC_USER
) &&
1152 (rule_get_timeout(engine
->currentRule
) == 0)) {
1153 // FIXME: kAuthorizationFlagPreAuthorize => kAuthorizationFlagCanNotPreAuthorize ???
1154 auth_rights_set_flags(engine
->grantedRights
, engine
->currentRightName
, kAuthorizationFlagPreAuthorize
);
1157 LOG("Succeeded authorizing right '%s' by client '%s' [%d] for authorization created by '%s' [%d] (%X,%d)",
1158 key
, process_get_code_url(engine
->proc
), process_get_pid(engine
->proc
),
1159 auth_token_get_code_url(engine
->auth
), auth_token_get_pid(engine
->auth
), (unsigned int)engine
->flags
, auth_token_least_privileged(engine
->auth
));
1161 case errAuthorizationDenied
:
1162 case errAuthorizationInteractionNotAllowed
:
1163 case errAuthorizationCanceled
:
1164 if (engine
->flags
& kAuthorizationFlagInteractionAllowed
) {
1165 LOG("Failed to authorize right '%s' by client '%s' [%d] for authorization created by '%s' [%d] (%X,%d) (%i)",
1166 key
, process_get_code_url(engine
->proc
), process_get_pid(engine
->proc
),
1167 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
);
1169 LOGV("Failed to authorize right '%s' by client '%s' [%d] for authorization created by '%s' [%d] (%X,%d) (%d)",
1170 key
, process_get_code_url(engine
->proc
), process_get_pid(engine
->proc
),
1171 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
);
1175 LOGE("engine[%i]: evaluate returned %d returning errAuthorizationInternal", connection_get_pid(engine
->conn
), (int)status
);
1176 status
= errAuthorizationInternal
;
1180 ccaudit_log_authorization(ccaudit
, engine
->currentRightName
, status
);
1182 CFReleaseSafe(rule
);
1183 engine
->currentRightName
= NULL
;
1184 engine
->currentRule
= NULL
;
1186 auth_items_remove_with_flags(engine
->hints
, kEngineHintsFlagTemporary
);
1188 if (!(engine
->flags
& kAuthorizationFlagPartialRights
) && (status
!= errAuthorizationSuccess
)) {
1195 if (password_only
) {
1196 LOGV("engine[%i]: removing password-only flag", connection_get_pid(engine
->conn
));
1197 auth_items_remove(engine
->immutable_hints
, AGENT_HINT_PASSWORD_ONLY
);
1200 if ((engine
->flags
& kAuthorizationFlagPartialRights
) && (auth_rights_get_count(engine
->grantedRights
) > 0)) {
1201 status
= errAuthorizationSuccess
;
1204 if (engine
->dismissed
) {
1205 LOGE("engine: engine dismissed");
1206 status
= errAuthorizationDenied
;
1209 LOGV("engine[%i]: authorize result: %d", connection_get_pid(engine
->conn
), (int)status
);
1211 if ((engine
->flags
& kAuthorizationFlagExtendRights
) && !(engine
->flags
& kAuthorizationFlagDestroyRights
)) {
1212 _cf_set_iterate(engine
->credentials
, ^bool(CFTypeRef value
) {
1213 credential_t cred
= (credential_t
)value
;
1214 // skip all uid credentials when running in least privileged
1215 if (auth_token_least_privileged(engine
->auth
) && !credential_is_right(cred
))
1218 session_t session
= auth_token_get_session(engine
->auth
);
1219 auth_token_set_credential(engine
->auth
, cred
);
1220 if (credential_get_shared(cred
)) {
1221 session_set_credential(session
, cred
);
1223 if (credential_is_right(cred
)) {
1224 LOGV("engine[%i]: adding least privileged %scredential %s to authorization", connection_get_pid(engine
->conn
), credential_get_shared(cred
) ? "shared " : "", credential_get_name(cred
));
1226 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
));
1232 if (status
== errAuthorizationSuccess
&& savePassword
) {
1233 auth_items_set_flags(engine
->context
, kAuthorizationEnvironmentPassword
, kAuthorizationContextFlagExtractable
);
1236 if ((status
== errAuthorizationSuccess
) || (status
== errAuthorizationCanceled
)) {
1237 auth_items_copy_with_flags(auth_token_get_context(engine
->auth
), engine
->context
, kAuthorizationContextFlagExtractable
);
1240 if (auth_rights_get_count(rights
) > 0) {
1241 ccaudit_log(ccaudit
, "end evaluation", NULL
, status
);
1245 LOGV("engine[%i]: ********** Dumping auth->credentials **********", connection_get_pid(engine
->conn
));
1246 auth_token_credentials_iterate(engine
->auth
, ^bool(credential_t cred
) {
1250 LOGV("engine[%i]: ********** Dumping session->credentials **********", connection_get_pid(engine
->conn
));
1251 session_credentials_iterate(auth_token_get_session(engine
->auth
), ^bool(credential_t cred
) {
1255 LOGV("engine[%i]: ********** Dumping engine->context **********", connection_get_pid(engine
->conn
));
1256 _show_cf(engine
->context
);
1257 LOGV("engine[%i]: ********** Dumping auth->context **********", connection_get_pid(engine
->conn
));
1258 _show_cf(auth_token_get_context(engine
->auth
));
1259 LOGV("engine[%i]: ********** Dumping granted rights **********", connection_get_pid(engine
->conn
));
1260 _show_cf(engine
->grantedRights
);
1264 auth_items_clear(engine
->context
);
1265 auth_items_clear(engine
->sticky_context
);
1266 CFReleaseSafe(ccaudit
);
1267 CFDictionaryRemoveAllValues(engine
->mechanism_agents
);
1273 _wildcard_right_exists(engine_t engine
, const char * right
)
1275 // checks if a wild card right exists
1276 // ex: com.apple. system.
1277 bool exists
= false;
1279 authdb_connection_t dbconn
= authdb_connection_acquire(server_get_database()); // get db handle
1280 require(dbconn
!= NULL
, done
);
1282 rule
= _find_rule(engine
, dbconn
, right
);
1283 require(rule
!= NULL
, done
);
1285 const char * ruleName
= rule_get_name(rule
);
1286 require(ruleName
!= NULL
, done
);
1287 size_t len
= strlen(ruleName
);
1288 require(len
!= 0, done
);
1290 if (ruleName
[len
-1] == '.') {
1296 authdb_connection_release(&dbconn
);
1297 CFReleaseSafe(rule
);
1302 // Validate db right modification
1304 // meta rights are constructed as follows:
1305 // we don't allow setting of wildcard rights, so you can only be more specific
1306 // note that you should never restrict things with a wildcard right without disallowing
1307 // changes to the entire domain. ie.
1308 // system.privilege. -> never
1309 // config.add.system.privilege. -> never
1310 // config.modify.system.privilege. -> never
1311 // config.delete.system.privilege. -> never
1312 // For now we don't allow any configuration of configuration rules
1313 // config.config. -> never
1315 OSStatus
engine_verify_modification(engine_t engine
, rule_t rule
, bool remove
, bool force_modify
)
1317 OSStatus status
= errAuthorizationDenied
;
1318 auth_rights_t checkRight
= NULL
;
1320 memset(buf
, 0, sizeof(buf
));
1322 const char * right
= rule_get_name(rule
);
1323 require(right
!= NULL
, done
);
1324 size_t len
= strlen(right
);
1325 require(len
!= 0, done
);
1327 require_action(right
[len
-1] != '.', done
, LOGE("engine[%i]: not allowed to set wild card rules", connection_get_pid(engine
->conn
)));
1329 if (strncasecmp(right
, kConfigRight
, strlen(kConfigRight
)) == 0) {
1330 // special handling of meta right change:
1331 // config.add. config.modify. config.remove. config.{}.
1332 // check for config.<right> (which always starts with config.config.)
1333 strlcat(buf
, kConfigRight
, sizeof(buf
));
1335 bool existing
= (rule_get_id(rule
) != 0) ? true : _wildcard_right_exists(engine
, right
);
1337 if (existing
|| force_modify
) {
1338 strlcat(buf
, kAuthorizationConfigRightModify
,sizeof(buf
));
1340 strlcat(buf
, kAuthorizationConfigRightAdd
, sizeof(buf
));
1344 strlcat(buf
, kAuthorizationConfigRightRemove
, sizeof(buf
));
1346 status
= errAuthorizationSuccess
;
1352 strlcat(buf
, right
, sizeof(buf
));
1354 checkRight
= auth_rights_create();
1355 auth_rights_add(checkRight
, buf
);
1356 status
= engine_authorize(engine
, checkRight
, NULL
, kAuthorizationFlagDefaults
| kAuthorizationFlagInteractionAllowed
| kAuthorizationFlagExtendRights
);
1359 LOGV("engine[%i]: authorizing %s for db modification: %d", connection_get_pid(engine
->conn
), right
, (int)status
);
1360 CFReleaseSafe(checkRight
);
1365 _engine_set_credential(engine_t engine
, credential_t cred
, bool shared
)
1367 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
);
1368 CFSetSetValue(engine
->credentials
, cred
);
1370 credential_t sharedCred
= credential_create_with_credential(cred
, true);
1371 CFSetSetValue(engine
->credentials
, sharedCred
);
1372 CFReleaseSafe(sharedCred
);
1377 engine_get_granted_rights(engine_t engine
)
1379 return engine
->grantedRights
;
1382 CFAbsoluteTime
engine_get_time(engine_t engine
)
1387 void engine_destroy_agents(engine_t engine
)
1389 engine
->dismissed
= true;
1391 _cf_dictionary_iterate(engine
->mechanism_agents
, ^bool(CFTypeRef key
__attribute__((__unused__
)), CFTypeRef value
) {
1392 LOGD("engine[%i]: Destroying %s", connection_get_pid(engine
->conn
), mechanism_get_string((mechanism_t
)key
));
1393 agent_t agent
= (agent_t
)value
;
1394 agent_destroy(agent
);
1400 void engine_interrupt_agent(engine_t engine
)
1402 _cf_dictionary_iterate(engine
->mechanism_agents
, ^bool(CFTypeRef key
__attribute__((__unused__
)), CFTypeRef value
) {
1403 agent_t agent
= (agent_t
)value
;
1404 agent_notify_interrupt(agent
);