]> granicus.if.org Git - sudo/commitdiff
Implement %h escape in sudoers include filenames.
authorTodd C. Miller <Todd.Miller@courtesan.com>
Sat, 21 Feb 2009 21:49:19 +0000 (21:49 +0000)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Sat, 21 Feb 2009 21:49:19 +0000 (21:49 +0000)
sudoers.pod
toke.l
visudo.c

index 6767e7e1b027d106497b5ff0fbe597d484fb3aca..bca770f0987d7430e00d2e2911c3ff508a86867f 100644 (file)
@@ -447,7 +447,7 @@ useful, for example, for keeping a site-wide I<sudoers> file in
 addition to a per-machine local one.  For the sake of this example
 the site-wide I<sudoers> will be F</etc/sudoers> and the per-machine
 one will be F</etc/sudoers.local>.  To include F</etc/sudoers.local>
-from F</etc/sudoers> we would use the following line in F</etc/sudoers>:
+from within F</etc/sudoers> we would use the following line in F</etc/sudoers>:
 
  #include /etc/sudoers.local
 
@@ -458,6 +458,13 @@ F</etc/sudoers> will be processed.  Files that are included may
 themselves include other files.  A hard limit of 128 nested include
 files is enforced to prevent include file loops.
 
+The filename may include the C<%h> escape, signifying the short form
+of the hostname.  I.e., if the machine's hostname is "xerxes", then
+
+ #include /etc/sudoers.%h
+
+will cause B<sudo> to include the file F</etc/sudoers.xerxes>.
+
 =head2 Other special characters and reserved words
 
 The pound sign ('#') is used to indicate a comment (unless it is
diff --git a/toke.l b/toke.l
index 23be98c4bd176d5e0f533924beb07916b400f3b6..90a5100b4bab0be209fe40e1a50ecb3d66a46dee 100644 (file)
--- a/toke.l
+++ b/toke.l
@@ -671,22 +671,43 @@ parse_include(base)
     char *base;
 {
     char *cp, *ep, *path;
-    int len;
+    int len = 0, subst = 0;
+    size_t shost_len = 0;
 
     /* Pull out path from #include line. */
     cp = base + sizeof("#include");
     while (isblank((unsigned char) *cp))
        cp++;
     ep = cp;
-    while (*ep != '\0' && !isspace((unsigned char) *ep))
+    while (*ep != '\0' && !isspace((unsigned char) *ep)) {
+       if (ep[0] == '%' && ep[1] == 'h') {
+           shost_len = strlen(user_shost);
+           len += shost_len - 2;
+           subst = 1;
+       }
        ep++;
+    }
 
     /* Make a copy of path and return it. */
-    len = (int)(ep - cp);
+    len += (int)(ep - cp);
     if ((path = malloc(len + 1)) == NULL)
        yyerror("unable to allocate memory");
-    memcpy(path, cp, len);
-    path[len] = '\0';
+    if (subst) {
+       /* substitute for %h */
+       char *pp = path;
+       while (cp < ep) {
+           if (cp[0] == '%' && cp[1] == 'h') {
+               memcpy(pp, user_shost, shost_len);
+               pp += shost_len;
+               cp += 2;
+           }
+           *pp++ = *cp++;
+       }
+       *pp = '\0';
+    } else {
+       memcpy(path, cp, len);
+       path[len] = '\0';
+    }
 
     /* Push any excess characters (e.g. comment, newline) back to the lexer */
     if (*ep != '\0')
index 235179f1643143495c1b95c37672708fb961e809..bbb97a8279261b47b746429871e1d844c802fcff 100644 (file)
--- a/visudo.c
+++ b/visudo.c
@@ -105,6 +105,7 @@ struct sudoersfile {
 static RETSIGTYPE quit         __P((int));
 static char *get_args          __P((char *));
 static char *get_editor                __P((char **));
+static void get_hostname       __P((void));
 static char whatnow            __P((void));
 static int check_aliases       __P((int));
 static int check_syntax                __P((char *, int, int));
@@ -195,9 +196,10 @@ main(argc, argv)
     sudo_setgrent();
 
     /* Mock up a fake sudo_user struct. */
-    user_host = user_shost = user_cmnd = "";
+    user_cmnd = "";
     if ((sudo_user.pw = sudo_getpwuid(getuid())) == NULL)
        errorx(1, "you don't exist in the passwd database");
+    get_hostname();
 
     /* Setup defaults data structures. */
     init_defaults();
@@ -908,6 +910,30 @@ get_args(cmnd)
     return(*args ? args : NULL);
 }
 
+/*
+ * Look up the hostname and set user_host and user_shost.
+ */
+static void
+get_hostname()
+{
+    char *p, thost[MAXHOSTNAMELEN + 1];
+
+    if (gethostname(thost, sizeof(thost)) != 0) {
+       user_host = user_shost = "localhost";
+       return;
+    }
+    thost[sizeof(thost) - 1] = '\0';
+    user_host = estrdup(thost);
+
+    if ((p = strchr(user_host, '.'))) {
+       *p = '\0';
+       user_shost = estrdup(user_host);
+       *p = '.';
+    } else {
+       user_shost = user_host;
+    }
+}
+
 /*
  * Iterate through the sudoers datastructures looking for undefined
  * aliases or unused aliases.