ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/libptytty/src/ptytty.C
Revision: 1.59
Committed: Tue Jun 29 12:09:53 2021 UTC (5 years, 2 months ago) by sf-exg
Content type: text/plain
Branch: MAIN
Changes since 1.58: +4 -4 lines
Log Message:
Update links

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 sf-exg 1.58 static struct ttyconf
264     {
265 root 1.1 gid_t gid;
266     mode_t mode;
267    
268     ttyconf ()
269 sf-exg 1.58 {
270 root 1.1 #ifdef TTY_GID_SUPPORT
271 sf-exg 1.58 struct group *gr = getgrnam ("tty");
272 root 1.1
273 sf-exg 1.58 if (gr)
274     {
275     /* change group ownership of tty to "tty" */
276     mode = S_IRUSR | S_IWUSR | S_IWGRP;
277     gid = gr->gr_gid;
278     }
279     else
280 ayin 1.31 #endif /* TTY_GID_SUPPORT */
281 sf-exg 1.58 {
282     mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
283     gid = 0;
284     }
285     }
286 root 1.1 } ttyconf;
287    
288 root 1.4 ptytty_unix::ptytty_unix ()
289 root 1.1 {
290     name = 0;
291 root 1.2 #if UTMP_SUPPORT
292     cmd_pid = 0;
293 root 1.1 #endif
294     }
295    
296 root 1.4 ptytty_unix::~ptytty_unix ()
297 root 1.1 {
298 root 1.2 #if UTMP_SUPPORT
299 sf-exg 1.57 if (cmd_pid)
300     log_session (false, 0);
301 root 1.2 #endif
302 root 1.1 put ();
303     }
304    
305     void
306 root 1.4 ptytty_unix::put ()
307 root 1.2 {
308 root 1.25 if (name)
309     {
310     chmod (name, RESTORE_TTY_MODE);
311     chown (name, 0, ttyconf.gid);
312     }
313 root 1.1
314 root 1.2 close_tty ();
315 root 1.1
316 root 1.2 if (pty >= 0)
317     close (pty);
318 root 1.1
319     free (name);
320    
321     pty = tty = -1;
322     name = 0;
323     }
324    
325     bool
326 root 1.4 ptytty_unix::get ()
327 root 1.1 {
328     /* get master (pty) */
329     if ((pty = get_pty (&tty, &name)) < 0)
330     return false;
331    
332     /* get slave (tty) */
333     if (tty < 0)
334     {
335     #ifndef NO_SETOWNER_TTYDEV
336 root 1.2 chown (name, getuid (), ttyconf.gid); /* fail silently */
337     chmod (name, ttyconf.mode);
338     # ifdef HAVE_REVOKE
339     revoke (name);
340     # endif
341 root 1.1 #endif
342    
343     if ((tty = get_tty (name)) < 0)
344     {
345     put ();
346     return false;
347     }
348     }
349    
350 sf-exg 1.40 #if defined(I_PUSH)
351 sf-exg 1.39 /*
352     * Push STREAMS modules:
353     * ptem: pseudo-terminal hardware emulation module.
354     * ldterm: standard terminal line discipline.
355     * ttcompat: V7, 4BSD and XENIX STREAMS compatibility module.
356     *
357 sf-exg 1.55 * On Solaris, a process can acquire a controlling terminal in the
358     * following ways:
359     * - open() of /dev/ptmx or of a slave device without O_NOCTTY
360     * - I_PUSH ioctl() of the "ptem" or "ldterm" module on a slave device
361     * The second case is problematic, because it cannot be disabled.
362     * Fortunately, Solaris (10 and 11 at least) provides an undocumented
363     * __IPUSH_NOCTTY ioctl which does not have this side-effect, so we
364     * use it if defined. See
365 sf-exg 1.59 * https://github.com/illumos/illumos-gate/blob/19d32b9ab53d17ac6605971e14c45a5281f8d9bb/usr/src/uts/common/os/streamio.c#L3755
366     * https://github.com/illumos/illumos-gate/blob/19d32b9ab53d17ac6605971e14c45a5281f8d9bb/usr/src/uts/common/io/ptem.c#L203
367     * https://github.com/illumos/illumos-gate/blob/19d32b9ab53d17ac6605971e14c45a5281f8d9bb/usr/src/uts/common/io/ldterm.c#L794
368 sf-exg 1.55 * Note that an open() of a slave device autoloads the modules,
369     * with __I_PUSH_NOCTTY, if xpg[46] mode is enabled (which requires
370     * linking /usr/lib/values-xpg[46].o).
371 sf-exg 1.59 * https://github.com/illumos/illumos-gate/blob/19d32b9ab53d17ac6605971e14c45a5281f8d9bb/usr/src/lib/libc/port/sys/open.c#L173
372 sf-exg 1.39 */
373 sf-exg 1.55
374     #ifdef __I_PUSH_NOCTTY
375     # define PT_I_PUSH __I_PUSH_NOCTTY
376     #else
377     # define PT_I_PUSH I_PUSH
378     #endif
379    
380 sf-exg 1.39 #if defined(HAVE_ISASTREAM) && defined(HAVE_STROPTS_H)
381     if (isastream (tty) == 1)
382     # endif
383     {
384 sf-exg 1.56 if (!ioctl (tty, I_FIND, "ptem"))
385     ioctl (tty, PT_I_PUSH, "ptem");
386    
387     if (!ioctl (tty, I_FIND, "ldterm"))
388     ioctl (tty, PT_I_PUSH, "ldterm");
389    
390     if (!ioctl (tty, I_FIND, "ttcompat"))
391     ioctl (tty, PT_I_PUSH, "ttcompat");
392 sf-exg 1.39 }
393     #endif
394    
395 sf-exg 1.57 #if defined(USE_UTMP) && !defined(HAVE_UTMP_PID)
396 sf-exg 1.44 int fd_stdin = dup (STDIN_FILENO);
397     dup2 (tty, STDIN_FILENO);
398    
399     utmp_pos = ttyslot ();
400    
401     dup2 (fd_stdin, STDIN_FILENO);
402     close (fd_stdin);
403     #endif
404    
405 root 1.1 return true;
406     }
407    
408 sf-exg 1.57 void
409     ptytty_unix::login (int cmd_pid, bool login_shell, const char *hostname)
410     {
411     #if UTMP_SUPPORT
412     if (!name || !*name)
413     return;
414    
415     this->cmd_pid = cmd_pid;
416     this->login_shell = login_shell;
417    
418     log_session (true, hostname);
419     #endif
420     }