ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/libptytty/src/ptytty.C
Revision: 1.57
Committed: Mon May 24 14:22:50 2021 UTC (5 years, 4 months ago) by sf-exg
Content type: text/plain
Branch: MAIN
Changes since 1.56: +16 -4 lines
Log Message:
Stop using utmp if utmpx is available

This commit changes ptytty to use only utmpx on systems where both
utmpx and utmp are available, as utmp is generally deprecated and
pointless to use on these, glibc being the exception. The commit also
refactors code to reduce the amount of ifdeffery.

File Contents

# User Rev Content
1 root 1.8 /*----------------------------------------------------------------------*
2 root 1.1 * File: ptytty.C
3     *----------------------------------------------------------------------*
4     *
5     * All portions of code are copyright by their respective author/s.
6     * Copyright (c) 1999-2001 Geoff Wing <gcw@pobox.com>
7 sf-exg 1.38 * Copyright (c) 2004-2006 Marc Lehmann <schmorp@schmorp.de>
8 root 1.12 * Copyright (c) 2006 Emanuele Giaquinta <e.giaquinta@glauco.it>
9 root 1.1 *
10     * This program is free software; you can redistribute it and/or modify
11     * it under the terms of the GNU General Public License as published by
12 sf-exg 1.54 * the Free Software Foundation; either version 2 of the License, or
13 root 1.1 * (at your option) any later version.
14     *
15     * This program is distributed in the hope that it will be useful,
16     * but WITHOUT ANY WARRANTY; without even the implied warranty of
17     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18     * GNU General Public License for more details.
19     *
20     * You should have received a copy of the GNU General Public License
21     * along with this program; if not, write to the Free Software
22     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23     *---------------------------------------------------------------------*/
24    
25 sf-exg 1.36 #include "config.h"
26 root 1.1
27 root 1.3 #include "ptytty.h"
28    
29 sf-exg 1.49 #include <stdlib.h>
30 sf-exg 1.51 #include <stdio.h>
31 sf-exg 1.50 #include <string.h>
32 root 1.2
33     #include <sys/types.h>
34 ayin 1.34 #include <sys/stat.h>
35 root 1.2 #include <unistd.h>
36     #include <fcntl.h>
37    
38 root 1.1 #ifdef HAVE_SYS_IOCTL_H
39     # include <sys/ioctl.h>
40     #endif
41 sf-exg 1.52 #ifdef HAVE_STROPTS_H
42 root 1.1 # include <stropts.h>
43     #endif
44 root 1.2 #if defined(HAVE_PTY_H)
45 root 1.1 # include <pty.h>
46 root 1.2 #elif defined(HAVE_LIBUTIL_H)
47 root 1.1 # include <libutil.h>
48 root 1.2 #elif defined(HAVE_UTIL_H)
49 root 1.1 # include <util.h>
50     #endif
51 root 1.2 #ifdef TTY_GID_SUPPORT
52     #include <grp.h>
53     #endif
54 root 1.1
55 sf-exg 1.47 #ifndef O_NOCTTY
56     # define O_NOCTTY 0
57     #endif
58    
59 root 1.2 /////////////////////////////////////////////////////////////////////////////
60 root 1.1
61     /* ------------------------------------------------------------------------- *
62     * GET PSEUDO TELETYPE - MASTER AND SLAVE *
63     * ------------------------------------------------------------------------- */
64     /*
65 ayin 1.26 * Returns pty file descriptor, or -1 on failure
66 root 1.1 * If successful, ttydev is set to the name of the slave device.
67     * fd_tty _may_ also be set to an open fd to the slave device
68     */
69 root 1.2 #if defined(UNIX98_PTY)
70 root 1.25
71     static int
72     get_pty (int *fd_tty, char **ttydev)
73     {
74     int pfd;
75 root 1.1
76 root 1.2 # if defined(HAVE_GETPT)
77 sf-exg 1.43 pfd = getpt ();
78 root 1.2 # elif defined(HAVE_POSIX_OPENPT)
79 sf-exg 1.41 pfd = posix_openpt (O_RDWR | O_NOCTTY);
80 root 1.2 # else
81 sf-exg 1.40 # ifdef _AIX
82     pfd = open ("/dev/ptc", O_RDWR | O_NOCTTY, 0);
83     # else
84     pfd = open ("/dev/ptmx", O_RDWR | O_NOCTTY, 0);
85     # endif
86 root 1.2 # endif
87 root 1.1
88 root 1.25 if (pfd >= 0)
89     {
90     if (grantpt (pfd) == 0 /* change slave permissions */
91     && unlockpt (pfd) == 0)
92 ayin 1.32 {
93     /* slave now unlocked */
94 root 1.25 *ttydev = strdup (ptsname (pfd)); /* get slave's name */
95     return pfd;
96     }
97    
98     close (pfd);
99     }
100    
101     return -1;
102     }
103 root 1.2
104     #elif defined(HAVE_OPENPTY)
105 root 1.1
106 root 1.25 static int
107     get_pty (int *fd_tty, char **ttydev)
108     {
109     int pfd;
110     int res;
111 ayin 1.26
112 ayin 1.29 res = openpty (&pfd, fd_tty, NULL, NULL, NULL);
113 root 1.25
114     if (res != -1)
115     {
116 ayin 1.29 *ttydev = strdup (ttyname (*fd_tty));
117 root 1.25 return pfd;
118     }
119    
120     return -1;
121     }
122    
123 root 1.2 #elif defined(HAVE__GETPTY)
124    
125 root 1.25 static int
126     get_pty (int *fd_tty, char **ttydev)
127     {
128     int pfd;
129 ayin 1.30 char *slave;
130 root 1.25
131 sf-exg 1.42 slave = _getpty (&pfd, O_RDWR | O_NOCTTY, 0622, 0);
132 root 1.25
133 ayin 1.33 if (slave != NULL)
134     {
135     *ttydev = strdup (slave);
136     return pfd;
137     }
138 root 1.25
139     return -1;
140     }
141 root 1.1
142 root 1.2 #else
143 root 1.1
144 root 1.25 /* Based on the code in openssh/openbsd-compat/bsd-openpty.c */
145     static int
146     get_pty (int *fd_tty, char **ttydev)
147     {
148     int pfd;
149     int i;
150     char pty_name[32];
151     char tty_name[32];
152     const char *majors = "pqrstuvwxyzabcde";
153     const char *minors = "0123456789abcdef";
154    
155     for (i = 0; i < 256; i++)
156     {
157 sf-exg 1.43 snprintf (pty_name, 32, "/dev/pty%c%c", majors[i / 16], minors[i % 16]);
158     snprintf (tty_name, 32, "/dev/tty%c%c", majors[i / 16], minors[i % 16]);
159 root 1.25
160     if ((pfd = open (pty_name, O_RDWR | O_NOCTTY, 0)) == -1)
161     {
162 sf-exg 1.43 snprintf (pty_name, 32, "/dev/ptyp%d", i);
163     snprintf (tty_name, 32, "/dev/ttyp%d", i);
164 root 1.25 if ((pfd = open (pty_name, O_RDWR | O_NOCTTY, 0)) == -1)
165     continue;
166     }
167    
168     if (access (tty_name, R_OK | W_OK) == 0)
169     {
170     *ttydev = strdup (tty_name);
171     return pfd;
172     }
173    
174     close (pfd);
175     }
176    
177     return -1;
178     }
179 ayin 1.24
180 root 1.1 #endif
181    
182     /*----------------------------------------------------------------------*/
183     /*
184 ayin 1.26 * Returns tty file descriptor, or -1 on failure
185 root 1.1 */
186     static int
187     get_tty (char *ttydev)
188     {
189     return open (ttydev, O_RDWR | O_NOCTTY, 0);
190     }
191    
192     /*----------------------------------------------------------------------*/
193     /*
194     * Make our tty a controlling tty so that /dev/tty points to us
195     */
196     static int
197 root 1.2 control_tty (int fd_tty)
198 root 1.1 {
199 ayin 1.28 int fd;
200    
201 root 1.1 setsid ();
202    
203 ayin 1.27 #ifdef TIOCSCTTY
204 root 1.2 ioctl (fd_tty, TIOCSCTTY, NULL);
205 ayin 1.27 #else
206 ayin 1.28 fd = open (ttyname (fd_tty), O_RDWR);
207 ayin 1.27 if (fd >= 0)
208     close (fd);
209     #endif
210 root 1.2
211 ayin 1.28 fd = open ("/dev/tty", O_WRONLY);
212 root 1.1 if (fd < 0)
213 root 1.10 return -1; /* fatal */
214 root 1.2
215 root 1.1 close (fd);
216    
217     return 0;
218     }
219    
220 root 1.2 void
221 root 1.4 ptytty::close_tty ()
222 root 1.2 {
223     if (tty < 0)
224     return;
225    
226     close (tty);
227     tty = -1;
228     }
229    
230     bool
231 root 1.4 ptytty::make_controlling_tty ()
232 root 1.2 {
233     return control_tty (tty) >= 0;
234     }
235    
236     void
237 root 1.4 ptytty::set_utf8_mode (bool on)
238 root 1.2 {
239     #ifdef IUTF8
240     if (pty < 0)
241     return;
242    
243     struct termios tio;
244    
245     if (tcgetattr (pty, &tio) != -1)
246     {
247     tcflag_t new_cflag = tio.c_iflag;
248    
249     if (on)
250     new_cflag |= IUTF8;
251     else
252     new_cflag &= ~IUTF8;
253    
254     if (new_cflag != tio.c_iflag)
255     {
256     tio.c_iflag = new_cflag;
257     tcsetattr (pty, TCSANOW, &tio);
258     }
259     }
260     #endif
261     }
262    
263 root 1.1 static struct ttyconf {
264     gid_t gid;
265     mode_t mode;
266    
267     ttyconf ()
268     {
269     #ifdef TTY_GID_SUPPORT
270     struct group *gr = getgrnam ("tty");
271    
272     if (gr)
273 ayin 1.32 {
274     /* change group ownership of tty to "tty" */
275 root 1.1 mode = S_IRUSR | S_IWUSR | S_IWGRP;
276     gid = gr->gr_gid;
277     }
278     else
279 ayin 1.31 #endif /* TTY_GID_SUPPORT */
280 root 1.1 {
281     mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
282 root 1.2 gid = 0;
283 root 1.1 }
284     }
285     } ttyconf;
286    
287 root 1.4 ptytty_unix::ptytty_unix ()
288 root 1.1 {
289     name = 0;
290 root 1.2 #if UTMP_SUPPORT
291     cmd_pid = 0;
292 root 1.1 #endif
293     }
294    
295 root 1.4 ptytty_unix::~ptytty_unix ()
296 root 1.1 {
297 root 1.2 #if UTMP_SUPPORT
298 sf-exg 1.57 if (cmd_pid)
299     log_session (false, 0);
300 root 1.2 #endif
301 root 1.1 put ();
302     }
303    
304     void
305 root 1.4 ptytty_unix::put ()
306 root 1.2 {
307 root 1.25 if (name)
308     {
309     chmod (name, RESTORE_TTY_MODE);
310     chown (name, 0, ttyconf.gid);
311     }
312 root 1.1
313 root 1.2 close_tty ();
314 root 1.1
315 root 1.2 if (pty >= 0)
316     close (pty);
317 root 1.1
318     free (name);
319    
320     pty = tty = -1;
321     name = 0;
322     }
323    
324     bool
325 root 1.4 ptytty_unix::get ()
326 root 1.1 {
327     /* get master (pty) */
328     if ((pty = get_pty (&tty, &name)) < 0)
329     return false;
330    
331     /* get slave (tty) */
332     if (tty < 0)
333     {
334     #ifndef NO_SETOWNER_TTYDEV
335 root 1.2 chown (name, getuid (), ttyconf.gid); /* fail silently */
336     chmod (name, ttyconf.mode);
337     # ifdef HAVE_REVOKE
338     revoke (name);
339     # endif
340 root 1.1 #endif
341    
342     if ((tty = get_tty (name)) < 0)
343     {
344     put ();
345     return false;
346     }
347     }
348    
349 sf-exg 1.40 #if defined(I_PUSH)
350 sf-exg 1.39 /*
351     * Push STREAMS modules:
352     * ptem: pseudo-terminal hardware emulation module.
353     * ldterm: standard terminal line discipline.
354     * ttcompat: V7, 4BSD and XENIX STREAMS compatibility module.
355     *
356 sf-exg 1.55 * On Solaris, a process can acquire a controlling terminal in the
357     * following ways:
358     * - open() of /dev/ptmx or of a slave device without O_NOCTTY
359     * - I_PUSH ioctl() of the "ptem" or "ldterm" module on a slave device
360     * The second case is problematic, because it cannot be disabled.
361     * Fortunately, Solaris (10 and 11 at least) provides an undocumented
362     * __IPUSH_NOCTTY ioctl which does not have this side-effect, so we
363     * use it if defined. See
364     * https://github.com/illumos/illumos-gate/blob/master/usr/src/uts/common/os/streamio.c#L3755
365     * https://github.com/illumos/illumos-gate/blob/master/usr/src/uts/common/io/ptem.c#L203
366     * https://github.com/illumos/illumos-gate/blob/master/usr/src/uts/common/io/ldterm.c#L794
367     * Note that an open() of a slave device autoloads the modules,
368     * with __I_PUSH_NOCTTY, if xpg[46] mode is enabled (which requires
369     * linking /usr/lib/values-xpg[46].o).
370     * https://github.com/illumos/illumos-gate/blob/master/usr/src/lib/libc/port/sys/open.c#L173
371 sf-exg 1.39 */
372 sf-exg 1.55
373     #ifdef __I_PUSH_NOCTTY
374     # define PT_I_PUSH __I_PUSH_NOCTTY
375     #else
376     # define PT_I_PUSH I_PUSH
377     #endif
378    
379 sf-exg 1.39 #if defined(HAVE_ISASTREAM) && defined(HAVE_STROPTS_H)
380     if (isastream (tty) == 1)
381     # endif
382     {
383 sf-exg 1.56 if (!ioctl (tty, I_FIND, "ptem"))
384     ioctl (tty, PT_I_PUSH, "ptem");
385    
386     if (!ioctl (tty, I_FIND, "ldterm"))
387     ioctl (tty, PT_I_PUSH, "ldterm");
388    
389     if (!ioctl (tty, I_FIND, "ttcompat"))
390     ioctl (tty, PT_I_PUSH, "ttcompat");
391 sf-exg 1.39 }
392     #endif
393    
394 sf-exg 1.57 #if defined(USE_UTMP) && !defined(HAVE_UTMP_PID)
395 sf-exg 1.44 int fd_stdin = dup (STDIN_FILENO);
396     dup2 (tty, STDIN_FILENO);
397    
398     utmp_pos = ttyslot ();
399    
400     dup2 (fd_stdin, STDIN_FILENO);
401     close (fd_stdin);
402     #endif
403    
404 root 1.1 return true;
405     }
406    
407 sf-exg 1.57 void
408     ptytty_unix::login (int cmd_pid, bool login_shell, const char *hostname)
409     {
410     #if UTMP_SUPPORT
411     if (!name || !*name)
412     return;
413    
414     this->cmd_pid = cmd_pid;
415     this->login_shell = login_shell;
416    
417     log_session (true, hostname);
418     #endif
419     }