]> granicus.if.org Git - sudo/commitdiff
Store info from stat(2)ing the tty in the tty ticket when tty tickets
authorTodd C. Miller <Todd.Miller@courtesan.com>
Thu, 22 Apr 2010 14:16:18 +0000 (10:16 -0400)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Thu, 22 Apr 2010 14:16:18 +0000 (10:16 -0400)
are in use.  On most systems, this closes the loophole whereby a user
can log out of a tty, log back in and still have the timestamp be valid.

plugins/sudoers/check.c

index 84576ff993f06ff0ecb84aeab931b29a3fbd20a7..d30d59d33bd40e0c7732769c6e8b133c8769edf0 100644 (file)
 #define TS_MAKE_DIRS           1
 #define TS_REMOVE              2
 
+/*
+ * Info stored in tty ticket from stat(2) to help with tty matching.
+ */
+static struct tty_info {
+    dev_t dev;                 /* ID of device tty resides on */
+    dev_t rdev;                        /* tty device ID */
+    ino_t ino;                 /* tty inode number */
+    struct timeval ctime;      /* tty inode change time */
+} tty_info;
+
 static int   build_timestamp(char **, char **);
 static int   timestamp_status(char *, char *, char *, int);
 static char *expand_prompt(char *, char *, char *);
@@ -88,8 +98,28 @@ check_user(validated, mode)
     char *timestampdir = NULL;
     char *timestampfile = NULL;
     char *prompt;
+    struct stat sb;
     int status, rval = TRUE;
 
+    /* Stash the tty's ctime for tty ticket comparison. */
+    if (def_tty_tickets && user_ttypath && stat(user_ttypath, &sb) == 0) {
+       tty_info.dev = sb.st_dev;
+       tty_info.ino = sb.st_ino;
+       tty_info.rdev = sb.st_rdev;
+       ctim_get(&sb, &tty_info.ctime);
+       if (stat("/", &sb) == 0) {
+           /*
+            * If tty does not reside on root partition, we assume it lives
+            * on a devfs without real ctime values (FreeBSD, Mac OS X).
+            * XXX - would like a smarter way to check this.
+            */
+           if (sb.st_dev != tty_info.dev) {
+               tty_info.ctime.tv_sec = 0;
+               tty_info.ctime.tv_usec = 0;
+           }
+       }
+    }
+
     /* Always prompt for a password when -k was specified with the command. */
     if (ISSET(mode, MODE_IGNORE_TICKET)) {
        SET(validated, FLAG_CHECK_USER);
@@ -201,15 +231,19 @@ update_timestamp(timestampdir, timestampfile)
 {
     if (timestamp_uid != 0)
        set_perms(PERM_TIMESTAMP);
-    if (touch(-1, timestampfile ? timestampfile : timestampdir, NULL) == -1) {
-       if (timestampfile) {
-           int fd = open(timestampfile, O_WRONLY|O_CREAT|O_TRUNC, 0600);
-
-           if (fd == -1)
-               log_error(NO_EXIT|USE_ERRNO, "Can't open %s", timestampfile);
-           else
-               close(fd);
-       } else {
+    if (timestampfile) {
+       /*
+        * Store tty info in timestamp file
+        */
+       int fd = open(timestampfile, O_WRONLY|O_CREAT|O_TRUNC, 0600);
+       if (fd == -1)
+           log_error(NO_EXIT|USE_ERRNO, "Can't open %s", timestampfile);
+       else {
+           write(fd, &tty_info, sizeof(tty_info));
+           close(fd);
+       }
+    } else {
+       if (touch(-1, timestampdir, NULL) == -1) {
            if (mkdir(timestampdir, 0700) == -1)
                log_error(NO_EXIT|USE_ERRNO, "Can't mkdir %s", timestampdir);
        }
@@ -543,7 +577,22 @@ timestamp_status(timestampdir, timestampfile, user, flags)
                    if ((sb.st_mode & 0000777) != 0600)
                        (void) chmod(timestampfile, 0600);
 
-                   status = TS_OLD;    /* actually check mtime below */
+                   /*
+                    * Check for stored tty info.  If the file is zero-sized
+                    * it is an old-style timestamp with no tty info in it.
+                    * The actual mtime check is done later.
+                    */
+                   if (sb.st_size != 0) {
+                       struct tty_info info;
+                       int fd = open(timestampfile, O_RDONLY, 0644);
+                       if (fd != -1) {
+                           if (read(fd, &info, sizeof(info)) == sizeof(info) &&
+                               memcmp(&info, &tty_info, sizeof(info)) == 0) {
+                               status = TS_OLD;
+                           }
+                           close(fd);
+                       }
+                   }
                }
            }
        } else if (errno != ENOENT) {