xref: /dragonfly/libexec/telnetd/sys_term.c (revision e96fb831)
1 /*
2  * Copyright (c) 1989, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * @(#)sys_term.c	8.4+1 (Berkeley) 5/30/95
34  * $FreeBSD: src/crypto/telnet/telnetd/sys_term.c,v 1.7.2.5 2002/06/17 02:48:02 jmallett Exp $
35  */
36 
37 #include <sys/types.h>
38 #include <sys/tty.h>
39 #include <libutil.h>
40 #include <stdlib.h>
41 #include <utmp.h>
42 
43 #include "telnetd.h"
44 #include "pathnames.h"
45 
46 #ifdef	AUTHENTICATION
47 #include <libtelnet/auth.h>
48 #endif
49 
50 int cleanopen(char *);
51 void scrub_env(void);
52 
53 struct	utmp wtmp;
54 
55 #ifdef _PATH_WTMP
56 char    wtmpf[] = _PATH_WTMP;
57 #else
58 char	wtmpf[]	= "/var/log/wtmp";
59 #endif
60 #ifdef _PATH_UTMP
61 char    utmpf[] = _PATH_UTMP;
62 #else
63 char	utmpf[] = "/var/run/utmp";
64 #endif
65 
66 char	*envinit[3];
67 extern char **environ;
68 
69 #define SCPYN(a, b)	(void) strncpy(a, b, sizeof(a))
70 #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
71 
72 #ifdef	t_erase
73 #undef	t_erase
74 #undef	t_kill
75 #undef	t_intrc
76 #undef	t_quitc
77 #undef	t_startc
78 #undef	t_stopc
79 #undef	t_eofc
80 #undef	t_brkc
81 #undef	t_suspc
82 #undef	t_dsuspc
83 #undef	t_rprntc
84 #undef	t_flushc
85 #undef	t_werasc
86 #undef	t_lnextc
87 #endif
88 
89 #ifndef	USE_TERMIO
90 struct termbuf {
91 	struct sgttyb sg;
92 	struct tchars tc;
93 	struct ltchars ltc;
94 	int state;
95 	int lflags;
96 } termbuf, termbuf2;
97 # define	cfsetospeed(tp, val)	(tp)->sg.sg_ospeed = (val)
98 # define	cfsetispeed(tp, val)	(tp)->sg.sg_ispeed = (val)
99 # define	cfgetospeed(tp)		(tp)->sg.sg_ospeed
100 # define	cfgetispeed(tp)		(tp)->sg.sg_ispeed
101 #else	/* USE_TERMIO */
102 # ifndef	TCSANOW
103 #  ifdef TCSETS
104 #   define	TCSANOW		TCSETS
105 #   define	TCSADRAIN	TCSETSW
106 #   define	tcgetattr(f, t)	ioctl(f, TCGETS, (char *)t)
107 #  else
108 #   ifdef TCSETA
109 #    define	TCSANOW		TCSETA
110 #    define	TCSADRAIN	TCSETAW
111 #    define	tcgetattr(f, t)	ioctl(f, TCGETA, (char *)t)
112 #   else
113 #    define	TCSANOW		TIOCSETA
114 #    define	TCSADRAIN	TIOCSETAW
115 #    define	tcgetattr(f, t)	ioctl(f, TIOCGETA, (char *)t)
116 #   endif
117 #  endif
118 #  define	tcsetattr(f, a, t)	ioctl(f, a, t)
119 #  define	cfsetospeed(tp, val)	(tp)->c_cflag &= ~CBAUD; \
120 					(tp)->c_cflag |= (val)
121 #  define	cfgetospeed(tp)		((tp)->c_cflag & CBAUD)
122 #  ifdef CIBAUD
123 #   define	cfsetispeed(tp, val)	(tp)->c_cflag &= ~CIBAUD; \
124 					(tp)->c_cflag |= ((val)<<IBSHIFT)
125 #   define	cfgetispeed(tp)		(((tp)->c_cflag & CIBAUD)>>IBSHIFT)
126 #  else
127 #   define	cfsetispeed(tp, val)	(tp)->c_cflag &= ~CBAUD; \
128 					(tp)->c_cflag |= (val)
129 #   define	cfgetispeed(tp)		((tp)->c_cflag & CBAUD)
130 #  endif
131 # endif /* TCSANOW */
132 struct termios termbuf, termbuf2;	/* pty control structure */
133 #endif	/* USE_TERMIO */
134 
135 #include <sys/types.h>
136 #include <libutil.h>
137 
138 int cleanopen(char *);
139 void scrub_env(void);
140 static char **addarg(char **, const char *);
141 
142 /*
143  * init_termbuf()
144  * copy_termbuf(cp)
145  * set_termbuf()
146  *
147  * These three routines are used to get and set the "termbuf" structure
148  * to and from the kernel.  init_termbuf() gets the current settings.
149  * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
150  * set_termbuf() writes the structure into the kernel.
151  */
152 
153 void
154 init_termbuf(void)
155 {
156 #ifndef	USE_TERMIO
157 	(void) ioctl(pty, TIOCGETP, (char *)&termbuf.sg);
158 	(void) ioctl(pty, TIOCGETC, (char *)&termbuf.tc);
159 	(void) ioctl(pty, TIOCGLTC, (char *)&termbuf.ltc);
160 # ifdef	TIOCGSTATE
161 	(void) ioctl(pty, TIOCGSTATE, (char *)&termbuf.state);
162 # endif
163 #else
164 	(void) tcgetattr(pty, &termbuf);
165 #endif
166 	termbuf2 = termbuf;
167 }
168 
169 #if	defined(LINEMODE) && defined(TIOCPKT_IOCTL)
170 void
171 copy_termbuf(char *cp, size_t len)
172 {
173 	if (len > sizeof(termbuf))
174 		len = sizeof(termbuf);
175 	memmove((char *)&termbuf, cp, len);
176 	termbuf2 = termbuf;
177 }
178 #endif	/* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */
179 
180 void
181 set_termbuf(void)
182 {
183 	/*
184 	 * Only make the necessary changes.
185 	 */
186 #ifndef	USE_TERMIO
187 	if (memcmp((char *)&termbuf.sg, (char *)&termbuf2.sg,
188 							sizeof(termbuf.sg)))
189 		(void) ioctl(pty, TIOCSETN, (char *)&termbuf.sg);
190 	if (memcmp((char *)&termbuf.tc, (char *)&termbuf2.tc,
191 							sizeof(termbuf.tc)))
192 		(void) ioctl(pty, TIOCSETC, (char *)&termbuf.tc);
193 	if (memcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc,
194 							sizeof(termbuf.ltc)))
195 		(void) ioctl(pty, TIOCSLTC, (char *)&termbuf.ltc);
196 	if (termbuf.lflags != termbuf2.lflags)
197 		(void) ioctl(pty, TIOCLSET, (char *)&termbuf.lflags);
198 #else	/* USE_TERMIO */
199 	if (memcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf)))
200 		(void) tcsetattr(pty, TCSANOW, &termbuf);
201 #endif	/* USE_TERMIO */
202 }
203 
204 
205 /*
206  * spcset(func, valp, valpp)
207  *
208  * This function takes various special characters (func), and
209  * sets *valp to the current value of that character, and
210  * *valpp to point to where in the "termbuf" structure that
211  * value is kept.
212  *
213  * It returns the SLC_ level of support for this function.
214  */
215 
216 #ifndef	USE_TERMIO
217 int
218 spcset(int func, cc_t *valp, cc_t **valpp)
219 {
220 	switch(func) {
221 	case SLC_EOF:
222 		*valp = termbuf.tc.t_eofc;
223 		*valpp = (cc_t *)&termbuf.tc.t_eofc;
224 		return(SLC_VARIABLE);
225 	case SLC_EC:
226 		*valp = termbuf.sg.sg_erase;
227 		*valpp = (cc_t *)&termbuf.sg.sg_erase;
228 		return(SLC_VARIABLE);
229 	case SLC_EL:
230 		*valp = termbuf.sg.sg_kill;
231 		*valpp = (cc_t *)&termbuf.sg.sg_kill;
232 		return(SLC_VARIABLE);
233 	case SLC_IP:
234 		*valp = termbuf.tc.t_intrc;
235 		*valpp = (cc_t *)&termbuf.tc.t_intrc;
236 		return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
237 	case SLC_ABORT:
238 		*valp = termbuf.tc.t_quitc;
239 		*valpp = (cc_t *)&termbuf.tc.t_quitc;
240 		return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
241 	case SLC_XON:
242 		*valp = termbuf.tc.t_startc;
243 		*valpp = (cc_t *)&termbuf.tc.t_startc;
244 		return(SLC_VARIABLE);
245 	case SLC_XOFF:
246 		*valp = termbuf.tc.t_stopc;
247 		*valpp = (cc_t *)&termbuf.tc.t_stopc;
248 		return(SLC_VARIABLE);
249 	case SLC_AO:
250 		*valp = termbuf.ltc.t_flushc;
251 		*valpp = (cc_t *)&termbuf.ltc.t_flushc;
252 		return(SLC_VARIABLE);
253 	case SLC_SUSP:
254 		*valp = termbuf.ltc.t_suspc;
255 		*valpp = (cc_t *)&termbuf.ltc.t_suspc;
256 		return(SLC_VARIABLE);
257 	case SLC_EW:
258 		*valp = termbuf.ltc.t_werasc;
259 		*valpp = (cc_t *)&termbuf.ltc.t_werasc;
260 		return(SLC_VARIABLE);
261 	case SLC_RP:
262 		*valp = termbuf.ltc.t_rprntc;
263 		*valpp = (cc_t *)&termbuf.ltc.t_rprntc;
264 		return(SLC_VARIABLE);
265 	case SLC_LNEXT:
266 		*valp = termbuf.ltc.t_lnextc;
267 		*valpp = (cc_t *)&termbuf.ltc.t_lnextc;
268 		return(SLC_VARIABLE);
269 	case SLC_FORW1:
270 		*valp = termbuf.tc.t_brkc;
271 		*valpp = (cc_t *)&termbuf.ltc.t_lnextc;
272 		return(SLC_VARIABLE);
273 	case SLC_BRK:
274 	case SLC_SYNCH:
275 	case SLC_AYT:
276 	case SLC_EOR:
277 		*valp = (cc_t)0;
278 		*valpp = NULL;
279 		return(SLC_DEFAULT);
280 	default:
281 		*valp = (cc_t)0;
282 		*valpp = NULL;
283 		return(SLC_NOSUPPORT);
284 	}
285 }
286 
287 #else	/* USE_TERMIO */
288 
289 
290 #define	setval(a, b)	*valp = termbuf.c_cc[a]; \
291 			*valpp = &termbuf.c_cc[a]; \
292 			return(b);
293 #define	defval(a) *valp = ((cc_t)a); *valpp = NULL; return(SLC_DEFAULT);
294 
295 int
296 spcset(int func, cc_t *valp, cc_t **valpp)
297 {
298 	switch(func) {
299 	case SLC_EOF:
300 		setval(VEOF, SLC_VARIABLE);
301 	case SLC_EC:
302 		setval(VERASE, SLC_VARIABLE);
303 	case SLC_EL:
304 		setval(VKILL, SLC_VARIABLE);
305 	case SLC_IP:
306 		setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
307 	case SLC_ABORT:
308 		setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
309 	case SLC_XON:
310 #ifdef	VSTART
311 		setval(VSTART, SLC_VARIABLE);
312 #else
313 		defval(0x13);
314 #endif
315 	case SLC_XOFF:
316 #ifdef	VSTOP
317 		setval(VSTOP, SLC_VARIABLE);
318 #else
319 		defval(0x11);
320 #endif
321 	case SLC_EW:
322 #ifdef	VWERASE
323 		setval(VWERASE, SLC_VARIABLE);
324 #else
325 		defval(0);
326 #endif
327 	case SLC_RP:
328 #ifdef	VREPRINT
329 		setval(VREPRINT, SLC_VARIABLE);
330 #else
331 		defval(0);
332 #endif
333 	case SLC_LNEXT:
334 #ifdef	VLNEXT
335 		setval(VLNEXT, SLC_VARIABLE);
336 #else
337 		defval(0);
338 #endif
339 	case SLC_AO:
340 #if	!defined(VDISCARD) && defined(VFLUSHO)
341 # define VDISCARD VFLUSHO
342 #endif
343 #ifdef	VDISCARD
344 		setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT);
345 #else
346 		defval(0);
347 #endif
348 	case SLC_SUSP:
349 #ifdef	VSUSP
350 		setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN);
351 #else
352 		defval(0);
353 #endif
354 #ifdef	VEOL
355 	case SLC_FORW1:
356 		setval(VEOL, SLC_VARIABLE);
357 #endif
358 #ifdef	VEOL2
359 	case SLC_FORW2:
360 		setval(VEOL2, SLC_VARIABLE);
361 #endif
362 	case SLC_AYT:
363 #ifdef	VSTATUS
364 		setval(VSTATUS, SLC_VARIABLE);
365 #else
366 		defval(0);
367 #endif
368 
369 	case SLC_BRK:
370 	case SLC_SYNCH:
371 	case SLC_EOR:
372 		defval(0);
373 
374 	default:
375 		*valp = 0;
376 		*valpp = 0;
377 		return(SLC_NOSUPPORT);
378 	}
379 }
380 #endif	/* USE_TERMIO */
381 
382 /*
383  * getpty()
384  *
385  * Allocate a pty.  As a side effect, the external character
386  * array "line" contains the name of the slave side.
387  *
388  * Returns the file descriptor of the opened pty.
389  */
390 char alpha[] = "0123456789abcdefghijklmnopqrstuv";
391 char line[16];
392 
393 int
394 getpty(int *ptynum __unused)
395 {
396 	int p;
397 	const char *cp;
398 	char *p1, *p2;
399 	int i;
400 
401 	(void) strcpy(line, _PATH_DEV);
402 	(void) strcat(line, "ptyXX");
403 	p1 = &line[8];
404 	p2 = &line[9];
405 
406 	for (cp = "pqrsPQRS"; *cp; cp++) {
407 		struct stat stb;
408 
409 		*p1 = *cp;
410 		*p2 = '0';
411 		/*
412 		 * This stat() check is just to keep us from
413 		 * looping through all 256 combinations if there
414 		 * aren't that many ptys available.
415 		 */
416 		if (stat(line, &stb) < 0)
417 			break;
418 		for (i = 0; i < 32; i++) {
419 			*p2 = alpha[i];
420 			p = open(line, 2);
421 			if (p > 0) {
422 				line[5] = 't';
423 				chown(line, 0, 0);
424 				chmod(line, 0600);
425 					return(p);
426 			}
427 		}
428 	}
429 	return(-1);
430 }
431 
432 #ifdef	LINEMODE
433 /*
434  * tty_flowmode()	Find out if flow control is enabled or disabled.
435  * tty_linemode()	Find out if linemode (external processing) is enabled.
436  * tty_setlinemod(on)	Turn on/off linemode.
437  * tty_isecho()		Find out if echoing is turned on.
438  * tty_setecho(on)	Enable/disable character echoing.
439  * tty_israw()		Find out if terminal is in RAW mode.
440  * tty_binaryin(on)	Turn on/off BINARY on input.
441  * tty_binaryout(on)	Turn on/off BINARY on output.
442  * tty_isediting()	Find out if line editing is enabled.
443  * tty_istrapsig()	Find out if signal trapping is enabled.
444  * tty_setedit(on)	Turn on/off line editing.
445  * tty_setsig(on)	Turn on/off signal trapping.
446  * tty_issofttab()	Find out if tab expansion is enabled.
447  * tty_setsofttab(on)	Turn on/off soft tab expansion.
448  * tty_islitecho()	Find out if typed control chars are echoed literally
449  * tty_setlitecho()	Turn on/off literal echo of control chars
450  * tty_tspeed(val)	Set transmit speed to val.
451  * tty_rspeed(val)	Set receive speed to val.
452  */
453 
454 
455 int
456 tty_linemode(void)
457 {
458 #ifndef	USE_TERMIO
459 	return(termbuf.state & TS_EXTPROC);
460 #else
461 	return(termbuf.c_lflag & EXTPROC);
462 #endif
463 }
464 
465 void
466 tty_setlinemode(int on)
467 {
468 #ifdef	TIOCEXT
469 	set_termbuf();
470 	(void) ioctl(pty, TIOCEXT, (char *)&on);
471 	init_termbuf();
472 #else	/* !TIOCEXT */
473 # ifdef	EXTPROC
474 	if (on)
475 		termbuf.c_lflag |= EXTPROC;
476 	else
477 		termbuf.c_lflag &= ~EXTPROC;
478 # endif
479 #endif	/* TIOCEXT */
480 }
481 #endif	/* LINEMODE */
482 
483 int
484 tty_isecho(void)
485 {
486 #ifndef USE_TERMIO
487 	return (termbuf.sg.sg_flags & ECHO);
488 #else
489 	return (termbuf.c_lflag & ECHO);
490 #endif
491 }
492 
493 int
494 tty_flowmode(void)
495 {
496 #ifndef USE_TERMIO
497 	return(((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0) ? 1 : 0);
498 #else
499 	return((termbuf.c_iflag & IXON) ? 1 : 0);
500 #endif
501 }
502 
503 int
504 tty_restartany(void)
505 {
506 #ifndef USE_TERMIO
507 # ifdef	DECCTQ
508 	return((termbuf.lflags & DECCTQ) ? 0 : 1);
509 # else
510 	return(-1);
511 # endif
512 #else
513 	return((termbuf.c_iflag & IXANY) ? 1 : 0);
514 #endif
515 }
516 
517 void
518 tty_setecho(int on)
519 {
520 #ifndef	USE_TERMIO
521 	if (on)
522 		termbuf.sg.sg_flags |= ECHO|CRMOD;
523 	else
524 		termbuf.sg.sg_flags &= ~(ECHO|CRMOD);
525 #else
526 	if (on)
527 		termbuf.c_lflag |= ECHO;
528 	else
529 		termbuf.c_lflag &= ~ECHO;
530 #endif
531 }
532 
533 int
534 tty_israw(void)
535 {
536 #ifndef USE_TERMIO
537 	return(termbuf.sg.sg_flags & RAW);
538 #else
539 	return(!(termbuf.c_lflag & ICANON));
540 #endif
541 }
542 
543 #ifdef	AUTHENTICATION
544 #if	defined(NO_LOGIN_F) && defined(LOGIN_R)
545 int
546 tty_setraw(int on)
547 {
548 #  ifndef USE_TERMIO
549 	if (on)
550 		termbuf.sg.sg_flags |= RAW;
551 	else
552 		termbuf.sg.sg_flags &= ~RAW;
553 #  else
554 	if (on)
555 		termbuf.c_lflag &= ~ICANON;
556 	else
557 		termbuf.c_lflag |= ICANON;
558 #  endif
559 }
560 #endif
561 #endif /* AUTHENTICATION */
562 
563 void
564 tty_binaryin(int on)
565 {
566 #ifndef	USE_TERMIO
567 	if (on)
568 		termbuf.lflags |= LPASS8;
569 	else
570 		termbuf.lflags &= ~LPASS8;
571 #else
572 	if (on) {
573 		termbuf.c_iflag &= ~ISTRIP;
574 	} else {
575 		termbuf.c_iflag |= ISTRIP;
576 	}
577 #endif
578 }
579 
580 void
581 tty_binaryout(int on)
582 {
583 #ifndef	USE_TERMIO
584 	if (on)
585 		termbuf.lflags |= LLITOUT;
586 	else
587 		termbuf.lflags &= ~LLITOUT;
588 #else
589 	if (on) {
590 		termbuf.c_cflag &= ~(CSIZE|PARENB);
591 		termbuf.c_cflag |= CS8;
592 		termbuf.c_oflag &= ~OPOST;
593 	} else {
594 		termbuf.c_cflag &= ~CSIZE;
595 		termbuf.c_cflag |= CS7|PARENB;
596 		termbuf.c_oflag |= OPOST;
597 	}
598 #endif
599 }
600 
601 int
602 tty_isbinaryin(void)
603 {
604 #ifndef	USE_TERMIO
605 	return(termbuf.lflags & LPASS8);
606 #else
607 	return(!(termbuf.c_iflag & ISTRIP));
608 #endif
609 }
610 
611 int
612 tty_isbinaryout(void)
613 {
614 #ifndef	USE_TERMIO
615 	return(termbuf.lflags & LLITOUT);
616 #else
617 	return(!(termbuf.c_oflag&OPOST));
618 #endif
619 }
620 
621 #ifdef	LINEMODE
622 int
623 tty_isediting(void)
624 {
625 #ifndef USE_TERMIO
626 	return(!(termbuf.sg.sg_flags & (CBREAK|RAW)));
627 #else
628 	return(termbuf.c_lflag & ICANON);
629 #endif
630 }
631 
632 int
633 tty_istrapsig(void)
634 {
635 #ifndef USE_TERMIO
636 	return(!(termbuf.sg.sg_flags&RAW));
637 #else
638 	return(termbuf.c_lflag & ISIG);
639 #endif
640 }
641 
642 void
643 tty_setedit(int on)
644 {
645 #ifndef USE_TERMIO
646 	if (on)
647 		termbuf.sg.sg_flags &= ~CBREAK;
648 	else
649 		termbuf.sg.sg_flags |= CBREAK;
650 #else
651 	if (on)
652 		termbuf.c_lflag |= ICANON;
653 	else
654 		termbuf.c_lflag &= ~ICANON;
655 #endif
656 }
657 
658 void
659 tty_setsig(int on)
660 {
661 #ifndef	USE_TERMIO
662 	if (on)
663 		;
664 #else
665 	if (on)
666 		termbuf.c_lflag |= ISIG;
667 	else
668 		termbuf.c_lflag &= ~ISIG;
669 #endif
670 }
671 #endif	/* LINEMODE */
672 
673 int
674 tty_issofttab(void)
675 {
676 #ifndef	USE_TERMIO
677 	return (termbuf.sg.sg_flags & XTABS);
678 #else
679 # ifdef	OXTABS
680 	return (termbuf.c_oflag & OXTABS);
681 # endif
682 # ifdef	TABDLY
683 	return ((termbuf.c_oflag & TABDLY) == TAB3);
684 # endif
685 #endif
686 }
687 
688 void
689 tty_setsofttab(int on)
690 {
691 #ifndef	USE_TERMIO
692 	if (on)
693 		termbuf.sg.sg_flags |= XTABS;
694 	else
695 		termbuf.sg.sg_flags &= ~XTABS;
696 #else
697 	if (on) {
698 # ifdef	OXTABS
699 		termbuf.c_oflag |= OXTABS;
700 # endif
701 # ifdef	TABDLY
702 		termbuf.c_oflag &= ~TABDLY;
703 		termbuf.c_oflag |= TAB3;
704 # endif
705 	} else {
706 # ifdef	OXTABS
707 		termbuf.c_oflag &= ~OXTABS;
708 # endif
709 # ifdef	TABDLY
710 		termbuf.c_oflag &= ~TABDLY;
711 		termbuf.c_oflag |= TAB0;
712 # endif
713 	}
714 #endif
715 }
716 
717 int
718 tty_islitecho(void)
719 {
720 #ifndef	USE_TERMIO
721 	return (!(termbuf.lflags & LCTLECH));
722 #else
723 # ifdef	ECHOCTL
724 	return (!(termbuf.c_lflag & ECHOCTL));
725 # endif
726 # ifdef	TCTLECH
727 	return (!(termbuf.c_lflag & TCTLECH));
728 # endif
729 # if	!defined(ECHOCTL) && !defined(TCTLECH)
730 	return (0);	/* assumes ctl chars are echoed '^x' */
731 # endif
732 #endif
733 }
734 
735 void
736 tty_setlitecho(int on)
737 {
738 #ifndef	USE_TERMIO
739 	if (on)
740 		termbuf.lflags &= ~LCTLECH;
741 	else
742 		termbuf.lflags |= LCTLECH;
743 #else
744 # ifdef	ECHOCTL
745 	if (on)
746 		termbuf.c_lflag &= ~ECHOCTL;
747 	else
748 		termbuf.c_lflag |= ECHOCTL;
749 # endif
750 # ifdef	TCTLECH
751 	if (on)
752 		termbuf.c_lflag &= ~TCTLECH;
753 	else
754 		termbuf.c_lflag |= TCTLECH;
755 # endif
756 #endif
757 }
758 
759 int
760 tty_iscrnl(void)
761 {
762 #ifndef	USE_TERMIO
763 	return (termbuf.sg.sg_flags & CRMOD);
764 #else
765 	return (termbuf.c_iflag & ICRNL);
766 #endif
767 }
768 
769 /*
770  * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
771  */
772 #if B4800 != 4800
773 #define	DECODE_BAUD
774 #endif
775 
776 #ifdef	DECODE_BAUD
777 
778 /*
779  * A table of available terminal speeds
780  */
781 struct termspeeds {
782 	int	speed;
783 	int	value;
784 } termspeeds[] = {
785 	{ 0,      B0 },      { 50,    B50 },    { 75,     B75 },
786 	{ 110,    B110 },    { 134,   B134 },   { 150,    B150 },
787 	{ 200,    B200 },    { 300,   B300 },   { 600,    B600 },
788 	{ 1200,   B1200 },   { 1800,  B1800 },  { 2400,   B2400 },
789 	{ 4800,   B4800 },
790 #ifdef	B7200
791 	{ 7200,  B7200 },
792 #endif
793 	{ 9600,   B9600 },
794 #ifdef	B14400
795 	{ 14400,  B14400 },
796 #endif
797 #ifdef	B19200
798 	{ 19200,  B19200 },
799 #endif
800 #ifdef	B28800
801 	{ 28800,  B28800 },
802 #endif
803 #ifdef	B38400
804 	{ 38400,  B38400 },
805 #endif
806 #ifdef	B57600
807 	{ 57600,  B57600 },
808 #endif
809 #ifdef	B115200
810 	{ 115200, B115200 },
811 #endif
812 #ifdef	B230400
813 	{ 230400, B230400 },
814 #endif
815 	{ -1,     0 }
816 };
817 #endif	/* DECODE_BAUD */
818 
819 void
820 tty_tspeed(int val)
821 {
822 #ifdef	DECODE_BAUD
823 	struct termspeeds *tp;
824 
825 	for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
826 		;
827 	if (tp->speed == -1)	/* back up to last valid value */
828 		--tp;
829 	cfsetospeed(&termbuf, tp->value);
830 #else	/* DECODE_BAUD */
831 	cfsetospeed(&termbuf, val);
832 #endif	/* DECODE_BAUD */
833 }
834 
835 void
836 tty_rspeed(int val)
837 {
838 #ifdef	DECODE_BAUD
839 	struct termspeeds *tp;
840 
841 	for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
842 		;
843 	if (tp->speed == -1)	/* back up to last valid value */
844 		--tp;
845 	cfsetispeed(&termbuf, tp->value);
846 #else	/* DECODE_BAUD */
847 	cfsetispeed(&termbuf, val);
848 #endif	/* DECODE_BAUD */
849 }
850 
851 /*
852  * getptyslave()
853  *
854  * Open the slave side of the pty, and do any initialization
855  * that is necessary.
856  */
857 static void
858 getptyslave(void)
859 {
860 	int t = -1;
861 	char erase;
862 
863 # ifdef	LINEMODE
864 	int waslm;
865 # endif
866 # ifdef	TIOCGWINSZ
867 	struct winsize ws;
868 	extern int def_row, def_col;
869 # endif
870 	extern int def_tspeed, def_rspeed;
871 	/*
872 	 * Opening the slave side may cause initilization of the
873 	 * kernel tty structure.  We need remember the state of
874 	 * 	if linemode was turned on
875 	 *	terminal window size
876 	 *	terminal speed
877 	 *	erase character
878 	 * so that we can re-set them if we need to.
879 	 */
880 # ifdef	LINEMODE
881 	waslm = tty_linemode();
882 # endif
883 	erase = termbuf.c_cc[VERASE];
884 
885 	/*
886 	 * Make sure that we don't have a controlling tty, and
887 	 * that we are the session (process group) leader.
888 	 */
889 # ifdef	TIOCNOTTY
890 	t = open(_PATH_TTY, O_RDWR);
891 	if (t >= 0) {
892 		(void) ioctl(t, TIOCNOTTY, NULL);
893 		(void) close(t);
894 	}
895 # endif
896 
897 	t = cleanopen(line);
898 	if (t < 0)
899 		fatalperror(net, line);
900 
901 
902 	/*
903 	 * set up the tty modes as we like them to be.
904 	 */
905 	init_termbuf();
906 # ifdef	TIOCGWINSZ
907 	if (def_row || def_col) {
908 		memset((char *)&ws, 0, sizeof(ws));
909 		ws.ws_col = def_col;
910 		ws.ws_row = def_row;
911 		(void)ioctl(t, TIOCSWINSZ, (char *)&ws);
912 	}
913 # endif
914 
915 	/*
916 	 * Settings for sgtty based systems
917 	 */
918 # ifndef	USE_TERMIO
919 	termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS;
920 # endif	/* USE_TERMIO */
921 
922 	/*
923 	 * Settings for all other termios/termio based
924 	 * systems, other than 4.4BSD.  In 4.4BSD the
925 	 * kernel does the initial terminal setup.
926 	 */
927 	tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);
928 	tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);
929 	if (erase)
930 		termbuf.c_cc[VERASE] = erase;
931 # ifdef	LINEMODE
932 	if (waslm)
933 		tty_setlinemode(1);
934 # endif	/* LINEMODE */
935 
936 	/*
937 	 * Set the tty modes, and make this our controlling tty.
938 	 */
939 	set_termbuf();
940 	if (login_tty(t) == -1)
941 		fatalperror(net, "login_tty");
942 	if (net > 2)
943 		(void) close(net);
944 #ifdef	AUTHENTICATION
945 #if	defined(NO_LOGIN_F) && defined(LOGIN_R)
946 	/*
947 	 * Leave the pty open so that we can write out the rlogin
948 	 * protocol for /bin/login, if the authentication works.
949 	 */
950 #else
951 	if (pty > 2) {
952 		(void) close(pty);
953 		pty = -1;
954 	}
955 #endif
956 #endif /* AUTHENTICATION */
957 }
958 
959 #ifndef	O_NOCTTY
960 #define	O_NOCTTY	0
961 #endif
962 /*
963  * Open the specified slave side of the pty,
964  * making sure that we have a clean tty.
965  */
966 int
967 cleanopen(char *li)
968 {
969 	int t;
970 
971 	/*
972 	 * Make sure that other people can't open the
973 	 * slave side of the connection.
974 	 */
975 	(void) chown(li, 0, 0);
976 	(void) chmod(li, 0600);
977 
978 	(void) revoke(li);
979 
980 	t = open(line, O_RDWR|O_NOCTTY);
981 
982 	if (t < 0)
983 		return(-1);
984 
985 	return(t);
986 }
987 
988 /*
989  * startslave(host)
990  *
991  * Given a hostname, do whatever
992  * is necessary to startup the login process on the slave side of the pty.
993  */
994 
995 /* ARGSUSED */
996 void
997 startslave(char *host, int autologin, char *autoname)
998 {
999 	int i;
1000 
1001 #ifdef	AUTHENTICATION
1002 	if (!autoname || !autoname[0])
1003 		autologin = 0;
1004 
1005 	if (autologin < auth_level) {
1006 		fatal(net, "Authorization failed");
1007 		exit(1);
1008 	}
1009 #endif
1010 
1011 
1012 	if ((i = fork()) < 0)
1013 		fatalperror(net, "fork");
1014 	if (i) {
1015 	} else {
1016 		getptyslave();
1017 		start_login(host, autologin, autoname);
1018 		/*NOTREACHED*/
1019 	}
1020 }
1021 
1022 void
1023 init_env(void)
1024 {
1025 	char **envp;
1026 
1027 	envp = envinit;
1028 	if ((*envp = getenv("TZ")))
1029 		*envp++ -= 3;
1030 	*envp = 0;
1031 	environ = envinit;
1032 }
1033 
1034 
1035 /*
1036  * start_login(host)
1037  *
1038  * Assuming that we are now running as a child processes, this
1039  * function will turn us into the login process.
1040  */
1041 
1042 #ifndef AUTHENTICATION
1043 #define undef1 __unused
1044 #else
1045 #define undef1
1046 #endif
1047 
1048 void
1049 start_login(char *host undef1, int autologin undef1, char *name undef1)
1050 {
1051 	char **argv;
1052 
1053 	scrub_env();
1054 
1055 	/*
1056 	 * -h : pass on name of host.
1057 	 *		WARNING:  -h is accepted by login if and only if
1058 	 *			getuid() == 0.
1059 	 * -p : don't clobber the environment (so terminal type stays set).
1060 	 *
1061 	 * -f : force this login, he has already been authenticated
1062 	 */
1063 	argv = addarg(0, "login");
1064 
1065 #if	!defined(NO_LOGIN_H)
1066 #ifdef	AUTHENTICATION
1067 # if	defined(NO_LOGIN_F) && defined(LOGIN_R)
1068 	/*
1069 	 * Don't add the "-h host" option if we are going
1070 	 * to be adding the "-r host" option down below...
1071 	 */
1072 	if ((auth_level < 0) || (autologin != AUTH_VALID))
1073 # endif
1074 	{
1075 		argv = addarg(argv, "-h");
1076 		argv = addarg(argv, host);
1077 	}
1078 #endif /* AUTHENTICATION */
1079 #endif
1080 #if	!defined(NO_LOGIN_P)
1081 	argv = addarg(argv, "-p");
1082 #endif
1083 #ifdef	LINEMODE
1084 	/*
1085 	 * Set the environment variable "LINEMODE" to either
1086 	 * "real" or "kludge" if we are operating in either
1087 	 * real or kludge linemode.
1088 	 */
1089 	if (lmodetype == REAL_LINEMODE) {
1090 		if (setenv("LINEMODE", "real", 1) == -1)
1091 			syslog(LOG_ERR, "setenv: cannot set LINEMODE=real: %m");
1092 	}
1093 # ifdef KLUDGELINEMODE
1094 	else if (lmodetype == KLUDGE_LINEMODE || lmodetype == KLUDGE_OK) {
1095 		if (setenv("LINEMODE", "kludge", 1) == -1)
1096 			syslog(LOG_ERR, "setenv: cannot set LINEMODE=kludge: %m");
1097 	}
1098 # endif
1099 #endif
1100 #ifdef	BFTPDAEMON
1101 	/*
1102 	 * Are we working as the bftp daemon?  If so, then ask login
1103 	 * to start bftp instead of shell.
1104 	 */
1105 	if (bftpd) {
1106 		argv = addarg(argv, "-e");
1107 		argv = addarg(argv, BFTPPATH);
1108 	} else
1109 #endif
1110 #ifdef	AUTHENTICATION
1111 	if (auth_level >= 0 && autologin == AUTH_VALID) {
1112 # if	!defined(NO_LOGIN_F)
1113 		argv = addarg(argv, "-f");
1114 		argv = addarg(argv, "--");
1115 		argv = addarg(argv, name);
1116 # else
1117 #  if defined(LOGIN_R)
1118 		/*
1119 		 * We don't have support for "login -f", but we
1120 		 * can fool /bin/login into thinking that we are
1121 		 * rlogind, and allow us to log in without a
1122 		 * password.  The rlogin protocol expects
1123 		 *	local-user\0remote-user\0term/speed\0
1124 		 */
1125 
1126 		if (pty > 2) {
1127 			char *cp;
1128 			char speed[128];
1129 			int isecho, israw, xpty, len;
1130 			extern int def_rspeed;
1131 #  ifndef LOGIN_HOST
1132 			/*
1133 			 * Tell login that we are coming from "localhost".
1134 			 * If we passed in the real host name, then the
1135 			 * user would have to allow .rhost access from
1136 			 * every machine that they want authenticated
1137 			 * access to work from, which sort of defeats
1138 			 * the purpose of an authenticated login...
1139 			 * So, we tell login that the session is coming
1140 			 * from "localhost", and the user will only have
1141 			 * to have "localhost" in their .rhost file.
1142 			 */
1143 #			define LOGIN_HOST "localhost"
1144 #  endif
1145 			argv = addarg(argv, "-r");
1146 			argv = addarg(argv, LOGIN_HOST);
1147 
1148 			xpty = pty;
1149 			pty = 0;
1150 			init_termbuf();
1151 			isecho = tty_isecho();
1152 			israw = tty_israw();
1153 			if (isecho || !israw) {
1154 				tty_setecho(0);		/* Turn off echo */
1155 				tty_setraw(1);		/* Turn on raw */
1156 				set_termbuf();
1157 			}
1158 			len = strlen(name)+1;
1159 			write(xpty, name, len);
1160 			write(xpty, name, len);
1161 			snprintf(speed, sizeof(speed),
1162 				"%s/%d", (cp = getenv("TERM")) ? cp : "",
1163 				(def_rspeed > 0) ? def_rspeed : 9600);
1164 			len = strlen(speed)+1;
1165 			write(xpty, speed, len);
1166 
1167 			if (isecho || !israw) {
1168 				init_termbuf();
1169 				tty_setecho(isecho);
1170 				tty_setraw(israw);
1171 				set_termbuf();
1172 				if (!israw) {
1173 					/*
1174 					 * Write a newline to ensure
1175 					 * that login will be able to
1176 					 * read the line...
1177 					 */
1178 					write(xpty, "\n", 1);
1179 				}
1180 			}
1181 			pty = xpty;
1182 		}
1183 #  else
1184 		argv = addarg(argv, "--");
1185 		argv = addarg(argv, name);
1186 #  endif
1187 # endif
1188 	} else
1189 #endif
1190 	if (getenv("USER")) {
1191  		argv = addarg(argv, "--");
1192 		argv = addarg(argv, getenv("USER"));
1193 #if	defined(LOGIN_ARGS) && defined(NO_LOGIN_P)
1194 		{
1195 			char **cpp;
1196 			for (cpp = environ; *cpp; cpp++)
1197 				argv = addarg(argv, *cpp);
1198 		}
1199 #endif
1200 		/*
1201 		 * Assume that login will set the USER variable
1202 		 * correctly.  For SysV systems, this means that
1203 		 * USER will no longer be set, just LOGNAME by
1204 		 * login.  (The problem is that if the auto-login
1205 		 * fails, and the user then specifies a different
1206 		 * account name, he can get logged in with both
1207 		 * LOGNAME and USER in his environment, but the
1208 		 * USER value will be wrong.
1209 		 */
1210 		unsetenv("USER");
1211 	}
1212 #ifdef	AUTHENTICATION
1213 #if	defined(NO_LOGIN_F) && defined(LOGIN_R)
1214 	if (pty > 2)
1215 		close(pty);
1216 #endif
1217 #endif /* AUTHENTICATION */
1218 	closelog();
1219 
1220 	if (altlogin == NULL) {
1221 		altlogin = _PATH_LOGIN;
1222 	}
1223 	execv(altlogin, argv);
1224 
1225 	syslog(LOG_ERR, "%s: %m", altlogin);
1226 	fatalperror(net, altlogin);
1227 	/*NOTREACHED*/
1228 }
1229 
1230 static char **
1231 addarg(char **argv, const char *val)
1232 {
1233 	char **cpp;
1234 
1235 	if (argv == NULL) {
1236 		/*
1237 		 * 10 entries, a leading length, and a null
1238 		 */
1239 		argv = (char **)malloc(sizeof(*argv) * 12);
1240 		if (argv == NULL)
1241 			return(NULL);
1242 		*argv++ = (char *)10;
1243 		*argv = NULL;
1244 	}
1245 	for (cpp = argv; *cpp; cpp++)
1246 		;
1247 	if (cpp == &argv[(long)argv[-1]]) {
1248 		--argv;
1249 		*argv = (char *)((long)(*argv) + 10);
1250 		argv = (char **)realloc(argv, sizeof(*argv)*((long)(*argv) + 2));
1251 		if (argv == NULL)
1252 			return(NULL);
1253 		argv++;
1254 		cpp = &argv[(long)argv[-1] - 10];
1255 	}
1256 	*cpp++ = strdup(val);
1257 	*cpp = 0;
1258 	return(argv);
1259 }
1260 
1261 /*
1262  * scrub_env()
1263  *
1264  * We only accept the environment variables listed below.
1265  */
1266 void
1267 scrub_env(void)
1268 {
1269 	static const char *rej[] = {
1270 		"TERMCAP=/",
1271 		NULL
1272 	};
1273 
1274 	static const char *acc[] = {
1275 		"XAUTH=", "XAUTHORITY=", "DISPLAY=",
1276 		"TERM=",
1277 		"EDITOR=",
1278 		"PAGER=",
1279 		"LOGNAME=",
1280 		"POSIXLY_CORRECT=",
1281 		"PRINTER=",
1282 		NULL
1283 	};
1284 
1285 	char **cpp, **cpp2;
1286 	const char **p;
1287 	char ** new_environ;
1288 	size_t count;
1289 
1290 	/* Allocate space for scrubbed environment. */
1291 	for (count = 1, cpp = environ; *cpp; count++, cpp++)
1292 		continue;
1293 	if ((new_environ = malloc(count * sizeof(char *))) == NULL) {
1294 		environ = NULL;
1295 		return;
1296 	}
1297 
1298 	for (cpp2 = new_environ, cpp = environ; *cpp; cpp++) {
1299 		int reject_it = 0;
1300 
1301 		for(p = rej; *p; p++)
1302 			if(strncmp(*cpp, *p, strlen(*p)) == 0) {
1303 				reject_it = 1;
1304 				break;
1305 			}
1306 		if (reject_it)
1307 			continue;
1308 
1309 		for(p = acc; *p; p++)
1310 			if(strncmp(*cpp, *p, strlen(*p)) == 0)
1311 				break;
1312 		if(*p != NULL) {
1313 			if ((*cpp2++ = strdup(*cpp)) == NULL) {
1314 				environ = new_environ;
1315 				return;
1316 			}
1317 		}
1318  	}
1319 	*cpp2 = NULL;
1320 	environ = new_environ;
1321 }
1322 
1323 /*
1324  * cleanup()
1325  *
1326  * This is the routine to call when we are all through, to
1327  * clean up anything that needs to be cleaned up.
1328  */
1329 /* ARGSUSED */
1330 void
1331 cleanup(int sig __unused)
1332 {
1333 	char *p;
1334 	sigset_t mask;
1335 
1336 	p = line + sizeof(_PATH_DEV) - 1;
1337 	/*
1338 	 * Block all signals before clearing the utmp entry.  We don't want to
1339 	 * be called again after calling logout() and then not add the wtmp
1340 	 * entry because of not finding the corresponding entry in utmp.
1341 	 */
1342 	sigfillset(&mask);
1343 	sigprocmask(SIG_SETMASK, &mask, NULL);
1344 	if (logout(p))
1345 		logwtmp(p, "", "");
1346 	(void)chmod(line, 0666);
1347 	(void)chown(line, 0, 0);
1348 	*p = 'p';
1349 	(void)chmod(line, 0666);
1350 	(void)chown(line, 0, 0);
1351 	(void) shutdown(net, SHUT_RDWR);
1352 	_exit(1);
1353 }
1354