Rototill code to determine the tty. For Linux, we now look up the

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().
This commit is contained in:
Todd C. Miller
2012-04-11 14:48:08 -04:00
parent 271f3e2054
commit 83fc02bc97
4 changed files with 192 additions and 77 deletions

View File

@@ -666,6 +666,9 @@
/* 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__

28
configure vendored
View File

@@ -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\\"

View 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

View 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)
@@ -90,6 +91,86 @@
# 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