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