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