]> granicus.if.org Git - sudo/commitdiff
When trying to determine the tty, fall back on /proc/ppid/fd/{0,1,2}
authorTodd C. Miller <Todd.Miller@courtesan.com>
Thu, 12 Jan 2012 20:17:30 +0000 (15:17 -0500)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Thu, 12 Jan 2012 20:17:30 +0000 (15:17 -0500)
if the main process's fds 0-2 are not hooked up to a tty.
On BSD, use the KERN_PROC_PID sysctl() instead.

--HG--
branch : 1.7

config.h.in
configure
configure.in
sudo.c

index f3413479a1ed45b3c68ea2fc9e34de9c5a5043ac..c796855bcdc474397ffcbcf552a89f242649a432 100644 (file)
 /* Define to 1 if the system has the type `struct in6_addr'. */
 #undef HAVE_STRUCT_IN6_ADDR
 
+/* Define to 1 if `ki_tdev' is a member of `struct kinfo_proc'. */
+#undef HAVE_STRUCT_KINFO_PROC_KI_TDEV
+
+/* Define to 1 if `kp_eproc.e_tdev' is a member of `struct kinfo_proc'. */
+#undef HAVE_STRUCT_KINFO_PROC_KP_EPROC_E_TDEV
+
+/* Define to 1 if `p_tdev' is a member of `struct kinfo_proc'. */
+#undef HAVE_STRUCT_KINFO_PROC_P_TDEV
+
 /* Define to 1 if the system has the type `struct timespec'. */
 #undef HAVE_STRUCT_TIMESPEC
 
index 8c19e5c09910630d584ca58f29f0e42c07ecc86f..64d074f5647bb47691888f0d600654fc4d0e57d3 100755 (executable)
--- a/configure
+++ b/configure
@@ -16145,7 +16145,7 @@ fi
 done
 
 
-for ac_func in sysctl getutxid getutid
+for ac_func in getutxid getutid
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
 done
 
 
+for ac_func in sysctl
+do :
+  ac_fn_c_check_func "$LINENO" "sysctl" "ac_cv_func_sysctl"
+if test "x$ac_cv_func_sysctl" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_SYSCTL 1
+_ACEOF
+ ac_fn_c_check_member "$LINENO" "struct kinfo_proc" "ki_tdev" "ac_cv_member_struct_kinfo_proc_ki_tdev" "
+       #include <sys/param.h>
+       #include <sys/sysctl.h>
+       #include <sys/user.h>
+
+"
+if test "x$ac_cv_member_struct_kinfo_proc_ki_tdev" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_KINFO_PROC_KI_TDEV 1
+_ACEOF
+
+
+else
+
+       ac_fn_c_check_member "$LINENO" "struct kinfo_proc" "kp_eproc.e_tdev" "ac_cv_member_struct_kinfo_proc_kp_eproc_e_tdev" "
+           #include <sys/param.h>
+           #include <sys/sysctl.h>
+
+"
+if test "x$ac_cv_member_struct_kinfo_proc_kp_eproc_e_tdev" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_KINFO_PROC_KP_EPROC_E_TDEV 1
+_ACEOF
+
+
+else
+
+           ac_fn_c_check_member "$LINENO" "struct kinfo_proc" "p_tdev" "ac_cv_member_struct_kinfo_proc_p_tdev" "
+               #include <sys/param.h>
+               #include <sys/sysctl.h>
+
+"
+if test "x$ac_cv_member_struct_kinfo_proc_p_tdev" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_KINFO_PROC_P_TDEV 1
+_ACEOF
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+done
+
+
 for ac_func in openpty
 do :
   ac_fn_c_check_func "$LINENO" "openpty" "ac_cv_func_openpty"
index ccce9ba9c5ccdcf26e04d1a2f347d182e3bd4856..1fff132504859b340e3390984e6c25e5a423c25f 100644 (file)
@@ -2022,7 +2022,28 @@ AC_CHECK_FUNCS(setsid, [], [
     AC_FUNC_SETPGRP
 ])
 
