sys_term.c revision 275508
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
34#if 0
35#ifndef lint
36static const char sccsid[] = "@(#)sys_term.c	8.4+1 (Berkeley) 5/30/95";
37#endif
38#endif
39#include <sys/cdefs.h>
40__FBSDID("$FreeBSD: stable/10/contrib/telnet/telnetd/sys_term.c 275508 2014-12-05 12:23:29Z ngie $");
41
42#include <sys/types.h>
43#include <sys/tty.h>
44#include <libutil.h>
45#include <stdlib.h>
46
47#include "telnetd.h"
48#include "pathnames.h"
49#include "types.h"
50#include "baud.h"
51
52#ifdef	AUTHENTICATION
53#include <libtelnet/auth.h>
54#endif
55
56int cleanopen(char *);
57void scrub_env(void);
58
59char	*envinit[3];
60extern char **environ;
61
62#define SCPYN(a, b)	(void) strncpy(a, b, sizeof(a))
63#define SCMPN(a, b)	strncmp(a, b, sizeof(a))
64
65#ifdef	t_erase
66#undef	t_erase
67#undef	t_kill
68#undef	t_intrc
69#undef	t_quitc
70#undef	t_startc
71#undef	t_stopc
72#undef	t_eofc
73#undef	t_brkc
74#undef	t_suspc
75#undef	t_dsuspc
76#undef	t_rprntc
77#undef	t_flushc
78#undef	t_werasc
79#undef	t_lnextc
80#endif
81
82#ifndef	USE_TERMIO
83struct termbuf {
84	struct sgttyb sg;
85	struct tchars tc;
86	struct ltchars ltc;
87	int state;
88	int lflags;
89} termbuf, termbuf2;
90# define	cfsetospeed(tp, val)	(tp)->sg.sg_ospeed = (val)
91# define	cfsetispeed(tp, val)	(tp)->sg.sg_ispeed = (val)
92# define	cfgetospeed(tp)		(tp)->sg.sg_ospeed
93# define	cfgetispeed(tp)		(tp)->sg.sg_ispeed
94#else	/* USE_TERMIO */
95# ifndef	TCSANOW
96#  ifdef TCSETS
97#   define	TCSANOW		TCSETS
98#   define	TCSADRAIN	TCSETSW
99#   define	tcgetattr(f, t)	ioctl(f, TCGETS, (char *)t)
100#  else
101#   ifdef TCSETA
102#    define	TCSANOW		TCSETA
103#    define	TCSADRAIN	TCSETAW
104#    define	tcgetattr(f, t)	ioctl(f, TCGETA, (char *)t)
105#   else
106#    define	TCSANOW		TIOCSETA
107#    define	TCSADRAIN	TIOCSETAW
108#    define	tcgetattr(f, t)	ioctl(f, TIOCGETA, (char *)t)
109#   endif
110#  endif
111#  define	tcsetattr(f, a, t)	ioctl(f, a, t)
112#  define	cfsetospeed(tp, val)	(tp)->c_cflag &= ~CBAUD; \
113					(tp)->c_cflag |= (val)
114#  define	cfgetospeed(tp)		((tp)->c_cflag & CBAUD)
115#  ifdef CIBAUD
116#   define	cfsetispeed(tp, val)	(tp)->c_cflag &= ~CIBAUD; \
117					(tp)->c_cflag |= ((val)<<IBSHIFT)
118#   define	cfgetispeed(tp)		(((tp)->c_cflag & CIBAUD)>>IBSHIFT)
119#  else
120#   define	cfsetispeed(tp, val)	(tp)->c_cflag &= ~CBAUD; \
121					(tp)->c_cflag |= (val)
122#   define	cfgetispeed(tp)		((tp)->c_cflag & CBAUD)
123#  endif
124# endif /* TCSANOW */
125struct termios termbuf, termbuf2;	/* pty control structure */
126#endif	/* USE_TERMIO */
127
128#include <sys/types.h>
129#include <libutil.h>
130
131int cleanopen(char *);
132void scrub_env(void);
133static 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
146void
147init_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)
163void
164copy_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
173void
174set_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
210int
211spcset(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 = (cc_t *)0;
272		return(SLC_DEFAULT);
273	default:
274		*valp = (cc_t)0;
275		*valpp = (cc_t *)0;
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 = (cc_t *)0; return(SLC_DEFAULT);
287
288int
289spcset(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 = 0;
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 */
383char line[32];
384
385int
386getpty(int *ptynum __unused)
387{
388	int p;
389	const char *pn;
390
391	p = posix_openpt(O_RDWR|O_NOCTTY);
392	if (p < 0)
393		return (-1);
394
395	if (grantpt(p) == -1)
396		return (-1);
397
398	if (unlockpt(p) == -1)
399		return (-1);
400
401	pn = ptsname(p);
402	if (pn == NULL)
403		return (-1);
404
405	if (strlcpy(line, pn, sizeof line) >= sizeof line)
406		return (-1);
407
408	return (p);
409}
410
411#ifdef	LINEMODE
412/*
413 * tty_flowmode()	Find out if flow control is enabled or disabled.
414 * tty_linemode()	Find out if linemode (external processing) is enabled.
415 * tty_setlinemod(on)	Turn on/off linemode.
416 * tty_isecho()		Find out if echoing is turned on.
417 * tty_setecho(on)	Enable/disable character echoing.
418 * tty_israw()		Find out if terminal is in RAW mode.
419 * tty_binaryin(on)	Turn on/off BINARY on input.
420 * tty_binaryout(on)	Turn on/off BINARY on output.
421 * tty_isediting()	Find out if line editing is enabled.
422 * tty_istrapsig()	Find out if signal trapping is enabled.
423 * tty_setedit(on)	Turn on/off line editing.
424 * tty_setsig(on)	Turn on/off signal trapping.
425 * tty_issofttab()	Find out if tab expansion is enabled.
426 * tty_setsofttab(on)	Turn on/off soft tab expansion.
427 * tty_islitecho()	Find out if typed control chars are echoed literally
428 * tty_setlitecho()	Turn on/off literal echo of control chars
429 * tty_tspeed(val)	Set transmit speed to val.
430 * tty_rspeed(val)	Set receive speed to val.
431 */
432
433
434int
435tty_linemode(void)
436{
437#ifndef	USE_TERMIO
438	return(termbuf.state & TS_EXTPROC);
439#else
440	return(termbuf.c_lflag & EXTPROC);
441#endif
442}
443
444void
445tty_setlinemode(int on)
446{
447#ifdef	TIOCEXT
448	set_termbuf();
449	(void) ioctl(pty, TIOCEXT, (char *)&on);
450	init_termbuf();
451#else	/* !TIOCEXT */
452# ifdef	EXTPROC
453	if (on)
454		termbuf.c_lflag |= EXTPROC;
455	else
456		termbuf.c_lflag &= ~EXTPROC;
457# endif
458#endif	/* TIOCEXT */
459}
460#endif	/* LINEMODE */
461
462int
463tty_isecho(void)
464{
465#ifndef USE_TERMIO
466	return (termbuf.sg.sg_flags & ECHO);
467#else
468	return (termbuf.c_lflag & ECHO);
469#endif
470}
471
472int
473tty_flowmode(void)
474{
475#ifndef USE_TERMIO
476	return(((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0) ? 1 : 0);
477#else
478	return((termbuf.c_iflag & IXON) ? 1 : 0);
479#endif
480}
481
482int
483tty_restartany(void)
484{
485#ifndef USE_TERMIO
486# ifdef	DECCTQ
487	return((termbuf.lflags & DECCTQ) ? 0 : 1);
488# else
489	return(-1);
490# endif
491#else
492	return((termbuf.c_iflag & IXANY) ? 1 : 0);
493#endif
494}
495
496void
497tty_setecho(int on)
498{
499#ifndef	USE_TERMIO
500	if (on)
501		termbuf.sg.sg_flags |= ECHO|CRMOD;
502	else
503		termbuf.sg.sg_flags &= ~(ECHO|CRMOD);
504#else
505	if (on)
506		termbuf.c_lflag |= ECHO;
507	else
508		termbuf.c_lflag &= ~ECHO;
509#endif
510}
511
512int
513tty_israw(void)
514{
515#ifndef USE_TERMIO
516	return(termbuf.sg.sg_flags & RAW);
517#else
518	return(!(termbuf.c_lflag & ICANON));
519#endif
520}
521
522#ifdef	AUTHENTICATION
523#if	defined(NO_LOGIN_F) && defined(LOGIN_R)
524int
525tty_setraw(int on)
526{
527#  ifndef USE_TERMIO
528	if (on)
529		termbuf.sg.sg_flags |= RAW;
530	else
531		termbuf.sg.sg_flags &= ~RAW;
532#  else
533	if (on)
534		termbuf.c_lflag &= ~ICANON;
535	else
536		termbuf.c_lflag |= ICANON;
537#  endif
538}
539#endif
540#endif /* AUTHENTICATION */
541
542void
543tty_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
559void
560tty_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
580int
581tty_isbinaryin(void)
582{
583#ifndef	USE_TERMIO
584	return(termbuf.lflags & LPASS8);
585#else
586	return(!(termbuf.c_iflag & ISTRIP));
587#endif
588}
589
590int
591tty_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
601int
602tty_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
611int
612tty_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
621void
622tty_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
637void
638tty_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
652int
653tty_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
667void
668tty_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
696int
697tty_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
714void
715tty_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
738int
739tty_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
748void
749tty_tspeed(int val)
750{
751#ifdef	DECODE_BAUD
752	struct termspeeds *tp;
753
754	for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
755		;
756	if (tp->speed == -1)	/* back up to last valid value */
757		--tp;
758	cfsetospeed(&termbuf, tp->value);
759#else	/* DECODE_BAUD */
760	cfsetospeed(&termbuf, val);
761#endif	/* DECODE_BAUD */
762}
763
764void
765tty_rspeed(int val)
766{
767#ifdef	DECODE_BAUD
768	struct termspeeds *tp;
769
770	for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
771		;
772	if (tp->speed == -1)	/* back up to last valid value */
773		--tp;
774	cfsetispeed(&termbuf, tp->value);
775#else	/* DECODE_BAUD */
776	cfsetispeed(&termbuf, val);
777#endif	/* DECODE_BAUD */
778}
779
780/*
781 * getptyslave()
782 *
783 * Open the slave side of the pty, and do any initialization
784 * that is necessary.
785 */
786static void
787getptyslave(void)
788{
789	int t = -1;
790	char erase;
791
792# ifdef	LINEMODE
793	int waslm;
794# endif
795# ifdef	TIOCGWINSZ
796	struct winsize ws;
797	extern int def_row, def_col;
798# endif
799	extern int def_tspeed, def_rspeed;
800	/*
801	 * Opening the slave side may cause initilization of the
802	 * kernel tty structure.  We need remember the state of
803	 * 	if linemode was turned on
804	 *	terminal window size
805	 *	terminal speed
806	 *	erase character
807	 * so that we can re-set them if we need to.
808	 */
809# ifdef	LINEMODE
810	waslm = tty_linemode();
811# endif
812	erase = termbuf.c_cc[VERASE];
813
814	/*
815	 * Make sure that we don't have a controlling tty, and
816	 * that we are the session (process group) leader.
817	 */
818# ifdef	TIOCNOTTY
819	t = open(_PATH_TTY, O_RDWR);
820	if (t >= 0) {
821		(void) ioctl(t, TIOCNOTTY, (char *)0);
822		(void) close(t);
823	}
824# endif
825
826	t = cleanopen(line);
827	if (t < 0)
828		fatalperror(net, line);
829
830
831	/*
832	 * set up the tty modes as we like them to be.
833	 */
834	init_termbuf();
835# ifdef	TIOCGWINSZ
836	if (def_row || def_col) {
837		memset((char *)&ws, 0, sizeof(ws));
838		ws.ws_col = def_col;
839		ws.ws_row = def_row;
840		(void)ioctl(t, TIOCSWINSZ, (char *)&ws);
841	}
842# endif
843
844	/*
845	 * Settings for sgtty based systems
846	 */
847# ifndef	USE_TERMIO
848	termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS;
849# endif	/* USE_TERMIO */
850
851	/*
852	 * Settings for all other termios/termio based
853	 * systems, other than 4.4BSD.  In 4.4BSD the
854	 * kernel does the initial terminal setup.
855	 */
856	tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);
857	tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);
858	if (erase)
859		termbuf.c_cc[VERASE] = erase;
860# ifdef	LINEMODE
861	if (waslm)
862		tty_setlinemode(1);
863# endif	/* LINEMODE */
864
865	/*
866	 * Set the tty modes, and make this our controlling tty.
867	 */
868	set_termbuf();
869	if (login_tty(t) == -1)
870		fatalperror(net, "login_tty");
871	if (net > 2)
872		(void) close(net);
873#ifdef	AUTHENTICATION
874#if	defined(NO_LOGIN_F) && defined(LOGIN_R)
875	/*
876	 * Leave the pty open so that we can write out the rlogin
877	 * protocol for /bin/login, if the authentication works.
878	 */
879#else
880	if (pty > 2) {
881		(void) close(pty);
882		pty = -1;
883	}
884#endif
885#endif /* AUTHENTICATION */
886}
887
888#ifndef	O_NOCTTY
889#define	O_NOCTTY	0
890#endif
891/*
892 * Open the specified slave side of the pty,
893 * making sure that we have a clean tty.
894 */
895int
896cleanopen(char *li)
897{
898	int t;
899
900	/*
901	 * Make sure that other people can't open the
902	 * slave side of the connection.
903	 */
904	(void) chown(li, 0, 0);
905	(void) chmod(li, 0600);
906
907	(void) revoke(li);
908
909	t = open(line, O_RDWR|O_NOCTTY);
910
911	if (t < 0)
912		return(-1);
913
914	return(t);
915}
916
917/*
918 * startslave(host)
919 *
920 * Given a hostname, do whatever
921 * is necessary to startup the login process on the slave side of the pty.
922 */
923
924/* ARGSUSED */
925void
926startslave(char *host, int autologin, char *autoname)
927{
928	int i;
929
930#ifdef	AUTHENTICATION
931	if (!autoname || !autoname[0])
932		autologin = 0;
933
934	if (autologin < auth_level) {
935		fatal(net, "Authorization failed");
936		exit(1);
937	}
938#endif
939
940
941	if ((i = fork()) < 0)
942		fatalperror(net, "fork");
943	if (i) {
944	} else {
945		getptyslave();
946		start_login(host, autologin, autoname);
947		/*NOTREACHED*/
948	}
949}
950
951void
952init_env(void)
953{
954	char **envp;
955
956	envp = envinit;
957	if ((*envp = getenv("TZ")))
958		*envp++ -= 3;
959	*envp = 0;
960	environ = envinit;
961}
962
963
964/*
965 * start_login(host)
966 *
967 * Assuming that we are now running as a child processes, this
968 * function will turn us into the login process.
969 */
970
971#ifndef AUTHENTICATION
972#define undef1 __unused
973#else
974#define undef1
975#endif
976
977void
978start_login(char *host undef1, int autologin undef1, char *name undef1)
979{
980	char **argv;
981	char *user;
982
983	user = getenv("USER");
984	user = (user != NULL) ? strdup(user) : NULL;
985
986	scrub_env();
987
988	/*
989	 * -h : pass on name of host.
990	 *		WARNING:  -h is accepted by login if and only if
991	 *			getuid() == 0.
992	 * -p : don't clobber the environment (so terminal type stays set).
993	 *
994	 * -f : force this login, he has already been authenticated
995	 */
996	argv = addarg(0, "login");
997
998#if	!defined(NO_LOGIN_H)
999#ifdef	AUTHENTICATION
1000# if	defined(NO_LOGIN_F) && defined(LOGIN_R)
1001	/*
1002	 * Don't add the "-h host" option if we are going
1003	 * to be adding the "-r host" option down below...
1004	 */
1005	if ((auth_level < 0) || (autologin != AUTH_VALID))
1006# endif
1007	{
1008		argv = addarg(argv, "-h");
1009		argv = addarg(argv, host);
1010	}
1011#endif /* AUTHENTICATION */
1012#endif
1013#if	!defined(NO_LOGIN_P)
1014	argv = addarg(argv, "-p");
1015#endif
1016#ifdef	LINEMODE
1017	/*
1018	 * Set the environment variable "LINEMODE" to either
1019	 * "real" or "kludge" if we are operating in either
1020	 * real or kludge linemode.
1021	 */
1022	if (lmodetype == REAL_LINEMODE)
1023		setenv("LINEMODE", "real", 1);
1024# ifdef KLUDGELINEMODE
1025	else if (lmodetype == KLUDGE_LINEMODE || lmodetype == KLUDGE_OK)
1026		setenv("LINEMODE", "kludge", 1);
1027# endif
1028#endif
1029#ifdef	BFTPDAEMON
1030	/*
1031	 * Are we working as the bftp daemon?  If so, then ask login
1032	 * to start bftp instead of shell.
1033	 */
1034	if (bftpd) {
1035		argv = addarg(argv, "-e");
1036		argv = addarg(argv, BFTPPATH);
1037	} else
1038#endif
1039#ifdef	AUTHENTICATION
1040	if (auth_level >= 0 && autologin == AUTH_VALID) {
1041# if	!defined(NO_LOGIN_F)
1042		argv = addarg(argv, "-f");
1043		argv = addarg(argv, "--");
1044		argv = addarg(argv, name);
1045# else
1046#  if defined(LOGIN_R)
1047		/*
1048		 * We don't have support for "login -f", but we
1049		 * can fool /bin/login into thinking that we are
1050		 * rlogind, and allow us to log in without a
1051		 * password.  The rlogin protocol expects
1052		 *	local-user\0remote-user\0term/speed\0
1053		 */
1054
1055		if (pty > 2) {
1056			char *cp;
1057			char speed[128];
1058			int isecho, israw, xpty, len;
1059			extern int def_rspeed;
1060#  ifndef LOGIN_HOST
1061			/*
1062			 * Tell login that we are coming from "localhost".
1063			 * If we passed in the real host name, then the
1064			 * user would have to allow .rhost access from
1065			 * every machine that they want authenticated
1066			 * access to work from, which sort of defeats
1067			 * the purpose of an authenticated login...
1068			 * So, we tell login that the session is coming
1069			 * from "localhost", and the user will only have
1070			 * to have "localhost" in their .rhost file.
1071			 */
1072#			define LOGIN_HOST "localhost"
1073#  endif
1074			argv = addarg(argv, "-r");
1075			argv = addarg(argv, LOGIN_HOST);
1076
1077			xpty = pty;
1078			pty = 0;
1079			init_termbuf();
1080			isecho = tty_isecho();
1081			israw = tty_israw();
1082			if (isecho || !israw) {
1083				tty_setecho(0);		/* Turn off echo */
1084				tty_setraw(1);		/* Turn on raw */
1085				set_termbuf();
1086			}
1087			len = strlen(name)+1;
1088			write(xpty, name, len);
1089			write(xpty, name, len);
1090			snprintf(speed, sizeof(speed),
1091				"%s/%d", (cp = getenv("TERM")) ? cp : "",
1092				(def_rspeed > 0) ? def_rspeed : 9600);
1093			len = strlen(speed)+1;
1094			write(xpty, speed, len);
1095
1096			if (isecho || !israw) {
1097				init_termbuf();
1098				tty_setecho(isecho);
1099				tty_setraw(israw);
1100				set_termbuf();
1101				if (!israw) {
1102					/*
1103					 * Write a newline to ensure
1104					 * that login will be able to
1105					 * read the line...
1106					 */
1107					write(xpty, "\n", 1);
1108				}
1109			}
1110			pty = xpty;
1111		}
1112#  else
1113		argv = addarg(argv, "--");
1114		argv = addarg(argv, name);
1115#  endif
1116# endif
1117	} else
1118#endif
1119	if (user != NULL) {
1120 		argv = addarg(argv, "--");
1121		argv = addarg(argv, user);
1122#if	defined(LOGIN_ARGS) && defined(NO_LOGIN_P)
1123		{
1124			char **cpp;
1125			for (cpp = environ; *cpp; cpp++)
1126				argv = addarg(argv, *cpp);
1127		}
1128#endif
1129	}
1130#ifdef	AUTHENTICATION
1131#if	defined(NO_LOGIN_F) && defined(LOGIN_R)
1132	if (pty > 2)
1133		close(pty);
1134#endif
1135#endif /* AUTHENTICATION */
1136	closelog();
1137
1138	if (user != NULL)
1139		free(user);
1140
1141	if (altlogin == NULL) {
1142		altlogin = _PATH_LOGIN;
1143	}
1144	execv(altlogin, argv);
1145
1146	syslog(LOG_ERR, "%s: %m", altlogin);
1147	fatalperror(net, altlogin);
1148	/*NOTREACHED*/
1149}
1150
1151static char **
1152addarg(char **argv, const char *val)
1153{
1154	char **cpp;
1155
1156	if (argv == NULL) {
1157		/*
1158		 * 10 entries, a leading length, and a null
1159		 */
1160		argv = (char **)malloc(sizeof(*argv) * 12);
1161		if (argv == NULL)
1162			return(NULL);
1163		*argv++ = (char *)10;
1164		*argv = (char *)0;
1165	}
1166	for (cpp = argv; *cpp; cpp++)
1167		;
1168	if (cpp == &argv[(long)argv[-1]]) {
1169		--argv;
1170		*argv = (char *)((long)(*argv) + 10);
1171		argv = (char **)realloc(argv, sizeof(*argv)*((long)(*argv) + 2));
1172		if (argv == NULL)
1173			return(NULL);
1174		argv++;
1175		cpp = &argv[(long)argv[-1] - 10];
1176	}
1177	*cpp++ = strdup(val);
1178	*cpp = 0;
1179	return(argv);
1180}
1181
1182/*
1183 * scrub_env()
1184 *
1185 * We only accept the environment variables listed below.
1186 */
1187void
1188scrub_env(void)
1189{
1190	static const char *rej[] = {
1191		"TERMCAP=/",
1192		NULL
1193	};
1194
1195	static const char *acc[] = {
1196		"XAUTH=", "XAUTHORITY=", "DISPLAY=",
1197		"TERM=",
1198		"EDITOR=",
1199		"PAGER=",
1200		"LOGNAME=",
1201		"POSIXLY_CORRECT=",
1202		"PRINTER=",
1203		NULL
1204	};
1205
1206	char **cpp, **cpp2;
1207	const char **p;
1208	char ** new_environ;
1209	size_t count;
1210
1211	/* Allocate space for scrubbed environment. */
1212	for (count = 1, cpp = environ; *cpp; count++, cpp++)
1213		continue;
1214	if ((new_environ = malloc(count * sizeof(char *))) == NULL) {
1215		environ = NULL;
1216		return;
1217	}
1218
1219 	for (cpp2 = new_environ, cpp = environ; *cpp; cpp++) {
1220		int reject_it = 0;
1221
1222		for(p = rej; *p; p++)
1223			if(strncmp(*cpp, *p, strlen(*p)) == 0) {
1224				reject_it = 1;
1225				break;
1226			}
1227		if (reject_it)
1228			continue;
1229
1230		for(p = acc; *p; p++)
1231			if(strncmp(*cpp, *p, strlen(*p)) == 0)
1232				break;
1233		if(*p != NULL) {
1234			if ((*cpp2++ = strdup(*cpp)) == NULL) {
1235				environ = new_environ;
1236				return;
1237			}
1238		}
1239 	}
1240	*cpp2 = NULL;
1241	environ = new_environ;
1242}
1243
1244/*
1245 * cleanup()
1246 *
1247 * This is the routine to call when we are all through, to
1248 * clean up anything that needs to be cleaned up.
1249 */
1250/* ARGSUSED */
1251void
1252cleanup(int sig __unused)
1253{
1254
1255	(void) shutdown(net, SHUT_RDWR);
1256	_exit(1);
1257}
1258