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