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