]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - crypto/heimdal/appl/telnet/telnetd/sys_term.c
unfinished sblive driver, playback/mixer only for now - not enabled in
[FreeBSD/FreeBSD.git] / crypto / heimdal / appl / telnet / telnetd / sys_term.c
1 /*
2  * Copyright (c) 1989, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #include "telnetd.h"
35
36 RCSID("$Id: sys_term.c,v 1.90 2000/01/01 11:53:59 assar Exp $");
37
38 #if defined(_CRAY) || (defined(__hpux) && !defined(HAVE_UTMPX_H))
39 # define PARENT_DOES_UTMP
40 #endif
41
42 #ifdef HAVE_UTMP_H
43 #include <utmp.h>
44 #endif
45
46 #ifdef HAVE_UTMPX_H
47 #include <utmpx.h>
48 #endif
49
50 #ifdef HAVE_UTMPX_H
51 struct  utmpx wtmp;
52 #elif defined(HAVE_UTMP_H)
53 struct  utmp wtmp;
54 #endif /* HAVE_UTMPX_H */
55
56 #ifdef HAVE_STRUCT_UTMP_UT_HOST
57 int     utmp_len = sizeof(wtmp.ut_host);
58 #else
59 int     utmp_len = MaxHostNameLen;
60 #endif
61
62 #ifndef UTMP_FILE
63 #ifdef _PATH_UTMP
64 #define UTMP_FILE _PATH_UTMP
65 #else
66 #define UTMP_FILE "/etc/utmp"
67 #endif
68 #endif
69
70 #if !defined(WTMP_FILE) && defined(_PATH_WTMP)
71 #define WTMP_FILE _PATH_WTMP
72 #endif
73
74 #ifndef PARENT_DOES_UTMP
75 #ifdef WTMP_FILE
76 char    wtmpf[] = WTMP_FILE;
77 #else
78 char    wtmpf[] = "/usr/adm/wtmp";
79 #endif
80 char    utmpf[] = UTMP_FILE;
81 #else /* PARENT_DOES_UTMP */
82 #ifdef WTMP_FILE
83 char    wtmpf[] = WTMP_FILE;
84 #else
85 char    wtmpf[] = "/etc/wtmp";
86 #endif
87 #endif /* PARENT_DOES_UTMP */
88
89 #ifdef HAVE_TMPDIR_H
90 #include <tmpdir.h>
91 #endif  /* CRAY */
92
93 #ifdef  STREAMSPTY
94
95 #ifdef HAVE_SAC_H
96 #include <sac.h>
97 #endif
98
99 #ifdef HAVE_SYS_STROPTS_H
100 #include <sys/stropts.h>
101 #endif
102
103 #endif /* STREAMSPTY */
104
105 #ifdef  HAVE_SYS_STREAM_H
106 #ifdef  HAVE_SYS_UIO_H
107 #include <sys/uio.h>
108 #endif
109 #ifdef __hpux
110 #undef SE
111 #endif
112 #include <sys/stream.h>
113 #endif
114 #if !(defined(__sgi) || defined(__linux) || defined(_AIX)) && defined(HAVE_SYS_TTY)
115 #include <sys/tty.h>
116 #endif
117 #ifdef  t_erase
118 #undef  t_erase
119 #undef  t_kill
120 #undef  t_intrc
121 #undef  t_quitc
122 #undef  t_startc
123 #undef  t_stopc
124 #undef  t_eofc
125 #undef  t_brkc
126 #undef  t_suspc
127 #undef  t_dsuspc
128 #undef  t_rprntc
129 #undef  t_flushc
130 #undef  t_werasc
131 #undef  t_lnextc
132 #endif
133
134 #ifdef HAVE_TERMIOS_H
135 #include <termios.h>
136 #else
137 #ifdef HAVE_TERMIO_H
138 #include <termio.h>
139 #endif
140 #endif
141
142 #ifdef HAVE_UTIL_H
143 #include <util.h>
144 #endif
145
146 # ifndef        TCSANOW
147 #  ifdef TCSETS
148 #   define      TCSANOW         TCSETS
149 #   define      TCSADRAIN       TCSETSW
150 #   define      tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
151 #  else
152 #   ifdef TCSETA
153 #    define     TCSANOW         TCSETA
154 #    define     TCSADRAIN       TCSETAW
155 #    define     tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
156 #   else
157 #    define     TCSANOW         TIOCSETA
158 #    define     TCSADRAIN       TIOCSETAW
159 #    define     tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
160 #   endif
161 #  endif
162 #  define       tcsetattr(f, a, t)      ioctl(f, a, t)
163 #  define       cfsetospeed(tp, val)    (tp)->c_cflag &= ~CBAUD; \
164 (tp)->c_cflag |= (val)
165 #  define       cfgetospeed(tp)         ((tp)->c_cflag & CBAUD)
166 #  ifdef CIBAUD
167 #   define      cfsetispeed(tp, val)    (tp)->c_cflag &= ~CIBAUD; \
168      (tp)->c_cflag |= ((val)<<IBSHIFT)
169 #   define      cfgetispeed(tp)         (((tp)->c_cflag & CIBAUD)>>IBSHIFT)
170 #  else
171 #   define      cfsetispeed(tp, val)    (tp)->c_cflag &= ~CBAUD; \
172      (tp)->c_cflag |= (val)
173 #   define      cfgetispeed(tp)         ((tp)->c_cflag & CBAUD)
174 #  endif
175 # endif /* TCSANOW */
176      struct termios termbuf, termbuf2;  /* pty control structure */
177 # ifdef  STREAMSPTY
178      static int ttyfd = -1;
179      int really_stream = 0;
180 # endif
181
182      const char *new_login = _PATH_LOGIN;
183
184 /*
185  * init_termbuf()
186  * copy_termbuf(cp)
187  * set_termbuf()
188  *
189  * These three routines are used to get and set the "termbuf" structure
190  * to and from the kernel.  init_termbuf() gets the current settings.
191  * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
192  * set_termbuf() writes the structure into the kernel.
193  */
194
195      void
196      init_termbuf(void)
197 {
198 # ifdef  STREAMSPTY
199     if (really_stream)
200         tcgetattr(ttyfd, &termbuf);
201     else
202 # endif
203         tcgetattr(ourpty, &termbuf);
204     termbuf2 = termbuf;
205 }
206
207 void
208 set_termbuf(void)
209 {
210     /*
211      * Only make the necessary changes.
212          */
213     if (memcmp(&termbuf, &termbuf2, sizeof(termbuf)))
214 # ifdef  STREAMSPTY
215         if (really_stream)
216             tcsetattr(ttyfd, TCSANOW, &termbuf);
217         else
218 # endif
219             tcsetattr(ourpty, TCSANOW, &termbuf);
220 }
221
222
223 /*
224  * spcset(func, valp, valpp)
225  *
226  * This function takes various special characters (func), and
227  * sets *valp to the current value of that character, and
228  * *valpp to point to where in the "termbuf" structure that
229  * value is kept.
230  *
231  * It returns the SLC_ level of support for this function.
232  */
233
234
235 int
236 spcset(int func, cc_t *valp, cc_t **valpp)
237 {
238
239 #define setval(a, b)    *valp = termbuf.c_cc[a]; \
240     *valpp = &termbuf.c_cc[a]; \
241                                    return(b);
242 #define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
243
244     switch(func) {
245     case SLC_EOF:
246         setval(VEOF, SLC_VARIABLE);
247     case SLC_EC:
248         setval(VERASE, SLC_VARIABLE);
249     case SLC_EL:
250         setval(VKILL, SLC_VARIABLE);
251     case SLC_IP:
252         setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
253     case SLC_ABORT:
254         setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
255     case SLC_XON:
256 #ifdef  VSTART
257         setval(VSTART, SLC_VARIABLE);
258 #else
259         defval(0x13);
260 #endif
261     case SLC_XOFF:
262 #ifdef  VSTOP
263         setval(VSTOP, SLC_VARIABLE);
264 #else
265         defval(0x11);
266 #endif
267     case SLC_EW:
268 #ifdef  VWERASE
269         setval(VWERASE, SLC_VARIABLE);
270 #else
271         defval(0);
272 #endif
273     case SLC_RP:
274 #ifdef  VREPRINT
275         setval(VREPRINT, SLC_VARIABLE);
276 #else
277         defval(0);
278 #endif
279     case SLC_LNEXT:
280 #ifdef  VLNEXT
281         setval(VLNEXT, SLC_VARIABLE);
282 #else
283         defval(0);
284 #endif
285     case SLC_AO:
286 #if     !defined(VDISCARD) && defined(VFLUSHO)
287 # define VDISCARD VFLUSHO
288 #endif
289 #ifdef  VDISCARD
290         setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT);
291 #else
292         defval(0);
293 #endif
294     case SLC_SUSP:
295 #ifdef  VSUSP
296         setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN);
297 #else
298         defval(0);
299 #endif
300 #ifdef  VEOL
301     case SLC_FORW1:
302         setval(VEOL, SLC_VARIABLE);
303 #endif
304 #ifdef  VEOL2
305     case SLC_FORW2:
306         setval(VEOL2, SLC_VARIABLE);
307 #endif
308     case SLC_AYT:
309 #ifdef  VSTATUS
310         setval(VSTATUS, SLC_VARIABLE);
311 #else
312         defval(0);
313 #endif
314
315     case SLC_BRK:
316     case SLC_SYNCH:
317     case SLC_EOR:
318         defval(0);
319
320     default:
321         *valp = 0;
322         *valpp = 0;
323         return(SLC_NOSUPPORT);
324     }
325 }
326
327 #ifdef _CRAY
328 /*
329  * getnpty()
330  *
331  * Return the number of pty's configured into the system.
332  */
333 int
334 getnpty()
335 {
336 #ifdef _SC_CRAY_NPTY
337     int numptys;
338
339     if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1)
340         return numptys;
341     else
342 #endif /* _SC_CRAY_NPTY */
343         return 128;
344 }
345 #endif /* CRAY */
346
347 /*
348  * getpty()
349  *
350  * Allocate a pty.  As a side effect, the external character
351  * array "line" contains the name of the slave side.
352  *
353  * Returns the file descriptor of the opened pty.
354  */
355
356 static char Xline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
357 char *line = Xline;
358
359 #ifdef  _CRAY
360 char myline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
361 #endif  /* CRAY */
362
363 #if !defined(HAVE_PTSNAME) && defined(STREAMSPTY)
364 static char *ptsname(int fd)
365 {
366 #ifdef HAVE_TTYNAME
367     return ttyname(fd);
368 #else
369     return NULL;
370 #endif
371 }
372 #endif
373
374 int getpty(int *ptynum)
375 {
376 #ifdef __osf__ /* XXX */
377     int master;
378     int slave;
379     if(openpty(&master, &slave, line, 0, 0) == 0){
380         close(slave);
381         return master;
382     }
383     return -1;
384 #else
385 #ifdef HAVE__GETPTY
386     int master, slave;
387     char *p;
388     p = _getpty(&master, O_RDWR, 0600, 1);
389     if(p == NULL)
390         return -1;
391     strlcpy(line, p, sizeof(Xline));
392     return master;
393 #else
394
395     int p;
396     char *cp, *p1, *p2;
397     int i;
398 #if SunOS == 40
399     int dummy;
400 #endif
401 #if 0 /* && defined(HAVE_OPENPTY) */
402     int master;
403     int slave;
404     if(openpty(&master, &slave, line, 0, 0) == 0){
405         close(slave);
406         return master;
407     }
408 #else
409 #ifdef  STREAMSPTY
410     char *clone[] = { "/dev/ptc", "/dev/ptmx", "/dev/ptm", 
411                       "/dev/ptym/clone", 0 };
412
413     char **q;
414     for(q=clone; *q; q++){
415         p=open(*q, O_RDWR);
416         if(p >= 0){
417 #ifdef HAVE_GRANTPT
418             grantpt(p);
419 #endif
420 #ifdef HAVE_UNLOCKPT
421             unlockpt(p);
422 #endif
423             strlcpy(line, ptsname(p), sizeof(Xline));
424             really_stream = 1;
425             return p;
426         }
427     }
428 #endif /* STREAMSPTY */
429 #ifndef _CRAY
430
431 #ifndef __hpux
432     snprintf(line, sizeof(Xline), "/dev/ptyXX");
433     p1 = &line[8];
434     p2 = &line[9];
435 #else
436     snprintf(line, sizeof(Xline), "/dev/ptym/ptyXX");
437     p1 = &line[13];
438     p2 = &line[14];
439 #endif
440
441         
442     for (cp = "pqrstuvwxyzPQRST"; *cp; cp++) {
443         struct stat stb;
444
445         *p1 = *cp;
446         *p2 = '0';
447         /*
448          * This stat() check is just to keep us from
449          * looping through all 256 combinations if there
450          * aren't that many ptys available.
451          */
452         if (stat(line, &stb) < 0)
453             break;
454         for (i = 0; i < 16; i++) {
455             *p2 = "0123456789abcdef"[i];
456             p = open(line, O_RDWR);
457             if (p > 0) {
458 #ifndef __hpux
459                 line[5] = 't';
460 #else
461                 for (p1 = &line[8]; *p1; p1++)
462                     *p1 = *(p1+1);
463                 line[9] = 't';
464 #endif
465                 chown(line, 0, 0);
466                 chmod(line, 0600);
467 #if SunOS == 40
468                 if (ioctl(p, TIOCGPGRP, &dummy) == 0
469                     || errno != EIO) {
470                     chmod(line, 0666);
471                     close(p);
472                     line[5] = 'p';
473                 } else
474 #endif /* SunOS == 40 */
475                     return(p);
476             }
477         }
478     }
479 #else   /* CRAY */
480     extern lowpty, highpty;
481     struct stat sb;
482
483     for (*ptynum = lowpty; *ptynum <= highpty; (*ptynum)++) {
484         snprintf(myline, sizeof(myline), "/dev/pty/%03d", *ptynum);
485         p = open(myline, 2);
486         if (p < 0)
487             continue;
488         snprintf(line, sizeof(Xline), "/dev/ttyp%03d", *ptynum);
489         /*
490          * Here are some shenanigans to make sure that there
491          * are no listeners lurking on the line.
492          */
493         if(stat(line, &sb) < 0) {
494             close(p);
495             continue;
496         }
497         if(sb.st_uid || sb.st_gid || sb.st_mode != 0600) {
498             chown(line, 0, 0);
499             chmod(line, 0600);
500             close(p);
501             p = open(myline, 2);
502             if (p < 0)
503                 continue;
504         }
505         /*
506          * Now it should be safe...check for accessability.
507          */
508         if (access(line, 6) == 0)
509             return(p);
510         else {
511             /* no tty side to pty so skip it */
512             close(p);
513         }
514     }
515 #endif  /* CRAY */
516 #endif  /* STREAMSPTY */
517 #endif /* OPENPTY */
518     return(-1);
519 #endif
520 }
521
522
523 int
524 tty_isecho(void)
525 {
526     return (termbuf.c_lflag & ECHO);
527 }
528
529 int
530 tty_flowmode(void)
531 {
532     return((termbuf.c_iflag & IXON) ? 1 : 0);
533 }
534
535 int
536 tty_restartany(void)
537 {
538     return((termbuf.c_iflag & IXANY) ? 1 : 0);
539 }
540
541 void
542 tty_setecho(int on)
543 {
544     if (on)
545         termbuf.c_lflag |= ECHO;
546     else
547         termbuf.c_lflag &= ~ECHO;
548 }
549
550 int
551 tty_israw(void)
552 {
553     return(!(termbuf.c_lflag & ICANON));
554 }
555
556 void
557 tty_binaryin(int on)
558 {
559     if (on) {
560         termbuf.c_iflag &= ~ISTRIP;
561     } else {
562         termbuf.c_iflag |= ISTRIP;
563     }
564 }
565
566 void
567 tty_binaryout(int on)
568 {
569     if (on) {
570         termbuf.c_cflag &= ~(CSIZE|PARENB);
571         termbuf.c_cflag |= CS8;
572         termbuf.c_oflag &= ~OPOST;
573     } else {
574         termbuf.c_cflag &= ~CSIZE;
575         termbuf.c_cflag |= CS7|PARENB;
576         termbuf.c_oflag |= OPOST;
577     }
578 }
579
580 int
581 tty_isbinaryin(void)
582 {
583     return(!(termbuf.c_iflag & ISTRIP));
584 }
585
586 int
587 tty_isbinaryout(void)
588 {
589     return(!(termbuf.c_oflag&OPOST));
590 }
591
592
593 int
594 tty_issofttab(void)
595 {
596 # ifdef OXTABS
597     return (termbuf.c_oflag & OXTABS);
598 # endif
599 # ifdef TABDLY
600     return ((termbuf.c_oflag & TABDLY) == TAB3);
601 # endif
602 }
603
604 void
605 tty_setsofttab(int on)
606 {
607     if (on) {
608 # ifdef OXTABS
609         termbuf.c_oflag |= OXTABS;
610 # endif
611 # ifdef TABDLY
612         termbuf.c_oflag &= ~TABDLY;
613         termbuf.c_oflag |= TAB3;
614 # endif
615     } else {
616 # ifdef OXTABS
617         termbuf.c_oflag &= ~OXTABS;
618 # endif
619 # ifdef TABDLY
620         termbuf.c_oflag &= ~TABDLY;
621         termbuf.c_oflag |= TAB0;
622 # endif
623     }
624 }
625
626 int
627 tty_islitecho(void)
628 {
629 # ifdef ECHOCTL
630     return (!(termbuf.c_lflag & ECHOCTL));
631 # endif
632 # ifdef TCTLECH
633     return (!(termbuf.c_lflag & TCTLECH));
634 # endif
635 # if    !defined(ECHOCTL) && !defined(TCTLECH)
636     return (0); /* assumes ctl chars are echoed '^x' */
637 # endif
638 }
639
640 void
641 tty_setlitecho(int on)
642 {
643 # ifdef ECHOCTL
644     if (on)
645         termbuf.c_lflag &= ~ECHOCTL;
646     else
647         termbuf.c_lflag |= ECHOCTL;
648 # endif
649 # ifdef TCTLECH
650     if (on)
651         termbuf.c_lflag &= ~TCTLECH;
652     else
653         termbuf.c_lflag |= TCTLECH;
654 # endif
655 }
656
657 int
658 tty_iscrnl(void)
659 {
660     return (termbuf.c_iflag & ICRNL);
661 }
662
663 /*
664  * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
665  */
666 #if B4800 != 4800
667 #define DECODE_BAUD
668 #endif
669
670 #ifdef  DECODE_BAUD
671
672 /*
673  * A table of available terminal speeds
674  */
675 struct termspeeds {
676     int speed;
677     int value;
678 } termspeeds[] = {
679     { 0,      B0 },      { 50,    B50 },    { 75,     B75 },
680     { 110,    B110 },    { 134,   B134 },   { 150,    B150 },
681     { 200,    B200 },    { 300,   B300 },   { 600,    B600 },
682     { 1200,   B1200 },   { 1800,  B1800 },  { 2400,   B2400 },
683     { 4800,   B4800 },
684 #ifdef  B7200
685     { 7200,  B7200 },
686 #endif
687     { 9600,   B9600 },
688 #ifdef  B14400
689     { 14400,  B14400 },
690 #endif
691 #ifdef  B19200
692     { 19200,  B19200 },
693 #endif
694 #ifdef  B28800
695     { 28800,  B28800 },
696 #endif
697 #ifdef  B38400
698     { 38400,  B38400 },
699 #endif
700 #ifdef  B57600
701     { 57600,  B57600 },
702 #endif
703 #ifdef  B115200
704     { 115200, B115200 },
705 #endif
706 #ifdef  B230400
707     { 230400, B230400 },
708 #endif
709     { -1,     0 }
710 };
711 #endif  /* DECODE_BUAD */
712
713 void
714 tty_tspeed(int val)
715 {
716 #ifdef  DECODE_BAUD
717     struct termspeeds *tp;
718
719     for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
720         ;
721     if (tp->speed == -1)        /* back up to last valid value */
722         --tp;
723     cfsetospeed(&termbuf, tp->value);
724 #else   /* DECODE_BUAD */
725     cfsetospeed(&termbuf, val);
726 #endif  /* DECODE_BUAD */
727 }
728
729 void
730 tty_rspeed(int val)
731 {
732 #ifdef  DECODE_BAUD
733     struct termspeeds *tp;
734
735     for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
736         ;
737     if (tp->speed == -1)        /* back up to last valid value */
738         --tp;
739     cfsetispeed(&termbuf, tp->value);
740 #else   /* DECODE_BAUD */
741     cfsetispeed(&termbuf, val);
742 #endif  /* DECODE_BAUD */
743 }
744
745 #ifdef PARENT_DOES_UTMP
746 extern  struct utmp wtmp;
747 extern char wtmpf[];
748
749 extern void utmp_sig_init (void);
750 extern void utmp_sig_reset (void);
751 extern void utmp_sig_wait (void);
752 extern void utmp_sig_notify (int);
753 # endif /* PARENT_DOES_UTMP */
754
755 #ifdef STREAMSPTY
756
757 /* I_FIND seems to live a life of its own */
758 static int my_find(int fd, char *module)
759 {
760 #if defined(I_FIND) && defined(I_LIST)
761     static int flag;
762     static struct str_list sl;
763     int n;
764     int i;
765   
766     if(!flag){
767         n = ioctl(fd, I_LIST, 0);
768         if(n < 0){
769             perror("ioctl(fd, I_LIST, 0)");
770             return -1;
771         }
772         sl.sl_modlist=(struct str_mlist*)malloc(n * sizeof(struct str_mlist));
773         sl.sl_nmods = n;
774         n = ioctl(fd, I_LIST, &sl);
775         if(n < 0){
776             perror("ioctl(fd, I_LIST, n)");
777             return -1;
778         }
779         flag = 1;
780     }
781   
782     for(i=0; i<sl.sl_nmods; i++)
783         if(!strcmp(sl.sl_modlist[i].l_name, module))
784             return 1;
785 #endif
786     return 0;
787 }
788
789 static void maybe_push_modules(int fd, char **modules)
790 {
791     char **p;
792     int err;
793
794     for(p=modules; *p; p++){
795         err = my_find(fd, *p);
796         if(err == 1)
797             break;
798         if(err < 0 && errno != EINVAL)
799             fatalperror(net, "my_find()");
800         /* module not pushed or does not exist */
801     }
802     /* p points to null or to an already pushed module, now push all
803        modules before this one */
804   
805     for(p--; p >= modules; p--){
806         err = ioctl(fd, I_PUSH, *p);
807         if(err < 0 && errno != EINVAL)
808             fatalperror(net, "I_PUSH");
809     }
810 }
811 #endif
812
813 /*
814  * getptyslave()
815  *
816  * Open the slave side of the pty, and do any initialization
817  * that is necessary.  The return value is a file descriptor
818  * for the slave side.
819  */
820 void getptyslave(void)
821 {
822     int t = -1;
823
824     struct winsize ws;
825     extern int def_row, def_col;
826     extern int def_tspeed, def_rspeed;
827     /*
828      * Opening the slave side may cause initilization of the
829      * kernel tty structure.  We need remember the state of
830      *  if linemode was turned on
831      *  terminal window size
832      *  terminal speed
833      * so that we can re-set them if we need to.
834      */
835
836
837     /*
838      * Make sure that we don't have a controlling tty, and
839      * that we are the session (process group) leader.
840      */
841
842 #ifdef HAVE_SETSID
843     if(setsid()<0)
844         fatalperror(net, "setsid()");
845 #else
846 # ifdef TIOCNOTTY
847     t = open(_PATH_TTY, O_RDWR);
848     if (t >= 0) {
849         ioctl(t, TIOCNOTTY, (char *)0);
850         close(t);
851     }
852 # endif
853 #endif
854
855 # ifdef PARENT_DOES_UTMP
856     /*
857      * Wait for our parent to get the utmp stuff to get done.
858      */
859     utmp_sig_wait();
860 # endif
861
862     t = cleanopen(line);
863     if (t < 0)
864         fatalperror(net, line);
865
866 #ifdef  STREAMSPTY
867     ttyfd = t;
868           
869
870     /*
871      * Not all systems have (or need) modules ttcompat and pckt so
872      * don't flag it as a fatal error if they don't exist.
873      */
874
875     if (really_stream)
876         {
877             /* these are the streams modules that we want pushed. note
878                that they are in reverse order, ptem will be pushed
879                first. maybe_push_modules() will try to push all modules
880                before the first one that isn't already pushed. i.e if
881                ldterm is pushed, only ttcompat will be attempted.
882
883                all this is because we don't know which modules are
884                available, and we don't know which modules are already
885                pushed (via autopush, for instance).
886
887                */
888              
889             char *ttymodules[] = { "ttcompat", "ldterm", "ptem", NULL };
890             char *ptymodules[] = { "pckt", NULL };
891
892             maybe_push_modules(t, ttymodules);
893             maybe_push_modules(ourpty, ptymodules);
894         }
895 #endif
896     /*
897      * set up the tty modes as we like them to be.
898      */
899     init_termbuf();
900 # ifdef TIOCSWINSZ
901     if (def_row || def_col) {
902         memset(&ws, 0, sizeof(ws));
903         ws.ws_col = def_col;
904         ws.ws_row = def_row;
905         ioctl(t, TIOCSWINSZ, (char *)&ws);
906     }
907 # endif
908
909     /*
910      * Settings for sgtty based systems
911      */
912
913     /*
914      * Settings for UNICOS (and HPUX)
915      */
916 # if defined(_CRAY) || defined(__hpux)
917     termbuf.c_oflag = OPOST|ONLCR|TAB3;
918     termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
919     termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
920     termbuf.c_cflag = EXTB|HUPCL|CS8;
921 # endif
922
923     /*
924      * Settings for all other termios/termio based
925      * systems, other than 4.4BSD.  In 4.4BSD the
926      * kernel does the initial terminal setup.
927      */
928 # if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43)
929 #  ifndef       OXTABS
930 #   define OXTABS       0
931 #  endif
932     termbuf.c_lflag |= ECHO;
933     termbuf.c_oflag |= ONLCR|OXTABS;
934     termbuf.c_iflag |= ICRNL;
935     termbuf.c_iflag &= ~IXOFF;
936 # endif
937     tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);
938     tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);
939
940     /*
941      * Set the tty modes, and make this our controlling tty.
942      */
943     set_termbuf();
944     if (login_tty(t) == -1)
945         fatalperror(net, "login_tty");
946     if (net > 2)
947         close(net);
948     if (ourpty > 2) {
949         close(ourpty);
950         ourpty = -1;
951     }
952 }
953
954 #ifndef O_NOCTTY
955 #define O_NOCTTY        0
956 #endif
957 /*
958  * Open the specified slave side of the pty,
959  * making sure that we have a clean tty.
960  */
961
962 int cleanopen(char *line)
963 {
964     int t;
965
966 #ifdef STREAMSPTY
967     if (!really_stream)
968 #endif
969         {
970             /*
971              * Make sure that other people can't open the
972              * slave side of the connection.
973              */
974             chown(line, 0, 0);
975             chmod(line, 0600);
976         }
977
978 #ifdef HAVE_REVOKE
979     revoke(line);
980 #endif
981
982     t = open(line, O_RDWR|O_NOCTTY);
983
984     if (t < 0)
985         return(-1);
986
987     /*
988      * Hangup anybody else using this ttyp, then reopen it for
989      * ourselves.
990      */
991 # if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43) && !defined(STREAMSPTY)
992     signal(SIGHUP, SIG_IGN);
993 #ifdef HAVE_VHANGUP
994     vhangup();
995 #else
996 #endif
997     signal(SIGHUP, SIG_DFL);
998     t = open(line, O_RDWR|O_NOCTTY);
999     if (t < 0)
1000         return(-1);
1001 # endif
1002 # if    defined(_CRAY) && defined(TCVHUP)
1003     {
1004         int i;
1005         signal(SIGHUP, SIG_IGN);
1006         ioctl(t, TCVHUP, (char *)0);
1007         signal(SIGHUP, SIG_DFL);
1008
1009         i = open(line, O_RDWR);
1010
1011         if (i < 0)
1012             return(-1);
1013         close(t);
1014         t = i;
1015     }
1016 # endif /* defined(CRAY) && defined(TCVHUP) */
1017     return(t);
1018 }
1019
1020 #if !defined(BSD4_4)
1021
1022 int login_tty(int t)
1023 {
1024 # if defined(TIOCSCTTY) && !defined(__hpux)
1025     if (ioctl(t, TIOCSCTTY, (char *)0) < 0)
1026         fatalperror(net, "ioctl(sctty)");
1027 #  ifdef _CRAY
1028     /*
1029      * Close the hard fd to /dev/ttypXXX, and re-open through
1030      * the indirect /dev/tty interface.
1031      */
1032     close(t);
1033     if ((t = open("/dev/tty", O_RDWR)) < 0)
1034         fatalperror(net, "open(/dev/tty)");
1035 #  endif
1036 # else
1037     /*
1038      * We get our controlling tty assigned as a side-effect
1039      * of opening up a tty device.  But on BSD based systems,
1040      * this only happens if our process group is zero.  The
1041      * setsid() call above may have set our pgrp, so clear
1042      * it out before opening the tty...
1043      */
1044 #ifdef HAVE_SETPGID
1045     setpgid(0, 0);
1046 #else
1047     setpgrp(0, 0); /* if setpgid isn't available, setpgrp
1048                       probably takes arguments */
1049 #endif
1050     close(open(line, O_RDWR));
1051 # endif
1052     if (t != 0)
1053         dup2(t, 0);
1054     if (t != 1)
1055         dup2(t, 1);
1056     if (t != 2)
1057         dup2(t, 2);
1058     if (t > 2)
1059         close(t);
1060     return(0);
1061 }
1062 #endif  /* BSD <= 43 */
1063
1064 /*
1065  * This comes from ../../bsd/tty.c and should not really be here.
1066  */
1067
1068 /*
1069  * Clean the tty name.  Return a pointer to the cleaned version.
1070  */
1071
1072 static char *
1073 clean_ttyname (char *tty)
1074 {
1075   char *res = tty;
1076
1077   if (strncmp (res, _PATH_DEV, strlen(_PATH_DEV)) == 0)
1078     res += strlen(_PATH_DEV);
1079   if (strncmp (res, "pty/", 4) == 0)
1080     res += 4;
1081   if (strncmp (res, "ptym/", 5) == 0)
1082     res += 5;
1083   return res;
1084 }
1085
1086 /*
1087  * Generate a name usable as an `ut_id', typically without `tty'.
1088  */
1089
1090 #ifdef HAVE_STRUCT_UTMP_UT_ID
1091 static char *
1092 make_id (char *tty)
1093 {
1094   char *res = tty;
1095   
1096   if (strncmp (res, "pts/", 4) == 0)
1097     res += 4;
1098   if (strncmp (res, "tty", 3) == 0)
1099     res += 3;
1100   return res;
1101 }
1102 #endif
1103
1104 /*
1105  * startslave(host)
1106  *
1107  * Given a hostname, do whatever
1108  * is necessary to startup the login process on the slave side of the pty.
1109  */
1110
1111 /* ARGSUSED */
1112 void
1113 startslave(char *host, int autologin, char *autoname)
1114 {
1115     int i;
1116
1117 #ifdef AUTHENTICATION
1118     if (!autoname || !autoname[0])
1119         autologin = 0;
1120
1121     if (autologin < auth_level) {
1122         fatal(net, "Authorization failed");
1123         exit(1);
1124     }
1125 #endif
1126
1127     {
1128         char *tbuf =
1129             "\r\n*** Connection not encrypted! "
1130             "Communication may be eavesdropped. ***\r\n";
1131 #ifdef ENCRYPTION
1132         if (!no_warn && (encrypt_output == 0 || decrypt_input == 0))
1133 #endif
1134             writenet((unsigned char*)tbuf, strlen(tbuf));
1135     }
1136 # ifdef PARENT_DOES_UTMP
1137     utmp_sig_init();
1138 # endif /* PARENT_DOES_UTMP */
1139
1140     if ((i = fork()) < 0)
1141         fatalperror(net, "fork");
1142     if (i) {
1143 # ifdef PARENT_DOES_UTMP
1144         /*
1145          * Cray parent will create utmp entry for child and send
1146          * signal to child to tell when done.  Child waits for signal
1147          * before doing anything important.
1148          */
1149         int pid = i;
1150         void sigjob (int);
1151
1152         setpgrp();
1153         utmp_sig_reset();               /* reset handler to default */
1154         /*
1155          * Create utmp entry for child
1156          */
1157         time(&wtmp.ut_time);
1158         wtmp.ut_type = LOGIN_PROCESS;
1159         wtmp.ut_pid = pid;
1160         strncpy(wtmp.ut_user,  "LOGIN", sizeof(wtmp.ut_user));
1161         strncpy(wtmp.ut_host,  host, sizeof(wtmp.ut_host));
1162         strncpy(wtmp.ut_line,  clean_ttyname(line), sizeof(wtmp.ut_line));
1163 #ifdef HAVE_STRUCT_UTMP_UT_ID
1164         strncpy(wtmp.ut_id, wtmp.ut_line + 3, sizeof(wtmp.ut_id));
1165 #endif
1166
1167         pututline(&wtmp);
1168         endutent();
1169         if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) {
1170             write(i, &wtmp, sizeof(struct utmp));
1171             close(i);
1172         }
1173 #ifdef  _CRAY
1174         signal(WJSIGNAL, sigjob);
1175 #endif
1176         utmp_sig_notify(pid);
1177 # endif /* PARENT_DOES_UTMP */
1178     } else {
1179         getptyslave();
1180         start_login(host, autologin, autoname);
1181         /*NOTREACHED*/
1182     }
1183 }
1184
1185 char    *envinit[3];
1186 extern char **environ;
1187
1188 void
1189 init_env(void)
1190 {
1191     extern char *getenv(const char *);
1192     char **envp;
1193
1194     envp = envinit;
1195     if ((*envp = getenv("TZ")))
1196         *envp++ -= 3;
1197 #if defined(_CRAY) || defined(__hpux)
1198     else
1199         *envp++ = "TZ=GMT0";
1200 #endif
1201     *envp = 0;
1202     environ = envinit;
1203 }
1204
1205 /*
1206  * scrub_env()
1207  *
1208  * Remove variables from the environment that might cause login to
1209  * behave in a bad manner. To avoid this, login should be staticly
1210  * linked.
1211  */
1212
1213 static void scrub_env(void)
1214 {
1215     static char *remove[] = { "LD_", "_RLD_", "LIBPATH=", "IFS=", NULL };
1216
1217     char **cpp, **cpp2;
1218     char **p;
1219   
1220     for (cpp2 = cpp = environ; *cpp; cpp++) {
1221         for(p = remove; *p; p++)
1222             if(strncmp(*cpp, *p, strlen(*p)) == 0)
1223                 break;
1224         if(*p == NULL)
1225             *cpp2++ = *cpp;
1226     }
1227     *cpp2 = 0;
1228 }
1229
1230
1231 struct arg_val {
1232     int size;
1233     int argc;
1234     char **argv;
1235 };
1236
1237 static void addarg(struct arg_val*, char*);
1238
1239 /*
1240  * start_login(host)
1241  *
1242  * Assuming that we are now running as a child processes, this
1243  * function will turn us into the login process.
1244  */
1245
1246 void
1247 start_login(char *host, int autologin, char *name)
1248 {
1249     struct arg_val argv;
1250     char *user;
1251
1252 #ifdef HAVE_UTMPX_H
1253     int pid = getpid();
1254     struct utmpx utmpx;
1255     char *clean_tty;
1256
1257     /*
1258      * Create utmp entry for child
1259      */
1260
1261     clean_tty = clean_ttyname(line);
1262     memset(&utmpx, 0, sizeof(utmpx));
1263     strncpy(utmpx.ut_user,  ".telnet", sizeof(utmpx.ut_user));
1264     strncpy(utmpx.ut_line,  clean_tty, sizeof(utmpx.ut_line));
1265 #ifdef HAVE_STRUCT_UTMP_UT_ID
1266     strncpy(utmpx.ut_id, make_id(clean_tty), sizeof(utmpx.ut_id));
1267 #endif
1268     utmpx.ut_pid = pid;
1269         
1270     utmpx.ut_type = LOGIN_PROCESS;
1271
1272     gettimeofday (&utmpx.ut_tv, NULL);
1273     if (pututxline(&utmpx) == NULL)
1274         fatal(net, "pututxline failed");
1275 #endif
1276
1277     scrub_env();
1278         
1279     /*
1280      * -h : pass on name of host.
1281      *          WARNING:  -h is accepted by login if and only if
1282      *                  getuid() == 0.
1283      * -p : don't clobber the environment (so terminal type stays set).
1284      *
1285      * -f : force this login, he has already been authenticated
1286      */
1287
1288     /* init argv structure */ 
1289     argv.size=0;
1290     argv.argc=0;
1291     argv.argv=(char**)malloc(0); /*so we can call realloc later */
1292     addarg(&argv, "login");
1293     addarg(&argv, "-h");
1294     addarg(&argv, host);
1295     addarg(&argv, "-p");
1296     if(name[0])
1297         user = name;
1298     else
1299         user = getenv("USER");
1300 #ifdef AUTHENTICATION
1301     if (auth_level < 0 || autologin != AUTH_VALID) {
1302         if(!no_warn) {
1303             printf("User not authenticated. ");
1304             if (require_otp)
1305                 printf("Using one-time password\r\n");
1306             else
1307                 printf("Using plaintext username and password\r\n");
1308         }
1309         if (require_otp) {
1310             addarg(&argv, "-a");
1311             addarg(&argv, "otp");
1312         }
1313         if(log_unauth) 
1314             syslog(LOG_INFO, "unauthenticated access from %s (%s)", 
1315                    host, user ? user : "unknown user");
1316     }
1317     if (auth_level >= 0 && autologin == AUTH_VALID)
1318         addarg(&argv, "-f");
1319 #endif
1320     if(user){
1321         addarg(&argv, "--");
1322         addarg(&argv, strdup(user));
1323     }
1324     if (getenv("USER")) {
1325         /*
1326          * Assume that login will set the USER variable
1327          * correctly.  For SysV systems, this means that
1328          * USER will no longer be set, just LOGNAME by
1329          * login.  (The problem is that if the auto-login
1330          * fails, and the user then specifies a different
1331          * account name, he can get logged in with both
1332          * LOGNAME and USER in his environment, but the
1333          * USER value will be wrong.
1334          */
1335         unsetenv("USER");
1336     }
1337     closelog();
1338     /*
1339      * This sleep(1) is in here so that telnetd can
1340      * finish up with the tty.  There's a race condition
1341      * the login banner message gets lost...
1342      */
1343     sleep(1);
1344
1345     execv(new_login, argv.argv);
1346
1347     syslog(LOG_ERR, "%s: %m\n", new_login);
1348     fatalperror(net, new_login);
1349     /*NOTREACHED*/
1350 }
1351
1352 static void
1353 addarg(struct arg_val *argv, char *val)
1354 {
1355     if(argv->size <= argv->argc+1) {
1356         argv->argv = realloc(argv->argv, sizeof(char*) * (argv->size + 10));
1357         if (argv->argv == NULL)
1358             fatal (net, "realloc: out of memory");
1359         argv->size+=10;
1360     }
1361     argv->argv[argv->argc++] = val;
1362     argv->argv[argv->argc]   = NULL;
1363 }
1364
1365
1366 /*
1367  * rmut()
1368  *
1369  * This is the function called by cleanup() to
1370  * remove the utmp entry for this person.
1371  */
1372
1373 #ifdef HAVE_UTMPX_H
1374 static void
1375 rmut(void)
1376 {
1377     struct utmpx utmpx, *non_save_utxp;
1378     char *clean_tty = clean_ttyname(line);
1379
1380     /*
1381      * This updates the utmpx and utmp entries and make a wtmp/x entry
1382      */
1383
1384     setutxent();
1385     memset(&utmpx, 0, sizeof(utmpx));
1386     strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line));
1387     utmpx.ut_type = LOGIN_PROCESS;
1388     non_save_utxp = getutxline(&utmpx);
1389     if (non_save_utxp) {
1390         struct utmpx *utxp;
1391         char user0;
1392
1393         utxp = malloc(sizeof(struct utmpx));
1394         *utxp = *non_save_utxp;
1395         user0 = utxp->ut_user[0];
1396         utxp->ut_user[0] = '\0';
1397         utxp->ut_type = DEAD_PROCESS;
1398 #ifdef HAVE_STRUCT_UTMPX_UT_EXIT
1399 #ifdef _STRUCT___EXIT_STATUS
1400         utxp->ut_exit.__e_termination = 0;
1401         utxp->ut_exit.__e_exit = 0;
1402 #elif defined(__osf__) /* XXX */
1403         utxp->ut_exit.ut_termination = 0;
1404         utxp->ut_exit.ut_exit = 0;
1405 #else   
1406         utxp->ut_exit.e_termination = 0;
1407         utxp->ut_exit.e_exit = 0;
1408 #endif
1409 #endif
1410         gettimeofday(&utxp->ut_tv, NULL);
1411         pututxline(utxp);
1412 #ifdef WTMPX_FILE
1413         utxp->ut_user[0] = user0;
1414         updwtmpx(WTMPX_FILE, utxp);
1415 #elif defined(WTMP_FILE)
1416         /* This is a strange system with a utmpx and a wtmp! */
1417         {
1418           int f = open(wtmpf, O_WRONLY|O_APPEND);
1419           struct utmp wtmp;
1420           if (f >= 0) {
1421             strncpy(wtmp.ut_line,  clean_tty, sizeof(wtmp.ut_line));
1422             strncpy(wtmp.ut_name,  "", sizeof(wtmp.ut_name));
1423 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1424             strncpy(wtmp.ut_host,  "", sizeof(wtmp.ut_host));
1425 #endif
1426             time(&wtmp.ut_time);
1427             write(f, &wtmp, sizeof(wtmp));
1428             close(f);
1429           }
1430         }
1431 #endif
1432         free (utxp);
1433     }
1434     endutxent();
1435 }  /* end of rmut */
1436 #endif
1437
1438 #if !defined(HAVE_UTMPX_H) && !(defined(_CRAY) || defined(__hpux)) && BSD <= 43
1439 static void
1440 rmut(void)
1441 {
1442     int f;
1443     int found = 0;
1444     struct utmp *u, *utmp;
1445     int nutmp;
1446     struct stat statbf;
1447     char *clean_tty = clean_ttyname(line);
1448
1449     f = open(utmpf, O_RDWR);
1450     if (f >= 0) {
1451         fstat(f, &statbf);
1452         utmp = (struct utmp *)malloc((unsigned)statbf.st_size);
1453         if (!utmp)
1454             syslog(LOG_ERR, "utmp malloc failed");
1455         if (statbf.st_size && utmp) {
1456             nutmp = read(f, utmp, (int)statbf.st_size);
1457             nutmp /= sizeof(struct utmp);
1458
1459             for (u = utmp ; u < &utmp[nutmp] ; u++) {
1460                 if (strncmp(u->ut_line,
1461                             clean_tty,
1462                             sizeof(u->ut_line)) ||
1463                     u->ut_name[0]==0)
1464                     continue;
1465                 lseek(f, ((long)u)-((long)utmp), L_SET);
1466                 strncpy(u->ut_name,  "", sizeof(u->ut_name));
1467 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1468                 strncpy(u->ut_host,  "", sizeof(u->ut_host));
1469 #endif
1470                 time(&u->ut_time);
1471                 write(f, u, sizeof(wtmp));
1472                 found++;
1473             }
1474         }
1475         close(f);
1476     }
1477     if (found) {
1478         f = open(wtmpf, O_WRONLY|O_APPEND);
1479         if (f >= 0) {
1480             strncpy(wtmp.ut_line,  clean_tty, sizeof(wtmp.ut_line));
1481             strncpy(wtmp.ut_name,  "", sizeof(wtmp.ut_name));
1482 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1483             strncpy(wtmp.ut_host,  "", sizeof(wtmp.ut_host));
1484 #endif
1485             time(&wtmp.ut_time);
1486             write(f, &wtmp, sizeof(wtmp));
1487             close(f);
1488         }
1489     }
1490     chmod(line, 0666);
1491     chown(line, 0, 0);
1492     line[strlen("/dev/")] = 'p';
1493     chmod(line, 0666);
1494     chown(line, 0, 0);
1495 }  /* end of rmut */
1496 #endif  /* CRAY */
1497
1498 #if defined(__hpux) && !defined(HAVE_UTMPX_H)
1499 static void
1500 rmut (char *line)
1501 {
1502     struct utmp utmp;
1503     struct utmp *utptr;
1504     int fd;                     /* for /etc/wtmp */
1505
1506     utmp.ut_type = USER_PROCESS;
1507     strncpy(utmp.ut_line, clean_ttyname(line), sizeof(utmp.ut_line));
1508     setutent();
1509     utptr = getutline(&utmp);
1510     /* write it out only if it exists */
1511     if (utptr) {
1512         utptr->ut_type = DEAD_PROCESS;
1513         utptr->ut_time = time(NULL);
1514         pututline(utptr);
1515         /* set wtmp entry if wtmp file exists */
1516         if ((fd = open(wtmpf, O_WRONLY | O_APPEND)) >= 0) {
1517             write(fd, utptr, sizeof(utmp));
1518             close(fd);
1519         }
1520     }
1521     endutent();
1522
1523     chmod(line, 0666);
1524     chown(line, 0, 0);
1525     line[14] = line[13];
1526     line[13] = line[12];
1527     line[8] = 'm';
1528     line[9] = '/';
1529     line[10] = 'p';
1530     line[11] = 't';
1531     line[12] = 'y';
1532     chmod(line, 0666);
1533     chown(line, 0, 0);
1534 }
1535 #endif
1536
1537 /*
1538  * cleanup()
1539  *
1540  * This is the routine to call when we are all through, to
1541  * clean up anything that needs to be cleaned up.
1542  */
1543
1544 #ifdef PARENT_DOES_UTMP
1545
1546 void
1547 cleanup(int sig)
1548 {
1549 #ifdef _CRAY
1550     static int incleanup = 0;
1551     int t;
1552     int child_status; /* status of child process as returned by waitpid */
1553     int flags = WNOHANG|WUNTRACED;
1554     
1555     /*
1556      * 1: Pick up the zombie, if we are being called
1557      *    as the signal handler.
1558      * 2: If we are a nested cleanup(), return.
1559      * 3: Try to clean up TMPDIR.
1560      * 4: Fill in utmp with shutdown of process.
1561      * 5: Close down the network and pty connections.
1562      * 6: Finish up the TMPDIR cleanup, if needed.
1563      */
1564     if (sig == SIGCHLD) {
1565         while (waitpid(-1, &child_status, flags) > 0)
1566             ;   /* VOID */
1567         /* Check if the child process was stopped
1568          * rather than exited.  We want cleanup only if
1569          * the child has died.
1570          */
1571         if (WIFSTOPPED(child_status)) {
1572             return;
1573         }
1574     }
1575     t = sigblock(sigmask(SIGCHLD));
1576     if (incleanup) {
1577         sigsetmask(t);
1578         return;
1579     }
1580     incleanup = 1;
1581     sigsetmask(t);
1582     
1583     t = cleantmp(&wtmp);
1584     setutent(); /* just to make sure */
1585 #endif /* CRAY */
1586     rmut(line);
1587     close(ourpty);
1588     shutdown(net, 2);
1589 #ifdef _CRAY
1590     if (t == 0)
1591         cleantmp(&wtmp);
1592 #endif /* CRAY */
1593     exit(1);
1594 }
1595
1596 #else /* PARENT_DOES_UTMP */
1597
1598 void
1599 cleanup(int sig)
1600 {
1601 #if defined(HAVE_UTMPX_H) || !defined(HAVE_LOGWTMP)
1602     rmut();
1603 #ifdef HAVE_VHANGUP
1604 #ifndef __sgi
1605     vhangup(); /* XXX */
1606 #endif
1607 #endif
1608 #else
1609     char *p;
1610     
1611     p = line + sizeof("/dev/") - 1;
1612     if (logout(p))
1613         logwtmp(p, "", "");
1614     chmod(line, 0666);
1615     chown(line, 0, 0);
1616     *p = 'p';
1617     chmod(line, 0666);
1618     chown(line, 0, 0);
1619 #endif
1620     shutdown(net, 2);
1621     exit(1);
1622 }
1623
1624 #endif /* PARENT_DOES_UTMP */
1625
1626 #ifdef PARENT_DOES_UTMP
1627 /*
1628  * _utmp_sig_rcv
1629  * utmp_sig_init
1630  * utmp_sig_wait
1631  *      These three functions are used to coordinate the handling of
1632  *      the utmp file between the server and the soon-to-be-login shell.
1633  *      The server actually creates the utmp structure, the child calls
1634  *      utmp_sig_wait(), until the server calls utmp_sig_notify() and
1635  *      signals the future-login shell to proceed.
1636  */
1637 static int caught=0;            /* NZ when signal intercepted */
1638 static void (*func)();          /* address of previous handler */
1639
1640 void
1641 _utmp_sig_rcv(sig)
1642      int sig;
1643 {
1644     caught = 1;
1645     signal(SIGUSR1, func);
1646 }
1647
1648 void
1649 utmp_sig_init()
1650 {
1651     /*
1652      * register signal handler for UTMP creation
1653      */
1654     if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1)
1655         fatalperror(net, "telnetd/signal");
1656 }
1657
1658 void
1659 utmp_sig_reset()
1660 {
1661     signal(SIGUSR1, func);      /* reset handler to default */
1662 }
1663
1664 # ifdef __hpux
1665 # define sigoff() /* do nothing */
1666 # define sigon() /* do nothing */
1667 # endif
1668
1669 void
1670 utmp_sig_wait()
1671 {
1672     /*
1673      * Wait for parent to write our utmp entry.
1674          */
1675     sigoff();
1676     while (caught == 0) {
1677         pause();        /* wait until we get a signal (sigon) */
1678         sigoff();       /* turn off signals while we check caught */
1679     }
1680     sigon();            /* turn on signals again */
1681 }
1682
1683 void
1684 utmp_sig_notify(pid)
1685 {
1686     kill(pid, SIGUSR1);
1687 }
1688
1689 #ifdef _CRAY
1690 static int gotsigjob = 0;
1691
1692         /*ARGSUSED*/
1693 void
1694 sigjob(sig)
1695      int sig;
1696 {
1697     int jid;
1698     struct jobtemp *jp;
1699
1700     while ((jid = waitjob(NULL)) != -1) {
1701         if (jid == 0) {
1702             return;
1703         }
1704         gotsigjob++;
1705         jobend(jid, NULL, NULL);
1706     }
1707 }
1708
1709 /*
1710  *      jid_getutid:
1711  *              called by jobend() before calling cleantmp()
1712  *              to find the correct $TMPDIR to cleanup.
1713  */
1714
1715 struct utmp *
1716 jid_getutid(jid)
1717      int jid;
1718 {
1719     struct utmp *cur = NULL;
1720
1721     setutent(); /* just to make sure */
1722     while (cur = getutent()) {
1723         if ( (cur->ut_type != NULL) && (jid == cur->ut_jid) ) {
1724             return(cur);
1725         }
1726     }
1727
1728     return(0);
1729 }
1730
1731 /*
1732  * Clean up the TMPDIR that login created.
1733  * The first time this is called we pick up the info
1734  * from the utmp.  If the job has already gone away,
1735  * then we'll clean up and be done.  If not, then
1736  * when this is called the second time it will wait
1737  * for the signal that the job is done.
1738  */
1739 int
1740 cleantmp(wtp)
1741      struct utmp *wtp;
1742 {
1743     struct utmp *utp;
1744     static int first = 1;
1745     int mask, omask, ret;
1746     extern struct utmp *getutid (const struct utmp *_Id);
1747
1748
1749     mask = sigmask(WJSIGNAL);
1750
1751     if (first == 0) {
1752         omask = sigblock(mask);
1753         while (gotsigjob == 0)
1754             sigpause(omask);
1755         return(1);
1756     }
1757     first = 0;
1758     setutent(); /* just to make sure */
1759
1760     utp = getutid(wtp);
1761     if (utp == 0) {
1762         syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
1763         return(-1);
1764     }
1765     /*
1766      * Nothing to clean up if the user shell was never started.
1767      */
1768     if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0)
1769         return(1);
1770
1771     /*
1772      * Block the WJSIGNAL while we are in jobend().
1773      */
1774     omask = sigblock(mask);
1775     ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user);
1776     sigsetmask(omask);
1777     return(ret);
1778 }
1779
1780 int
1781 jobend(jid, path, user)
1782      int jid;
1783      char *path;
1784      char *user;
1785 {
1786     static int saved_jid = 0;
1787     static int pty_saved_jid = 0;
1788     static char saved_path[sizeof(wtmp.ut_tpath)+1];
1789     static char saved_user[sizeof(wtmp.ut_user)+1];
1790
1791     /*
1792      * this little piece of code comes into play
1793      * only when ptyreconnect is used to reconnect
1794      * to an previous session.
1795      *
1796      * this is the only time when the
1797      * "saved_jid != jid" code is executed.
1798      */
1799
1800     if ( saved_jid && saved_jid != jid ) {
1801         if (!path) {    /* called from signal handler */
1802             pty_saved_jid = jid;
1803         } else {
1804             pty_saved_jid = saved_jid;
1805         }
1806     }
1807
1808     if (path) {
1809         strncpy(saved_path, path, sizeof(wtmp.ut_tpath));
1810         strncpy(saved_user, user, sizeof(wtmp.ut_user));
1811         saved_path[sizeof(saved_path)] = '\0';
1812         saved_user[sizeof(saved_user)] = '\0';
1813     }
1814     if (saved_jid == 0) {
1815         saved_jid = jid;
1816         return(0);
1817     }
1818
1819     /* if the jid has changed, get the correct entry from the utmp file */
1820
1821     if ( saved_jid != jid ) {
1822         struct utmp *utp = NULL;
1823         struct utmp *jid_getutid();
1824
1825         utp = jid_getutid(pty_saved_jid);
1826
1827         if (utp == 0) {
1828             syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
1829             return(-1);
1830         }
1831
1832         cleantmpdir(jid, utp->ut_tpath, utp->ut_user);
1833         return(1);
1834     }
1835
1836     cleantmpdir(jid, saved_path, saved_user);
1837     return(1);
1838 }
1839
1840 /*
1841  * Fork a child process to clean up the TMPDIR
1842  */
1843 cleantmpdir(jid, tpath, user)
1844      int jid;
1845      char *tpath;
1846      char *user;
1847 {
1848     switch(fork()) {
1849     case -1:
1850         syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m\n",
1851                tpath);
1852         break;
1853     case 0:
1854         execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, 0);
1855         syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m\n",
1856                tpath, CLEANTMPCMD);
1857         exit(1);
1858     default:
1859         /*
1860          * Forget about child.  We will exit, and
1861          * /etc/init will pick it up.
1862          */
1863         break;
1864     }
1865 }
1866 #endif /* CRAY */
1867 #endif  /* defined(PARENT_DOES_UTMP) */