|
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) |