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