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