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"
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, [
#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"
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.
}
}
- 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