ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/libptytty/src/ptytty.C
Revision: 1.60
Committed: Fri Jul 23 10:15:08 2021 UTC (5 years, 1 month ago) by sf-exg
Content type: text/plain
Branch: MAIN
Changes since 1.59: +2 -1 lines
Log Message:
Simplify

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 sf-exg 1.60 # define SET_TTY_OWNER
144 root 1.1
145 root 1.25 /* Based on the code in openssh/openbsd-compat/bsd-openpty.c */
146     static int
147     get_pty (int *fd_tty, char **ttydev)
148     {
149     int pfd;
150     int i;
151     char pty_name[32];
152     char tty_name[32];
153     const char *majors = "pqrstuvwxyzabcde";
154     const char *minors = "0123456789abcdef";
155    
156     for (i = 0; i < 256; i++)
157     {
158 sf-exg 1.43 snprintf (pty_name, 32, "/dev/pty%c%c", majors[i / 16], minors[i % 16]);
159     snprintf (tty_name, 32, "/dev/tty%c%c", majors[i / 16], minors[i % 16]);
160 root 1.25
161     if ((pfd = open (pty_name, O_RDWR | O_NOCTTY, 0)) == -1)
162     {
163 sf-exg 1.43 snprintf (pty_name, 32, "/dev/ptyp%d", i);
164     snprintf (tty_name, 32, "/dev/ttyp%d", i);
165 root 1.25 if ((pfd = open (pty_name, O_RDWR | O_NOCTTY, 0)) == -1)
166     continue;
167     }
168    
169     if (access (tty_name, R_OK | W_OK) == 0)
170     {
171     *ttydev = strdup (tty_name);
172     return pfd;
173     }
174    
175     close (pfd);
176     }
177    
178     return -1;
179     }
180 ayin 1.24
181 root 1.1 #endif
182    
183     /*----------------------------------------------------------------------*/
184     /*
185 ayin 1.26 * Returns tty file descriptor, or -1 on failure
186 root 1.1 */
187     static int
188     get_tty (char *ttydev)
189     {
190     return open (ttydev, O_RDWR | O_NOCTTY, 0);
191     }
192    
193     /*----------------------------------------------------------------------*/
194     /*
195     * Make our tty a controlling tty so that /dev/tty points to us
196     */
197     static int
198 root 1.2 control_tty (int fd_tty)
199 root 1.1 {
200 ayin 1.28 int fd;
201    
202 root 1.1 setsid ();
203    
204 ayin 1.27 #ifdef TIOCSCTTY
205 root 1.2 ioctl (fd_tty, TIOCSCTTY, NULL);
206 ayin 1.27 #else
207 ayin 1.28 fd = open (ttyname (fd_tty), O_RDWR);
208 ayin 1.27 if (fd >= 0)
209     close (fd);
210     #endif
211 root 1.2
212 ayin 1.28 fd = open ("/dev/tty", O_WRONLY);
213 root 1.1 if (fd < 0)
214 root 1.10 return -1; /* fatal */
215 root 1.2
216 root 1.1 close (fd);
217    
218     return 0;
219     }
220    
221 root 1.2 void
222 root 1.4 ptytty::close_tty ()
223 root 1.2 {
224     if (tty < 0)
225     return;
226    
227     close (tty);
228     tty = -1;
229     }
230    
231     bool
232 root 1.4 ptytty::make_controlling_tty ()
233 root 1.2 {
234     return control_tty (tty) >= 0;
235     }
236    
237     void
238 root 1.4 ptytty::set_utf8_mode (bool on)
239 root 1.2 {
240     #ifdef IUTF8
241     if (pty < 0)
242     return;
243    
244     struct termios tio;
245    
246     if (tcgetattr (pty, &tio) != -1)
247     {
248     tcflag_t new_cflag = tio.c_iflag;
249    
250     if (on)
251     new_cflag |= IUTF8;
252     else
253     new_cflag &= ~IUTF8;
254    
255     if (new_cflag != tio.c_iflag)
256     {
257     tio.c_iflag = new_cflag;
258     tcsetattr (pty, TCSANOW, &tio);
259     }
260     }
261     #endif
262     }
263    
264 sf-exg 1.58 static struct ttyconf
265     {
266 root 1.1 gid_t gid;
267     mode_t mode;
268    
269     ttyconf ()
270 sf-exg 1.58 {
271 root 1.1 #ifdef TTY_GID_SUPPORT
272 sf-exg 1.58 struct group *gr = getgrnam ("tty");
273 root 1.1
274 sf-exg 1.58 if (gr)
275     {
276     /* change group ownership of tty to "tty" */
277     mode = S_IRUSR | S_IWUSR | S_IWGRP;
278     gid = gr->gr_gid;
279     }
280     else
281 ayin 1.31 #endif /* TTY_GID_SUPPORT */
282 sf-exg 1.58 {
283     mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
284     gid = 0;
285     }
286     }
287 root 1.1 } ttyconf;
288    
289 root 1.4 ptytty_unix::ptytty_unix ()
290 root 1.1 {
291     name = 0;
292 root 1.2 #if UTMP_SUPPORT
293     cmd_pid = 0;
294 root 1.1 #endif
295     }
296    
297 root 1.4 ptytty_unix::~ptytty_unix ()
298 root 1.1 {
299 root 1.2 #if UTMP_SUPPORT
300 sf-exg 1.57 if (cmd_pid)
301     log_session (false, 0);
302 root 1.2 #endif
303 root 1.1 put ();
304     }
305    
306     void
307 root 1.4 ptytty_unix::put ()
308 root 1.2 {
309 root 1.25 if (name)
310     {
311     chmod (name, RESTORE_TTY_MODE);
312     chown (name, 0, ttyconf.gid);
313     }
314 root 1.1
315 root 1.2 close_tty ();
316 root 1.1
317 root 1.2 if (pty >= 0)
318     close (pty);
319 root 1.1
320     free (name);
321    
322     pty = tty = -1;
323     name = 0;
324     }
325    
326     bool
327 root 1.4 ptytty_unix::get ()
328 root 1.1 {
329     /* get master (pty) */
330     if ((pty = get_pty (&tty, &name)) < 0)
331     return false;
332    
333     /* get slave (tty) */
334     if (tty < 0)
335     {
336 sf-exg 1.60 #ifdef SET_TTY_OWNER
337 root 1.2 chown (name, getuid (), ttyconf.gid); /* fail silently */
338     chmod (name, ttyconf.mode);
339     # ifdef HAVE_REVOKE
340     revoke (name);
341     # endif
342 root 1.1 #endif
343    
344     if ((tty = get_tty (name)) < 0)
345     {
346     put ();
347     return false;
348     }
349     }
350    
351 sf-exg 1.40 #if defined(I_PUSH)
352 sf-exg 1.39 /*
353     * Push STREAMS modules:
354     * ptem: pseudo-terminal hardware emulation module.
355     * ldterm: standard terminal line discipline.
356     * ttcompat: V7, 4BSD and XENIX STREAMS compatibility module.
357     *
358 sf-exg 1.55 * On Solaris, a process can acquire a controlling terminal in the
359     * following ways:
360     * - open() of /dev/ptmx or of a slave device without O_NOCTTY
361     * - I_PUSH ioctl() of the "ptem" or "ldterm" module on a slave device
362     * The second case is problematic, because it cannot be disabled.
363     * Fortunately, Solaris (10 and 11 at least) provides an undocumented
364     * __IPUSH_NOCTTY ioctl which does not have this side-effect, so we
365     * use it if defined. See
366 sf-exg 1.59 * https://github.com/illumos/illumos-gate/blob/19d32b9ab53d17ac6605971e14c45a5281f8d9bb/usr/src/uts/common/os/streamio.c#L3755
367     * https://github.com/illumos/illumos-gate/blob/19d32b9ab53d17ac6605971e14c45a5281f8d9bb/usr/src/uts/common/io/ptem.c#L203
368     * https://github.com/illumos/illumos-gate/blob/19d32b9ab53d17ac6605971e14c45a5281f8d9bb/usr/src/uts/common/io/ldterm.c#L794
369 sf-exg 1.55 * Note that an open() of a slave device autoloads the modules,
370     * with __I_PUSH_NOCTTY, if xpg[46] mode is enabled (which requires
371     * linking /usr/lib/values-xpg[46].o).
372 sf-exg 1.59 * https://github.com/illumos/illumos-gate/blob/19d32b9ab53d17ac6605971e14c45a5281f8d9bb/usr/src/lib/libc/port/sys/open.c#L173
373 sf-exg 1.39 */
374 sf-exg 1.55
375     #ifdef __I_PUSH_NOCTTY
376     # define PT_I_PUSH __I_PUSH_NOCTTY
377     #else
378     # define PT_I_PUSH I_PUSH
379     #endif
380    
381 sf-exg 1.39 #if defined(HAVE_ISASTREAM) && defined(HAVE_STROPTS_H)
382     if (isastream (tty) == 1)
383     # endif
384     {
385 sf-exg 1.56 if (!ioctl (tty, I_FIND, "ptem"))
386     ioctl (tty, PT_I_PUSH, "ptem");
387    
388     if (!ioctl (tty, I_FIND, "ldterm"))
389     ioctl (tty, PT_I_PUSH, "ldterm");
390    
391     if (!ioctl (tty, I_FIND, "ttcompat"))
392     ioctl (tty, PT_I_PUSH, "ttcompat");
393 sf-exg 1.39 }
394     #endif
395    
396 sf-exg 1.57 #if defined(USE_UTMP) && !defined(HAVE_UTMP_PID)
397 sf-exg 1.44 int fd_stdin = dup (STDIN_FILENO);
398     dup2 (tty, STDIN_FILENO);
399    
400     utmp_pos = ttyslot ();
401    
402     dup2 (fd_stdin, STDIN_FILENO);
403     close (fd_stdin);
404     #endif
405    
406 root 1.1 return true;
407     }
408    
409 sf-exg 1.57 void
410     ptytty_unix::login (int cmd_pid, bool login_shell, const char *hostname)
411     {
412     #if UTMP_SUPPORT
413     if (!name || !*name)
414     return;
415    
416     this->cmd_pid = cmd_pid;
417     this->login_shell = login_shell;
418    
419     log_session (true, hostname);
420     #endif
421     }