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) */
1900