From f9f4aca556270b01b0f5ae742556d262240825fe Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Wed, 21 Nov 2007 20:12:00 +0000 Subject: [PATCH] Add support for runas groups. This allows the user to run a command with a different effective group. If the -g option is specified without -u the command will be run as the current user (only the group will change). the -g and -u options may be used together. TODO: implement runas group for ldap improve runas group documentation add testsudoers support --- WHATSNEW | 4 + check.c | 8 +- def_data.in | 1 - defaults.c | 10 +- gram.c | 572 +++++++++++++++++++++++++---------------------- gram.h | 1 + gram.y | 126 +++++++---- ldap.c | 5 + logging.c | 27 ++- match.c | 113 +++++++--- mon_systrace.c | 1 - parse.c | 21 +- parse.h | 11 +- pwutil.c | 30 +++ set_perms.c | 25 ++- sudo.c | 86 +++++-- sudo.cat | 490 ++++++++++++++++++++++------------------ sudo.h | 5 +- sudo.man.in | 95 ++++---- sudo.pod | 26 ++- sudo_usage.h.in | 6 +- sudoers.cat | 580 ++++++++++++++++++++++++------------------------ sudoers.man.in | 62 ++++-- sudoers.pod | 52 +++-- testsudoers.c | 27 +-- visudo.c | 5 +- visudo.cat | 70 +++--- visudo.man.in | 18 +- 28 files changed, 1431 insertions(+), 1046 deletions(-) diff --git a/WHATSNEW b/WHATSNEW index 7b2464cb6..45c911318 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -15,6 +15,10 @@ What's new in Sudo 1.7? o a new -U flag can be used in conjunction with "sudo -l" to allow root (or a user with "sudo ALL") list another user's privileges. + * A new -g flag has been added to allow the user to specify a + primary group to run the command as. The sudoers syntax has been + extended to include a group section in the Runas specification. + * A uid may now be used anywhere a username is valid. * The "secure_path" run-time Defaults option has been restored. diff --git a/check.c b/check.c index a0e410957..d4f086093 100644 --- a/check.c +++ b/check.c @@ -208,7 +208,7 @@ expand_prompt(old_prompt, user, host) break; case 'U': p++; - len += strlen(*user_runas) - 2; + len += strlen(runas_pw->pw_name) - 2; subst = 1; break; case '%': @@ -251,7 +251,7 @@ expand_prompt(old_prompt, user, host) continue; case 'U': p++; - n = strlcpy(np, *user_runas, np - endp); + n = strlcpy(np, runas_pw->pw_name, np - endp); if (n >= np - endp) goto oflow; np += n; @@ -335,14 +335,14 @@ build_timestamp(timestampdir, timestampfile) p = user_tty; if (def_targetpw) len = easprintf(timestampfile, "%s/%s/%s:%s", dirparent, user_name, - p, *user_runas); + p, runas_pw->pw_name); else len = easprintf(timestampfile, "%s/%s/%s", dirparent, user_name, p); if (len >= PATH_MAX) log_error(0, "timestamp path too long: %s", *timestampfile); } else if (def_targetpw) { len = easprintf(timestampfile, "%s/%s/%s", dirparent, user_name, - *user_runas); + runas_pw->pw_name); if (len >= PATH_MAX) log_error(0, "timestamp path too long: %s", *timestampfile); } else diff --git a/def_data.in b/def_data.in index 9a79d33bb..c03a0f034 100644 --- a/def_data.in +++ b/def_data.in @@ -155,7 +155,6 @@ passprompt runas_default T_STR "Default user to run commands as: %s" - *set_runaspw secure_path T_STR|T_BOOL "Value to override user's $PATH with: %s" diff --git a/defaults.c b/defaults.c index fc630cb82..a0d702ac1 100644 --- a/defaults.c +++ b/defaults.c @@ -479,14 +479,6 @@ init_defaults() /* Finally do the lists (currently just environment tables). */ init_envtables(); - /* - * The following depend on the above values. - * We use a pointer to the string so that if its - * value changes we get the change. - */ - if (user_runas == NULL) - user_runas = &def_runas_default; - firsttime = 0; } @@ -514,7 +506,7 @@ update_defaults(skip_cmnd) return(FALSE); break; case DEFAULTS_RUNAS: - if (runaslist_matches(&def->binding) && + if (runaslist_matches(&def->binding, NULL) && !set_default(def->var, def->val, def->op)) return(FALSE); break; diff --git a/gram.c b/gram.c index 1a0bb868e..a35796011 100644 --- a/gram.c +++ b/gram.c @@ -16,7 +16,7 @@ static char yyrcsid[] #define yyerrok (yyerrflag=0) #define YYRECOVERING() (yyerrflag!=0) #define YYPREFIX "yy" -#line 2 "./gram.y" +#line 2 "gram.y" /* * Copyright (c) 1996, 1998-2005, 2007 * Todd C. Miller @@ -116,13 +116,14 @@ yyerror(s) } parse_error = TRUE; } -#line 103 "./gram.y" +#line 103 "gram.y" #ifndef YYSTYPE_DEFINED #define YYSTYPE_DEFINED typedef union { struct cmndspec *cmndspec; struct defaults *defaults; struct member *member; + struct runascontainer *runas; struct privilege *privilege; struct sudo_command command; struct cmndtag tag; @@ -130,7 +131,7 @@ typedef union { int tok; } YYSTYPE; #endif /* YYSTYPE_DEFINED */ -#line 134 "y.tab.c" +#line 135 "y.tab.c" #define COMMAND 257 #define ALIAS 258 #define DEFVAR 259 @@ -163,15 +164,15 @@ const short yylhs[] = short yylhs[] = #endif { -1, - 0, 0, 21, 21, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 4, 4, 3, 3, - 3, 3, 3, 19, 19, 18, 10, 10, 8, 8, - 8, 8, 8, 2, 2, 1, 6, 6, 14, 14, - 13, 13, 11, 11, 15, 15, 15, 15, 15, 20, - 20, 20, 20, 20, 20, 20, 5, 5, 5, 24, - 24, 27, 9, 9, 25, 25, 28, 7, 7, 26, - 26, 29, 23, 23, 30, 17, 17, 12, 12, 16, - 16, 16, 16, 16, + 0, 0, 22, 22, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 4, 4, 3, 3, + 3, 3, 3, 20, 20, 19, 10, 10, 8, 8, + 8, 8, 8, 2, 2, 1, 6, 6, 17, 17, + 18, 18, 18, 21, 21, 21, 21, 21, 21, 21, + 5, 5, 5, 25, 25, 28, 9, 9, 26, 26, + 29, 7, 7, 27, 27, 30, 24, 24, 31, 13, + 13, 11, 11, 12, 12, 12, 12, 12, 16, 16, + 14, 14, 15, 15, 15, }; #if defined(__cplusplus) || defined(__STDC__) const short yylen[] = @@ -183,11 +184,11 @@ short yylen[] = 2, 2, 3, 3, 3, 3, 1, 3, 1, 2, 3, 3, 3, 1, 3, 3, 1, 2, 1, 1, 1, 1, 1, 1, 3, 3, 1, 2, 0, 3, - 1, 3, 1, 2, 1, 1, 1, 1, 1, 0, - 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, - 3, 3, 1, 3, 1, 3, 3, 1, 3, 1, - 3, 3, 1, 3, 3, 1, 3, 1, 2, 1, - 1, 1, 1, 1, + 1, 3, 2, 0, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 3, 3, 1, 3, 1, 3, + 3, 1, 3, 1, 3, 3, 1, 3, 3, 1, + 3, 1, 2, 1, 1, 1, 1, 1, 1, 3, + 1, 2, 1, 1, 1, }; #if defined(__cplusplus) || defined(__STDC__) const short yydefred[] = @@ -195,19 +196,20 @@ const short yydefred[] = short yydefred[] = #endif { 0, - 0, 80, 82, 83, 84, 0, 0, 0, 0, 0, - 81, 5, 0, 0, 0, 0, 0, 0, 76, 78, + 0, 74, 76, 77, 78, 0, 0, 0, 0, 0, + 75, 5, 0, 0, 0, 0, 0, 0, 70, 72, 0, 0, 3, 6, 0, 0, 17, 0, 29, 32, - 31, 33, 30, 0, 27, 0, 63, 0, 45, 47, - 48, 49, 46, 0, 41, 0, 43, 59, 58, 57, - 0, 37, 68, 0, 0, 0, 60, 0, 0, 65, - 0, 0, 73, 0, 0, 70, 79, 0, 0, 24, - 0, 4, 0, 0, 0, 20, 0, 28, 0, 0, - 0, 44, 0, 0, 38, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 77, 0, 0, 21, 22, - 23, 18, 64, 42, 69, 0, 61, 0, 66, 0, - 74, 0, 71, 0, 34, 0, 50, 25, 0, 0, - 0, 40, 35, 51, 52, 53, 54, 55, 56, 36, + 31, 33, 30, 0, 27, 0, 57, 0, 0, 53, + 52, 51, 0, 37, 62, 0, 0, 0, 54, 0, + 0, 59, 0, 0, 67, 0, 0, 64, 73, 0, + 0, 24, 0, 4, 0, 0, 0, 20, 0, 28, + 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 71, 0, 0, 21, 22, + 23, 18, 58, 63, 0, 55, 0, 60, 0, 68, + 0, 65, 0, 34, 0, 44, 25, 0, 0, 0, + 0, 0, 83, 85, 84, 0, 79, 81, 0, 0, + 40, 35, 45, 46, 47, 48, 49, 50, 36, 82, + 0, 0, 80, }; #if defined(__cplusplus) || defined(__STDC__) const short yydgoto[] = @@ -215,9 +217,10 @@ const short yydgoto[] = short yydgoto[] = #endif { 18, - 115, 116, 27, 28, 52, 53, 54, 35, 69, 37, - 45, 19, 46, 117, 47, 20, 21, 70, 71, 121, - 22, 23, 62, 56, 59, 65, 57, 60, 66, 63, + 104, 105, 27, 28, 44, 45, 46, 35, 61, 37, + 19, 20, 21, 117, 118, 119, 106, 110, 62, 63, + 112, 22, 23, 54, 48, 51, 57, 49, 52, 58, + 55, }; #if defined(__cplusplus) || defined(__STDC__) const short yysindex[] = @@ -225,94 +228,97 @@ const short yysindex[] = short yysindex[] = #endif { -33, - -269, 0, 0, 0, 0, -6, 217, 454, 461, -17, - 0, 0, -250, -247, -240, -238, -220, 0, 0, 0, - 141, -33, 0, 0, -26, -231, 0, -4, 0, 0, - 0, 0, 0, -212, 0, -23, 0, -21, 0, 0, - 0, 0, 0, -205, 0, -11, 0, 0, 0, 0, - -243, 0, 0, -8, -1, -14, 0, 3, 4, 0, - 5, 7, 0, 6, 10, 0, 0, 454, -31, 0, - 11, 0, -213, -209, -202, 0, -6, 0, 217, -4, - -4, 0, 461, -4, 0, -17, -4, 217, -250, -17, - -247, 454, -240, 461, -238, 0, 31, 217, 0, 0, - 0, 0, 0, 0, 0, 28, 0, 29, 0, 30, - 0, 32, 0, 461, 0, 33, 0, 0, -35, 31, - 250, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; + -269, 0, 0, 0, 0, -8, 454, 458, 458, -17, + 0, 0, -249, -247, -241, -231, -243, 0, 0, 0, + 141, -33, 0, 0, -37, -216, 0, -16, 0, 0, + 0, 0, 0, -221, 0, -23, 0, -21, -21, 0, + 0, 0, -244, 0, 0, -11, -14, -1, 0, -6, + 2, 0, 3, 4, 0, 5, 7, 0, 0, 458, + -15, 0, 9, 0, -219, -207, -202, 0, -8, 0, + 454, -16, -16, -16, 0, -17, -16, 454, -249, -17, + -247, 458, -241, 458, -231, 0, 23, 454, 0, 0, + 0, 0, 0, 0, 24, 0, 25, 0, 27, 0, + 27, 0, 217, 0, 28, 0, 0, -3, -9, 29, + 23, 250, 0, 0, 0, -222, 0, 0, 30, -3, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -3, 30, 0,}; #if defined(__cplusplus) || defined(__STDC__) const short yyrindex[] = #else short yyrindex[] = #endif - { 75, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + { 73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 79, 0, 0, 1, 0, 0, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 75, 0, 0, 1, 0, 0, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 181, 0, 0, 206, 0, - 0, 237, 0, 0, 274, 0, 0, 0, 0, 0, - 300, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 352, 0, 0, 378, 0, 0, 430, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 181, 0, 0, + 206, 0, 0, 237, 0, 0, 274, 0, 0, 0, + 0, 0, 300, 0, 0, 0, 0, 0, 0, 0, + 0, 326, 352, 378, 0, 0, 430, 0, 0, 0, 0, 0, 0, 0, 0, 0, 392, 0, 0, 0, - 0, 0, 0, 0, 0, 26, 0, 52, 0, 78, - 0, 104, 0, 0, 0, 130, 0, 0, 0, 392, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; + 0, 0, 0, 0, 26, 0, 52, 0, 78, 0, + 104, 0, 0, 0, 130, 0, 0, 0, 39, 0, + 392, 0, 0, 0, 0, 0, 0, 0, 40, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 41, 0,}; #if defined(__cplusplus) || defined(__STDC__) const short yygindex[] = #else short yygindex[] = #endif { 0, - -40, 0, 12, -7, 37, -84, -9, 48, -2, 13, - 8, 15, -90, 0, 46, 76, -5, -3, 0, 0, - 0, 72, 0, 0, 0, 0, 9, 14, 2, 16, + -28, 0, 17, 12, 44, -74, 8, 55, -2, 19, + 31, 76, -5, -39, -22, -25, 0, 0, 11, 0, + 0, 0, 74, 0, 0, 0, 0, 18, 20, 15, + 22, }; -#define YYTABLESIZE 736 +#define YYTABLESIZE 733 #if defined(__cplusplus) || defined(__STDC__) const short yytable[] = #else short yytable[] = #endif { 17, - 19, 105, 38, 112, 36, 122, 24, 55, 83, 26, - 58, 26, 79, 48, 49, 51, 74, 61, 75, 64, - 79, 26, 68, 119, 26, 62, 26, 76, 80, 97, - 81, 50, 83, 19, 73, 86, 130, 2, 84, 77, - 3, 4, 5, 89, 19, 29, 87, 30, 31, 99, - 32, 67, 39, 100, 11, 40, 41, 42, 62, 88, - 101, 91, 33, 90, 93, 92, 94, 95, 98, 43, - 114, 79, 86, 68, 1, 83, 120, 75, 2, 123, - 108, 78, 96, 62, 67, 106, 110, 85, 102, 82, - 104, 103, 67, 72, 118, 0, 113, 107, 0, 0, - 0, 0, 0, 72, 109, 0, 0, 0, 111, 67, - 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 19, 94, 38, 39, 36, 66, 24, 67, 47, 26, + 50, 26, 40, 41, 2, 43, 53, 3, 4, 5, + 71, 26, 60, 65, 26, 56, 56, 69, 71, 116, + 42, 11, 76, 19, 60, 113, 29, 129, 30, 31, + 114, 32, 68, 89, 19, 87, 78, 72, 120, 73, + 74, 61, 115, 33, 80, 90, 79, 77, 56, 81, + 91, 83, 103, 82, 85, 84, 88, 71, 76, 121, + 60, 111, 1, 131, 2, 95, 99, 69, 101, 41, + 43, 42, 122, 56, 61, 92, 75, 97, 70, 93, + 86, 133, 59, 130, 132, 64, 96, 109, 107, 102, + 98, 0, 0, 66, 100, 0, 0, 0, 0, 61, + 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, - 0, 0, 0, 0, 0, 75, 72, 0, 0, 0, + 0, 0, 0, 0, 0, 69, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, - 0, 72, 26, 0, 0, 0, 0, 0, 0, 0, + 0, 66, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, - 9, 0, 0, 0, 68, 0, 0, 26, 12, 0, + 9, 0, 0, 0, 60, 0, 0, 26, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 3, 4, 5, - 6, 7, 8, 9, 10, 25, 8, 25, 10, 48, - 49, 11, 12, 13, 14, 15, 16, 25, 0, 34, - 25, 0, 25, 0, 0, 0, 19, 50, 19, 0, + 6, 7, 8, 9, 10, 25, 8, 25, 10, 40, + 41, 11, 12, 13, 14, 15, 16, 25, 0, 17, + 25, 0, 0, 0, 113, 0, 19, 42, 19, 114, 0, 19, 19, 19, 19, 19, 19, 19, 19, 8, - 0, 0, 0, 11, 0, 19, 19, 19, 19, 19, - 19, 62, 51, 62, 0, 0, 62, 62, 62, 62, - 62, 62, 62, 62, 0, 0, 0, 0, 0, 7, - 62, 62, 62, 62, 62, 62, 11, 67, 0, 67, - 0, 0, 67, 67, 67, 67, 67, 67, 67, 67, - 0, 0, 0, 0, 0, 15, 67, 67, 67, 67, - 67, 67, 7, 75, 0, 75, 0, 0, 75, 75, - 75, 75, 75, 75, 75, 75, 0, 0, 0, 0, - 0, 13, 75, 75, 75, 75, 75, 75, 15, 72, - 0, 72, 0, 0, 72, 72, 72, 72, 72, 72, - 72, 72, 0, 0, 0, 0, 0, 14, 72, 72, - 72, 72, 72, 72, 13, 26, 0, 26, 0, 0, + 0, 115, 0, 11, 108, 19, 19, 19, 19, 19, + 19, 56, 43, 56, 0, 0, 56, 56, 56, 56, + 56, 56, 56, 56, 0, 0, 0, 0, 0, 7, + 56, 56, 56, 56, 56, 56, 11, 61, 0, 61, + 0, 0, 61, 61, 61, 61, 61, 61, 61, 61, + 0, 0, 0, 0, 0, 15, 61, 61, 61, 61, + 61, 61, 7, 69, 0, 69, 0, 0, 69, 69, + 69, 69, 69, 69, 69, 69, 0, 0, 0, 0, + 0, 13, 69, 69, 69, 69, 69, 69, 15, 66, + 0, 66, 0, 0, 66, 66, 66, 66, 66, 66, + 66, 66, 0, 0, 0, 0, 0, 14, 66, 66, + 66, 66, 66, 66, 13, 26, 0, 26, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 29, 0, 30, 31, 0, 32, 26, 26, 26, 26, 26, 26, 14, 12, 0, 12, 0, 33, 12, 12, 12, 12, @@ -321,12 +327,12 @@ short yytable[] = 0, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 10, 16, 10, 0, 0, 10, 10, 10, 10, - 10, 10, 10, 10, 29, 0, 30, 31, 0, 32, - 10, 10, 10, 10, 10, 10, 17, 0, 0, 0, - 0, 33, 8, 44, 8, 0, 0, 8, 8, 8, - 8, 8, 8, 8, 8, 0, 48, 49, 0, 0, - 0, 8, 8, 8, 8, 8, 8, 0, 124, 125, - 126, 127, 128, 129, 50, 0, 0, 0, 0, 11, + 10, 10, 10, 10, 2, 0, 0, 3, 4, 5, + 10, 10, 10, 10, 10, 10, 34, 0, 0, 0, + 17, 11, 8, 0, 8, 0, 0, 8, 8, 8, + 8, 8, 8, 8, 8, 0, 40, 41, 0, 0, + 0, 8, 8, 8, 8, 8, 8, 0, 123, 124, + 125, 126, 127, 128, 42, 0, 0, 0, 0, 11, 0, 11, 0, 0, 11, 11, 11, 11, 11, 11, 11, 11, 0, 0, 0, 0, 0, 0, 11, 11, 11, 11, 11, 11, 0, 7, 0, 7, 0, 0, @@ -345,9 +351,9 @@ short yytable[] = 0, 0, 0, 0, 0, 16, 0, 16, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, - 0, 2, 0, 0, 3, 4, 5, 0, 39, 0, - 0, 40, 41, 42, 0, 0, 0, 0, 11, 0, - 0, 0, 0, 0, 0, 43, + 0, 29, 0, 30, 31, 2, 32, 0, 3, 4, + 5, 0, 0, 0, 0, 0, 0, 0, 33, 0, + 0, 0, 11, }; #if defined(__cplusplus) || defined(__STDC__) const short yycheck[] = @@ -355,17 +361,17 @@ const short yycheck[] = short yycheck[] = #endif { 33, - 0, 86, 8, 94, 7, 41, 276, 258, 44, 33, - 258, 33, 44, 257, 258, 33, 43, 258, 45, 258, - 44, 33, 44, 114, 33, 0, 33, 259, 36, 61, - 38, 275, 44, 33, 61, 44, 121, 258, 46, 44, - 261, 262, 263, 58, 44, 258, 54, 260, 261, 263, - 263, 0, 258, 263, 275, 261, 262, 263, 33, 61, - 263, 58, 275, 61, 58, 61, 61, 58, 58, 275, - 40, 44, 44, 44, 0, 44, 44, 0, 0, 120, - 90, 34, 68, 58, 33, 88, 92, 51, 77, 44, - 83, 79, 17, 22, 98, -1, 95, 89, -1, -1, - -1, -1, -1, 0, 91, -1, -1, -1, 93, 58, + 0, 76, 8, 9, 7, 43, 276, 45, 258, 33, + 258, 33, 257, 258, 258, 33, 258, 261, 262, 263, + 44, 33, 44, 61, 33, 0, 258, 44, 44, 33, + 275, 275, 44, 33, 44, 258, 258, 112, 260, 261, + 263, 263, 259, 263, 44, 61, 61, 36, 58, 38, + 39, 0, 275, 275, 61, 263, 58, 46, 33, 58, + 263, 58, 40, 61, 58, 61, 58, 44, 44, 41, + 44, 44, 0, 44, 0, 78, 82, 0, 84, 41, + 41, 41, 111, 58, 33, 69, 43, 80, 34, 71, + 60, 131, 17, 116, 120, 22, 79, 103, 88, 85, + 81, -1, -1, 0, 83, -1, -1, -1, -1, 58, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, 58, 33, -1, -1, -1, @@ -380,9 +386,9 @@ short yycheck[] = -1, -1, 256, -1, 258, -1, -1, 261, 262, 263, 264, 265, 266, 267, 268, 259, 0, 259, 33, 257, 258, 275, 276, 277, 278, 279, 280, 259, -1, 33, - 259, -1, 259, -1, -1, -1, 256, 275, 258, -1, + 259, -1, -1, -1, 258, -1, 256, 275, 258, 263, -1, 261, 262, 263, 264, 265, 266, 267, 268, 33, - -1, -1, -1, 0, -1, 275, 276, 277, 278, 279, + -1, 275, -1, 0, 58, 275, 276, 277, 278, 279, 280, 256, 33, 258, -1, -1, 261, 262, 263, 264, 265, 266, 267, 268, -1, -1, -1, -1, -1, 0, 275, 276, 277, 278, 279, 280, 33, 256, -1, 258, @@ -402,9 +408,9 @@ short yycheck[] = -1, 261, 262, 263, 264, 265, 266, 267, 268, -1, -1, -1, -1, -1, -1, 275, 276, 277, 278, 279, 280, 256, 33, 258, -1, -1, 261, 262, 263, 264, - 265, 266, 267, 268, 258, -1, 260, 261, -1, 263, + 265, 266, 267, 268, 258, -1, -1, 261, 262, 263, 275, 276, 277, 278, 279, 280, 33, -1, -1, -1, - -1, 275, 256, 33, 258, -1, -1, 261, 262, 263, + 33, 275, 256, -1, 258, -1, -1, 261, 262, 263, 264, 265, 266, 267, 268, -1, 257, 258, -1, -1, -1, 275, 276, 277, 278, 279, 280, -1, 269, 270, 271, 272, 273, 274, 275, -1, -1, -1, -1, 256, @@ -426,9 +432,9 @@ short yycheck[] = -1, -1, -1, -1, -1, 256, -1, 258, -1, -1, 261, 262, 263, 264, 265, 266, 267, 268, -1, -1, -1, -1, -1, -1, 275, 276, 277, 278, 279, 280, - -1, 258, -1, -1, 261, 262, 263, -1, 258, -1, - -1, 261, 262, 263, -1, -1, -1, -1, 275, -1, - -1, -1, -1, -1, -1, 275, + -1, 258, -1, 260, 261, 258, 263, -1, 261, 262, + 263, -1, -1, -1, -1, -1, -1, -1, 275, -1, + -1, -1, 275, }; #define YYFINAL 18 #ifndef YYDEBUG @@ -473,7 +479,7 @@ char *yyrule[] = "entry : RUNASALIAS runasaliases", "entry : DEFAULTS defaults_list", "entry : DEFAULTS_USER userlist defaults_list", -"entry : DEFAULTS_RUNAS runaslist defaults_list", +"entry : DEFAULTS_RUNAS userlist defaults_list", "entry : DEFAULTS_HOST hostlist defaults_list", "entry : DEFAULTS_CMND cmndlist defaults_list", "defaults_list : defaults_entry", @@ -500,15 +506,9 @@ char *yyrule[] = "opcmnd : '!' cmnd", "runasspec :", "runasspec : '(' runaslist ')'", -"runaslist : oprunasuser", -"runaslist : runaslist ',' oprunasuser", -"oprunasuser : runasuser", -"oprunasuser : '!' runasuser", -"runasuser : ALIAS", -"runasuser : ALL", -"runasuser : NETGROUP", -"runasuser : USERGROUP", -"runasuser : WORD", +"runaslist : userlist", +"runaslist : userlist ':' grouplist", +"runaslist : ':' grouplist", "cmndtag :", "cmndtag : cmndtag NOPASSWD", "cmndtag : cmndtag PASSWD", @@ -531,7 +531,7 @@ char *yyrule[] = "cmndlist : cmndlist ',' opcmnd", "runasaliases : runasalias", "runasaliases : runasaliases ':' runasalias", -"runasalias : ALIAS '=' runaslist", +"runasalias : ALIAS '=' userlist", "useraliases : useralias", "useraliases : useraliases ':' useralias", "useralias : ALIAS '=' userlist", @@ -544,6 +544,13 @@ char *yyrule[] = "user : NETGROUP", "user : USERGROUP", "user : WORD", +"grouplist : opgroup", +"grouplist : grouplist ',' opgroup", +"opgroup : group", +"opgroup : '!' group", +"group : ALIAS", +"group : ALL", +"group : WORD", }; #endif #ifdef YYSTACKSIZE @@ -571,7 +578,7 @@ short *yyss; short *yysslim; YYSTYPE *yyvs; int yystacksize; -#line 503 "./gram.y" +#line 527 "gram.y" static struct defaults * new_default(var, val, op) char *var; @@ -660,7 +667,7 @@ init_parser(path, quiet) int quiet; { struct defaults *d; - struct member *m, *freed; + struct member *m, *binding; struct userspec *us; struct privilege *priv; struct cmndspec *cs; @@ -671,15 +678,23 @@ init_parser(path, quiet) efree(m); } while ((priv = tq_pop(&us->privileges)) != NULL) { + struct member *runasuser = NULL, *runasgroup = NULL; + while ((m = tq_pop(&priv->hostlist)) != NULL) { efree(m->name); efree(m); } - freed = NULL; while ((cs = tq_pop(&priv->cmndlist)) != NULL) { - if (tq_last(&cs->runaslist) != freed) { - freed = tq_last(&cs->runaslist); - while ((m = tq_pop(&cs->runaslist)) != NULL) { + if (tq_last(&cs->runasuserlist) != runasuser) { + runasuser = tq_last(&cs->runasuserlist); + while ((m = tq_pop(&cs->runasuserlist)) != NULL) { + efree(m->name); + efree(m); + } + } + if (tq_last(&cs->runasgrouplist) != runasgroup) { + runasgroup = tq_last(&cs->runasgrouplist); + while ((m = tq_pop(&cs->runasgrouplist)) != NULL) { efree(m->name); efree(m); } @@ -693,10 +708,10 @@ init_parser(path, quiet) } tq_init(&userspecs); - freed = NULL; + binding = NULL; while ((d = tq_pop(&defaults)) != NULL) { - if (tq_last(&d->binding) != freed) { - freed = tq_last(&d->binding); + if (tq_last(&d->binding) != binding) { + binding = tq_last(&d->binding); while ((m = tq_pop(&d->binding)) != NULL) { efree(m->name); efree(m); @@ -718,7 +733,7 @@ init_parser(path, quiet) sudolineno = 1; verbose = !quiet; } -#line 670 "y.tab.c" +#line 685 "y.tab.c" /* allocate initial stack or double stack size, up to YYMAXDEPTH */ #if defined(__cplusplus) || defined(__STDC__) static int yygrowstack(void) @@ -921,127 +936,127 @@ yyreduce: switch (yyn) { case 1: -#line 166 "./gram.y" +#line 168 "gram.y" { ; } break; case 5: -#line 174 "./gram.y" +#line 176 "gram.y" { ; } break; case 6: -#line 177 "./gram.y" +#line 179 "gram.y" { yyerrok; } break; case 7: -#line 180 "./gram.y" +#line 182 "gram.y" { add_userspec(yyvsp[-1].member, yyvsp[0].privilege); } break; case 8: -#line 183 "./gram.y" +#line 185 "gram.y" { ; } break; case 9: -#line 186 "./gram.y" +#line 188 "gram.y" { ; } break; case 10: -#line 189 "./gram.y" +#line 191 "gram.y" { ; } break; case 11: -#line 192 "./gram.y" +#line 194 "gram.y" { ; } break; case 12: -#line 195 "./gram.y" +#line 197 "gram.y" { add_defaults(DEFAULTS, NULL, yyvsp[0].defaults); } break; case 13: -#line 198 "./gram.y" +#line 200 "gram.y" { add_defaults(DEFAULTS_USER, yyvsp[-1].member, yyvsp[0].defaults); } break; case 14: -#line 201 "./gram.y" +#line 203 "gram.y" { add_defaults(DEFAULTS_RUNAS, yyvsp[-1].member, yyvsp[0].defaults); } break; case 15: -#line 204 "./gram.y" +#line 206 "gram.y" { add_defaults(DEFAULTS_HOST, yyvsp[-1].member, yyvsp[0].defaults); } break; case 16: -#line 207 "./gram.y" +#line 209 "gram.y" { add_defaults(DEFAULTS_CMND, yyvsp[-1].member, yyvsp[0].defaults); } break; case 18: -#line 213 "./gram.y" +#line 215 "gram.y" { list_append(yyvsp[-2].defaults, yyvsp[0].defaults); yyval.defaults = yyvsp[-2].defaults; } break; case 19: -#line 219 "./gram.y" +#line 221 "gram.y" { yyval.defaults = new_default(yyvsp[0].string, NULL, TRUE); } break; case 20: -#line 222 "./gram.y" +#line 224 "gram.y" { yyval.defaults = new_default(yyvsp[0].string, NULL, FALSE); } break; case 21: -#line 225 "./gram.y" +#line 227 "gram.y" { yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, TRUE); } break; case 22: -#line 228 "./gram.y" +#line 230 "gram.y" { yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '+'); } break; case 23: -#line 231 "./gram.y" +#line 233 "gram.y" { yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '-'); } break; case 25: -#line 237 "./gram.y" +#line 239 "gram.y" { list_append(yyvsp[-2].privilege, yyvsp[0].privilege); yyval.privilege = yyvsp[-2].privilege; } break; case 26: -#line 243 "./gram.y" +#line 245 "gram.y" { struct privilege *p = emalloc(sizeof(*p)); list2tq(&p->hostlist, yyvsp[-2].member); @@ -1052,51 +1067,51 @@ case 26: } break; case 27: -#line 253 "./gram.y" +#line 255 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = FALSE; } break; case 28: -#line 257 "./gram.y" +#line 259 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = TRUE; } break; case 29: -#line 263 "./gram.y" +#line 265 "gram.y" { yyval.member = new_member(yyvsp[0].string, ALIAS); } break; case 30: -#line 266 "./gram.y" +#line 268 "gram.y" { yyval.member = new_member(NULL, ALL); } break; case 31: -#line 269 "./gram.y" +#line 271 "gram.y" { yyval.member = new_member(yyvsp[0].string, NETGROUP); } break; case 32: -#line 272 "./gram.y" +#line 274 "gram.y" { yyval.member = new_member(yyvsp[0].string, NTWKADDR); } break; case 33: -#line 275 "./gram.y" +#line 277 "gram.y" { yyval.member = new_member(yyvsp[0].string, WORD); } break; case 35: -#line 281 "./gram.y" +#line 283 "gram.y" { list_append(yyvsp[-2].cmndspec, yyvsp[0].cmndspec); /* propagate tags and runas list */ @@ -1107,17 +1122,28 @@ case 35: if (yyvsp[0].cmndspec->tags.setenv == UNSPEC && yyvsp[0].cmndspec->prev->tags.setenv != IMPLIED) yyvsp[0].cmndspec->tags.setenv = yyvsp[0].cmndspec->prev->tags.setenv; - if (tq_empty(&yyvsp[0].cmndspec->runaslist) && - !tq_empty(&yyvsp[0].cmndspec->prev->runaslist)) - yyvsp[0].cmndspec->runaslist = yyvsp[0].cmndspec->prev->runaslist; + if ((tq_empty(&yyvsp[0].cmndspec->runasuserlist) && + tq_empty(&yyvsp[0].cmndspec->runasgrouplist)) && + (!tq_empty(&yyvsp[0].cmndspec->prev->runasuserlist) || + !tq_empty(&yyvsp[0].cmndspec->prev->runasgrouplist))) { + yyvsp[0].cmndspec->runasuserlist = yyvsp[0].cmndspec->prev->runasuserlist; + yyvsp[0].cmndspec->runasgrouplist = yyvsp[0].cmndspec->prev->runasgrouplist; + } yyval.cmndspec = yyvsp[-2].cmndspec; } break; case 36: -#line 298 "./gram.y" +#line 304 "gram.y" { struct cmndspec *cs = emalloc(sizeof(*cs)); - list2tq(&cs->runaslist, yyvsp[-2].member); + if (yyvsp[-2].runas != NULL) { + list2tq(&cs->runasuserlist, yyvsp[-2].runas->runasusers); + list2tq(&cs->runasgrouplist, yyvsp[-2].runas->runasgroups); + efree(yyvsp[-2].runas); + } else { + tq_init(&cs->runasuserlist); + tq_init(&cs->runasgrouplist); + } cs->tags = yyvsp[-1].tag; cs->cmnd = yyvsp[0].member; cs->prev = cs; @@ -1130,138 +1156,111 @@ case 36: } break; case 37: -#line 313 "./gram.y" +#line 326 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = FALSE; } break; case 38: -#line 317 "./gram.y" +#line 330 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = TRUE; } break; case 39: -#line 323 "./gram.y" +#line 336 "gram.y" { - yyval.member = NULL; + yyval.runas = NULL; } break; case 40: -#line 326 "./gram.y" -{ - yyval.member = yyvsp[-1].member; - } -break; -case 42: -#line 332 "./gram.y" +#line 339 "gram.y" { - list_append(yyvsp[-2].member, yyvsp[0].member); - yyval.member = yyvsp[-2].member; - } -break; -case 43: -#line 338 "./gram.y" -{ - yyval.member = yyvsp[0].member; - yyval.member->negated = FALSE; + yyval.runas = yyvsp[-1].runas; } break; -case 44: -#line 342 "./gram.y" +case 41: +#line 344 "gram.y" { - yyval.member = yyvsp[0].member; - yyval.member->negated = TRUE; + yyval.runas = emalloc(sizeof(struct runascontainer)); + yyval.runas->runasusers = yyvsp[0].member; + yyval.runas->runasgroups = NULL; } break; -case 45: -#line 348 "./gram.y" -{ - yyval.member = new_member(yyvsp[0].string, ALIAS); - } -break; -case 46: -#line 351 "./gram.y" -{ - yyval.member = new_member(NULL, ALL); - } -break; -case 47: -#line 354 "./gram.y" +case 42: +#line 349 "gram.y" { - yyval.member = new_member(yyvsp[0].string, NETGROUP); + yyval.runas = emalloc(sizeof(struct runascontainer)); + yyval.runas->runasusers = yyvsp[-2].member; + yyval.runas->runasgroups = yyvsp[0].member; } break; -case 48: -#line 357 "./gram.y" -{ - yyval.member = new_member(yyvsp[0].string, USERGROUP); - } -break; -case 49: -#line 360 "./gram.y" +case 43: +#line 354 "gram.y" { - yyval.member = new_member(yyvsp[0].string, WORD); + yyval.runas = emalloc(sizeof(struct runascontainer)); + yyval.runas->runasusers = NULL; + yyval.runas->runasgroups = yyvsp[0].member; } break; -case 50: -#line 365 "./gram.y" +case 44: +#line 361 "gram.y" { yyval.tag.nopasswd = yyval.tag.noexec = yyval.tag.setenv = UNSPEC; } break; -case 51: -#line 368 "./gram.y" +case 45: +#line 364 "gram.y" { yyval.tag.nopasswd = TRUE; } break; -case 52: -#line 371 "./gram.y" +case 46: +#line 367 "gram.y" { yyval.tag.nopasswd = FALSE; } break; -case 53: -#line 374 "./gram.y" +case 47: +#line 370 "gram.y" { yyval.tag.noexec = TRUE; } break; -case 54: -#line 377 "./gram.y" +case 48: +#line 373 "gram.y" { yyval.tag.noexec = FALSE; } break; -case 55: -#line 380 "./gram.y" +case 49: +#line 376 "gram.y" { yyval.tag.setenv = TRUE; } break; -case 56: -#line 383 "./gram.y" +case 50: +#line 379 "gram.y" { yyval.tag.setenv = FALSE; } break; -case 57: -#line 388 "./gram.y" +case 51: +#line 384 "gram.y" { yyval.member = new_member(NULL, ALL); } break; -case 58: -#line 391 "./gram.y" +case 52: +#line 387 "gram.y" { yyval.member = new_member(yyvsp[0].string, ALIAS); } break; -case 59: -#line 394 "./gram.y" +case 53: +#line 390 "gram.y" { struct sudo_command *c = emalloc(sizeof(*c)); c->cmnd = yyvsp[0].command.cmnd; @@ -1269,8 +1268,8 @@ case 59: yyval.member = new_member((char *)c, COMMAND); } break; -case 62: -#line 406 "./gram.y" +case 56: +#line 402 "gram.y" { char *s; if ((s = alias_add(yyvsp[-2].string, HOSTALIAS, yyvsp[0].member)) != NULL) { @@ -1279,15 +1278,15 @@ case 62: } } break; -case 64: -#line 416 "./gram.y" +case 58: +#line 412 "gram.y" { list_append(yyvsp[-2].member, yyvsp[0].member); yyval.member = yyvsp[-2].member; } break; -case 67: -#line 426 "./gram.y" +case 61: +#line 422 "gram.y" { char *s; if ((s = alias_add(yyvsp[-2].string, CMNDALIAS, yyvsp[0].member)) != NULL) { @@ -1296,15 +1295,15 @@ case 67: } } break; -case 69: -#line 436 "./gram.y" +case 63: +#line 432 "gram.y" { list_append(yyvsp[-2].member, yyvsp[0].member); yyval.member = yyvsp[-2].member; } break; -case 72: -#line 446 "./gram.y" +case 66: +#line 442 "gram.y" { char *s; if ((s = alias_add(yyvsp[-2].string, RUNASALIAS, yyvsp[0].member)) != NULL) { @@ -1313,8 +1312,8 @@ case 72: } } break; -case 75: -#line 459 "./gram.y" +case 69: +#line 455 "gram.y" { char *s; if ((s = alias_add(yyvsp[-2].string, USERALIAS, yyvsp[0].member)) != NULL) { @@ -1323,58 +1322,97 @@ case 75: } } break; -case 77: -#line 469 "./gram.y" +case 71: +#line 465 "gram.y" { list_append(yyvsp[-2].member, yyvsp[0].member); yyval.member = yyvsp[-2].member; } break; -case 78: -#line 475 "./gram.y" +case 72: +#line 471 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = FALSE; } break; -case 79: -#line 479 "./gram.y" +case 73: +#line 475 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = TRUE; } break; -case 80: -#line 485 "./gram.y" +case 74: +#line 481 "gram.y" { yyval.member = new_member(yyvsp[0].string, ALIAS); } break; -case 81: -#line 488 "./gram.y" +case 75: +#line 484 "gram.y" { yyval.member = new_member(NULL, ALL); } break; -case 82: -#line 491 "./gram.y" +case 76: +#line 487 "gram.y" { yyval.member = new_member(yyvsp[0].string, NETGROUP); } break; -case 83: -#line 494 "./gram.y" +case 77: +#line 490 "gram.y" { yyval.member = new_member(yyvsp[0].string, USERGROUP); } break; +case 78: +#line 493 "gram.y" +{ + yyval.member = new_member(yyvsp[0].string, WORD); + } +break; +case 80: +#line 499 "gram.y" +{ + list_append(yyvsp[-2].member, yyvsp[0].member); + yyval.member = yyvsp[-2].member; + } +break; +case 81: +#line 505 "gram.y" +{ + yyval.member = yyvsp[0].member; + yyval.member->negated = FALSE; + } +break; +case 82: +#line 509 "gram.y" +{ + yyval.member = yyvsp[0].member; + yyval.member->negated = TRUE; + } +break; +case 83: +#line 515 "gram.y" +{ + yyval.member = new_member(yyvsp[0].string, ALIAS); + } +break; case 84: -#line 497 "./gram.y" +#line 518 "gram.y" +{ + yyval.member = new_member(NULL, ALL); + } +break; +case 85: +#line 521 "gram.y" { yyval.member = new_member(yyvsp[0].string, WORD); } break; -#line 1326 "y.tab.c" +#line 1364 "y.tab.c" } yyssp -= yym; yystate = *yyssp; diff --git a/gram.h b/gram.h index 6e709dfc3..d4aaf6d5c 100644 --- a/gram.h +++ b/gram.h @@ -29,6 +29,7 @@ typedef union { struct cmndspec *cmndspec; struct defaults *defaults; struct member *member; + struct runascontainer *runas; struct privilege *privilege; struct sudo_command command; struct cmndtag tag; diff --git a/gram.y b/gram.y index eb53edf46..706e1a661 100644 --- a/gram.y +++ b/gram.y @@ -104,6 +104,7 @@ yyerror(s) struct cmndspec *cmndspec; struct defaults *defaults; struct member *member; + struct runascontainer *runas; struct privilege *privilege; struct sudo_command command; struct cmndtag tag; @@ -150,13 +151,14 @@ yyerror(s) %type host %type hostlist %type ophost -%type oprunasuser %type opuser -%type runaslist -%type runasspec -%type runasuser %type user %type userlist +%type opgroup +%type group +%type grouplist +%type runasspec +%type runaslist %type privilege %type privileges %type cmndtag @@ -198,7 +200,7 @@ entry : COMMENT { | DEFAULTS_USER userlist defaults_list { add_defaults(DEFAULTS_USER, $2, $3); } - | DEFAULTS_RUNAS runaslist defaults_list { + | DEFAULTS_RUNAS userlist defaults_list { add_defaults(DEFAULTS_RUNAS, $2, $3); } | DEFAULTS_HOST hostlist defaults_list { @@ -288,16 +290,27 @@ cmndspeclist : cmndspec if ($3->tags.setenv == UNSPEC && $3->prev->tags.setenv != IMPLIED) $3->tags.setenv = $3->prev->tags.setenv; - if (tq_empty(&$3->runaslist) && - !tq_empty(&$3->prev->runaslist)) - $3->runaslist = $3->prev->runaslist; + if ((tq_empty(&$3->runasuserlist) && + tq_empty(&$3->runasgrouplist)) && + (!tq_empty(&$3->prev->runasuserlist) || + !tq_empty(&$3->prev->runasgrouplist))) { + $3->runasuserlist = $3->prev->runasuserlist; + $3->runasgrouplist = $3->prev->runasgrouplist; + } $$ = $1; } ; cmndspec : runasspec cmndtag opcmnd { struct cmndspec *cs = emalloc(sizeof(*cs)); - list2tq(&cs->runaslist, $1); + if ($1 != NULL) { + list2tq(&cs->runasuserlist, $1->runasusers); + list2tq(&cs->runasgrouplist, $1->runasgroups); + efree($1); + } else { + tq_init(&cs->runasuserlist); + tq_init(&cs->runasgrouplist); + } cs->tags = $2; cs->cmnd = $3; cs->prev = cs; @@ -328,37 +341,20 @@ runasspec : /* empty */ { } ; -runaslist : oprunasuser - | runaslist ',' oprunasuser { - list_append($1, $3); - $$ = $1; +runaslist : userlist { + $$ = emalloc(sizeof(struct runascontainer)); + $$->runasusers = $1; + $$->runasgroups = NULL; } - ; - -oprunasuser : runasuser { - $$ = $1; - $$->negated = FALSE; + | userlist ':' grouplist { + $$ = emalloc(sizeof(struct runascontainer)); + $$->runasusers = $1; + $$->runasgroups = $3; } - | '!' runasuser { - $$ = $2; - $$->negated = TRUE; - } - ; - -runasuser : ALIAS { - $$ = new_member($1, ALIAS); - } - | ALL { - $$ = new_member(NULL, ALL); - } - | NETGROUP { - $$ = new_member($1, NETGROUP); - } - | USERGROUP { - $$ = new_member($1, USERGROUP); - } - | WORD { - $$ = new_member($1, WORD); + | ':' grouplist { + $$ = emalloc(sizeof(struct runascontainer)); + $$->runasusers = NULL; + $$->runasgroups = $2; } ; @@ -443,7 +439,7 @@ runasaliases : runasalias | runasaliases ':' runasalias ; -runasalias : ALIAS '=' runaslist { +runasalias : ALIAS '=' userlist { char *s; if ((s = alias_add($1, RUNASALIAS, $3)) != NULL) { yyerror(s); @@ -499,6 +495,34 @@ user : ALIAS { } ; +grouplist : opgroup + | grouplist ',' opgroup { + list_append($1, $3); + $$ = $1; + } + ; + +opgroup : group { + $$ = $1; + $$->negated = FALSE; + } + | '!' group { + $$ = $2; + $$->negated = TRUE; + } + ; + +group : ALIAS { + $$ = new_member($1, ALIAS); + } + | ALL { + $$ = new_member(NULL, ALL); + } + | WORD { + $$ = new_member($1, WORD); + } + ; + %% static struct defaults * new_default(var, val, op) @@ -588,7 +612,7 @@ init_parser(path, quiet) int quiet; { struct defaults *d; - struct member *m, *freed; + struct member *m, *binding; struct userspec *us; struct privilege *priv; struct cmndspec *cs; @@ -599,15 +623,23 @@ init_parser(path, quiet) efree(m); } while ((priv = tq_pop(&us->privileges)) != NULL) { + struct member *runasuser = NULL, *runasgroup = NULL; + while ((m = tq_pop(&priv->hostlist)) != NULL) { efree(m->name); efree(m); } - freed = NULL; while ((cs = tq_pop(&priv->cmndlist)) != NULL) { - if (tq_last(&cs->runaslist) != freed) { - freed = tq_last(&cs->runaslist); - while ((m = tq_pop(&cs->runaslist)) != NULL) { + if (tq_last(&cs->runasuserlist) != runasuser) { + runasuser = tq_last(&cs->runasuserlist); + while ((m = tq_pop(&cs->runasuserlist)) != NULL) { + efree(m->name); + efree(m); + } + } + if (tq_last(&cs->runasgrouplist) != runasgroup) { + runasgroup = tq_last(&cs->runasgrouplist); + while ((m = tq_pop(&cs->runasgrouplist)) != NULL) { efree(m->name); efree(m); } @@ -621,10 +653,10 @@ init_parser(path, quiet) } tq_init(&userspecs); - freed = NULL; + binding = NULL; while ((d = tq_pop(&defaults)) != NULL) { - if (tq_last(&d->binding) != freed) { - freed = tq_last(&d->binding); + if (tq_last(&d->binding) != binding) { + binding = tq_last(&d->binding); while ((m = tq_pop(&d->binding)) != NULL) { efree(m->name); efree(m); diff --git a/ldap.c b/ldap.c index 9ebb998ab..d3fd7bd57 100644 --- a/ldap.c +++ b/ldap.c @@ -213,6 +213,11 @@ sudo_ldap_check_runas(ld, entry) if (!entry) return(ret); + /* If no runas user, just check the group. */ + /* XXX - implement runas group checking via sudoRunasGroup */ + if (!runas_pw) + return(TRUE); + /* get the values from the entry */ v = ldap_get_values(ld, entry, "sudoRunAs"); diff --git a/logging.c b/logging.c index d901bc8dc..bce2d2a29 100644 --- a/logging.c +++ b/logging.c @@ -314,10 +314,12 @@ log_auth(status, inform_user) user_name, user_shost); else (void) fprintf(stderr, - "Sorry, user %s is not allowed to execute '%s%s%s' as %s on %s.\n", + "Sorry, user %s is not allowed to execute '%s%s%s' as %s%s%s on %s.\n", user_name, user_cmnd, user_args ? " " : "", user_args ? user_args : "", - list_pw ? list_pw->pw_name : *user_runas, user_host); + list_pw ? list_pw->pw_name : runas_pw ? + runas_pw->pw_name : user_name, runas_gr ? ":" : "", + runas_gr ? runas_gr->gr_name : "", user_host); } /* @@ -633,7 +635,10 @@ new_logline(message, serrno) } len += sizeof(LL_TTY_STR) + 2 + strlen(user_tty); len += sizeof(LL_CWD_STR) + 2 + strlen(user_cwd); - len += sizeof(LL_USER_STR) + 2 + strlen(*user_runas); + if (runas_pw != NULL) + len += sizeof(LL_USER_STR) + 2 + strlen(runas_pw->pw_name); + if (runas_gr != NULL) + len += sizeof(LL_GROUP_STR) + 2 + strlen(runas_gr->gr_name); if (sudo_user.env_vars != NULL) { size_t evlen = 0; struct list_member *cur; @@ -675,10 +680,18 @@ new_logline(message, serrno) strlcat(line, user_cwd, len) >= len || strlcat(line, " ; ", len) >= len) goto toobig; - if (strlcat(line, LL_USER_STR, len) >= len || - strlcat(line, *user_runas, len) >= len || - strlcat(line, " ; ", len) >= len) - goto toobig; + if (runas_pw != NULL) { + if (strlcat(line, LL_USER_STR, len) >= len || + strlcat(line, runas_pw->pw_name, len) >= len || + strlcat(line, " ; ", len) >= len) + goto toobig; + } + if (runas_gr != NULL) { + if (strlcat(line, LL_GROUP_STR, len) >= len || + strlcat(line, runas_gr->gr_name, len) >= len || + strlcat(line, " ; ", len) >= len) + goto toobig; + } if (evstr != NULL) { if (strlcat(line, LL_ENV_STR, len) >= len || strlcat(line, evstr, len) >= len || diff --git a/match.c b/match.c index 448761b10..50115a784 100644 --- a/match.c +++ b/match.c @@ -93,6 +93,8 @@ __unused static const char rcsid[] = "$Sudo$"; #endif /* lint */ +static struct member_list empty; + /* * Returns TRUE if string 's' contains meta characters. */ @@ -154,58 +156,92 @@ userlist_matches(pw, list) /* * Check for user described by pw in a list of members. - * If list is NULL compare against def_runas_default. + * If both lists are empty compare against def_runas_default. * Returns ALLOW, DENY or UNSPEC. */ static int -_runaslist_matches(list) - struct member_list *list; +_runaslist_matches(user_list, group_list) + struct member_list *user_list; + struct member_list *group_list; { struct member *m; struct alias *a; int rval, matched = UNSPEC; - if (tq_empty(list)) + /* Deny if user specified a group but there is no group in sudoers */ + if (runas_gr != NULL && tq_empty(group_list)) + return(DENY); + + if (tq_empty(user_list) && tq_empty(group_list)) return(userpw_matches(def_runas_default, runas_pw->pw_name, runas_pw)); - tq_foreach_rev(list, m) { - switch (m->type) { - case ALL: - matched = !m->negated; - break; - case NETGROUP: - if (netgr_matches(m->name, NULL, NULL, runas_pw->pw_name)) + if (runas_pw != NULL) { + tq_foreach_rev(user_list, m) { + switch (m->type) { + case ALL: matched = !m->negated; + break; + case NETGROUP: + if (netgr_matches(m->name, NULL, NULL, runas_pw->pw_name)) + matched = !m->negated; + break; + case USERGROUP: + if (usergr_matches(m->name, runas_pw->pw_name, runas_pw)) + matched = !m->negated; + break; + case ALIAS: + if ((a = find_alias(m->name, RUNASALIAS)) != NULL) { + rval = _runaslist_matches(&a->members, &empty); + if (rval != UNSPEC) + matched = m->negated ? !rval : rval; + break; + } + /* FALLTHROUGH */ + case WORD: + if (userpw_matches(m->name, runas_pw->pw_name, runas_pw)) + matched = !m->negated; + break; + } + if (matched != UNSPEC) break; - case USERGROUP: - if (usergr_matches(m->name, runas_pw->pw_name, runas_pw)) + } + } + + if (runas_gr != NULL) { + tq_foreach_rev(group_list, m) { + switch (m->type) { + case ALL: matched = !m->negated; - break; - case ALIAS: - if ((a = find_alias(m->name, RUNASALIAS)) != NULL) { - rval = _runaslist_matches(&a->members); - if (rval != UNSPEC) - matched = m->negated ? !rval : rval; break; - } - /* FALLTHROUGH */ - case WORD: - if (userpw_matches(m->name, runas_pw->pw_name, runas_pw)) - matched = !m->negated; + case ALIAS: + if ((a = find_alias(m->name, RUNASALIAS)) != NULL) { + rval = _runaslist_matches(&a->members, &empty); + if (rval != UNSPEC) + matched = m->negated ? !rval : rval; + break; + } + /* FALLTHROUGH */ + case WORD: + if (group_matches(m->name, runas_gr)) + matched = !m->negated; + break; + } + if (matched != UNSPEC) break; } - if (matched != UNSPEC) - break; } + return(matched); } int -runaslist_matches(list) - struct member_list *list; +runaslist_matches(user_list, group_list) + struct member_list *user_list; + struct member_list *group_list; { alias_seqno++; - return(_runaslist_matches(list)); + return(_runaslist_matches(user_list ? user_list : &empty, + group_list ? group_list : &empty)); } /* @@ -660,11 +696,28 @@ userpw_matches(sudoers_user, user, pw) if (pw != NULL && *sudoers_user == '#') { uid_t uid = (uid_t) atoi(sudoers_user + 1); if (uid == pw->pw_uid) - return(1); + return(TRUE); } return(strcmp(sudoers_user, user) == 0); } +/* + * Returns TRUE if the group/gid from sudoers matches the specified group/gid, + * else returns FALSE. + */ +int +group_matches(sudoers_group, gr) + char *sudoers_group; + struct group *gr; +{ + if (*sudoers_group == '#') { + gid_t gid = (gid_t) atoi(sudoers_group + 1); + if (gid == gr->gr_gid) + return(TRUE); + } + return(strcmp(gr->gr_name, sudoers_group) == 0); +} + /* * Returns TRUE if the given user belongs to the named group, * else returns FALSE. diff --git a/mon_systrace.c b/mon_systrace.c index f6fbcfe01..26be13913 100644 --- a/mon_systrace.c +++ b/mon_systrace.c @@ -912,7 +912,6 @@ check_execv(fd, pid, seqnr, askp, policyp, errorp) init_defaults(); def_authenticate = FALSE; runas_pw = info->pw; - user_runas = &info->pw->pw_name; validated = VALIDATE_NOT_OK; #ifdef HAVE_LDAP if ((ld = sudo_ldap_open()) != NULL) { diff --git a/parse.c b/parse.c index da561121f..d2f55c475 100644 --- a/parse.c +++ b/parse.c @@ -157,7 +157,8 @@ sudoers_lookup(pwflag) else continue; tq_foreach_rev(&priv->cmndlist, cs) { - runas_match = runaslist_matches(&cs->runaslist); + runas_match = runaslist_matches(&cs->runasuserlist, + &cs->runasgrouplist); if (runas_match == ALLOW) { cmnd_match = cmnd_matches(cs->cmnd); if (cmnd_match != UNSPEC) { @@ -240,9 +241,9 @@ display_privs(v, pw) if (cs != tq_first(&priv->cmndlist)) lbuf_append(&lbuf, ", ", NULL); lbuf_append(&lbuf, "(", NULL); - if (!tq_empty(&cs->runaslist)) { - tq_foreach_fwd(&cs->runaslist, m) { - if (m != tq_first(&cs->runaslist)) + if (!tq_empty(&cs->runasuserlist)) { + tq_foreach_fwd(&cs->runasuserlist, m) { + if (m != tq_first(&cs->runasuserlist)) lbuf_append(&lbuf, ", ", NULL); print_member(&lbuf, m->name, m->type, m->negated, RUNASALIAS); @@ -250,6 +251,15 @@ display_privs(v, pw) } else { lbuf_append(&lbuf, def_runas_default, NULL); } + if (!tq_empty(&cs->runasgrouplist)) { + lbuf_append(&lbuf, " : ", NULL); + tq_foreach_fwd(&cs->runasgrouplist, m) { + if (m != tq_first(&cs->runasgrouplist)) + lbuf_append(&lbuf, ", ", NULL); + print_member(&lbuf, m->name, m->type, m->negated, + RUNASALIAS); + } + } lbuf_append(&lbuf, ") ", NULL); if (TAG_CHANGED(setenv)) { lbuf_append(&lbuf, cs->tags.setenv ? "SETENV: " : @@ -439,7 +449,8 @@ display_cmnd(v, pw) if (host_match != ALLOW) continue; tq_foreach_rev(&priv->cmndlist, cs) { - runas_match = runaslist_matches(&cs->runaslist); + runas_match = runaslist_matches(&cs->runasuserlist, + &cs->runasgrouplist); if (runas_match == ALLOW) { cmnd_match = cmnd_matches(cs->cmnd); if (cmnd_match != UNSPEC) { diff --git a/parse.h b/parse.h index b1958d557..ab20de4bb 100644 --- a/parse.h +++ b/parse.h @@ -98,7 +98,8 @@ struct privilege { */ struct cmndspec { struct cmndspec *prev, *next; - struct member_list runaslist; /* list of runas users */ + struct member_list runasuserlist; /* list of runas users */ + struct member_list runasgrouplist; /* list of runas groups */ struct member *cmnd; /* command to allow/deny */ struct cmndtag tags; /* tag specificaion */ }; @@ -113,6 +114,11 @@ struct member { short negated; /* negated via '!'? */ }; +struct runascontainer { + struct member *runasusers; + struct member *runasgroups; +}; + /* * Generic structure to hold {User,Host,Runas,Cmnd}_Alias * Aliases are stored in a red-black tree, sorted by name and type. @@ -160,10 +166,11 @@ int hostlist_matches __P((struct member_list *)); int hostname_matches __P((char *, char *, char *)); int netgr_matches __P((char *, char *, char *, char *)); int no_aliases __P((void)); -int runaslist_matches __P((struct member_list *)); +int runaslist_matches __P((struct member_list *, struct member_list *)); int userlist_matches __P((struct passwd *, struct member_list *)); int usergr_matches __P((char *, char *, struct passwd *)); int userpw_matches __P((char *, char *, struct passwd *)); +int group_matches __P((char *, struct group *)); struct alias *find_alias __P((char *, int)); void alias_apply __P((int (*)(void *, void *), void *)); void init_aliases __P((void)); diff --git a/pwutil.c b/pwutil.c index 5c02a44b1..1b0224b7d 100644 --- a/pwutil.c +++ b/pwutil.c @@ -329,6 +329,36 @@ sudo_fakepwnam(user) return(pw); } +/* + * Take a gid in string form "#123" and return a faked up group struct. + */ +struct group * +sudo_fakegrnam(group) + const char *group; +{ + struct group *gr; + struct rbnode *node; + size_t len; + + len = strlen(group); + gr = emalloc(sizeof(struct group) + len + 1); + memset(gr, 0, sizeof(struct group)); + gr->gr_gid = (gid_t) atoi(group + 1); + gr->gr_name = (char *)gr + sizeof(struct group); + strlcpy(gr->gr_name, group, len + 1); + + /* Store by gid and by name, overwriting cached version. */ + if ((node = rbinsert(grcache_bygid, gr)) != NULL) { + efree(node->data); + node->data = (void *) gr; + } + if ((node = rbinsert(grcache_byname, gr)) != NULL) { + efree(node->data); + node->data = (void *) gr; + } + return(gr); +} + void sudo_setpwent() { diff --git a/set_perms.c b/set_perms.c index 3034889ef..6548f6dd9 100644 --- a/set_perms.c +++ b/set_perms.c @@ -98,8 +98,10 @@ set_perms(perm) break; case PERM_RUNAS: - (void) setresgid(-1, runas_pw->pw_gid, -1); - if (setresuid(-1, runas_pw->pw_uid, -1)) + (void) setresgid(-1, runas_gr ? + runas_gr->gr_gid : runas_pw->pw_gid, -1); + if (setresuid(-1, + runas_pw ? runas_pw->pw_uid : user_uid, -1)) error(1, "unable to change to runas uid"); break; @@ -175,8 +177,10 @@ set_perms(perm) break; case PERM_RUNAS: - (void) setregid(-1, runas_pw->pw_gid); - if (setreuid(-1, runas_pw->pw_uid)) + (void) setregid(-1, runas_gr ? + runas_gr->gr_gid : runas_pw->pw_gid); + if (setreuid(-1, + runas_pw ? runas_pw->pw_uid : user_uid)) error(1, "unable to change to runas uid"); break; @@ -256,8 +260,9 @@ set_perms(perm) break; case PERM_RUNAS: - (void) setegid(runas_pw->pw_gid); - if (seteuid(runas_pw->pw_uid)) + (void) setegid(runas_gr ? + runas_gr->gr_gid : runas_pw->pw_gid); + if (seteuid(runas_pw ? runas_pw->pw_uid : user_uid)) error(1, "unable to change to runas uid"); break; @@ -339,12 +344,14 @@ set_perms(perm) static void runas_setup() { + gid_t gid; #ifdef HAVE_LOGIN_CAP_H int flags; extern login_cap_t *lc; #endif if (runas_pw->pw_name != NULL) { + gid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid; #ifdef HAVE_PAM pam_prep_user(runas_pw); #endif /* HAVE_PAM */ @@ -360,7 +367,7 @@ runas_setup() flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY; if (!def_preserve_groups) SET(flags, LOGIN_SETGROUP); - else if (setgid(runas_pw->pw_gid)) + else if (setgid(gid)) warning("cannot set gid to runas gid"); if (setusercontext(lc, runas_pw, runas_pw->pw_uid, flags)) { if (runas_pw->pw_uid != ROOT_UID) @@ -371,14 +378,14 @@ runas_setup() } else #endif /* HAVE_LOGIN_CAP_H */ { - if (setgid(runas_pw->pw_gid)) + if (setgid(gid)) warning("cannot set gid to runas gid"); #ifdef HAVE_INITGROUPS /* * Initialize group vector unless asked not to. */ if (!def_preserve_groups && - initgroups(*user_runas, runas_pw->pw_gid) < 0) + initgroups(runas_pw->pw_name, runas_pw->pw_gid) < 0) warning("cannot set group vector"); #endif /* HAVE_INITGROUPS */ } diff --git a/sudo.c b/sudo.c index e7bcd9c2d..0b3ce032a 100644 --- a/sudo.c +++ b/sudo.c @@ -111,6 +111,7 @@ static int parse_args __P((int, char **)); static void initial_setup __P((void)); static void set_loginclass __P((struct passwd *)); static void set_project __P((struct passwd *)); +static void set_runasgr __P((char *)); static void usage __P((int)) __attribute__((__noreturn__)); static void usage_excl __P((int)) @@ -147,6 +148,8 @@ login_cap_t *lc; char *login_style; #endif /* HAVE_BSD_AUTH_H */ sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp, saved_sa_chld; +static char *runas_user; +static char *runas_group; int @@ -280,6 +283,19 @@ main(argc, argv, envp) log_error(NO_STDERR|NO_EXIT, "problem with defaults entries"); } + /* + * Set runas passwd/group entries based on command line or sudoers. + * Note that if runas_group was specified without runas_user we + * defer setting runas_pw so the match routines know to ignore it. + * XXX - early enough? + */ + if (runas_group != NULL) { + set_runasgr(runas_group); + if (runas_user != NULL) + set_runaspw(runas_user); + } else + set_runaspw(runas_user ? runas_user : def_runas_default); + /* This goes after sudoers is parsed since it may have timestamp options. */ if (sudo_mode == MODE_KILL || sudo_mode == MODE_INVALIDATE) { remove_timestamp((sudo_mode == MODE_KILL)); @@ -314,6 +330,10 @@ main(argc, argv, envp) if (safe_cmnd == NULL) safe_cmnd = estrdup(user_cmnd); + /* If only a group was specified, set runas_pw based on invoking user. */ + if (runas_pw == NULL) + set_runaspw(user_name); + /* * Look up the timestamp dir owner if one is specified. */ @@ -603,8 +623,8 @@ init_vars(sudo_mode, envp) * be run during reboot after the YP/NIS/NIS+/LDAP/etc daemon has died. */ if (sudo_mode & (MODE_INVALIDATE|MODE_KILL)) - errorx(1, "uid %s does not exist in the passwd file!", pw_name); - log_error(0, "uid %s does not exist in the passwd file!", pw_name); + errorx(1, "unknown uid: %s", pw_name); + log_error(0, "unknown uid: %s", pw_name); } if (user_shell == NULL || *user_shell == '\0') user_shell = estrdup(sudo_user.pw->pw_shell); @@ -626,10 +646,6 @@ init_vars(sudo_mode, envp) if (nohostname) log_error(USE_ERRNO|MSG_ONLY, "can't get hostname"); - set_runaspw(*user_runas); /* may call log_error() */ - if (*user_runas[0] == '#' && runas_pw->pw_name[0] != '#') - *user_runas = estrdup(runas_pw->pw_name); - /* * Get current working directory. Try as user, fall back to root. */ @@ -668,6 +684,7 @@ init_vars(sudo_mode, envp) } /* Set login class if applicable. */ + /* XXX - should move to after sudoers_lookup */ set_loginclass(sudo_user.pw); } @@ -738,7 +755,7 @@ set_cmnd(sudo_mode) } /* - * Command line argument parsing, can't use getopt(3). + * Command line argument parsing, can't use getopt(3) due to optional args. */ static int parse_args(argc, argv) @@ -779,7 +796,17 @@ parse_args(argc, argv) if (NewArgv[1] == NULL) usage(1); - user_runas = &NewArgv[1]; + runas_user = NewArgv[1]; + + NewArgc--; + NewArgv++; + break; + case 'g': + /* Must have an associated runas group. */ + if (NewArgv[1] == NULL) + usage(1); + + runas_group = NewArgv[1]; NewArgc--; NewArgv++; @@ -897,7 +924,7 @@ parse_args(argc, argv) if (NewArgv[1] == NULL) usage(1); if ((list_pw = sudo_getpwnam(NewArgv[1])) == NULL) - errorx(1, "unknown user %s", NewArgv[1]); + errorx(1, "unknown user: %s", NewArgv[1]); NewArgc--; NewArgv++; break; @@ -943,10 +970,11 @@ args_done: usage(1); } - if (user_runas != NULL && !ISSET(rval, (MODE_EDIT|MODE_RUN|MODE_CHECK))) { + if ((runas_user != NULL || runas_group != NULL) && + !ISSET(rval, (MODE_EDIT|MODE_RUN|MODE_CHECK))) { if (excl != '\0') - warningx("the `-u' and `-%c' options may not be used together", - excl); + warningx("the `-%c' and `-%c' options may not be used together", + runas_user ? 'u' : 'g', excl); usage(1); } if (list_pw != NULL && rval != MODE_LIST && rval != MODE_CHECK) { @@ -1105,7 +1133,9 @@ set_loginclass(pw) errflags = NO_MAIL|MSG_ONLY|NO_EXIT; if (login_class && strcmp(login_class, "-") != 0) { - if (strcmp(*user_runas, "root") != 0 && user_uid != 0) + /* XXX - def_runas user may change after sudoers parse */ + if (user_uid != 0 && + strcmp(runas_user ? runas_user : def_runas_default, "root") != 0) errorx(1, "only root can use -c %s", login_class); } else { login_class = pw->pw_class; @@ -1246,20 +1276,33 @@ int set_runaspw(user) char *user; { - if (runas_pw != NULL) { - if (user_runas != &def_runas_default) - return(TRUE); /* don't override -u option */ - } if (*user == '#') { if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL) runas_pw = sudo_fakepwnam(user); } else { if ((runas_pw = sudo_getpwnam(user)) == NULL) - log_error(NO_MAIL|MSG_ONLY, "no passwd entry for %s!", user); + log_error(NO_MAIL|MSG_ONLY, "unknown user: %s", user); } return(TRUE); } +/* + * Get group entry for the group we are going to run commands as. + * Updates runas_pw as a side effect. + */ +static void +set_runasgr(group) + char *group; +{ + if (*group == '#') { + if ((runas_gr = sudo_getgrgid(atoi(group + 1))) == NULL) + runas_gr = sudo_fakegrnam(group); + } else { + if ((runas_gr = sudo_getgrnam(group)) == NULL) + log_error(NO_MAIL|MSG_ONLY, "unknown group: %s", group); + } +} + /* * Get passwd entry for the user we are going to authenticate as. * By default, this is the user invoking sudo. In the most common @@ -1272,14 +1315,13 @@ get_authpw() if (def_rootpw) { if ((pw = sudo_getpwuid(0)) == NULL) - log_error(0, "uid 0 does not exist in the passwd file!"); + log_error(0, "unknown uid: 0"); } else if (def_runaspw) { if ((pw = sudo_getpwnam(def_runas_default)) == NULL) - log_error(0, "user %s does not exist in the passwd file!", - def_runas_default); + log_error(0, "unknown user: %s", def_runas_default); } else if (def_targetpw) { if (runas_pw->pw_name == NULL) - log_error(NO_MAIL|MSG_ONLY, "no passwd entry for %lu!", + log_error(NO_MAIL|MSG_ONLY, "unknown uid: %lu", (unsigned long) runas_pw->pw_uid); pw = runas_pw; } else diff --git a/sudo.cat b/sudo.cat index cf188abbd..00f026b67 100644 --- a/sudo.cat +++ b/sudo.cat @@ -10,14 +10,16 @@ NNAAMMEE SSYYNNOOPPSSIISS ssuuddoo --hh | --KK | --kk | --LL | --VV | --vv - ssuuddoo --ll [--UU _u_s_e_r_n_a_m_e] [--uu _u_s_e_r_n_a_m_e|_#_u_i_d] [_c_o_m_m_a_n_d] + ssuuddoo --ll [--gg _g_r_o_u_p_n_a_m_e|_#_g_i_d] [--UU _u_s_e_r_n_a_m_e] [--uu _u_s_e_r_- + _n_a_m_e|_#_u_i_d] [_c_o_m_m_a_n_d] ssuuddoo [--bbEEHHPPSS] [--aa _a_u_t_h___t_y_p_e] [--CC _f_d] [--cc _c_l_a_s_s|_-] - [--pp _p_r_o_m_p_t] [--uu _u_s_e_r_n_a_m_e|_#_u_i_d] [VVAARR=_v_a_l_u_e] {--ii | --ss | _c_o_m_- - _m_a_n_d} + [--gg _g_r_o_u_p_n_a_m_e|_#_g_i_d] [--pp _p_r_o_m_p_t] [--uu _u_s_e_r_n_a_m_e|_#_u_i_d] + [VVAARR=_v_a_l_u_e] {--ii | --ss | _c_o_m_m_a_n_d} ssuuddooeeddiitt [--SS] [--aa _a_u_t_h___t_y_p_e] [--CC _f_d] [--cc _c_l_a_s_s|_-] - [--pp _p_r_o_m_p_t] [--uu _u_s_e_r_n_a_m_e|_#_u_i_d] file ... + [--gg _g_r_o_u_p_n_a_m_e|_#_g_i_d] [--pp _p_r_o_m_p_t] [--uu _u_s_e_r_n_a_m_e|_#_u_i_d] file + ... DDEESSCCRRIIPPTTIIOONN ssuuddoo allows a permitted user to execute a _c_o_m_m_a_n_d as the @@ -55,13 +57,11 @@ DDEESSCCRRIIPPTTIIOONN If ssuuddoo is run by root and the SUDO_USER environment vari- able is set, ssuuddoo will use this value to determine who the - actual user is. This can be used by a user to log com- - mands through sudo even when a root shell has been - invoked. It also allows the --ee flag to remain useful even + actual user is. This can be used by a user to log -1.7 August 15, 2007 1 +1.7 November 21, 2007 1 @@ -70,6 +70,8 @@ DDEESSCCRRIIPPTTIIOONN SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) + commands through sudo even when a root shell has been + invoked. It also allows the --ee flag to remain useful even when being run via a sudo-run script or program. Note however, that the sudoers lookup is still done for root, not the user specified by SUDO_USER. @@ -82,52 +84,50 @@ SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) OOPPTTIIOONNSS ssuuddoo accepts the following command line options: - -a The --aa (_a_u_t_h_e_n_t_i_c_a_t_i_o_n _t_y_p_e) option causes ssuuddoo to use - the specified authentication type when validating the - user, as allowed by _/_e_t_c_/_l_o_g_i_n_._c_o_n_f. The system - administrator may specify a list of sudo-specific - authentication methods by adding an "auth-sudo" entry - in _/_e_t_c_/_l_o_g_i_n_._c_o_n_f. This option is only available on - systems that support BSD authentication. + -a _t_y_p_e The --aa (_a_u_t_h_e_n_t_i_c_a_t_i_o_n _t_y_p_e) option causes + ssuuddoo to use the specified authentication type + when validating the user, as allowed by + _/_e_t_c_/_l_o_g_i_n_._c_o_n_f. The system administrator may + specify a list of sudo-specific authentication + methods by adding an "auth-sudo" entry in + _/_e_t_c_/_l_o_g_i_n_._c_o_n_f. This option is only avail- + able on systems that support BSD authentica- + tion. - -b The --bb (_b_a_c_k_g_r_o_u_n_d) option tells ssuuddoo to run the given - command in the background. Note that if you use the - --bb option you cannot use shell job control to manipu- - late the process. + -b The --bb (_b_a_c_k_g_r_o_u_n_d) option tells ssuuddoo to run + the given command in the background. Note + that if you use the --bb option you cannot use + shell job control to manipulate the process. - -C fd - Normally, ssuuddoo will close all open file descriptors - other than standard input, standard output and stan- - dard error. The --CC (_c_l_o_s_e _f_r_o_m) option allows the - user to specify a starting point above the standard - error (file descriptor three). Values less than three - are not permitted. This option is only available if - the administrator has enabled the _c_l_o_s_e_f_r_o_m___o_v_e_r_r_i_d_e - option in _s_u_d_o_e_r_s(4). + -C _f_d Normally, ssuuddoo will close all open file + descriptors other than standard input, stan- + dard output and standard error. The --CC (_c_l_o_s_e + _f_r_o_m) option allows the user to specify a + starting point above the standard error (file + descriptor three). Values less than three are + not permitted. This option is only available + if the administrator has enabled the _c_l_o_s_e_- + _f_r_o_m___o_v_e_r_r_i_d_e option in _s_u_d_o_e_r_s(4). - -c The --cc (_c_l_a_s_s) option causes ssuuddoo to run the specified - command with resources limited by the specified login - class. The _c_l_a_s_s argument can be either a class name - as defined in _/_e_t_c_/_l_o_g_i_n_._c_o_n_f, or a single '-' charac- - ter. Specifying a _c_l_a_s_s of - indicates that the com- - mand should be run restricted by the default login - capabilities for the user the command is run as. If - the _c_l_a_s_s argument specifies an existing user class, - the command must be run as root, or the ssuuddoo command - must be run from a shell that is already root. This - option is only available on systems with BSD login - classes. + -c _c_l_a_s_s The --cc (_c_l_a_s_s) option causes ssuuddoo to run the + specified command with resources limited by + the specified login class. The _c_l_a_s_s argument + can be either a class name as defined in + _/_e_t_c_/_l_o_g_i_n_._c_o_n_f, or a single '-' character. + Specifying a _c_l_a_s_s of - indicates that the + command should be run restricted by the + default login capabilities for the user the + command is run as. If the _c_l_a_s_s argument + specifies an existing user class, the command + must be run as root, or the ssuuddoo command must + be run from a shell that is already root. + This option is only available on systems with + BSD login classes. - -E The --EE (_p_r_e_s_e_r_v_e _e_n_v_i_r_o_n_m_e_n_t) option will override the - _e_n_v___r_e_s_e_t option in _s_u_d_o_e_r_s(4)). It is only available - when either the matching command has the SETENV tag or - the _s_e_t_e_n_v option is set in _s_u_d_o_e_r_s(4). - -e The --ee (_e_d_i_t) option indicates that, instead of - -1.7 August 15, 2007 2 +1.7 November 21, 2007 2 @@ -136,165 +136,214 @@ OOPPTTIIOONNSS SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) - running a command, the user wishes to edit one or more - files. In lieu of a command, the string "sudoedit" is - used when consulting the _s_u_d_o_e_r_s file. If the user is - authorized by _s_u_d_o_e_r_s the following steps are taken: + -E The --EE (_p_r_e_s_e_r_v_e _e_n_v_i_r_o_n_m_e_n_t) option will + override the _e_n_v___r_e_s_e_t option in _s_u_d_o_e_r_s(4)). + It is only available when either the matching + command has the SETENV tag or the _s_e_t_e_n_v + option is set in _s_u_d_o_e_r_s(4). - 1. Temporary copies are made of the files to be - edited with the owner set to the invoking user. + -e The --ee (_e_d_i_t) option indicates that, instead + of running a command, the user wishes to edit + one or more files. In lieu of a command, the + string "sudoedit" is used when consulting the + _s_u_d_o_e_r_s file. If the user is authorized by + _s_u_d_o_e_r_s the following steps are taken: - 2. The editor specified by the VISUAL or EDITOR envi- - ronment variables is run to edit the temporary - files. If neither VISUAL nor EDITOR are set, the - program listed in the _e_d_i_t_o_r _s_u_d_o_e_r_s variable is - used. + 1. Temporary copies are made of the files to + be edited with the owner set to the invok- + ing user. - 3. If they have been modified, the temporary files - are copied back to their original location and the - temporary versions are removed. + 2. The editor specified by the VISUAL or EDI- + TOR environment variables is run to edit + the temporary files. If neither VISUAL + nor EDITOR are set, the program listed in + the _e_d_i_t_o_r _s_u_d_o_e_r_s variable is used. - If the specified file does not exist, it will be cre- - ated. Note that unlike most commands run by ssuuddoo, the - editor is run with the invoking user's environment - unmodified. If, for some reason, ssuuddoo is unable to - update a file with its edited version, the user will - receive a warning and the edited copy will remain in a - temporary file. + 3. If they have been modified, the temporary + files are copied back to their original + location and the temporary versions are + removed. - -H The --HH (_H_O_M_E) option sets the HOME environment vari- - able to the homedir of the target user (root by - default) as specified in _p_a_s_s_w_d(4). By default, ssuuddoo - does not modify HOME (see _s_e_t___h_o_m_e and _a_l_w_a_y_s___s_e_t___h_o_m_e - in _s_u_d_o_e_r_s(4)). + If the specified file does not exist, it will + be created. Note that unlike most commands + run by ssuuddoo, the editor is run with the invok- + ing user's environment unmodified. If, for + some reason, ssuuddoo is unable to update a file + with its edited version, the user will receive + a warning and the edited copy will remain in a + temporary file. - -h The --hh (_h_e_l_p) option causes ssuuddoo to print a usage mes- - sage and exit. + -g _g_r_o_u_p Normally, ssuuddoo sets the primary group to the + one specified by the passwd database for the + user the command is being run as (by default, + root). The --gg (_g_r_o_u_p) option causes ssuuddoo to + run the specified command with the primary + group set to _g_r_o_u_p. To specify a _g_i_d instead + of a _g_r_o_u_p _n_a_m_e, use _#_g_i_d. When running com- + mands as a _g_i_d, many shells require that the + '#' be escaped with a backslash ('\'). If no + --uu option is specified, the command will be + run as the invoking user (not root). In + either case, the primary group will be set to + _g_r_o_u_p. - -i The --ii (_s_i_m_u_l_a_t_e _i_n_i_t_i_a_l _l_o_g_i_n) option runs the shell - specified in the _p_a_s_s_w_d(4) entry of the user that the - command is being run as. The command name argument - given to the shell begins with a `-' to tell the shell - to run as a login shell. ssuuddoo attempts to change to - that user's home directory before running the shell. - It also initializes the environment, leaving _D_I_S_P_L_A_Y - and _T_E_R_M unchanged, setting _H_O_M_E, _S_H_E_L_L, _U_S_E_R, _L_O_G_- - _N_A_M_E, and _P_A_T_H, and unsetting all other environment - variables. + -H The --HH (_H_O_M_E) option sets the HOME environment + variable to the homedir of the target user + (root by default) as specified in _p_a_s_s_w_d(4). - -K The --KK (sure _k_i_l_l) option is like --kk except that it - removes the user's timestamp entirely. Like --kk, this - option does not require a password. - -k The --kk (_k_i_l_l) option to ssuuddoo invalidates the user's - timestamp by setting the time on it to the Epoch. The - next time ssuuddoo is run a password will be required. - This option does not require a password and was added +1.7 November 21, 2007 3 -1.7 August 15, 2007 3 +SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) -SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) + By default, ssuuddoo does not modify HOME (see + _s_e_t___h_o_m_e and _a_l_w_a_y_s___s_e_t___h_o_m_e in _s_u_d_o_e_r_s(4)). + + -h The --hh (_h_e_l_p) option causes ssuuddoo to print a + usage message and exit. + + -i The --ii (_s_i_m_u_l_a_t_e _i_n_i_t_i_a_l _l_o_g_i_n) option runs + the shell specified in the _p_a_s_s_w_d(4) entry of + the user that the command is being run as. + The command name argument given to the shell + begins with a `-' to tell the shell to run as + a login shell. ssuuddoo attempts to change to + that user's home directory before running the + shell. It also initializes the environment, + leaving _D_I_S_P_L_A_Y and _T_E_R_M unchanged, setting + _H_O_M_E, _S_H_E_L_L, _U_S_E_R, _L_O_G_N_A_M_E, and _P_A_T_H, and + unsetting all other environment variables. + + -K The --KK (sure _k_i_l_l) option is like --kk except + that it removes the user's timestamp entirely. + Like --kk, this option does not require a pass- + word. + + -k The --kk (_k_i_l_l) option to ssuuddoo invalidates the + user's timestamp by setting the time on it to + the Epoch. The next time ssuuddoo is run a pass- + word will be required. This option does not + require a password and was added to allow a + user to revoke ssuuddoo permissions from a .logout + file. + + -L The --LL (_l_i_s_t defaults) option will list out + the parameters that may be set in a _D_e_f_a_u_l_t_s + line along with a short description for each. + This option is useful in conjunction with + _g_r_e_p(1). + -l [_c_o_m_m_a_n_d] + If no _c_o_m_m_a_n_d is specified, the --ll (_l_i_s_t) + option will list the allowed (and forbidden) + commands for the invoking user (or the user + specified by the --UU option) on the current + host. If a _c_o_m_m_a_n_d is specified and is per- + mitted by _s_u_d_o_e_r_s, the fully-qualified path to + the command is displayed along with any com- + mand line arguments. If _c_o_m_m_a_n_d is not + allowed, ssuuddoo will exit with a return value of + 1. - to allow a user to revoke ssuuddoo permissions from a - .logout file. + -P The --PP (_p_r_e_s_e_r_v_e _g_r_o_u_p _v_e_c_t_o_r) option causes + ssuuddoo to preserve the invoking user's group + vector unaltered. By default, ssuuddoo will ini- + tialize the group vector to the list of groups + the target user is in. The real and effective - -L The --LL (_l_i_s_t defaults) option will list out the param- - eters that may be set in a _D_e_f_a_u_l_t_s line along with a - short description for each. This option is useful in - conjunction with _g_r_e_p(1). - -l [_c_o_m_m_a_n_d] - If no _c_o_m_m_a_n_d is specified, the --ll (_l_i_s_t) option will - list the allowed (and forbidden) commands for the - invoking user (or the user specified by the --UU option) - on the current host. If a _c_o_m_m_a_n_d is specified and is - permitted by _s_u_d_o_e_r_s, the fully-qualified path to the - command is displayed along with any command line argu- - ments. If _c_o_m_m_a_n_d is not allowed, ssuuddoo will exit with - a return value of 1. - -P The --PP (_p_r_e_s_e_r_v_e _g_r_o_u_p _v_e_c_t_o_r) option causes ssuuddoo to - preserve the invoking user's group vector unaltered. - By default, ssuuddoo will initialize the group vector to - the list of groups the target user is in. The real - and effective group IDs, however, are still set to - match the target user. +1.7 November 21, 2007 4 - -p The --pp (_p_r_o_m_p_t) option allows you to override the - default password prompt and use a custom one. The - following percent (`%') escapes are supported: - %H expanded to the local hostname including the - domain name (on if the machine's hostname is fully - qualified or the _f_q_d_n _s_u_d_o_e_r_s option is set) - %h expanded to the local hostname without the domain - name - %U expanded to the login name of the user the command - will be run as (defaults to root) - %u expanded to the invoking user's login name +SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) - %% two consecutive % characters are collapsed into a - single % character - -S The --SS (_s_t_d_i_n) option causes ssuuddoo to read the password - from the standard input instead of the terminal - device. + group IDs, however, are still set to match the + target user. - -s The --ss (_s_h_e_l_l) option runs the shell specified by the - _S_H_E_L_L environment variable if it is set or the shell - as specified in _p_a_s_s_w_d(4). + -p _p_r_o_m_p_t The --pp (_p_r_o_m_p_t) option allows you to override + the default password prompt and use a custom + one. The following percent (`%') escapes are + supported: - -U The --UU (_o_t_h_e_r _u_s_e_r) option is used in conjunction with - the --ll option to specify the user whose privileges + %H expanded to the local hostname including + the domain name (on if the machine's host- + name is fully qualified or the _f_q_d_n _s_u_d_o_- + _e_r_s option is set) + %h expanded to the local hostname without the + domain name + %U expanded to the login name of the user the + command will be run as (defaults to root) -1.7 August 15, 2007 4 + %u expanded to the invoking user's login name + %% two consecutive % characters are collapsed + into a single % character + -S The --SS (_s_t_d_i_n) option causes ssuuddoo to read the + password from the standard input instead of + the terminal device. + -s The --ss (_s_h_e_l_l) option runs the shell specified + by the _S_H_E_L_L environment variable if it is set + or the shell as specified in _p_a_s_s_w_d(4). + + -U _u_s_e_r The --UU (_o_t_h_e_r _u_s_e_r) option is used in conjunc- + tion with the --ll option to specify the user + whose privileges should be listed. Only root + or a user with ssuuddoo ALL on the current host + may use this option. + + -u _u_s_e_r The --uu (_u_s_e_r) option causes ssuuddoo to run the + specified command as a user other than _r_o_o_t. + To specify a _u_i_d instead of a _u_s_e_r _n_a_m_e, use + _#_u_i_d. When running commands as a _u_i_d, many + shells require that the '#' be escaped with a + backslash ('\'). Note that if the _t_a_r_g_e_t_p_w + Defaults option is set (see _s_u_d_o_e_r_s(4)) it is + not possible to run commands with a uid not + listed in the password database. + + -V The --VV (_v_e_r_s_i_o_n) option causes ssuuddoo to print + the version number and exit. If the invoking + user is already root the --VV option will print + out a list of the defaults ssuuddoo was compiled + with as well as the machine's local network + addresses. + + + +1.7 November 21, 2007 5 -SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) - should be listed. Only root or a user with ssuuddoo ALL - on the current host may use this option. - -u The --uu (_u_s_e_r) option causes ssuuddoo to run the specified - command as a user other than _r_o_o_t. To specify a _u_i_d - instead of a _u_s_e_r_n_a_m_e, use _#_u_i_d. When running com- - mands as a _u_i_d, many shells require that the '#' be - escaped with a backslash ('\'). Note that if the _t_a_r_- - _g_e_t_p_w Defaults option is set (see _s_u_d_o_e_r_s(4)) it is - not possible to run commands with a uid not listed in - the password database. +SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) - -V The --VV (_v_e_r_s_i_o_n) option causes ssuuddoo to print the ver- - sion number and exit. If the invoking user is already - root the --VV option will print out a list of the - defaults ssuuddoo was compiled with as well as the - machine's local network addresses. - -v If given the --vv (_v_a_l_i_d_a_t_e) option, ssuuddoo will update - the user's timestamp, prompting for the user's pass- - word if necessary. This extends the ssuuddoo timeout for - another 5 minutes (or whatever the timeout is set to - in _s_u_d_o_e_r_s) but does not run a command. + -v If given the --vv (_v_a_l_i_d_a_t_e) option, ssuuddoo will + update the user's timestamp, prompting for the + user's password if necessary. This extends + the ssuuddoo timeout for another 5 minutes (or + whatever the timeout is set to in _s_u_d_o_e_r_s) but + does not run a command. - -- The ---- flag indicates that ssuuddoo should stop processing - command line arguments. It is most useful in conjunc- - tion with the --ss flag. + -- The ---- flag indicates that ssuuddoo should stop + processing command line arguments. It is most + useful in conjunction with the --ss flag. Environment variables to be set for the command may also be passed on the command line in the form of VVAARR=_v_a_l_u_e, @@ -302,9 +351,10 @@ SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) passed on the command line are subject to the same restrictions as normal environment variables with one important exception. If the _s_e_t_e_n_v option is set in _s_u_d_o_- - _e_r_s or the command to be run has the SETENV tag set the - user may set variables that would overwise be forbidden. - See _s_u_d_o_e_r_s(4) for more information. + _e_r_s, the command to be run has the SETENV tag set or the + command matched is ALL, the user may set variables that + would overwise be forbidden. See _s_u_d_o_e_r_s(4) for more + information. RREETTUURRNN VVAALLUUEESS Upon successful execution of a program, the return value @@ -322,18 +372,6 @@ RREETTUURRNN VVAALLUUEESS stances. The most common reason for _s_t_a_t(2) to return "permission denied" is if you are running an automounter and one of the directories in your PATH is on a machine - - - -1.7 August 15, 2007 5 - - - - - -SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) - - that is currently unreachable. SSEECCUURRIITTYY NNOOTTEESS @@ -350,6 +388,18 @@ SSEECCUURRIITTYY NNOOTTEESS If, however, the _e_n_v___r_e_s_e_t option is disabled in _s_u_d_o_e_r_s, any variables not explicitly denied by the _e_n_v___c_h_e_c_k and + + + +1.7 November 21, 2007 6 + + + + + +SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) + + _e_n_v___d_e_l_e_t_e options are inherited from the invoking pro- cess. In this case, _e_n_v___c_h_e_c_k and _e_n_v___d_e_l_e_t_e behave like a blacklist. Since it is not possible to blacklist all @@ -388,18 +438,6 @@ SSEECCUURRIITTYY NNOOTTEESS timestamp directory before ssuuddoo is run. However, because ssuuddoo checks the ownership and mode of the directory and its contents, the only damage that can be done is to - - - -1.7 August 15, 2007 6 - - - - - -SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) - - "hide" files by putting them in the timestamp dir. This is unlikely to happen since once the timestamp dir is owned by root and inaccessible by any other user, the user @@ -417,6 +455,17 @@ SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) timestamp with a bogus date on systems that allow users to give away files. + + +1.7 November 21, 2007 7 + + + + + +SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) + + Please note that ssuuddoo will normally only log the command it explicitly runs. If a user runs a command such as sudo su or sudo sh, subsequent commands run from that shell @@ -455,17 +504,6 @@ EENNVVIIRROONNMMEENNTT SUDO_UID Set to the uid of the user who invoked sudo - - -1.7 August 15, 2007 7 - - - - - -SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) - - SUDO_GID Set to the gid of the user who invoked sudo @@ -481,6 +519,19 @@ FFIILLEESS _/_e_t_c_/_s_u_d_o_e_r_s List of who can run what _/_v_a_r_/_r_u_n_/_s_u_d_o Directory containing timestamps + + + + +1.7 November 21, 2007 8 + + + + + +SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) + + EEXXAAMMPPLLEESS Note: the following examples assume suitable _s_u_d_o_e_r_s(4) entries. @@ -520,18 +571,6 @@ AAUUTTHHOORRSS Todd C. Miller See the HISTORY file in the ssuuddoo distribution or visit - - - -1.7 August 15, 2007 8 - - - - - -SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) - - http://www.sudo.ws/sudo/history.html for a short history of ssuuddoo. @@ -547,6 +586,18 @@ CCAAVVEEAATTSS It is not meaningful to run the cd command directly via sudo, e.g., + + + +1.7 November 21, 2007 9 + + + + + +SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) + + $ sudo cd /usr/local/protected since when the command exits the parent process (your @@ -589,6 +640,21 @@ DDIISSCCLLAAIIMMEERR -1.7 August 15, 2007 9 + + + + + + + + + + + + + + + +1.7 November 21, 2007 10 diff --git a/sudo.h b/sudo.h index d79160785..9377aad39 100644 --- a/sudo.h +++ b/sudo.h @@ -37,6 +37,7 @@ struct sudo_user { struct passwd *pw; struct passwd *_runas_pw; + struct group *_runas_gr; struct stat *cmnd_stat; char *path; char *shell; @@ -44,7 +45,6 @@ struct sudo_user { char *ttypath; char *host; char *shost; - char **runas; char *prompt; char *cmnd; char *cmnd_args; @@ -132,7 +132,6 @@ struct sudo_user { #define user_tty (sudo_user.tty) #define user_ttypath (sudo_user.ttypath) #define user_cwd (sudo_user.cwd) -#define user_runas (sudo_user.runas) #define user_cmnd (sudo_user.cmnd) #define user_args (sudo_user.cmnd_args) #define user_base (sudo_user.cmnd_base) @@ -145,6 +144,7 @@ struct sudo_user { #define safe_cmnd (sudo_user.cmnd_safe) #define login_class (sudo_user.class_name) #define runas_pw (sudo_user._runas_pw) +#define runas_gr (sudo_user._runas_gr) /* * We used to use the system definition of PASS_MAX or _PASSWD_LEN, @@ -281,6 +281,7 @@ struct passwd *sudo_fakepwnam __P((const char *)); struct passwd *sudo_getpwuid __P((uid_t)); struct passwd *sudo_fakepwuid __P((uid_t)); struct group *sudo_getgrnam __P((const char *)); +struct group *sudo_fakegrnam __P((const char *)); struct group *sudo_getgrgid __P((gid_t)); YY_DECL; diff --git a/sudo.man.in b/sudo.man.in index 05516a920..77b3c80cc 100644 --- a/sudo.man.in +++ b/sudo.man.in @@ -150,22 +150,24 @@ .\" ======================================================================== .\" .IX Title "SUDO @mansectsu@" -.TH SUDO @mansectsu@ "August 15, 2007" "1.7" "MAINTENANCE COMMANDS" +.TH SUDO @mansectsu@ "November 21, 2007" "1.7" "MAINTENANCE COMMANDS" .SH "NAME" sudo, sudoedit \- execute a command as another user .SH "SYNOPSIS" .IX Header "SYNOPSIS" \&\fBsudo\fR \fB\-h\fR | \fB\-K\fR | \fB\-k\fR | \fB\-L\fR | \fB\-V\fR | \fB\-v\fR .PP -\&\fBsudo\fR \fB\-l\fR [\fB\-U\fR\ \fIusername\fR] [\fB\-u\fR\ \fIusername\fR|\fI#uid\fR] [\fIcommand\fR] +\&\fBsudo\fR \fB\-l\fR [\fB\-g\fR\ \fIgroupname\fR|\fI#gid\fR] [\fB\-U\fR\ \fIusername\fR] +[\fB\-u\fR\ \fIusername\fR|\fI#uid\fR] [\fIcommand\fR] .PP \&\fBsudo\fR [\fB\-bEHPS\fR] [\fB\-a\fR\ \fIauth_type\fR] [\fB\-C\fR\ \fIfd\fR] -[\fB\-c\fR\ \fIclass\fR|\fI\-\fR] [\fB\-p\fR\ \fIprompt\fR] [\fB\-u\fR\ \fIusername\fR|\fI#uid\fR] -[\fB\s-1VAR\s0\fR=\fIvalue\fR] {\fB\-i\fR\ |\ \fB\-s\fR\ |\ \fIcommand\fR} +[\fB\-c\fR\ \fIclass\fR|\fI\-\fR] [\fB\-g\fR\ \fIgroupname\fR|\fI#gid\fR] [\fB\-p\fR\ \fIprompt\fR] +[\fB\-u\fR\ \fIusername\fR|\fI#uid\fR] [\fB\s-1VAR\s0\fR=\fIvalue\fR] +{\fB\-i\fR\ |\ \fB\-s\fR\ |\ \fIcommand\fR} .PP \&\fBsudoedit\fR [\fB\-S\fR] [\fB\-a\fR\ \fIauth_type\fR] [\fB\-C\fR\ \fIfd\fR] -[\fB\-c\fR\ \fIclass\fR|\fI\-\fR] [\fB\-p\fR\ \fIprompt\fR] [\fB\-u\fR\ \fIusername\fR|\fI#uid\fR] -file ... +[\fB\-c\fR\ \fIclass\fR|\fI\-\fR] [\fB\-g\fR\ \fIgroupname\fR|\fI#gid\fR] [\fB\-p\fR\ \fIprompt\fR] +[\fB\-u\fR\ \fIusername\fR|\fI#uid\fR] file ... .SH "DESCRIPTION" .IX Header "DESCRIPTION" \&\fBsudo\fR allows a permitted user to execute a \fIcommand\fR as the @@ -215,20 +217,20 @@ or via the \fIsudoers\fR file. .SH "OPTIONS" .IX Header "OPTIONS" \&\fBsudo\fR accepts the following command line options: -.IP "\-a" 4 -.IX Item "-a" +.IP "\-a \fItype\fR" 12 +.IX Item "-a type" The \fB\-a\fR (\fIauthentication type\fR) option causes \fBsudo\fR to use the specified authentication type when validating the user, as allowed by \fI/etc/login.conf\fR. The system administrator may specify a list of sudo-specific authentication methods by adding an \*(L"auth\-sudo\*(R" entry in \fI/etc/login.conf\fR. This option is only available on systems that support \s-1BSD\s0 authentication. -.IP "\-b" 4 +.IP "\-b" 12 .IX Item "-b" The \fB\-b\fR (\fIbackground\fR) option tells \fBsudo\fR to run the given command in the background. Note that if you use the \fB\-b\fR option you cannot use shell job control to manipulate the process. -.IP "\-C fd" 4 +.IP "\-C \fIfd\fR" 12 .IX Item "-C fd" Normally, \fBsudo\fR will close all open file descriptors other than standard input, standard output and standard error. The \fB\-C\fR @@ -237,8 +239,8 @@ above the standard error (file descriptor three). Values less than three are not permitted. This option is only available if the administrator has enabled the \fIclosefrom_override\fR option in \&\fIsudoers\fR\|(@mansectform@). -.IP "\-c" 4 -.IX Item "-c" +.IP "\-c \fIclass\fR" 12 +.IX Item "-c class" The \fB\-c\fR (\fIclass\fR) option causes \fBsudo\fR to run the specified command with resources limited by the specified login class. The \fIclass\fR argument can be either a class name as defined in \fI/etc/login.conf\fR, @@ -248,20 +250,20 @@ capabilities for the user the command is run as. If the \fIclass\fR argument specifies an existing user class, the command must be run as root, or the \fBsudo\fR command must be run from a shell that is already root. This option is only available on systems with \s-1BSD\s0 login classes. -.IP "\-E" 4 +.IP "\-E" 12 .IX Item "-E" The \fB\-E\fR (\fIpreserve\fR \fIenvironment\fR) option will override the \&\fIenv_reset\fR option in \fIsudoers\fR\|(@mansectform@)). It is only available when either the matching command has the \f(CW\*(C`SETENV\*(C'\fR tag or the \fIsetenv\fR option is set in \fIsudoers\fR\|(@mansectform@). -.IP "\-e" 4 +.IP "\-e" 12 .IX Item "-e" The \fB\-e\fR (\fIedit\fR) option indicates that, instead of running a command, the user wishes to edit one or more files. In lieu of a command, the string \*(L"sudoedit\*(R" is used when consulting the \fIsudoers\fR file. If the user is authorized by \fIsudoers\fR the following steps are taken: -.RS 4 +.RS 12 .IP "1." 4 Temporary copies are made of the files to be edited with the owner set to the invoking user. @@ -274,7 +276,7 @@ variable is used. If they have been modified, the temporary files are copied back to their original location and the temporary versions are removed. .RE -.RS 4 +.RS 12 .Sp If the specified file does not exist, it will be created. Note that unlike most commands run by \fBsudo\fR, the editor is run with @@ -283,16 +285,27 @@ the invoking user's environment unmodified. If, for some reason, user will receive a warning and the edited copy will remain in a temporary file. .RE -.IP "\-H" 4 +.IP "\-g \fIgroup\fR" 12 +.IX Item "-g group" +Normally, \fBsudo\fR sets the primary group to the one specified by +the passwd database for the user the command is being run as (by +default, root). The \fB\-g\fR (\fIgroup\fR) option causes \fBsudo\fR to run +the specified command with the primary group set to \fIgroup\fR. To +specify a \fIgid\fR instead of a \fIgroup name\fR, use \fI#gid\fR. When +running commands as a \fIgid\fR, many shells require that the '#' be +escaped with a backslash ('\e'). If no \fB\-u\fR option is specified, +the command will be run as the invoking user (not root). In either +case, the primary group will be set to \fIgroup\fR. +.IP "\-H" 12 .IX Item "-H" The \fB\-H\fR (\fI\s-1HOME\s0\fR) option sets the \f(CW\*(C`HOME\*(C'\fR environment variable to the homedir of the target user (root by default) as specified in \fIpasswd\fR\|(@mansectform@). By default, \fBsudo\fR does not modify \f(CW\*(C`HOME\*(C'\fR (see \fIset_home\fR and \fIalways_set_home\fR in \fIsudoers\fR\|(@mansectform@)). -.IP "\-h" 4 +.IP "\-h" 12 .IX Item "-h" The \fB\-h\fR (\fIhelp\fR) option causes \fBsudo\fR to print a usage message and exit. -.IP "\-i" 4 +.IP "\-i" 12 .IX Item "-i" The \fB\-i\fR (\fIsimulate initial login\fR) option runs the shell specified in the \fIpasswd\fR\|(@mansectform@) entry of the user that the command is @@ -302,24 +315,24 @@ attempts to change to that user's home directory before running the shell. It also initializes the environment, leaving \fI\s-1DISPLAY\s0\fR and \fI\s-1TERM\s0\fR unchanged, setting \fI\s-1HOME\s0\fR, \fI\s-1SHELL\s0\fR, \fI\s-1USER\s0\fR, \fI\s-1LOGNAME\s0\fR, and \&\fI\s-1PATH\s0\fR, and unsetting all other environment variables. -.IP "\-K" 4 +.IP "\-K" 12 .IX Item "-K" The \fB\-K\fR (sure \fIkill\fR) option is like \fB\-k\fR except that it removes the user's timestamp entirely. Like \fB\-k\fR, this option does not require a password. -.IP "\-k" 4 +.IP "\-k" 12 .IX Item "-k" The \fB\-k\fR (\fIkill\fR) option to \fBsudo\fR invalidates the user's timestamp by setting the time on it to the Epoch. The next time \fBsudo\fR is run a password will be required. This option does not require a password and was added to allow a user to revoke \fBsudo\fR permissions from a .logout file. -.IP "\-L" 4 +.IP "\-L" 12 .IX Item "-L" The \fB\-L\fR (\fIlist\fR defaults) option will list out the parameters that may be set in a \fIDefaults\fR line along with a short description for each. This option is useful in conjunction with \fIgrep\fR\|(1). -.IP "\-l [\fIcommand\fR]" 4 +.IP "\-l [\fIcommand\fR]" 12 .IX Item "-l [command]" If no \fIcommand\fR is specified, the \fB\-l\fR (\fIlist\fR) option will list the allowed (and forbidden) commands for the invoking user (or the @@ -328,19 +341,19 @@ user specified by the \fB\-U\fR option) on the current host. If a fully-qualified path to the command is displayed along with any command line arguments. If \fIcommand\fR is not allowed, \fBsudo\fR will exit with a return value of 1. -.IP "\-P" 4 +.IP "\-P" 12 .IX Item "-P" The \fB\-P\fR (\fIpreserve\fR \fIgroup vector\fR) option causes \fBsudo\fR to preserve the invoking user's group vector unaltered. By default, \&\fBsudo\fR will initialize the group vector to the list of groups the target user is in. The real and effective group IDs, however, are still set to match the target user. -.IP "\-p" 4 -.IX Item "-p" +.IP "\-p \fIprompt\fR" 12 +.IX Item "-p prompt" The \fB\-p\fR (\fIprompt\fR) option allows you to override the default password prompt and use a custom one. The following percent (`\f(CW\*(C`%\*(C'\fR') escapes are supported: -.RS 4 +.RS 12 .ie n .IP "%H" 4 .el .IP "\f(CW%H\fR" 4 .IX Item "%H" @@ -365,46 +378,46 @@ expanded to the invoking user's login name .IX Item "%%" two consecutive \f(CW\*(C`%\*(C'\fR characters are collapsed into a single \f(CW\*(C`%\*(C'\fR character .RE -.RS 4 +.RS 12 .RE -.IP "\-S" 4 +.IP "\-S" 12 .IX Item "-S" The \fB\-S\fR (\fIstdin\fR) option causes \fBsudo\fR to read the password from the standard input instead of the terminal device. -.IP "\-s" 4 +.IP "\-s" 12 .IX Item "-s" The \fB\-s\fR (\fIshell\fR) option runs the shell specified by the \fI\s-1SHELL\s0\fR environment variable if it is set or the shell as specified in \fIpasswd\fR\|(@mansectform@). -.IP "\-U" 4 -.IX Item "-U" +.IP "\-U \fIuser\fR" 12 +.IX Item "-U user" The \fB\-U\fR (\fIother user\fR) option is used in conjunction with the \fB\-l\fR option to specify the user whose privileges should be listed. Only root or a user with \fBsudo\fR \f(CW\*(C`ALL\*(C'\fR on the current host may use this option. -.IP "\-u" 4 -.IX Item "-u" +.IP "\-u \fIuser\fR" 12 +.IX Item "-u user" The \fB\-u\fR (\fIuser\fR) option causes \fBsudo\fR to run the specified command as a user other than \fIroot\fR. To specify a \fIuid\fR instead -of a \fIusername\fR, use \fI#uid\fR. When running commands as a \fIuid\fR, +of a \fIuser name\fR, use \fI#uid\fR. When running commands as a \fIuid\fR, many shells require that the '#' be escaped with a backslash ('\e'). Note that if the \fItargetpw\fR Defaults option is set (see \fIsudoers\fR\|(@mansectform@)) it is not possible to run commands with a uid not listed in the password database. -.IP "\-V" 4 +.IP "\-V" 12 .IX Item "-V" The \fB\-V\fR (\fIversion\fR) option causes \fBsudo\fR to print the version number and exit. If the invoking user is already root the \fB\-V\fR option will print out a list of the defaults \fBsudo\fR was compiled with as well as the machine's local network addresses. -.IP "\-v" 4 +.IP "\-v" 12 .IX Item "-v" If given the \fB\-v\fR (\fIvalidate\fR) option, \fBsudo\fR will update the user's timestamp, prompting for the user's password if necessary. This extends the \fBsudo\fR timeout for another \f(CW\*(C`@timeout@\*(C'\fR minutes (or whatever the timeout is set to in \fIsudoers\fR) but does not run a command. -.IP "\-\-" 4 +.IP "\-\-" 12 The \fB\-\-\fR flag indicates that \fBsudo\fR should stop processing command line arguments. It is most useful in conjunction with the \fB\-s\fR flag. .PP @@ -413,9 +426,9 @@ on the command line in the form of \fB\s-1VAR\s0\fR=\fIvalue\fR, e.g. \&\fB\s-1LD_LIBRARY_PATH\s0\fR=\fI/usr/local/pkg/lib\fR. Variables passed on the command line are subject to the same restrictions as normal environment variables with one important exception. If the \fIsetenv\fR option -is set in \fIsudoers\fR or the command to be run has the \f(CW\*(C`SETENV\*(C'\fR tag -set the user may set variables that would overwise be forbidden. -See \fIsudoers\fR\|(@mansectform@) for more information. +is set in \fIsudoers\fR, the command to be run has the \f(CW\*(C`SETENV\*(C'\fR tag +set or the command matched is \f(CW\*(C`ALL\*(C'\fR, the user may set variables +that would overwise be forbidden. See \fIsudoers\fR\|(@mansectform@) for more information. .SH "RETURN VALUES" .IX Header "RETURN VALUES" Upon successful execution of a program, the return value from \fBsudo\fR diff --git a/sudo.pod b/sudo.pod index 686817c2e..e8636b09c 100644 --- a/sudo.pod +++ b/sudo.pod @@ -30,15 +30,17 @@ sudo, sudoedit - execute a command as another user B B<-h> | B<-K> | B<-k> | B<-L> | B<-V> | B<-v> -B B<-l> S<[B<-U> I]> S<[B<-u> I|I<#uid>]> [I] +B B<-l> S<[B<-g> I|I<#gid>]> S<[B<-U> I]> +S<[B<-u> I|I<#uid>]> [I] B [B<-bEHPS>] S<[B<-a> I]> S<[B<-C> I]> -S<[B<-c> I|I<->]> S<[B<-p> I]> S<[B<-u> I|I<#uid>]> -S<[B=I]> S<{B<-i> | B<-s> | I}> +S<[B<-c> I|I<->]> S<[B<-g> I|I<#gid>]> S<[B<-p> I]> +S<[B<-u> I|I<#uid>]> S<[B=I]> +S<{B<-i> | B<-s> | I}> B [B<-S>] S<[B<-a> I]> S<[B<-C> I]> -S<[B<-c> I|I<->]> S<[B<-p> I]> S<[B<-u> I|I<#uid>]> -file ... +S<[B<-c> I|I<->]> S<[B<-g> I|I<#gid>]> S<[B<-p> I]> +S<[B<-u> I|I<#uid>]> file ... =head1 DESCRIPTION @@ -173,6 +175,18 @@ B is unable to update a file with its edited version, the user will receive a warning and the edited copy will remain in a temporary file. +=item -g I + +Normally, B sets the primary group to the one specified by +the passwd database for the user the command is being run as (by +default, root). The B<-g> (I) option causes B to run +the specified command with the primary group set to I. To +specify a I instead of a I, use I<#gid>. When +running commands as a I, many shells require that the '#' be +escaped with a backslash ('\'). If no B<-u> option is specified, +the command will be run as the invoking user (not root). In either +case, the primary group will be set to I. + =item -H The B<-H> (I) option sets the C environment variable @@ -288,7 +302,7 @@ option. The B<-u> (I) option causes B to run the specified command as a user other than I. To specify a I instead -of a I, use I<#uid>. When running commands as a I, +of a I, use I<#uid>. When running commands as a I, many shells require that the '#' be escaped with a backslash ('\'). Note that if the I Defaults option is set (see L) it is not possible to run commands with a uid not listed in the diff --git a/sudo_usage.h.in b/sudo_usage.h.in index b0c5c1eb9..3f1de3407 100644 --- a/sudo_usage.h.in +++ b/sudo_usage.h.in @@ -6,8 +6,8 @@ * need to be able to substitute values from configure. */ #define SUDO_USAGE1 " -h | -K | -k | -L | -V | -v" -#define SUDO_USAGE2 " -l [-U username] [-u username|#uid] [command]" -#define SUDO_USAGE3 " [-bEHPS] @BSDAUTH_USAGE@[-C fd] @LOGINCAP_USAGE@[-p prompt] [-u username|#uid] [VAR=value] {-i | -s | }" -#define SUDO_USAGE4 " -e [-S] @BSDAUTH_USAGE@[-C fd] @LOGINCAP_USAGE@[-p prompt] [-u username|#uid] file ..." +#define SUDO_USAGE2 " -l [-g groupname|#gid] [-U username] [-u username|#uid] [-g groupname|#gid] [command]" +#define SUDO_USAGE3 " [-bEHPS] @BSDAUTH_USAGE@[-C fd] @LOGINCAP_USAGE@[-g groupname|#gid] [-p prompt] [-u username|#uid] [-g groupname|#gid] [VAR=value] {-i | -s | }" +#define SUDO_USAGE4 " -e [-S] @BSDAUTH_USAGE@[-C fd] @LOGINCAP_USAGE@[-g groupname|#gid] [-p prompt] [-u username|#uid] file ..." #endif /* _SUDO_USAGE_H */ diff --git a/sudoers.cat b/sudoers.cat index 14b997af7..3bf1024eb 100644 --- a/sudoers.cat +++ b/sudoers.cat @@ -61,7 +61,7 @@ DDEESSCCRRIIPPTTIIOONN -1.7 September 5, 2007 1 +1.7 November 21, 2007 1 @@ -117,8 +117,8 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) odd number of '!' operators negate the value of the item; an even number just cancel each other out. - Runas_List ::= Runas_User | - Runas_User ',' Runas_List + Runas_List ::= Runas_Member | + Runas_Member ',' Runas_List @@ -127,7 +127,7 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) -1.7 September 5, 2007 2 +1.7 November 21, 2007 2 @@ -136,11 +136,11 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - Runas_User ::= '!'* username | - '!'* '#'uid | - '!'* '%'group | - '!'* +netgroup | - '!'* Runas_Alias + Runas_Member ::= '!'* username | + '!'* '#'uid | + '!'* '%'group | + '!'* +netgroup | + '!'* Runas_Alias A Runas_List is similar to a User_List except that instead of User_Aliases it can contain Runas_Aliases. Note that @@ -193,7 +193,7 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) -1.7 September 5, 2007 3 +1.7 November 21, 2007 3 @@ -259,7 +259,7 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) -1.7 September 5, 2007 4 +1.7 November 21, 2007 4 @@ -288,7 +288,7 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) Cmnd_Spec ::= Runas_Spec? Tag_Spec* Cmnd - Runas_Spec ::= '(' Runas_List ')' + Runas_Spec ::= '(' Runas_List? (: Runas_List)? ')' Tag_Spec ::= ('NOPASSWD:' | 'PASSWD:' | 'NOEXEC:' | 'EXEC:' | 'SETENV:' | 'NOSETENV:' ) @@ -302,12 +302,37 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) RRuunnaass__SSppeecc - A Runas_Spec is simply a Runas_List (as defined above) - enclosed in a set of parentheses. If you do not specify a - Runas_Spec in the user specification, a default Runas_Spec - of rroooott will be used. A Runas_Spec sets the default for - commands that follow it. What this means is that for the - entry: + A Runas_Spec determines the user and/or the group that a + command may be run as. A fully-specified Runas_Spec con- + sists of two Runas_Lists (as defined above) separated by a + colon (':') and enclosed in a set of parentheses. The + first Runas_List indicates which users the command may be + run as via ssuuddoo's --uu flag. The second defines a list of + groups that can be specified via ssuuddoo's --gg flag. If both + Runas_Lists are specified, the command may be run with any + combination of users and groups listed in their respective + Runas_Lists. If only the first is specified, the command + may be run as any user in the list but no --gg flag may be + specified. If the first Runas_List is empty but the sec- + ond is specified, the command may be run as the invoking + user with the group set to any listed in the Runas_List. + If no Runas_Spec is specified the command may be run as + rroooott and no group may be specified. + + A Runas_Spec sets the default for the commands that follow + it. What this means is that for the entry: + + + + +1.7 November 21, 2007 5 + + + + + +SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) + dgb boulder = (operator) /bin/ls, /bin/kill, /usr/bin/lprm @@ -322,19 +347,21 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) dgb boulder = (operator) /bin/ls, (root) /bin/kill, /usr/bin/lprm Then user ddggbb is now allowed to run _/_b_i_n_/_l_s as ooppeerraattoorr, + but _/_b_i_n_/_k_i_l_l and _/_u_s_r_/_b_i_n_/_l_p_r_m as rroooott. + We can extend this to allow ddggbb to run /bin/ls with either + the user or group set to ooppeerraattoorr: + dgb boulder = (operator : operator) /bin/ls, (root) /bin/kill, \ + /usr/bin/lprm -1.7 September 5, 2007 5 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) + In the following example, user ttccmm may run commands that + access a modem device file with the dialer group. Note + that in this example only the group will be set, the com- + mand still runs as user ttccmm. - - but _/_b_i_n_/_k_i_l_l and _/_u_s_r_/_b_i_n_/_l_p_r_m as rroooott. + tcm boulder = (:dialer) /usr/bin/tip, /usr/bin/cu, \ + /usr/local/bin/minicom TTaagg__SSppeecc @@ -362,6 +389,17 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) able to run _/_b_i_n_/_k_i_l_l without a password the entry would be: + + +1.7 November 21, 2007 6 + + + + + +SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) + + ray rushmore = NOPASSWD: /bin/kill, PASSWD: /bin/ls, /usr/bin/lprm Note, however, that the PASSWD tag has no effect on users @@ -388,18 +426,6 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) aaron shanty = NOEXEC: /usr/bin/more, /usr/bin/vi See the "PREVENTING SHELL ESCAPES" section below for more - - - -1.7 September 5, 2007 6 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - details on how NOEXEC works and whether or not it will work on your system. @@ -411,6 +437,9 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) way are not subject to the restrictions imposed by _e_n_v___c_h_e_c_k, _e_n_v___d_e_l_e_t_e, or _e_n_v___k_e_e_p. As such, only trusted users should be allowed to set variables in this manner. + If the command matched is AALLLL, the SETENV tag is implied + for that command; this default may be overridden by use of + the UNSETENV tag. WWiillddccaarrddss @@ -426,6 +455,17 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) [...] Matches any character in the specified range. + + +1.7 November 21, 2007 7 + + + + + +SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) + + [!...] Matches any character nnoott in the specified range. \x For any character "x", evaluates to "x". This is @@ -454,18 +494,6 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) It is possible to include other _s_u_d_o_e_r_s files from within the _s_u_d_o_e_r_s file currently being parsed using the #include directive, similar to the one used by the C preprocessor. - - - -1.7 September 5, 2007 7 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - This is useful, for example, for keeping a site-wide _s_u_d_o_- _e_r_s file in addition to a per-machine local one. For the sake of this example the site-wide _s_u_d_o_e_r_s will be @@ -492,6 +520,18 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) comment character and any text after it, up to the end of the line, are ignored. + + + +1.7 November 21, 2007 8 + + + + + +SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) + + The reserved word AALLLL is a built-in _a_l_i_a_s that always causes a match to succeed. It can be used wherever one might otherwise use a Cmnd_Alias, User_Alias, Runas_Alias, @@ -519,19 +559,6 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) ('\') when used as part of a word (e.g. a username or hostname): '@', '!', '=', ':', ',', '(', ')', '\'. - - - - -1.7 September 5, 2007 8 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - SSUUDDOOEERRSS OOPPTTIIOONNSS ssuuddoo's behavior can be modified by Default_Entry lines, as explained earlier. A list of all supported Defaults @@ -559,6 +586,18 @@ SSUUDDOOEERRSS OOPPTTIIOONNSS at which ssuuddoo begins closing open file descriptors. This flag is _o_f_f by default. + + + +1.7 November 21, 2007 9 + + + + + +SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) + + env_editor If set, vviissuuddoo will use the value of the EDITOR or VISUAL environment variables before falling back on the default editor @@ -586,18 +625,6 @@ SSUUDDOOEERRSS OOPPTTIIOONNSS default. fqdn Set this flag if you want to put fully - - - -1.7 September 5, 2007 9 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - qualified hostnames in the _s_u_d_o_e_r_s file. I.e., instead of myhost you would use myhost.mydomain.edu. You may still use @@ -625,6 +652,18 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) ignore_local_sudoers If set via LDAP, parsing of @sysconfdir@/sudoers will be skipped. + + + +1.7 November 21, 2007 10 + + + + + +SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) + + This is intended for Enterprises that wish to prevent the usage of local sudoers files so that only LDAP is used. This @@ -652,18 +691,6 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) flag is _o_f_f by default. long_otp_prompt When validating with a One Time Password - - - -1.7 September 5, 2007 10 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - (OPT) scheme such as SS//KKeeyy or OOPPIIEE, a two- line prompt is used to make it easier to cut and paste the challenge to a local @@ -692,6 +719,17 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) or is explicitly denied. This flag is _o_f_f by default. + + +1.7 November 21, 2007 11 + + + + + +SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) + + mail_no_user If set, mail will be sent to the _m_a_i_l_t_o user if the invoking user is not in the _s_u_d_o_e_r_s file. This flag is _o_n by default. @@ -718,18 +756,6 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) preserve_groups By default ssuuddoo will initialize the group vector to the list of groups the target - - - -1.7 September 5, 2007 11 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - user is in. When _p_r_e_s_e_r_v_e___g_r_o_u_p_s is set, the user's existing group vector is left unaltered. The real and effective group @@ -758,6 +784,18 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) by default. rootpw If set, ssuuddoo will prompt for the root + + + +1.7 November 21, 2007 12 + + + + + +SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) + + password instead of the password of the invoking user. This flag is _o_f_f by default. @@ -783,21 +821,9 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) since some programs (including the RCS revision control system) use LOGNAME to determine the real identity of the user, - it may be desirable to change this - - - -1.7 September 5, 2007 12 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - - behavior. This can be done by negating - the set_logname option. Note that if the + it may be desirable to change this behav- + ior. This can be done by negating the + set_logname option. Note that if the _e_n_v___r_e_s_e_t option has not been disabled, entries in the _e_n_v___k_e_e_p list will override the value of _s_e_t___l_o_g_n_a_m_e. This flag is @@ -824,6 +850,18 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) stay_setuid Normally, when ssuuddoo executes a command the real and effective UIDs are set to the + + + +1.7 November 21, 2007 13 + + + + + +SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) + + target user (root by default). This option changes that behavior such that the real UID is left as the invoking user's @@ -850,18 +888,6 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) as the user running it. With this flag enabled, ssuuddoo will use a file named for the tty the user is logged in on in that - - - -1.7 September 5, 2007 13 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - directory. This flag is _o_f_f by default. use_loginclass If set, ssuuddoo will apply the defaults spec- @@ -890,6 +916,18 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) log. This value is used to decide when to wrap lines for nicer log files. This has no effect on the syslog log file, only the + + + +1.7 November 21, 2007 14 + + + + + +SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) + + file log. The default is 80 (use 0 or negate the option to disable word wrap). @@ -916,18 +954,6 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) SSttrriinnggss: badpass_message Message that is displayed if a user enters - - - -1.7 September 5, 2007 14 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - an incorrect password. The default is Sorry, try again. unless insults are enabled. @@ -952,10 +978,22 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) _n_o_e_x_e_c functionality on systems that sup- port LD_PRELOAD or its equivalent. Defaults to - _/_u_s_r_/_l_o_c_a_l_/_l_i_b_e_x_e_c_/_s_u_d_o___n_o_e_x_e_c. + _/_u_s_r_/_l_o_c_a_l_/_l_i_b_e_x_e_c_/_s_u_d_o___n_o_e_x_e_c_._s_o. passprompt The default prompt to use when asking for a password; can be overridden via the --pp + + + +1.7 November 21, 2007 15 + + + + + +SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) + + option or the SUDO_PROMPT environment variable. The following percent (`%') escapes are supported: @@ -982,18 +1020,6 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) runas_default The default user to run commands as if the --uu flag is not specified on the command - - - -1.7 September 5, 2007 15 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - line. This defaults to root. Note that if _r_u_n_a_s___d_e_f_a_u_l_t is set it mmuusstt occur before any Runas_Alias specifications. @@ -1023,6 +1049,17 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) be printed along with the password prompt. It has the following possible values: + + +1.7 November 21, 2007 16 + + + + + +SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) + + always Always lecture the user. never Never lecture the user. @@ -1049,17 +1086,6 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) current host must have the NOPASSWD flag set to avoid entering a password. - - -1.7 September 5, 2007 16 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - always The user must always enter a password to use the --ll flag. @@ -1088,6 +1114,18 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) mail. Defaults to the path to sendmail found at configure time. + + + +1.7 November 21, 2007 17 + + + + + +SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) + + mailto Address to send warning and error mail to. The address should be enclosed in double quotes (") to protect against ssuuddoo interpret- @@ -1114,18 +1152,6 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) current host must have the NOPASSWD flag set to avoid entering a password. - - - -1.7 September 5, 2007 17 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - always The user must always enter a password to use the --vv flag. @@ -1154,6 +1180,18 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) gle value without double-quotes. The list can be replaced, added to, deleted from, or disabled by using the =, +=, -=, and ! + + + +1.7 November 21, 2007 18 + + + + + +SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) + + operators respectively. Regardless of whether the env_reset option is enabled or disabled, variables specified by env_check @@ -1180,18 +1218,6 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) env_keep Environment variables to be preserved in the user's environment when the _e_n_v___r_e_s_e_t option is in effect. This allows fine- - - - -1.7 September 5, 2007 18 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - grained control over the environment ssuuddoo-spawned processes will receive. The argument may be a double-quoted, space- @@ -1220,6 +1246,18 @@ EEXXAAMMPPLLEESS Below are example _s_u_d_o_e_r_s entries. Admittedly, some of these are a bit contrived. First, we define our _a_l_i_a_s_e_s: + + + +1.7 November 21, 2007 19 + + + + + +SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) + + # User alias specification User_Alias FULLTIMERS = millert, mikef, dowdy User_Alias PARTTIMERS = bostley, jwfox, crawl @@ -1239,25 +1277,6 @@ EEXXAAMMPPLLEESS Host_Alias SERVERS = master, mail, www, ns Host_Alias CDROM = orion, perseus, hercules - - - - - - - - - - -1.7 September 5, 2007 19 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - # Cmnd alias specification Cmnd_Alias DUMPS = /usr/bin/mt, /usr/sbin/dump, /usr/sbin/rdump,\ /usr/sbin/restore, /usr/sbin/rrestore @@ -1293,6 +1312,18 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) Defaults@SERVERS log_year, logfile=/var/log/sudo.log Defaults!PAGERS noexec + + + +1.7 November 21, 2007 20 + + + + + +SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) + + The _U_s_e_r _s_p_e_c_i_f_i_c_a_t_i_o_n is the part that actually deter- mines who may run what. @@ -1313,17 +1344,6 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) any command on any host but they must authenticate them- selves first (since the entry lacks the NOPASSWD tag). - - -1.7 September 5, 2007 20 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - jack CSNETS = ALL The user jjaacckk may run any command on the machines in the @@ -1359,6 +1379,17 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) bob SPARC = (OP) ALL : SGI = (OP) ALL + + +1.7 November 21, 2007 21 + + + + + +SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) + + The user bboobb may run anything on the _S_P_A_R_C and _S_G_I machines as any user listed in the _O_P Runas_Alias (rroooott and ooppeerraattoorr). @@ -1378,18 +1409,6 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) fred ALL = (DB) NOPASSWD: ALL The user ffrreedd can run commands as any user in the _D_B - - - -1.7 September 5, 2007 21 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - Runas_Alias (oorraaccllee or ssyybbaassee) without giving a password. john ALPHA = /usr/bin/su [!-]*, !/usr/bin/su *root* @@ -1425,6 +1444,18 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) (will, wendy, and wim), may run any command as user www (which owns the web pages) or simply _s_u(1) to www. + + + +1.7 November 21, 2007 22 + + + + + +SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) + + ALL CDROM = NOPASSWD: /sbin/umount /CDROM,\ /sbin/mount -o nosuid\,nodev /dev/cd0a /CDROM @@ -1443,21 +1474,9 @@ SSEECCUURRIITTYY NNOOTTEESS bill ALL = ALL, !SU, !SHELLS Doesn't really prevent bbiillll from running the commands - listed in _S_U or _S_H_E_L_L_S since he can simply copy those - - - -1.7 September 5, 2007 22 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - - commands to a different name, or use a shell escape from - an editor or other program. Therefore, these kind of + listed in _S_U or _S_H_E_L_L_S since he can simply copy those com- + mands to a different name, or use a shell escape from an + editor or other program. Therefore, these kind of restrictions should be considered advisory at best (and reinforced by policy). @@ -1491,6 +1510,18 @@ PPRREEVVEENNTTIINNGG SSHHEELLLL EESSCCAAPPEESS that this applies only to native dynamically- linked executables. Statically-linked executa- bles and foreign executables running under + + + +1.7 November 21, 2007 23 + + + + + +SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) + + binary emulation are not affected. To tell whether or not ssuuddoo supports _n_o_e_x_e_c, you @@ -1510,18 +1541,6 @@ PPRREEVVEENNTTIINNGG SSHHEELLLL EESSCCAAPPEESS _n_o_e_x_e_c will work at compile-time. _n_o_e_x_e_c should work on SunOS, Solaris, *BSD, Linux, IRIX, Tru64 UNIX, MacOS X, and HP-UX 11.x. It is known nnoott - - - -1.7 September 5, 2007 23 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - to work on AIX and UnixWare. _n_o_e_x_e_c is expected to work on most operating systems that support the LD_PRELOAD environment variable. Check your @@ -1556,8 +1575,20 @@ SSEEEE AALLSSOO CCAAVVEEAATTSS The _s_u_d_o_e_r_s file should aallwwaayyss be edited by the vviissuuddoo - command which locks the file and does grammatical check- - ing. It is imperative that _s_u_d_o_e_r_s be free of syntax + command which locks the file and does grammatical + + + +1.7 November 21, 2007 24 + + + + + +SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) + + + checking. It is imperative that _s_u_d_o_e_r_s be free of syntax errors since ssuuddoo will not run with a syntactically incor- rect _s_u_d_o_e_r_s file. @@ -1577,17 +1608,6 @@ SSUUPPPPOORRTT man/listinfo/sudo-users to subscribe or search the archives. - - -1.7 September 5, 2007 24 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - DDIISSCCLLAAIIMMEERR ssuuddoo is provided ``AS IS'' and any express or implied war- ranties, including, but not limited to, the implied war- @@ -1625,26 +1645,6 @@ DDIISSCCLLAAIIMMEERR - - - - - - - - - - - - - - - - - - - - -1.7 September 5, 2007 25 +1.7 November 21, 2007 25 diff --git a/sudoers.man.in b/sudoers.man.in index 09d7e01ad..cba921204 100644 --- a/sudoers.man.in +++ b/sudoers.man.in @@ -150,7 +150,7 @@ .\" ======================================================================== .\" .IX Title "SUDOERS @mansectform@" -.TH SUDOERS @mansectform@ "September 5, 2007" "1.7" "MAINTENANCE COMMANDS" +.TH SUDOERS @mansectform@ "November 21, 2007" "1.7" "MAINTENANCE COMMANDS" .SH "NAME" sudoers \- list of which users may execute what .SH "DESCRIPTION" @@ -269,16 +269,16 @@ zero or more '!' operators. An odd number of '!' operators negate the value of the item; an even number just cancel each other out. .PP .Vb 2 -\& Runas_List ::= Runas_User | -\& Runas_User ',' Runas_List +\& Runas_List ::= Runas_Member | +\& Runas_Member ',' Runas_List .Ve .PP .Vb 5 -\& Runas_User ::= '!'* username | -\& '!'* '#'uid | -\& '!'* '%'group | -\& '!'* +netgroup | -\& '!'* Runas_Alias +\& Runas_Member ::= '!'* username | +\& '!'* '#'uid | +\& '!'* '%'group | +\& '!'* +netgroup | +\& '!'* Runas_Alias .Ve .PP A \f(CW\*(C`Runas_List\*(C'\fR is similar to a \f(CW\*(C`User_List\*(C'\fR except that instead @@ -417,7 +417,7 @@ See \*(L"\s-1SUDOERS\s0 \s-1OPTIONS\s0\*(R" for a list of supported Defaults par .Ve .PP .Vb 1 -\& Runas_Spec ::= '(' Runas_List ')' +\& Runas_Spec ::= '(' Runas_List? (: Runas_List)? ')' .Ve .PP .Vb 2 @@ -432,11 +432,24 @@ run as \fBroot\fR, but this can be changed on a per-command basis. Let's break that down into its constituent parts: .Sh "Runas_Spec" .IX Subsection "Runas_Spec" -A \f(CW\*(C`Runas_Spec\*(C'\fR is simply a \f(CW\*(C`Runas_List\*(C'\fR (as defined above) -enclosed in a set of parentheses. If you do not specify a -\&\f(CW\*(C`Runas_Spec\*(C'\fR in the user specification, a default \f(CW\*(C`Runas_Spec\*(C'\fR -of \fBroot\fR will be used. A \f(CW\*(C`Runas_Spec\*(C'\fR sets the default for -commands that follow it. What this means is that for the entry: +A \f(CW\*(C`Runas_Spec\*(C'\fR determines the user and/or the group that a command +may be run as. A fully-specified \f(CW\*(C`Runas_Spec\*(C'\fR consists of two +\&\f(CW\*(C`Runas_List\*(C'\fRs (as defined above) separated by a colon (':') and +enclosed in a set of parentheses. The first \f(CW\*(C`Runas_List\*(C'\fR indicates +which users the command may be run as via \fBsudo\fR's \fB\-u\fR flag. +The second defines a list of groups that can be specified via +\&\fBsudo\fR's \fB\-g\fR flag. If both \f(CW\*(C`Runas_List\*(C'\fRs are specified, the +command may be run with any combination of users and groups listed +in their respective \f(CW\*(C`Runas_List\*(C'\fRs. If only the first is specified, +the command may be run as any user in the list but no \fB\-g\fR flag +may be specified. If the first \f(CW\*(C`Runas_List\*(C'\fR is empty but the +second is specified, the command may be run as the invoking user +with the group set to any listed in the \f(CW\*(C`Runas_List\*(C'\fR. If no +\&\f(CW\*(C`Runas_Spec\*(C'\fR is specified the command may be run as \fBroot\fR and +no group may be specified. +.PP +A \f(CW\*(C`Runas_Spec\*(C'\fR sets the default for the commands that follow it. +What this means is that for the entry: .PP .Vb 1 \& dgb boulder = (operator) /bin/ls, /bin/kill, /usr/bin/lprm @@ -458,6 +471,23 @@ entry. If we modify the entry like so: .PP Then user \fBdgb\fR is now allowed to run \fI/bin/ls\fR as \fBoperator\fR, but \fI/bin/kill\fR and \fI/usr/bin/lprm\fR as \fBroot\fR. +.PP +We can extend this to allow \fBdgb\fR to run \f(CW\*(C`/bin/ls\*(C'\fR with either +the user or group set to \fBoperator\fR: +.PP +.Vb 2 +\& dgb boulder = (operator : operator) /bin/ls, (root) /bin/kill, \e +\& /usr/bin/lprm +.Ve +.PP +In the following example, user \fBtcm\fR may run commands that access +a modem device file with the dialer group. Note that in this example +only the group will be set, the command still runs as user \fBtcm\fR. +.PP +.Vb 2 +\& tcm boulder = (:dialer) /usr/bin/tip, /usr/bin/cu, \e +\& /usr/local/bin/minicom +.Ve .Sh "Tag_Spec" .IX Subsection "Tag_Spec" A command may have zero or more tags associated with it. There are @@ -526,7 +556,9 @@ basis. Note that if \f(CW\*(C`SETENV\*(C'\fR has been set for a command, any environment variables set on the command line way are not subject to the restrictions imposed by \fIenv_check\fR, \fIenv_delete\fR, or \&\fIenv_keep\fR. As such, only trusted users should be allowed to set -variables in this manner. +variables in this manner. If the command matched is \fB\s-1ALL\s0\fR, the +\&\f(CW\*(C`SETENV\*(C'\fR tag is implied for that command; this default may +be overridden by use of the \f(CW\*(C`UNSETENV\*(C'\fR tag. .Sh "Wildcards" .IX Subsection "Wildcards" \&\fBsudo\fR allows shell-style \fIwildcards\fR (aka meta or glob characters) diff --git a/sudoers.pod b/sudoers.pod index 4193d922b..918fde1b5 100644 --- a/sudoers.pod +++ b/sudoers.pod @@ -125,14 +125,14 @@ with '+') and Ces. Each list item may be prefixed with zero or more '!' operators. An odd number of '!' operators negate the value of the item; an even number just cancel each other out. - Runas_List ::= Runas_User | - Runas_User ',' Runas_List + Runas_List ::= Runas_Member | + Runas_Member ',' Runas_List - Runas_User ::= '!'* username | - '!'* '#'uid | - '!'* '%'group | - '!'* +netgroup | - '!'* Runas_Alias + Runas_Member ::= '!'* username | + '!'* '#'uid | + '!'* '%'group | + '!'* +netgroup | + '!'* Runas_Alias A C is similar to a C except that instead of Ces it can contain Ces. Note that @@ -247,7 +247,7 @@ See L for a list of supported Defaults parameters. Cmnd_Spec ::= Runas_Spec? Tag_Spec* Cmnd - Runas_Spec ::= '(' Runas_List ')' + Runas_Spec ::= '(' Runas_List? (: Runas_List)? ')' Tag_Spec ::= ('NOPASSWD:' | 'PASSWD:' | 'NOEXEC:' | 'EXEC:' | 'SETENV:' | 'NOSETENV:' ) @@ -260,11 +260,24 @@ Let's break that down into its constituent parts: =head2 Runas_Spec -A C is simply a C (as defined above) -enclosed in a set of parentheses. If you do not specify a -C in the user specification, a default C -of B will be used. A C sets the default for -commands that follow it. What this means is that for the entry: +A C determines the user and/or the group that a command +may be run as. A fully-specified C consists of two +Cs (as defined above) separated by a colon (':') and +enclosed in a set of parentheses. The first C indicates +which users the command may be run as via B's B<-u> flag. +The second defines a list of groups that can be specified via +B's B<-g> flag. If both Cs are specified, the +command may be run with any combination of users and groups listed +in their respective Cs. If only the first is specified, +the command may be run as any user in the list but no B<-g> flag +may be specified. If the first C is empty but the +second is specified, the command may be run as the invoking user +with the group set to any listed in the C. If no +C is specified the command may be run as B and +no group may be specified. + +A C sets the default for the commands that follow it. +What this means is that for the entry: dgb boulder = (operator) /bin/ls, /bin/kill, /usr/bin/lprm @@ -281,6 +294,19 @@ entry. If we modify the entry like so: Then user B is now allowed to run F as B, but F and F as B. +We can extend this to allow B to run C with either +the user or group set to B: + + dgb boulder = (operator : operator) /bin/ls, (root) /bin/kill, \ + /usr/bin/lprm + +In the following example, user B may run commands that access +a modem device file with the dialer group. Note that in this example +only the group will be set, the command still runs as user B. + + tcm boulder = (:dialer) /usr/bin/tip, /usr/bin/cu, \ + /usr/local/bin/minicom + =head2 Tag_Spec A command may have zero or more tags associated with it. There are diff --git a/testsudoers.c b/testsudoers.c index b7016968c..91118a4ed 100644 --- a/testsudoers.c +++ b/testsudoers.c @@ -127,7 +127,7 @@ main(argc, argv) struct cmndspec *cs; struct privilege *priv; struct userspec *us; - char *p, *grfile, *pwfile, *uflag, hbuf[MAXHOSTNAMELEN]; + char *p, *grfile, *pwfile, *runas_user, hbuf[MAXHOSTNAMELEN]; int ch, dflag, rval, matched; #ifdef YYDEBUG extern int yydebug; @@ -138,7 +138,7 @@ main(argc, argv) Argc = argc; dflag = 0; - grfile = pwfile = uflag = NULL; + grfile = pwfile = runas_user = NULL; while ((ch = getopt(argc, argv, "dg:h:p:u:")) != -1) { switch (ch) { case 'd': @@ -154,8 +154,7 @@ main(argc, argv) pwfile = optarg; break; case 'u': - uflag = optarg; - user_runas = &uflag; + runas_user = optarg; break; default: usage(); @@ -235,12 +234,12 @@ main(argc, argv) /* Initialize default values. */ init_defaults(); - if (**user_runas == '#') { - if ((runas_pw = sudo_getpwuid(atoi(*user_runas + 1))) == NULL) - runas_pw = sudo_fakepwnam(*user_runas); + if (*runas_user == '#') { + if ((runas_pw = sudo_getpwuid(atoi(runas_user + 1))) == NULL) + runas_pw = sudo_fakepwnam(runas_user); } else { - if ((runas_pw = sudo_getpwnam(*user_runas)) == NULL) - errorx(1, "no passwd entry for %s!", *user_runas); + if ((runas_pw = sudo_getpwnam(runas_user)) == NULL) + errorx(1, "no passwd entry for %s!", runas_user); } /* Load ip addr/mask for each interface. */ @@ -278,7 +277,8 @@ main(argc, argv) if (hostlist_matches(&priv->hostlist) == ALLOW) { puts("\thost matched"); tq_foreach_rev(&priv->cmndlist, cs) { - if (runaslist_matches(&cs->runaslist) == ALLOW) { + if (runaslist_matches(&cs->runasuserlist, + &cs->runasgrouplist) == ALLOW) { puts("\trunas matched"); rval = cmnd_matches(cs->cmnd); if (rval != UNSPEC) @@ -472,10 +472,11 @@ print_privilege(priv) tq_foreach_fwd(&p->cmndlist, cs) { if (cs != tq_first(&p->cmndlist)) fputs(", ", stdout); - if (!tq_empty(&cs->runaslist)) { + /* XXX - runasgrouplist too */ + if (!tq_empty(&cs->runasuserlist)) { fputs("(", stdout); - tq_foreach_fwd(&cs->runaslist, m) { - if (m != tq_first(&cs->runaslist)) + tq_foreach_fwd(&cs->runasuserlist, m) { + if (m != tq_first(&cs->runasuserlist)) fputs(", ", stdout); print_member(m); } diff --git a/visudo.c b/visudo.c index d67a4aec9..f6e3e7bad 100644 --- a/visudo.c +++ b/visudo.c @@ -412,7 +412,6 @@ reparse_sudoers(editor, args, strict, quiet) sp->tpath, sp->path); /* Clean slate for each parse */ - user_runas = NULL; init_defaults(); init_parser(sp->path, quiet); @@ -929,7 +928,7 @@ check_aliases(strict) } } tq_foreach_fwd(&priv->cmndlist, cs) { - tq_foreach_fwd(&cs->runaslist, m) { + tq_foreach_fwd(&cs->runasuserlist, m) { if (m->type == RUNASALIAS) { if (find_alias(m->name, m->type) == NULL) { fprintf(stderr, @@ -963,7 +962,7 @@ check_aliases(strict) (void) alias_remove(m->name, m->type); } tq_foreach_fwd(&priv->cmndlist, cs) { - tq_foreach_fwd(&cs->runaslist, m) { + tq_foreach_fwd(&cs->runasuserlist, m) { if (m->type == RUNASALIAS) (void) alias_remove(m->name, m->type); } diff --git a/visudo.cat b/visudo.cat index 62ae4fab5..2035e7aaa 100644 --- a/visudo.cat +++ b/visudo.cat @@ -50,18 +50,18 @@ DDEESSCCRRIIPPTTIIOONN OOPPTTIIOONNSS vviissuuddoo accepts the following command line options: - -c Enable cchheecckk--oonnllyy mode. The existing _s_u_d_o_e_r_s file - will be checked for syntax and a message will be - printed to the standard output detailing the status of - _s_u_d_o_e_r_s. If the syntax check completes successfully, - vviissuuddoo will exit with a value of 0. If a syntax error - is encountered, vviissuuddoo will exit with a value of 1. + -c Enable cchheecckk--oonnllyy mode. The existing _s_u_d_o_e_r_s + file will be checked for syntax and a message + will be printed to the standard output detail- + ing the status of _s_u_d_o_e_r_s. If the syntax + check completes successfully, vviissuuddoo will exit + with a value of 0. If a syntax error is + encountered, vviissuuddoo will exit with a value of + 1. - -f Specify and alternate _s_u_d_o_e_r_s file location. With - -1.7 August 15, 2007 1 +1.7 October 20, 2007 1 @@ -70,28 +70,32 @@ OOPPTTIIOONNSS VISUDO(1m) MAINTENANCE COMMANDS VISUDO(1m) - this option vviissuuddoo will edit (or check) the _s_u_d_o_e_r_s - file of your choice, instead of the default, - _/_e_t_c_/_s_u_d_o_e_r_s. The lock file used is the specified - _s_u_d_o_e_r_s file with ".tmp" appended to it. + -f _s_u_d_o_e_r_s Specify and alternate _s_u_d_o_e_r_s file location. + With this option vviissuuddoo will edit (or check) + the _s_u_d_o_e_r_s file of your choice, instead of + the default, _/_e_t_c_/_s_u_d_o_e_r_s. The lock file used + is the specified _s_u_d_o_e_r_s file with ".tmp" + appended to it. - -q Enable qquuiieett mode. In this mode details about syntax - errors are not printed. This option is only useful - when combined with the --cc flag. + -q Enable qquuiieett mode. In this mode details about + syntax errors are not printed. This option is + only useful when combined with the --cc flag. - -s Enable ssttrriicctt checking of the _s_u_d_o_e_r_s file. If an - alias is used before it is defined, vviissuuddoo will con- - sider this a parse error. Note that it is not possi- - ble to differentiate between an alias and a hostname - or username that consists solely of uppercase letters, - digits, and the underscore ('_') character. + -s Enable ssttrriicctt checking of the _s_u_d_o_e_r_s file. + If an alias is used before it is defined, + vviissuuddoo will consider this a parse error. Note + that it is not possible to differentiate + between an alias and a hostname or username + that consists solely of uppercase letters, + digits, and the underscore ('_') character. - -V The --VV (version) option causes vviissuuddoo to print its - version number and exit. + -V The --VV (version) option causes vviissuuddoo to print + its version number and exit. EENNVVIIRROONNMMEENNTT - The following environment variables are used only if - vviissuuddoo was configured with the _-_-_w_i_t_h_-_e_n_v_-_e_d_i_t_o_r option: + The following environment variables may be consulted + depending on the value of the _e_d_i_t_o_r and _e_n_v___e_d_i_t_o_r _s_u_d_o_- + _e_r_s variables: VISUAL Invoked by visudo as the editor to use @@ -121,13 +125,9 @@ DDIIAAGGNNOOSSTTIICCSS will not complain). In --ss (strict) mode these are errors, not warnings. - Warning: unused {User,Runas,Host,Cmnd}_Alias - The specified {User,Runas,Host,Cmnd}_Alias was defined - but never used. You may wish to comment out or remove - -1.7 August 15, 2007 2 +1.7 October 20, 2007 2 @@ -136,6 +136,9 @@ DDIIAAGGNNOOSSTTIICCSS VISUDO(1m) MAINTENANCE COMMANDS VISUDO(1m) + Warning: unused {User,Runas,Host,Cmnd}_Alias + The specified {User,Runas,Host,Cmnd}_Alias was defined + but never used. You may wish to comment out or remove the unused alias. In --ss (strict) mode this is an error, not a warning. @@ -190,9 +193,6 @@ DDIISSCCLLAAIIMMEERR - - - -1.7 August 15, 2007 3 +1.7 October 20, 2007 3 diff --git a/visudo.man.in b/visudo.man.in index 28d88988a..cb32f061f 100644 --- a/visudo.man.in +++ b/visudo.man.in @@ -149,7 +149,7 @@ .\" ======================================================================== .\" .IX Title "VISUDO @mansectsu@" -.TH VISUDO @mansectsu@ "August 15, 2007" "1.7" "MAINTENANCE COMMANDS" +.TH VISUDO @mansectsu@ "October 20, 2007" "1.7" "MAINTENANCE COMMANDS" .SH "NAME" visudo \- edit the sudoers file .SH "SYNOPSIS" @@ -191,7 +191,7 @@ error occurred (if the editor supports this feature). .SH "OPTIONS" .IX Header "OPTIONS" \&\fBvisudo\fR accepts the following command line options: -.IP "\-c" 4 +.IP "\-c" 12 .IX Item "-c" Enable \fBcheck-only\fR mode. The existing \fIsudoers\fR file will be checked for syntax and a message will be printed to the @@ -199,32 +199,32 @@ standard output detailing the status of \fIsudoers\fR. If the syntax check completes successfully, \fBvisudo\fR will exit with a value of 0. If a syntax error is encountered, \&\fBvisudo\fR will exit with a value of 1. -.IP "\-f" 4 -.IX Item "-f" +.IP "\-f \fIsudoers\fR" 12 +.IX Item "-f sudoers" Specify and alternate \fIsudoers\fR file location. With this option \&\fBvisudo\fR will edit (or check) the \fIsudoers\fR file of your choice, instead of the default, \fI@sysconfdir@/sudoers\fR. The lock file used is the specified \fIsudoers\fR file with \*(L".tmp\*(R" appended to it. -.IP "\-q" 4 +.IP "\-q" 12 .IX Item "-q" Enable \fBquiet\fR mode. In this mode details about syntax errors are not printed. This option is only useful when combined with the \fB\-c\fR flag. -.IP "\-s" 4 +.IP "\-s" 12 .IX Item "-s" Enable \fBstrict\fR checking of the \fIsudoers\fR file. If an alias is used before it is defined, \fBvisudo\fR will consider this a parse error. Note that it is not possible to differentiate between an alias and a hostname or username that consists solely of uppercase letters, digits, and the underscore ('_') character. -.IP "\-V" 4 +.IP "\-V" 12 .IX Item "-V" The \fB\-V\fR (version) option causes \fBvisudo\fR to print its version number and exit. .SH "ENVIRONMENT" .IX Header "ENVIRONMENT" -The following environment variables are used only if \fBvisudo\fR -was configured with the \fI\-\-with\-env\-editor\fR option: +The following environment variables may be consulted depending on +the value of the \fIeditor\fR and \fIenv_editor\fR \fIsudoers\fR variables: .ie n .IP "\*(C`VISUAL\*(C'" 16 .el .IP "\f(CW\*(C`VISUAL\*(C'\fR" 16 .IX Item "VISUAL" -- 2.40.0