Allow the -k flag to be specified in conjunction with a command or

another option that may require authentication.
This commit is contained in:
Todd C. Miller
2009-02-24 13:04:39 +00:00
parent e7ee38d62c
commit 15975b83ce
4 changed files with 80 additions and 40 deletions

20
check.c
View File

@@ -84,24 +84,29 @@ static void update_timestamp __P((char *, char *));
* verify who he/she is. * verify who he/she is.
*/ */
void void
check_user(validated, interactive) check_user(validated, mode)
int validated; int validated;
int interactive; int mode;
{ {
char *timestampdir = NULL; char *timestampdir = NULL;
char *timestampfile = NULL; char *timestampfile = NULL;
char *prompt; char *prompt;
int status; int status;
if (user_uid == 0 || user_uid == runas_pw->pw_uid || user_is_exempt()) if (mode & MODE_INVALIDATE) {
return; /* do not check or update timestamp */
status = TS_ERROR;
} else {
if (user_uid == 0 || user_uid == runas_pw->pw_uid || user_is_exempt())
return;
build_timestamp(&timestampdir, &timestampfile); build_timestamp(&timestampdir, &timestampfile);
status = timestamp_status(timestampdir, timestampfile, user_name, status = timestamp_status(timestampdir, timestampfile, user_name,
TS_MAKE_DIRS); TS_MAKE_DIRS);
}
if (status != TS_CURRENT || ISSET(validated, FLAG_CHECK_USER)) { if (status != TS_CURRENT || ISSET(validated, FLAG_CHECK_USER)) {
/* Bail out if we are non-interactive and a password is required */ /* Bail out if we are non-interactive and a password is required */
if (!interactive) if (ISSET(mode, MODE_NONINTERACTIVE))
errorx(1, "sorry, a password is required to run %s", getprogname()); errorx(1, "sorry, a password is required to run %s", getprogname());
/* If user specified -A, make sure we have an askpass helper. */ /* If user specified -A, make sure we have an askpass helper. */
@@ -139,7 +144,6 @@ check_user(validated, interactive)
/* /*
* Standard sudo lecture. * Standard sudo lecture.
* TODO: allow the user to specify a file name instead.
*/ */
static void static void
lecture(status) lecture(status)

58
sudo.c
View File

@@ -95,8 +95,8 @@
# include <selinux/selinux.h> # include <selinux/selinux.h>
#endif #endif
#include <sudo_usage.h>
#include "sudo.h" #include "sudo.h"
#include "sudo_usage.h"
#include "lbuf.h" #include "lbuf.h"
#include "interfaces.h" #include "interfaces.h"
#include "version.h" #include "version.h"
@@ -231,7 +231,7 @@ main(argc, argv, envp)
user_cmnd = "shell"; user_cmnd = "shell";
else if (ISSET(sudo_mode, MODE_EDIT)) else if (ISSET(sudo_mode, MODE_EDIT))
user_cmnd = "sudoedit"; user_cmnd = "sudoedit";
else else {
switch (sudo_mode) { switch (sudo_mode) {
case MODE_VERSION: case MODE_VERSION:
show_version(); show_version();
@@ -240,11 +240,12 @@ main(argc, argv, envp)
usage(0); usage(0);
break; break;
case MODE_VALIDATE: case MODE_VALIDATE:
case MODE_VALIDATE|MODE_INVALIDATE:
user_cmnd = "validate"; user_cmnd = "validate";
pwflag = I_VERIFYPW; pwflag = I_VERIFYPW;
break; break;
case MODE_KILL:
case MODE_INVALIDATE: case MODE_INVALIDATE:
case MODE_KILL:
user_cmnd = "kill"; user_cmnd = "kill";
pwflag = -1; pwflag = -1;
break; break;
@@ -253,13 +254,16 @@ main(argc, argv, envp)
exit(0); exit(0);
break; break;
case MODE_LIST: case MODE_LIST:
case MODE_LIST|MODE_INVALIDATE:
user_cmnd = "list"; user_cmnd = "list";
pwflag = I_LISTPW; pwflag = I_LISTPW;
break; break;
case MODE_CHECK: case MODE_CHECK:
case MODE_CHECK|MODE_INVALIDATE:
pwflag = I_LISTPW; pwflag = I_LISTPW;
break; break;
} }
}
/* Must have a command to run... */ /* Must have a command to run... */
if (user_cmnd == NULL && NewArgc == 0) if (user_cmnd == NULL && NewArgc == 0)
@@ -405,7 +409,7 @@ main(argc, argv, envp)
/* Require a password if sudoers says so. */ /* Require a password if sudoers says so. */
if (def_authenticate) if (def_authenticate)
check_user(validated, !ISSET(sudo_mode, MODE_NONINTERACTIVE)); check_user(validated, sudo_mode);
/* If run as root with SUDO_USER set, set sudo_user.pw to that user. */ /* If run as root with SUDO_USER set, set sudo_user.pw to that user. */
/* XXX - causes confusion when root is not listed in sudoers */ /* XXX - causes confusion when root is not listed in sudoers */
@@ -438,9 +442,9 @@ main(argc, argv, envp)
} }
log_allowed(validated); log_allowed(validated);
if (sudo_mode == MODE_CHECK) if (ISSET(sudo_mode, MODE_CHECK))
rc = display_cmnd(snl, list_pw ? list_pw : sudo_user.pw); rc = display_cmnd(snl, list_pw ? list_pw : sudo_user.pw);
else if (sudo_mode == MODE_LIST) else if (ISSET(sudo_mode, MODE_LIST))
display_privs(snl, list_pw ? list_pw : sudo_user.pw); display_privs(snl, list_pw ? list_pw : sudo_user.pw);
/* Cleanup sudoers sources */ /* Cleanup sudoers sources */
@@ -448,8 +452,7 @@ main(argc, argv, envp)
nss->close(nss); nss->close(nss);
/* Deferred exit due to sudo_ldap_close() */ /* Deferred exit due to sudo_ldap_close() */
if (sudo_mode == MODE_VALIDATE || sudo_mode == MODE_CHECK || if (ISSET(sudo_mode, (MODE_VALIDATE|MODE_CHECK|MODE_LIST)))
sudo_mode == MODE_LIST)
exit(rc); exit(rc);
/* /*
@@ -835,7 +838,7 @@ parse_args(argc, argv)
{ {
int mode = 0; /* what mode is sudo to be run in? */ int mode = 0; /* what mode is sudo to be run in? */
int flags = 0; /* mode flags */ int flags = 0; /* mode flags */
int ch; int allowed_flags, ch;
/* First, check to see if we were invoked as "sudoedit". */ /* First, check to see if we were invoked as "sudoedit". */
if (strcmp(getprogname(), "sudoedit") == 0) if (strcmp(getprogname(), "sudoedit") == 0)
@@ -849,6 +852,10 @@ parse_args(argc, argv)
#define is_envar (optind < argc && argv[optind][0] != '/' && \ #define is_envar (optind < argc && argv[optind][0] != '/' && \
strchr(argv[optind], '=') != NULL) strchr(argv[optind], '=') != NULL)
/* Flags allowed when running a command */
allowed_flags = MODE_BACKGROUND|MODE_PRESERVE_ENV|MODE_RESET_HOME|
MODE_LOGIN_SHELL|MODE_INVALIDATE|MODE_NONINTERACTIVE|
MODE_PRESERVE_GROUPS|MODE_SHELL;
for (;;) { for (;;) {
/* /*
* We disable arg permutation for GNU getopt(). * We disable arg permutation for GNU getopt().
@@ -887,6 +894,7 @@ parse_args(argc, argv)
if (mode && mode != MODE_EDIT) if (mode && mode != MODE_EDIT)
usage_excl(1); usage_excl(1);
mode = MODE_EDIT; mode = MODE_EDIT;
allowed_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE;
break; break;
case 'g': case 'g':
runas_group = optarg; runas_group = optarg;
@@ -898,25 +906,26 @@ parse_args(argc, argv)
if (mode && mode != MODE_HELP) if (mode && mode != MODE_HELP)
usage_excl(1); usage_excl(1);
mode = MODE_HELP; mode = MODE_HELP;
allowed_flags = 0;
break; break;
case 'i': case 'i':
SET(flags, MODE_LOGIN_SHELL); SET(flags, MODE_LOGIN_SHELL);
def_env_reset = TRUE; def_env_reset = TRUE;
break; break;
case 'k': case 'k':
if (mode && mode != MODE_INVALIDATE) SET(flags, MODE_INVALIDATE);
usage_excl(1);
mode = MODE_INVALIDATE;
break; break;
case 'K': case 'K':
if (mode && mode != MODE_KILL) if (mode && mode != MODE_KILL)
usage_excl(1); usage_excl(1);
mode = MODE_KILL; mode = MODE_KILL;
allowed_flags = 0;
break; break;
case 'L': case 'L':
if (mode && mode != MODE_LISTDEFS) if (mode && mode != MODE_LISTDEFS)
usage_excl(1); usage_excl(1);
mode = MODE_LISTDEFS; mode = MODE_LISTDEFS;
allowed_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE;
break; break;
case 'l': case 'l':
if (mode) { if (mode) {
@@ -926,6 +935,7 @@ parse_args(argc, argv)
usage_excl(1); usage_excl(1);
} }
mode = MODE_LIST; mode = MODE_LIST;
allowed_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE;
break; break;
case 'n': case 'n':
SET(flags, MODE_NONINTERACTIVE); SET(flags, MODE_NONINTERACTIVE);
@@ -962,11 +972,13 @@ parse_args(argc, argv)
if (mode && mode != MODE_VALIDATE) if (mode && mode != MODE_VALIDATE)
usage_excl(1); usage_excl(1);
mode = MODE_VALIDATE; mode = MODE_VALIDATE;
allowed_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE;
break; break;
case 'V': case 'V':
if (mode && mode != MODE_VERSION) if (mode && mode != MODE_VERSION)
usage_excl(1); usage_excl(1);
mode = MODE_VERSION; mode = MODE_VERSION;
allowed_flags = 0;
break; break;
default: default:
usage(1); usage(1);
@@ -991,8 +1003,15 @@ parse_args(argc, argv)
NewArgc = argc - optind; NewArgc = argc - optind;
NewArgv = argv + optind; NewArgv = argv + optind;
if (!mode) if (!mode) {
mode = MODE_RUN; /* Defer -k mode setting until we know whether it is a flag or not */
if (ISSET(flags, MODE_INVALIDATE) && NewArgc == 0) {
mode = MODE_INVALIDATE; /* -k by itself */
allowed_flags = 0;
} else {
mode = MODE_RUN; /* running a command */
}
}
if (NewArgc > 0 && mode == MODE_LIST) if (NewArgc > 0 && mode == MODE_LIST)
mode = MODE_CHECK; mode = MODE_CHECK;
@@ -1008,6 +1027,8 @@ parse_args(argc, argv)
} }
SET(flags, MODE_SHELL); SET(flags, MODE_SHELL);
} }
if ((flags & allowed_flags) != flags)
usage(1);
if (mode == MODE_EDIT && if (mode == MODE_EDIT &&
(ISSET(flags, MODE_PRESERVE_ENV) || sudo_user.env_vars != NULL)) { (ISSET(flags, MODE_PRESERVE_ENV) || sudo_user.env_vars != NULL)) {
if (ISSET(mode, MODE_PRESERVE_ENV)) if (ISSET(mode, MODE_PRESERVE_ENV))
@@ -1431,7 +1452,7 @@ static void
usage_excl(exit_val) usage_excl(exit_val)
int exit_val; int exit_val;
{ {
warningx("Only one of the -e, -h, -i, -k, -K, -l, -s, -v or -V options may be specified"); warningx("Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified");
usage(exit_val); usage(exit_val);
} }
@@ -1444,21 +1465,22 @@ usage(exit_val)
int exit_val; int exit_val;
{ {
struct lbuf lbuf; struct lbuf lbuf;
char *uvec[5]; char *uvec[6];
int i, ulen; int i, ulen;
/* /*
* Use usage vectors appropriate to the progname. * Use usage vectors appropriate to the progname.
*/ */
if (strcmp(getprogname(), "sudoedit") == 0) { if (strcmp(getprogname(), "sudoedit") == 0) {
uvec[0] = SUDO_USAGE4 + 3; uvec[0] = SUDO_USAGE5 + 3;
uvec[1] = NULL; uvec[1] = NULL;
} else { } else {
uvec[0] = SUDO_USAGE1; uvec[0] = SUDO_USAGE1;
uvec[1] = SUDO_USAGE2; uvec[1] = SUDO_USAGE2;
uvec[2] = SUDO_USAGE3; uvec[2] = SUDO_USAGE3;
uvec[3] = SUDO_USAGE4; uvec[3] = SUDO_USAGE4;
uvec[4] = NULL; uvec[4] = SUDO_USAGE5;
uvec[5] = NULL;
} }
/* /*

View File

@@ -27,10 +27,16 @@ sudo, sudoedit - execute a command as another user
=head1 SYNOPSIS =head1 SYNOPSIS
B<sudo> [B<-n>] B<-h> | B<-K> | B<-k> | B<-L> | B<-V> | B<-v> B<sudo> B<-h> | B<-K> | B<-k> | B<-L> | B<-V>
B<sudo> B<-l[l]> [B<-AnS>] S<[B<-g> I<groupname>|I<#gid>]> S<[B<-U> I<username>]> B<sudo> B<-v> [B<-AknS>]
S<[B<-u> I<username>|I<#uid>]> [I<command>] S<[B<-a> I<auth_type>]>
S<[B<-p> I<prompt>]>
B<sudo> B<-l[l]> [B<-AknS>]
S<[B<-a> I<auth_type>]>
S<[B<-g> I<groupname>|I<#gid>]> S<[B<-p> I<prompt>]>
S<[B<-U> I<username>]> S<[B<-u> I<username>|I<#uid>]> [I<command>]
B<sudo> [B<-AbEHnPS>] B<sudo> [B<-AbEHnPS>]
S<[B<-a> I<auth_type>]> S<[B<-a> I<auth_type>]>
@@ -231,16 +237,23 @@ All other environment variables are removed.
=item -K =item -K
The B<-K> (sure I<kill>) option is like B<-k> except that it removes The B<-K> (sure I<kill>) option is like B<-k> except that it removes
the user's timestamp entirely. Like B<-k>, this option does not the user's timestamp entirely and may not be used in conjunction
require a password. with a command or other option. This option does not require a
password.
=item -k =item -k
The B<-k> (I<kill>) option to B<sudo> invalidates the user's timestamp When used by itself, the B<-k> (I<kill>) option to B<sudo> invalidates
by setting the time on it to the Epoch. The next time B<sudo> is the user's timestamp by setting the time on it to the Epoch. The
run a password will be required. This option does not require a password next time B<sudo> is run a password will be required. This option
and was added to allow a user to revoke B<sudo> permissions from a .logout does not require a password and was added to allow a user to revoke
file. B<sudo> permissions from a .logout file.
When used in conjunction with a command or an option that may require
a password, the B<-k> option will cause B<sudo> to ignore the user's
timestamp file. As a result, B<sudo> will prompt for a password
(if one is required by I<sudoers>) and will not update the user's
timestamp file.
=item -L =item -L

View File

@@ -5,9 +5,10 @@
* Usage strings for sudo. These are here because we * Usage strings for sudo. These are here because we
* need to be able to substitute values from configure. * need to be able to substitute values from configure.
*/ */
#define SUDO_USAGE1 " [-n] -h | -K | -k | -L | -V | -v" #define SUDO_USAGE1 " -h | -K | -k | -L | -V"
#define SUDO_USAGE2 " -l[l] [-AnS] [-g groupname|#gid] [-U username] [-u username|#uid] [-g groupname|#gid] [command]" #define SUDO_USAGE2 " -v [-AknS] @BSDAUTH_USAGE@[-p prompt]"
#define SUDO_USAGE3 " [-AbEHnPS] @BSDAUTH_USAGE@@SELINUX_USAGE@[-C fd] @LOGINCAP_USAGE@[-g groupname|#gid] [-p prompt] [-u username|#uid] [-g groupname|#gid] [VAR=value] [-i|-s] [<command>]" #define SUDO_USAGE3 " -l[l] [-AknS] @BSDAUTH_USAGE@[-g groupname|#gid] [-p prompt] [-U username] [-u username|#uid] [-g groupname|#gid] [command]"
#define SUDO_USAGE4 " -e [-AnS] @BSDAUTH_USAGE@@SELINUX_USAGE@[-C fd] @LOGINCAP_USAGE@[-g groupname|#gid] [-p prompt] [-u username|#uid] file ..." #define SUDO_USAGE4 " [-AbEHknPS] @BSDAUTH_USAGE@@SELINUX_USAGE@[-C fd] @LOGINCAP_USAGE@[-g groupname|#gid] [-p prompt] [-u username|#uid] [-g groupname|#gid] [VAR=value] [-i|-s] [<command>]"
#define SUDO_USAGE5 " -e [-AknS] @BSDAUTH_USAGE@@SELINUX_USAGE@[-C fd] @LOGINCAP_USAGE@[-g groupname|#gid] [-p prompt] [-u username|#uid] file ..."
#endif /* _SUDO_USAGE_H */ #endif /* _SUDO_USAGE_H */