]> granicus.if.org Git - sudo/commitdiff
Rototill code to determine the tty. For Linux, we now look up the
authorTodd C. Miller <Todd.Miller@courtesan.com>
Wed, 11 Apr 2012 18:48:08 +0000 (14:48 -0400)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Wed, 11 Apr 2012 18:48:08 +0000 (14:48 -0400)
tty device in /proc/pid/stat instead of trying to open /proc/pid/fd/[0-2].
The sudo_ttyname_dev() function maps the given device number to a
string.  On BSD, we can use devname().  On Solaris, _ttyname_dev()
does what we want.
TODO: write /dev/ traversal code for the generic sudo_ttyname_dev().

config.h.in
configure
configure.in
src/ttyname.c

index 05f14b5fc6477ea088f93fb679e86586c2b50e74..0574a4df73a692362e113f0b9a9820ab543d3bf7 100644 (file)
 /* Define to 1 if you have the `_innetgr' function. */
 #undef HAVE__INNETGR
 
+/* Define to 1 if you have the `_ttyname_dev' function. */
+#undef HAVE__TTYNAME_DEV
+
 /* Define to 1 if the compiler supports the C99 __func__ variable. */
 #undef HAVE___FUNC__
 
index 134c19d6fbfb8ba695a66b453848781068b4ce07..aa3cd3041aa08156d86164d18ee1d049dd6e5849 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.68 for sudo 1.8.5.
+# Generated by GNU Autoconf 2.68 for sudo 1.8.5b8.
 #
 # Report bugs to <http://www.sudo.ws/bugs/>.
 #
@@ -570,8 +570,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='sudo'
 PACKAGE_TARNAME='sudo'
-PACKAGE_VERSION='1.8.5'
-PACKAGE_STRING='sudo 1.8.5'
+PACKAGE_VERSION='1.8.5b8'
+PACKAGE_STRING='sudo 1.8.5b8'
 PACKAGE_BUGREPORT='http://www.sudo.ws/bugs/'
 PACKAGE_URL=''
 
