Add support for setting environment variables on the command line.

This is only allowed if the setenv sudoers options is enabled or if
the command is prefixed with the SETENV tag.
This commit is contained in:
Todd C. Miller
2007-06-23 23:58:54 +00:00
parent 459c4bcd3a
commit 879c46e4dd
16 changed files with 1379 additions and 1188 deletions

View File

@@ -271,6 +271,10 @@ struct sudo_defs_types sudo_defs_table[] = {
"env_keep", T_LIST|T_BOOL, "env_keep", T_LIST|T_BOOL,
"Environment variables to preserve:", "Environment variables to preserve:",
NULL, NULL,
}, {
"setenv", T_FLAG,
"Allow users to set arbitrary environment variables",
NULL,
}, { }, {
NULL, 0, NULL NULL, 0, NULL
} }

View File

@@ -122,6 +122,8 @@
#define I_ENV_DELETE 60 #define I_ENV_DELETE 60
#define def_env_keep (sudo_defs_table[61].sd_un.list) #define def_env_keep (sudo_defs_table[61].sd_un.list)
#define I_ENV_KEEP 61 #define I_ENV_KEEP 61
#define def_setenv (sudo_defs_table[62].sd_un.flag)
#define I_SETENV 62
enum def_tupple { enum def_tupple {
never, never,

View File

@@ -200,3 +200,6 @@ env_delete
env_keep env_keep
T_LIST|T_BOOL T_LIST|T_BOOL
"Environment variables to preserve:" "Environment variables to preserve:"
setenv
T_FLAG
"Allow users to set arbitrary environment variables"

6
env.c
View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000-2005 Todd C. Miller <Todd.Miller@courtesan.com> * Copyright (c) 2000-2007 Todd C. Miller <Todd.Miller@courtesan.com>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -551,6 +551,10 @@ rebuild_env(envp, sudo_mode, noexec)
easprintf(&cp, "SUDO_GID=%lu", (unsigned long) user_gid); easprintf(&cp, "SUDO_GID=%lu", (unsigned long) user_gid);
insert_env(cp, &env, 1); insert_env(cp, &env, 1);
/* Add user-specified environment variables. */
for (cur = sudo_user.env_vars; cur != NULL; cur = cur->next)
insert_env(cur->value, &env, 1);
return(env.envp); return(env.envp);
} }

639
gram.c

File diff suppressed because it is too large Load Diff

16
gram.h
View File

