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