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