From: Todd C. Miller Date: Tue, 10 Apr 2012 19:53:41 +0000 (-0400) Subject: Check for SVR4-style struct psinfo.pr_ttydev and use that to determine X-Git-Tag: SUDO_1_8_5~1^2~63 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=11f13be0dd9ab6325b174830708e3f7df0438aea;p=sudo Check for SVR4-style struct psinfo.pr_ttydev and use that to determine the tty if std{in,out,err} are not ttys. --- diff --git a/config.h.in b/config.h.in index 45211d83c..05f14b5fc 100644 --- a/config.h.in +++ b/config.h.in @@ -390,6 +390,9 @@ /* Define to 1 if you have the `priv_set' function. */ #undef HAVE_PRIV_SET +/* Define to 1 if you have the header file. */ +#undef HAVE_PROCFS_H + /* Define to 1 if you have the header file. */ #undef HAVE_PROJECT_H @@ -520,6 +523,9 @@ /* Define to 1 if `p_tdev' is a member of `struct kinfo_proc'. */ #undef HAVE_STRUCT_KINFO_PROC_P_TDEV +/* Define to 1 if `pr_ttydev' is a member of `struct psinfo'. */ +#undef HAVE_STRUCT_PSINFO_PR_TTYDEV + /* Define if your struct sockadr has an sa_len field. */ #undef HAVE_STRUCT_SOCKADDR_SA_LEN @@ -597,6 +603,9 @@ */ #undef HAVE_SYS_NDIR_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PROCFS_H + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SELECT_H diff --git a/configure b/configure index 7584a798b..134c19d6f 100755 --- a/configure +++ b/configure @@ -2150,6 +2150,63 @@ fi } # ac_fn_c_check_header_mongrel +# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES +# ---------------------------------------------------- +# Tries to find if the field MEMBER exists in type AGGR, after including +# INCLUDES, setting cache variable VAR accordingly. +ac_fn_c_check_member () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 +$as_echo_n "checking for $2.$3... " >&6; } +if eval \${$4+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$5 +int +main () +{ +static $2 ac_aggr; +if (ac_aggr.$3) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$4=yes" +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$5 +int +main () +{ +static $2 ac_aggr; +if (sizeof ac_aggr.$3) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$4=yes" +else + eval "$4=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$4 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_member + # ac_fn_c_compute_int LINENO EXPR VAR INCLUDES # -------------------------------------------- # Tries to find the compile-time value of EXPR in a program that includes @@ -2328,63 +2385,6 @@ rm -f conftest.val } # ac_fn_c_compute_int -# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES -# ---------------------------------------------------- -# Tries to find if the field MEMBER exists in type AGGR, after including -# INCLUDES, setting cache variable VAR accordingly. -ac_fn_c_check_member () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 -$as_echo_n "checking for $2.$3... " >&6; } -if eval \${$4+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$5 -int -main () -{ -static $2 ac_aggr; -if (ac_aggr.$3) -return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$4=yes" -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$5 -int -main () -{ -static $2 ac_aggr; -if (sizeof ac_aggr.$3) -return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$4=yes" -else - eval "$4=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$4 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_member - # ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES # --------------------------------------------- # Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR @@ -15248,6 +15248,37 @@ fi done +for ac_header in procfs.h sys/procfs.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + ac_fn_c_check_member "$LINENO" "struct psinfo" "pr_ttydev" "ac_cv_member_struct_psinfo_pr_ttydev" "$ac_includes_default +#ifdef HAVE_PROCFS_H +#include +#endif +#ifdef HAVE_SYS_PROCFS_H +#include +#endif + +" +if test "x$ac_cv_member_struct_psinfo_pr_ttydev" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_PSINFO_PR_TTYDEV 1 +_ACEOF + + +fi + +break +fi + +done + # Check whether --enable-largefile was given. if test "${enable_largefile+set}" = set; then : enableval=$enable_largefile; diff --git a/configure.in b/configure.in index 14bfe25f6..bedf548ad 100644 --- a/configure.in +++ b/configure.in @@ -2007,6 +2007,15 @@ 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 +#ifdef HAVE_PROCFS_H +#include +#endif +#ifdef HAVE_SYS_PROCFS_H +#include +#endif +])] +break) dnl dnl Check for large file support. HP-UX 11.23 has a broken sys/type.h dnl when large files support is enabled so work around it. diff --git a/src/ttyname.c b/src/ttyname.c index 4bd10e510..499bfa872 100644 --- a/src/ttyname.c +++ b/src/ttyname.c @@ -16,6 +16,12 @@ #include +/* Large files not supported by procfs.h */ +#if defined(HAVE_PROCFS_H) || defined(HAVE_SYS_PROCFS_H) +# undef _FILE_OFFSET_BITS +# undef _LARGE_FILES +#endif + #include #include #include @@ -51,6 +57,11 @@ # include # include #endif +#if defined(HAVE_PROCFS_H) +# include +#elif defined(HAVE_SYS_PROCFS_H) +# include +#endif #include "sudo.h" @@ -79,7 +90,7 @@ # define sudo_kp_namelen 4 #endif -#ifdef sudo_kp_tdev +#if defined(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 @@ -145,13 +156,59 @@ get_process_ttyname(void) debug_return_str(tty); } +#elif defined(HAVE_STRUCT_PSINFO_PR_TTYDEV) +/* + * 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. + */ +char * +get_process_ttyname(void) +{ + char path[PATH_MAX], *tty = NULL; + struct stat sb; + struct psinfo psinfo; + ssize_t nread; + 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); + } + } + } + } + + debug_return_str(estrdup(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 SVR4). + * parent). First tries std{in,out,err} then falls back to our parent's /proc + * entry. */ char * get_process_ttyname(void) @@ -168,26 +225,8 @@ get_process_ttyname(void) /* 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", (int)ppid, i); - if (stat(path, &sb) != 0) - continue; - /* - * SVR4-style /proc doesn't allow /proc/pid/fd/[0-2] - * to be used if it is a device and sets the mode to 0000. - * Linux-style /proc uses a link to the actual tty. - */ - if (S_ISCHR(sb.st_mode) && - (sb.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) == 0) { - /* - * We can't open it but maybe we can determine - * the pts device using the minor number. - */ - dev_t fd_dev = sb.st_rdev; - (void)snprintf(path, sizeof(path), "/dev/pts/%u", - (unsigned int)minor(sb.st_rdev)); - if (stat(path, &sb) != 0 || sb.st_rdev != fd_dev) - continue; - } + 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); @@ -198,4 +237,4 @@ get_process_ttyname(void) debug_return_str(estrdup(tty)); } -#endif /* sudo_kp_tdev */ +#endif /* !sudo_kp_tdev && !HAVE_STRUCT_PSINFO_PR_TTYDEV */