From: Todd C. Miller Date: Fri, 13 Jan 2012 11:01:58 +0000 (-0500) Subject: Move tty name lookup code to its own file. X-Git-Tag: SUDO_1_8_4~56^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=106bbebba78274be58e6a9bbf5874b204e4822f5;p=sudo Move tty name lookup code to its own file. --- diff --git a/MANIFEST b/MANIFEST index 42d92f42f..2447ab812 100644 --- a/MANIFEST +++ b/MANIFEST @@ -307,6 +307,7 @@ src/sudo_noexec.c src/sudo_plugin_int.h src/sudo_usage.h.in src/tgetpass.c +src/ttyname.c src/ttysize.c src/utmp.c sudo.pp diff --git a/src/Makefile.in b/src/Makefile.in index 792f28883..b24f2bb36 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -75,7 +75,7 @@ PROGS = @PROGS@ OBJS = conversation.o error.o exec.o exec_pty.o get_pty.o net_ifs.o \ load_plugins.o parse_args.o sudo.o sudo_edit.o tgetpass.o \ - ttysize.o utmp.o @SUDO_OBJS@ + ttyname.o ttysize.o utmp.o @SUDO_OBJS@ LIBOBJDIR = $(top_builddir)/@ac_config_libobj_dir@/ @@ -234,6 +234,12 @@ tgetpass.o: $(srcdir)/tgetpass.c $(top_builddir)/config.h $(srcdir)/sudo.h \ $(incdir)/fileops.h $(incdir)/list.h $(incdir)/sudo_debug.h \ $(incdir)/gettext.h $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/tgetpass.c +ttyname.o: $(srcdir)/ttyname.c $(top_builddir)/config.h $(srcdir)/sudo.h \ + $(top_builddir)/pathnames.h $(top_srcdir)/compat/stdbool.h \ + $(incdir)/missing.h $(incdir)/alloc.h $(incdir)/error.h \ + $(incdir)/fileops.h $(incdir)/list.h $(incdir)/sudo_conf.h \ + $(incdir)/list.h $(incdir)/sudo_debug.h $(incdir)/gettext.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/ttyname.c ttysize.o: $(srcdir)/ttysize.c $(top_builddir)/config.h $(incdir)/missing.h \ $(incdir)/sudo_debug.h $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/ttysize.c diff --git a/src/sudo.c b/src/sudo.c index 87b388e87..4d976b91a 100644 --- a/src/sudo.c +++ b/src/sudo.c @@ -25,9 +25,6 @@ #include #include #include -#ifdef HAVE_SYS_SELECT_H -# include -#endif /* HAVE_SYS_SELECT_H */ #include #include #include @@ -426,121 +423,6 @@ get_user_groups(struct user_details *ud) debug_return_str(gid_list); } -/* - * 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. - */ -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; - debug_decl(get_process_tty, SUDO_DEBUG_UTIL) - - /* - * 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 == '#') { - 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); - } - } else { - sudo_debug_printf(SUDO_DEBUG_WARN, - "unable to resolve tty via KERN_PROC: %s", strerror(errno)); - } - 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); -} -#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; - debug_decl(get_process_tty, 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/%d/fd/%d", ppid, i); - fd = open(path, O_RDONLY|O_NOCTTY, 0); - if (fd != -1) { - tty = ttyname(fd); - close(fd); - } - } - } - - debug_return_str(estrdup(tty)); -} -#endif /* sudo_kp_tdev */ - /* * Return user information as an array of name=value pairs. * and fill in struct user_details (which shares the same strings). @@ -591,7 +473,7 @@ get_user_info(struct user_details *ud) ud->cwd = user_info[i] + sizeof("cwd=") - 1; } - if ((cp = get_process_tty()) != NULL) { + if ((cp = get_process_ttyname()) != NULL) { user_info[++i] = fmt_string("tty", cp); if (user_info[i] == NULL) errorx(1, _("unable to allocate memory")); diff --git a/src/sudo.h b/src/sudo.h index ca3ed4095..0aea65bb7 100644 --- a/src/sudo.h +++ b/src/sudo.h @@ -227,4 +227,7 @@ int get_net_ifs(char **addrinfo); /* setgroups.c */ int sudo_setgroups(int ngids, const GETGROUPS_T *gids); +/* ttyname.c */ +char *get_process_ttyname(void); + #endif /* _SUDO_SUDO_H */ diff --git a/src/ttyname.c b/src/ttyname.c new file mode 100644 index 000000000..1a275da8f --- /dev/null +++ b/src/ttyname.c @@ -0,0 +1,167 @@ +/* + * 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(void) +{ + char *tty = NULL; + struct kinfo_proc *ki_proc = NULL; + size_t size = sizeof(*ki_proc); + int i, mib[6], rc; + debug_decl(get_process_ttyname, SUDO_DEBUG_UTIL) + + /* + * 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 == '#') { + 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); + } + } else { + sudo_debug_printf(SUDO_DEBUG_WARN, + "unable to resolve tty via KERN_PROC: %s", strerror(errno)); + } + 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); +} +#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(void) +{ + char path[PATH_MAX], *tty = NULL; + pid_t ppid; + 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 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); + } + } + } + + debug_return_str(estrdup(tty)); +} +#endif /* sudo_kp_tdev */