2
0
mirror of https://github.com/sudo-project/sudo.git synced 2025-09-03 07:45:47 +00:00

Add "list" pseudo-command to allow a user to list another user's

privs.  Previously, only root or a user with the ability to run any
command as either root or the target user on the current host could
use the -U option.  For "sudo -l [-U otheruser] command", NewArgv[0]
is now set to "list" (just like "sudo -l") and the actual command
to be checked starts with NewArgv[1].
This commit is contained in:
Todd C. Miller
2022-12-11 13:46:00 -07:00
parent 8c16c8faf6
commit a514a6eed5
9 changed files with 2577 additions and 2418 deletions

View File

@@ -60,6 +60,7 @@ static int
sudoers_lookup_pseudo(struct sudo_nss_list *snl, struct passwd *pw,
int validated, int pwflag)
{
char *saved_runchroot;
struct passwd *root_pw = NULL;
struct sudo_nss *nss;
struct cmndspec *cs;
@@ -82,6 +83,11 @@ sudoers_lookup_pseudo(struct sudo_nss_list *snl, struct passwd *pw,
} else {
SET(validated, FLAG_NO_CHECK);
}
/* Don't use chroot setting for pseudo-commands. */
saved_runchroot = def_runchroot;
def_runchroot = NULL;
TAILQ_FOREACH(nss, snl, entries) {
if (nss->query(nss, pw) == -1) {
/* The query function should have printed an error message. */
@@ -111,19 +117,34 @@ sudoers_lookup_pseudo(struct sudo_nss_list *snl, struct passwd *pw,
if (match == ALLOW)
continue;
/* Only check runas/command when listing another user. */
/*
* 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;
}
/* Runas user must match list user or root. */
if (runas_matches_pw(nss->parse_tree, cs, list_pw) == DENY)
/*
* 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:
continue;
if (root_pw == NULL || runas_matches_pw(nss->parse_tree,
cs, root_pw) != ALLOW) {
case ALLOW:
break;
default:
if (root_pw != NULL && runas_matches_pw(nss->parse_tree,
cs, root_pw) == ALLOW) {
break;
}
continue;
}
/* Match command: "list" or ALL. */
if (cmnd_matches(nss->parse_tree, cs->cmnd, cs->runchroot,
NULL) == ALLOW) {
match = ALLOW;
@@ -143,6 +164,10 @@ sudoers_lookup_pseudo(struct sudo_nss_list *snl, struct passwd *pw,
SET(validated, FLAG_CHECK_USER);
else if (nopass == true)
def_authenticate = false;
/* Restore original def_runchroot. */
def_runchroot = saved_runchroot;
debug_return_int(validated);
}
@@ -963,12 +988,22 @@ static int
display_cmnd_check(struct sudoers_parse_tree *parse_tree, struct passwd *pw,
time_t now)
{
int host_match, runas_match, cmnd_match;
int host_match, runas_match, cmnd_match = UNSPEC;
char *saved_user_cmnd, *saved_user_base;
struct cmndspec *cs;
struct privilege *priv;
struct userspec *us;
debug_decl(display_cmnd_check, SUDOERS_DEBUG_PARSER);
/*
* For "sudo -l command", user_cmnd is "list" and the actual
* command we are checking is in list_cmnd.
*/
saved_user_cmnd = user_cmnd;
saved_user_base = user_base;
user_cmnd = list_cmnd;
user_base = sudo_basename(user_cmnd);
TAILQ_FOREACH_REVERSE(us, &parse_tree->userspecs, userspec_list, entries) {
if (userlist_matches(parse_tree, pw, &us->users) != ALLOW)
continue;
@@ -991,12 +1026,15 @@ display_cmnd_check(struct sudoers_parse_tree *parse_tree, struct passwd *pw,
cmnd_match = cmnd_matches(parse_tree, cs->cmnd,
cs->runchroot, NULL);
if (cmnd_match != UNSPEC)
debug_return_int(cmnd_match);
goto done;
}
}
}
}
debug_return_int(UNSPEC);
done:
user_cmnd = saved_user_cmnd;
user_base = saved_user_base;
debug_return_int(cmnd_match);
}
/*
@@ -1029,8 +1067,8 @@ display_cmnd(struct sudo_nss_list *snl, struct passwd *pw)
break;
}
if (match == ALLOW) {
const int len = sudo_printf(SUDO_CONV_INFO_MSG, "%s%s%s\n",
safe_cmnd, user_args ? " " : "", user_args ? user_args : "");
/* For "sudo -l cmd" user_args includes the command being checked. */
const int len = sudo_printf(SUDO_CONV_INFO_MSG, "%s\n", user_args);
ret = len < 0 ? -1 : true;
}
debug_return_int(ret);