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