version 1.1.1.2, 2012/10/09 09:29:52
|
version 1.1.1.3, 2013/07/22 10:46:13
|
Line 1
|
Line 1
|
/* |
/* |
* Copyright (c) 2012 Todd C. Miller <Todd.Miller@courtesan.com> | * Copyright (c) 2012-2013 Todd C. Miller <Todd.Miller@courtesan.com> |
* |
* |
* Permission to use, copy, modify, and distribute this software for any |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* purpose with or without fee is hereby granted, provided that the above |
Line 23
|
Line 23
|
#endif |
#endif |
|
|
#include <sys/types.h> |
#include <sys/types.h> |
#include <sys/param.h> |
|
#include <sys/stat.h> |
#include <sys/stat.h> |
#if defined(MAJOR_IN_MKDEV) |
#if defined(MAJOR_IN_MKDEV) |
# include <sys/mkdev.h> |
# include <sys/mkdev.h> |
Line 71
|
Line 70
|
# endif |
# endif |
#endif |
#endif |
#if defined(HAVE_STRUCT_KINFO_PROC_P_TDEV) || defined (HAVE_STRUCT_KINFO_PROC_KP_EPROC_E_TDEV) || defined(HAVE_STRUCT_KINFO_PROC2_P_TDEV) |
#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/param.h> |
# include <sys/sysctl.h> |
# include <sys/sysctl.h> |
#elif defined(HAVE_STRUCT_KINFO_PROC_KI_TDEV) |
#elif defined(HAVE_STRUCT_KINFO_PROC_KI_TDEV) |
|
# include <sys/param.h> |
# include <sys/sysctl.h> |
# include <sys/sysctl.h> |
# include <sys/user.h> |
# include <sys/user.h> |
#endif |
#endif |
Line 81
|
Line 82
|
#elif defined(HAVE_SYS_PROCFS_H) |
#elif defined(HAVE_SYS_PROCFS_H) |
# include <sys/procfs.h> |
# include <sys/procfs.h> |
#endif |
#endif |
|
#ifdef HAVE_PSTAT_GETPROC |
|
# include <sys/param.h> |
|
# include <sys/pstat.h> |
|
#endif |
|
|
#include "sudo.h" |
#include "sudo.h" |
|
|
Line 155 sudo_ttyname_dev(dev_t tdev)
|
Line 160 sudo_ttyname_dev(dev_t tdev)
|
|
|
debug_return_str(estrdup(tty)); |
debug_return_str(estrdup(tty)); |
} |
} |
#else | #elif defined(HAVE_STRUCT_PSINFO_PR_TTYDEV) || defined(HAVE_PSTAT_GETPROC) || defined(__linux__) |
/* |
/* |
* Devices to search before doing a breadth-first scan. |
* Devices to search before doing a breadth-first scan. |
*/ |
*/ |
Line 180 static char *ignore_devs[] = {
|
Line 185 static char *ignore_devs[] = {
|
/* |
/* |
* Do a breadth-first scan of dir looking for the specified device. |
* Do a breadth-first scan of dir looking for the specified device. |
*/ |
*/ |
static | static char * |
char *sudo_ttyname_scan(const char *dir, dev_t rdev, bool builtin) | sudo_ttyname_scan(const char *dir, dev_t rdev, bool builtin) |
{ |
{ |
DIR *d; | DIR *d = NULL; |
char pathbuf[PATH_MAX], **subdirs = NULL, *devname = NULL; |
char pathbuf[PATH_MAX], **subdirs = NULL, *devname = NULL; |
size_t sdlen, d_len, len, num_subdirs = 0, max_subdirs = 0; |
size_t sdlen, d_len, len, num_subdirs = 0, max_subdirs = 0; |
struct dirent *dp; |
struct dirent *dp; |
Line 194 char *sudo_ttyname_scan(const char *dir, dev_t rdev, b
|
Line 199 char *sudo_ttyname_scan(const char *dir, dev_t rdev, b
|
if (dir[0] == '\0' || (d = opendir(dir)) == NULL) |
if (dir[0] == '\0' || (d = opendir(dir)) == NULL) |
goto done; |
goto done; |
|
|
|
sudo_debug_printf(SUDO_DEBUG_INFO, "scanning for dev %u in %s", |
|
(unsigned int)rdev, dir); |
|
|
sdlen = strlen(dir); |
sdlen = strlen(dir); |
if (dir[sdlen - 1] == '/') |
if (dir[sdlen - 1] == '/') |
sdlen--; |
sdlen--; |
Line 239 char *sudo_ttyname_scan(const char *dir, dev_t rdev, b
|
Line 247 char *sudo_ttyname_scan(const char *dir, dev_t rdev, b
|
continue; |
continue; |
} |
} |
# if defined(HAVE_STRUCT_DIRENT_D_TYPE) && defined(DTTOIF) |
# if defined(HAVE_STRUCT_DIRENT_D_TYPE) && defined(DTTOIF) |
/* Use d_type to avoid a stat() if possible. */ | /* |
/* Convert d_type to stat-style type bits but follow links. */ | * Convert dp->d_type to sb.st_mode to avoid a stat(2) if possible. |
if (dp->d_type != DT_LNK && dp->d_type != DT_CHR) | * We can't use it for links (since we want to follow them) or |
| * char devs (since we need st_rdev to compare the device number). |
| */ |
| if (dp->d_type != DT_UNKNOWN && dp->d_type != DT_LNK && dp->d_type != DT_CHR) |
sb.st_mode = DTTOIF(dp->d_type); |
sb.st_mode = DTTOIF(dp->d_type); |
else |
else |
# endif |
# endif |
Line 260 char *sudo_ttyname_scan(const char *dir, dev_t rdev, b
|
Line 271 char *sudo_ttyname_scan(const char *dir, dev_t rdev, b
|
} |
} |
if (S_ISCHR(sb.st_mode) && sb.st_rdev == rdev) { |
if (S_ISCHR(sb.st_mode) && sb.st_rdev == rdev) { |
devname = estrdup(pathbuf); |
devname = estrdup(pathbuf); |
break; | sudo_debug_printf(SUDO_DEBUG_INFO, "resolved dev %u as %s", |
| (unsigned int)rdev, pathbuf); |
| goto done; |
} |
} |
} |
} |
closedir(d); |
|
|
|
/* Search subdirs if we didn't find it in the root level. */ |
/* Search subdirs if we didn't find it in the root level. */ |
for (i = 0; devname == NULL && i < num_subdirs; i++) |
for (i = 0; devname == NULL && i < num_subdirs; i++) |
devname = sudo_ttyname_scan(subdirs[i], rdev, false); |
devname = sudo_ttyname_scan(subdirs[i], rdev, false); |
|
|
done: |
done: |
|
if (d != NULL) |
|
closedir(d); |
for (i = 0; i < num_subdirs; i++) |
for (i = 0; i < num_subdirs; i++) |
efree(subdirs[i]); |
efree(subdirs[i]); |
efree(subdirs); |
efree(subdirs); |
Line 290 sudo_ttyname_dev(dev_t rdev)
|
Line 304 sudo_ttyname_dev(dev_t rdev)
|
debug_decl(sudo_ttyname_dev, SUDO_DEBUG_UTIL) |
debug_decl(sudo_ttyname_dev, SUDO_DEBUG_UTIL) |
|
|
/* |
/* |
* First check search_devs. | * First check search_devs for common tty devices. |
*/ |
*/ |
for (sd = search_devs; (devname = *sd) != NULL; sd++) { | for (sd = search_devs; tty == NULL && (devname = *sd) != NULL; sd++) { |
len = strlen(devname); |
len = strlen(devname); |
if (devname[len - 1] == '/') { |
if (devname[len - 1] == '/') { |
/* Special case /dev/pts */ |
|
if (strcmp(devname, "/dev/pts/") == 0) { |
if (strcmp(devname, "/dev/pts/") == 0) { |
|
/* Special case /dev/pts */ |
(void)snprintf(buf, sizeof(buf), "%spts/%u", _PATH_DEV, |
(void)snprintf(buf, sizeof(buf), "%spts/%u", _PATH_DEV, |
(unsigned int)minor(rdev)); |
(unsigned int)minor(rdev)); |
if (stat(buf, &sb) == 0) { |
if (stat(buf, &sb) == 0) { |
if (S_ISCHR(sb.st_mode) && sb.st_rdev == rdev) { | if (S_ISCHR(sb.st_mode) && sb.st_rdev == rdev) |
tty = estrdup(buf); |
tty = estrdup(buf); |
break; |
|
} |
|
} |
} |
continue; | sudo_debug_printf(SUDO_DEBUG_INFO, "comparing dev %u to %s: %s", |
| (unsigned int)rdev, buf, tty ? "yes" : "no"); |
| } else { |
| /* Traverse directory */ |
| tty = sudo_ttyname_scan(devname, rdev, true); |
} |
} |
/* Traverse directory */ |
|
tty = sudo_ttyname_scan(devname, rdev, true); |
|
} else { |
} else { |
if (stat(devname, &sb) == 0) { |
if (stat(devname, &sb) == 0) { |
if (S_ISCHR(sb.st_mode) && sb.st_rdev == rdev) { | if (S_ISCHR(sb.st_mode) && sb.st_rdev == rdev) |
tty = estrdup(devname); |
tty = estrdup(devname); |
break; |
|
} |
|
} |
} |
} |
} |
} |
} |
Line 332 sudo_ttyname_dev(dev_t rdev)
|
Line 344 sudo_ttyname_dev(dev_t rdev)
|
#if defined(sudo_kp_tdev) |
#if defined(sudo_kp_tdev) |
/* |
/* |
* Return a string from ttyname() containing the tty to which the process is |
* 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 | * attached or NULL if the process has no controlling tty. |
* 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. | |
*/ |
*/ |
char * |
char * |
get_process_ttyname(void) |
get_process_ttyname(void) |
Line 342 get_process_ttyname(void)
|
Line 352 get_process_ttyname(void)
|
char *tty = NULL; |
char *tty = NULL; |
struct sudo_kinfo_proc *ki_proc = NULL; |
struct sudo_kinfo_proc *ki_proc = NULL; |
size_t size = sizeof(*ki_proc); |
size_t size = sizeof(*ki_proc); |
int i, mib[6], rc; | int mib[6], rc; |
debug_decl(get_process_ttyname, SUDO_DEBUG_UTIL) |
debug_decl(get_process_ttyname, SUDO_DEBUG_UTIL) |
|
|
/* |
/* |
* Lookup tty for this process and, failing that, our parent. | * Lookup controlling tty for this process via sysctl. |
* Even if we redirect std{in,out,err} the kernel should still know. | * This will work even if std{in,out,err} are redirected. |
*/ |
*/ |
for (i = 0; tty == NULL && i < 2; i++) { | mib[0] = CTL_KERN; |
mib[0] = CTL_KERN; | mib[1] = SUDO_KERN_PROC; |
mib[1] = SUDO_KERN_PROC; | mib[2] = KERN_PROC_PID; |
mib[2] = KERN_PROC_PID; | mib[3] = (int)getpid(); |
mib[3] = i ? (int)getppid() : (int)getpid(); | mib[4] = sizeof(*ki_proc); |
mib[4] = sizeof(*ki_proc); | mib[5] = 1; |
mib[5] = 1; | do { |
do { | size += size / 10; |
size += size / 10; | ki_proc = erealloc(ki_proc, size); |
ki_proc = erealloc(ki_proc, size); | rc = sysctl(mib, sudo_kp_namelen, ki_proc, &size, NULL, 0); |
rc = sysctl(mib, sudo_kp_namelen, ki_proc, &size, NULL, 0); | } while (rc == -1 && errno == ENOMEM); |
} while (rc == -1 && errno == ENOMEM); | if (rc != -1) { |
if (rc != -1) { | if (ki_proc->sudo_kp_tdev != (dev_t)-1) { |
if (ki_proc->sudo_kp_tdev != (dev_t)-1) { | tty = sudo_ttyname_dev(ki_proc->sudo_kp_tdev); |
tty = sudo_ttyname_dev(ki_proc->sudo_kp_tdev); | if (tty == NULL) { |
if (tty == NULL) { | sudo_debug_printf(SUDO_DEBUG_WARN, |
sudo_debug_printf(SUDO_DEBUG_WARN, | "unable to map device number %u to name", |
"unable to map device number %u to name", | ki_proc->sudo_kp_tdev); |
ki_proc->sudo_kp_tdev); | |
} | |
} |
} |
} else { |
|
sudo_debug_printf(SUDO_DEBUG_WARN, |
|
"unable to resolve tty via KERN_PROC: %s", strerror(errno)); |
|
} |
} |
|
} else { |
|
sudo_debug_printf(SUDO_DEBUG_WARN, |
|
"unable to resolve tty via KERN_PROC: %s", strerror(errno)); |
} |
} |
efree(ki_proc); |
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); |
|
} |
|
|
|
debug_return_str(tty); |
debug_return_str(tty); |
} |
} |
#elif defined(HAVE_STRUCT_PSINFO_PR_TTYDEV) |
#elif defined(HAVE_STRUCT_PSINFO_PR_TTYDEV) |
/* |
/* |
* Return a string from ttyname() containing the tty to which the process is |
* 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 | * attached or NULL if the process has no controlling tty. |
* parent). First tries /proc/pid/psinfo, then /proc/ppid/psinfo. | |
* Falls back on ttyname of std{in,out,err} if that fails. | |
*/ |
*/ |
char * |
char * |
get_process_ttyname(void) |
get_process_ttyname(void) |
Line 400 get_process_ttyname(void)
|
Line 398 get_process_ttyname(void)
|
char path[PATH_MAX], *tty = NULL; |
char path[PATH_MAX], *tty = NULL; |
struct psinfo psinfo; |
struct psinfo psinfo; |
ssize_t nread; |
ssize_t nread; |
int i, fd; | int fd; |
debug_decl(get_process_ttyname, SUDO_DEBUG_UTIL) |
debug_decl(get_process_ttyname, SUDO_DEBUG_UTIL) |
|
|
/* Try to determine the tty from pr_ttydev in /proc/pid/psinfo. */ |
/* Try to determine the tty from pr_ttydev in /proc/pid/psinfo. */ |
for (i = 0; tty == NULL && i < 2; i++) { | snprintf(path, sizeof(path), "/proc/%u/psinfo", (unsigned int)getpid()); |
(void)snprintf(path, sizeof(path), "/proc/%u/psinfo", | if ((fd = open(path, O_RDONLY, 0)) != -1) { |
i ? (unsigned int)getppid() : (unsigned int)getpid()); | |
if ((fd = open(path, O_RDONLY, 0)) == -1) | |
continue; | |
nread = read(fd, &psinfo, sizeof(psinfo)); |
nread = read(fd, &psinfo, sizeof(psinfo)); |
close(fd); |
close(fd); |
if (nread == (ssize_t)sizeof(psinfo) && psinfo.pr_ttydev != (dev_t)-1) { | if (nread == (ssize_t)sizeof(psinfo)) { |
tty = sudo_ttyname_dev(psinfo.pr_ttydev); | dev_t rdev = (dev_t)psinfo.pr_ttydev; |
| #if defined(_AIX) && defined(DEVNO64) |
| if (psinfo.pr_ttydev & DEVNO64) |
| rdev = makedev(major64(psinfo.pr_ttydev), minor64(psinfo.pr_ttydev)); |
| #endif |
| if (rdev != (dev_t)-1) |
| tty = sudo_ttyname_dev(rdev); |
} |
} |
} |
} |
|
|
/* 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); |
debug_return_str(tty); |
} |
} |
#elif defined(__linux__) |
#elif defined(__linux__) |
/* |
/* |
* Return a string from ttyname() containing the tty to which the process is |
* 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 | * attached or NULL if the process has no controlling tty. |
* 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 * |
char * |
get_process_ttyname(void) |
get_process_ttyname(void) |
{ |
{ |
char *line = NULL, *tty = NULL; | char path[PATH_MAX], *line = NULL, *tty = NULL; |
size_t linesize = 0; |
size_t linesize = 0; |
ssize_t len; |
ssize_t len; |
int i; | FILE *fp; |
debug_decl(get_process_ttyname, SUDO_DEBUG_UTIL) |
debug_decl(get_process_ttyname, SUDO_DEBUG_UTIL) |
|
|
/* Try to determine the tty from pr_ttydev in /proc/pid/psinfo. */ | /* Try to determine the tty from tty_nr in /proc/pid/stat. */ |
for (i = 0; tty == NULL && i < 2; i++) { | snprintf(path, sizeof(path), "/proc/%u/stat", (unsigned int)getpid()); |
FILE *fp; | if ((fp = fopen(path, "r")) != NULL) { |
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); |
len = getline(&line, &linesize, fp); |
fclose(fp); |
fclose(fp); |
if (len != -1) { |
if (len != -1) { |
Line 467 get_process_ttyname(void)
|
Line 453 get_process_ttyname(void)
|
} |
} |
} |
} |
} |
} |
|
efree(line); |
} |
} |
efree(line); |
|
|
|
/* If all else fails, fall back on ttyname(). */ | debug_return_str(tty); |
if (tty == NULL) { | } |
if ((tty = ttyname(STDIN_FILENO)) != NULL || | #elif HAVE_PSTAT_GETPROC |
(tty = ttyname(STDOUT_FILENO)) != NULL || | /* |
(tty = ttyname(STDERR_FILENO)) != NULL) | * Return a string from ttyname() containing the tty to which the process is |
tty = estrdup(tty); | * attached or NULL if the process has no controlling tty. |
} | */ |
| char * |
| get_process_ttyname(void) |
| { |
| struct pst_status pstat; |
| char *tty = NULL; |
| debug_decl(get_process_ttyname, SUDO_DEBUG_UTIL) |
|
|
|
/* Try to determine the tty from psdev in struct pst_status. */ |
|
if (pstat_getproc(&pstat, sizeof(pstat), 0, (int)getpid()) != -1) { |
|
if (pstat.pst_term.psd_major != -1 && pstat.pst_term.psd_minor != -1) { |
|
tty = sudo_ttyname_dev(makedev(pstat.pst_term.psd_major, |
|
pstat.pst_term.psd_minor)); |
|
} |
|
} |
debug_return_str(tty); |
debug_return_str(tty); |
} |
} |
#else |
#else |
/* |
/* |
* Return a string from ttyname() containing the tty to which the process is |
* 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. | * attached or NULL if the process has no controlling tty. |
* parent). | |
*/ |
*/ |
char * |
char * |
get_process_ttyname(void) |
get_process_ttyname(void) |