xref: /netbsd-src/libexec/telnetd/sys_term.c (revision 5f7096188587a2c7c95fa3c69b78e1ec9c7923d0)
1 /*
2  * Copyright (c) 1989 Regents of the University of California.
3  * 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 #ifndef lint
35 /*static char sccsid[] = "from: @(#)sys_term.c	5.16 (Berkeley) 3/22/91";*/
36 static char rcsid[] = "$Id: sys_term.c,v 1.2 1993/08/01 18:29:10 mycroft Exp $";
37 #endif /* not lint */
38 
39 #include "telnetd.h"
40 #include "pathnames.h"
41 
42 #if	defined(AUTHENTICATE)
43 #include <libtelnet/auth.h>
44 #endif
45 
46 #ifdef	NEWINIT
47 #include <initreq.h>
48 #else	/* NEWINIT*/
49 #include <utmp.h>
50 struct	utmp wtmp;
51 
52 # ifndef CRAY
53 char	wtmpf[]	= "/usr/adm/wtmp";
54 char	utmpf[] = "/etc/utmp";
55 # else	/* CRAY */
56 char	wtmpf[]	= "/etc/wtmp";
57 #include <tmpdir.h>
58 #include <sys/wait.h>
59 # endif	/* CRAY */
60 #endif	/* NEWINIT */
61 
62 #define SCPYN(a, b)	(void) strncpy(a, b, sizeof(a))
63 #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
64 
65 #ifdef	STREAMS
66 #include <sys/stream.h>
67 #endif
68 #include <sys/tty.h>
69 #ifdef	t_erase
70 #undef	t_erase
71 #undef	t_kill
72 #undef	t_intrc
73 #undef	t_quitc
74 #undef	t_startc
75 #undef	t_stopc
76 #undef	t_eofc
77 #undef	t_brkc
78 #undef	t_suspc
79 #undef	t_dsuspc
80 #undef	t_rprntc
81 #undef	t_flushc
82 #undef	t_werasc
83 #undef	t_lnextc
84 #endif
85 
86 #if defined(UNICOS5) && defined(CRAY2) && !defined(EXTPROC)
87 # define EXTPROC 0400
88 #endif
89 
90 #ifndef	USE_TERMIO
91 struct termbuf {
92 	struct sgttyb sg;
93 	struct tchars tc;
94 	struct ltchars ltc;
95 	int state;
96 	int lflags;
97 } termbuf, termbuf2;
98 # define	cfsetospeed(tp, val)	(tp)->sg.sg_ospeed = (val)
99 # define	cfsetispeed(tp, val)	(tp)->sg.sg_ispeed = (val)
100 # define	cfgetospeed(tp)		(tp)->sg.sg_ospeed
101 # define	cfgetispeed(tp)		(tp)->sg.sg_ispeed
102 #else	/* USE_TERMIO */
103 # ifdef	SYSV_TERMIO
104 #	define termios termio
105 # endif
106 # ifndef	TCSANOW
107 #  ifdef TCSETS
108 #   define	TCSANOW		TCSETS
109 #   define	TCSADRAIN	TCSETSW
110 #   define	tcgetattr(f, t)	ioctl(f, TCGETS, (char *)t)
111 #  else
112 #   ifdef TCSETA
113 #    define	TCSANOW		TCSETA
114 #    define	TCSADRAIN	TCSETAW
115 #    define	tcgetattr(f, t)	ioctl(f, TCGETA, (char *)t)
116 #   else
117 #    define	TCSANOW		TIOCSETA
118 #    define	TCSADRAIN	TIOCSETAW
119 #    define	tcgetattr(f, t)	ioctl(f, TIOCGETA, (char *)t)
120 #   endif
121 #  endif
122 #  define	tcsetattr(f, a, t)	ioctl(f, a, t)
123 #  define	cfsetospeed(tp, val)	(tp)->c_cflag &= ~CBAUD; \
124 					(tp)->c_cflag |= (val)
125 #  define	cfgetospeed(tp)		((tp)->c_cflag & CBAUD)
126 #  ifdef CIBAUD
127 #   define	cfsetispeed(tp, val)	(tp)->c_cflag &= ~CIBAUD; \
128 					(tp)->c_cflag |= ((val)<<IBSHIFT)
129 #   define	cfgetispeed(tp)		(((tp)->c_cflag & CIBAUD)>>IBSHIFT)
130 #  else
131 #   define	cfsetispeed(tp, val)	(tp)->c_cflag &= ~CBAUD; \
132 					(tp)->c_cflag |= (val)
133 #   define	cfgetispeed(tp)		((tp)->c_cflag & CBAUD)
134 #  endif
135 # endif /* TCSANOW */
136 struct termios termbuf, termbuf2;	/* pty control structure */
137 #endif	/* USE_TERMIO */
138 
139 /*
140  * init_termbuf()
141  * copy_termbuf(cp)
142  * set_termbuf()
143  *
144  * These three routines are used to get and set the "termbuf" structure
145  * to and from the kernel.  init_termbuf() gets the current settings.
146  * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
147  * set_termbuf() writes the structure into the kernel.
148  */
149 
150 	void
151 init_termbuf()
152 {
153 #ifndef	USE_TERMIO
154 	(void) ioctl(pty, TIOCGETP, (char *)&termbuf.sg);
155 	(void) ioctl(pty, TIOCGETC, (char *)&termbuf.tc);
156 	(void) ioctl(pty, TIOCGLTC, (char *)&termbuf.ltc);
157 # ifdef	TIOCGSTATE
158 	(void) ioctl(pty, TIOCGSTATE, (char *)&termbuf.state);
159 # endif
160 #else
161 	(void) tcgetattr(pty, &termbuf);
162 #endif
163 	termbuf2 = termbuf;
164 }
165 
166 #if	defined(LINEMODE) && defined(TIOCPKT_IOCTL)
167 	void
168 copy_termbuf(cp, len)
169 	char *cp;
170 	int len;
171 {
172 	if (len > sizeof(termbuf))
173 		len = sizeof(termbuf);
174 	bcopy(cp, (char *)&termbuf, len);
175 	termbuf2 = termbuf;
176 }
177 #endif	/* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */
178 
179 	void
180 set_termbuf()
181 {
182 	/*
183 	 * Only make the necessary changes.
184 	 */
185 #ifndef	USE_TERMIO
186 	if (bcmp((char *)&termbuf.sg, (char *)&termbuf2.sg, sizeof(termbuf.sg)))
187 		(void) ioctl(pty, TIOCSETN, (char *)&termbuf.sg);
188 	if (bcmp((char *)&termbuf.tc, (char *)&termbuf2.tc, sizeof(termbuf.tc)))
189 		(void) ioctl(pty, TIOCSETC, (char *)&termbuf.tc);
190 	if (bcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc,
191 							sizeof(termbuf.ltc)))
192 		(void) ioctl(pty, TIOCSLTC, (char *)&termbuf.ltc);
193 	if (termbuf.lflags != termbuf2.lflags)
194 		(void) ioctl(pty, TIOCLSET, (char *)&termbuf.lflags);
195 #else	/* USE_TERMIO */
196 	if (bcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf)))
197 		(void) tcsetattr(pty, TCSANOW, &termbuf);
198 # if	defined(CRAY2) && defined(UNCIOS5)
199 	needtermstat = 1;
200 # endif
201 #endif	/* USE_TERMIO */
202 }
203 
204 
205 /*
206  * spcset(func, valp, valpp)
207  *
208  * This function takes various special characters (func), and
209  * sets *valp to the current value of that character, and
210  * *valpp to point to where in the "termbuf" structure that
211  * value is kept.
212  *
213  * It returns the SLC_ level of support for this function.
214  */
215 
216 #ifndef	USE_TERMIO
217 	int
218 spcset(func, valp, valpp)
219 	int func;
220 	cc_t *valp;
221 	cc_t **valpp;
222 {
223 	switch(func) {
224 	case SLC_EOF:
225 		*valp = termbuf.tc.t_eofc;
226 		*valpp = (cc_t *)&termbuf.tc.t_eofc;
227 		return(SLC_VARIABLE);
228 	case SLC_EC:
229 		*valp = termbuf.sg.sg_erase;
230 		*valpp = (cc_t *)&termbuf.sg.sg_erase;
231 		return(SLC_VARIABLE);
232 	case SLC_EL:
233 		*valp = termbuf.sg.sg_kill;
234 		*valpp = (cc_t *)&termbuf.sg.sg_kill;
235 		return(SLC_VARIABLE);
236 	case SLC_IP:
237 		*valp = termbuf.tc.t_intrc;
238 		*valpp = (cc_t *)&termbuf.tc.t_intrc;
239 		return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
240 	case SLC_ABORT:
241 		*valp = termbuf.tc.t_quitc;
242 		*valpp = (cc_t *)&termbuf.tc.t_quitc;
243 		return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
244 	case SLC_XON:
245 		*valp = termbuf.tc.t_startc;
246 		*valpp = (cc_t *)&termbuf.tc.t_startc;
247 		return(SLC_VARIABLE);
248 	case SLC_XOFF:
249 		*valp = termbuf.tc.t_stopc;
250 		*valpp = (cc_t *)&termbuf.tc.t_stopc;
251 		return(SLC_VARIABLE);
252 	case SLC_AO:
253 		*valp = termbuf.ltc.t_flushc;
254 		*valpp = (cc_t *)&termbuf.ltc.t_flushc;
255 		return(SLC_VARIABLE);
256 	case SLC_SUSP:
257 		*valp = termbuf.ltc.t_suspc;
258 		*valpp = (cc_t *)&termbuf.ltc.t_suspc;
259 		return(SLC_VARIABLE);
260 	case SLC_EW:
261 		*valp = termbuf.ltc.t_werasc;
262 		*valpp = (cc_t *)&termbuf.ltc.t_werasc;
263 		return(SLC_VARIABLE);
264 	case SLC_RP:
265 		*valp = termbuf.ltc.t_rprntc;
266 		*valpp = (cc_t *)&termbuf.ltc.t_rprntc;
267 		return(SLC_VARIABLE);
268 	case SLC_LNEXT:
269 		*valp = termbuf.ltc.t_lnextc;
270 		*valpp = (cc_t *)&termbuf.ltc.t_lnextc;
271 		return(SLC_VARIABLE);
272 	case SLC_FORW1:
273 		*valp = termbuf.tc.t_brkc;
274 		*valpp = (cc_t *)&termbuf.ltc.t_lnextc;
275 		return(SLC_VARIABLE);
276 	case SLC_BRK:
277 	case SLC_SYNCH:
278 	case SLC_AYT:
279 	case SLC_EOR:
280 		*valp = (cc_t)0;
281 		*valpp = (cc_t *)0;
282 		return(SLC_DEFAULT);
283 	default:
284 		*valp = (cc_t)0;
285 		*valpp = (cc_t *)0;
286 		return(SLC_NOSUPPORT);
287 	}
288 }
289 
290 #else	/* USE_TERMIO */
291 
292 	int
293 spcset(func, valp, valpp)
294 	int func;
295 	cc_t *valp;
296 	cc_t **valpp;
297 {
298 
299 #define	setval(a, b)	*valp = termbuf.c_cc[a]; \
300 			*valpp = &termbuf.c_cc[a]; \
301 			return(b);
302 #define	defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
303 
304 	switch(func) {
305 	case SLC_EOF:
306 		setval(VEOF, SLC_VARIABLE);
307 	case SLC_EC:
308 		setval(VERASE, SLC_VARIABLE);
309 	case SLC_EL:
310 		setval(VKILL, SLC_VARIABLE);
311 	case SLC_IP:
312 		setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
313 	case SLC_ABORT:
314 		setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
315 	case SLC_XON:
316 #ifdef	VSTART
317 		setval(VSTART, SLC_VARIABLE);
318 #else
319 		defval(0x13);
320 #endif
321 	case SLC_XOFF:
322 #ifdef	VSTOP
323 		setval(VSTOP, SLC_VARIABLE);
324 #else
325 		defval(0x11);
326 #endif
327 	case SLC_EW:
328 #ifdef	VWERASE
329 		setval(VWERASE, SLC_VARIABLE);
330 #else
331 		defval(0);
332 #endif
333 	case SLC_RP:
334 #ifdef	VREPRINT
335 		setval(VREPRINT, SLC_VARIABLE);
336 #else
337 		defval(0);
338 #endif
339 	case SLC_LNEXT:
340 #ifdef	VLNEXT
341 		setval(VLNEXT, SLC_VARIABLE);
342 #else
343 		defval(0);
344 #endif
345 	case SLC_AO:
346 #if	!defined(VDISCARD) && defined(VFLUSHO)
347 # define VDISCARD VFLUSHO
348 #endif
349 #ifdef	VDISCARD
350 		setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT);
351 #else
352 		defval(0);
353 #endif
354 	case SLC_SUSP:
355 #ifdef	VSUSP
356 		setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN);
357 #else
358 		defval(0);
359 #endif
360 #ifdef	VEOL
361 	case SLC_FORW1:
362 		setval(VEOL, SLC_VARIABLE);
363 #endif
364 #ifdef	VEOL2
365 	case SLC_FORW2:
366 		setval(VEOL2, SLC_VARIABLE);
367 #endif
368 	case SLC_AYT:
369 #ifdef	VSTATUS
370 		setval(VSTATUS, SLC_VARIABLE);
371 #else
372 		defval(0);
373 #endif
374 
375 	case SLC_BRK:
376 	case SLC_SYNCH:
377 	case SLC_EOR:
378 		defval(0);
379 
380 	default:
381 		*valp = 0;
382 		*valpp = 0;
383 		return(SLC_NOSUPPORT);
384 	}
385 }
386 #endif	/* USE_TERMIO */
387 
388 #ifdef CRAY
389 /*
390  * getnpty()
391  *
392  * Return the number of pty's configured into the system.
393  */
394 	int
395 getnpty()
396 {
397 #ifdef _SC_CRAY_NPTY
398 	int numptys;
399 
400 	if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1)
401 		return numptys;
402 	else
403 #endif /* _SC_CRAY_NPTY */
404 		return 128;
405 }
406 #endif /* CRAY */
407 
408 #ifndef	convex
409 /*
410  * getpty()
411  *
412  * Allocate a pty.  As a side effect, the external character
413  * array "line" contains the name of the slave side.
414  *
415  * Returns the file descriptor of the opened pty.
416  */
417 #ifndef	__GNUC__
418 char *line = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
419 #else
420 static char Xline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
421 char *line = Xline;
422 #endif
423 #ifdef	CRAY
424 char *myline = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
425 #endif	/* CRAY */
426 
427 	int
428 getpty()
429 {
430 	register int p;
431 #ifndef CRAY
432 	register char c, *p1, *p2;
433 	register int i;
434 
435 	(void) sprintf(line, "/dev/ptyXX");
436 	p1 = &line[8];
437 	p2 = &line[9];
438 
439 	for (c = 'p'; c <= 's'; c++) {
440 		struct stat stb;
441 
442 		*p1 = c;
443 		*p2 = '0';
444 		if (stat(line, &stb) < 0)
445 			break;
446 		for (i = 0; i < 16; i++) {
447 			*p2 = "0123456789abcdef"[i];
448 			p = open(line, 2);
449 			if (p > 0) {
450 				line[5] = 't';
451 				return(p);
452 			}
453 		}
454 	}
455 #else	/* CRAY */
456 	register int npty;
457 	extern lowpty, highpty;
458 	struct stat sb;
459 
460 	for (npty = lowpty; npty <= highpty; npty++) {
461 		(void) sprintf(myline, "/dev/pty/%03d", npty);
462 		p = open(myline, 2);
463 		if (p < 0)
464 			continue;
465 		(void) sprintf(line, "/dev/ttyp%03d", npty);
466 		/*
467 		 * Here are some shenanigans to make sure that there
468 		 * are no listeners lurking on the line.
469 		 */
470 		if(stat(line, &sb) < 0) {
471 			(void) close(p);
472 			continue;
473 		}
474 		if(sb.st_uid || sb.st_gid || sb.st_mode != 0600) {
475 			chown(line, 0, 0);
476 			chmod(line, 0600);
477 			(void)close(p);
478 			p = open(myline, 2);
479 			if (p < 0)
480 				continue;
481 		}
482 		/*
483 		 * Now it should be safe...check for accessability.
484 		 */
485 		if (access(line, 6) == 0)
486 			return(p);
487 		else {
488 			/* no tty side to pty so skip it */
489 			(void) close(p);
490 		}
491 	}
492 #endif	/* CRAY */
493 	return(-1);
494 }
495 #endif	/* convex */
496 
497 #ifdef	LINEMODE
498 /*
499  * tty_flowmode()	Find out if flow control is enabled or disabled.
500  * tty_linemode()	Find out if linemode (external processing) is enabled.
501  * tty_setlinemod(on)	Turn on/off linemode.
502  * tty_isecho()		Find out if echoing is turned on.
503  * tty_setecho(on)	Enable/disable character echoing.
504  * tty_israw()		Find out if terminal is in RAW mode.
505  * tty_binaryin(on)	Turn on/off BINARY on input.
506  * tty_binaryout(on)	Turn on/off BINARY on output.
507  * tty_isediting()	Find out if line editing is enabled.
508  * tty_istrapsig()	Find out if signal trapping is enabled.
509  * tty_setedit(on)	Turn on/off line editing.
510  * tty_setsig(on)	Turn on/off signal trapping.
511  * tty_issofttab()	Find out if tab expansion is enabled.
512  * tty_setsofttab(on)	Turn on/off soft tab expansion.
513  * tty_islitecho()	Find out if typed control chars are echoed literally
514  * tty_setlitecho()	Turn on/off literal echo of control chars
515  * tty_tspeed(val)	Set transmit speed to val.
516  * tty_rspeed(val)	Set receive speed to val.
517  */
518 
519 	int
520 tty_flowmode()
521 {
522 #ifndef USE_TERMIO
523 	return(((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0) ? 1 : 0);
524 #else
525 	return(termbuf.c_iflag & IXON ? 1 : 0);
526 #endif
527 }
528 
529 #ifdef convex
530 static int linestate;
531 #endif
532 
533 	int
534 tty_linemode()
535 {
536 #ifndef convex
537 #ifndef	USE_TERMIO
538 	return(termbuf.state & TS_EXTPROC);
539 #else
540 	return(termbuf.c_lflag & EXTPROC);
541 #endif
542 #else
543 	return(linestate);
544 #endif
545 }
546 
547 	void
548 tty_setlinemode(on)
549 	int on;
550 {
551 #ifdef	TIOCEXT
552 # ifndef convex
553 	set_termbuf();
554 # else
555 	linestate = on;
556 # endif
557 	(void) ioctl(pty, TIOCEXT, (char *)&on);
558 # ifndef convex
559 	init_termbuf();
560 # endif
561 #else	/* !TIOCEXT */
562 # ifdef	EXTPROC
563 	if (on)
564 		termbuf.c_lflag |= EXTPROC;
565 	else
566 		termbuf.c_lflag &= ~EXTPROC;
567 # endif
568 #endif	/* TIOCEXT */
569 }
570 
571 	int
572 tty_isecho()
573 {
574 #ifndef USE_TERMIO
575 	return (termbuf.sg.sg_flags & ECHO);
576 #else
577 	return (termbuf.c_lflag & ECHO);
578 #endif
579 }
580 #endif	/* LINEMODE */
581 
582 	void
583 tty_setecho(on)
584 	int on;
585 {
586 #ifndef	USE_TERMIO
587 	if (on)
588 		termbuf.sg.sg_flags |= ECHO|CRMOD;
589 	else
590 		termbuf.sg.sg_flags &= ~(ECHO|CRMOD);
591 #else
592 	if (on)
593 		termbuf.c_lflag |= ECHO;
594 	else
595 		termbuf.c_lflag &= ~ECHO;
596 #endif
597 }
598 
599 #if	defined(LINEMODE) && defined(KLUDGELINEMODE)
600 	int
601 tty_israw()
602 {
603 #ifndef USE_TERMIO
604 	return(termbuf.sg.sg_flags & RAW);
605 #else
606 	return(!(termbuf.c_lflag & ICANON));
607 #endif
608 }
609 #endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
610 
611 	void
612 tty_binaryin(on)
613 	int on;
614 {
615 #ifndef	USE_TERMIO
616 	if (on)
617 		termbuf.lflags |= LPASS8;
618 	else
619 		termbuf.lflags &= ~LPASS8;
620 #else
621 	if (on) {
622 		termbuf.c_iflag &= ~ISTRIP;
623 	} else {
624 		termbuf.c_iflag |= ISTRIP;
625 	}
626 #endif
627 }
628 
629 	void
630 tty_binaryout(on)
631 	int on;
632 {
633 #ifndef	USE_TERMIO
634 	if (on)
635 		termbuf.lflags |= LLITOUT;
636 	else
637 		termbuf.lflags &= ~LLITOUT;
638 #else
639 	if (on) {
640 		termbuf.c_cflag &= ~(CSIZE|PARENB);
641 		termbuf.c_cflag |= CS8;
642 		termbuf.c_oflag &= ~OPOST;
643 	} else {
644 		termbuf.c_cflag &= ~CSIZE;
645 		termbuf.c_cflag |= CS7|PARENB;
646 		termbuf.c_oflag |= OPOST;
647 	}
648 #endif
649 }
650 
651 	int
652 tty_isbinaryin()
653 {
654 #ifndef	USE_TERMIO
655 	return(termbuf.lflags & LPASS8);
656 #else
657 	return(!(termbuf.c_iflag & ISTRIP));
658 #endif
659 }
660 
661 	int
662 tty_isbinaryout()
663 {
664 #ifndef	USE_TERMIO
665 	return(termbuf.lflags & LLITOUT);
666 #else
667 	return(!(termbuf.c_oflag&OPOST));
668 #endif
669 }
670 
671 #ifdef	LINEMODE
672 	int
673 tty_isediting()
674 {
675 #ifndef USE_TERMIO
676 	return(!(termbuf.sg.sg_flags & (CBREAK|RAW)));
677 #else
678 	return(termbuf.c_lflag & ICANON);
679 #endif
680 }
681 
682 	int
683 tty_istrapsig()
684 {
685 #ifndef USE_TERMIO
686 	return(!(termbuf.sg.sg_flags&RAW));
687 #else
688 	return(termbuf.c_lflag & ISIG);
689 #endif
690 }
691 
692 	void
693 tty_setedit(on)
694 	int on;
695 {
696 #ifndef USE_TERMIO
697 	if (on)
698 		termbuf.sg.sg_flags &= ~CBREAK;
699 	else
700 		termbuf.sg.sg_flags |= CBREAK;
701 #else
702 	if (on)
703 		termbuf.c_lflag |= ICANON;
704 	else
705 		termbuf.c_lflag &= ~ICANON;
706 #endif
707 }
708 
709 	void
710 tty_setsig(on)
711 	int on;
712 {
713 #ifndef	USE_TERMIO
714 	if (on)
715 		;
716 #else
717 	if (on)
718 		termbuf.c_lflag |= ISIG;
719 	else
720 		termbuf.c_lflag &= ~ISIG;
721 #endif
722 }
723 #endif	/* LINEMODE */
724 
725 	int
726 tty_issofttab()
727 {
728 #ifndef	USE_TERMIO
729 	return (termbuf.sg.sg_flags & XTABS);
730 #else
731 # ifdef	OXTABS
732 	return (termbuf.c_oflag & OXTABS);
733 # endif
734 # ifdef	TABDLY
735 	return ((termbuf.c_oflag & TABDLY) == TAB3);
736 # endif
737 #endif
738 }
739 
740 	void
741 tty_setsofttab(on)
742 	int on;
743 {
744 #ifndef	USE_TERMIO
745 	if (on)
746 		termbuf.sg.sg_flags |= XTABS;
747 	else
748 		termbuf.sg.sg_flags &= ~XTABS;
749 #else
750 	if (on) {
751 # ifdef	OXTABS
752 		termbuf.c_oflag |= OXTABS;
753 # endif
754 # ifdef	TABDLY
755 		termbuf.c_oflag &= ~TABDLY;
756 		termbuf.c_oflag |= TAB3;
757 # endif
758 	} else {
759 # ifdef	OXTABS
760 		termbuf.c_oflag &= ~OXTABS;
761 # endif
762 # ifdef	TABDLY
763 		termbuf.c_oflag &= ~TABDLY;
764 		termbuf.c_oflag |= TAB0;
765 # endif
766 	}
767 #endif
768 }
769 
770 	int
771 tty_islitecho()
772 {
773 #ifndef	USE_TERMIO
774 	return (!(termbuf.lflags & LCTLECH));
775 #else
776 # ifdef	ECHOCTL
777 	return (!(termbuf.c_lflag & ECHOCTL));
778 # endif
779 # ifdef	TCTLECH
780 	return (!(termbuf.c_lflag & TCTLECH));
781 # endif
782 # if	!defined(ECHOCTL) && !defined(TCTLECH)
783 	return (0);	/* assumes ctl chars are echoed '^x' */
784 # endif
785 #endif
786 }
787 
788 	void
789 tty_setlitecho(on)
790 	int on;
791 {
792 #ifndef	USE_TERMIO
793 	if (on)
794 		termbuf.lflags &= ~LCTLECH;
795 	else
796 		termbuf.lflags |= LCTLECH;
797 #else
798 # ifdef	ECHOCTL
799 	if (on)
800 		termbuf.c_lflag &= ~ECHOCTL;
801 	else
802 		termbuf.c_lflag |= ECHOCTL;
803 # endif
804 # ifdef	TCTLECH
805 	if (on)
806 		termbuf.c_lflag &= ~TCTLECH;
807 	else
808 		termbuf.c_lflag |= TCTLECH;
809 # endif
810 #endif
811 }
812 
813 	int
814 tty_iscrnl()
815 {
816 #ifndef	USE_TERMIO
817 	return (termbuf.sg.sg_flags & CRMOD);
818 #else
819 	return (termbuf.c_iflag & ICRNL);
820 #endif
821 }
822 
823 /*
824  * A table of available terminal speeds
825  */
826 struct termspeeds {
827 	int	speed;
828 	int	value;
829 } termspeeds[] = {
830 	{ 0,     B0 },    { 50,    B50 },   { 75,    B75 },
831 	{ 110,   B110 },  { 134,   B134 },  { 150,   B150 },
832 	{ 200,   B200 },  { 300,   B300 },  { 600,   B600 },
833 	{ 1200,  B1200 }, { 1800,  B1800 }, { 2400,  B2400 },
834 	{ 4800,  B4800 }, { 9600,  B9600 }, { 19200, B9600 },
835 	{ 38400, B9600 }, { -1,    B9600 }
836 };
837 
838 	void
839 tty_tspeed(val)
840 	int val;
841 {
842 	register struct termspeeds *tp;
843 
844 	for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
845 		;
846 	cfsetospeed(&termbuf, tp->value);
847 }
848 
849 	void
850 tty_rspeed(val)
851 	int val;
852 {
853 	register struct termspeeds *tp;
854 
855 	for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
856 		;
857 	cfsetispeed(&termbuf, tp->value);
858 }
859 
860 #if	defined(CRAY2) && defined(UNICOS5)
861 	int
862 tty_isnewmap()
863 {
864 	return((termbuf.c_oflag & OPOST) && (termbuf.c_oflag & ONLCR) &&
865 			!(termbuf.c_oflag & ONLRET));
866 }
867 #endif
868 
869 #ifdef	CRAY
870 # ifndef NEWINIT
871 extern	struct utmp wtmp;
872 extern char wtmpf[];
873 # else	/* NEWINIT */
874 int	gotalarm;
875 
876 	/* ARGSUSED */
877 	void
878 nologinproc(sig)
879 	int sig;
880 {
881 	gotalarm++;
882 }
883 # endif	/* NEWINIT */
884 #endif /* CRAY */
885 
886 #ifndef	NEWINIT
887 # ifdef	CRAY
888 extern void utmp_sig_init P((void));
889 extern void utmp_sig_reset P((void));
890 extern void utmp_sig_wait P((void));
891 extern void utmp_sig_notify P((int));
892 # endif
893 #endif
894 
895 /*
896  * getptyslave()
897  *
898  * Open the slave side of the pty, and do any initialization
899  * that is necessary.  The return value is a file descriptor
900  * for the slave side.
901  */
902 	int
903 getptyslave()
904 {
905 	register int t = -1;
906 
907 #if	!defined(CRAY) || !defined(NEWINIT)
908 # ifdef	LINEMODE
909 	int waslm;
910 # endif
911 # ifdef	TIOCGWINSZ
912 	struct winsize ws;
913 	extern int def_row, def_col;
914 # endif
915 	extern int def_tspeed, def_rspeed;
916 	/*
917 	 * Opening the slave side may cause initilization of the
918 	 * kernel tty structure.  We need remember the state of
919 	 * 	if linemode was turned on
920 	 *	terminal window size
921 	 *	terminal speed
922 	 * so that we can re-set them if we need to.
923 	 */
924 # ifdef	LINEMODE
925 	waslm = tty_linemode();
926 # endif
927 
928 
929 	/*
930 	 * Make sure that we don't have a controlling tty, and
931 	 * that we are the session (process group) leader.
932 	 */
933 # ifdef	TIOCNOTTY
934 	t = open(_PATH_TTY, O_RDWR);
935 	if (t >= 0) {
936 		(void) ioctl(t, TIOCNOTTY, (char *)0);
937 		(void) close(t);
938 	}
939 # endif
940 
941 
942 # ifdef	CRAY
943 	/*
944 	 * Wait for our parent to get the utmp stuff to get done.
945 	 */
946 	utmp_sig_wait();
947 # endif
948 
949 	t = cleanopen(line);
950 	if (t < 0)
951 		fatalperror(net, line);
952 
953 	/*
954 	 * set up the tty modes as we like them to be.
955 	 */
956 	init_termbuf();
957 # ifdef	TIOCGWINSZ
958 	if (def_row || def_col) {
959 		bzero((char *)&ws, sizeof(ws));
960 		ws.ws_col = def_col;
961 		ws.ws_row = def_row;
962 		(void)ioctl(t, TIOCSWINSZ, (char *)&ws);
963 	}
964 # endif
965 
966 	/*
967 	 * Settings for sgtty based systems
968 	 */
969 # ifndef	USE_TERMIO
970 	termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS;
971 # endif	/* USE_TERMIO */
972 
973 	/*
974 	 * Settings for UNICOS
975 	 */
976 # ifdef	CRAY
977 	termbuf.c_oflag = OPOST|ONLCR|TAB3;
978 	termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
979 	termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
980 	termbuf.c_cflag = EXTB|HUPCL|CS8;
981 # endif
982 
983 	/*
984 	 * Settings for all other termios/termio based
985 	 * systems, other than 4.4BSD.  In 4.4BSD the
986 	 * kernel does the initial terminal setup.
987 	 */
988 # if defined(USE_TERMIO) && !defined(CRAY) && (BSD <= 43)
989 #  ifndef	OXTABS
990 #   define OXTABS	0
991 #  endif
992 	termbuf.c_lflag |= ECHO;
993 	termbuf.c_oflag |= ONLCR|OXTABS;
994 	termbuf.c_iflag |= ICRNL;
995 	termbuf.c_iflag &= ~IXOFF;
996 # endif /* defined(USE_TERMIO) && !defined(CRAY) && (BSD <= 43) */
997 	tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);
998 	tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);
999 # ifdef	LINEMODE
1000 	if (waslm)
1001 		tty_setlinemode(1);
1002 # endif	/* LINEMODE */
1003 
1004 	/*
1005 	 * Set the tty modes, and make this our controlling tty.
1006 	 */
1007 	set_termbuf();
1008 	if (login_tty(t) == -1)
1009 		fatalperror(net, "login_tty");
1010 #endif	/* !defined(CRAY) || !defined(NEWINIT) */
1011 	if (net > 2)
1012 		(void) close(net);
1013 	if (pty > 2)
1014 		(void) close(pty);
1015 }
1016 
1017 #if	!defined(CRAY) || !defined(NEWINIT)
1018 #ifndef	O_NOCTTY
1019 #define	O_NOCTTY	0
1020 #endif
1021 /*
1022  * Open the specified slave side of the pty,
1023  * making sure that we have a clean tty.
1024  */
1025 	int
1026 cleanopen(line)
1027 	char *line;
1028 {
1029 	register int t;
1030 
1031 	/*
1032 	 * Make sure that other people can't open the
1033 	 * slave side of the connection.
1034 	 */
1035 	(void) chown(line, 0, 0);
1036 	(void) chmod(line, 0600);
1037 
1038 # if !defined(CRAY) && (BSD > 43)
1039 	(void) revoke(line);
1040 # endif
1041 	t = open(line, O_RDWR|O_NOCTTY);
1042 	if (t < 0)
1043 		return(-1);
1044 
1045 	/*
1046 	 * Hangup anybody else using this ttyp, then reopen it for
1047 	 * ourselves.
1048 	 */
1049 # if !defined(CRAY) && (BSD <= 43)
1050 	(void) signal(SIGHUP, SIG_IGN);
1051 	vhangup();
1052 	(void) signal(SIGHUP, SIG_DFL);
1053 	t = open(line, O_RDWR|O_NOCTTY);
1054 	if (t < 0)
1055 		return(-1);
1056 # endif
1057 # if	defined(CRAY) && defined(TCVHUP)
1058 	{
1059 		register int i;
1060 		(void) signal(SIGHUP, SIG_IGN);
1061 		(void) ioctl(t, TCVHUP, (char *)0);
1062 		(void) signal(SIGHUP, SIG_DFL);
1063 		setpgrp();
1064 		i = open(line, O_RDWR);
1065 		if (i < 0)
1066 			return(-1);
1067 		(void) close(t);
1068 		t = i;
1069 	}
1070 # endif	/* defined(CRAY) && defined(TCVHUP) */
1071 	return(t);
1072 }
1073 #endif	/* !defined(CRAY) || !defined(NEWINIT) */
1074 
1075 #if BSD <= 43
1076 	int
1077 login_tty(t)
1078 	int t;
1079 {
1080 	if (setsid() < 0)
1081 		fatalperror(net, "setsid()");
1082 # ifdef	TIOCSCTTY
1083 	if (ioctl(t, TIOCSCTTY, (char *)0) < 0)
1084 		fatalperror(net, "ioctl(sctty)");
1085 #  if defined(CRAY) && defined(SESS_CTTY)	/* SESS_CTTY is in param.h */
1086 	/*
1087 	 * Close the hard fd to /dev/ttypXXX, and re-open through
1088 	 * the indirect /dev/tty interface.
1089 	 */
1090 	close(t);
1091 	if ((t = open("/dev/tty", O_RDWR)) < 0)
1092 		fatalperror(net, "open(/dev/tty)");
1093 #  endif
1094 # else
1095 	close(open(line, O_RDWR));
1096 # endif
1097 	if (t != 0)
1098 		(void) dup2(t, 0);
1099 	if (t != 1)
1100 		(void) dup2(t, 1);
1101 	if (t != 2)
1102 		(void) dup2(t, 2);
1103 	if (t > 2)
1104 		close(t);
1105 	return(0);
1106 }
1107 #endif	/* BSD <= 43 */
1108 
1109 #ifdef	NEWINIT
1110 char *gen_id = "fe";
1111 #endif
1112 
1113 /*
1114  * startslave(host)
1115  *
1116  * Given a hostname, do whatever
1117  * is necessary to startup the login process on the slave side of the pty.
1118  */
1119 
1120 /* ARGSUSED */
1121 	void
1122 startslave(host, autologin, autoname)
1123 	char *host;
1124 	int autologin;
1125 	char *autoname;
1126 {
1127 	register int i;
1128 	long time();
1129 	char name[256];
1130 #ifdef	NEWINIT
1131 	extern char *ptyip;
1132 	struct init_request request;
1133 	void nologinproc();
1134 	register int n;
1135 #endif	/* NEWINIT */
1136 
1137 #if	defined(AUTHENTICATE)
1138 	if (!autoname || !autoname[0])
1139 		autologin = 0;
1140 
1141 	if (autologin < auth_level) {
1142 		fatal(net, "Authorization failed");
1143 		exit(1);
1144 	}
1145 #endif
1146 
1147 #ifndef	NEWINIT
1148 # ifdef	CRAY
1149 	utmp_sig_init();
1150 # endif	/* CRAY */
1151 
1152 	if ((i = fork()) < 0)
1153 		fatalperror(net, "fork");
1154 	if (i) {
1155 # ifdef	CRAY
1156 		/*
1157 		 * Cray parent will create utmp entry for child and send
1158 		 * signal to child to tell when done.  Child waits for signal
1159 		 * before doing anything important.
1160 		 */
1161 		register int pid = i;
1162 		void sigjob P((int));
1163 
1164 		setpgrp();
1165 		utmp_sig_reset();		/* reset handler to default */
1166 		/*
1167 		 * Create utmp entry for child
1168 		 */
1169 		(void) time(&wtmp.ut_time);
1170 		wtmp.ut_type = LOGIN_PROCESS;
1171 		wtmp.ut_pid = pid;
1172 		SCPYN(wtmp.ut_user, "LOGIN");
1173 		SCPYN(wtmp.ut_host, host);
1174 		SCPYN(wtmp.ut_line, line + sizeof("/dev/") - 1);
1175 		SCPYN(wtmp.ut_id, wtmp.ut_line+3);
1176 		pututline(&wtmp);
1177 		endutent();
1178 		if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) {
1179 			(void) write(i, (char *)&wtmp, sizeof(struct utmp));
1180 			(void) close(i);
1181 		}
1182 		(void) signal(WJSIGNAL, sigjob);
1183 		utmp_sig_notify(pid);
1184 # endif	/* CRAY */
1185 	} else {
1186 		getptyslave();
1187 		start_login(host, autologin, autoname);
1188 		/*NOTREACHED*/
1189 	}
1190 #else	/* NEWINIT */
1191 
1192 	/*
1193 	 * Init will start up login process if we ask nicely.  We only wait
1194 	 * for it to start up and begin normal telnet operation.
1195 	 */
1196 	if ((i = open(INIT_FIFO, O_WRONLY)) < 0) {
1197 		char tbuf[128];
1198 		(void) sprintf(tbuf, "Can't open %s\n", INIT_FIFO);
1199 		fatalperror(net, tbuf);
1200 	}
1201 	memset((char *)&request, 0, sizeof(request));
1202 	request.magic = INIT_MAGIC;
1203 	SCPYN(request.gen_id, gen_id);
1204 	SCPYN(request.tty_id, &line[8]);
1205 	SCPYN(request.host, host);
1206 	SCPYN(request.term_type, terminaltype ? terminaltype : "network");
1207 #if	!defined(UNICOS5)
1208 	request.signal = SIGCLD;
1209 	request.pid = getpid();
1210 #endif
1211 #ifdef BFTPDAEMON
1212 	/*
1213 	 * Are we working as the bftp daemon?
1214 	 */
1215 	if (bftpd) {
1216 		SCPYN(request.exec_name, BFTPPATH);
1217 	}
1218 #endif /* BFTPDAEMON */
1219 	if (write(i, (char *)&request, sizeof(request)) < 0) {
1220 		char tbuf[128];
1221 		(void) sprintf(tbuf, "Can't write to %s\n", INIT_FIFO);
1222 		fatalperror(net, tbuf);
1223 	}
1224 	(void) close(i);
1225 	(void) signal(SIGALRM, nologinproc);
1226 	for (i = 0; ; i++) {
1227 		char tbuf[128];
1228 		alarm(15);
1229 		n = read(pty, ptyip, BUFSIZ);
1230 		if (i == 3 || n >= 0 || !gotalarm)
1231 			break;
1232 		gotalarm = 0;
1233 		sprintf(tbuf, "telnetd: waiting for /etc/init to start login process on %s\r\n", line);
1234 		(void) write(net, tbuf, strlen(tbuf));
1235 	}
1236 	if (n < 0 && gotalarm)
1237 		fatal(net, "/etc/init didn't start login process");
1238 	pcc += n;
1239 	alarm(0);
1240 	(void) signal(SIGALRM, SIG_DFL);
1241 
1242 	return;
1243 #endif	/* NEWINIT */
1244 }
1245 
1246 char	*envinit[3];
1247 extern char **environ;
1248 
1249 	void
1250 init_env()
1251 {
1252 	extern char *getenv();
1253 	char **envp;
1254 
1255 	envp = envinit;
1256 	if (*envp = getenv("TZ"))
1257 		*envp++ -= 3;
1258 #ifdef	CRAY
1259 	else
1260 		*envp++ = "TZ=GMT0";
1261 #endif
1262 	*envp = 0;
1263 	environ = envinit;
1264 }
1265 
1266 #ifndef	NEWINIT
1267 
1268 /*
1269  * start_login(host)
1270  *
1271  * Assuming that we are now running as a child processes, this
1272  * function will turn us into the login process.
1273  */
1274 
1275 	void
1276 start_login(host, autologin, name)
1277 	char *host;
1278 	int autologin;
1279 	char *name;
1280 {
1281 	register char *cp;
1282 	register char **argv;
1283 	char **addarg();
1284 
1285 	/*
1286 	 * -h : pass on name of host.
1287 	 *		WARNING:  -h is accepted by login if and only if
1288 	 *			getuid() == 0.
1289 	 * -p : don't clobber the environment (so terminal type stays set).
1290 	 *
1291 	 * -f : force this login, he has already been authenticated
1292 	 */
1293 	argv = addarg(0, "login");
1294 	argv = addarg(argv, "-h");
1295 	argv = addarg(argv, host);
1296 #if	!defined(NO_LOGIN_P)
1297 	argv = addarg(argv, "-p");
1298 #endif
1299 #ifdef	BFTPDAEMON
1300 	/*
1301 	 * Are we working as the bftp daemon?  If so, then ask login
1302 	 * to start bftp instead of shell.
1303 	 */
1304 	if (bftpd) {
1305 		argv = addarg(argv, "-e");
1306 		argv = addarg(argv, BFTPPATH);
1307 	} else
1308 #endif
1309 #if	defined (SecurID)
1310 	/*
1311 	 * don't worry about the -f that might get sent.
1312 	 * A -s is supposed to override it anyhow.
1313 	 */
1314 	if (require_SecurID)
1315 		argv = addarg(argv, "-s");
1316 #endif
1317 #if	defined (AUTHENTICATE)
1318 	if (auth_level >= 0 && autologin == AUTH_VALID) {
1319 # if	!defined(NO_LOGIN_F)
1320 		argv = addarg(argv, "-f");
1321 # endif
1322 		argv = addarg(argv, name);
1323 	} else
1324 #endif
1325 	if (getenv("USER")) {
1326 		argv = addarg(argv, getenv("USER"));
1327 #if	defined(CRAY) && defined(NO_LOGIN_P)
1328 		{
1329 			register char **cpp;
1330 			for (cpp = environ; *cpp; cpp++)
1331 				argv = addarg(argv, *cpp);
1332 		}
1333 #endif
1334 	}
1335 	closelog();
1336 	execv(_PATH_LOGIN, argv);
1337 
1338 	syslog(LOG_ERR, "%s: %m\n", _PATH_LOGIN);
1339 	fatalperror(net, _PATH_LOGIN);
1340 	/*NOTREACHED*/
1341 }
1342 
1343 	char **
1344 addarg(argv, val)
1345 	register char **argv;
1346 	register char *val;
1347 {
1348 	register char **cpp;
1349 
1350 	if (argv == NULL) {
1351 		/*
1352 		 * 10 entries, a leading length, and a null
1353 		 */
1354 		argv = (char **)malloc(sizeof(*argv) * 12);
1355 		if (argv == NULL)
1356 			return(NULL);
1357 		*argv++ = (char *)10;
1358 		*argv = (char *)0;
1359 	}
1360 	for (cpp = argv; *cpp; cpp++)
1361 		;
1362 	if (cpp == &argv[(int)argv[-1]]) {
1363 		--argv;
1364 		*argv = (char *)((int)(*argv) + 10);
1365 		argv = (char **)realloc(argv, (int)(*argv) + 2);
1366 		if (argv == NULL)
1367 			return(NULL);
1368 		argv++;
1369 		cpp = &argv[(int)argv[-1] - 10];
1370 	}
1371 	*cpp++ = val;
1372 	*cpp = 0;
1373 	return(argv);
1374 }
1375 #endif	/* NEWINIT */
1376 
1377 /*
1378  * cleanup()
1379  *
1380  * This is the routine to call when we are all through, to
1381  * clean up anything that needs to be cleaned up.
1382  */
1383 	/* ARGSUSED */
1384 	void
1385 cleanup(sig)
1386 	int sig;
1387 {
1388 #ifndef	CRAY
1389 # if (BSD > 43) || defined(convex)
1390 	char *p;
1391 
1392 	p = line + sizeof("/dev/") - 1;
1393 	if (logout(p))
1394 		logwtmp(p, "", "");
1395 	(void)chmod(line, 0666);
1396 	(void)chown(line, 0, 0);
1397 	*p = 'p';
1398 	(void)chmod(line, 0666);
1399 	(void)chown(line, 0, 0);
1400 	(void) shutdown(net, 2);
1401 	exit(1);
1402 # else
1403 	void rmut();
1404 
1405 	rmut();
1406 	vhangup();	/* XXX */
1407 	(void) shutdown(net, 2);
1408 	exit(1);
1409 # endif
1410 #else	/* CRAY */
1411 # ifdef	NEWINIT
1412 	(void) shutdown(net, 2);
1413 	exit(1);
1414 # else	/* NEWINIT */
1415 	static int incleanup = 0;
1416 	register int t;
1417 
1418 	/*
1419 	 * 1: Pick up the zombie, if we are being called
1420 	 *    as the signal handler.
1421 	 * 2: If we are a nested cleanup(), return.
1422 	 * 3: Try to clean up TMPDIR.
1423 	 * 4: Fill in utmp with shutdown of process.
1424 	 * 5: Close down the network and pty connections.
1425 	 * 6: Finish up the TMPDIR cleanup, if needed.
1426 	 */
1427 	if (sig == SIGCHLD)
1428 		while (waitpid(-1, 0, WNOHANG) > 0)
1429 			;	/* VOID */
1430 	t = sigblock(sigmask(SIGCHLD));
1431 	if (incleanup) {
1432 		sigsetmask(t);
1433 		return;
1434 	}
1435 	incleanup = 1;
1436 	sigsetmask(t);
1437 
1438 	t = cleantmp(&wtmp);
1439 	setutent();	/* just to make sure */
1440 	rmut(line);
1441 	close(pty);
1442 	(void) shutdown(net, 2);
1443 	if (t == 0)
1444 		cleantmp(&wtmp);
1445 	exit(1);
1446 # endif	/* NEWINT */
1447 #endif	/* CRAY */
1448 }
1449 
1450 #if	defined(CRAY) && !defined(NEWINIT)
1451 /*
1452  * _utmp_sig_rcv
1453  * utmp_sig_init
1454  * utmp_sig_wait
1455  *	These three functions are used to coordinate the handling of
1456  *	the utmp file between the server and the soon-to-be-login shell.
1457  *	The server actually creates the utmp structure, the child calls
1458  *	utmp_sig_wait(), until the server calls utmp_sig_notify() and
1459  *	signals the future-login shell to proceed.
1460  */
1461 static int caught=0;		/* NZ when signal intercepted */
1462 static void (*func)();		/* address of previous handler */
1463 
1464 	void
1465 _utmp_sig_rcv(sig)
1466 	int sig;
1467 {
1468 	caught = 1;
1469 	(void) signal(SIGUSR1, func);
1470 }
1471 
1472 	void
1473 utmp_sig_init()
1474 {
1475 	/*
1476 	 * register signal handler for UTMP creation
1477 	 */
1478 	if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1)
1479 		fatalperror(net, "telnetd/signal");
1480 }
1481 
1482 	void
1483 utmp_sig_reset()
1484 {
1485 	(void) signal(SIGUSR1, func);	/* reset handler to default */
1486 }
1487 
1488 	void
1489 utmp_sig_wait()
1490 {
1491 	/*
1492 	 * Wait for parent to write our utmp entry.
1493 	 */
1494 	sigoff();
1495 	while (caught == 0) {
1496 		pause();	/* wait until we get a signal (sigon) */
1497 		sigoff();	/* turn off signals while we check caught */
1498 	}
1499 	sigon();		/* turn on signals again */
1500 }
1501 
1502 	void
1503 utmp_sig_notify(pid)
1504 {
1505 	kill(pid, SIGUSR1);
1506 }
1507 
1508 static int gotsigjob = 0;
1509 
1510 	/*ARGSUSED*/
1511 	void
1512 sigjob(sig)
1513 	int sig;
1514 {
1515 	register int jid;
1516 	register struct jobtemp *jp;
1517 
1518 	while ((jid = waitjob(NULL)) != -1) {
1519 		if (jid == 0) {
1520 			return;
1521 		}
1522 		gotsigjob++;
1523 		jobend(jid, NULL, NULL);
1524 	}
1525 }
1526 
1527 /*
1528  * Clean up the TMPDIR that login created.
1529  * The first time this is called we pick up the info
1530  * from the utmp.  If the job has already gone away,
1531  * then we'll clean up and be done.  If not, then
1532  * when this is called the second time it will wait
1533  * for the signal that the job is done.
1534  */
1535 	int
1536 cleantmp(wtp)
1537 	register struct utmp *wtp;
1538 {
1539 	struct utmp *utp;
1540 	static int first = 1;
1541 	register int mask, omask, ret;
1542 	extern struct utmp *getutid P((struct utmp *));
1543 
1544 	mask = sigmask(WJSIGNAL);
1545 
1546 	if (first == 0) {
1547 		omask = sigblock(mask);
1548 		while (gotsigjob == 0)
1549 			sigpause(omask);
1550 		return(1);
1551 	}
1552 	first = 0;
1553 	setutent();	/* just to make sure */
1554 
1555 	utp = getutid(wtp);
1556 	if (utp == 0) {
1557 		syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
1558 		return(-1);
1559 	}
1560 	/*
1561 	 * Nothing to clean up if the user shell was never started.
1562 	 */
1563 	if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0)
1564 		return(1);
1565 
1566 	/*
1567 	 * Block the WJSIGNAL while we are in jobend().
1568 	 */
1569 	omask = sigblock(mask);
1570 	ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user);
1571 	sigsetmask(omask);
1572 	return(ret);
1573 }
1574 
1575 	int
1576 jobend(jid, path, user)
1577 	register int jid;
1578 	register char *path;
1579 	register char *user;
1580 {
1581 	static int saved_jid = 0;
1582 	static char saved_path[sizeof(wtmp.ut_tpath)+1];
1583 	static char saved_user[sizeof(wtmp.ut_user)+1];
1584 
1585 	if (path) {
1586 		strncpy(saved_path, path, sizeof(wtmp.ut_tpath));
1587 		strncpy(saved_user, user, sizeof(wtmp.ut_user));
1588 		saved_path[sizeof(saved_path)] = '\0';
1589 		saved_user[sizeof(saved_user)] = '\0';
1590 	}
1591 	if (saved_jid == 0) {
1592 		saved_jid = jid;
1593 		return(0);
1594 	}
1595 	cleantmpdir(jid, saved_path, saved_user);
1596 	return(1);
1597 }
1598 
1599 /*
1600  * Fork a child process to clean up the TMPDIR
1601  */
1602 cleantmpdir(jid, tpath, user)
1603 	register int jid;
1604 	register char *tpath;
1605 	register char *user;
1606 {
1607 	switch(fork()) {
1608 	case -1:
1609 		syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m\n",
1610 							tpath);
1611 		break;
1612 	case 0:
1613 		execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, 0);
1614 		syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m\n",
1615 							tpath, CLEANTMPCMD);
1616 		exit(1);
1617 	default:
1618 		/*
1619 		 * Forget about child.  We will exit, and
1620 		 * /etc/init will pick it up.
1621 		 */
1622 		break;
1623 	}
1624 }
1625 #endif	/* defined(CRAY) && !defined(NEWINIT) */
1626 
1627 /*
1628  * rmut()
1629  *
1630  * This is the function called by cleanup() to
1631  * remove the utmp entry for this person.
1632  */
1633 
1634 #if	!defined(CRAY) && BSD <= 43
1635 	void
1636 rmut()
1637 {
1638 	register f;
1639 	int found = 0;
1640 	struct utmp *u, *utmp;
1641 	int nutmp;
1642 	struct stat statbf;
1643 
1644 	f = open(utmpf, O_RDWR);
1645 	if (f >= 0) {
1646 		(void) fstat(f, &statbf);
1647 		utmp = (struct utmp *)malloc((unsigned)statbf.st_size);
1648 		if (!utmp)
1649 			syslog(LOG_ERR, "utmp malloc failed");
1650 		if (statbf.st_size && utmp) {
1651 			nutmp = read(f, (char *)utmp, (int)statbf.st_size);
1652 			nutmp /= sizeof(struct utmp);
1653 
1654 			for (u = utmp ; u < &utmp[nutmp] ; u++) {
1655 				if (SCMPN(u->ut_line, line+5) ||
1656 				    u->ut_name[0]==0)
1657 					continue;
1658 				(void) lseek(f, ((long)u)-((long)utmp), L_SET);
1659 				SCPYN(u->ut_name, "");
1660 				SCPYN(u->ut_host, "");
1661 				(void) time(&u->ut_time);
1662 				(void) write(f, (char *)u, sizeof(wtmp));
1663 				found++;
1664 			}
1665 		}
1666 		(void) close(f);
1667 	}
1668 	if (found) {
1669 		f = open(wtmpf, O_WRONLY|O_APPEND);
1670 		if (f >= 0) {
1671 			SCPYN(wtmp.ut_line, line+5);
1672 			SCPYN(wtmp.ut_name, "");
1673 			SCPYN(wtmp.ut_host, "");
1674 			(void) time(&wtmp.ut_time);
1675 			(void) write(f, (char *)&wtmp, sizeof(wtmp));
1676 			(void) close(f);
1677 		}
1678 	}
1679 	(void) chmod(line, 0666);
1680 	(void) chown(line, 0, 0);
1681 	line[strlen("/dev/")] = 'p';
1682 	(void) chmod(line, 0666);
1683 	(void) chown(line, 0, 0);
1684 }  /* end of rmut */
1685 #endif	/* CRAY */
1686