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