Add support for runas groups. This allows the user to run a command
authorTodd C. Miller <Todd.Miller@courtesan.com>
Wed, 21 Nov 2007 20:12:00 +0000 (20:12 +0000)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Wed, 21 Nov 2007 20:12:00 +0000 (20:12 +0000)
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

28 files changed:
WHATSNEW
check.c
def_data.in
defaults.c
gram.c
gram.h
gram.y
ldap.c
logging.c
match.c
mon_systrace.c
parse.c
parse.h
pwutil.c
set_perms.c
sudo.c
sudo.cat
sudo.h
sudo.man.in
sudo.pod
sudo_usage.h.in
sudoers.cat
sudoers.man.in
sudoers.pod
testsudoers.c
visudo.c
visudo.cat
visudo.man.in

index 7b2464cb68da17ef8879a0054049347073788eed..45c91131867c1e21f00a3b2a08682ac22b830e95 100644 (file)
--- 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 a0e410957722fa03c561d2f9bf493785be2522b4..d4f0860930b0cc2ff293ceed1d0288eb1b3d84f1 100644 (file)
--- 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
index 9a79d33bbbf680680063c99d80c8c322c7d5c1f1..c03a0f03488d5ac991737d5e856d9e76cb4a55b9 100644 (file)
@@ -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"
index fc630cb82f3ec221c86b91209cda86031bb93fad..a0d702ac1e021beaa64f662b7b16dd7f2a30c333 100644 (file)
@@ -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 1a0bb868e3748ec77fe09c4c198437b781f17d6c..a35796011981d3d76c27ad1cae559df55fe4b625 100644 (file)
--- 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 <Todd.Miller@courtesan.com>
@@ -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 6e709dfc337204f43c15d63ddae198d2db79dc67..d4aaf6d5ca0b12316fbc4b6faacff8e7721a3c98 100644 (file)
--- 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 eb53edf46838f4c32bac477b2e687ceafafc1d51..706e1a6610f5f61ab379499cd123bf0b89be8672 100644 (file)
--- 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 <member>   host
 %type <member>   hostlist
 %type <member>   ophost
-%type <member>   oprunasuser
 %type <member>   opuser
-%type <member>   runaslist
-%type <member>   runasspec
-%type <member>   runasuser
 %type <member>   user
 %type <member>   userlist
+%type <member>   opgroup
+%type <member>   group
+%type <member>   grouplist
+%type <runas>    runasspec
+%type <runas>    runaslist
 %type <privilege> privilege
 %type <privilege> privileges
 %type <tag>      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 9ebb998ab931f5c671ff0d77ab439c4854f5e93e..d3fd7bd572fa1b8b67842aec46601236597d7529 100644 (file)
--- 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");
 