@@ -17,13 +17,15 @@
#define EXEC 273 #define EXEC 273
#define MONITOR 274 #define MONITOR 274
#define NOMONITOR 275 #define NOMONITOR 275
#define ALL 276 #define SETENV 276
#define COMMENT 277 #define NOSETENV 277
#define HOSTALIAS 278 #define ALL 278
#define CMNDALIAS 279 #define COMMENT 279
#define USERALIAS 280 #define HOSTALIAS 280
#define RUNASALIAS 281 #define CMNDALIAS 281
#define ERROR 282 #define USERALIAS 282
#define RUNASALIAS 283
#define ERROR 284
#ifndef YYSTYPE_DEFINED #ifndef YYSTYPE_DEFINED
#define YYSTYPE_DEFINED #define YYSTYPE_DEFINED
typedef union { typedef union {

19
gram.y
View File

@@ -1,6 +1,7 @@
%{ %{
/* /*
* Copyright (c) 1996, 1998-2005 Todd C. Miller <Todd.Miller@courtesan.com> * Copyright (c) 1996, 1998-2005, 2007
* Todd C. Miller <Todd.Miller@courtesan.com>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -128,6 +129,8 @@ yyerror(s)
%token <tok> EXEC /* don't preload dummy execve() */ %token <tok> EXEC /* don't preload dummy execve() */
%token <tok> MONITOR /* monitor children of cmnd */ %token <tok> MONITOR /* monitor children of cmnd */
%token <tok> NOMONITOR /* disable monitoring of children */ %token <tok> NOMONITOR /* disable monitoring of children */
%token <tok> SETENV /* user may set environment for cmnd */
%token <tok> NOSETENV /* user may not set environment */
%token <tok> ALL /* ALL keyword */ %token <tok> ALL /* ALL keyword */
%token <tok> COMMENT /* comment and/or carriage return */ %token <tok> COMMENT /* comment and/or carriage return */
%token <tok> HOSTALIAS /* Host_Alias keyword */ %token <tok> HOSTALIAS /* Host_Alias keyword */
@@ -243,13 +246,16 @@ privilege : hostlist '=' cmndspeclist {
struct cmndspec *cs; struct cmndspec *cs;
p->hostlist = $1; p->hostlist = $1;
p->cmndlist = $3; p->cmndlist = $3;
tags.nopasswd = tags.noexec = tags.monitor = UNSPEC; tags.nopasswd = tags.noexec = tags.monitor =
tags.setenv = UNSPEC;
/* propagate tags */ /* propagate tags */
for (cs = $3; cs != NULL; cs = cs->next) { for (cs = $3; cs != NULL; cs = cs->next) {
if (cs->tags.nopasswd == UNSPEC) if (cs->tags.nopasswd == UNSPEC)
cs->tags.nopasswd = tags.nopasswd; cs->tags.nopasswd = tags.nopasswd;
if (cs->tags.noexec == UNSPEC) if (cs->tags.noexec == UNSPEC)
cs->tags.noexec = tags.noexec; cs->tags.noexec = tags.noexec;
if (cs->tags.setenv == UNSPEC)
cs->tags.setenv = tags.setenv;
if (cs->tags.monitor == UNSPEC) if (cs->tags.monitor == UNSPEC)
cs->tags.monitor = tags.monitor; cs->tags.monitor = tags.monitor;
memcpy(&tags, &cs->tags, sizeof(tags)); memcpy(&tags, &cs->tags, sizeof(tags));
@@ -358,7 +364,8 @@ runasuser : ALIAS {
; ;
cmndtag : /* empty */ { cmndtag : /* empty */ {
$$.nopasswd = $$.noexec = $$.monitor = UNSPEC; $$.nopasswd = $$.noexec = $$.monitor =
$$.setenv = UNSPEC;
} }
| cmndtag NOPASSWD { | cmndtag NOPASSWD {
$$.nopasswd = TRUE; $$.nopasswd = TRUE;
@@ -372,6 +379,12 @@ cmndtag : /* empty */ {
| cmndtag EXEC { | cmndtag EXEC {
$$.noexec = FALSE; $$.noexec = FALSE;
} }
| cmndtag SETENV {
$$.setenv = TRUE;
}
| cmndtag NOSETENV {
$$.setenv = FALSE;
}
| cmndtag MONITOR { | cmndtag MONITOR {
$$.monitor = TRUE; $$.monitor = TRUE;
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1994-1996,1998-2005 Todd C. Miller <Todd.Miller@courtesan.com> * Copyright (c) 1994-1996,1998-2007 Todd C. Miller <Todd.Miller@courtesan.com>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -275,6 +275,7 @@ log_auth(status, inform_user)
int status; int status;
int inform_user; int inform_user;
{ {
char *evstr = NULL;
char *message; char *message;
char *logline; char *logline;
int pri; int pri;
@@ -296,9 +297,21 @@ log_auth(status, inform_user)
else else
message = "unknown error ; "; message = "unknown error ; ";
easprintf(&logline, "%sTTY=%s ; PWD=%s ; USER=%s ; COMMAND=%s%s%s", if (sudo_user.env_vars != NULL) {
message, user_tty, user_cwd, *user_runas, user_cmnd, size_t len = 7; /* " ; ENV=" */
user_args ? " " : "", user_args ? user_args : ""); struct list_member *cur;
for (cur = sudo_user.env_vars; cur != NULL; cur = cur->next)
len += strlen(cur->value) + 1;
evstr = emalloc(len);
strlcpy(evstr, " ; ENV=", len);
for (cur = sudo_user.env_vars; cur != NULL; cur = cur->next) {
strlcat(evstr, cur->value, len);
strlcat(evstr, " ", len); /* NOTE: last one will fail */
}
}
easprintf(&logline, "%sTTY=%s ; PWD=%s ; USER=%s%s ; COMMAND=%s%s%s",
message, user_tty, user_cwd, *user_runas, evstr ? evstr : "",
user_cmnd, user_args ? " " : "", user_args ? user_args : "");
mail_auth(status, logline); /* send mail based on status */ mail_auth(status, logline); /* send mail based on status */
@@ -329,6 +342,7 @@ log_auth(status, inform_user)
if (def_logfile) if (def_logfile)
do_logfile(logline); do_logfile(logline);
efree(evstr);
efree(logline); efree(logline);
} }
@@ -345,6 +359,7 @@ log_error(flags, fmt, va_alist)
int serrno = errno; int serrno = errno;
char *message; char *message;
char *logline; char *logline;
char *evstr = NULL;
va_list ap; va_list ap;
#ifdef __STDC__ #ifdef __STDC__
va_start(ap, fmt); va_start(ap, fmt);
@@ -360,28 +375,43 @@ log_error(flags, fmt, va_alist)
evasprintf(&message, fmt, ap); evasprintf(&message, fmt, ap);
va_end(ap); va_end(ap);
if (sudo_user.env_vars != NULL) {
size_t len = 7; /* " ; ENV=" */
struct list_member *cur;
for (cur = sudo_user.env_vars; cur != NULL; cur = cur->next)
len += strlen(cur->value) + 1;
evstr = emalloc(len);
strlcpy(evstr, " ; ENV=", len);
for (cur = sudo_user.env_vars; cur != NULL; cur = cur->next) {
strlcat(evstr, cur->value, len);
strlcat(evstr, " ", len); /* NOTE: last one will fail */
}
}
if (ISSET(flags, MSG_ONLY)) if (ISSET(flags, MSG_ONLY))
logline = message; logline = message;
else if (ISSET(flags, USE_ERRNO)) { else if (ISSET(flags, USE_ERRNO)) {
if (user_args) { if (user_args) {
easprintf(&logline, easprintf(&logline,
"%s: %s ; TTY=%s ; PWD=%s ; USER=%s ; COMMAND=%s %s", "%s: %s ; TTY=%s ; PWD=%s ; USER=%s%s ; COMMAND=%s %s",
message, strerror(serrno), user_tty, user_cwd, *user_runas, message, strerror(serrno), user_tty, user_cwd, *user_runas,
user_cmnd, user_args); evstr ? evstr : "", user_cmnd, user_args);
} else { } else {
easprintf(&logline, easprintf(&logline,
"%s: %s ; TTY=%s ; PWD=%s ; USER=%s ; COMMAND=%s", message, "%s: %s ; TTY=%s ; PWD=%s ; USER=%s%s ; COMMAND=%s", message,
strerror(serrno), user_tty, user_cwd, *user_runas, user_cmnd); strerror(serrno), user_tty, user_cwd, *user_runas,
evstr ? evstr : "", user_cmnd);
} }
} else { } else {
if (user_args) { if (user_args) {
easprintf(&logline, easprintf(&logline,
"%s ; TTY=%s ; PWD=%s ; USER=%s ; COMMAND=%s %s", message, "%s ; TTY=%s ; PWD=%s ; USER=%s%s ; COMMAND=%s %s", message,
user_tty, user_cwd, *user_runas, user_cmnd, user_args); user_tty, user_cwd, *user_runas, evstr ? evstr : "",
user_cmnd, user_args);
} else { } else {
easprintf(&logline, easprintf(&logline,
"%s ; TTY=%s ; PWD=%s ; USER=%s ; COMMAND=%s", message, "%s ; TTY=%s ; PWD=%s ; USER=%s%s ; COMMAND=%s", message,
user_tty, user_cwd, *user_runas, user_cmnd); user_tty, user_cwd, *user_runas, evstr ? evstr : "", user_cmnd);
} }
} }

13
parse.c
View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2004-2005 Todd C. Miller <Todd.Miller@courtesan.com> * Copyright (c) 2004-2005, 2007 Todd C. Miller <Todd.Miller@courtesan.com>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -193,6 +193,8 @@ sudoers_lookup(pwflag)
def_authenticate = !tags->nopasswd; def_authenticate = !tags->nopasswd;
if (tags->noexec != UNSPEC) if (tags->noexec != UNSPEC)
def_noexec = tags->noexec; def_noexec = tags->noexec;
if (tags->setenv != UNSPEC)
def_setenv = tags->setenv;
if (tags->monitor != UNSPEC) if (tags->monitor != UNSPEC)
def_monitor = tags->monitor; def_monitor = tags->monitor;
} }
@@ -244,6 +246,7 @@ display_privs(v, pw)
for (priv = us->privileges; priv != NULL; priv = priv->next) { for (priv = us->privileges; priv != NULL; priv = priv->next) {
tags.monitor = def_monitor; tags.monitor = def_monitor;
tags.noexec = def_noexec; tags.noexec = def_noexec;
tags.setenv = def_setenv;
tags.nopasswd = !def_authenticate; tags.nopasswd = !def_authenticate;
for (cs = priv->cmndlist; cs != NULL; cs = cs->next) { for (cs = priv->cmndlist; cs != NULL; cs = cs->next) {
if (cs != priv->cmndlist) if (cs != priv->cmndlist)
@@ -261,12 +264,16 @@ display_privs(v, pw)
print_priv(cs->tags.monitor ? "MONITOR: " : "NOMONITOR: "); print_priv(cs->tags.monitor ? "MONITOR: " : "NOMONITOR: ");
tags.monitor = cs->tags.monitor; tags.monitor = cs->tags.monitor;
} }
if (TAG_CHANGED(setenv)) {
print_priv(cs->tags.setenv ? "SETENV: " : "NOSETENV: ");
tags.setenv = cs->tags.setenv;
}
if (TAG_CHANGED(noexec)) { if (TAG_CHANGED(noexec)) {
print_priv(cs->tags.monitor ? "EXEC: " : "NOEXEC: "); print_priv(cs->tags.noexec ? "NOEXEC: " : "EXEC: ");
tags.noexec = cs->tags.noexec; tags.noexec = cs->tags.noexec;
} }
if (TAG_CHANGED(nopasswd)) { if (TAG_CHANGED(nopasswd)) {
print_priv(cs->tags.monitor ? "PASSWD: " : "NOPASSWD: "); print_priv(cs->tags.nopasswd ? "NOPASSWD: " : "PASSWD: ");
tags.nopasswd = cs->tags.nopasswd; tags.nopasswd = cs->tags.nopasswd;
} }
m = cs->cmnd; m = cs->cmnd;

View File

@@ -1,5 +1,6 @@
/* /*
* Copyright (c) 1996,1998-2000,2004 Todd C. Miller <Todd.Miller@courtesan.com> * Copyright (c) 1996, 1998-2000, 2004, 2007
* Todd C. Miller <Todd.Miller@courtesan.com>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -42,6 +43,7 @@ struct sudo_command {
struct cmndtag { struct cmndtag {
char nopasswd; char nopasswd;
char noexec; char noexec;
char setenv;
char monitor; char monitor;
char extra; char extra;
}; };

342
sudo.c
View File

@@ -342,6 +342,14 @@ main(argc, argv)
(void) close(fd); (void) close(fd);
} }
/* Build a new environment based on the rules in sudoers. */
if (ISSET(sudo_mode, MODE_RUN)) {
/* User may have overrided environment resetting via the -E flag. */
if (ISSET(sudo_mode, MODE_PRESERVE_ENV) && def_setenv)
def_env_reset = FALSE;
environ = rebuild_env(environ, sudo_mode, def_noexec);
}
/* Fill in passwd struct based on user we are authenticating as. */ /* Fill in passwd struct based on user we are authenticating as. */
auth_pw = get_authpw(); auth_pw = get_authpw();
@@ -360,10 +368,6 @@ main(argc, argv)
} }
} }
/* Build a new environment based on the rules in sudoers. */
if (ISSET(sudo_mode, MODE_RUN))
environ = rebuild_env(environ, sudo_mode, def_noexec);
if (ISSET(validated, VALIDATE_OK)) { if (ISSET(validated, VALIDATE_OK)) {
/* Finally tell the user if the command did not exist. */ /* Finally tell the user if the command did not exist. */
if (cmnd_status == NOT_FOUND_DOT) { if (cmnd_status == NOT_FOUND_DOT) {
@@ -374,6 +378,16 @@ main(argc, argv)
exit(1); exit(1);
} }
/* If user specified env vars make sure sudoers allows it. */
if (ISSET(sudo_mode, MODE_RUN) && !def_setenv) {
if (ISSET(sudo_mode, MODE_PRESERVE_ENV))
log_error(NO_MAIL,
"sorry, you are not allowed to preserve the environment");
else if (sudo_user.env_vars != NULL)
log_error(NO_MAIL,
"sorry, you are not allowed to set environment variables");
}
log_auth(validated, 1); log_auth(validated, 1);
if (sudo_mode == MODE_VALIDATE) if (sudo_mode == MODE_VALIDATE)
exit(0); exit(0);
@@ -745,160 +759,175 @@ parse_args(argc, argv)
return(rval); return(rval);
} }
while (NewArgc > 0 && NewArgv[0][0] == '-') { while (NewArgc > 0) {
if (NewArgv[0][1] != '\0' && NewArgv[0][2] != '\0') if (NewArgv[0][0] == '-') {
warningx("please use single character options"); if (NewArgv[0][1] != '\0' && NewArgv[0][2] != '\0')
warningx("please use single character options");
switch (NewArgv[0][1]) { switch (NewArgv[0][1]) {
case 'p': case 'p':
/* Must have an associated prompt. */ /* Must have an associated prompt. */
if (NewArgv[1] == NULL) if (NewArgv[1] == NULL)
usage(1);
user_prompt = NewArgv[1];
NewArgc--;
NewArgv++;
break;
case 'u':
/* Must have an associated runas user. */
if (NewArgv[1] == NULL)
usage(1);
user_runas = &NewArgv[1];
NewArgc--;
NewArgv++;
break;
#ifdef HAVE_BSD_AUTH_H
case 'a':
/* Must have an associated authentication style. */
if (NewArgv[1] == NULL)
usage(1);
login_style = NewArgv[1];
NewArgc--;
NewArgv++;
break;
#endif
#ifdef HAVE_LOGIN_CAP_H
case 'c':
/* Must have an associated login class. */
if (NewArgv[1] == NULL)
usage(1);
login_class = NewArgv[1];
def_use_loginclass = TRUE;
NewArgc--;
NewArgv++;
break;
#endif
case 'C':
if (NewArgv[1] == NULL)
usage(1);
if ((user_closefrom = atoi(NewArgv[1])) < 3) {
warningx("the argument to -C must be at least 3");
usage(1);
}
NewArgc--;
NewArgv++;
break;
case 'b':
SET(rval, MODE_BACKGROUND);
break;
case 'e':
rval = MODE_EDIT;
if (excl && excl != 'e')
usage_excl(1);
excl = 'e';
break;
case 'v':
rval = MODE_VALIDATE;
if (excl && excl != 'v')
usage_excl(1);
excl = 'v';
break;
case 'i':
SET(rval, (MODE_LOGIN_SHELL | MODE_SHELL));
def_env_reset = TRUE;
if (excl && excl != 'i')
usage_excl(1);
excl = 'i';
break;
case 'k':
rval = MODE_INVALIDATE;
if (excl && excl != 'k')
usage_excl(1);
excl = 'k';
break;
case 'K':
rval = MODE_KILL;
if (excl && excl != 'K')
usage_excl(1);
excl = 'K';
break;
case 'L':
rval = MODE_LISTDEFS;
if (excl && excl != 'L')
usage_excl(1);
excl = 'L';
break;
case 'l':
rval = MODE_LIST;
if (excl && excl != 'l')
usage_excl(1);
excl = 'l';
break;
case 'V':
rval = MODE_VERSION;
if (excl && excl != 'V')
usage_excl(1);
excl = 'V';
break;
case 'h':
rval = MODE_HELP;
if (excl && excl != 'h')
usage_excl(1);
excl = 'h';
break;
case 's':
SET(rval, MODE_SHELL);
if (excl && excl != 's')
usage_excl(1);
excl = 's';
break;
case 'H':
SET(rval, MODE_RESET_HOME);
break;
case 'P':
SET(rval, MODE_PRESERVE_GROUPS);
break;
case 'S':
SET(tgetpass_flags, TGP_STDIN);
break;
case 'U':
/* Must have an associated list user. */
if (NewArgv[1] == NULL)
usage(1);
if ((list_pw = sudo_getpwnam(NewArgv[1])) == NULL)
errorx(1, "unknown user %s", NewArgv[1]);
NewArgc--;
NewArgv++;
break;
case 'E':
SET(rval, MODE_PRESERVE_ENV);
break;
case '-':
NewArgc--;
NewArgv++;
if (rval == MODE_RUN)
SET(rval, (MODE_IMPLIED_SHELL | MODE_SHELL));
return(rval);
case '\0':
warningx("'-' requires an argument");
usage(1); usage(1);
default:
user_prompt = NewArgv[1]; warningx("illegal option `%s'", NewArgv[0]);
NewArgc--;
NewArgv++;
break;
case 'u':
/* Must have an associated runas user. */
if (NewArgv[1] == NULL)
usage(1); usage(1);
}
user_runas = &NewArgv[1]; } else if (NewArgv[0][0] != '/' && strchr(NewArgv[0], '=') != NULL) {
/* Could be an environment variable. */
NewArgc--; struct list_member *ev;
NewArgv++; ev = emalloc(sizeof(*ev));
break; ev->value = NewArgv[0];
#ifdef HAVE_BSD_AUTH_H ev->next = sudo_user.env_vars;
case 'a': sudo_user.env_vars = ev;
/* Must have an associated authentication style. */ } else {
if (NewArgv[1] == NULL) /* Not an arg */
usage(1); break;
login_style = NewArgv[1];
NewArgc--;
NewArgv++;
break;
#endif
#ifdef HAVE_LOGIN_CAP_H
case 'c':
/* Must have an associated login class. */
if (NewArgv[1] == NULL)
usage(1);
login_class = NewArgv[1];
def_use_loginclass = TRUE;
NewArgc--;
NewArgv++;
break;
#endif
case 'C':
if (NewArgv[1] == NULL)
usage(1);
if ((user_closefrom = atoi(NewArgv[1])) < 3) {
warningx("the argument to -C must be at least 3");
usage(1);
}
NewArgc--;
NewArgv++;
break;
case 'b':
SET(rval, MODE_BACKGROUND);
break;
case 'e':
rval = MODE_EDIT;
if (excl && excl != 'e')
usage_excl(1);
excl = 'e';
break;
case 'v':
rval = MODE_VALIDATE;
if (excl && excl != 'v')
usage_excl(1);
excl = 'v';
break;
case 'i':
SET(rval, (MODE_LOGIN_SHELL | MODE_SHELL));
def_env_reset = TRUE;
if (excl && excl != 'i')
usage_excl(1);
excl = 'i';
break;
case 'k':
rval = MODE_INVALIDATE;
if (excl && excl != 'k')
usage_excl(1);
excl = 'k';
break;
case 'K':
rval = MODE_KILL;
if (excl && excl != 'K')
usage_excl(1);
excl = 'K';
break;
case 'L':
rval = MODE_LISTDEFS;
if (excl && excl != 'L')
usage_excl(1);
excl = 'L';
break;
case 'l':
rval = MODE_LIST;
if (excl && excl != 'l')
usage_excl(1);
excl = 'l';
break;
case 'V':
rval = MODE_VERSION;
if (excl && excl != 'V')
usage_excl(1);
excl = 'V';
break;
case 'h':
rval = MODE_HELP;
if (excl && excl != 'h')
usage_excl(1);
excl = 'h';
break;
case 's':
SET(rval, MODE_SHELL);
if (excl && excl != 's')
usage_excl(1);
excl = 's';
break;
case 'H':
SET(rval, MODE_RESET_HOME);
break;
case 'P':
SET(rval, MODE_PRESERVE_GROUPS);
break;
case 'S':
SET(tgetpass_flags, TGP_STDIN);
break;
case 'U':
/* Must have an associated list user. */
if (NewArgv[1] == NULL)
usage(1);
if ((list_pw = sudo_getpwnam(NewArgv[1])) == NULL)
errorx(1, "unknown user %s", NewArgv[1]);
NewArgc--;
NewArgv++;
break;
case '-':
NewArgc--;
NewArgv++;
if (rval == MODE_RUN)
SET(rval, (MODE_IMPLIED_SHELL | MODE_SHELL));
return(rval);
case '\0':
warningx("'-' requires an argument");
usage(1);
default:
warningx("illegal option `%s'", NewArgv[0]);
usage(1);
} }
NewArgc--; NewArgc--;
NewArgv++; NewArgv++;
@@ -1267,7 +1296,7 @@ usage(exit_val)
char **p; char **p;
int linelen, linemax, ulen; int linelen, linemax, ulen;
static char *uvec[] = { static char *uvec[] = {
" [-bHPS]", " [-bEHPS]",
#ifdef HAVE_BSD_AUTH_H #ifdef HAVE_BSD_AUTH_H
" [-a auth_type]", " [-a auth_type]",
#endif #endif
@@ -1277,6 +1306,7 @@ usage(exit_val)
#endif #endif
" [-p prompt]", " [-p prompt]",
" [-u username|#uid]", " [-u username|#uid]",
" [VAR=value]",
" { -e file [...] | -i | -s | <command> }", " { -e file [...] | -i | -s | <command> }",
NULL NULL
}; };

37
sudo.h
View File

@@ -1,5 +1,6 @@
/* /*
* Copyright (c) 1993-1996,1998-2005 Todd C. Miller <Todd.Miller@courtesan.com> * Copyright (c) 1993-1996, 1998-2005, 2007
* Todd C. Miller <Todd.Miller@courtesan.com>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -51,6 +52,7 @@ struct sudo_user {
char *class_name; char *class_name;
int ngroups; int ngroups;
gid_t *groups; gid_t *groups;
struct list_member *env_vars;
char cwd[PATH_MAX]; char cwd[PATH_MAX];
}; };
@@ -85,22 +87,23 @@ struct sudo_user {
/* /*
* Various modes sudo can be in (based on arguments) in hex * Various modes sudo can be in (based on arguments) in hex
*/ */
#define MODE_RUN 0x0001 #define MODE_RUN 0x00001
#define MODE_EDIT 0x0002 #define MODE_EDIT 0x00002
#define MODE_VALIDATE 0x0004 #define MODE_VALIDATE 0x00004
#define MODE_INVALIDATE 0x0008 #define MODE_INVALIDATE 0x00008
#define MODE_KILL 0x0010 #define MODE_KILL 0x00010
#define MODE_VERSION 0x0020 #define MODE_VERSION 0x00020
#define MODE_HELP 0x0040 #define MODE_HELP 0x00040
#define MODE_LIST 0x0080 #define MODE_LIST 0x00080
#define MODE_CHECK 0x0100 #define MODE_CHECK 0x00100
#define MODE_LISTDEFS 0x0200 #define MODE_LISTDEFS 0x00200
#define MODE_BACKGROUND 0x0400 #define MODE_BACKGROUND 0x00400
#define MODE_SHELL 0x0800 #define MODE_SHELL 0x00800
#define MODE_LOGIN_SHELL 0x1000 #define MODE_LOGIN_SHELL 0x01000
#define MODE_IMPLIED_SHELL 0x2000 #define MODE_IMPLIED_SHELL 0x02000
#define MODE_RESET_HOME 0x4000 #define MODE_RESET_HOME 0x04000
#define MODE_PRESERVE_GROUPS 0x8000 #define MODE_PRESERVE_GROUPS 0x08000
#define MODE_PRESERVE_ENV 0x10000
/* /*
* Used with set_perms() * Used with set_perms()

View File

@@ -1,5 +1,6 @@
=cut =cut
Copyright (c) 1994-1996,1998-2004 Todd C. Miller <Todd.Miller@courtesan.com> Copyright (c) 1994-1996, 1998-2005, 2007
Todd C. Miller <Todd.Miller@courtesan.com>
Permission to use, copy, modify, and distribute this software for any Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above purpose with or without fee is hereby granted, provided that the above
@@ -31,9 +32,9 @@ B<sudo> B<-K> | B<-k> | B<-h> | B<-L> | B<-V> | B<-v>
B<sudo> B<-l> S<[B<-U> I<username>]> S<[B<-u> I<username>|I<#uid>]> [I<command>] B<sudo> B<-l> S<[B<-U> I<username>]> S<[B<-u> I<username>|I<#uid>]> [I<command>]
B<sudo> [B<-bHPS>] S<[B<-a> I<auth_type>]> S<[B<-C> I<fd>]> B<sudo> [B<-bEHPS>] S<[B<-a> I<auth_type>]> S<[B<-C> I<fd>]>
S<[B<-c> I<class>|I<->]> S<[B<-p> I<prompt>]> S<[B<-u> I<username>|I<#uid>]> S<[B<-c> I<class>|I<->]> S<[B<-p> I<prompt>]> S<[B<-u> I<username>|I<#uid>]>
S<{B<-e> file [...] | B<-i> | B<-s> | I<command>}> S<[B<VAR>=I<value>]> S<{B<-e> file [...] | B<-i> | B<-s> | I<command>}>
B<sudoedit> S<[B<-a> I<auth_type>]> B<sudoedit> S<[B<-a> I<auth_type>]>
S<[B<-p> I<prompt>]> [B<-S>] S<[B<-u> I<username>|I<#uid>]> S<[B<-p> I<prompt>]> [B<-S>] S<[B<-u> I<username>|I<#uid>]>
@@ -131,6 +132,13 @@ as root, or the B<sudo> command must be run from a shell that is already
root. This option is only available on systems with BSD login classes root. This option is only available on systems with BSD login classes
where B<sudo> has been configured with the --with-logincap option. where B<sudo> has been configured with the --with-logincap option.
=item -E
The B<-E> (I<preserve environment>) option will override the
I<env_reset> option in L<sudoers(@mansectform@)>). It is only
available when either the matching command has the C<SETENV> tag
or the I<setenv> option is set in L<sudoers(@mansectform@)>.
=item -e =item -e
The B<-e> (I<edit>) option indicates that, instead of running The B<-e> (I<edit>) option indicates that, instead of running
@@ -252,7 +260,7 @@ expanded to the local hostname without the domain name
expanded to the local hostname including the domain name expanded to the local hostname including the domain name
(on if the machine's hostname is fully qualified or the I<fqdn> (on if the machine's hostname is fully qualified or the I<fqdn>
sudoers option is set) I<sudoers> option is set)
=item C<%%> =item C<%%>
@@ -308,6 +316,13 @@ line arguments. It is most useful in conjunction with the B<-s> flag.
=back =back
Environment variables to be set for the command may also be passed
on the command line in the form of B<VAR>=I<value>, e.g.
B<LD_LIBRARY_PATH>=I</usr/local/pkg/lib>. This is only permitted
when the I<setenv> option is set in I<sudoers> or the command to
be run has the C<SETENV> tag set. See L<sudoers(@mansectform@)>
for more information.
=head1 RETURN VALUES =head1 RETURN VALUES
Upon successful execution of a program, the return value from B<sudo> Upon successful execution of a program, the return value from B<sudo>

View File

@@ -475,7 +475,7 @@ This flag is I<off> by default.
=item ignore_local_sudoers =item ignore_local_sudoers
If set via LDAP, parsing of @sysconfdir@/sudoers will be skipped. If set via LDAP, parsing of @sysconfdir@/sudoers will be skipped.
This is intended for an Enterprises that wish to prevent the usage of local This is intended for Enterprises that wish to prevent the usage of local
sudoers files so that only LDAP is used. This thwarts the efforts of sudoers files so that only LDAP is used. This thwarts the efforts of
rogue operators who would attempt to add roles to @sysconfdir@/sudoers. rogue operators who would attempt to add roles to @sysconfdir@/sudoers.
When this option is present, @sysconfdir@/sudoers does not even need to exist. When this option is present, @sysconfdir@/sudoers does not even need to exist.
@@ -540,6 +540,14 @@ error (ie: file descriptors 0-2). The I<closefrom> option can be used
to specify a different file descriptor at which to start closing. to specify a different file descriptor at which to start closing.
The default is 3. The default is 3.
=item setenv
Allow the user to set additional environment variables from the
command line. Note that variables set this way are not subject to
the restrictions imposed by I<env_check>, I<env_delete>, or
I<env_reset>. As such, only trusted users should be allowed to set
variables in this manner.
=back =back
B<Strings>: B<Strings>:
@@ -838,7 +846,7 @@ B<notice>, and B<warning>.
Runas_Spec ::= '(' Runas_List ')' Runas_Spec ::= '(' Runas_List ')'
Tag_Spec ::= ('NOPASSWD:' | 'PASSWD:' | 'NOEXEC:' | 'EXEC:' | Tag_Spec ::= ('NOPASSWD:' | 'PASSWD:' | 'NOEXEC:' | 'EXEC:' |
'MONITOR' | 'NOMONITOR') 'SETENV:' | 'NOSETENV:' | 'MONITOR:' | 'NOMONITOR:')
A B<user specification> determines which commands a user may run A B<user specification> determines which commands a user may run
(and as what user) on specified hosts. By default, commands are (and as what user) on specified hosts. By default, commands are
@@ -872,12 +880,12 @@ but F</bin/kill> and F</usr/bin/lprm> as B<root>.
=head2 Tag_Spec =head2 Tag_Spec
A command may have zero or more tags associated with it. There are A command may have zero or more tags associated with it. There are
four possible tag values, C<NOPASSWD>, C<PASSWD>, C<NOEXEC>, C<EXEC>, eight possible tag values, C<NOPASSWD>, C<PASSWD>, C<NOEXEC>, C<EXEC>,
C<MONITOR> and C<NOMONITOR>. C<SETENV>, C<NOSETENV>, C<MONITOR> and C<NOMONITOR>.
Once a tag is set on a C<Cmnd>, subsequent C<Cmnd>s in the Once a tag is set on a C<Cmnd>, subsequent C<Cmnd>s in the
C<Cmnd_Spec_List>, inherit the tag unless it is overridden by the C<Cmnd_Spec_List>, inherit the tag unless it is overridden by the
opposite tag (ie: C<PASSWD> overrides C<NOPASSWD> and C<NOMONITOR> opposite tag (i.e.: C<PASSWD> overrides C<NOPASSWD> and C<NOEXEC>
overrides C<MONITOR>). overrides C<EXEC>).
=head3 NOPASSWD and PASSWD =head3 NOPASSWD and PASSWD
@@ -921,6 +929,14 @@ and F</usr/bin/vi> but shell escapes will be disabled.
See the L<PREVENTING SHELL ESCAPES> section below for more details See the L<PREVENTING SHELL ESCAPES> section below for more details
on how C<NOEXEC> works and whether or not it will work on your system. on how C<NOEXEC> works and whether or not it will work on your system.
=head3 SETENV and NOSETENV
These tags override the value of the I<setenv> option on a per-command
basis. Note that environment variables set on the command line way
are not subject to the restrictions imposed by I<env_check>,
I<env_delete>, or I<env_reset>. As such, only trusted users should
be allowed to set variables in this manner.
=head3 MONITOR and NOMONITOR =head3 MONITOR and NOMONITOR
If B<sudo> has been configured with the C<--with-systrace> option, If B<sudo> has been configured with the C<--with-systrace> option,

1364
toke.c

File diff suppressed because it is too large Load Diff

13
toke.l
View File

@@ -1,6 +1,7 @@
%{ %{
/* /*
* Copyright (c) 1996, 1998-2005 Todd C. Miller <Todd.Miller@courtesan.com> * Copyright (c) 1996, 1998-2005, 2007
* Todd C. Miller <Todd.Miller@courtesan.com>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -272,6 +273,16 @@ EXEC[[:blank:]]*: {
return(EXEC); return(EXEC);
} }
SETENV[[:blank:]]*: {
LEXTRACE("SETENV ");
return(SETENV);
}
NOSETENV[[:blank:]]*: {
LEXTRACE("NOSETENV ");
return(NOSETENV);
}
NOMONITOR[[:blank:]]*: { NOMONITOR[[:blank:]]*: {
LEXTRACE("NOMONITOR "); LEXTRACE("NOMONITOR ");
return(NOMONITOR); return(NOMONITOR);