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