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