-AC_CHECK_FUNCS(sysctl getutxid getutid, [break])
+AC_CHECK_FUNCS(getutxid getutid, [break])
+
+AC_CHECK_FUNCS(sysctl, [AC_CHECK_MEMBERS([struct kinfo_proc.ki_tdev], 
+    [],
+    [
+       AC_CHECK_MEMBERS([struct kinfo_proc.kp_eproc.e_tdev], [], [
+           AC_CHECK_MEMBERS([struct kinfo_proc.p_tdev], [], [], [
+               #include <sys/param.h>
+               #include <sys/sysctl.h>
+           ])
+       ],
+       [
+           #include <sys/param.h>
+           #include <sys/sysctl.h>
+       ])
+    ],
+    [
+       #include <sys/param.h>
+       #include <sys/sysctl.h>
+       #include <sys/user.h>
+    ])
+])
 
 AC_CHECK_FUNCS(openpty, [AC_CHECK_HEADERS(libutil.h util.h pty.h, [break])], [
     AC_CHECK_LIB(util, openpty, [
diff --git a/sudo.c b/sudo.c
index 287f551afdfb81d3d3bd49ee944402d9f690e94a..bdd64df44157f145bf0c8a827057fc40a0189c47 100644 (file)
--- a/sudo.c
+++ b/sudo.c
 #ifdef HAVE_MBR_CHECK_MEMBERSHIP
 # include <membership.h>
 #endif
+#if defined(HAVE_STRUCT_KINFO_PROC_P_TDEV) || defined (HAVE_STRUCT_KINFO_PROC_KP_EPROC_E_TDEV)
+# include <sys/sysctl.h>
+#else
+# if defined(HAVE_STRUCT_KINFO_PROC_KI_TDEV)
+#  include <sys/sysctl.h>
+#  include <sys/user.h>
+# endif
+#endif
 
 #include "sudo.h"
 #include "lbuf.h"
@@ -574,6 +582,118 @@ main(argc, argv, envp)
     exit(0);   /* not reached */
 }
 
+/*
+ * How to access the tty device number in struct kinfo_proc.
+ */
+#if defined(HAVE_STRUCT_KINFO_PROC_KP_EPROC_E_TDEV)
+# define sudo_kp_tdev          kp_eproc.e_tdev
+# define sudo_kp_namelen       4
+#else
+# if defined(HAVE_STRUCT_KINFO_PROC_KI_TDEV)
+#  define sudo_kp_tdev         ki_tdev
+#  define sudo_kp_namelen      4
+# else
+#  if defined(HAVE_STRUCT_KINFO_PROC_P_TDEV)
+#   define sudo_kp_tdev                p_tdev
+#   define sudo_kp_namelen     6
+#  endif
+# endif
+#endif
+
+#ifdef sudo_kp_tdev
+/*
+ * 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 sysctl using the current pid, then the parent's pid.
+ * Falls back on ttyname of std{in,out,err} if that fails.
+ */
+static char *
+get_process_tty(void)
+{
+    char *tty = NULL;
+    struct kinfo_proc *ki_proc = NULL;
+    size_t size = sizeof(*ki_proc);
+    int i, mib[6], rc;
+
+    /*
+     * Lookup tty for this process and, failing that, our parent.
+     * Even if we redirect std{in,out,err} the kernel should still know.
+     */
+    for (i = 0; tty == NULL && i < 2; i++) {
+       mib[0] = CTL_KERN;
+       mib[1] = KERN_PROC;
+       mib[2] = KERN_PROC_PID;
+       mib[3] = i ? (int)getppid() : (int)getpid();
+       mib[4] = sizeof(*ki_proc);
+       mib[5] = 1;
+       do {
+           size += size / 10;
+           ki_proc = erealloc(ki_proc, size);
+           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 != '#') {
+               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);
+               }
+           }
+       }
+       efree(ki_proc);
+    }
+
+    /* 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);
+    }
+
+    return 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 (or its
+ * parent).  First tries std{in,out,err} then falls back to the parent's /proc
+ * entry.  We could try following the parent all the way to pid 1 but
+ * /proc/%d/status is system-specific (text on Linux, a struct on Solaris).
+ */
+static char *
+get_process_tty(void)
+{
+    char path[PATH_MAX], *tty = NULL;
+    pid_t ppid;
+    int i, fd;
+
+    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/%d/fd/%d", ppid, i);
+           fd = open(path, O_RDONLY|O_NOCTTY, 0);
+           if (fd != -1) {
+               tty = ttyname(fd);
+               close(fd);
+           }
+       }
+    }
+
+    return estrdup(tty);
+}
+#endif /* sudo_kp_tdev */
+
 /*
  * Initialize timezone, set umask, fill in ``sudo_user'' struct and
  * load the ``interfaces'' array.
@@ -619,9 +739,8 @@ init_vars(envp)
        }
     }
 
-    if ((p = ttyname(STDIN_FILENO)) || (p = ttyname(STDOUT_FILENO)) ||
-       (p = ttyname(STDERR_FILENO))) {
-       user_tty = user_ttypath = estrdup(p);
+    if ((p = get_process_tty()) != NULL) {
+       user_tty = user_ttypath = p;
        if (strncmp(user_tty, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
            user_tty += sizeof(_PATH_DEV) - 1;
     } else