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