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