]> granicus.if.org Git - sudo/commitdiff
Use the expanded io log dir when updating the sequence number.
authorTodd C. Miller <Todd.Miller@courtesan.com>
Fri, 15 Jun 2012 16:33:12 +0000 (12:33 -0400)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Fri, 15 Jun 2012 16:33:12 +0000 (12:33 -0400)
Includes a workaround for older versions of sudo where the
sequence number was stored in the unexpanded io log dir.

plugins/sudoers/iolog.c
plugins/sudoers/iolog_path.c
plugins/sudoers/regress/iolog_path/check_iolog_path.c
plugins/sudoers/sudoers.h

index 1782d4f549c1151ce94c49c463d91c025a9aaec6..3047a03389d84d4a9ea965dbac9d5c1494f0964f 100644 (file)
@@ -135,7 +135,7 @@ mkdir_parents(char *path)
  * Uses file locking to avoid sequence number collisions.
  */
 void
-io_nextid(char *iolog_dir, char sessid[7])
+io_nextid(char *iolog_dir, char *iolog_dir_fallback, char sessid[7])
 {
     struct stat sb;
     char buf[32], *ep;
@@ -172,14 +172,41 @@ io_nextid(char *iolog_dir, char sessid[7])
        log_fatal(USE_ERRNO, _("unable to open %s"), pathbuf);
     lock_file(fd, SUDO_LOCK);
 
-    /* Read seq number (base 36). */
-    nread = read(fd, buf, sizeof(buf));
-    if (nread != 0) {
-       if (nread == -1)
-           log_fatal(USE_ERRNO, _("unable to read %s"), pathbuf);
-       id = strtoul(buf, &ep, 36);
-       if (buf == ep || id >= SESSID_MAX)
-           log_fatal(0, _("invalid sequence number %s"), pathbuf);
+    /*
+     * If there is no seq file in iolog_dir and a fallback dir was
+     * specified, look for seq in the fallback dir.  This is to work
+     * around a bug in sudo 1.8.5 and older where iolog_dir was not
+     * expanded before the sequence number was updated.
+     */
+    if (iolog_dir_fallback != NULL && fstat(fd, &sb) == 0 && sb.st_size == 0) {
+       char fallback[PATH_MAX];
+
+       len = snprintf(fallback, sizeof(fallback), "%s/seq",
+           iolog_dir_fallback);
+       if (len > 0 && len < sizeof(fallback)) {
+           int fd2 = open(fallback, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
+           if (fd2 != -1) {
+               nread = read(fd2, buf, sizeof(buf));
+               if (nread > 0) {
+                   id = strtoul(buf, &ep, 36);
+                   if (buf == ep || id >= SESSID_MAX)
+                       id = 0;
+               }
+               close(fd2);
+           }
+       }
+    }
+
+    /* Read current seq number (base 36). */
+    if (id == 0) {
+       nread = read(fd, buf, sizeof(buf));
+       if (nread != 0) {
+           if (nread == -1)
+               log_fatal(USE_ERRNO, _("unable to read %s"), pathbuf);
+           id = strtoul(buf, &ep, 36);
+           if (buf == ep || id >= SESSID_MAX)
+               log_fatal(0, _("invalid sequence number %s"), pathbuf);
+       }
     }
     id++;
 
@@ -476,7 +503,7 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation,
        /* Get next session ID and convert it into a path. */
        tofree = emalloc(sizeof(_PATH_SUDO_IO_LOGDIR) + sizeof(sessid) + 2);
        memcpy(tofree, _PATH_SUDO_IO_LOGDIR, sizeof(_PATH_SUDO_IO_LOGDIR));
-       io_nextid(tofree, sessid);
+       io_nextid(tofree, NULL, sessid);
        snprintf(tofree + sizeof(_PATH_SUDO_IO_LOGDIR), sizeof(sessid) + 2,
            "%c%c/%c%c/%c%c", sessid[0], sessid[1], sessid[2], sessid[3],
            sessid[4], sessid[5]);
index 154705d491da0df628a28ffc69e6563d9e47b88b..71030e4b555a335e89344960f56a910577e367a8 100644 (file)
 
 struct path_escape {
     const char *name;
-    size_t (*copy_fn)(char *, size_t);
+    size_t (*copy_fn)(char *, size_t, char *);
 };
 
-static size_t fill_seq(char *, size_t);
-static size_t fill_user(char *, size_t);
-static size_t fill_group(char *, size_t);
-static size_t fill_runas_user(char *, size_t);
-static size_t fill_runas_group(char *, size_t);
-static size_t fill_hostname(char *, size_t);
-static size_t fill_command(char *, size_t);
+static size_t fill_seq(char *, size_t, char *);
+static size_t fill_user(char *, size_t, char *);
+static size_t fill_group(char *, size_t, char *);
+static size_t fill_runas_user(char *, size_t, char *);
+static size_t fill_runas_group(char *, size_t, char *);
+static size_t fill_hostname(char *, size_t, char *);
+static size_t fill_command(char *, size_t, char *);
 
-static struct path_escape escapes[] = {
+/* Note: "seq" must be first in the list. */
+static struct path_escape io_path_escapes[] = {
     { "seq", fill_seq },
     { "user", fill_user },
     { "group", fill_group },
@@ -69,14 +70,14 @@ static struct path_escape escapes[] = {
 };
 
 static size_t
-fill_seq(char *str, size_t strsize)
+fill_seq(char *str, size_t strsize, char *logdir)
 {
     static char sessid[7];
     int len;
     debug_decl(sudoers_io_version, SUDO_DEBUG_UTIL)
 
     if (sessid[0] == '\0')
-       io_nextid(def_iolog_dir, sessid);
+       io_nextid(logdir, def_iolog_dir, sessid);
 
     /* Path is of the form /var/log/sudo-io/00/00/01. */
     len = snprintf(str, strsize, "%c%c/%c%c/%c%c", sessid[0],
@@ -87,14 +88,14 @@ fill_seq(char *str, size_t strsize)
 }
 
 static size_t
-fill_user(char *str, size_t strsize)
+fill_user(char *str, size_t strsize, char *unused)
 {
     debug_decl(fill_user, SUDO_DEBUG_UTIL)
     debug_return_size_t(strlcpy(str, user_name, strsize));
 }
 
 static size_t
-fill_group(char *str, size_t strsize)
+fill_group(char *str, size_t strsize, char *unused)
 {
     struct group *grp;
     size_t len;
@@ -112,14 +113,14 @@ fill_group(char *str, size_t strsize)
 }
 
 static size_t
-fill_runas_user(char *str, size_t strsize)
+fill_runas_user(char *str, size_t strsize, char *unused)
 {
     debug_decl(fill_runas_user, SUDO_DEBUG_UTIL)
     debug_return_size_t(strlcpy(str, runas_pw->pw_name, strsize));
 }
 
 static size_t
-fill_runas_group(char *str, size_t strsize)
+fill_runas_group(char *str, size_t strsize, char *unused)
 {
     struct group *grp;
     size_t len;
@@ -141,14 +142,14 @@ fill_runas_group(char *str, size_t strsize)
 }
 
 static size_t
-fill_hostname(char *str, size_t strsize)
+fill_hostname(char *str, size_t strsize, char *unused)
 {
     debug_decl(fill_hostname, SUDO_DEBUG_UTIL)
     debug_return_size_t(strlcpy(str, user_shost, strsize));
 }
 
 static size_t
-fill_command(char *str, size_t strsize)
+fill_command(char *str, size_t strsize, char *unused)
 {
     debug_decl(fill_command, SUDO_DEBUG_UTIL)
     debug_return_size_t(strlcpy(str, user_base, strsize));
@@ -165,7 +166,9 @@ expand_iolog_path(const char *prefix, const char *dir, const char *file,
 {
     size_t len, prelen = 0;
     char *dst, *dst0, *path, *pathend, tmpbuf[PATH_MAX];
+    char *slash = NULL;
     const char *endbrace, *src = dir;
+    static struct path_escape *escapes;
     int pass;
     bool strfit;
     debug_decl(expand_iolog_path, SUDO_DEBUG_UTIL)
@@ -193,17 +196,20 @@ expand_iolog_path(const char *prefix, const char *dir, const char *file,
        switch (pass) {
        case 0:
            src = dir;
+           escapes = io_path_escapes + 1; /* skip "${seq}" */
            break;
        case 1:
            /* Trim trailing slashes from dir component. */
            while (dst - path - 1 > prelen && dst[-1] == '/')
                dst--;
-           if (slashp)
-               *slashp = dst;
-           src = "/";
-           break;
+           /* The NUL will be replaced with a '/' at the end. */
+           if (dst + 1 >= pathend)
+               goto bad;
+           slash = dst++;
+           continue;
        case 2:
            src = file;
+           escapes = io_path_escapes;
            break;
        }
        dst0 = dst;
@@ -220,7 +226,8 @@ expand_iolog_path(const char *prefix, const char *dir, const char *file,
                                break;
                        }
                        if (esc->name != NULL) {
-                           len = esc->copy_fn(dst, (size_t)(pathend - dst));
+                           len = esc->copy_fn(dst, (size_t)(pathend - dst),
+                               path + prelen);
                            if (len >= (size_t)(pathend - dst))
                                goto bad;
                            dst += len;
@@ -275,6 +282,9 @@ expand_iolog_path(const char *prefix, const char *dir, const char *file,
            *dst = '\0';
        }
     }
+    if (slashp)
+       *slashp = slash;
+    *slash = '/';
 
     debug_return_str(path);
 bad:
index f8079adb11337fe2dd218ef1909a6470ac45d8bd..374b5fb90e81a80659efda01860c66edb6c17516 100644 (file)
@@ -200,7 +200,7 @@ main(int argc, char *argv[])
     exit(errors);
 }
 
-void io_nextid(char *iolog_dir, char id[7])
+void io_nextid(char *iolog_dir, char *fallback, char id[7])
 {
     memcpy(id, sessid, sizeof(sessid));
 }
index 420742d0b10a3cb4a3f7794b7c5f72f631eac77a..b0152b851367186404370d8c7388dd92ab241a3b 100644 (file)
@@ -296,7 +296,7 @@ int atobool(const char *str);
 int get_boottime(struct timeval *);
 
 /* iolog.c */
-void io_nextid(char *iolog_dir, char sessid[7]);
+void io_nextid(char *iolog_dir, char *iolog_dir_fallback, char sessid[7]);
 
 /* iolog_path.c */
 char *expand_iolog_path(const char *prefix, const char *dir, const char *file,