From 15975b83ce2d103618f59caa97a9e0b909f1643c Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Tue, 24 Feb 2009 13:04:39 +0000 Subject: [PATCH] Allow the -k flag to be specified in conjunction with a command or another option that may require authentication. --- check.c | 20 ++++++++++------- sudo.c | 58 ++++++++++++++++++++++++++++++++++--------------- sudo.pod | 33 +++++++++++++++++++--------- sudo_usage.h.in | 9 ++++---- 4 files changed, 80 insertions(+), 40 deletions(-) diff --git a/check.c b/check.c index ad4074bdb..e7ce829f8 100644 --- a/check.c +++ b/check.c @@ -84,24 +84,29 @@ static void update_timestamp __P((char *, char *)); * verify who he/she is. */ void -check_user(validated, interactive) +check_user(validated, mode) int validated; - int interactive; + int mode; { char *timestampdir = NULL; char *timestampfile = NULL; char *prompt; int status; - if (user_uid == 0 || user_uid == runas_pw->pw_uid || user_is_exempt()) - return; + if (mode & MODE_INVALIDATE) { + /* 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(×tampdir, ×tampfile); - status = timestamp_status(timestampdir, timestampfile, user_name, + build_timestamp(×tampdir, ×tampfile); + status = timestamp_status(timestampdir, timestampfile, user_name, TS_MAKE_DIRS); + } if (status != TS_CURRENT || ISSET(validated, FLAG_CHECK_USER)) { /* 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()); /* If user specified -A, make sure we have an askpass helper. */ @@ -139,7 +144,6 @@ check_user(validated, interactive) /* * Standard sudo lecture. - * TODO: allow the user to specify a file name instead. */ static void lecture(status) diff --git a/sudo.c b/sudo.c index 71186ef2c..f4e4537a2 100644 --- a/sudo.c +++ b/sudo.c @@ -95,8 +95,8 @@ # include #endif +#include #include "sudo.h" -#include "sudo_usage.h" #include "lbuf.h" #include "interfaces.h" #include "version.h" @@ -231,7 +231,7 @@ main(argc, argv, envp) user_cmnd = "shell"; else if (ISSET(sudo_mode, MODE_EDIT)) user_cmnd = "sudoedit"; - else + else { switch (sudo_mode) { case MODE_VERSION: show_version(); @@ -240,11 +240,12 @@ main(argc, argv, envp) usage(0); break; case MODE_VALIDATE: + case MODE_VALIDATE|MODE_INVALIDATE: user_cmnd = "validate"; pwflag = I_VERIFYPW; break; - case MODE_KILL: case MODE_INVALIDATE: + case MODE_KILL: user_cmnd = "kill"; pwflag = -1; break; @@ -253,13 +254,16 @@ main(argc, argv, envp) exit(0); break; case MODE_LIST: + case MODE_LIST|MODE_INVALIDATE: user_cmnd = "list"; pwflag = I_LISTPW; break; case MODE_CHECK: + case MODE_CHECK|MODE_INVALIDATE: pwflag = I_LISTPW; break; } + } /* Must have a command to run... */ if (user_cmnd == NULL && NewArgc == 0) @@ -405,7 +409,7 @@ main(argc, argv, envp) /* Require a password if sudoers says so. */ 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. */ /* XXX - causes confusion when root is not listed in sudoers */ @@ -438,9 +442,9 @@ main(argc, argv, envp) } 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); - else if (sudo_mode == MODE_LIST) + else if (ISSET(sudo_mode, MODE_LIST)) display_privs(snl, list_pw ? list_pw : sudo_user.pw); /* Cleanup sudoers sources */ @@ -448,8 +452,7 @@ main(argc, argv, envp) nss->close(nss); /* Deferred exit due to sudo_ldap_close() */ - if (sudo_mode == MODE_VALIDATE || sudo_mode == MODE_CHECK || - sudo_mode == MODE_LIST) + if (ISSET(sudo_mode, (MODE_VALIDATE|MODE_CHECK|MODE_LIST))) exit(rc); /* @@ -835,7 +838,7 @@ parse_args(argc, argv) { int mode = 0; /* what mode is sudo to be run in? */ int flags = 0; /* mode flags */ - int ch; + int allowed_flags, ch; /* First, check to see if we were invoked as "sudoedit". */ if (strcmp(getprogname(), "sudoedit") == 0) @@ -849,6 +852,10 @@ parse_args(argc, argv) #define is_envar (optind < argc && argv[optind][0] != '/' && \ 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 (;;) { /* * We disable arg permutation for GNU getopt(). @@ -887,6 +894,7 @@ parse_args(argc, argv) if (mode && mode != MODE_EDIT) usage_excl(1); mode = MODE_EDIT; + allowed_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE; break; case 'g': runas_group = optarg; @@ -898,25 +906,26 @@ parse_args(argc, argv) if (mode && mode != MODE_HELP) usage_excl(1); mode = MODE_HELP; + allowed_flags = 0; break; case 'i': SET(flags, MODE_LOGIN_SHELL); def_env_reset = TRUE; break; case 'k': - if (mode && mode != MODE_INVALIDATE) - usage_excl(1); - mode = MODE_INVALIDATE; + SET(flags, MODE_INVALIDATE); break; case 'K': if (mode && mode != MODE_KILL) usage_excl(1); mode = MODE_KILL; + allowed_flags = 0; break; case 'L': if (mode && mode != MODE_LISTDEFS) usage_excl(1); mode = MODE_LISTDEFS; + allowed_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE; break; case 'l': if (mode) { @@ -926,6 +935,7 @@ parse_args(argc, argv) usage_excl(1); } mode = MODE_LIST; + allowed_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE; break; case 'n': SET(flags, MODE_NONINTERACTIVE); @@ -962,11 +972,13 @@ parse_args(argc, argv) if (mode && mode != MODE_VALIDATE) usage_excl(1); mode = MODE_VALIDATE; + allowed_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE; break; case 'V': if (mode && mode != MODE_VERSION) usage_excl(1); mode = MODE_VERSION; + allowed_flags = 0; break; default: usage(1); @@ -991,8 +1003,15 @@ parse_args(argc, argv) NewArgc = argc - optind; NewArgv = argv + optind; - if (!mode) - mode = MODE_RUN; + if (!mode) { + /* 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) mode = MODE_CHECK; @@ -1008,6 +1027,8 @@ parse_args(argc, argv) } SET(flags, MODE_SHELL); } + if ((flags & allowed_flags) != flags) + usage(1); if (mode == MODE_EDIT && (ISSET(flags, MODE_PRESERVE_ENV) || sudo_user.env_vars != NULL)) { if (ISSET(mode, MODE_PRESERVE_ENV)) @@ -1431,7 +1452,7 @@ static void usage_excl(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); } @@ -1444,21 +1465,22 @@ usage(exit_val) int exit_val; { struct lbuf lbuf; - char *uvec[5]; + char *uvec[6]; int i, ulen; /* * Use usage vectors appropriate to the progname. */ if (strcmp(getprogname(), "sudoedit") == 0) { - uvec[0] = SUDO_USAGE4 + 3; + uvec[0] = SUDO_USAGE5 + 3; uvec[1] = NULL; } else { uvec[0] = SUDO_USAGE1; uvec[1] = SUDO_USAGE2; uvec[2] = SUDO_USAGE3; uvec[3] = SUDO_USAGE4; - uvec[4] = NULL; + uvec[4] = SUDO_USAGE5; + uvec[5] = NULL; } /* diff --git a/sudo.pod b/sudo.pod index a8543a796..6aff7c1a5 100644 --- a/sudo.pod +++ b/sudo.pod @@ -27,10 +27,16 @@ sudo, sudoedit - execute a command as another user =head1 SYNOPSIS -B [B<-n>] B<-h> | B<-K> | B<-k> | B<-L> | B<-V> | B<-v> +B B<-h> | B<-K> | B<-k> | B<-L> | B<-V> -B B<-l[l]> [B<-AnS>] S<[B<-g> I|I<#gid>]> S<[B<-U> I]> -S<[B<-u> I|I<#uid>]> [I] +B B<-v> [B<-AknS>] +S<[B<-a> I]> +S<[B<-p> I]> + +B B<-l[l]> [B<-AknS>] +S<[B<-a> I]> +S<[B<-g> I|I<#gid>]> S<[B<-p> I]> +S<[B<-U> I]> S<[B<-u> I|I<#uid>]> [I] B [B<-AbEHnPS>] S<[B<-a> I]> @@ -231,16 +237,23 @@ All other environment variables are removed. =item -K The B<-K> (sure I) option is like B<-k> except that it removes -the user's timestamp entirely. Like B<-k>, this option does not -require a password. +the user's timestamp entirely and may not be used in conjunction +with a command or other option. This option does not require a +password. =item -k -The B<-k> (I) option to B invalidates the user's timestamp -by setting the time on it to the Epoch. The next time B is -run a password will be required. This option does not require a password -and was added to allow a user to revoke B permissions from a .logout -file. +When used by itself, the B<-k> (I) option to B invalidates +the user's timestamp by setting the time on it to the Epoch. The +next time B is run a password will be required. This option +does not require a password and was added to allow a user to revoke +B 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 to ignore the user's +timestamp file. As a result, B will prompt for a password +(if one is required by I) and will not update the user's +timestamp file. =item -L diff --git a/sudo_usage.h.in b/sudo_usage.h.in index 5a1bfc60f..e6db4ee3f 100644 --- a/sudo_usage.h.in +++ b/sudo_usage.h.in @@ -5,9 +5,10 @@ * Usage strings for sudo. These are here because we * need to be able to substitute values from configure. */ -#define SUDO_USAGE1 " [-n] -h | -K | -k | -L | -V | -v" -#define SUDO_USAGE2 " -l[l] [-AnS] [-g groupname|#gid] [-U username] [-u username|#uid] [-g groupname|#gid] [command]" -#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] []" -#define SUDO_USAGE4 " -e [-AnS] @BSDAUTH_USAGE@@SELINUX_USAGE@[-C fd] @LOGINCAP_USAGE@[-g groupname|#gid] [-p prompt] [-u username|#uid] file ..." +#define SUDO_USAGE1 " -h | -K | -k | -L | -V" +#define SUDO_USAGE2 " -v [-AknS] @BSDAUTH_USAGE@[-p prompt]" +#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 " [-AbEHknPS] @BSDAUTH_USAGE@@SELINUX_USAGE@[-C fd] @LOGINCAP_USAGE@[-g groupname|#gid] [-p prompt] [-u username|#uid] [-g groupname|#gid] [VAR=value] [-i|-s] []" +#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 */ -- 2.40.0