xref: /csrg-svn/libexec/telnetd/sys_term.c (revision 39974)
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 are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 static char sccsid[] = "@(#)sys_term.c	5.4 (Berkeley) 02/01/90";
20 #endif /* not lint */
21 
22 #include "telnetd.h"
23 #include "pathnames.h"
24 
25 #ifdef	NEWINIT
26 #include <initreq.h>
27 #else	/* NEWINIT*/
28 #include <utmp.h>
29 struct	utmp wtmp;
30 
31 # ifndef CRAY
32 char	wtmpf[]	= "/usr/adm/wtmp";
33 char	utmpf[] = "/etc/utmp";
34 # else	/* CRAY */
35 char	wtmpf[]	= "/etc/wtmp";
36 # endif	/* CRAY */
37 #endif	/* NEWINIT */
38 
39 #define SCPYN(a, b)	(void) strncpy(a, b, sizeof(a))
40 #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
41 
42 #include <sys/tty.h>
43 #ifdef	t_erase
44 #undef	t_erase
45 #undef	t_kill
46 #undef	t_intrc
47 #undef	t_quitc
48 #undef	t_startc
49 #undef	t_stopc
50 #undef	t_eofc
51 #undef	t_brkc
52 #undef	t_suspc
53 #undef	t_dsuspc
54 #undef	t_rprntc
55 #undef	t_flushc
56 #undef	t_werasc
57 #undef	t_lnextc
58 #endif
59 
60 #ifndef	USE_TERMIO
61 struct termbuf {
62 	struct sgttyb sg;
63 	struct tchars tc;
64 	struct ltchars ltc;
65 	int state;
66 	int lflags;
67 } termbuf, termbuf2;
68 #else	/* USE_TERMIO */
69 # ifndef EXTPROC
70 # define EXTPROC 0400
71 # endif
72 # ifdef	SYSV_TERMIO
73 #	define termios termio
74 # endif
75 # ifndef TCSETA
76 # define TCSETA TIOCSETA
77 # define TCGETA TIOCGETA
78 # endif /* 4.4BSD */
79 struct termios termbuf, termbuf2;	/* pty control structure */
80 #endif	/* USE_TERMIO */
81 
82 /*
83  * init_termbuf()
84  * copy_termbuf(cp)
85  * set_termbuf()
86  *
87  * These three routines are used to get and set the "termbuf" structure
88  * to and from the kernel.  init_termbuf() gets the current settings.
89  * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
90  * set_termbuf() writes the structure into the kernel.
91  */
92 
93 init_termbuf()
94 {
95 #ifndef	USE_TERMIO
96 	(void) ioctl(pty, TIOCGETP, (char *)&termbuf.sg);
97 	(void) ioctl(pty, TIOCGETC, (char *)&termbuf.tc);
98 	(void) ioctl(pty, TIOCGLTC, (char *)&termbuf.ltc);
99 # ifdef	TIOCGSTATE
100 	(void) ioctl(pty, TIOCGSTATE, (char *)&termbuf.state);
101 # endif
102 #else
103 	(void) ioctl(pty, TCGETA, (char *)&termbuf);
104 #endif
105 	termbuf2 = termbuf;
106 }
107 
108 #if	defined(LINEMODE) && defined(TIOCPKT_IOCTL)
109 copy_termbuf(cp, len)
110 char *cp;
111 int len;
112 {
113 	if (len > sizeof(termbuf))
114 		len = sizeof(termbuf);
115 	bcopy(cp, (char *)&termbuf, len);
116 	termbuf2 = termbuf;
117 }
118 #endif	/* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */
119 
120 set_termbuf()
121 {
122 	/*
123 	 * Only make the necessary changes.
124 	 */
125 #ifndef	USE_TERMIO
126 	if (bcmp((char *)&termbuf.sg, (char *)&termbuf2.sg, sizeof(termbuf.sg)))
127 		(void) ioctl(pty, TIOCSETP, (char *)&termbuf.sg);
128 	if (bcmp((char *)&termbuf.tc, (char *)&termbuf2.tc, sizeof(termbuf.tc)))
129 		(void) ioctl(pty, TIOCSETC, (char *)&termbuf.tc);
130 	if (bcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc,
131 							sizeof(termbuf.ltc)))
132 		(void) ioctl(pty, TIOCSLTC, (char *)&termbuf.ltc);
133 	if (termbuf.lflags != termbuf2.lflags)
134 		(void) ioctl(pty, TIOCLSET, (char *)&termbuf.lflags);
135 #else	/* USE_TERMIO */
136 	if (bcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf)))
137 		(void) ioctl(pty, TCSETA, (char *)&termbuf);
138 # ifdef	CRAY2
139 	needtermstat = 1;
140 # endif
141 #endif	/* USE_TERMIO */
142 }
143 
144 
145 /*
146  * spcset(func, valp, valpp)
147  *
148  * This function takes various special characters (func), and
149  * sets *valp to the current value of that character, and
150  * *valpp to point to where in the "termbuf" structure that
151  * value is kept.
152  *
153  * It returns the SLC_ level of support for this function.
154  */
155 
156 #ifndef	USE_TERMIO
157 spcset(func, valp, valpp)
158 int func;
159 unsigned char *valp;
160 unsigned char **valpp;
161 {
162 	switch(func) {
163 	case SLC_EOF:
164 		*valp = termbuf.tc.t_eofc;
165 		*valpp = (unsigned char *)&termbuf.tc.t_eofc;
166 		return(SLC_VARIABLE);
167 	case SLC_EC:
168 		*valp = termbuf.sg.sg_erase;
169 		*valpp = (unsigned char *)&termbuf.sg.sg_erase;
170 		return(SLC_VARIABLE);
171 	case SLC_EL:
172 		*valp = termbuf.sg.sg_kill;
173 		*valpp = (unsigned char *)&termbuf.sg.sg_kill;
174 		return(SLC_VARIABLE);
175 	case SLC_IP:
176 		*valp = termbuf.tc.t_intrc;
177 		*valpp = (unsigned char *)&termbuf.tc.t_intrc;
178 		return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
179 	case SLC_ABORT:
180 		*valp = termbuf.tc.t_quitc;
181 		*valpp = (unsigned char *)&termbuf.tc.t_quitc;
182 		return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
183 	case SLC_XON:
184 		*valp = termbuf.tc.t_startc;
185 		*valpp = (unsigned char *)&termbuf.tc.t_startc;
186 		return(SLC_VARIABLE);
187 	case SLC_XOFF:
188 		*valp = termbuf.tc.t_stopc;
189 		*valpp = (unsigned char *)&termbuf.tc.t_stopc;
190 		return(SLC_VARIABLE);
191 	case SLC_AO:
192 		*valp = termbuf.ltc.t_flushc;
193 		*valpp = (unsigned char *)&termbuf.ltc.t_flushc;
194 		return(SLC_VARIABLE);
195 	case SLC_SUSP:
196 		*valp = termbuf.ltc.t_suspc;
197 		*valpp = (unsigned char *)&termbuf.ltc.t_suspc;
198 		return(SLC_VARIABLE);
199 	case SLC_EW:
200 		*valp = termbuf.ltc.t_werasc;
201 		*valpp = (unsigned char *)&termbuf.ltc.t_werasc;
202 		return(SLC_VARIABLE);
203 	case SLC_RP:
204 		*valp = termbuf.ltc.t_rprntc;
205 		*valpp = (unsigned char *)&termbuf.ltc.t_rprntc;
206 		return(SLC_VARIABLE);
207 	case SLC_LNEXT:
208 		*valp = termbuf.ltc.t_lnextc;
209 		*valpp = (unsigned char *)&termbuf.ltc.t_lnextc;
210 		return(SLC_VARIABLE);
211 	case SLC_BRK:
212 	case SLC_SYNCH:
213 	case SLC_AYT:
214 	case SLC_EOR:
215 		*valp = 0;
216 		*valpp = 0;
217 		return(SLC_DEFAULT);
218 	default:
219 		*valp = 0;
220 		*valpp = 0;
221 		return(SLC_NOSUPPORT);
222 	}
223 }
224 
225 #else	/* USE_TERMIO */
226 
227 spcset(func, valp, valpp)
228 int func;
229 unsigned char *valp;
230 unsigned char **valpp;
231 {
232 
233 #define	setval(a, b)	*valp = termbuf.c_cc[a]; \
234 			*valpp = &termbuf.c_cc[a]; \
235 			return(b);
236 #define	defval(a)	*valp = (a); *valpp = 0; return(SLC_DEFAULT);
237 
238 	switch(func) {
239 	case SLC_EOF:
240 		setval(VEOF, SLC_VARIABLE);
241 	case SLC_EC:
242 		setval(VERASE, SLC_VARIABLE);
243 	case SLC_EL:
244 		setval(VKILL, SLC_VARIABLE);
245 	case SLC_IP:
246 		setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
247 	case SLC_ABORT:
248 		setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
249 	case SLC_XON:
250 #ifdef	VSTART
251 		setval(VSTART, SLC_VARIABLE);
252 #else
253 		defval(0x13);
254 #endif
255 	case SLC_XOFF:
256 #ifdef	VSTOP
257 		setval(VSTOP, SLC_VARIABLE);
258 #else
259 		defval(0x11);
260 #endif
261 	case SLC_EW:
262 #ifdef	VWERASE
263 		setval(VWERASE, SLC_VARIABLE);
264 #else
265 		defval(0);
266 #endif
267 	case SLC_RP:
268 #ifdef	VREPRINT
269 		setval(VREPRINT, SLC_VARIABLE);
270 #else
271 		defval(0);
272 #endif
273 	case SLC_LNEXT:
274 #ifdef	VLNEXT
275 		setval(VLNEXT, SLC_VARIABLE);
276 #else
277 		defval(0);
278 #endif
279 	case SLC_AO:
280 #ifdef	VFLUSHO
281 		setval(VFLUSHO, SLC_VARIABLE|SLC_FLUSHOUT);
282 #else
283 		defval(0);
284 #endif
285 	case SLC_SUSP:
286 #ifdef	VSUSP
287 		setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN);
288 #else
289 		defval(0);
290 #endif
291 
292 	case SLC_BRK:
293 	case SLC_SYNCH:
294 	case SLC_AYT:
295 	case SLC_EOR:
296 		defval(0);
297 
298 	default:
299 		*valp = 0;
300 		*valpp = 0;
301 		return(SLC_NOSUPPORT);
302 	}
303 }
304 #endif	/* USE_TERMIO */
305 
306 /*
307  * getpty()
308  *
309  * Allocate a pty.  As a side effect, the external character
310  * array "line" contains the name of the slave side.
311  *
312  * Returns the file descriptor of the opened pty.
313  */
314 char *line = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
315 
316 getpty()
317 {
318 	register int p;
319 #ifndef CRAY
320 	register char c, *p1, *p2;
321 	register int i;
322 
323 	(void) sprintf(line, "/dev/ptyXX");
324 	p1 = &line[8];
325 	p2 = &line[9];
326 
327 	for (c = 'p'; c <= 's'; c++) {
328 		struct stat stb;
329 
330 		*p1 = c;
331 		*p2 = '0';
332 		if (stat(line, &stb) < 0)
333 			break;
334 		for (i = 0; i < 16; i++) {
335 			*p2 = "0123456789abcdef"[i];
336 			p = open(line, 2);
337 			if (p > 0) {
338 				line[5] = 't';
339 				return(p);
340 			}
341 		}
342 	}
343 #else	/* CRAY */
344 	register int npty;
345 	extern lowpty, highpty;
346 
347 	for (npty = lowpty; npty <= highpty; npty++) {
348 		(void) sprintf(line, "/dev/pty/%03d", npty);
349 		p = open(line, 2);
350 		if (p < 0)
351 			continue;
352 		(void) sprintf(line, "/dev/ttyp%03d", npty);
353 		if (access(line, 6) == 0)
354 			return(p);
355 		else {
356 			/* no tty side to pty so skip it */
357 			(void) close(p);
358 		}
359 	}
360 #endif	/* CRAY */
361 	return(-1);
362 }
363 
364 #ifdef	LINEMODE
365 /*
366  * tty_flowmode()	Find out if flow control is enabled or disabled.
367  * tty_linemode()	Find out if linemode (external processing) is enabled.
368  * tty_setlinemod(on)	Turn on/off linemode.
369  * tty_isecho()		Find out if echoing is turned on.
370  * tty_setecho(on)	Enable/disable character echoing.
371  * tty_israw()		Find out if terminal is in RAW mode.
372  * tty_binaryin(on)	Turn on/off BINARY on input.
373  * tty_binaryout(on)	Turn on/off BINARY on output.
374  * tty_isediting()	Find out if line editing is enabled.
375  * tty_istrapsig()	Find out if signal trapping is enabled.
376  * tty_setedit(on)	Turn on/off line editing.
377  * tty_setsig(on)	Turn on/off signal trapping.
378  * tty_tspeed(val)	Set transmit speed to val.
379  * tty_rspeed(val)	Set receive speed to val.
380  */
381 
382 tty_flowmode()
383 {
384 #ifndef USE_TERMIO
385 	return((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0);
386 #else
387 	return(termbuf.c_iflag & IXON ? 1 : 0);
388 #endif
389 }
390 
391 tty_linemode()
392 {
393 #ifndef	USE_TERMIO
394 	return(termbuf.state & TS_EXTPROC);
395 #else
396 	return(termbuf.c_lflag & EXTPROC);
397 #endif
398 }
399 
400 tty_setlinemode(on)
401 int on;
402 {
403 #ifdef	TIOCEXT
404 	(void) ioctl(pty, TIOCEXT, (char *)&on);
405 #else	/* !TIOCEXT */
406 #ifdef	EXTPROC
407 	if (on)
408 		termbuf.c_lflag |= EXTPROC;
409 	else
410 		termbuf.c_lflag &= ~EXTPROC;
411 #endif
412 	set_termbuf();
413 #endif	/* TIOCEXT */
414 }
415 
416 tty_isecho()
417 {
418 #ifndef USE_TERMIO
419 	return (termbuf.sg.sg_flags & ECHO);
420 #else
421 	return (termbuf.c_lflag & ECHO);
422 #endif
423 }
424 #endif	/* LINEMODE */
425 
426 tty_setecho(on)
427 {
428 #ifndef	USE_TERMIO
429 	if (on)
430 		termbuf.sg.sg_flags |= ECHO|CRMOD;
431 	else
432 		termbuf.sg.sg_flags &= ~(ECHO|CRMOD);
433 #else
434 	if (on)
435 		termbuf.c_lflag |= ECHO;
436 	else
437 		termbuf.c_lflag &= ~ECHO;
438 #endif
439 }
440 
441 #if	defined(LINEMODE) && defined(KLUDGELINEMODE)
442 tty_israw()
443 {
444 #ifndef USE_TERMIO
445 	return(termbuf.sg.sg_flags & RAW);
446 #else
447 	return(!(termbuf.c_lflag & ICANON));
448 #endif
449 }
450 #endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
451 
452 tty_binaryin(on)
453 {
454 #ifndef	USE_TERMIO
455 	if (on)
456 		termbuf.lflags |= LPASS8;
457 	else
458 		termbuf.lflags &= ~LPASS8;
459 #else
460 	if (on) {
461 		termbuf.c_lflag &= ~ISTRIP;
462 	} else {
463 		termbuf.c_lflag |= ISTRIP;
464 	}
465 #endif
466 }
467 
468 tty_binaryout(on)
469 {
470 #ifndef	USE_TERMIO
471 	if (on)
472 		termbuf.lflags |= LLITOUT;
473 	else
474 		termbuf.lflags &= ~LLITOUT;
475 #else
476 	if (on) {
477 		termbuf.c_cflag &= ~(CSIZE|PARENB);
478 		termbuf.c_cflag |= CS8;
479 		termbuf.c_oflag &= ~OPOST;
480 	} else {
481 		termbuf.c_cflag &= ~CSIZE;
482 		termbuf.c_cflag |= CS7|PARENB;
483 		termbuf.c_oflag |= OPOST;
484 	}
485 #endif
486 }
487 
488 tty_isbinaryin()
489 {
490 #ifndef	USE_TERMIO
491 	return(termbuf.lflags & LPASS8);
492 #else
493 	return(!(termbuf.c_iflag & ISTRIP));
494 #endif
495 }
496 
497 tty_isbinaryout()
498 {
499 #ifndef	USE_TERMIO
500 	return(termbuf.lflags & LLITOUT);
501 #else
502 	return(!(termbuf.c_oflag&OPOST));
503 #endif
504 }
505 
506 #ifdef	LINEMODE
507 tty_isediting()
508 {
509 #ifndef USE_TERMIO
510 	return(!(termbuf.sg.sg_flags & (CBREAK|RAW)));
511 #else
512 	return(termbuf.c_lflag & ICANON);
513 #endif
514 }
515 
516 tty_istrapsig()
517 {
518 #ifndef USE_TERMIO
519 	return(!(termbuf.sg.sg_flags&RAW));
520 #else
521 	return(termbuf.c_lflag & ISIG);
522 #endif
523 }
524 
525 tty_setedit(on)
526 int on;
527 {
528 #ifndef USE_TERMIO
529 	if (on)
530 		termbuf.sg.sg_flags &= ~CBREAK;
531 	else
532 		termbuf.sg.sg_flags |= CBREAK;
533 #else
534 	if (on)
535 		termbuf.c_lflag |= ICANON;
536 	else
537 		termbuf.c_lflag &= ~ICANON;
538 #endif
539 }
540 
541 tty_setsig(on)
542 int on;
543 {
544 #ifndef	USE_TERMIO
545 	if (on)
546 		;
547 #else
548 	if (on)
549 		termbuf.c_lflag |= ISIG;
550 	else
551 		termbuf.c_lflag &= ~ISIG;
552 #endif
553 }
554 #endif	/* LINEMODE */
555 
556 /*
557  * A table of available terminal speeds
558  */
559 struct termspeeds {
560 	int	speed;
561 	int	value;
562 } termspeeds[] = {
563 	{ 0,     B0 },    { 50,    B50 },   { 75,    B75 },
564 	{ 110,   B110 },  { 134,   B134 },  { 150,   B150 },
565 	{ 200,   B200 },  { 300,   B300 },  { 600,   B600 },
566 	{ 1200,  B1200 }, { 1800,  B1800 }, { 2400,  B2400 },
567 	{ 4800,  B4800 }, { 9600,  B9600 }, { 19200, B9600 },
568 	{ 38400, B9600 }, { -1,    B9600 }
569 };
570 
571 tty_tspeed(val)
572 {
573 	register struct termspeeds *tp;
574 
575 	for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
576 		;
577 #ifndef	USE_TERMIO
578 	termbuf.sg.sg_ospeed = tp->value;
579 #else
580 # ifdef	SYSV_TERMIO
581 	termbuf.c_cflag &= ~CBAUD;
582 	termbuf.c_cflag |= tp->value;
583 # else
584 	termbuf.c_ospeed = tp->value;
585 # endif
586 #endif
587 }
588 
589 tty_rspeed(val)
590 {
591 	register struct termspeeds *tp;
592 
593 	for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
594 		;
595 #ifndef	USE_TERMIO
596 	termbuf.sg.sg_ispeed = tp->value;
597 #else
598 # ifdef	SYSV_TERMIO
599 	termbuf.c_cflag &= ~CBAUD;
600 	termbuf.c_cflag |= tp->value;
601 # else
602 	termbuf.c_ispeed = tp->value;
603 # endif
604 #endif
605 }
606 
607 #ifdef	CRAY2
608 tty_isnewmap()
609 {
610 	return((termbuf.c_oflag & OPOST) && (termbuf.c_oflag & ONLCR) &&
611 			!(termbuf.c_oflag & ONLRET));
612 }
613 #endif
614 
615 #ifdef	CRAY
616 # ifndef NEWINIT
617 extern	struct utmp wtmp;
618 extern char wtmpf[];
619 # else	/* NEWINIT */
620 int	gotalarm;
621 nologinproc()
622 {
623 	gotalarm++;
624 }
625 # endif	/* NEWINIT */
626 #endif /* CRAY */
627 
628 /*
629  * getptyslave()
630  *
631  * Open the slave side of the pty, and do any initialization
632  * that is necessary.  The return value is a file descriptor
633  * for the slave side.
634  */
635 getptyslave()
636 {
637 	register int t = -1;
638 
639 #ifndef	CRAY
640 	/*
641 	 * Disassociate self from control terminal and open ttyp side.
642 	 * Set important flags on ttyp and ptyp.
643 	 */
644 	t = open(_PATH_TTY, O_RDWR);
645 	if (t >= 0) {
646 		(void) ioctl(t, TIOCNOTTY, (char *)0);
647 		(void) close(t);
648 	}
649 
650 	t = open(line, O_RDWR);
651 	if (t < 0)
652 		fatalperror(net, line);
653 	if (fchmod(t, 0))
654 		fatalperror(net, line);
655 	(void) signal(SIGHUP, SIG_IGN);
656 	vhangup();
657 	(void) signal(SIGHUP, SIG_DFL);
658 	t = open(line, O_RDWR);
659 	if (t < 0)
660 		fatalperror(net, line);
661 
662 	init_termbuf();
663 #ifndef	USE_TERMIO
664 	termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO;
665 	termbuf.sg.sg_ospeed = termbuf.sg.sg_ispeed = B9600;
666 #else
667 	termbuf.c_lflag |= ECHO;
668 	termbuf.c_oflag |= ONLCR|OXTABS;
669 	termbuf.c_iflag |= ICRNL;
670 	termbuf.c_iflag &= ~IXOFF;
671 # ifdef	SYSV_TERMIO
672 	termbuf.sg.sg_ospeed = termbuf.sg.sg_ispeed = B9600;
673 # else SYSV_TERMIO
674 	termbuf.c_ospeed = termbuf.c_ispeed = B9600;
675 # endif
676 #endif
677 	set_termbuf();
678 #else	/* CRAY */
679 	(void) chown(line, 0, 0);
680 	(void) chmod(line, 0600);
681 #endif	/* CRAY */
682 	return(t);
683 }
684 
685 #ifdef	NEWINIT
686 char *gen_id = "fe";
687 #endif
688 
689 /*
690  * startslave(t, host)
691  *
692  * Given a file descriptor (t) for a tty, and a hostname, do whatever
693  * is necessary to startup the login process on the slave side of the pty.
694  */
695 
696 /* ARGSUSED */
697 startslave(t, host)
698 int t;
699 char *host;
700 {
701 	register int i;
702 	long time();
703 
704 #ifndef	NEWINIT
705 # ifdef	CRAY
706 	utmp_sig_init();
707 # endif	/* CRAY */
708 
709 	if ((i = fork()) < 0)
710 		fatalperror(net, "fork");
711 	if (i) {
712 # ifdef	CRAY
713 		/*
714 		 * Cray parent will create utmp entry for child and send
715 		 * signal to child to tell when done.  Child waits for signal
716 		 * before doing anything important.
717 		 */
718 		register int pid = i;
719 
720 		setpgrp();
721 		(void) signal(SIGUSR1, func);	/* reset handler to default */
722 		/*
723 		 * Create utmp entry for child
724 		 */
725 		(void) time(&wtmp.ut_time);
726 		wtmp.ut_type = LOGIN_PROCESS;
727 		wtmp.ut_pid = pid;
728 		SCPYN(wtmp.ut_user, "LOGIN");
729 		SCPYN(wtmp.ut_host, host);
730 		SCPYN(wtmp.ut_line, line + sizeof("/dev/") - 1);
731 		SCPYN(wtmp.ut_id, wtmp.ut_line+3);
732 		pututline(&wtmp);
733 		endutent();
734 		if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) {
735 			(void) write(i, (char *)&wtmp, sizeof(struct utmp));
736 			(void) close(i);
737 		}
738 		utmp_sig_notify(pid);
739 # endif	/* CRAY */
740 		(void) close(t);
741 	} else {
742 		start_login(t, host);
743 		/*NOTREACHED*/
744 	}
745 #else	/* NEWINIT */
746 
747 	extern char *ptyip;
748 	struct init_request request;
749 	int nologinproc();
750 	register int n;
751 
752 	/*
753 	 * Init will start up login process if we ask nicely.  We only wait
754 	 * for it to start up and begin normal telnet operation.
755 	 */
756 	if ((i = open(INIT_FIFO, O_WRONLY)) < 0) {
757 		char tbuf[128];
758 		(void) sprintf(tbuf, "Can't open %s\n", INIT_FIFO);
759 		fatalperror(net, tbuf);
760 	}
761 	memset((char *)&request, 0, sizeof(request));
762 	request.magic = INIT_MAGIC;
763 	SCPYN(request.gen_id, gen_id);
764 	SCPYN(request.tty_id, &line[8]);
765 	SCPYN(request.host, host);
766 	SCPYN(request.term_type, &terminaltype[5]);
767 	if (write(i, (char *)&request, sizeof(request)) < 0) {
768 		char tbuf[128];
769 		(void) sprintf(tbuf, "Can't write to %s\n", INIT_FIFO);
770 		fatalperror(net, tbuf);
771 	}
772 	(void) close(i);
773 	(void) signal(SIGALRM, nologinproc);
774 	for (i = 0; ; i++) {
775 		alarm(15);
776 		n = read(pty, ptyip, BUFSIZ);
777 		if (i == 3 || n >= 0 || !gotalarm)
778 			break;
779 		gotalarm = 0;
780 		(void) write(net, "telnetd: waiting for /etc/init to start login process.\r\n", 56);
781 	}
782 	if (n < 0 && gotalarm)
783 		fatal(net, "/etc/init didn't start login process");
784 	pcc += n;
785 	alarm(0);
786 	(void) signal(SIGALRM, SIG_DFL);
787 
788 	/*
789 	 * Set tab expansion the way we like, in case init did something
790 	 * different.
791 	 */
792 	init_termbuf();
793 	termbuf.c_oflag &= ~TABDLY;
794 	termbuf.c_oflag |= TAB0;
795 	set_termbuf();
796 	return;
797 #endif	/* NEWINIT */
798 }
799 
800 #ifndef	NEWINIT
801 char	*envinit[3];
802 
803 /*
804  * start_login(t, host)
805  *
806  * Assuming that we are now running as a child processes, this
807  * function will turn us into the login process.
808  */
809 
810 start_login(t, host)
811 int t;
812 char *host;
813 {
814 	extern char *getenv();
815 	char **envp;
816 
817 #ifdef	CRAY
818 	utmp_sig_wait();
819 # ifndef TCVHUP
820 	setpgrp();
821 # endif
822 	t = open(line, 2);	/* open ttyp */
823 	if (t < 0)
824 		fatalperror(net, line);
825 # ifdef	TCVHUP
826 	/*
827 	 * Hangup anybody else using this ttyp, then reopen it for
828 	 * ourselves.
829 	 */
830 	(void) chown(line, 0, 0);
831 	(void) chmod(line, 0600);
832 	(void) signal(SIGHUP, SIG_IGN);
833 	(void) ioctl(t, TCVHUP, (char *)0);
834 	(void) signal(SIGHUP, SIG_DFL);
835 	setpgrp();
836 	i = open(line, 2);
837 	if (i < 0)
838 		fatalperror(net, line);
839 	(void) close(t);
840 	t = i;
841 # endif	/* TCVHUP */
842 	/*
843 	 * set ttyp modes as we like them to be
844 	 */
845 	init_termbuf();
846 	termbuf.c_oflag = OPOST|ONLCR;
847 	termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
848 	termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
849 	termbuf.c_cflag = EXTB|HUPCL|CS8;
850 	set_termbuf();
851 #endif	/* CRAY */
852 
853 	/*
854 	 * set up standard paths before forking to login
855 	 */
856 #if	BSD >43
857 	if (setsid() < 0)
858 		fatalperror(net, "setsid");
859 	if (ioctl(t, TIOCSCTTY, (char *)0) < 0)
860 		fatalperror(net, "ioctl(sctty)");
861 #endif
862 	(void) close(net);
863 	(void) close(pty);
864 	(void) dup2(t, 0);
865 	(void) dup2(t, 1);
866 	(void) dup2(t, 2);
867 	(void) close(t);
868 	envp = envinit;
869 	*envp++ = terminaltype;
870 	if (*envp = getenv("TZ"))
871 		*envp++ -= 3;
872 #ifdef	CRAY
873 	else
874 		*envp++ = "TZ=GMT0";
875 #endif
876 	*envp = 0;
877 	environ = envinit;
878 	/*
879 	 * -h : pass on name of host.
880 	 *		WARNING:  -h is accepted by login if and only if
881 	 *			getuid() == 0.
882 	 * -p : don't clobber the environment (so terminal type stays set).
883 	 */
884 	execl(_PATH_LOGIN, "login", "-h", host,
885 #ifndef CRAY
886 					terminaltype ? "-p" : 0,
887 #endif
888 								0);
889 	syslog(LOG_ERR, "%s: %m\n", _PATH_LOGIN);
890 	fatalperror(net, _PATH_LOGIN);
891 	/*NOTREACHED*/
892 }
893 #endif	NEWINIT
894 
895 /*
896  * cleanup()
897  *
898  * This is the routine to call when we are all through, to
899  * clean up anything that needs to be cleaned up.
900  */
901 cleanup()
902 {
903 
904 #ifndef	CRAY
905 # if BSD > 43
906 	char *p;
907 
908 	p = line + sizeof("/dev/") - 1;
909 	if (logout(p))
910 		logwtmp(p, "", "");
911 	(void)chmod(line, 0666);
912 	(void)chown(line, 0, 0);
913 	*p = 'p';
914 	(void)chmod(line, 0666);
915 	(void)chown(line, 0, 0);
916 # else
917 	rmut();
918 	vhangup();	/* XXX */
919 # endif
920 	(void) shutdown(net, 2);
921 #else	/* CRAY */
922 # ifndef NEWINIT
923 	rmut(line);
924 	(void) shutdown(net, 2);
925 	kill(0, SIGHUP);
926 # else	/* NEWINIT */
927 	(void) shutdown(net, 2);
928 	sleep(5);
929 # endif	/* NEWINT */
930 #endif	/* CRAY */
931 	exit(1);
932 }
933 
934 #if	defined(CRAY) && !defined(NEWINIT)
935 /*
936  * _utmp_sig_rcv
937  * utmp_sig_init
938  * utmp_sig_wait
939  *	These three functions are used to coordinate the handling of
940  *	the utmp file between the server and the soon-to-be-login shell.
941  *	The server actually creates the utmp structure, the child calls
942  *	utmp_sig_wait(), until the server calls utmp_sig_notify() and
943  *	signals the future-login shell to proceed.
944  */
945 static int caught=0;		/* NZ when signal intercepted */
946 static void (*func)();		/* address of previous handler */
947 
948 void
949 _utmp_sig_rcv(sig)
950 int sig;
951 {
952 	caught = 1;
953 	(void) signal(SIGUSR1, func);
954 }
955 
956 utmp_sig_init()
957 {
958 	/*
959 	 * register signal handler for UTMP creation
960 	 */
961 	if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1)
962 		fatalperror(net, "telnetd/signal");
963 }
964 
965 utmp_sig_wait()
966 {
967 	/*
968 	 * Wait for parent to write our utmp entry.
969 	 */
970 	sigoff();
971 	while (caught == 0) {
972 		pause();	/* wait until we get a signal (sigon) */
973 		sigoff();	/* turn off signals while we check caught */
974 	}
975 	sigon();		/* turn on signals again */
976 }
977 
978 utmp_sig_notify(pid)
979 {
980 	kill(pid, SIGUSR1);
981 }
982 #endif	/* defined(CRAY) && !defined(NEWINIT) */
983 
984 /*
985  * rmut()
986  *
987  * This is the function called by cleanup() to
988  * remove the utmp entry for this person.
989  */
990 
991 #if	!defined(CRAY) && BSD <= 43
992 rmut()
993 {
994 	register f;
995 	int found = 0;
996 	struct utmp *u, *utmp;
997 	int nutmp;
998 	struct stat statbf;
999 	char *malloc();
1000 	long time();
1001 	off_t lseek();
1002 
1003 	f = open(utmpf, O_RDWR);
1004 	if (f >= 0) {
1005 		(void) fstat(f, &statbf);
1006 		utmp = (struct utmp *)malloc((unsigned)statbf.st_size);
1007 		if (!utmp)
1008 			syslog(LOG_ERR, "utmp malloc failed");
1009 		if (statbf.st_size && utmp) {
1010 			nutmp = read(f, (char *)utmp, (int)statbf.st_size);
1011 			nutmp /= sizeof(struct utmp);
1012 
1013 			for (u = utmp ; u < &utmp[nutmp] ; u++) {
1014 				if (SCMPN(u->ut_line, line+5) ||
1015 				    u->ut_name[0]==0)
1016 					continue;
1017 				(void) lseek(f, ((long)u)-((long)utmp), L_SET);
1018 				SCPYN(u->ut_name, "");
1019 				SCPYN(u->ut_host, "");
1020 				(void) time(&u->ut_time);
1021 				(void) write(f, (char *)u, sizeof(wtmp));
1022 				found++;
1023 			}
1024 		}
1025 		(void) close(f);
1026 	}
1027 	if (found) {
1028 		f = open(wtmpf, O_WRONLY|O_APPEND);
1029 		if (f >= 0) {
1030 			SCPYN(wtmp.ut_line, line+5);
1031 			SCPYN(wtmp.ut_name, "");
1032 			SCPYN(wtmp.ut_host, "");
1033 			(void) time(&wtmp.ut_time);
1034 			(void) write(f, (char *)&wtmp, sizeof(wtmp));
1035 			(void) close(f);
1036 		}
1037 	}
1038 	(void) chmod(line, 0666);
1039 	(void) chown(line, 0, 0);
1040 	line[strlen("/dev/")] = 'p';
1041 	(void) chmod(line, 0666);
1042 	(void) chown(line, 0, 0);
1043 }  /* end of rmut */
1044 #endif	/* CRAY */
1045