@@ -1447,7 +1447,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures sudo 1.8.5 to adapt to many kinds of systems.
+\`configure' configures sudo 1.8.5b8 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1512,7 +1512,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of sudo 1.8.5:";;
+     short | recursive ) echo "Configuration of sudo 1.8.5b8:";;
    esac
   cat <<\_ACEOF
 
@@ -1730,7 +1730,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-sudo configure 1.8.5
+sudo configure 1.8.5b8
 generated by GNU Autoconf 2.68
 
 Copyright (C) 2010 Free Software Foundation, Inc.
@@ -2434,7 +2434,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by sudo $as_me 1.8.5, which was
+It was created by sudo $as_me 1.8.5b8, which was
 generated by GNU Autoconf 2.68.  Invocation command line was
 
   $ $0 $@
@@ -15271,6 +15271,16 @@ cat >>confdefs.h <<_ACEOF
 #define HAVE_STRUCT_PSINFO_PR_TTYDEV 1
 _ACEOF
 
+for ac_func in _ttyname_dev
+do :
+  ac_fn_c_check_func "$LINENO" "_ttyname_dev" "ac_cv_func__ttyname_dev"
+if test "x$ac_cv_func__ttyname_dev" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE__TTYNAME_DEV 1
+_ACEOF
+
+fi
+done
 
 fi
 
@@ -20608,7 +20618,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by sudo $as_me 1.8.5, which was
+This file was extended by sudo $as_me 1.8.5b8, which was
 generated by GNU Autoconf 2.68.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -20674,7 +20684,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-sudo config.status 1.8.5
+sudo config.status 1.8.5b8
 configured by $0, generated by GNU Autoconf 2.68,
   with options \\"\$ac_cs_config\\"
 
index bedf548ad3fc4355365a550962ffeceec17073b7..1cbc836648222267a06fdc9837abe9b4eae26a11 100644 (file)
@@ -3,7 +3,7 @@ dnl Process this file with GNU autoconf to produce a configure script.
 dnl
 dnl Copyright (c) 1994-1996,1998-2012 Todd C. Miller <Todd.Miller@courtesan.com>
 dnl
-AC_INIT([sudo], [1.8.5], [http://www.sudo.ws/bugs/], [sudo])
+AC_INIT([sudo], [1.8.5b8], [http://www.sudo.ws/bugs/], [sudo])
 AC_CONFIG_HEADER([config.h pathnames.h])
 dnl
 dnl Note: this must come after AC_INIT
@@ -2007,7 +2007,7 @@ AC_HEADER_DIRENT
 AC_HEADER_TIME
 AC_HEADER_STDBOOL
 AC_CHECK_HEADERS(malloc.h netgroup.h paths.h spawn.h utime.h utmpx.h sys/sockio.h sys/bsdtypes.h sys/select.h sys/stropts.h sys/sysmacros.h)
-AC_CHECK_HEADERS([procfs.h] [sys/procfs.h], [AC_CHECK_MEMBERS(struct psinfo.pr_ttydev, [], [], [AC_INCLUDES_DEFAULT
+AC_CHECK_HEADERS([procfs.h] [sys/procfs.h], [AC_CHECK_MEMBERS(struct psinfo.pr_ttydev, [AC_CHECK_FUNCS(_ttyname_dev)], [], [AC_INCLUDES_DEFAULT
 #ifdef HAVE_PROCFS_H
 #include <procfs.h>
 #endif
index 395cba8233e9ec37aacf86feb7909ffbdd08e2a6..f7d119082e7f7e12840470957be5aecd97ed54f9 100644 (file)
@@ -51,6 +51,7 @@
 #endif /* HAVE_UNISTD_H */
 #include <errno.h>
 #include <fcntl.h>
+#include <limits.h>
 #if defined(HAVE_STRUCT_KINFO_PROC_P_TDEV) || defined (HAVE_STRUCT_KINFO_PROC_KP_EPROC_E_TDEV) || defined(HAVE_STRUCT_KINFO_PROC2_P_TDEV)
 # include <sys/sysctl.h>
 #elif defined(HAVE_STRUCT_KINFO_PROC_KI_TDEV)
 # define sudo_kp_namelen       4
 #endif
 
+#if defined(sudo_kp_tdev)
+/*
+ * Like ttyname() but uses a dev_t instead of an open fd.
+ * Caller is responsible for freeing the returned string.
+ * The BSD version uses devname()
+ */
+static char *
+sudo_ttyname_dev(dev_t tdev)
+{
+    char *dev, *tty = NULL;
+    debug_decl(sudo_ttyname_dev, SUDO_DEBUG_UTIL)
+
+    /* Some versions of devname() return NULL on failure, others do not. */
+    dev = devname(tdev, S_IFCHR);
+    if (dev != NULL && *dev != '?' && *dev != '#') {
+       if (*dev != '/') {
+           /* devname() doesn't use the /dev/ prefix, add one... */
+           size_t len = sizeof(_PATH_DEV) + strlen(dev);
+           tty = emalloc(len);
+           strlcpy(tty, _PATH_DEV, len);
+           strlcat(tty, dev, len);
+       } else {
+           /* Should not happen but just in case... */
+           tty = estrdup(dev);
+       }
+    }
+    debug_return_str(tty);
+}
+#elif defined(HAVE__TTYNAME_DEV)
+extern char *_ttyname_dev(dev_t rdev, char *buffer, size_t buflen);
+
+/*
+ * Like ttyname() but uses a dev_t instead of an open fd.
+ * Caller is responsible for freeing the returned string.
+ * This version is just a wrapper around _ttyname_dev().
+ */
+static char *
+sudo_ttyname_dev(dev_t tdev)
+{
+    char buf[TTYNAME_MAX], *tty;
+    struct stat sb;
+    debug_decl(sudo_ttyname_dev, SUDO_DEBUG_UTIL)
+
+    /* Check if it is a pseudo-tty slave, falling back on _ttyname_dev() */
+    (void)snprintf(buf, sizeof(buf), "%spts/%u", _PATH_DEV,
+       (unsigned int)minor(tdev));
+    if (stat(buf, &sb) == 0 && sb.st_rdev == tdev) {
+       tty = buf;
+    } else {
+       tty = _ttyname_dev(tdev, buf, sizeof(buf));
+    }
+
+    debug_return_str(estrdup(tty));
+}
+#else
+/*
+ * Like ttyname() but uses a dev_t instead of an open fd.
+ * Caller is responsible for freeing the returned string.
+ * Generic version.
+ */
+static char *
+sudo_ttyname_dev(dev_t tdev)
+{
+    char buf[PATH_MAX], *tty = NULL;
+    struct stat sb;
+    debug_decl(sudo_ttyname_dev, SUDO_DEBUG_UTIL)
+
+    /* First, check if it is a pseudo-tty slave. */
+    (void)snprintf(buf, sizeof(buf), "%spts/%u", _PATH_DEV,
+       (unsigned int)minor(tdev));
+    if (stat(buf, &sb) == 0 && sb.st_rdev == tdev) {
+       tty = buf;
+    } else {
+       /* XXX - fallback to scanning /dev/ */
+    }
+
+    debug_return_str(estrdup(tty));
+}
+#endif
+
 #if defined(sudo_kp_tdev)
 /*
  * Return a string from ttyname() containing the tty to which the process is
@@ -123,21 +204,13 @@ get_process_ttyname(void)
            rc = sysctl(mib, sudo_kp_namelen, ki_proc, &size, NULL, 0);
        } while (rc == -1 && errno == ENOMEM);
        if (rc != -1) {
-           char *dev = devname(ki_proc->sudo_kp_tdev, S_IFCHR);
-           /* Some versions of devname() return NULL, others do not. */
-           if (dev == NULL || *dev == '?' || *dev == '#') {
-               sudo_debug_printf(SUDO_DEBUG_WARN,
-                   "unable to map device number %u to name",
-                   ki_proc->sudo_kp_tdev);
-           } else if (*dev != '/') {
-               /* devname() doesn't use the /dev/ prefix, add one... */
-               size_t len = sizeof(_PATH_DEV) + strlen(dev);
-               tty = emalloc(len);
-               strlcpy(tty, _PATH_DEV, len);
-               strlcat(tty, dev, len);
-           } else {
-               /* Should not happen but just in case... */
-               tty = estrdup(dev);
+           if (ki_proc->sudo_kp_tdev != (dev_t)-1) {
+               tty = sudo_ttyname_dev(ki_proc->sudo_kp_tdev);
+               if (tty == NULL) {
+                   sudo_debug_printf(SUDO_DEBUG_WARN,
+                       "unable to map device number %u to name",
+                       ki_proc->sudo_kp_tdev);
+               }
            }
        } else {
            sudo_debug_printf(SUDO_DEBUG_WARN,
@@ -157,14 +230,11 @@ get_process_ttyname(void)
     debug_return_str(tty);
 }
 #elif defined(HAVE_STRUCT_PSINFO_PR_TTYDEV)
-# ifndef PRNODEV
-#  define PRNODEV      ((dev_t)-1)
-# endif
 /*
  * Return a string from ttyname() containing the tty to which the process is
  * attached or NULL if there is no tty associated with the process (or its
- * parent).  First tries std{in,out,err} then falls back to our /proc entry,
- * or our parent's if that doesn't work.
+ * parent).  First tries /proc/pid/psinfo, then /proc/ppid/psinfo.
+ * Falls back on ttyname of std{in,out,err} if that fails.
  */
 char *
 get_process_ttyname(void)
@@ -176,68 +246,100 @@ get_process_ttyname(void)
     int i, fd;
     debug_decl(get_process_ttyname, SUDO_DEBUG_UTIL)
 
-    if ((tty = ttyname(STDIN_FILENO)) == NULL &&
-       (tty = ttyname(STDOUT_FILENO)) == NULL &&
-       (tty = ttyname(STDERR_FILENO)) == NULL) {
-       /*
-        * No tty hooked up to std{in,out,err}, check /proc.
-        * We try to map pr_ttydev in psinfo to /dev/pts/N
-        */
-       for (i = 0; tty == NULL && i < 2; i++) {
-           snprintf(path, sizeof(path), "/proc/%u/psinfo",
-               i ? (unsigned int)getppid() : (unsigned int)getpid());
-           if ((fd = open(path, O_RDONLY, 0)) == -1)
-               continue;
-           nread = read(fd, &psinfo, sizeof(psinfo));
-           close(fd);
-           if (nread != (ssize_t)sizeof(psinfo) || psinfo.pr_ttydev == PRNODEV)
-               continue;
-           (void)snprintf(path, sizeof(path), "%spts/%u", _PATH_DEV,
-               (unsigned int)minor(psinfo.pr_ttydev));
-           if (stat(path, &sb) == 0 && sb.st_rdev == psinfo.pr_ttydev) {
-               fd = open(path, O_RDONLY|O_NOCTTY|O_NONBLOCK, 0);
-               if (fd != -1) {
-                   tty = ttyname(fd);
-                   close(fd);
-               }
-           }
+    /* Try to determine the tty from pr_ttydev in /proc/pid/psinfo. */
+    for (i = 0; tty == NULL && i < 2; i++) {
+       (void)snprintf(path, sizeof(path), "/proc/%u/psinfo",
+           i ? (unsigned int)getppid() : (unsigned int)getpid());
+       if ((fd = open(path, O_RDONLY, 0)) == -1)
+           continue;
+       nread = read(fd, &psinfo, sizeof(psinfo));
+       close(fd);
+       if (nread == (ssize_t)sizeof(psinfo) && psinfo.pr_ttydev != (dev_t)-1) {
+           tty = sudo_ttyname_dev(psinfo.pr_ttydev);
        }
     }
 
-    debug_return_str(estrdup(tty));
+    /* If all else fails, fall back on ttyname(). */
+    if (tty == NULL) {
+       if ((tty = ttyname(STDIN_FILENO)) != NULL ||
+           (tty = ttyname(STDOUT_FILENO)) != NULL ||
+           (tty = ttyname(STDERR_FILENO)) != NULL)
+           tty = estrdup(tty);
+    }
+
+    debug_return_str(tty);
 }
-#else
+#elif defined(__linux__)
 /*
  * Return a string from ttyname() containing the tty to which the process is
  * attached or NULL if there is no tty associated with the process (or its
- * parent).  First tries std{in,out,err} then falls back to our parent's /proc
- * entry.
+ * parent).  First tries field 7 in /proc/pid/stat, then /proc/ppid/stat.
+ * Falls back on ttyname of std{in,out,err} if that fails.
  */
 char *
 get_process_ttyname(void)
 {
-    char path[PATH_MAX], *tty = NULL;
-    struct stat sb;
-    pid_t ppid;
-    int i, fd;
+    char *line = NULL, *tty = NULL;
+    size_t linesize = 0;
+    ssize_t len;
+    int i;
     debug_decl(get_process_ttyname, SUDO_DEBUG_UTIL)
 
-    if ((tty = ttyname(STDIN_FILENO)) == NULL &&
-       (tty = ttyname(STDOUT_FILENO)) == NULL &&
-       (tty = ttyname(STDERR_FILENO)) == NULL) {
-       /* No tty for child, check the parent via /proc. */
-       ppid = getppid();
-       for (i = STDIN_FILENO; i <= STDERR_FILENO && tty == NULL; i++) {
-           snprintf(path, sizeof(path), "/proc/%u/fd/%d",
-               (unsigned int)ppid, i);
-           fd = open(path, O_RDONLY|O_NOCTTY|O_NONBLOCK, 0);
-           if (fd != -1) {
-               tty = ttyname(fd);
-               close(fd);
+    /* Try to determine the tty from pr_ttydev in /proc/pid/psinfo. */
+    for (i = 0; tty == NULL && i < 2; i++) {
+       FILE *fp;
+       char path[PATH_MAX];
+       (void)snprintf(path, sizeof(path), "/proc/%u/stat",
+           i ? (unsigned int)getppid() : (unsigned int)getpid());
+       if ((fp = fopen(path, "r")) == NULL)
+           continue;
+       len = getline(&line, &linesize, fp);
+       fclose(fp);
+       if (len != -1) {
+           /* Field 7 is the tty dev (0 if no tty) */
+           char *cp = line;
+           int field = 1;
+           while (*cp != '\0') {
+               if (*cp++ == ' ') {
+                   if (++field == 7) {
+                       dev_t tdev = (dev_t)atoi(cp);
+                       if (tdev > 0)
+                           tty = sudo_ttyname_dev(tdev);
+                       break;
+                   }
+               }
            }
        }
     }
+    efree(line);
+
+    /* If all else fails, fall back on ttyname(). */
+    if (tty == NULL) {
+       if ((tty = ttyname(STDIN_FILENO)) != NULL ||
+           (tty = ttyname(STDOUT_FILENO)) != NULL ||
+           (tty = ttyname(STDERR_FILENO)) != NULL)
+           tty = estrdup(tty);
+    }
+
+    debug_return_str(tty);
+}
+#else
+/*
+ * Return a string from ttyname() containing the tty to which the process is
+ * attached or NULL if there is no tty associated with the process.
+ * parent).
+ */
+char *
+get_process_ttyname(void)
+{
+    char *tty;
+    debug_decl(get_process_ttyname, SUDO_DEBUG_UTIL)
+
+    if ((tty = ttyname(STDIN_FILENO)) == NULL) {
+       if ((tty = ttyname(STDOUT_FILENO)) == NULL)
+           tty = ttyname(STDERR_FILENO);
+    }
 
     debug_return_str(estrdup(tty));
 }
-#endif /* !sudo_kp_tdev && !HAVE_STRUCT_PSINFO_PR_TTYDEV */
+#endif