From fd021451b926bb3feba0e4bc62ea7eea691afcc9 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Fri, 13 Jan 2012 06:11:23 -0500 Subject: [PATCH] Move tty name lookup code to its own file. --HG-- branch : 1.7 --- Makefile.in | 10 ++-- sudo.c | 114 +------------------------------------ sudo.h | 3 + ttyname.c | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 170 insertions(+), 117 deletions(-) create mode 100644 ttyname.c diff --git a/Makefile.in b/Makefile.in index e5fbda7cb..7a92ef936 100644 --- a/Makefile.in +++ b/Makefile.in @@ -114,9 +114,9 @@ SRCS = aix.c alias.c alloc.c audit.c boottime.c bsm_audit.c check.c \ parse_args.c pwutil.c set_perms.c setsid.c sigaction.c snprintf.c \ strcasecmp.c strerror.c strlcat.c strlcpy.c strsignal.c sudo.c \ sudo_noexec.c sudo_edit.c sudo_nss.c term.c testsudoers.c tgetpass.c \ - toke.c toke.l toke_util.c tsgetgrpw.c utimes.c vasgroups.c visudo.c \ - zero_bytes.c redblack.c selinux.c sesh.c sudoreplay.c getdate.c \ - getdate.y getline.c timestr.c $(AUTH_SRCS) + toke.c toke.l toke_util.c tsgetgrpw.c ttyname.c utimes.c vasgroups.c \ + visudo.c zero_bytes.c redblack.c selinux.c sesh.c sudoreplay.c \ + getdate.c getdate.y getline.c timestr.c $(AUTH_SRCS) AUTH_SRCS = auth/afs.c auth/aix_auth.c auth/bsdauth.c auth/dce.c auth/fwtk.c \ auth/kerb4.c auth/kerb5.c auth/pam.c auth/passwd.c auth/rfc1938.c \ @@ -139,7 +139,7 @@ COMMON_OBJS = alias.o alloc.o defaults.o error.o gram.o \ SUDO_OBJS = $(AUTH_OBJS) @SUDO_OBJS@ audit.o boottime.o check.o env.o \ exec.o gettime.o goodpath.o fileops.o find_path.o \ interfaces.o lbuf.o logging.o logwrap.o parse.o parse_args.o \ - set_perms.o sudo.o sudo_edit.o sudo_nss.o tgetpass.o + set_perms.o sudo.o sudo_edit.o sudo_nss.o tgetpass.o ttyname.o VISUDO_OBJS = visudo.o fileops.o gettime.o goodpath.o find_path.o @@ -391,6 +391,8 @@ testsudoers.o: $(srcdir)/testsudoers.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/li $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/testsudoers.c tgetpass.o: $(srcdir)/tgetpass.c $(SUDODEP) $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/tgetpass.c +ttyname.o: $(srcdir)/ttyname.c $(SUDODEP) + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/ttyname.c timestr.o: $(srcdir)/timestr.c $(srcdir)/missing.h config.h $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/timestr.c toke.o: $(devdir)/toke.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/list.h $(srcdir)/toke.h $(devdir)/gram.h diff --git a/sudo.c b/sudo.c index bdd64df44..e5235ecf6 100644 --- a/sudo.c +++ b/sudo.c @@ -582,118 +582,6 @@ main(argc, argv, envp) 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. @@ -739,7 +627,7 @@ init_vars(envp) } } - if ((p = get_process_tty()) != NULL) { + if ((p = get_process_ttyname()) != NULL) { user_tty = user_ttypath = p; if (strncmp(user_tty, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) user_tty += sizeof(_PATH_DEV) - 1; diff --git a/sudo.h b/sudo.h index bbb80ac23..36edf22cb 100644 --- a/sudo.h +++ b/sudo.h @@ -356,6 +356,9 @@ YY_DECL; /* zero_bytes.c */ void zero_bytes __P((volatile void *, size_t)); +/* ttyname.c */ +char *get_process_ttyname __P((void)); + /* Only provide extern declarations outside of sudo.c. */ #ifndef _SUDO_MAIN extern struct sudo_user sudo_user; diff --git a/ttyname.c b/ttyname.c new file mode 100644 index 000000000..68a1e38bd --- /dev/null +++ b/ttyname.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2012 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#ifdef HAVE_STRING_H +# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS) +# include +# endif +# include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#include +#include +#if defined(HAVE_STRUCT_KINFO_PROC_P_TDEV) || defined (HAVE_STRUCT_KINFO_PROC_KP_EPROC_E_TDEV) +# include +#elif defined(HAVE_STRUCT_KINFO_PROC_KI_TDEV) +# include +# include +#endif + +#include "sudo.h" + +/* + * 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 +#elif defined(HAVE_STRUCT_KINFO_PROC_KI_TDEV) +# define sudo_kp_tdev ki_tdev +# define sudo_kp_namelen 4 +#elif defined(HAVE_STRUCT_KINFO_PROC_P_TDEV) +# define sudo_kp_tdev p_tdev +# define sudo_kp_namelen 6 +#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. + */ +char * +get_process_ttyname() +{ + 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). + */ +char * +get_process_ttyname() +{ + 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 */ -- 2.40.0