ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/libptytty/src/ptytty.C
Revision: 1.61
Committed: Sat Jul 24 09:05:17 2021 UTC (5 years, 1 month ago) by sf-exg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.60: +1 -1 lines
Log Message:
Update my email address

File Contents

# Content
1 /*----------------------------------------------------------------------*
2 * 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 * Copyright (c) 2004-2006 Marc Lehmann <schmorp@schmorp.de>
8 * Copyright (c) 2006 Emanuele Giaquinta <emanuele.giaquinta@gmail.com>
9 *
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 * the Free Software Foundation; either version 2 of the License, or
13 * (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 #include "config.h"
26
27 #include "ptytty.h"
28
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <unistd.h>
36 #include <fcntl.h>
37
38 #ifdef HAVE_SYS_IOCTL_H
39 # include <sys/ioctl.h>
40 #endif
41 #ifdef HAVE_STROPTS_H
42 # include <stropts.h>
43 #endif
44 #if defined(HAVE_PTY_H)
45 # include <pty.h>
46 #elif defined(HAVE_LIBUTIL_H)
47 # include <libutil.h>
48 #elif defined(HAVE_UTIL_H)
49 # include <util.h>
50 #endif
51 #ifdef TTY_GID_SUPPORT
52 #include <grp.h>
53 #endif
54
55 #ifndef O_NOCTTY
56 # define O_NOCTTY 0
57 #endif
58
59 /////////////////////////////////////////////////////////////////////////////
60
61 /* ------------------------------------------------------------------------- *
62 * GET PSEUDO TELETYPE - MASTER AND SLAVE *
63 * ------------------------------------------------------------------------- */
64 /*
65 * Returns pty file descriptor, or -1 on failure
66 * 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 #if defined(UNIX98_PTY)
70
71 static int
72 get_pty (int *fd_tty, char **ttydev)
73 {
74 int pfd;
75
76 # if defined(HAVE_GETPT)
77 pfd = getpt ();
78 # elif defined(HAVE_POSIX_OPENPT)
79 pfd = posix_openpt (O_RDWR | O_NOCTTY);
80 # else
81 # 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 # endif
87
88 if (pfd >= 0)
89 {
90 if (grantpt (pfd) == 0 /* change slave permissions */
91 && unlockpt (pfd) == 0)
92 {
93 /* slave now unlocked */
94 *ttydev = strdup (ptsname (pfd)); /* get slave's name */
95 return pfd;
96 }
97
98 close (pfd);
99 }
100
101 return -1;
102 }
103
104 #elif defined(HAVE_OPENPTY)
105
106 static int
107 get_pty (int *fd_tty, char **ttydev)
108 {
109 int pfd;
110 int res;
111
112 res = openpty (&pfd, fd_tty, NULL, NULL, NULL);
113
114 if (res != -1)
115 {
116 *ttydev = strdup (ttyname (*fd_tty));
117 return pfd;
118 }
119
120 return -1;
121 }
122
123 #elif defined(HAVE__GETPTY)
124
125 static int
126 get_pty (int *fd_tty, char **ttydev)
127 {
128 int pfd;
129 char *slave;
130
131 slave = _getpty (&pfd, O_RDWR | O_NOCTTY, 0622, 0);
132
133 if (slave != NULL)
134 {
135 *ttydev = strdup (slave);
136 return pfd;
137 }
138
139 return -1;
140 }
141
142 #else
143 # define SET_TTY_OWNER
144
145 /* 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 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
161 if ((pfd = open (pty_name, O_RDWR | O_NOCTTY, 0)) == -1)
162 {
163 snprintf (pty_name, 32, "/dev/ptyp%d", i);
164 snprintf (tty_name, 32, "/dev/ttyp%d", i);
165 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
181 #endif
182
183 /*----------------------------------------------------------------------*/
184 /*
185 * Returns tty file descriptor, or -1 on failure
186 */
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 control_tty (int fd_tty)
199 {
200 int fd;
201
202 setsid ();
203
204 #ifdef TIOCSCTTY
205 ioctl (fd_tty, TIOCSCTTY, NULL);
206 #else
207 fd = open (ttyname (fd_tty), O_RDWR);
208 if (fd >= 0)
209 close (fd);
210 #endif
211
212 fd = open ("/dev/tty", O_WRONLY);
213 if (fd < 0)
214 return -1; /* fatal */
215
216 close (fd);
217
218 return 0;
219 }
220
221 void
222 ptytty::close_tty ()
223 {
224 if (tty < 0)
225 return;
226
227 close (tty);
228 tty = -1;
229 }
230
231 bool
232 ptytty::make_controlling_tty ()
233 {
234 return control_tty (tty) >= 0;
235 }
236
237 void
238 ptytty::set_utf8_mode (bool on)
239 {
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 static struct ttyconf
265 {
266 gid_t gid;
267 mode_t mode;
268
269 ttyconf ()
270 {
271 #ifdef TTY_GID_SUPPORT
272 struct group *gr = getgrnam ("tty");
273
274 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 #endif /* TTY_GID_SUPPORT */
282 {
283 mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
284 gid = 0;
285 }
286 }
287 } ttyconf;
288
289 ptytty_unix::ptytty_unix ()
290 {
291 name = 0;
292 #if UTMP_SUPPORT
293 cmd_pid = 0;
294 #endif
295 }
296
297 ptytty_unix::~ptytty_unix ()
298 {
299 #if UTMP_SUPPORT
300 if (cmd_pid)
301 log_session (false, 0);
302 #endif
303 put ();
304 }
305
306 void
307 ptytty_unix::put ()
308 {
309 if (name)
310 {
311 chmod (name, RESTORE_TTY_MODE);
312 chown (name, 0, ttyconf.gid);
313 }
314
315 close_tty ();
316
317 if (pty >= 0)
318 close (pty);
319
320 free (name);
321
322 pty = tty = -1;
323 name = 0;
324 }
325
326 bool
327 ptytty_unix::get ()
328 {
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 #ifdef SET_TTY_OWNER
337 chown (name, getuid (), ttyconf.gid); /* fail silently */
338 chmod (name, ttyconf.mode);
339 # ifdef HAVE_REVOKE
340 revoke (name);
341 # endif
342 #endif
343
344 if ((tty = get_tty (name)) < 0)
345 {
346 put ();
347 return false;
348 }
349 }
350
351 #if defined(I_PUSH)
352 /*
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 * 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 * 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 * 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 * https://github.com/illumos/illumos-gate/blob/19d32b9ab53d17ac6605971e14c45a5281f8d9bb/usr/src/lib/libc/port/sys/open.c#L173
373 */
374
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 #if defined(HAVE_ISASTREAM) && defined(HAVE_STROPTS_H)
382 if (isastream (tty) == 1)
383 # endif
384 {
385 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 }
394 #endif
395
396 #if defined(USE_UTMP) && !defined(HAVE_UTMP_PID)
397 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 return true;
407 }
408
409 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 }