sudoers_lookup_pseudo: sync with sudoers_lookup_check
This makes sudoers_lookup_pseudo(), which is used for pseudo-command like "list" and "validate" a bit more like sudoers_lookup_check(). Time of day checks are performed, and callbacks are supported. We cannot use the same code for regular commands and pseudo-commands due to the "pwcheck == all" case.
This commit is contained in:
@@ -54,7 +54,8 @@ runas_matches_pw(struct sudoers_parse_tree *parse_tree,
|
||||
* list, verify and kill.
|
||||
*/
|
||||
static unsigned int
|
||||
sudoers_lookup_pseudo(struct sudo_nss_list *snl, struct passwd *pw, int pwflag)
|
||||
sudoers_lookup_pseudo(struct sudo_nss_list *snl, struct passwd *pw,
|
||||
time_t now, struct sudoers_lookup_callbacks *callbacks, int pwflag)
|
||||
{
|
||||
char *saved_runchroot;
|
||||
struct passwd *root_pw = NULL;
|
||||
@@ -63,7 +64,7 @@ sudoers_lookup_pseudo(struct sudo_nss_list *snl, struct passwd *pw, int pwflag)
|
||||
struct privilege *priv;
|
||||
struct userspec *us;
|
||||
struct defaults *def;
|
||||
int cmnd_match, nopass, match = DENY;
|
||||
int nopass, match = DENY;
|
||||
unsigned int validated = 0;
|
||||
enum def_tuple pwcheck;
|
||||
debug_decl(sudoers_lookup_pseudo, SUDOERS_DEBUG_PARSER);
|
||||
@@ -89,19 +90,36 @@ sudoers_lookup_pseudo(struct sudo_nss_list *snl, struct passwd *pw, int pwflag)
|
||||
SET(validated, VALIDATE_ERROR);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to traverse the policy forwards, not in reverse,
|
||||
* to support the "pwcheck == all" case.
|
||||
*/
|
||||
TAILQ_FOREACH(us, &nss->parse_tree->userspecs, entries) {
|
||||
if (userlist_matches(nss->parse_tree, pw, &us->users) != ALLOW)
|
||||
int user_match = userlist_matches(nss->parse_tree, pw, &us->users);
|
||||
if (callbacks != NULL)
|
||||
callbacks->cb_userspec(us, user_match);
|
||||
if (user_match != ALLOW)
|
||||
continue;
|
||||
TAILQ_FOREACH(priv, &us->privileges, entries) {
|
||||
int priv_nopass = UNSPEC;
|
||||
|
||||
if (hostlist_matches(nss->parse_tree, pw, &priv->hostlist) != ALLOW)
|
||||
int host_match = hostlist_matches(nss->parse_tree, pw,
|
||||
&priv->hostlist);
|
||||
if (callbacks != NULL)
|
||||
callbacks->cb_privilege(priv, host_match);
|
||||
if (host_match != ALLOW)
|
||||
continue;
|
||||
TAILQ_FOREACH(def, &priv->defaults, entries) {
|
||||
if (strcmp(def->var, "authenticate") == 0)
|
||||
if (strcmp(def->var, "authenticate") == 0) {
|
||||
priv_nopass = !def->op;
|
||||
break;
|
||||
}
|
||||
}
|
||||
TAILQ_FOREACH(cs, &priv->cmndlist, entries) {
|
||||
int cmnd_match = UNSPEC;
|
||||
int date_match = UNSPEC;
|
||||
int runas_match = UNSPEC;
|
||||
|
||||
if (pwcheck == any) {
|
||||
if (cs->tags.nopasswd == true || priv_nopass == true)
|
||||
nopass = true;
|
||||
@@ -109,59 +127,72 @@ sudoers_lookup_pseudo(struct sudo_nss_list *snl, struct passwd *pw, int pwflag)
|
||||
if (cs->tags.nopasswd != true && priv_nopass != true)
|
||||
nopass = false;
|
||||
}
|
||||
if (match == ALLOW)
|
||||
continue;
|
||||
|
||||
if (cs->notbefore != UNSPEC) {
|
||||
date_match = now < cs->notbefore ? DENY : ALLOW;
|
||||
}
|
||||
if (cs->notafter != UNSPEC) {
|
||||
date_match = now > cs->notafter ? DENY : ALLOW;
|
||||
}
|
||||
/*
|
||||
* Root can list any user's privileges.
|
||||
* A user may always list their own privileges.
|
||||
*/
|
||||
if (user_uid == 0 || list_pw == NULL ||
|
||||
user_uid == list_pw->pw_uid) {
|
||||
match = ALLOW;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* To list another user's prilileges, the runas
|
||||
* user must match the list user or root.
|
||||
*/
|
||||
switch (runas_matches_pw(nss->parse_tree, cs, list_pw)) {
|
||||
case DENY:
|
||||
break;
|
||||
case ALLOW:
|
||||
cmnd_match = ALLOW;
|
||||
runas_match = ALLOW;
|
||||
} else if (date_match != DENY) {
|
||||
/*
|
||||
* RunAs user matches list user.
|
||||
* Match on command "list" or ALL.
|
||||
* To list another user's prilileges, the runas
|
||||
* user must match the list user or root.
|
||||
*/
|
||||
cmnd_match = cmnd_matches(nss->parse_tree,
|
||||
cs->cmnd, cs->runchroot, NULL);
|
||||
if (cmnd_match != UNSPEC) {
|
||||
match = cmnd_match;
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* RunAs user doesn't match list user. Only allow
|
||||
* listing if the user has "sudo ALL" for root.
|
||||
*/
|
||||
if (root_pw != NULL && runas_matches_pw(nss->parse_tree,
|
||||
cs, root_pw) == ALLOW) {
|
||||
cmnd_match = cmnd_matches_all(nss->parse_tree,
|
||||
runas_match = runas_matches_pw(nss->parse_tree, cs,
|
||||
list_pw);
|
||||
switch (runas_match) {
|
||||
case DENY:
|
||||
break;
|
||||
case ALLOW:
|
||||
/*
|
||||
* RunAs user matches list user.
|
||||
* Match on command "list" or ALL.
|
||||
*/
|
||||
cmnd_match = cmnd_matches(nss->parse_tree,
|
||||
cs->cmnd, cs->runchroot, NULL);
|
||||
if (cmnd_match != UNSPEC) {
|
||||
match = cmnd_match;
|
||||
goto done;
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* RunAs user doesn't match list user.
|
||||
* Only allow listing if the user has
|
||||
* "sudo ALL" for root.
|
||||
*/
|
||||
if (root_pw != NULL &&
|
||||
runas_matches_pw(nss->parse_tree, cs,
|
||||
root_pw) == ALLOW) {
|
||||
runas_match = ALLOW;
|
||||
cmnd_match = cmnd_matches_all(nss->parse_tree,
|
||||
cs->cmnd, cs->runchroot, NULL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (callbacks != NULL) {
|
||||
callbacks->cb_cmndspec(cs, date_match, runas_match,
|
||||
cmnd_match);
|
||||
}
|
||||
if (cmnd_match != UNSPEC) {
|
||||
/*
|
||||
* We take the last match but must process
|
||||
* the entire policy for pwcheck == all.
|
||||
*/
|
||||
match = cmnd_match;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!sudo_nss_can_continue(nss, match))
|
||||
break;
|
||||
}
|
||||
done:
|
||||
if (root_pw != NULL)
|
||||
sudo_pw_delref(root_pw);
|
||||
if (match == ALLOW || user_uid == 0) {
|
||||
@@ -475,7 +506,7 @@ sudoers_lookup(struct sudo_nss_list *snl, struct passwd *pw, time_t now,
|
||||
* Special case checking the "validate", "list" and "kill" pseudo-commands.
|
||||
*/
|
||||
if (pwflag)
|
||||
debug_return_uint(sudoers_lookup_pseudo(snl, pw, pwflag));
|
||||
debug_return_uint(sudoers_lookup_pseudo(snl, pw, now, callbacks, pwflag));
|
||||
|
||||
/* Need to be runas user while stat'ing things. */
|
||||
if (!set_perms(PERM_RUNAS))
|
||||
|
Reference in New Issue
Block a user