index d901bc8dc88dbae25370bd1aace4fb9fa05ace4b..bce2d2a299ed21e4d76897ea44e67e0f9c2ce856 100644 (file)
--- 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 448761b100eba7f8c579cab794a4d6373267fa97..50115a7844482eaacfa5137eb52be2fc5fd72dc0 100644 (file)
--- 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.
index f6fbcfe013aedcb0b258d99752b63a5420695e21..26be1391399f6db8c955f131ed7eb0d79bd7a8d3 100644 (file)
@@ -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 da561121f6b34f920ea64f966bd771195283aa21..d2f55c4755a7c14720427669cab72164762eaeab 100644 (file)
--- 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 b1958d557a318cee6f0879352ee0d82d2b8a2008..ab20de4bbecdcc7a45e0ee52d038b7ea72eb85f6 100644 (file)
--- 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));
index 5c02a44b192480da12d6ec6941e486953ae88faf..1b0224b7db27274dc823c785a320b7156758b26c 100644 (file)
--- 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()
 {
index 3034889ef82d7287fdadf424c09f31c2e789e8fc..6548f6dd9aba422f50d2c1f8ac2a88fac0191fde 100644 (file)
@@ -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 e7bcd9c2d8b3d7dd7bd9fe491605ff2e7a8f8f11..0b3ce032a17d5b3f8fda2558a2becee2002ccab3 100644 (file)
--- 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
index cf188abbda6e6bb7776c03f0621e754da17a8172..00f026b67d998c5d4c6d0f8fff9a8aff91499860 100644 (file)
--- a/sudo.cat
+++ b/sudo.cat
@@ -10,14 +10,16 @@ N\bNA\bAM\bME\bE
 S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS
        s\bsu\bud\bdo\bo -\b-h\bh | -\b-K\bK | -\b-k\bk | -\b-L\bL | -\b-V\bV | -\b-v\bv
 
-       s\bsu\bud\bdo\bo -\b-l\bl [-\b-U\bU _\bu_\bs_\be_\br_\bn_\ba_\bm_\be] [-\b-u\bu _\bu_\bs_\be_\br_\bn_\ba_\bm_\be|_\b#_\bu_\bi_\bd] [_\bc_\bo_\bm_\bm_\ba_\bn_\bd]
+       s\bsu\bud\bdo\bo -\b-l\bl [-\b-g\bg _\bg_\br_\bo_\bu_\bp_\bn_\ba_\bm_\be|_\b#_\bg_\bi_\bd] [-\b-U\bU _\bu_\bs_\be_\br_\bn_\ba_\bm_\be] [-\b-u\bu _\bu_\bs_\be_\br_\b-
+       _\bn_\ba_\bm_\be|_\b#_\bu_\bi_\bd] [_\bc_\bo_\bm_\bm_\ba_\bn_\bd]
 
        s\bsu\bud\bdo\bo [-\b-b\bbE\bEH\bHP\bPS\bS] [-\b-a\ba _\ba_\bu_\bt_\bh_\b__\bt_\by_\bp_\be] [-\b-C\bC _\bf_\bd] [-\b-c\bc _\bc_\bl_\ba_\bs_\bs|_\b-]
-       [-\b-p\bp _\bp_\br_\bo_\bm_\bp_\bt] [-\b-u\bu _\bu_\bs_\be_\br_\bn_\ba_\bm_\be|_\b#_\bu_\bi_\bd] [V\bVA\bAR\bR=_\bv_\ba_\bl_\bu_\be] {-\b-i\bi | -\b-s\bs | _\bc_\bo_\bm_\b-
-       _\bm_\ba_\bn_\bd}
+       [-\b-g\bg _\bg_\br_\bo_\bu_\bp_\bn_\ba_\bm_\be|_\b#_\bg_\bi_\bd] [-\b-p\bp _\bp_\br_\bo_\bm_\bp_\bt] [-\b-u\bu _\bu_\bs_\be_\br_\bn_\ba_\bm_\be|_\b#_\bu_\bi_\bd]
+       [V\bVA\bAR\bR=_\bv_\ba_\bl_\bu_\be] {-\b-i\bi | -\b-s\bs | _\bc_\bo_\bm_\bm_\ba_\bn_\bd}
 
        s\bsu\bud\bdo\boe\bed\bdi\bit\bt [-\b-S\bS] [-\b-a\ba _\ba_\bu_\bt_\bh_\b__\bt_\by_\bp_\be] [-\b-C\bC _\bf_\bd] [-\b-c\bc _\bc_\bl_\ba_\bs_\bs|_\b-]
-       [-\b-p\bp _\bp_\br_\bo_\bm_\bp_\bt] [-\b-u\bu _\bu_\bs_\be_\br_\bn_\ba_\bm_\be|_\b#_\bu_\bi_\bd] file ...
+       [-\b-g\bg _\bg_\br_\bo_\bu_\bp_\bn_\ba_\bm_\be|_\b#_\bg_\bi_\bd] [-\b-p\bp _\bp_\br_\bo_\bm_\bp_\bt] [-\b-u\bu _\bu_\bs_\be_\br_\bn_\ba_\bm_\be|_\b#_\bu_\bi_\bd] file
+       ...
 
 D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
        s\bsu\bud\bdo\bo allows a permitted user to execute a _\bc_\bo_\bm_\bm_\ba_\bn_\bd as the
@@ -55,13 +57,11 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
 
        If s\bsu\bud\bdo\bo is run by root and the SUDO_USER environment vari-
        able is set, s\bsu\bud\bdo\bo 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 -\b-e\be 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 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
 SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
 
 
+       commands through sudo even when a root shell has been
+       invoked.  It also allows the -\b-e\be 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)
 O\bOP\bPT\bTI\bIO\bON\bNS\bS
        s\bsu\bud\bdo\bo accepts the following command line options:
 
-       -a  The -\b-a\ba (_\ba_\bu_\bt_\bh_\be_\bn_\bt_\bi_\bc_\ba_\bt_\bi_\bo_\bn _\bt_\by_\bp_\be) option causes s\bsu\bud\bdo\bo to use
-           the specified authentication type when validating the
-           user, as allowed by _\b/_\be_\bt_\bc_\b/_\bl_\bo_\bg_\bi_\bn_\b._\bc_\bo_\bn_\bf.  The system
-           administrator may specify a list of sudo-specific
-           authentication methods by adding an "auth-sudo" entry
-           in _\b/_\be_\bt_\bc_\b/_\bl_\bo_\bg_\bi_\bn_\b._\bc_\bo_\bn_\bf.  This option is only available on
-           systems that support BSD authentication.
+       -a _\bt_\by_\bp_\be     The -\b-a\ba (_\ba_\bu_\bt_\bh_\be_\bn_\bt_\bi_\bc_\ba_\bt_\bi_\bo_\bn _\bt_\by_\bp_\be) option causes
+                   s\bsu\bud\bdo\bo to use the specified authentication type
+                   when validating the user, as allowed by
+                   _\b/_\be_\bt_\bc_\b/_\bl_\bo_\bg_\bi_\bn_\b._\bc_\bo_\bn_\bf.  The system administrator may
+                   specify a list of sudo-specific authentication
+                   methods by adding an "auth-sudo" entry in
+                   _\b/_\be_\bt_\bc_\b/_\bl_\bo_\bg_\bi_\bn_\b._\bc_\bo_\bn_\bf.  This option is only avail-
+                   able on systems that support BSD authentica-
+                   tion.
 
-       -b  The -\b-b\bb (_\bb_\ba_\bc_\bk_\bg_\br_\bo_\bu_\bn_\bd) option tells s\bsu\bud\bdo\bo to run the given
-           command in the background.  Note that if you use the
-           -\b-b\bb option you cannot use shell job control to manipu-
-           late the process.
+       -b          The -\b-b\bb (_\bb_\ba_\bc_\bk_\bg_\br_\bo_\bu_\bn_\bd) option tells s\bsu\bud\bdo\bo to run
+                   the given command in the background.  Note
+                   that if you use the -\b-b\bb option you cannot use
+                   shell job control to manipulate the process.
 
-       -C fd
-           Normally, s\bsu\bud\bdo\bo will close all open file descriptors
-           other than standard input, standard output and stan-
-           dard error.  The -\b-C\bC (_\bc_\bl_\bo_\bs_\be _\bf_\br_\bo_\bm) 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 _\bc_\bl_\bo_\bs_\be_\bf_\br_\bo_\bm_\b__\bo_\bv_\be_\br_\br_\bi_\bd_\be
-           option in _\bs_\bu_\bd_\bo_\be_\br_\bs(4).
+       -C _\bf_\bd       Normally, s\bsu\bud\bdo\bo will close all open file
+                   descriptors other than standard input, stan-
+                   dard output and standard error.  The -\b-C\bC (_\bc_\bl_\bo_\bs_\be
+                   _\bf_\br_\bo_\bm) 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 _\bc_\bl_\bo_\bs_\be_\b-
+                   _\bf_\br_\bo_\bm_\b__\bo_\bv_\be_\br_\br_\bi_\bd_\boption in _\bs_\bu_\bd_\bo_\be_\br_\bs(4).
 
-       -c  The -\b-c\bc (_\bc_\bl_\ba_\bs_\bs) option causes s\bsu\bud\bdo\bo to run the specified
-           command with resources limited by the specified login
-           class.  The _\bc_\bl_\ba_\bs_\bs argument can be either a class name
-           as defined in _\b/_\be_\bt_\bc_\b/_\bl_\bo_\bg_\bi_\bn_\b._\bc_\bo_\bn_\bf, or a single '-' charac-
-           ter.  Specifying a _\bc_\bl_\ba_\bs_\bs 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 _\bc_\bl_\ba_\bs_\bs argument specifies an existing user class,
-           the command must be run as root, or the s\bsu\bud\bdo\bo command
-           must be run from a shell that is already root.  This
-           option is only available on systems with BSD login
-           classes.
+       -c _\bc_\bl_\ba_\bs_\bs    The -\b-c\bc (_\bc_\bl_\ba_\bs_\bs) option causes s\bsu\bud\bdo\bo to run the
+                   specified command with resources limited by
+                   the specified login class.  The _\bc_\bl_\ba_\bs_\bs argument
+                   can be either a class name as defined in
+                   _\b/_\be_\bt_\bc_\b/_\bl_\bo_\bg_\bi_\bn_\b._\bc_\bo_\bn_\bf, or a single '-' character.
+                   Specifying a _\bc_\bl_\ba_\bs_\bs of - indicates that the
+                   command should be run restricted by the
+                   default login capabilities for the user the
+                   command is run as.  If the _\bc_\bl_\ba_\bs_\bs argument
+                   specifies an existing user class, the command
+                   must be run as root, or the s\bsu\bud\bdo\bo command must
+                   be run from a shell that is already root.
+                   This option is only available on systems with
+                   BSD login classes.
 
-       -E  The -\b-E\bE (_\bp_\br_\be_\bs_\be_\br_\bv_\be _\be_\bn_\bv_\bi_\br_\bo_\bn_\bm_\be_\bn_\bt) option will override the
-           _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt option in _\bs_\bu_\bd_\bo_\be_\br_\bs(4)).  It is only available
-           when either the matching command has the SETENV tag or
-           the _\bs_\be_\bt_\be_\bn_\bv option is set in _\bs_\bu_\bd_\bo_\be_\br_\bs(4).
 
-       -e  The -\b-e\be (_\be_\bd_\bi_\bt) option indicates that, instead of
 
 
-
-1.7                      August 15, 2007                        2
+1.7                     November 21, 2007                       2
 
 
 
@@ -136,165 +136,214 @@ O\bOP\bPT\bTI\bIO\bON\bNS\bS
 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 _\bs_\bu_\bd_\bo_\be_\br_\bs file.  If the user is
-           authorized by _\bs_\bu_\bd_\bo_\be_\br_\bs the following steps are taken:
+       -E          The -\b-E\bE (_\bp_\br_\be_\bs_\be_\br_\bv_\be _\be_\bn_\bv_\bi_\br_\bo_\bn_\bm_\be_\bn_\bt) option will
+                   override the _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt option in _\bs_\bu_\bd_\bo_\be_\br_\bs(4)).
+                   It is only available when either the matching
+                   command has the SETENV tag or the _\bs_\be_\bt_\be_\bn_\bv
+                   option is set in _\bs_\bu_\bd_\bo_\be_\br_\bs(4).
 
-           1.  Temporary copies are made of the files to be
-               edited with the owner set to the invoking user.
+       -e          The -\b-e\be (_\be_\bd_\bi_\bt) 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
+                   _\bs_\bu_\bd_\bo_\be_\br_\bs file.  If the user is authorized by
+                   _\bs_\bu_\bd_\bo_\be_\br_\bs 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 _\be_\bd_\bi_\bt_\bo_\br _\bs_\bu_\bd_\bo_\be_\br_\bs 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 _\be_\bd_\bi_\bt_\bo_\br _\bs_\bu_\bd_\bo_\be_\br_\bs variable is used.
 
-           If the specified file does not exist, it will be cre-
-           ated.  Note that unlike most commands run by s\bsu\bud\bdo\bo, the
-           editor is run with the invoking user's environment
-           unmodified.  If, for some reason, s\bsu\bud\bdo\bo 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 -\b-H\bH (_\bH_\bO_\bM_\bE) option sets the HOME environment vari-
-           able to the homedir of the target user (root by
-           default) as specified in _\bp_\ba_\bs_\bs_\bw_\bd(4).  By default, s\bsu\bud\bdo\bo
-           does not modify HOME (see _\bs_\be_\bt_\b__\bh_\bo_\bm_\be and _\ba_\bl_\bw_\ba_\by_\bs_\b__\bs_\be_\bt_\b__\bh_\bo_\bm_\be
-           in _\bs_\bu_\bd_\bo_\be_\br_\bs(4)).
+                   If the specified file does not exist, it will
+                   be created.  Note that unlike most commands
+                   run by s\bsu\bud\bdo\bo, the editor is run with the invok-
+                   ing user's environment unmodified.  If, for
+                   some reason, s\bsu\bud\bdo\bo 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 -\b-h\bh (_\bh_\be_\bl_\bp) option causes s\bsu\bud\bdo\bo to print a usage mes-
-           sage and exit.
+       -g _\bg_\br_\bo_\bu_\bp    Normally, s\bsu\bud\bdo\bo 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\bg (_\bg_\br_\bo_\bu_\bp) option causes s\bsu\bud\bdo\bo to
+                   run the specified command with the primary
+                   group set to _\bg_\br_\bo_\bu_\bp.  To specify a _\bg_\bi_\bd instead
+                   of a _\bg_\br_\bo_\bu_\bp _\bn_\ba_\bm_\be, use _\b#_\bg_\bi_\bd.  When running com-
+                   mands as a _\bg_\bi_\bd, many shells require that the
+                   '#' be escaped with a backslash ('\').  If no
+                   -\b-u\bu option is specified, the command will be
+                   run as the invoking user (not root).  In
+                   either case, the primary group will be set to
+                   _\bg_\br_\bo_\bu_\bp.
 
-       -i  The -\b-i\bi (_\bs_\bi_\bm_\bu_\bl_\ba_\bt_\be _\bi_\bn_\bi_\bt_\bi_\ba_\bl _\bl_\bo_\bg_\bi_\bn) option runs the shell
-           specified in the _\bp_\ba_\bs_\bs_\bw_\bd(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.  s\bsu\bud\bdo\bo attempts to change to
-           that user's home directory before running the shell.
-           It also initializes the environment, leaving _\bD_\bI_\bS_\bP_\bL_\bA_\bY
-           and _\bT_\bE_\bR_\bM unchanged, setting _\bH_\bO_\bM_\bE, _\bS_\bH_\bE_\bL_\bL, _\bU_\bS_\bE_\bR, _\bL_\bO_\bG_\b-
-           _\bN_\bA_\bM_\bE, and _\bP_\bA_\bT_\bH, and unsetting all other environment
-           variables.
+       -H          The -\b-H\bH (_\bH_\bO_\bM_\bE) option sets the HOME environment
+                   variable to the homedir of the target user
+                   (root by default) as specified in _\bp_\ba_\bs_\bs_\bw_\bd(4).
 
-       -K  The -\b-K\bK (sure _\bk_\bi_\bl_\bl) option is like -\b-k\bk except that it
-           removes the user's timestamp entirely.  Like -\b-k\bk, this
-           option does not require a password.
 
-       -k  The -\b-k\bk (_\bk_\bi_\bl_\bl) option to s\bsu\bud\bdo\bo invalidates the user's
-           timestamp by setting the time on it to the Epoch.  The
-           next time s\bsu\bud\bdo\bo 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, s\bsu\bud\bdo\bo does not modify HOME (see
+                   _\bs_\be_\bt_\b__\bh_\bo_\bm_\be and _\ba_\bl_\bw_\ba_\by_\bs_\b__\bs_\be_\bt_\b__\bh_\bo_\bm_\be in _\bs_\bu_\bd_\bo_\be_\br_\bs(4)).
+
+       -h          The -\b-h\bh (_\bh_\be_\bl_\bp) option causes s\bsu\bud\bdo\bo to print a
+                   usage message and exit.
+
+       -i          The -\b-i\bi (_\bs_\bi_\bm_\bu_\bl_\ba_\bt_\be _\bi_\bn_\bi_\bt_\bi_\ba_\bl _\bl_\bo_\bg_\bi_\bn) option runs
+                   the shell specified in the _\bp_\ba_\bs_\bs_\bw_\bd(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.  s\bsu\bud\bdo\bo attempts to change to
+                   that user's home directory before running the
+                   shell.  It also initializes the environment,
+                   leaving _\bD_\bI_\bS_\bP_\bL_\bA_\bY and _\bT_\bE_\bR_\bM unchanged, setting
+                   _\bH_\bO_\bM_\bE, _\bS_\bH_\bE_\bL_\bL, _\bU_\bS_\bE_\bR, _\bL_\bO_\bG_\bN_\bA_\bM_\bE, and _\bP_\bA_\bT_\bH, and
+                   unsetting all other environment variables.
+
+       -K          The -\b-K\bK (sure _\bk_\bi_\bl_\bl) option is like -\b-k\bk except
+                   that it removes the user's timestamp entirely.
+                   Like -\b-k\bk, this option does not require a pass-
+                   word.
+
+       -k          The -\b-k\bk (_\bk_\bi_\bl_\bl) option to s\bsu\bud\bdo\bo invalidates the
+                   user's timestamp by setting the time on it to
+                   the Epoch.  The next time s\bsu\bud\bdo\bo is run a pass-
+                   word will be required.  This option does not
+                   require a password and was added to allow a
+                   user to revoke s\bsu\bud\bdo\bo permissions from a .logout
+                   file.
+
+       -L          The -\b-L\bL (_\bl_\bi_\bs_\bt defaults) option will list out
+                   the parameters that may be set in a _\bD_\be_\bf_\ba_\bu_\bl_\bt_\bs
+                   line along with a short description for each.
+                   This option is useful in conjunction with
+                   _\bg_\br_\be_\bp(1).
 
+       -l [_\bc_\bo_\bm_\bm_\ba_\bn_\bd]
+                   If no _\bc_\bo_\bm_\bm_\ba_\bn_\bd is specified, the -\b-l\bl (_\bl_\bi_\bs_\bt)
+                   option will list the allowed (and forbidden)
+                   commands for the invoking user (or the user
+                   specified by the -\b-U\bU option) on the current
+                   host.  If a _\bc_\bo_\bm_\bm_\ba_\bn_\bd is specified and is per-
+                   mitted by _\bs_\bu_\bd_\bo_\be_\br_\bs, the fully-qualified path to
+                   the command is displayed along with any com-
+                   mand line arguments.  If _\bc_\bo_\bm_\bm_\ba_\bn_\bd is not
+                   allowed, s\bsu\bud\bdo\bo will exit with a return value of
+                   1.
 
-           to allow a user to revoke s\bsu\bud\bdo\bo permissions from a
-           .logout file.
+       -P          The -\b-P\bP (_\bp_\br_\be_\bs_\be_\br_\bv_\be _\bg_\br_\bo_\bu_\bp _\bv_\be_\bc_\bt_\bo_\br) option causes
+                   s\bsu\bud\bdo\bo to preserve the invoking user's group
+                   vector unaltered.  By default, s\bsu\bud\bdo\bo will ini-
+                   tialize the group vector to the list of groups
+                   the target user is in.  The real and effective
 
-       -L  The -\b-L\bL (_\bl_\bi_\bs_\bt defaults) option will list out the param-
-           eters that may be set in a _\bD_\be_\bf_\ba_\bu_\bl_\bt_\bs line along with a
-           short description for each.  This option is useful in
-           conjunction with _\bg_\br_\be_\bp(1).
 
-       -l [_\bc_\bo_\bm_\bm_\ba_\bn_\bd]
-           If no _\bc_\bo_\bm_\bm_\ba_\bn_\bd is specified, the -\b-l\bl (_\bl_\bi_\bs_\bt) option will
-           list the allowed (and forbidden) commands for the
-           invoking user (or the user specified by the -\b-U\bU option)
-           on the current host.  If a _\bc_\bo_\bm_\bm_\ba_\bn_\bd is specified and is
-           permitted by _\bs_\bu_\bd_\bo_\be_\br_\bs, the fully-qualified path to the
-           command is displayed along with any command line argu-
-           ments.  If _\bc_\bo_\bm_\bm_\ba_\bn_\bd is not allowed, s\bsu\bud\bdo\bo will exit with
-           a return value of 1.
 
-       -P  The -\b-P\bP (_\bp_\br_\be_\bs_\be_\br_\bv_\be _\bg_\br_\bo_\bu_\bp _\bv_\be_\bc_\bt_\bo_\br) option causes s\bsu\bud\bdo\bo to
-           preserve the invoking user's group vector unaltered.
-           By default, s\bsu\bud\bdo\bo 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 -\b-p\bp (_\bp_\br_\bo_\bm_\bp_\bt) 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 _\bf_\bq_\bd_\bn _\bs_\bu_\bd_\bo_\be_\br_\bs 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 -\b-S\bS (_\bs_\bt_\bd_\bi_\bn) option causes s\bsu\bud\bdo\bo 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 -\b-s\bs (_\bs_\bh_\be_\bl_\bl) option runs the shell specified by the
-           _\bS_\bH_\bE_\bL_\bL environment variable if it is set or the shell
-           as specified in _\bp_\ba_\bs_\bs_\bw_\bd(4).
+       -p _\bp_\br_\bo_\bm_\bp_\bt   The -\b-p\bp (_\bp_\br_\bo_\bm_\bp_\bt) option allows you to override
+                   the default password prompt and use a custom
+                   one.  The following percent (`%') escapes are
+                   supported:
 
-       -U  The -\b-U\bU (_\bo_\bt_\bh_\be_\br _\bu_\bs_\be_\br) option is used in conjunction with
-           the -\b-l\bl 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 _\bf_\bq_\bd_\bn _\bs_\bu_\bd_\bo_\b-
+                       _\be_\br_\bs 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 -\b-S\bS (_\bs_\bt_\bd_\bi_\bn) option causes s\bsu\bud\bdo\bo to read the
+                   password from the standard input instead of
+                   the terminal device.
 
+       -s          The -\b-s\bs (_\bs_\bh_\be_\bl_\bl) option runs the shell specified
+                   by the _\bS_\bH_\bE_\bL_\bL environment variable if it is set
+                   or the shell as specified in _\bp_\ba_\bs_\bs_\bw_\bd(4).
+
+       -U _\bu_\bs_\be_\br     The -\b-U\bU (_\bo_\bt_\bh_\be_\br _\bu_\bs_\be_\br) option is used in conjunc-
+                   tion with the -\b-l\bl option to specify the user
+                   whose privileges should be listed.  Only root
+                   or a user with s\bsu\bud\bdo\bo ALL on the current host
+                   may use this option.
+
+       -u _\bu_\bs_\be_\br     The -\b-u\bu (_\bu_\bs_\be_\br) option causes s\bsu\bud\bdo\bo to run the
+                   specified command as a user other than _\br_\bo_\bo_\bt.
+                   To specify a _\bu_\bi_\bd instead of a _\bu_\bs_\be_\br _\bn_\ba_\bm_\be, use
+                   _\b#_\bu_\bi_\bd.  When running commands as a _\bu_\bi_\bd, many
+                   shells require that the '#' be escaped with a
+                   backslash ('\').  Note that if the _\bt_\ba_\br_\bg_\be_\bt_\bp_\bw
+                   Defaults option is set (see _\bs_\bu_\bd_\bo_\be_\br_\bs(4)) it is
+                   not possible to run commands with a uid not
+                   listed in the password database.
+
+       -V          The -\b-V\bV (_\bv_\be_\br_\bs_\bi_\bo_\bn) option causes s\bsu\bud\bdo\bo to print
+                   the version number and exit.  If the invoking
+                   user is already root the -\b-V\bV option will print
+                   out a list of the defaults s\bsu\bud\bdo\bo 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 s\bsu\bud\bdo\bo ALL
-           on the current host may use this option.
 
-       -u  The -\b-u\bu (_\bu_\bs_\be_\br) option causes s\bsu\bud\bdo\bo to run the specified
-           command as a user other than _\br_\bo_\bo_\bt.  To specify a _\bu_\bi_\bd
-           instead of a _\bu_\bs_\be_\br_\bn_\ba_\bm_\be, use _\b#_\bu_\bi_\bd.  When running com-
-           mands as a _\bu_\bi_\bd, many shells require that the '#' be
-           escaped with a backslash ('\').  Note that if the _\bt_\ba_\br_\b-
-           _\bg_\be_\bt_\bp_\bw Defaults option is set (see _\bs_\bu_\bd_\bo_\be_\br_\bs(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 -\b-V\bV (_\bv_\be_\br_\bs_\bi_\bo_\bn) option causes s\bsu\bud\bdo\bo to print the ver-
-           sion number and exit.  If the invoking user is already
-           root the -\b-V\bV option will print out a list of the
-           defaults s\bsu\bud\bdo\bo was compiled with as well as the
-           machine's local network addresses.
 
-       -v  If given the -\b-v\bv (_\bv_\ba_\bl_\bi_\bd_\ba_\bt_\be) option, s\bsu\bud\bdo\bo will update
-           the user's timestamp, prompting for the user's pass-
-           word if necessary.  This extends the s\bsu\bud\bdo\bo timeout for
-           another 5 minutes (or whatever the timeout is set to
-           in _\bs_\bu_\bd_\bo_\be_\br_\bs) but does not run a command.
+       -v          If given the -\b-v\bv (_\bv_\ba_\bl_\bi_\bd_\ba_\bt_\be) option, s\bsu\bud\bdo\bo will
+                   update the user's timestamp, prompting for the
+                   user's password if necessary.  This extends
+                   the s\bsu\bud\bdo\bo timeout for another 5 minutes (or
+                   whatever the timeout is set to in _\bs_\bu_\bd_\bo_\be_\br_\bs) but
+                   does not run a command.
 
-       --  The -\b--\b- flag indicates that s\bsu\bud\bdo\bo should stop processing
-           command line arguments.  It is most useful in conjunc-
-           tion with the -\b-s\bs flag.
+       --          The -\b--\b- flag indicates that s\bsu\bud\bdo\bo should stop
+                   processing command line arguments.  It is most
+                   useful in conjunction with the -\b-s\bs flag.
 
        Environment variables to be set for the command may also
        be passed on the command line in the form of V\bVA\bAR\bR=_\bv_\ba_\bl_\bu_\be,
@@ -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 _\bs_\be_\bt_\be_\bn_\bv option is set in _\bs_\bu_\bd_\bo_\b-
-       _\be_\br_\bs or the command to be run has the SETENV tag set the
-       user may set variables that would overwise be forbidden.
-       See _\bs_\bu_\bd_\bo_\be_\br_\bs(4) for more information.
+       _\be_\br_\bs, 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 _\bs_\bu_\bd_\bo_\be_\br_\bs(4) for more
+       information.
 
 R\bRE\bET\bTU\bUR\bRN\bN V\bVA\bAL\bLU\bUE\bES\bS
        Upon successful execution of a program, the return value
@@ -322,18 +372,6 @@ R\bRE\bET\bTU\bUR\bRN\bN V\bVA\bAL\bLU\bUE\bES\bS
        stances.  The most common reason for _\bs_\bt_\ba_\bt(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.
 
 S\bSE\bEC\bCU\bUR\bRI\bIT\bTY\bY N\bNO\bOT\bTE\bES\bS
@@ -350,6 +388,18 @@ S\bSE\bEC\bCU\bUR\bRI\bIT\bTY\bY N\bNO\bOT\bTE\bES\bS
 
        If, however, the _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt option is disabled in _\bs_\bu_\bd_\bo_\be_\br_\bs,
        any variables not explicitly denied by the _\be_\bn_\bv_\b__\bc_\bh_\be_\bc_\bk and
+
+
+
+1.7                     November 21, 2007                       6
+
+
+
+
+
+SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
+
+
        _\be_\bn_\bv_\b__\bd_\be_\bl_\be_\bt_\be options are inherited from the invoking pro-
        cess.  In this case, _\be_\bn_\bv_\b__\bc_\bh_\be_\bc_\bk and _\be_\bn_\bv_\b__\bd_\be_\bl_\be_\bt_\be behave like
        a blacklist.  Since it is not possible to blacklist all
@@ -388,18 +438,6 @@ S\bSE\bEC\bCU\bUR\bRI\bIT\bTY\bY N\bNO\bOT\bTE\bES\bS
        timestamp directory before s\bsu\bud\bdo\bo is run.  However, because
        s\bsu\bud\bdo\bo 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 s\bsu\bud\bdo\bo 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 @@ E\bEN\bNV\bVI\bIR\bRO\bON\bNM\bME\bEN\bNT\bT
        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 @@ F\bFI\bIL\bLE\bES\bS
        _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs        List of who can run what
        _\b/_\bv_\ba_\br_\b/_\br_\bu_\bn_\b/_\bs_\bu_\bd_\bo       Directory containing timestamps
 
+
+
+
+
+1.7                     November 21, 2007                       8
+
+
+
+
+
+SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
+
+
 E\bEX\bXA\bAM\bMP\bPL\bLE\bES\bS
        Note: the following examples assume suitable _\bs_\bu_\bd_\bo_\be_\br_\bs(4)
        entries.
@@ -520,18 +571,6 @@ A\bAU\bUT\bTH\bHO\bOR\bRS\bS
                Todd C. Miller
 
        See the HISTORY file in the s\bsu\bud\bdo\bo 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 s\bsu\bud\bdo\bo.
 
@@ -547,6 +586,18 @@ C\bCA\bAV\bVE\bEA\bAT\bTS\bS
        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 @@ D\bDI\bIS\bSC\bCL\bLA\bAI\bIM\bME\bER\bR
 
 
 
-1.7                      August 15, 2007                        9
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1.7                     November 21, 2007                      10
 
 
diff --git a/sudo.h b/sudo.h
index d79160785b29de87e74226eefa8650f9ba5b2346..9377aad391ea95e7a933c78271465342684c78e6 100644 (file)
--- 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;
 
index 05516a9202cbbb3527eaf4c2fbcd1279a30c0731..77b3c80cc5795fc84600ba97f28bb6b9068d294d 100644 (file)
 .\" ========================================================================
 .\"
 .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
index 686817c2eed823475218fb05b1fe6302f6ad7a40..e8636b09c9d780228e717249f4f94bc8f2fb6575 100644 (file)
--- a/sudo.pod
+++ b/sudo.pod
@@ -30,15 +30,17 @@ sudo, sudoedit - execute a command as another user
 
 B<sudo> B<-h> | B<-K> | B<-k> | B<-L> | B<-V> | B<-v>
 
-B<sudo> B<-l> S<[B<-U> I<username>]> S<[B<-u> I<username>|I<#uid>]> [I<command>]
+B<sudo> B<-l> S<[B<-g> I<groupname>|I<#gid>]> S<[B<-U> I<username>]>
+S<[B<-u> I<username>|I<#uid>]> [I<command>]
 
 B<sudo> [B<-bEHPS>] S<[B<-a> I<auth_type>]> S<[B<-C> I<fd>]>
-S<[B<-c> I<class>|I<->]> S<[B<-p> I<prompt>]> S<[B<-u> I<username>|I<#uid>]>
-S<[B<VAR>=I<value>]> S<{B<-i> | B<-s> | I<command>}>
+S<[B<-c> I<class>|I<->]> S<[B<-g> I<groupname>|I<#gid>]> S<[B<-p> I<prompt>]>
+S<[B<-u> I<username>|I<#uid>]> S<[B<VAR>=I<value>]>
+S<{B<-i> | B<-s> | I<command>}>
 
 B<sudoedit> [B<-S>] S<[B<-a> I<auth_type>]> S<[B<-C> I<fd>]>
-S<[B<-c> I<class>|I<->]> S<[B<-p> I<prompt>]> S<[B<-u> I<username>|I<#uid>]>
-file ...
+S<[B<-c> I<class>|I<->]> S<[B<-g> I<groupname>|I<#gid>]> S<[B<-p> I<prompt>]>
+S<[B<-u> I<username>|I<#uid>]> file ...
 
 =head1 DESCRIPTION
 
@@ -173,6 +175,18 @@ B<sudo> 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<group>
+
+Normally, B<sudo> 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<group>) option causes B<sudo> to run
+the specified command with the primary group set to I<group>.  To
+specify a I<gid> instead of a I<group name>, use I<#gid>.  When
+running commands as a I<gid>, 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<group>.
+
 =item -H
 
 The B<-H> (I<HOME>) option sets the C<HOME> environment variable
@@ -288,7 +302,7 @@ option.
 
 The B<-u> (I<user>) option causes B<sudo> to run the specified
 command as a user other than I<root>.  To specify a I<uid> instead
-of a I<username>, use I<#uid>.  When running commands as a I<uid>,
+of a I<user name>, use I<#uid>.  When running commands as a I<uid>,
 many shells require that the '#' be escaped with a backslash ('\').
 Note that if the I<targetpw> Defaults option is set (see L<sudoers(5)>)
 it is not possible to run commands with a uid not listed in the
index b0c5c1eb99418d79b2dfa73e79c68ef3c11362ca..3f1de3407815465ef5ab761b37ce35d019f978e0 100644 (file)
@@ -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 | <command>}"
-#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 | <command>}"
+#define SUDO_USAGE4 " -e [-S] @BSDAUTH_USAGE@[-C fd] @LOGINCAP_USAGE@[-g groupname|#gid] [-p prompt] [-u username|#uid] file ..."
 
 #endif /* _SUDO_USAGE_H */
index 14b997af7c3a028a0c359d724aa4d3537fb9ede3..3bf1024eb03d05ca4a9dd3c581565ec8bbfc34cd 100644 (file)
@@ -61,7 +61,7 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
 
 
 
-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)
 
        R\bRu\bun\bna\bas\bs_\b_S\bSp\bpe\bec\bc
 
-       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 r\bro\boo\bot\bt 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 s\bsu\bud\bdo\bo's -\b-u\bu flag.  The second defines a list of
+       groups that can be specified via s\bsu\bud\bdo\bo's -\b-g\bg 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 -\b-g\bg 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
+       r\bro\boo\bot\bt 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 d\bdg\bgb\bb is now allowed to run _\b/_\bb_\bi_\bn_\b/_\bl_\bs as o\bop\bpe\ber\bra\bat\bto\bor\br,
+       but  _\b/_\bb_\bi_\bn_\b/_\bk_\bi_\bl_\bl and _\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn_\b/_\bl_\bp_\br_\bm as r\bro\boo\bot\bt.
 
+       We can extend this to allow d\bdg\bgb\bb to run /bin/ls with either
+       the user or group set to o\bop\bpe\ber\bra\bat\bto\bor\br:
 
+        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 t\btc\bcm\bm 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 t\btc\bcm\bm.
 
-
-       but  _\b/_\bb_\bi_\bn_\b/_\bk_\bi_\bl_\bl and _\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn_\b/_\bl_\bp_\br_\bm as r\bro\boo\bot\bt.
+        tcm    boulder = (:dialer) /usr/bin/tip, /usr/bin/cu, \
+               /usr/local/bin/minicom
 
        T\bTa\bag\bg_\b_S\bSp\bpe\bec\bc
 
@@ -362,6 +389,17 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
        able to run _\b/_\bb_\bi_\bn_\b/_\bk_\bi_\bl_\bl 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
        _\be_\bn_\bv_\b__\bc_\bh_\be_\bc_\bk, _\be_\bn_\bv_\b__\bd_\be_\bl_\be_\bt_\be, or _\be_\bn_\bv_\b__\bk_\be_\be_\bp.  As such, only trusted
        users should be allowed to set variables in this manner.
+       If the command matched is A\bAL\bLL\bL, the SETENV tag is implied
+       for that command; this default may be overridden by use of
+       the UNSETENV tag.
 
        W\bWi\bil\bld\bdc\bca\bar\brd\bds\bs
 
@@ -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 n\bno\bot\bt 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 _\bs_\bu_\bd_\bo_\be_\br_\bs files from within
        the _\bs_\bu_\bd_\bo_\be_\br_\bs 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 _\bs_\bu_\bd_\bo_\b-
        _\be_\br_\bs file in addition to a per-machine local one.  For the
        sake of this example the site-wide _\bs_\bu_\bd_\bo_\be_\br_\bs 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 A\bAL\bLL\bL is a built-in _\ba_\bl_\bi_\ba_\bs 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)
-
-
 S\bSU\bUD\bDO\bOE\bER\bRS\bS O\bOP\bPT\bTI\bIO\bON\bNS\bS
        s\bsu\bud\bdo\bo's behavior can be modified by Default_Entry lines, as
        explained earlier.  A list of all supported Defaults
@@ -559,6 +586,18 @@ S\bSU\bUD\bDO\bOE\bER\bRS\bS O\bOP\bPT\bTI\bIO\bON\bNS\bS
                        at which s\bsu\bud\bdo\bo begins closing open file
                        descriptors.  This flag is _\bo_\bf_\bf by default.
 
+
+
+
+1.7                     November 21, 2007                       9
+
+
+
+
+
+SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
+
+
        env_editor      If set, v\bvi\bis\bsu\bud\bdo\bo will use the value of the
                        EDITOR or VISUAL environment variables
                        before falling back on the default editor
@@ -586,18 +625,6 @@ S\bSU\bUD\bDO\bOE\bER\bRS\bS O\bOP\bPT\bTI\bIO\bON\bNS\bS
                        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 _\bs_\bu_\bd_\bo_\be_\br_\bs 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 _\bo_\bf_\bf 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 S\bS/\b/K\bKe\bey\by or O\bOP\bPI\bIE\bE, 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 _\bo_\bf_\bf
                        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 _\bm_\ba_\bi_\bl_\bt_\bo
                        user if the invoking user is not in the
                        _\bs_\bu_\bd_\bo_\be_\br_\bs file.  This flag is _\bo_\bn by default.
@@ -718,18 +756,6 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
        preserve_groups By default s\bsu\bud\bdo\bo 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 _\bp_\br_\be_\bs_\be_\br_\bv_\be_\b__\bg_\br_\bo_\bu_\bp_\bs 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, s\bsu\bud\bdo\bo 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 _\bo_\bf_\bf 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
                        _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt option has not been disabled,
                        entries in the _\be_\bn_\bv_\b__\bk_\be_\be_\bp list will override
                        the value of _\bs_\be_\bt_\b__\bl_\bo_\bg_\bn_\ba_\bm_\be.  This flag is
@@ -824,6 +850,18 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
        stay_setuid     Normally, when s\bsu\bud\bdo\bo 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, s\bsu\bud\bdo\bo 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 _\bo_\bf_\bf by default.
 
        use_loginclass  If set, s\bsu\bud\bdo\bo 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)
        S\bSt\btr\bri\bin\bng\bgs\bs:
 
        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)
                        _\bn_\bo_\be_\bx_\be_\bc functionality on systems that sup-
                        port LD_PRELOAD or its equivalent.
                        Defaults to
-                       _\b/_\bu_\bs_\br_\b/_\bl_\bo_\bc_\ba_\bl_\b/_\bl_\bi_\bb_\be_\bx_\be_\bc_\b/_\bs_\bu_\bd_\bo_\b__\bn_\bo_\be_\bx_\be_\bc.
+                       _\b/_\bu_\bs_\br_\b/_\bl_\bo_\bc_\ba_\bl_\b/_\bl_\bi_\bb_\be_\bx_\be_\bc_\b/_\bs_\bu_\bd_\bo_\b__\bn_\bo_\be_\bx_\be_\bc_\b._\bs_\bo.
 
        passprompt      The default prompt to use when asking for
                        a password; can be overridden via the -\b-p\bp
+
+
+
+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
                        -\b-u\bu 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 _\br_\bu_\bn_\ba_\bs_\b__\bd_\be_\bf_\ba_\bu_\bl_\bt is set it m\bmu\bus\bst\bt 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 -\b-l\bl 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 s\bsu\bud\bdo\bo 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 -\b-v\bv 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 _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt
                        option is in effect.  This allows fine-
-
-
-
-1.7                     September  5, 2007                     18
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
                        grained control over the environment
                        s\bsu\bud\bdo\bo-spawned processes will receive.  The
                        argument may be a double-quoted, space-
@@ -1220,6 +1246,18 @@ E\bEX\bXA\bAM\bMP\bPL\bLE\bES\bS
        Below are example _\bs_\bu_\bd_\bo_\be_\br_\bs entries.  Admittedly, some of
        these are a bit contrived.  First, we define our _\ba_\bl_\bi_\ba_\bs_\be_\bs:
 
+
+
+
+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 @@ E\bEX\bXA\bAM\bMP\bPL\bLE\bES\bS
         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 _\bU_\bs_\be_\br _\bs_\bp_\be_\bc_\bi_\bf_\bi_\bc_\ba_\bt_\bi_\bo_\bn 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 j\bja\bac\bck\bk 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 b\bbo\bob\bb may run anything on the _\bS_\bP_\bA_\bR_\bC and _\bS_\bG_\bI
        machines as any user listed in the _\bO_\bP Runas_Alias (r\bro\boo\bot\bt
        and o\bop\bpe\ber\bra\bat\bto\bor\br).
@@ -1378,18 +1409,6 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
         fred           ALL = (DB) NOPASSWD: ALL
 
        The user f\bfr\bre\bed\bd can run commands as any user in the _\bD_\bB
-
-
-
-1.7                     September  5, 2007                     21
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
        Runas_Alias (o\bor\bra\bac\bcl\ble\be or s\bsy\byb\bba\bas\bse\be) 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 _\bs_\bu(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 @@ S\bSE\bEC\bCU\bUR\bRI\bIT\bTY\bY N\bNO\bOT\bTE\bES\bS
            bill        ALL = ALL, !SU, !SHELLS
 
        Doesn't really prevent b\bbi\bil\bll\bl from running the commands
-       listed in _\bS_\bU or _\bS_\bH_\bE_\bL_\bL_\bS 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 _\bS_\bU or _\bS_\bH_\bE_\bL_\bL_\bS 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 @@ P\bPR\bRE\bEV\bVE\bEN\bNT\bTI\bIN\bNG\bG S\bSH\bHE\bEL\bLL\bL E\bES\bSC\bCA\bAP\bPE\bES\bS
                  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 s\bsu\bud\bdo\bo supports _\bn_\bo_\be_\bx_\be_\bc, you
@@ -1510,18 +1541,6 @@ P\bPR\bRE\bEV\bVE\bEN\bNT\bTI\bIN\bNG\bG S\bSH\bHE\bEL\bLL\bL E\bES\bSC\bCA\bAP\bPE\bES\bS
                  _\bn_\bo_\be_\bx_\be_\bc will work at compile-time.  _\bn_\bo_\be_\bx_\be_\bc should
                  work on SunOS, Solaris, *BSD, Linux, IRIX, Tru64
                  UNIX, MacOS X, and HP-UX 11.x.  It is known n\bno\bot\bt
-
-
-
-1.7                     September  5, 2007                     23
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
                  to work on AIX and UnixWare.  _\bn_\bo_\be_\bx_\be_\bc is expected
                  to work on most operating systems that support
                  the LD_PRELOAD environment variable.  Check your
@@ -1556,8 +1575,20 @@ S\bSE\bEE\bE A\bAL\bLS\bSO\bO
 
 C\bCA\bAV\bVE\bEA\bAT\bTS\bS
        The _\bs_\bu_\bd_\bo_\be_\br_\bs file should a\bal\blw\bwa\bay\bys\bs be edited by the v\bvi\bis\bsu\bud\bdo\bo
-       command which locks the file and does grammatical check-
-       ing. It is imperative that _\bs_\bu_\bd_\bo_\be_\br_\bs 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 _\bs_\bu_\bd_\bo_\be_\br_\bs be free of syntax
        errors since s\bsu\bud\bdo\bo will not run with a syntactically incor-
        rect _\bs_\bu_\bd_\bo_\be_\br_\bs file.
 
@@ -1577,17 +1608,6 @@ S\bSU\bUP\bPP\bPO\bOR\bRT\bT
        man/listinfo/sudo-users to subscribe or search the
        archives.
 
-
-
-1.7                     September  5, 2007                     24
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
 D\bDI\bIS\bSC\bCL\bLA\bAI\bIM\bME\bER\bR
        s\bsu\bud\bdo\bo is provided ``AS IS'' and any express or implied war-
        ranties, including, but not limited to, the implied war-
@@ -1625,26 +1645,6 @@ D\bDI\bIS\bSC\bCL\bLA\bAI\bIM\bME\bER\bR
 
 
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-1.7                     September  5, 2007                     25
+1.7                     November 21, 2007                      25
 
 
index 09d7e01addee9428eaf076c3b4d2ec2e5ce7a5a0..cba921204b6c7bbd7ebfccf66fc01ddb77edee45 100644 (file)
 .\" ========================================================================
 .\"
 .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)
index 4193d922b1ac355565f9f5e003d1bf34cf6d2b69..918fde1b530af3cbcaf8f479a3b8211392319b23 100644 (file)
@@ -125,14 +125,14 @@ with '+') and C<User_Alias>es.  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<Runas_List> is similar to a C<User_List> except that instead
 of C<User_Alias>es it can contain C<Runas_Alias>es.  Note that
@@ -247,7 +247,7 @@ See L</"SUDOERS OPTIONS"> 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<Runas_Spec> is simply a C<Runas_List> (as defined above)
-enclosed in a set of parentheses.  If you do not specify a
-C<Runas_Spec> in the user specification, a default C<Runas_Spec>
-of B<root> will be used.  A C<Runas_Spec> sets the default for
-commands that follow it.  What this means is that for the entry:
+A C<Runas_Spec> determines the user and/or the group that a command
+may be run as.  A fully-specified C<Runas_Spec> consists of two
+C<Runas_List>s (as defined above) separated by a colon (':') and
+enclosed in a set of parentheses.  The first C<Runas_List> indicates
+which users the command may be run as via B<sudo>'s B<-u> flag.
+The second defines a list of groups that can be specified via
+B<sudo>'s B<-g> flag.  If both C<Runas_List>s are specified, the
+command may be run with any combination of users and groups listed
+in their respective C<Runas_List>s.  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<Runas_List> 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<Runas_List>.  If no
+C<Runas_Spec> is specified the command may be run as B<root> and
+no group may be specified.
+
+A C<Runas_Spec> 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<dgb> is now allowed to run F</bin/ls> as B<operator>,
 but  F</bin/kill> and F</usr/bin/lprm> as B<root>.
 
+We can extend this to allow B<dgb> to run C</bin/ls> with either
+the user or group set to B<operator>:
+
+ dgb   boulder = (operator : operator) /bin/ls, (root) /bin/kill, \
+       /usr/bin/lprm
+
+In the following example, user B<tcm> 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>.
+
+ 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
index b7016968c8da80f5f21ff30a4219a836d1f887b4..91118a4ed01a78d7b1c47a722f0d236aaf727d82 100644 (file)
@@ -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);
                }
index d67a4aec9a5ef140f5b3373f0dd466a4e7ca44a6..f6e3e7badc33d0b30665b8e3748e89020de2f76a 100644 (file)
--- 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);
                }
index 62ae4fab545918f4340e8d6a19e05a5b9d22360a..2035e7aaab3838af13befc8b93ddc66b03ff2116 100644 (file)
@@ -50,18 +50,18 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
 O\bOP\bPT\bTI\bIO\bON\bNS\bS
        v\bvi\bis\bsu\bud\bdo\bo accepts the following command line options:
 
-       -c  Enable c\bch\bhe\bec\bck\bk-\b-o\bon\bnl\bly\by mode.  The existing _\bs_\bu_\bd_\bo_\be_\br_\bs file
-           will be checked for syntax and a message will be
-           printed to the standard output detailing the status of
-           _\bs_\bu_\bd_\bo_\be_\br_\bs.  If the syntax check completes successfully,
-           v\bvi\bis\bsu\bud\bdo\bo will exit with a value of 0.  If a syntax error
-           is encountered, v\bvi\bis\bsu\bud\bdo\bo will exit with a value of 1.
+       -c          Enable c\bch\bhe\bec\bck\bk-\b-o\bon\bnl\bly\by mode.  The existing _\bs_\bu_\bd_\bo_\be_\br_\bs
+                   file will be checked for syntax and a message
+                   will be printed to the standard output detail-
+                   ing the status of _\bs_\bu_\bd_\bo_\be_\br_\bs.  If the syntax
+                   check completes successfully, v\bvi\bis\bsu\bud\bdo\bo will exit
+                   with a value of 0.  If a syntax error is
+                   encountered, v\bvi\bis\bsu\bud\bdo\bo will exit with a value of
+                   1.
 
-       -f  Specify and alternate _\bs_\bu_\bd_\bo_\be_\br_\bs file location.  With
 
 
-
-1.7                      August 15, 2007                        1
+1.7                      October 20, 2007                       1
 
 
 
@@ -70,28 +70,32 @@ O\bOP\bPT\bTI\bIO\bON\bNS\bS
 VISUDO(1m)             MAINTENANCE COMMANDS            VISUDO(1m)
 
 
-           this option v\bvi\bis\bsu\bud\bdo\bo will edit (or check) the _\bs_\bu_\bd_\bo_\be_\br_\bs
-           file of your choice, instead of the default,
-           _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs.  The lock file used is the specified
-           _\bs_\bu_\bd_\bo_\be_\br_\bs file with ".tmp" appended to it.
+       -f _\bs_\bu_\bd_\bo_\be_\br_\bs  Specify and alternate _\bs_\bu_\bd_\bo_\be_\br_\bs file location.
+                   With this option v\bvi\bis\bsu\bud\bdo\bo will edit (or check)
+                   the _\bs_\bu_\bd_\bo_\be_\br_\bs file of your choice, instead of
+                   the default, _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs.  The lock file used
+                   is the specified _\bs_\bu_\bd_\bo_\be_\br_\bs file with ".tmp"
+                   appended to it.
 
-       -q  Enable q\bqu\bui\bie\bet\bt mode.  In this mode details about syntax
-           errors are not printed.  This option is only useful
-           when combined with the -\b-c\bc flag.
+       -q          Enable q\bqu\bui\bie\bet\bt mode.  In this mode details about
+                   syntax errors are not printed.  This option is
+                   only useful when combined with the -\b-c\bc flag.
 
-       -s  Enable s\bst\btr\bri\bic\bct\bt checking of the _\bs_\bu_\bd_\bo_\be_\br_\bs file.  If an
-           alias is used before it is defined, v\bvi\bis\bsu\bud\bdo\bo 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 s\bst\btr\bri\bic\bct\bt checking of the _\bs_\bu_\bd_\bo_\be_\br_\bs file.
+                   If an alias is used before it is defined,
+                   v\bvi\bis\bsu\bud\bdo\bo 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 -\b-V\bV (version) option causes v\bvi\bis\bsu\bud\bdo\bo to print its
-           version number and exit.
+       -V          The -\b-V\bV (version) option causes v\bvi\bis\bsu\bud\bdo\bo to print
+                   its version number and exit.
 
 E\bEN\bNV\bVI\bIR\bRO\bON\bNM\bME\bEN\bNT\bT
-       The following environment variables are used only if
-       v\bvi\bis\bsu\bud\bdo\bo was configured with the _\b-_\b-_\bw_\bi_\bt_\bh_\b-_\be_\bn_\bv_\b-_\be_\bd_\bi_\bt_\bo_\br option:
+       The following environment variables may be consulted
+       depending on the value of the _\be_\bd_\bi_\bt_\bo_\br and _\be_\bn_\bv_\b__\be_\bd_\bi_\bt_\bo_\br _\bs_\bu_\bd_\bo_\b-
+       _\be_\br_\bs variables:
 
        VISUAL          Invoked by visudo as the editor to use
 
@@ -121,13 +125,9 @@ D\bDI\bIA\bAG\bGN\bNO\bOS\bST\bTI\bIC\bCS\bS
            will not complain).  In -\b-s\bs (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 @@ D\bDI\bIA\bAG\bGN\bNO\bOS\bST\bTI\bIC\bCS\bS
 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 -\b-s\bs (strict) mode this is an
            error, not a warning.
 
@@ -190,9 +193,6 @@ D\bDI\bIS\bSC\bCL\bLA\bAI\bIM\bME\bER\bR
 
 
 
-
-
-
-1.7                      August 15, 2007                        3
+1.7                      October 20, 2007                       3
 
 
index 28d88988adf077330ef6537c822bcb1568731bac..cb32f061fada9e8d0ad9fcccca9ad3c95b1956a4 100644 (file)
 .\" ========================================================================
 .\"
 .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"