1 char *ckptyv = "Pseudoterminal support, 9.0.104, 18 Sep 2020";
2 
3 /*  C K U P T Y  --  C-Kermit pseudoterminal control functions for UNIX  */
4 
5 /* Last update: Sat Sep 19 15:25:13 2020 */
6 
7 /*
8   Copyright 1995 by the Massachusetts Institute of Technology.
9 
10   Permission to use, copy, modify, and distribute this software and its
11   documentation for any purpose and without fee is hereby granted, provided
12   that the above copyright notice appear in all copies and that both that
13   copyright notice and this permission notice appear in supporting
14   documentation, and that the name of M.I.T. not be used in advertising or
15   publicity pertaining to distribution of the software without specific,
16   written prior permission.  Furthermore if you modify this software you must
17   label your software as modified software and not distribute it in such a
18   fashion that it might be confused with the original M.I.T. software.
19   M.I.T. makes no representations about the suitability of this software for
20   any purpose.  It is provided "as is" without express or implied warranty.
21 
22   Modified for use in C-Kermit, and new material added, by:
23 
24   Jeffrey Altman <jaltman@secure-endpoints.com>
25   Secure Endpoints Inc., New York City
26   November 1999
27 
28   Parameterized for pty file descriptor and function code,
29   Dec 2006 - Sep 2009, plus some minor "compliance" nits addressed in 2020.
30   See "HAVE_OPENPTY" section of ckcdeb.h.
31   Frank da Cruz, The Kermit Project, New York City
32 */
33 
34 /*
35   Built and tested successully on:
36    . 4.4BSD, including BSDI/OS, NetBSD, FreeBSD, OpenBSD, Mac OS X
37    . AIX 4.1 and later
38    . DG/UX 5.4R4.11
39    . Digital UNIX 3.2 and 4.0
40    . HP-UX 9.00 and later
41    . IRIX 6.0 and later
42    . Linux
43    . Mac OS X 10.4
44    . NeXTSTEP 3.x
45    . OpenBSD
46    . QNX 4.25 (except PTY process termination not detected)
47    . SCO OSR5.0.5
48    . SCO Unixware 7
49    . SINIX 5.42
50    . Solaris 2.x and 7
51    . SunOS 4.1.3
52 
53   Failures include:
54    . SCO UNIX 3.2v4.2 (compile fails with syntax error in <memory.h>)
55    . HP-UX 8.00 and earlier (no vhangup or ptsname routines)
56 */
57 
58 #if !defined(__FreeBSD__) && !defined(__DragonFly__) /* bs  20151224 */
59 #define _XOPEN_SOURCE 500		/* mdw 20140223 */
60 #endif /* __FreeBSD__ */		/* bs  20151224 */
61 #include <stdlib.h>			/* mdw 20140223 */
62 #include "ckcsym.h"
63 #include "ckcdeb.h"			/* To pick up NETPTY definition */
64 
65 #ifdef __DragonFly__
66 #include <libutil.h>  /* for openpty() */
67 #endif
68 
69 #ifndef NETPTY				/* Selector for PTY support */
70 
71 char * ptyver = "No PTY support";
72 
73 #else  /* (rest of this module...) */
74 
75 char * ptyver = "PTY support 8.0.017, 18 Sep 2020";
76 
77 /* These will no doubt need adjustment... */
78 
79 #ifndef NEXT
80 #define HAVE_SETSID
81 #endif /* NEXT */
82 #define HAVE_KILLPG
83 #define HAVE_TTYNAME
84 #define HAVE_WAITPID
85 
86 #ifdef SUNOS41
87 #define BSD44ORPOSIX
88 #endif	/* SUNOS41 */
89 
90 #ifndef USE_TERMIO
91 #ifdef LINUX
92 #define USE_TERMIO
93 #else
94 #ifdef ATTSV
95 #define USE_TERMIO
96 #else
97 #ifdef HPUX
98 #define USE_TERMIO
99 #else
100 #ifdef AIX
101 #define USE_TERMIO
102 #else
103 #ifdef BSD44ORPOSIX
104 #define USE_TERMIO
105 #else
106 #ifdef IRIX60
107 #define USE_TERMIO
108 #else
109 #ifdef QNX
110 #define USE_TERMIO
111 #endif /* QNX */
112 #endif /* IRIX60 */
113 #endif /* BSD44ORPOSIX */
114 #endif /* AIX */
115 #endif /* HPUX */
116 #endif /* ATTSV */
117 #endif /* LINUX */
118 #endif /* USE_TERMIO */
119 
120 #ifdef QNX
121 #include <fcntl.h>
122 #endif /* QNX */
123 
124 #ifdef USE_TERMIO
125 #define POSIX_TERMIOS			/* Seems to be a misnomer */
126 #endif /* USE_TERMIO */
127 
128 #ifdef NEXT
129 #ifndef GETPGRP_ONEARG
130 #define GETPGRP_ONEARG
131 #endif /* GETPGRP_ONEARG */
132 #endif /* NEXT */
133 
134 #ifdef WANT_UTMP			/* See ckupty.h */
135 /*
136   WANT_UTMP is not defined because (a) the utmp/wtmp junk is the most
137   nonportable part of this module, and (b) we're not logging anybody
138   in, we're just running a process, and don't need to write utmp/wtmp records.
139 */
140 #ifndef HAVE_SETUTXENT			/* Who has <utmpx.h> */
141 #ifdef SOLARIS
142 #define HAVE_SETUTXENT
143 #else
144 #ifdef IRIX60
145 #define HAVE_SETUTXENT
146 #else
147 #ifdef CK_SCOV5
148 #define HAVE_SETUTXENT
149 #else
150 #ifdef HPUX10
151 #define HAVE_SETUTXENT
152 #else
153 #ifdef UNIXWARE
154 #define HAVE_SETUTXENT
155 #else
156 #ifdef IRIX60
157 #define HAVE_SETUTXENT
158 #endif /* IRIX60 */
159 #endif /* UNIXWARE */
160 #endif /* HPUX10 */
161 #endif /* CK_SCOV5 */
162 #endif /* IRIX60 */
163 #endif /* SOLARIS */
164 #endif /* HAVE_SETUTXENT */
165 
166 #ifndef HAVE_UTHOST			/* Does utmp include ut_host[]? */
167 #ifdef HAVE_SETUTXENT			/* utmpx always does */
168 #define HAVE_UTHOST
169 #else
170 #ifdef LINUX				/* Linux does */
171 #define HAVE_UTHOST
172 #else
173 #ifdef SUNOS4				/* SunOS does */
174 #define HAVE_UTHOST
175 #else
176 #ifdef AIX41				/* AIX 4.1 and later do */
177 #define HAVE_UTHOST
178 #endif /* AIX41 */
179 #endif /* SUNOS4 */
180 #endif /* LINUX */
181 #endif /* HAVE_SETUTXENT */
182 #endif /* HAVE_UTHOST */
183 
184 #ifndef HAVE_UT_HOST
185 #ifndef NO_UT_HOST
186 #define NO_UT_HOST
187 #endif /* NO_UT_HOST */
188 #endif /* HAVE_UT_HOST */
189 
190 #endif /* WANT_UTMP */
191 
192 #ifdef LINUX
193 #define CK_VHANGUP
194 #define HAVE_SYS_SELECT_H
195 #define HAVE_GETUTENT
196 #define HAVE_SETUTENT
197 #define HAVE_UPDWTMP
198 #endif /* LINUX */
199 
200 #ifdef HPUX10
201 #define CK_VHANGUP
202 #define VHANG_FIRST
203 #define HAVE_PTSNAME
204 #ifndef HAVE_PTYTRAP
205 #define HAVE_PTYTRAP
206 #endif /* HAVE_PTYTRAP */
207 #else
208 #ifdef HPUX9
209 #define CK_VHANGUP
210 #define VHANG_FIRST
211 #define HAVE_PTSNAME
212 #ifndef HAVE_PTYTRAP
213 #define HAVE_PTYTRAP
214 #endif /* HAVE_PTYTRAP */
215 #endif /* HPUX9 */
216 #endif /* HPUX10 */
217 
218 #ifdef SUNOS4
219 #define CK_VHANGUP
220 #define NO_UT_PID
221 #define VHANG_FIRST
222 #endif /* SUNOS4 */
223 
224 #ifdef IRIX60
225 #define CK_VHANGUP
226 #define HAVE__GETPTY
227 #endif /* IRIX60 */
228 
229 #ifdef SINIX
230 #define HAVE_STREAMS
231 #define HAVE_GRANTPT
232 #define HAVE_PTSNAME
233 #define PUSH_PTEM
234 #define PUSH_LDTERM
235 #define PUSH_TTCOMPAT
236 #endif /* SINIX */
237 
238 #ifdef ultrix
239 #define MUST_SETPGRP
240 #endif /* ultrix */
241 
242 #ifdef QNX
243 #define MUST_SETPGRP
244 #define NO_DEVTTY
245 #define INIT_SPTY
246 #endif /* QNX */
247 
248 #ifdef LINUX
249 #ifdef HAVE_PTMX
250 #define HAVE_GRANTPT
251 #define HAVE_PTSNAME
252 #endif /* HAVE_PTMX */
253 #else
254 #ifdef HAVE_STREAMS
255 #define HAVE_PTMX
256 #endif /* HAVE_STREAMS */
257 #endif /* LINUX */
258 
259 #include "ckupty.h"
260 
261 #ifdef PTYNOBLOCK
262 #ifndef O_NDELAY
263 #ifdef O_NONBLOCK
264 #define O_NDELAY O_NONBLOCK
265 #endif /* O_NONBLOCK */
266 #endif /* O_NDELAY */
267 #else /* PTYNOBLOCK */
268 #ifdef O_NDELAY
269 #undef O_NDELAY
270 #endif /* O_NDELAY */
271 #define O_NDELAY 0
272 #endif /* PTYNOBLOCK */
273 
274 #ifndef ONLCR
275 #define ONLCR 0
276 #endif /* ONLCR */
277 
278 #ifdef CK_WAIT_H
279 #include <sys/wait.h>
280 #endif /* CK_WAIT_H */
281 
282 #ifdef STREAMSPTY
283 #ifndef INIT_SPTY
284 #define INIT_SPTY
285 #endif /* INIT_SPTY */
286 
287 #include <sys/stream.h>
288 #include <stropts.h>
289 #include <termio.h>
290 
291 /* Make sure we don't get the BSD version */
292 
293 #ifdef HAVE_SYS_TTY_H
294 #include "/usr/include/sys/tty.h"
295 #endif /* HAVE_SYS_TTY_H */
296 
297 #ifdef HAS_PTYVAR			/* Where is this set? */
298 
299 #include <sys/ptyvar.h>
300 
301 #else /* HAS_PTYVAR */
302 
303 #ifndef TIOCPKT_FLUSHWRITE
304 #define TIOCPKT_FLUSHWRITE 0x02
305 #define TIOCPKT_NOSTOP     0x10
306 #define TIOCPKT_DOSTOP     0x20
307 #define TIOCPKT_IOCTL      0x40
308 #endif /* TIOCPKT_FLUSHWRITE */
309 
310 #endif /* HAS_PTYVAR */
311 
312 #ifdef HAVE_TTY_H
313 #include <tty.h>
314 #endif /* HAVE_TTY_H */
315 
316 /*
317   Because of the way ptyibuf is used with streams messages, we need
318   ptyibuf+1 to be on a full-word boundary.  The following weirdness
319   is simply to make that happen.
320 */
321 long ptyibufbuf[BUFSIZ/sizeof(long)+1];
322 char *ptyibuf = ((char *)&ptyibufbuf[1])-1;
323 char *ptyip = ((char *)&ptyibufbuf[1])-1;
324 char ptyibuf2[BUFSIZ];
325 unsigned char ctlbuf[BUFSIZ];
326 struct strbuf strbufc, strbufd;
327 
328 int readstream();
329 
330 #else  /* ! STREAMSPTY */
331 
332 /* I/O data buffers, pointers, and counters. */
333 
334 char ptyibuf[BUFSIZ], *ptyip = ptyibuf;
335 char ptyibuf2[BUFSIZ];
336 
337 #endif /* ! STREAMSPTY */
338 
339 #ifndef USE_TERMIO
340 struct termbuf {
341     struct sgttyb sg;
342     struct tchars tc;
343     struct ltchars ltc;
344     int state;
345     int lflags;
346 } termbuf, termbuf2;
347 
348 #define cfsetospeed(tp,val) (tp)->sg.sg_ospeed = (val)
349 #define cfsetispeed(tp,val) (tp)->sg.sg_ispeed = (val)
350 #define cfgetospeed(tp)     (tp)->sg.sg_ospeed
351 #define cfgetispeed(tp)     (tp)->sg.sg_ispeed
352 
353 #else  /* USE_TERMIO */
354 
355 #ifdef SYSV_TERMIO
356 #define termios termio
357 #endif /* SYSV_TERMIO */
358 
359 #ifndef TCSANOW
360 
361 #ifdef TCSETS
362 
363 #define TCSANOW TCSETS
364 #define TCSADRAIN TCSETSW
365 #define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
366 
367 #else /* TCSETS */
368 
369 #ifdef TCSETA
370 #define TCSANOW TCSETA
371 #define TCSADRAIN TCSETAW
372 #define tcgetattr(f,t) ioctl(f,TCGETA,(char *)t)
373 #else /* TCSETA */
374 #define TCSANOW TIOCSETA
375 #define TCSADRAIN TIOCSETAW
376 #define tcgetattr(f,t) ioctl(f,TIOCGETA,(char *)t)
377 #endif /* TCSETA */
378 
379 #endif /* TCSETS */
380 
381 #define tcsetattr(f,a,t) ioctl(f,a,t)
382 #define cfsetospeed(tp,val) (tp)->c_cflag &= ~CBAUD;(tp)->c_cflag|=(val)
383 #define cfgetospeed(tp) ((tp)->c_cflag & CBAUD)
384 
385 #ifdef CIBAUD
386 #define cfsetispeed(tp,val) \
387  (tp)->c_cflag &= ~CIBAUD; (tp)->c_cflag |= ((val)<<IBSHIFT)
388 #define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT)
389 #else /* CIBAUD */
390 #define cfsetispeed(tp,val) (tp)->c_cflag &= ~CBAUD; (tp)->c_cflag|=(val)
391 #define cfgetispeed(tp) ((tp)->c_cflag & CBAUD)
392 #endif /* CIBAUD */
393 
394 #endif /* TCSANOW */
395 
396 struct termios termbuf, termbuf2;       /* pty control structure */
397 
398 #ifdef INIT_SPTY
399 static int spty = -1;
400 #endif /* INIT_SPTY */
401 
402 #endif /* USE_TERMIO */
403 
404 #ifndef IXANY				/* This was in #ifdef QNX.. */
405 #define IXANY 0				/* but because of _XOPEN_SOURCE */
406 #endif	/* IXANY */                     /* must be universal - does no harm */
407 
408 static int msg = 0;
409 
410 /* Variables available to other modules */
411 
412 int pty_fork_active = 0;		/* pty fork is active */
413 PID_T pty_fork_pid = -1;		/* pty fork pid */
414 int pty_slave_fd = -1;			/* pty slave file descriptor */
415 int pty_master_fd = -1;			/* pty master file descriptor */
416 
417 /* termbuf routines (begin) */
418 /*
419   init_termbuf()
420   copy_termbuf(cp)
421   set_termbuf()
422 
423   These three routines are used to get and set the "termbuf" structure
424   to and from the kernel.  init_termbuf() gets the current settings.
425   copy_termbuf() hands in a new "termbuf" to write to the kernel, and
426   set_termbuf() writes the structure into the kernel.
427 */
428 VOID
init_termbuf(fd)429 init_termbuf(fd) int fd; {
430     int ttyfd;
431     int rc = 0;
432 
433     ttyfd = fd;
434 
435 #ifdef HAVE_STREAMS
436     debug(F100,"init_termbuf HAVE_STREAMS","",0);
437 #else
438     debug(F100,"init_termbuf HAVE_STREAMS NOT DEFINED","",0);
439 #endif	/* HAVE_STREAMS */
440 #ifdef STREAMSPTY
441     debug(F100,"init_termbuf STREAMSPTY","",0);
442 #else
443     debug(F100,"init_termbuf STREAMSPTY NOT DEFINED","",0);
444 #endif	/* STREAMSPTY */
445 #ifdef INIT_SPTY
446     debug(F100,"init_termbuf INIT_SPTY","",0);
447 #else
448     debug(F100,"init_termbuf INIT_SPTY NOT DEFINED","",0);
449 #endif	/* INIT_SPTY */
450 
451     debug(F101,"init_termbuf ttyfd","",ttyfd);
452 #ifdef INIT_SPTY
453     debug(F101,"init_termbuf spty","",spty);
454 #endif	/* INIT_SPTY */
455 
456     memset(&termbuf,0,sizeof(termbuf));
457     memset(&termbuf2,0,sizeof(termbuf2));
458 #ifndef	USE_TERMIO
459     rc = ioctl(ttyfd, TIOCGETP, (char *)&termbuf.sg);
460     rc |= ioctl(ttyfd, TIOCGETC, (char *)&termbuf.tc);
461     rc |= ioctl(ttyfd, TIOCGLTC, (char *)&termbuf.ltc);
462 #ifdef TIOCGSTATE
463     rc |= ioctl(ttyfd, TIOCGSTATE, (char *)&termbuf.state);
464 #endif /* TIOCGSTATE */
465 #else /* USE_TERMIO */
466     errno = 0;
467 #ifdef INIT_SPTY
468     rc = tcgetattr(spty, &termbuf);
469     debug(F111,"init_termbuf() tcgetattr(spty)",ckitoa(rc),errno);
470 #else
471     rc = tcgetattr(ttyfd, &termbuf);
472     debug(F111,"init_termbuf() tcgetattr(ttyfd)",ckitoa(rc),errno);
473 #endif /* INIT_SPTY */
474 #endif /* USE_TERMIO */
475     if (!rc)
476       termbuf2 = termbuf;
477 }
478 
479 #ifdef TIOCPKT_IOCTL
480 VOID
copy_termbuf(cp,len)481 copy_termbuf(cp, len) char *cp; int len; {
482     if (len > sizeof(termbuf))
483       len = sizeof(termbuf);
484     memcpy((char *)&termbuf, cp, len);
485     termbuf2 = termbuf;
486 }
487 #endif /* TIOCPKT_IOCTL */
488 
489 VOID
set_termbuf(fd)490 set_termbuf(fd) int fd; {		/* Only make the necessary changes. */
491     int x;
492     int ttyfd;
493     ttyfd = fd;
494 
495     debug(F101,"set_termbuf ttyfd","",ttyfd);
496 #ifdef INIT_SPTY
497     debug(F101,"set_termbuf spty","",spty);
498 #endif	/* INIT_SPTY */
499 
500 #ifndef	USE_TERMIO
501     debug(F100,"set_termbuf USE_TERMIO","",0);
502     if (memcmp((char *)&termbuf.sg, (char *)&termbuf2.sg, sizeof(termbuf.sg)))
503       ioctl(ttyfd, TIOCSETN, (char *)&termbuf.sg);
504     if (memcmp((char *)&termbuf.tc, (char *)&termbuf2.tc, sizeof(termbuf.tc)))
505       ioctl(ttyfd, TIOCSETC, (char *)&termbuf.tc);
506     if (memcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc,
507 	       sizeof(termbuf.ltc)))
508       ioctl(ttyfd, TIOCSLTC, (char *)&termbuf.ltc);
509     if (termbuf.lflags != termbuf2.lflags)
510       ioctl(ttyfd, TIOCLSET, (char *)&termbuf.lflags);
511 #else  /* USE_TERMIO */
512     x = memcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf));
513     debug(F101,"set_termbuf !USE_TERMIO memcmp","",x);
514     x = 1;				/* Force this */
515     if (x) {
516 	int x;
517 	errno = 0;
518 #ifdef INIT_SPTY
519 	debug(F100,"set_termbuf INIT_SPTY","",0);
520 	x = tcsetattr(spty, TCSANOW, &termbuf);
521 	debug(F111,"set_termbuf tcsetattr(spty)",ckitoa(x),errno);
522 #else
523 	debug(F100,"set_termbuf !INIT_SPTY","",0);
524 	x = tcsetattr(ttyfd, TCSANOW, &termbuf);
525 	debug(F111,"set_termbuf tcsetattr(ttyfd)",ckitoa(x),errno);
526 #endif /* INIT_SPTY */
527     }
528 #endif /* USE_TERMIO */
529 }
530 /* termbuf routines (end) */
531 
532 VOID
ptyint_vhangup()533 ptyint_vhangup() {
534 #ifdef CK_VHANGUP
535     _PROTOTYP( int vhangup, (void) );
536 #ifdef CK_POSIX_SIG
537     struct sigaction sa;
538     /* Initialize "sa" structure. */
539     sigemptyset(&sa.sa_mask);
540     sa.sa_flags = 0;
541     sa.sa_handler = SIG_IGN;
542     sigaction(SIGHUP, &sa, (struct sigaction *)0);
543     vhangup();
544     sa.sa_handler = SIG_DFL;
545     sigaction(SIGHUP, &sa, (struct sigaction *)0);
546 #else /* CK_POSIX_SIG */
547     signal(SIGHUP,SIG_IGN);
548     vhangup();
549     signal(SIGHUP,SIG_DFL);
550 #endif /* CK_POSIX_SIG */
551 #endif /* CK_VHANGUP */
552 }
553 
554 /*
555   This routine is called twice.  It's not particularly important that the
556   setsid() or TIOCSCTTY ioctls succeed (they may not the second time), but
557   rather that we have a controlling terminal at the end.  It is assumed that
558   vhangup doesn't exist and confuse the process's notion of controlling
559   terminal on any system without TIOCNOTTY.  That is, either vhangup() leaves
560   the controlling terminal in tact, breaks the association completely, or the
561   system provides TIOCNOTTY to get things back into a reasonable state.  In
562   practice, vhangup() either breaks the association completely or doesn't
563   effect controlling terminals, so this condition is met.
564 */
565 long
ptyint_void_association()566 ptyint_void_association() {
567     int con_fd;
568 #ifdef HAVE_SETSID
569     debug(F110,
570 	  "ptyint_void_association()",
571 	  "setsid()",
572 	  0
573 	  );
574     setsid();
575 #endif /* HAVE_SETSID */
576 
577 #ifndef NO_DEVTTY
578     /* Void tty association first */
579 #ifdef TIOCNOTTY
580     con_fd = open("/dev/tty", O_RDWR);
581     debug(F111,
582 	  "ptyint_void_association() open(/dev/tty,O_RDWR)",
583 	  "/dev/tty",
584 	  con_fd);
585     if (con_fd >= 0) {
586         ioctl(con_fd, TIOCNOTTY, 0);
587         close(con_fd);
588     }
589 #ifdef DEBUG
590     else debug(F101, "ptyint_void_association() open() errno","",errno);
591 #endif /* DEBUG */
592 #endif /* TIOCNOTTY */
593 #endif /* NO_DEVTTY */
594     return(0);
595 }
596 
597 /* PID may be zero for unknown.*/
598 
599 long
pty_cleanup(slave,pid,update_utmp)600 pty_cleanup(slave, pid, update_utmp) char *slave; int pid; int update_utmp; {
601 #ifdef VHANG_LAST
602     int retval, fd;
603 #endif /* VHANG_LAST */
604 
605     debug(F111,"pty_cleanup()",slave,pid);
606 #ifdef WANT_UTMP
607     if (update_utmp)
608       pty_update_utmp(PTY_DEAD_PROCESS,
609 		      0,
610 		      "",
611 		      slave,
612 		      (char *)0,
613 		      PTY_UTMP_USERNAME_VALID
614 		      );
615 #endif /* WANT_UTMP */
616 
617 #ifdef SETUID
618     chmod(slave, 0666);
619     chown(slave, 0, 0);
620 #endif /* SETUID */
621 
622 #ifdef HAVE_REVOKE
623     revoke(slave);
624     /*
625        Revoke isn't guaranteed to send a SIGHUP to the processes it
626        dissociates from the terminal.  The best solution without a Posix
627        mechanism for forcing a hangup is to killpg() the process group of the
628        pty.  This will at least kill the shell and hopefully, the child
629        processes.  This is not always the case, however.  If the shell puts
630        each job in a process group and doesn't pass along SIGHUP, all
631        processes may not die.
632     */
633     if (pid > 0) {
634 #ifdef HAVE_KILLPG
635 	killpg(pid, SIGHUP);
636 #else
637 	kill(-(pid), SIGHUP);
638 #endif /*HAVE_KILLPG*/
639     }
640 #else /* HAVE_REVOKE*/
641 #ifdef VHANG_LAST
642     {
643         int status;
644 #ifdef CK_POSIX_SIG
645         sigset_t old, new;
646         sigemptyset(&new);
647         sigaddset(&new, SIGCHLD);
648         sigprocmask(SIG_BLOCK, &new, &old);
649 #else /*CK_POSIX_SIG*/
650         int mask = sigblock(sigmask(SIGCHLD));
651 #endif /*CK_POSIX_SIG*/
652         switch (retval = fork()) {
653 	  case -1:
654 #ifdef CK_POSIX_SIG
655             sigprocmask(SIG_SETMASK, &old, 0);
656 #else /*CK_POSIX_SIG*/
657             sigsetmask(mask);
658 #endif /*CK_POSIX_SIG*/
659             return errno;
660 	  case 0:
661             ptyint_void_association();
662             if (retval = (pty_open_ctty(slave, &fd, -1)))
663 	      exit(retval);
664             ptyint_vhangup();
665             exit(0);
666 	    break;
667 	  default:
668 #ifdef HAVE_WAITPID
669             waitpid(retval, &status, 0);
670 #else /*HAVE_WAITPID*/
671             wait(&status);
672 #endif /* HAVE_WAITPID */
673 #ifdef CK_POSIX_SIG
674             sigprocmask(SIG_SETMASK, &old, 0);
675 #else /*CK_POSIX_SIG*/
676             sigsetmask(mask);
677 #endif /*CK_POSIX_SIG*/
678             break;
679         }
680     }
681 #endif /*VHANG_LAST*/
682 #endif /* HAVE_REVOKE*/
683 #ifndef HAVE_STREAMS
684     slave[strlen("/dev/")] = 'p';
685 #ifdef SETUID
686     chmod(slave, 0666);
687     chown(slave, 0, 0);
688 #endif /* SETUID */
689 #endif /* HAVE_STREAMS */
690     return(0);
691 }
692 
693 long
pty_getpty(fd,slave,slavelength)694 pty_getpty(fd, slave, slavelength) int slavelength; int *fd; char *slave; {
695     char *cp;
696     char *p;
697     int i, ptynum;
698     struct stat stb;
699 #ifndef HAVE_OPENPTY
700 #ifndef HAVE__GETPTY
701     char slavebuf[1024];
702 #endif /* HAVE__GETPTY */
703 #endif /* HAVE_OPENPTY */
704 #ifdef HAVE__GETPTY
705     char *slaveret;			/* Temp to hold pointer to slave */
706 #endif /*HAVE__GETPTY*/
707 
708 #ifdef HAVE_OPENPTY
709     int slavefd;
710 
711     pty_master_fd = -1;
712     debug(F100,"HAVE_OPENPTY","",0);
713     if (openpty(fd,
714 		&slavefd,
715 		slave,
716 		(struct termios *)0,
717 		(struct winsize *)0
718 		)
719 	) {
720 	pty_master_fd = *fd;
721 	return(1);
722     }
723     close(slavefd);
724     return(0);
725 
726 #else /* HAVE_OPENPTY */
727 
728 #ifdef HAVE__GETPTY
729 /*
730   This code is included for Irix; as of version 5.3, Irix has /dev/ptmx, but
731   it fails to work properly; even after calling unlockpt, root gets permission
732   denied opening the pty.  The code to support _getpty should be removed if
733   Irix gets working streams ptys in favor of maintaining the least needed code
734   paths.
735 */
736     debug(F100,"HAVE__GETPTY","",0);
737     if ((slaveret = _getpty(fd, O_RDWR | O_NDELAY, 0600, 0)) == 0) {
738 	*fd = -1;
739 	return(PTY_GETPTY_NOPTY);
740     }
741     if (strlen(slaveret) > slavelength - 1) {
742 	close(*fd);
743 	*fd = -1;
744 	return(PTY_GETPTY_SLAVE_TOOLONG);
745     } else {
746 	ckstrncpy(slave, slaveret, slavelength);
747     }
748     return(0);
749 
750 #else /* HAVE__GETPTY */
751 
752     *fd = open("/dev/ptym/clone", O_RDWR|O_NDELAY); /* HPUX */
753     if (*fd >= 0) {
754         debug(F110,"pty_getpty()","open(/dev/ptym/clone) success",0);
755         goto have_fd;
756     }
757 
758 #ifdef HAVE_PTMX
759     debug(F100,"HAVE_PTMX","",0);
760     *fd = open("/dev/ptmx",O_RDWR|O_NDELAY);
761     if (*fd >= 0) {
762         debug(F110,"pty_getpty()","open(/dev/ptmx) success",0);
763         goto have_fd;
764     }
765 #endif /* HAVE_PTMX */
766 
767     *fd = open("/dev/ptc", O_RDWR|O_NDELAY); /* AIX */
768     if (*fd >= 0) {
769         debug(F110,"pty_getpty()","open(/dev/ptc) success",0);
770         goto have_fd;
771     }
772     *fd = open("/dev/pty", O_RDWR|O_NDELAY); /* sysvimp */
773     if (*fd >= 0)
774         debug(F110,"pty_getpty()","open(/dev/pty) success",0);
775 
776   have_fd:
777     /* This would be the pty master */
778     debug(F101,"pty_getpty fd(A)","",*fd);
779     if (*fd >= 0) {
780 	pty_master_fd = *fd;
781 
782 #ifdef HAVE_GRANTPT
783 #ifdef HAVE_PTMX
784         debug(F100,"HAVE_GRANTPT","",0);
785 	if (grantpt(*fd) || unlockpt(*fd))
786 	  return(PTY_GETPTY_STREAMS);
787 #endif /* HAVE_PTMX */
788 #endif /* HAVE_GRANTPT */
789 
790 #ifdef HAVE_PTSNAME
791         debug(F100,"HAVE_PTSNAME","",0);
792 	p = (char *)ptsname(*fd);
793         debug(F110,"pty_getpty() ptsname()",p,0);
794 #else
795 #ifdef HAVE_TTYNAME
796         debug(F100,"HAVE_TTYNAME","",0);
797 	p = ttyname(*fd);
798         debug(F110,"pty_getpty() ttyname()",p,0);
799 #else
800 	/* If we don't have either what do we do? */
801   	return(PTY_GETPTY_NOPTY);	/* punt */
802 #endif /* HAVE_TTYNAME */
803 #endif /* HAVE_PTSNAME */
804 	if (p) {
805 	    if (strlen(p) > slavelength - 1) {
806                 close (*fd);
807                 *fd = -1;
808                 return(PTY_GETPTY_SLAVE_TOOLONG);
809 	    }
810 	    ckstrncpy(slave, p, slavelength);
811 	    return(0);
812 	}
813 	if (fstat(*fd, &stb) < 0) {
814 	    close(*fd);
815 	    return(PTY_GETPTY_FSTAT);
816 	}
817 	ptynum = (int)(stb.st_rdev&0xFF);
818 	sprintf(slavebuf, "/dev/ttyp%x", ptynum); /* safe */
819 	if (strlen(slavebuf) > slavelength - 1) {
820 	    close(*fd);
821 	    *fd = -1;
822 	    return(PTY_GETPTY_SLAVE_TOOLONG);
823 	}
824         debug(F110,"pty_getpty() slavebuf",slavebuf,0);
825 	ckstrncpy(slave, slavebuf, slavelength);
826 	return(0);
827     } else {
828     	for (cp = "pqrstuvwxyzPQRST";*cp; cp++) {
829 	    sprintf(slavebuf,"/dev/ptyXX"); /* safe */
830 	    slavebuf[sizeof("/dev/pty") - 1] = *cp;
831 	    slavebuf[sizeof("/dev/ptyp") - 1] = '0';
832 	    if (stat(slavebuf, &stb) < 0)
833 	      break;
834 	    for (i = 0; i < 16; i++) {
835 		slavebuf[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i];
836 		errno = 0;
837 		*fd = open(slavebuf, O_RDWR|O_NDELAY);
838 		if (*fd < 0) {
839 		    debug(F111,"pty_getpty() pty master open error",
840 			  slavebuf,errno);
841 		    continue;
842 		}
843                 debug(F111,"pty_getpty() found pty master",slavebuf,*fd);
844 		slavebuf[sizeof("/dev/") - 1] = 't'; /* got pty */
845 		if (strlen(slavebuf) > slavelength -1) {
846 		    close(*fd);
847 		    *fd = -1;
848 		    return(PTY_GETPTY_SLAVE_TOOLONG);
849 		}
850 		ckstrncpy(slave, slavebuf, slavelength);
851                 debug(F110,"pty_getpty slave name",slave,0);
852 		pty_master_fd = *fd;
853 		return(0);
854 	    }
855 	}
856 	return(PTY_GETPTY_NOPTY);
857     }
858 #endif /*HAVE__GETPTY*/
859 #endif /* HAVE_OPENPTY */
860 }
861 
862 long
pty_init()863 pty_init() {
864 #ifdef HAVE_PTYM
865     static char dummy;
866     debug(F100,"HAVE_PTYM","",0);
867     tty_bank =  &master_name[strlen("/dev/ptym/pty")];
868     tty_num  =  &master_name[strlen("/dev/ptym/ptyX")];
869     slave_bank = &slave_name[strlen("/dev/pty/tty")];
870     slave_num  = &slave_name[strlen("/dev/pty/ttyX")];
871 #endif
872     return(0L);
873 }
874 
875 /*
876   The following is an array of modules that should be pushed on the stream.
877   See configure.in for caviats and notes about when this array is used and not
878   used.
879 */
880 #ifdef HAVE_STREAMS
881 #ifndef HAVE_LINE_PUSH
882 static char *push_list[] = {
883 #ifdef PUSH_PTEM
884     "ptem",
885 #endif
886 #ifdef PUSH_LDTERM
887     "ldterm",
888 #endif
889 #ifdef PUSH_TTCOMPAT
890     "ttcompat",
891 #endif
892     0
893 };
894 #endif /* HAVE_LINE_PUSH */
895 #endif /* HAVE_STREAMS */
896 
897 long
pty_initialize_slave(fd)898 pty_initialize_slave (fd) int fd; {
899 #ifdef POSIX_TERMIOS
900 #ifndef ultrix
901     struct termios new_termio;
902 #else
903     struct sgttyb b;
904 #endif /* ultrix */
905 #else
906     struct sgttyb b;
907 #endif /* POSIX_TERMIOS */
908     int pid;
909 #ifdef POSIX_TERMIOS
910 #ifndef ultrix
911     int rc;
912 #endif /* ultrix */
913 #endif /* POSIX_TERMIOS */
914 
915     debug(F111,"pty_initialize_slave()","fd",fd);
916 
917 #ifdef HAVE_STREAMS
918 #ifdef HAVE_LINE_PUSH
919     while (ioctl(fd,I_POP,0) == 0) ;	/* Clear out any old lined's */
920 
921     if (line_push(fd) < 0) {
922         debug(F110,"pty_initialize_slave()","line_push() failed",0);
923 	close(fd);
924         fd = -1;
925         return(PTY_OPEN_SLAVE_LINE_PUSHFAIL);
926     }
927 #else /*No line_push */
928     {
929         char **module = &push_list[0];
930         while (*module) {
931 	    if (ioctl(fd, I_PUSH, *(module++)) < 0) {
932                 debug(F110,"pty_initialize_slave()","ioctl(I_PUSH) failed",0);
933 		return(PTY_OPEN_SLAVE_PUSH_FAIL);
934 	    }
935 	}
936     }
937 #endif /*LINE_PUSH*/
938 #endif /*HAVE_STREAMS*/
939 /*
940   Under Ultrix 3.0, the pgrp of the slave pty terminal needs to be set
941   explicitly.  Why rlogind works at all without this on 4.3BSD is a mystery.
942 */
943 #ifdef GETPGRP_ONEARG
944     pid = getpgrp(getpid());
945 #else
946     pid = getpgrp();
947 #endif /* GETPGRP_ONEARG */
948 
949     debug(F111,"pty_initialize_slave()","pid",pid);
950 
951 #ifdef TIOCSPGRP
952     ioctl(fd, TIOCSPGRP, &pid);
953 #endif /* TIOCSPGRP */
954 
955 #ifdef POSIX_TERMIOS
956 #ifndef ultrix
957     tcsetpgrp(fd, pid);
958     errno = 0;
959     rc = tcgetattr(fd,&new_termio);
960     debug(F111,"pty_initialize_slave tcgetattr(fd)",ckitoa(rc),errno);
961     if (rc == 0) {
962 	new_termio.c_cc[VMIN] = 1;
963 	new_termio.c_cc[VTIME] = 0;
964 	rc = tcsetattr(fd,TCSANOW,&new_termio);
965 	debug(F111,"pty_initialize_slave tcsetattr(fd)",ckitoa(rc),errno);
966     }
967 #endif /* ultrix */
968 #endif /* POSIX_TERMIOS */
969     return(0L);
970 }
971 
972 #ifdef WANT_UTMP
973 long
pty_logwtmp(tty,user,host)974 pty_logwtmp (tty, user, host) char *user, *tty, *host; {
975 #ifdef HAVE_LOGWTMP
976     logwtmp(tty,user,host);
977     return(0);
978 #else
979     struct utmp ut;
980     char *tmpx;
981     char utmp_id[5];
982     int loggingin = user[0];		/* Will be empty for logout */
983 
984 #ifndef NO_UT_HOST
985     strncpy(ut.ut_host, host, sizeof(ut.ut_host));
986 #endif /* NO_UT_HOST */
987 
988     strncpy(ut.ut_line, tty, sizeof(ut.ut_line));
989     ut.ut_time = time(0);
990 
991 #ifndef NO_UT_PID
992     ut.ut_pid = getpid();
993     strncpy(ut.ut_user, user, sizeof(ut.ut_user));
994 
995     tmpx = tty + strlen(tty) - 2;
996     ckmakmsg(utmp_id,5,"kr",tmpx,NULL,NULL);
997     strncpy(ut.ut_id, utmp_id, sizeof(ut.ut_id));
998     ut.ut_pid = (loggingin ? getpid() : 0);
999     ut.ut_type = (loggingin ? USER_PROCESS : DEAD_PROCESS);
1000 #else
1001     strncpy(ut.ut_name, user, sizeof(ut.ut_name));
1002 #endif /* NO_UT_PID */
1003 
1004     return(ptyint_update_wtmp(&ut, host, user));
1005 
1006 #endif /* HAVE_LOGWTMP */
1007 }
1008 #endif /* WANT_UTMP */
1009 
1010 /*
1011   This routine is called twice.  It's not particularly important that the
1012   setsid() or TIOCSCTTY ioctls succeed (they may not the second time), but
1013   rather that we have a controlling terminal at the end.  It is assumed that
1014   vhangup doesn't exist and confuse the process's notion of controlling
1015   terminal on any system without TIOCNOTTY.  That is, either vhangup() leaves
1016   the controlling terminal in tact, breaks the association completely, or the
1017   system provides TIOCNOTTY to get things back into a reasonable state.  In
1018   practice, vhangup() either breaks the association completely or doesn't
1019   effect controlling terminals, so this condition is met.
1020 */
1021 long
pty_open_ctty(slave,fd,fc)1022 pty_open_ctty(slave, fd, fc) char * slave; int *fd; int fc; {
1023     int retval;
1024 
1025     debug(F110,"pty_open_ctty() slave",slave,0);
1026 
1027 /* First, dissociate from previous terminal */
1028 
1029     if ((retval = ptyint_void_association()) != 0) {
1030         debug(F111,
1031 	      "pty_open_ctty()",
1032 	      "ptyint_void_association() failed",
1033 	      retval
1034 	      );
1035 	return(retval);
1036     }
1037 #ifdef MUST_SETPGRP
1038 /*
1039   The Ultrix (and other BSD tty drivers) require the process group
1040   to be zero in order to acquire the new tty as a controlling tty.
1041 */
1042     setpgrp(0,0);
1043     debug(F101,"pty_open_ctty MUST_SETPGRP setpgrp(0,0)","",errno);
1044 #endif /* MUST_SETPGRP */
1045 
1046     errno = 0;
1047     *fd = open(slave, O_RDWR);
1048     debug(F111,"pty_open_ctty open(slave) fd",slave,*fd);
1049     if (*fd < 0) {
1050 	debug(F111,"pty_open_ctty() open failure", slave, errno);
1051 	return(PTY_OPEN_SLAVE_OPENFAIL);
1052     }
1053 #ifdef SOLARIS
1054     /* This forces the job to have a controlling terminal. */
1055     close(*fd);
1056     *fd = open(slave, O_RDWR);
1057     debug(F111,"pty_open_ctty close/open(slave) fd",slave,*fd);
1058 #ifdef DEBUG
1059     /* This shows that /dev/tty exists */
1060 if (deblog) {
1061 	int x;
1062 	x = open("/dev/tty", O_RDWR);
1063 	debug(F111,"pty_open_ctty open(/dev/tty) fd",slave,x);
1064 	if (x < 0) debug(F111,"pty_open_ctty open(/dev/tty) errno","",errno);
1065 	debug(F110,"pty_open_ctty ttyname(/dev/tty)",ttyname(x),0);
1066 	if (x > -1) close(x);
1067     }
1068 #endif	/* DEBUG */
1069 #endif /* SOLARIS */
1070 
1071 #ifdef MUST_SETPGRP
1072     setpgrp(0, getpid());
1073 #endif /* MUST_SETPGRP */
1074 
1075 #ifdef TIOCSCTTY
1076     if (
1077 #ifdef COMMENT
1078 	fc == 0
1079 #else
1080 	1
1081 #endif	/* COMMENT */
1082 	) {
1083 	/* TIOCSCTTY = Make this the job's controlling terminal */
1084 	errno = 0;
1085 	retval = ioctl(*fd, TIOCSCTTY, 0); /* Don't check return.*/
1086 	debug(F111,"pty_open_ctty() ioctl TIOCSCTTY",ckitoa(retval),errno);
1087     }
1088 #endif /* TIOCSCTTY */
1089     return(0L);
1090 }
1091 
1092 long
pty_open_slave(slave,fd,fc)1093 pty_open_slave(slave, fd, fc) char *slave; int *fd; int fc; {
1094     int vfd, testfd;
1095     long retval;
1096 #ifdef CK_POSIX_SIG
1097     struct sigaction sa;
1098 
1099     sigemptyset(&sa.sa_mask);		/* Initialize "sa" structure. */
1100     sa.sa_flags = 0;
1101 #endif /* CK_POSIX_SIG */
1102 
1103 /*
1104   First, chmod and chown the slave.  If we have vhangup then we really need
1105   pty_open_ctty to make sure our controlling terminal is the pty we're
1106   opening.  However, if we are using revoke or nothing then we just need a
1107   file descriiptor for the pty.  Considering some OSes in this category break
1108   on the second call to open_ctty (currently OSF but others may), we simply
1109   use a descriptor if we can.
1110 */
1111 #ifdef VHANG_FIRST
1112     if ((retval = pty_open_ctty(slave, &vfd, fc)) != 0) {
1113         debug(F111,
1114 	      "pty_open_slave() VHANG_FIRST",
1115 	      "pty_open_ctty() failed",
1116 	      retval
1117 	      );
1118         return(retval);
1119     }
1120     if (vfd < 0) {
1121         debug(F111,
1122 	      "pty_open_slave() VHANG_FIRST",
1123 	      "PTY_OPEN_SLAVE_OPENFAIL",
1124 	      vfd
1125 	      );
1126 	return(PTY_OPEN_SLAVE_OPENFAIL);
1127     }
1128 #endif /* VHANG_FIRST */
1129 
1130     if (slave == NULL || *slave == '\0') {
1131         debug(F110,"pty_open_slave()","PTY_OPEN_SLAVE_TOOSHORT",0);
1132         return(PTY_OPEN_SLAVE_TOOSHORT);
1133     }
1134 
1135 #ifdef SETUID
1136     if (chmod(slave, 0)) {
1137         debug(F110,"pty_open_slave()","PTY_OPEN_SLAVE_CHMODFAIL",0);
1138         return(PTY_OPEN_SLAVE_CHMODFAIL);
1139     }
1140     if (chown(slave, 0, 0 ) == -1 ) {
1141         debug(F110,"pty_open_slave()","PTY_OPEN_SLAVE_CHOWNFAIL",0);
1142         return(PTY_OPEN_SLAVE_CHOWNFAIL);
1143     }
1144 #endif /* SETUID */
1145 #ifdef VHANG_FIRST
1146     ptyint_vhangup();
1147     close(vfd);
1148 #endif /* VHANG_FIRST */
1149 
1150     if ((retval = ptyint_void_association()) != 0) {
1151         debug(F111,
1152 	      "pty_open_slave()",
1153 	      "ptyint_void_association() failed",
1154 	      retval
1155 	      );
1156         return(retval);
1157     }
1158 
1159 #ifdef HAVE_REVOKE
1160     if (revoke (slave) < 0 ) {
1161         debug(F110,"pty_open_slave()","PTY_OPEN_SLAVE_REVOKEFAIL",0);
1162 	return(PTY_OPEN_SLAVE_REVOKEFAIL);
1163     }
1164 #endif /* HAVE_REVOKE */
1165 
1166 /* Open the pty for real. */
1167 
1168     retval = pty_open_ctty(slave, fd, fc);
1169     debug(F111,"pty_open_slave retval",slave,retval);
1170     debug(F111,"pty_open_slave fd",slave,*fd);
1171     if (retval != 0) {
1172         debug(F111,"pty_open_slave()","pty_open_ctty() failed",retval);
1173 	return(PTY_OPEN_SLAVE_OPENFAIL);
1174     }
1175     pty_slave_fd = *fd;		   /* This is not visible to the upper fork */
1176     debug(F111,"pty_open_slave fd ctty'd",slave,pty_slave_fd);
1177     retval = pty_initialize_slave(*fd);
1178     debug(F111,"pty_open_slave fd init'd",slave,pty_slave_fd);
1179     if (retval) {
1180         debug(F111,"pty_open_slave()","pty_initialize_slave() failed",retval);
1181         return(retval);
1182     }
1183     /* (VOID)pty_make_raw(*fd); */
1184 
1185     debug(F100,"pty_open_slave OK","",*fd);
1186     return(0L);
1187 }
1188 
1189 #ifdef WANT_UTMP
1190 
1191 #ifndef UTMP_FILE
1192 #ifdef _PATH_UTMP
1193 #define UTMP_FILE _PATH_UTMP
1194 #endif /* _PATH_UTMP */
1195 #endif /*  UTMP_FILE */
1196 
1197 /* If it is *still* missing, assume /etc/utmp */
1198 
1199 #ifndef UTMP_FILE
1200 #define	UTMP_FILE "/etc/utmp"
1201 #endif /* UTMP_FILE */
1202 
1203 #ifndef NO_UT_PID
1204 #define WTMP_REQUIRES_USERNAME
1205 #endif /* NO_UT_PID */
1206 
1207 long
pty_update_utmp(process_type,pid,username,line,host,flags)1208 pty_update_utmp(process_type, pid, username, line, host, flags)
1209     int process_type;
1210     int pid;
1211     char *username, *line, *host;
1212     int flags;
1213 /* pty_update_utmp */ {
1214     struct utmp ent, ut;
1215 #ifndef HAVE_SETUTENT
1216     struct stat statb;
1217     int tty;
1218 #endif /* HAVE_SETUTENT */
1219 #ifdef HAVE_SETUTXENT
1220     struct utmpx utx;
1221 #endif /* HAVE_SETUTXENT */
1222 #ifndef NO_UT_PID
1223     char *tmpx;
1224     char utmp_id[5];
1225 #endif /* NO_UT_PID */
1226     char userbuf[32];
1227     int fd;
1228 
1229     debug(F100,"pty_update_utmp()","",0);
1230     strncpy(ent.ut_line, line+sizeof("/dev/")-1, sizeof(ent.ut_line));
1231     ent.ut_time = time(0);
1232 
1233 #ifdef NO_UT_PID
1234     if (process_type == PTY_LOGIN_PROCESS)
1235       return(0L);
1236 #else /* NO_UT_PID */
1237 
1238     ent.ut_pid = pid;
1239 
1240     switch (process_type) {
1241       case PTY_LOGIN_PROCESS:
1242 	ent.ut_type = LOGIN_PROCESS;
1243 	break;
1244       case PTY_USER_PROCESS:
1245 	ent.ut_type = USER_PROCESS;
1246 	break;
1247       case PTY_DEAD_PROCESS:
1248 	ent.ut_type = DEAD_PROCESS;
1249 	break;
1250       default:
1251 	return(PTY_UPDATE_UTMP_PROCTYPE_INVALID);
1252     }
1253 #endif /*NO_UT_PID*/
1254 
1255 #ifndef NO_UT_HOST
1256     if (host)
1257       strncpy(ent.ut_host, host, sizeof(ent.ut_host));
1258     else
1259       ent.ut_host[0] = '\0';
1260 #endif /* NO_UT_HOST */
1261 
1262 #ifndef NO_UT_PID
1263     if (!strcmp (line, "/dev/console")) {
1264 	char * s = NULL;
1265 
1266 #ifdef sun
1267 #ifdef __SVR4
1268 	s = "co";
1269 #else
1270 	s = "cons";
1271 #endif /* __SVR4 */
1272 #else
1273 	s = "cons";
1274 #endif /* sun */
1275 
1276 	strncpy(ent.ut_id, s, 4);
1277 
1278     } else {
1279 
1280 	tmpx = line + strlen(line)-1;
1281 	if (*(tmpx-1) != '/') tmpx--;	/* last 2 chars unless it's a '/' */
1282 #ifdef __hpux
1283 	ckstrncpy(utmp_id, tmpx, 5);
1284 #else
1285 	ckmakmsg(utmp_id,5,"kl",tmpx,NULL,NULL);
1286 #endif /* __hpux */
1287 	strncpy(ent.ut_id, utmp_id, sizeof(ent.ut_id));
1288     }
1289     strncpy(ent.ut_user, username, sizeof(ent.ut_user));
1290 
1291 #else
1292 
1293     strncpy(ent.ut_name, username, sizeof(ent.ut_name));
1294 
1295 #endif /* NO_UT_PID */
1296 
1297     if (username[0])
1298       strncpy(userbuf, username, sizeof(userbuf));
1299     else
1300       userbuf[0] = '\0';
1301 
1302 #ifdef HAVE_SETUTENT
1303 
1304     utmpname(UTMP_FILE);
1305     setutent();
1306 /*
1307   If we need to preserve the user name in the wtmp structure and Our flags
1308   tell us we can obtain it from the utmp and we succeed in obtaining it, we
1309   then save the utmp structure we obtain, write out the utmp structure and
1310   change the username pointer so it is used by update_wtmp.
1311 */
1312 
1313 #ifdef WTMP_REQUIRES_USERNAME
1314     if ((!username[0]) && (flags&PTY_UTMP_USERNAME_VALID) &&line) {
1315 	struct utmp *utptr;
1316 	strncpy(ut.ut_line, line, sizeof(ut.ut_line));
1317 	utptr = getutline(&ut);
1318 	if (utptr)
1319 	  strncpy(userbuf,utptr->ut_user,sizeof(ut.ut_user));
1320     }
1321 #endif /* WTMP_REQUIRES_USERNAME */
1322 
1323     pututline(&ent);
1324     endutent();
1325 
1326 #ifdef HAVE_SETUTXENT
1327     setutxent();
1328 #ifdef HAVE_GETUTMPX
1329     getutmpx(&ent, &utx);
1330 #else /* HAVE_GETUTMPX */
1331     /* For platforms like HPUX and Dec Unix which don't have getutmpx */
1332     strncpy(utx.ut_user, ent.ut_user, sizeof(ent.ut_user));
1333     strncpy(utx.ut_id, ent.ut_id, sizeof(ent.ut_id));
1334     strncpy(utx.ut_line, ent.ut_line, sizeof(ent.ut_line));
1335     utx.ut_pid = pid;		/* kludge for Irix, etc. to avoid trunc. */
1336     utx.ut_type = ent.ut_type;
1337 #ifdef UT_EXIT_STRUCTURE_DIFFER
1338     utx.ut_exit.ut_exit = ent.ut_exit.e_exit;
1339 #else /* UT_EXIT_STRUCTURE_DIFFER */
1340 /* KLUDGE for now; eventually this will be a feature test... See PR#[40] */
1341 #ifdef __hpux
1342     utx.ut_exit.__e_termination = ent.ut_exit.e_termination;
1343     utx.ut_exit.__e_exit = ent.ut_exit.e_exit;
1344 #else /* __hpux */
1345     /* XXX do nothing for now; we don't even know the struct member exists */
1346 #endif /* __hpux */
1347 #endif /* UT_EXIT_STRUCTURE_DIFFER */
1348     utx.ut_tv.tv_sec = ent.ut_time;
1349     utx.ut_tv.tv_usec = 0;
1350 #endif /* HAVE_GETUTMPX */
1351     if (host)
1352       strncpy(utx.ut_host, host, sizeof(utx.ut_host));
1353     else
1354       utx.ut_host[0] = 0;
1355     pututxline(&utx);
1356     endutxent();
1357 #endif /* HAVE_SETUTXENT */
1358 
1359 #else /* HAVE_SETUTENT */
1360     if (flags&PTY_TTYSLOT_USABLE) {
1361 	tty = ttyslot();
1362     } else {
1363 	int lc;
1364 	tty = -1;
1365 	if ((fd = open(UTMP_FILE, O_RDWR)) < 0)
1366 	  return(errno);
1367 	for (lc = 0;
1368 	     lseek(fd, (off_t)(lc * sizeof(struct utmp)), SEEK_SET) != -1;
1369 	     lc++
1370 	     ) {
1371 	    if (read(fd,
1372 		     (char *)&ut,
1373 		     sizeof(struct utmp)
1374 		     ) != sizeof(struct utmp)
1375 		)
1376 	      break;
1377 	    if (strncmp(ut.ut_line, ent.ut_line, sizeof(ut.ut_line)) == 0) {
1378 		tty = lc;
1379 #ifdef WTMP_REQUIRES_USERNAME
1380 		if (!username&&(flags&PTY_UTMP_USERNAME_VALID))
1381 		  strncpy(userbuf, ut.ut_user, sizeof(ut.ut_user));
1382 #endif /* WTMP_REQUIRES_USERNAME */
1383 		break;
1384 	    }
1385 	}
1386 	close(fd);
1387     }
1388     if (tty > 0 && (fd = open(UTMP_FILE, O_WRONLY, 0)) >= 0) {
1389 	lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
1390 	write(fd, (char *)&ent, sizeof(struct utmp));
1391 	close(fd);
1392     }
1393 #endif /* HAVE_SETUTENT */
1394 
1395     /* Don't record LOGIN_PROCESS entries. */
1396     if (process_type == PTY_LOGIN_PROCESS)
1397       return(0);
1398     else
1399       return(ptyint_update_wtmp(&ent, host, userbuf));
1400 }
1401 #ifndef WTMP_FILE
1402 #ifdef _PATH_WTMP
1403 #define WTMP_FILE _PATH_WTMP
1404 #endif /* _PATH_WTMP */
1405 #endif /* WTMP_FILE */
1406 
1407 #ifndef WTMPX_FILE
1408 #ifdef _PATH_WTMPX
1409 #ifdef HAVE_UPDWTMPX
1410 #define WTMPX_FILE _PATH_WTMPX
1411 #endif /* HAVE_UPDWTMPX */
1412 #endif /* _PATH_WTMPX */
1413 #endif /* WTMPX_FILE */
1414 
1415 /* If it is *still* missing, assume /usr/adm/wtmp */
1416 
1417 #ifndef WTMP_FILE
1418 #define	WTMP_FILE "/usr/adm/wtmp"
1419 #endif /* WTMP_FILE */
1420 
1421 #ifdef COMMENT
1422 /* The following test can not be made portably */
1423 
1424 /* #if defined(__GLIBC__) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) */
1425 /*
1426   This is ugly, but the lack of standardization in the utmp/utmpx space, and
1427   what glibc implements and doesn't make available, is even worse.
1428 */
1429 /* #undef HAVE_UPDWTMPX */	/* Don't use updwtmpx for glibc 2.1 */
1430 /* #endif */ /* __GLIBC__ etc */
1431 
1432 #else  /* COMMENT */
1433 
1434 #ifdef __GLIBC__
1435 #undef HAVE_UPDWTMPX		/* Don't use updwtmpx for glibc period */
1436 #endif /* __GLIBC__ */
1437 #endif /* COMMENT */
1438 
1439 long
ptyint_update_wtmp(ent,host,user)1440 ptyint_update_wtmp(ent,host,user) struct utmp *ent; char *host; char *user; {
1441     struct utmp ut;
1442     struct stat statb;
1443     int fd;
1444     time_t uttime;
1445 #ifdef HAVE_UPDWTMPX
1446     struct utmpx utx;
1447 
1448     getutmpx(ent, &utx);
1449     if (host)
1450       strncpy(utx.ut_host, host, sizeof(utx.ut_host) );
1451     else
1452       utx.ut_host[0] = 0;
1453     if (user)
1454       strncpy(utx.ut_user, user, sizeof(utx.ut_user));
1455     updwtmpx(WTMPX_FILE, &utx);
1456 #endif /* HAVE_UPDWTMPX */
1457 
1458 #ifdef HAVE_UPDWTMP
1459 #ifndef HAVE_UPDWTMPX
1460     /* This is already performed byupdwtmpx if present.*/
1461     updwtmp(WTMP_FILE, ent);
1462 #endif /* HAVE_UPDWTMPX*/
1463 #else /* HAVE_UPDWTMP */
1464 
1465     if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) >= 0) {
1466 	if (!fstat(fd, &statb)) {
1467 	    memset((char *)&ut, 0, sizeof(ut));
1468 #ifdef __hpux
1469 	    strncpy(ut.ut_id, ent->ut_id, sizeof (ut.ut_id));
1470 #endif /* __hpux */
1471 	    strncpy(ut.ut_line, ent->ut_line, sizeof(ut.ut_line));
1472 	    strncpy(ut.ut_name, ent->ut_name, sizeof(ut.ut_name));
1473 #ifndef NO_UT_HOST
1474 	    strncpy(ut.ut_host, ent->ut_host, sizeof(ut.ut_host));
1475 #endif /* NO_UT_HOST */
1476 
1477 	    time(&uttime);
1478 	    ut.ut_time = uttime;
1479 
1480 #ifdef HAVE_GETUTENT
1481 #ifdef USER_PROCESS
1482 	    if (ent->ut_name) {
1483 		if (!ut.ut_pid)
1484 		  ut.ut_pid = getpid();
1485 #ifndef __hpux
1486 		ut.ut_type = USER_PROCESS;
1487 #else  /* __hpux */
1488 		ut.ut_type = ent->ut_type;
1489 #endif /* __hpux */
1490 
1491 	    } else {
1492 
1493 #ifdef EMPTY
1494 		ut.ut_type = EMPTY;
1495 #else
1496 		ut.ut_type = DEAD_PROCESS; /* For Linux brokenness*/
1497 #endif /* EMPTY */
1498 
1499 	    }
1500 #endif /* USER_PROCESS */
1501 #endif /* HAVE_GETUTENT */
1502 
1503 	    if (write(fd, (char *)&ut, sizeof(struct utmp)) !=
1504 		sizeof(struct utmp))
1505 #ifndef COHERENT
1506 	      ftruncate(fd, statb.st_size);
1507 #else
1508 	      chsize(fd, statb.st_size);
1509 #endif /* COHERENT */
1510 	}
1511 	close(fd);
1512     }
1513 #endif /* HAVE_UPDWTMP */
1514     return(0); /* no current failure cases; file not found is not failure! */
1515 }
1516 #endif /* WANT_UTMP */
1517 
1518 /* This is for ancient Unixes that don't have these tty symbols defined. */
1519 
1520 #ifndef PENDIN
1521 #define PENDIN ICANON
1522 #endif /* PENDIN */
1523 #ifndef FLUSHO
1524 #define FLUSHO ICANON
1525 #endif /* FLUSHO */
1526 #ifndef IMAXBEL
1527 #define IMAXBEL ICANON
1528 #endif /* IMAXBEL */
1529 #ifndef EXTPROC
1530 #define EXTPROC ICANON
1531 #endif /* EXTPROC */
1532 
1533 static char Xline[17] = { 0, 0 };
1534 /*
1535   getptyslave()
1536   Open the slave side of the pty, and do any initialization that is necessary.
1537   The return value fd is a file descriptor for the slave side.
1538   fc = function code from do_pty() (q.v.)
1539 */
1540 int
getptyslave(fd,fc)1541 getptyslave(fd, fc) int * fd, fc; {
1542     int ttyfd;
1543     int t = -1;
1544     long retval;
1545 #ifdef TIOCGWINSZ
1546     struct winsize ws;
1547     extern int cmd_rows, cmd_cols;
1548 #endif /* TIOCGWINSZ */
1549 
1550     ttyfd = *fd;
1551     debug(F111,"getptyslave()","ttyfd",ttyfd);
1552     /*
1553      * Opening the slave side may cause initilization of the
1554      * kernel tty structure.  We need remember the state of:
1555      *      if linemode was turned on
1556      *      terminal window size
1557      *      terminal speed
1558      * so that we can reset them if we need to.
1559      */
1560     if ((retval = pty_open_slave(Xline, &t, fc)) != 0) {
1561 	perror(Xline);
1562 	msg++;
1563         debug(F111,"getptyslave()","Unable to open slave",retval);
1564         return(-1);
1565     }
1566     debug(F111,"getptyslave","t",t);
1567 #ifdef INIT_SPTY
1568     spty = t;
1569     debug(F111,"getptyslave","spty",spty);
1570 #endif /* INIT_SPTY */
1571 #ifdef STREAMSPTY
1572     if (ioctl(t,I_PUSH,"pckt") < 0) {
1573         debug(F111,"getptyslave()","ioctl(I_PUSH) failed",errno);
1574 #ifndef _AIX
1575         fatal("I_PUSH pckt");
1576 #endif /* _AIX */
1577     }
1578 #endif /* STREAMSPTY */
1579 
1580     /* Set up the tty modes as we like them to be. */
1581 #ifdef COMMENT
1582     /* Originally like this... But this is the master - we want the slave */
1583     /* Anyway, this fails on Solaris and probably other System V OS's */
1584     init_termbuf(ttyfd);
1585 #else
1586     init_termbuf(t);
1587 #endif	/* COMMENT */
1588 #ifdef TIOCGWINSZ
1589     if (cmd_rows || cmd_cols) {
1590         memset((char *)&ws, 0, sizeof(ws));
1591         ws.ws_col = cmd_cols;
1592         ws.ws_row = cmd_rows;
1593 	debug(F101,"getptyslave() doing TIOCSWINSZ...","",t);
1594         ioctl(t, TIOCSWINSZ, (char *)&ws);
1595     }
1596 #endif /* TIOCGWINSZ */
1597 
1598     /* For external protocols, put the pty in no-echo mode */
1599     if (fc == 1) {
1600 	debug(F100,"getptyslave() setting rawmode","",0);
1601 	/* iflags */
1602 	termbuf.c_iflag &= ~(PARMRK|ISTRIP|BRKINT|INLCR|IGNCR|ICRNL);
1603 	termbuf.c_iflag &= ~(INPCK|IGNPAR|IMAXBEL|IXANY|IXON|IXOFF);
1604 	termbuf.c_iflag |= IGNBRK;
1605 #ifdef IUCLC
1606 	termbuf.c_iflag &= ~IUCLC;
1607 #endif /* IUCLC */
1608 
1609 	/* oflags */
1610 	termbuf.c_oflag &= ~OPOST;
1611 #ifdef OXTABS
1612 	termbuf.c_oflag &= ~OXTABS;
1613 #endif /* OXTABS */
1614 #ifdef ONOCR
1615 	termbuf.c_oflag &= ~ONOCR;
1616 #endif /* ONOCR */
1617 #ifdef ONLRET
1618 	termbuf.c_oflag &= ~ONLRET;
1619 #endif /* ONLRET */
1620 #ifdef ONLCR
1621 	termbuf.c_oflag &= ~ONLCR;
1622 #endif /* ONLCR */
1623 
1624 	/* lflags */
1625 	termbuf.c_lflag &= ~ECHO;
1626 #ifdef ECHOE
1627 	termbuf.c_lflag &= ~ECHOE;
1628 #endif /* ECHOE */
1629 #ifdef ECHONL
1630 	termbuf.c_lflag &= ~ECHONL;
1631 #endif /* ECHONL */
1632 #ifdef ECHOPRT
1633 	termbuf.c_lflag &= ~ECHOPRT;
1634 #endif /* ECHOPRT */
1635 #ifdef ECHOKE
1636 	termbuf.c_lflag &= ~ECHOKE;
1637 #endif /* ECHOKE */
1638 #ifdef ECHOCTL
1639 	termbuf.c_lflag &= ~ECHOCTL;
1640 #endif /* ECHOCTL */
1641 #ifdef ALTWERASE
1642 	termbuf.c_lflag &= ~ALTWERASE;
1643 #endif /* ALTWERASE */
1644 #ifdef EXTPROC
1645 	termbuf.c_lflag &= ~EXTPROC;
1646 #endif /* EXTPROC */
1647 	termbuf.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN);
1648 
1649 #ifdef NOKERNINFO
1650 	termbuf.c_lflag |= NOKERNINFO;
1651 #endif	/* NOKERNINFO */
1652 	/* termbuf.c_lflag |= NOFLSH; */
1653 	termbuf.c_lflag &= ~NOFLSH;
1654 
1655 	/* cflags */
1656 	termbuf.c_cflag &= ~(CSIZE|PARENB|PARODD);
1657 	termbuf.c_cflag |= CS8|CREAD;
1658 #ifdef VMIN
1659 	termbuf.c_cc[VMIN] = 1;
1660 #endif	/* VMIN */
1661     } else {				/* Regular interactive use */
1662 	debug(F100,"getptyslave() setting cooked mode","",0);
1663 
1664 	/* Settings for sgtty based systems */
1665 
1666 #ifndef USE_TERMIO
1667 	termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS;
1668 #endif /* USE_TERMIO */
1669 
1670 #ifndef OXTABS
1671 #define OXTABS 0
1672 #endif /* OXTABS */
1673 
1674 	/* Settings for UNICOS and HPUX */
1675 
1676 #ifdef CRAY
1677 	termbuf.c_oflag = OPOST|ONLCR|TAB3;
1678 	termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
1679 	termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
1680 	termbuf.c_cflag = EXTB|HUPCL|CS8;
1681 #else /* CRAY */
1682 #ifdef HPUX
1683 	termbuf.c_oflag = OPOST|ONLCR|TAB3;
1684 	termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
1685 	termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
1686 	termbuf.c_cflag = EXTB|HUPCL|CS8;
1687 #else /* HPUX */
1688 #ifdef USE_TERMIO
1689 	/*
1690 	  Settings for all other termios/termio based systems, other than
1691 	  4.4BSD.  In 4.4BSD the kernel does the initial terminal setup.
1692 	*/
1693 #ifdef BSD42
1694 #ifndef BSD44
1695 	termbuf.c_lflag |= ECHO|ICANON|IEXTEN|ISIG;
1696 	termbuf.c_oflag |= ONLCR|OXTABS|OPOST;
1697 	termbuf.c_iflag |= ICRNL|IGNPAR;
1698 	termbuf.c_cflag |= HUPCL;
1699 	termbuf.c_iflag &= ~IXOFF;
1700 #endif /* BSD44 */
1701 #else /* BSD42 */
1702 	termbuf.c_lflag |= ECHO|ICANON|IEXTEN|ISIG;
1703 	termbuf.c_oflag |= ONLCR|OXTABS|OPOST;
1704 	termbuf.c_iflag |= ICRNL|IGNPAR;
1705 	termbuf.c_cflag |= HUPCL;
1706 	termbuf.c_iflag &= ~IXOFF;
1707 #endif /* BSD42 */
1708 #endif /* USE_TERMIO */
1709 #endif /* HPUX */
1710 #endif /* CRAY */
1711     }
1712 
1713     /* Set the tty modes, and make this our controlling tty. */
1714 #ifdef COMMENT
1715     /* But this is the master - we want the slave */
1716     set_termbuf(ttyfd);
1717 #else
1718     set_termbuf(t);
1719 #endif	/* COMMENT */
1720 
1721     if (t != 0)
1722       dup2(t, 0);
1723     if (t != 1)
1724       dup2(t, 1);
1725     if (t != 2) {
1726 	if (fc == 0) {
1727 	    dup2(t, 2);
1728 	} else if (fc == 1) {
1729 	    /* For external protocols, send stderr to /dev/null */
1730 #ifdef COMMENT
1731 	    int xx;
1732 #ifndef COMMENT
1733 	    char * s = "/dev/null";
1734 	    errno = 0;
1735 	    xx = open(s, O_WRONLY);
1736 #else
1737 	    char * s = "pty.log";
1738 	    errno = 0;
1739 	    xx = open(s, O_CREAT, 0644);
1740 #endif /* COMMENT */
1741 	    debug(F111,"getptyslave redirect stderr",s,errno);
1742 	    dup2(xx,2);
1743 #endif	/* COMMENT */
1744 	}
1745     }
1746     if (t > 2)
1747       close(t);
1748 
1749     if (ttyfd > 2) {
1750 	close(ttyfd);
1751         ttyfd = -1;
1752 	*fd = ttyfd;
1753     }
1754     return(0);
1755 }
1756 
1757 #ifdef HAVE_PTYTRAP
1758 /*
1759   To be called to determine if a trap is pending on a pty
1760   if and only if select() cannot be used.
1761 */
1762 int
pty_trap_pending(fd)1763 pty_trap_pending(fd) int fd; {
1764     int pending;
1765     int rc;
1766 
1767     rc = ioctl(fd, TIOCTRAPSTATUS, (char *)&pending, sizeof(pending));
1768     if (rc == 0) {
1769         debug(F101,"pty_trap_pending()","",pending);
1770         return(pending);
1771     } else {
1772         debug(F111,"pty_trap_pending()","ioctl() failed",rc);
1773         return(-1);
1774     }
1775 }
1776 
1777 /*
1778   To be called after select() has returned indicating that an exception is
1779   waiting on a pty.  It should be called with the file descriptor of the pty.
1780   Returns -1 on error; 0 if pty is still open; 1 if pty has closed.
1781 */
1782 int
pty_trap_handler(fd)1783 pty_trap_handler(fd) int fd; {
1784     struct request_info ri;
1785 
1786     memset(&ri,0,sizeof(ri));
1787     if (ioctl(fd,TIOCREQCHECK,(char *)&ri, sizeof(ri)) != 0) {
1788         debug(F111,"pty_trap_handler()","ioctl(TIOCREQCHECK) failed",errno);
1789         return(-1);
1790     }
1791     switch (ri.request) {
1792       case TIOCOPEN:
1793         debug(F110,"pty_trap_handler()","an open() call",0);
1794         break;
1795       case TIOCCLOSE:
1796         debug(F110,"pty_trap_handler()","a close() call",0);
1797         break;
1798       default:
1799         debug(F110,"pty_trap_handler()","an ioctl() call",0);
1800         ri.errno_error = EINVAL;
1801     }
1802     if (ioctl(fd, TIOCREQSET, (char *)&ri,sizeof(ri)) != 0) {
1803         debug(F111,"pty_trap_handler()","ioctl(TIOCREQSET) failed",errno);
1804         return(-1);
1805     }
1806     if (ri.request == TIOCCLOSE)
1807       return(1);
1808     else
1809       return(0);
1810 }
1811 #endif /* HAVE_PTYTRAP */
1812 
1813 VOID
exec_cmd(s)1814 exec_cmd(s) char * s; {
1815     struct stringarray * q;
1816     char ** args = NULL;
1817 
1818     if (!s) return;
1819     if (!*s) return;
1820 
1821     q = cksplit(1,0,s,NULL,"\\%[]&$+-/=*^_@!{}/<>|.#~'`:;?",7,0,0,0);
1822     if (!q) return;
1823 
1824     args = q->a_head + 1;
1825 
1826 #ifdef DEBUG
1827     {
1828 	int i, n;
1829 	n = q->a_size;
1830 	for (i = 0; i <= n; i++) {
1831 	    if (!args[i]) {
1832 		debug(F111,"exec_cmd arg","NULL",i);
1833 		break;
1834 	    } else {
1835 		debug(F111,"exec_cmd arg",args[i],i);
1836 		if (i == n && args[i]) {
1837 		    debug(F101,"exec_cmd SUBSTITUTING NULL","",i);
1838 		    if (strlen(args[i]) == 0)
1839 		      makestr(&(args[i]),NULL);
1840 		}
1841 
1842 	    }
1843 	}
1844     }
1845 #endif	/* DEBUG */
1846 
1847     execvp(args[0],args);
1848 }
1849 
1850 /* Get a pty, scan input lines. */
1851 /* fc = 0 for interactive access; fc = 1 for running external protocols */
1852 
1853 static int pty_fc = -1;			/* Global copy of fc */
1854 
1855 int
do_pty(fd,cmd,fc)1856 do_pty(fd, cmd, fc) int * fd; char * cmd; int fc; {
1857     long retval;
1858     int syncpipe[2];
1859     int i, ttyfd;
1860 #ifdef HAVE_PTYTRAP
1861     int x;
1862 #endif /* HAVE_PTYTRAP */
1863     int dummy;
1864 
1865     debug(F101,"CKUPTY.C do_pty fc","",fc);
1866 
1867     ttyfd = *fd;
1868 
1869     pty_master_fd = -2;
1870     pty_slave_fd = -2;
1871     pty_fork_pid = -2;
1872 
1873     msg = 0;				/* Message counter */
1874     pty_init();				/* Find an available pty to use. */
1875     errno = 0;
1876 
1877     if ((retval = pty_getpty(&ttyfd, Xline, 20)) != 0) {
1878 	if (msg++ == 0)
1879 	  perror(Xline);
1880         debug(F111,"do_pty()","pty_getpty() fails",retval);
1881 	*fd = ttyfd;
1882         return(-1);
1883     }
1884     *fd = ttyfd;
1885     debug(F111,"do_pty() Xline",Xline,ttyfd);
1886 
1887 #ifdef SIGTTOU
1888 /*
1889   Ignoring SIGTTOU keeps the kernel from blocking us.  we tweak the tty with
1890   an ioctl() (in ttioct() in /sys/tty.c in a BSD kernel)
1891 */
1892      signal(SIGTTOU, SIG_IGN);
1893 #endif /* SIGTTOU */
1894 
1895 /* Start up the command on the slave side of the terminal */
1896 
1897     if (pipe(syncpipe) < 0) {
1898         debug(F110,"do_pty()","pipe() fails",0);
1899 	perror("pipe() failed");
1900 	msg++;
1901         debug(F111,"do_pty()","pipe fails",errno);
1902         return(-1);
1903     }
1904     if ((i = fork()) < 0) {
1905         /* XXX - need to clean up the allocated pty */
1906         perror("fork() failed");
1907 	msg++;
1908         debug(F111,"do_pty()","fork fails",errno);
1909         return(-1);
1910     }
1911     if (i) {  /* Wait for child before writing to parent side of pty. */
1912         char c;
1913 #ifdef HAVE_PTYTRAP
1914         int on = 1;
1915 #endif /* HAVE_PTYTRAP */
1916 	close(syncpipe[1]);
1917 	errno = 0;
1918         if (read(syncpipe[0], &c, 1) == 0) { /* Slave side died */
1919 	    perror("Pipe read() failed");
1920 	    msg++;
1921             debug(F110,"do_pty()","Slave fails to initialize",0);
1922             close(syncpipe[0]);
1923             return(-1);
1924         }
1925         pty_fork_pid = i;		/* So we can clean it up later */
1926 	pty_fork_active = 1;
1927 	debug(F101,"do_pty pty_fork_pid","",pty_fork_pid);
1928 #ifdef HAVE_PTYTRAP
1929         /* HPUX does not allow the master to read end of file.  */
1930         /* Therefore, we must determine that the slave has been */
1931         /* closed by trapping the call to close().              */
1932 	errno = 0;
1933 	x = ioctl(ttyfd, TIOCTRAP, (char *)&on);
1934 	debug(F111,"do_pty ioctl(TIOCTRAP)",ckitoa(x),errno);
1935 #endif /* HAVE_PTYTRAP */
1936         debug(F111,"do_pty()","synchronized - pty_fork_pid",pty_fork_pid);
1937         close(syncpipe[0]);
1938     } else {
1939 	int x;
1940 	debug(F101,"do_pty getptyslave ttyfd A","",ttyfd);
1941         debug(F110,"do_pty()","Slave starts",0);
1942 	x = getptyslave(&ttyfd,fc);
1943 	debug(F101,"do_pty getptyslave","",x);
1944         if (x == 0) {
1945 	    debug(F101,"do_pty getptyslave ttyfd B","",ttyfd);
1946 #ifdef WANT_UTMP
1947             pty_update_utmp(PTY_USER_PROCESS,
1948 			    getpid(),
1949 			    "KERMIT",
1950 			    Xline,
1951 			    cmd,
1952 			    PTY_TTYSLOT_USABLE
1953 			    );
1954 #endif /* WANT_UTMP */
1955             /* Notify our parent we're ready to continue.*/
1956             debug(F110,"do_pty()","slave synchronizing",0);
1957             dummy = write(syncpipe[1],"y",1);
1958             close(syncpipe[0]);
1959             close(syncpipe[1]);
1960 
1961 	    debug(F110,"do_pty cmd",cmd,0);
1962             exec_cmd(cmd);
1963             debug(F111,"do_pty()","exec_cmd() returns - why?",errno);
1964         }
1965 	*fd = ttyfd;
1966         debug(F110,"do_pty()","getptyslave() fails - exiting",0);
1967         exit(1);
1968     }
1969     *fd = ttyfd;
1970     pty_fc = fc;
1971     return(getpid());
1972 } /* end of do_pty() */
1973 
1974 
1975 VOID
end_pty()1976 end_pty() {
1977     msg = 0;				/* Message counter */
1978     debug(F101,"end_pty pty_fork_pid","",pty_fork_pid);
1979     if (Xline[0] && pty_fork_pid >= 0) {
1980         pty_cleanup(Xline,pty_fork_pid,1);
1981         Xline[0] = '\0';
1982         pty_fork_pid = -1;
1983 	pty_fork_active = 0;
1984 	debug(F101,"end_pty pty_fork_active","",pty_fork_active);
1985     }
1986     pty_fc = -1;
1987 }
1988 #endif /* NETPTY */
1989