2 * Copyright (c) 2012 Todd C. Miller <Todd.Miller@courtesan.com>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/types.h>
20 #include <sys/param.h>
30 #endif /* STDC_HEADERS */
32 # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
36 #endif /* HAVE_STRING_H */
39 #endif /* HAVE_STRINGS_H */
42 #endif /* HAVE_UNISTD_H */
45 #if defined(HAVE_STRUCT_KINFO_PROC_P_TDEV) || defined (HAVE_STRUCT_KINFO_PROC_KP_EPROC_E_TDEV) || defined(HAVE_STRUCT_KINFO_PROC2_P_TDEV)
46 # include <sys/sysctl.h>
47 #elif defined(HAVE_STRUCT_KINFO_PROC_KI_TDEV)
48 # include <sys/sysctl.h>
49 # include <sys/user.h>
55 * How to access the tty device number in struct kinfo_proc.
57 #if defined(HAVE_STRUCT_KINFO_PROC2_P_TDEV)
58 # define SUDO_KERN_PROC KERN_PROC2
59 # define sudo_kinfo_proc kinfo_proc2
60 # define sudo_kp_tdev p_tdev
61 # define sudo_kp_namelen 6
62 #elif defined(HAVE_STRUCT_KINFO_PROC_P_TDEV)
63 # define SUDO_KERN_PROC KERN_PROC
64 # define sudo_kinfo_proc kinfo_proc
65 # define sudo_kp_tdev p_tdev
66 # define sudo_kp_namelen 6
67 #elif defined(HAVE_STRUCT_KINFO_PROC_KI_TDEV)
68 # define SUDO_KERN_PROC KERN_PROC
69 # define sudo_kinfo_proc kinfo_proc
70 # define sudo_kp_tdev ki_tdev
71 # define sudo_kp_namelen 4
72 #elif defined(HAVE_STRUCT_KINFO_PROC_KP_EPROC_E_TDEV)
73 # define SUDO_KERN_PROC KERN_PROC
74 # define sudo_kinfo_proc kinfo_proc
75 # define sudo_kp_tdev kp_eproc.e_tdev
76 # define sudo_kp_namelen 4
81 * Return a string from ttyname() containing the tty to which the process is
82 * attached or NULL if there is no tty associated with the process (or its
83 * parent). First tries sysctl using the current pid, then the parent's pid.
84 * Falls back on ttyname of std{in,out,err} if that fails.
87 get_process_ttyname(void)
90 struct sudo_kinfo_proc *ki_proc = NULL;
91 size_t size = sizeof(*ki_proc);
93 debug_decl(get_process_ttyname, SUDO_DEBUG_UTIL)
96 * Lookup tty for this process and, failing that, our parent.
97 * Even if we redirect std{in,out,err} the kernel should still know.
99 for (i = 0; tty == NULL && i < 2; i++) {
101 mib[1] = SUDO_KERN_PROC;
102 mib[2] = KERN_PROC_PID;
103 mib[3] = i ? (int)getppid() : (int)getpid();
104 mib[4] = sizeof(*ki_proc);
108 ki_proc = erealloc(ki_proc, size);
109 rc = sysctl(mib, sudo_kp_namelen, ki_proc, &size, NULL, 0);
110 } while (rc == -1 && errno == ENOMEM);
112 char *dev = devname(ki_proc->sudo_kp_tdev, S_IFCHR);
113 /* Some versions of devname() return NULL, others do not. */
114 if (dev == NULL || *dev == '?' || *dev == '#') {
115 sudo_debug_printf(SUDO_DEBUG_WARN,
116 "unable to map device number %u to name",
117 ki_proc->sudo_kp_tdev);
118 } else if (*dev != '/') {
119 /* devname() doesn't use the /dev/ prefix, add one... */
120 size_t len = sizeof(_PATH_DEV) + strlen(dev);
122 strlcpy(tty, _PATH_DEV, len);
123 strlcat(tty, dev, len);
125 /* Should not happen but just in case... */
129 sudo_debug_printf(SUDO_DEBUG_WARN,
130 "unable to resolve tty via KERN_PROC: %s", strerror(errno));
135 /* If all else fails, fall back on ttyname(). */
137 if ((tty = ttyname(STDIN_FILENO)) != NULL ||
138 (tty = ttyname(STDOUT_FILENO)) != NULL ||
139 (tty = ttyname(STDERR_FILENO)) != NULL)
143 debug_return_str(tty);
147 * Return a string from ttyname() containing the tty to which the process is
148 * attached or NULL if there is no tty associated with the process (or its
149 * parent). First tries std{in,out,err} then falls back to the parent's /proc
150 * entry. We could try following the parent all the way to pid 1 but
151 * /proc/%d/status is system-specific (text on Linux, a struct on Solaris).
154 get_process_ttyname(void)
156 char path[PATH_MAX], *tty = NULL;
159 debug_decl(get_process_ttyname, SUDO_DEBUG_UTIL)
161 if ((tty = ttyname(STDIN_FILENO)) == NULL &&
162 (tty = ttyname(STDOUT_FILENO)) == NULL &&
163 (tty = ttyname(STDERR_FILENO)) == NULL) {
164 /* No tty for child, check the parent via /proc. */
166 for (i = STDIN_FILENO; i < STDERR_FILENO && tty == NULL; i++) {
167 snprintf(path, sizeof(path), "/proc/%d/fd/%d", (int)ppid, i);
168 fd = open(path, O_RDONLY|O_NOCTTY, 0);
176 debug_return_str(estrdup(tty));
178 #endif /* sudo_kp_tdev */