sys_term.c revision 184935
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 184935 2008-11-13 19:05:27Z 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	strcpy(line, pn);
418
419	return (p);
420}
421
422#ifdef	LINEMODE
423/*
424 * tty_flowmode()	Find out if flow control is enabled or disabled.
425 * tty_linemode()	Find out if linemode (external processing) is enabled.
426 * tty_setlinemod(on)	Turn on/off linemode.
427 * tty_isecho()		Find out if echoing is turned on.
428 * tty_setecho(on)	Enable/disable character echoing.
429 * tty_israw()		Find out if terminal is in RAW mode.
430 * tty_binaryin(on)	Turn on/off BINARY on input.
431 * tty_binaryout(on)	Turn on/off BINARY on output.
432 * tty_isediting()	Find out if line editing is enabled.
433 * tty_istrapsig()	Find out if signal trapping is enabled.
434 * tty_setedit(on)	Turn on/off line editing.
435 * tty_setsig(on)	Turn on/off signal trapping.
436 * tty_issofttab()	Find out if tab expansion is enabled.
437 * tty_setsofttab(on)	Turn on/off soft tab expansion.
438 * tty_islitecho()	Find out if typed control chars are echoed literally
439 * tty_setlitecho()	Turn on/off literal echo of control chars
440 * tty_tspeed(val)	Set transmit speed to val.
441 * tty_rspeed(val)	Set receive speed to val.
442 */
443
444
445int
446tty_linemode(void)
447{
448#ifndef	USE_TERMIO
449	return(termbuf.state & TS_EXTPROC);
450#else
451	return(termbuf.c_lflag & EXTPROC);
452#endif
453}
454
455void
456tty_setlinemode(int on)
457{
458#ifdef	TIOCEXT
459	set_termbuf();
460	(void) ioctl(pty, TIOCEXT, (char *)&on);
461	init_termbuf();
462#else	/* !TIOCEXT */
463# ifdef	EXTPROC
464	if (on)
465		termbuf.c_lflag |= EXTPROC;
466	else
467		termbuf.c_lflag &= ~EXTPROC;
468# endif
469#endif	/* TIOCEXT */
470}
471#endif	/* LINEMODE */
472
473int
474tty_isecho(void)
475{
476#ifndef USE_TERMIO
477	return (termbuf.sg.sg_flags & ECHO);
478#else
479	return (termbuf.c_lflag & ECHO);
480#endif
481}
482
483int
484tty_flowmode(void)
485{
486#ifndef USE_TERMIO
487	return(((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0) ? 1 : 0);
488#else
489	return((termbuf.c_iflag & IXON) ? 1 : 0);
490#endif
491}
492
493int
494tty_restartany(void)
495{
496#ifndef USE_TERMIO
497# ifdef	DECCTQ
498	return((termbuf.lflags & DECCTQ) ? 0 : 1);
499# else
500	return(-1);
501# endif
502#else
503	return((termbuf.c_iflag & IXANY) ? 1 : 0);
504#endif
505}
506
507void
508tty_setecho(int on)
509{
510#ifndef	USE_TERMIO
511	if (on)
512		termbuf.sg.sg_flags |= ECHO|CRMOD;
513	else
514		termbuf.sg.sg_flags &= ~(ECHO|CRMOD);
515#else
516	if (on)
517		termbuf.c_lflag |= ECHO;
518	else
519		termbuf.c_lflag &= ~ECHO;
520#endif
521}
522
523int
524tty_israw(void)
525{
526#ifndef USE_TERMIO
527	return(termbuf.sg.sg_flags & RAW);
528#else
529	return(!(termbuf.c_lflag & ICANON));
530#endif
531}
532
533#ifdef	AUTHENTICATION
534#if	defined(NO_LOGIN_F) && defined(LOGIN_R)
535int
536tty_setraw(int on)
537{
538#  ifndef USE_TERMIO
539	if (on)
540		termbuf.sg.sg_flags |= RAW;
541	else
542		termbuf.sg.sg_flags &= ~RAW;
543#  else
544	if (on)
545		termbuf.c_lflag &= ~ICANON;
546	else
547		termbuf.c_lflag |= ICANON;
548#  endif
549}
550#endif
551#endif /* AUTHENTICATION */
552
553void
554tty_binaryin(int on)
555{
556#ifndef	USE_TERMIO
557	if (on)
558		termbuf.lflags |= LPASS8;
559	else
560		termbuf.lflags &= ~LPASS8;
561#else
562	if (on) {
563		termbuf.c_iflag &= ~ISTRIP;
564	} else {
565		termbuf.c_iflag |= ISTRIP;
566	}
567#endif
568}
569
570void
571tty_binaryout(int on)
572{
573#ifndef	USE_TERMIO
574	if (on)
575		termbuf.lflags |= LLITOUT;
576	else
577		termbuf.lflags &= ~LLITOUT;
578#else
579	if (on) {
580		termbuf.c_cflag &= ~(CSIZE|PARENB);
581		termbuf.c_cflag |= CS8;
582		termbuf.c_oflag &= ~OPOST;
583	} else {
584		termbuf.c_cflag &= ~CSIZE;
585		termbuf.c_cflag |= CS7|PARENB;
586		termbuf.c_oflag |= OPOST;
587	}
588#endif
589}
590
591int
592tty_isbinaryin(void)
593{
594#ifndef	USE_TERMIO
595	return(termbuf.lflags & LPASS8);
596#else
597	return(!(termbuf.c_iflag & ISTRIP));
598#endif
599}
600
601int
602tty_isbinaryout(void)
603{
604#ifndef	USE_TERMIO
605	return(termbuf.lflags & LLITOUT);
606#else
607	return(!(termbuf.c_oflag&OPOST));
608#endif
609}
610
611#ifdef	LINEMODE
612int
613tty_isediting(void)
614{
615#ifndef USE_TERMIO
616	return(!(termbuf.sg.sg_flags & (CBREAK|RAW)));
617#else
618	return(termbuf.c_lflag & ICANON);
619#endif
620}
621
622int
623tty_istrapsig(void)
624{
625#ifndef USE_TERMIO
626	return(!(termbuf.sg.sg_flags&RAW));
627#else
628	return(termbuf.c_lflag & ISIG);
629#endif
630}
631
632void
633tty_setedit(int on)
634{
635#ifndef USE_TERMIO
636	if (on)
637		termbuf.sg.sg_flags &= ~CBREAK;
638	else
639		termbuf.sg.sg_flags |= CBREAK;
640#else
641	if (on)
642		termbuf.c_lflag |= ICANON;
643	else
644		termbuf.c_lflag &= ~ICANON;
645#endif
646}
647
648void
649tty_setsig(int on)
650{
651#ifndef	USE_TERMIO
652	if (on)
653		;
654#else
655	if (on)
656		termbuf.c_lflag |= ISIG;
657	else
658		termbuf.c_lflag &= ~ISIG;
659#endif
660}
661#endif	/* LINEMODE */
662
663int
664tty_issofttab(void)
665{
666#ifndef	USE_TERMIO
667	return (termbuf.sg.sg_flags & XTABS);
668#else
669# ifdef	OXTABS
670	return (termbuf.c_oflag & OXTABS);
671# endif
672# ifdef	TABDLY
673	return ((termbuf.c_oflag & TABDLY) == TAB3);
674# endif
675#endif
676}
677
678void
679tty_setsofttab(int on)
680{
681#ifndef	USE_TERMIO
682	if (on)
683		termbuf.sg.sg_flags |= XTABS;
684	else
685		termbuf.sg.sg_flags &= ~XTABS;
686#else
687	if (on) {
688# ifdef	OXTABS
689		termbuf.c_oflag |= OXTABS;
690# endif
691# ifdef	TABDLY
692		termbuf.c_oflag &= ~TABDLY;
693		termbuf.c_oflag |= TAB3;
694# endif
695	} else {
696# ifdef	OXTABS
697		termbuf.c_oflag &= ~OXTABS;
698# endif
699# ifdef	TABDLY
700		termbuf.c_oflag &= ~TABDLY;
701		termbuf.c_oflag |= TAB0;
702# endif
703	}
704#endif
705}
706
707int
708tty_islitecho(void)
709{
710#ifndef	USE_TERMIO
711	return (!(termbuf.lflags & LCTLECH));
712#else
713# ifdef	ECHOCTL
714	return (!(termbuf.c_lflag & ECHOCTL));
715# endif
716# ifdef	TCTLECH
717	return (!(termbuf.c_lflag & TCTLECH));
718# endif
719# if	!defined(ECHOCTL) && !defined(TCTLECH)
720	return (0);	/* assumes ctl chars are echoed '^x' */
721# endif
722#endif
723}
724
725void
726tty_setlitecho(int on)
727{
728#ifndef	USE_TERMIO
729	if (on)
730		termbuf.lflags &= ~LCTLECH;
731	else
732		termbuf.lflags |= LCTLECH;
733#else
734# ifdef	ECHOCTL
735	if (on)
736		termbuf.c_lflag &= ~ECHOCTL;
737	else
738		termbuf.c_lflag |= ECHOCTL;
739# endif
740# ifdef	TCTLECH
741	if (on)
742		termbuf.c_lflag &= ~TCTLECH;
743	else
744		termbuf.c_lflag |= TCTLECH;
745# endif
746#endif
747}
748
749int
750tty_iscrnl(void)
751{
752#ifndef	USE_TERMIO
753	return (termbuf.sg.sg_flags & CRMOD);
754#else
755	return (termbuf.c_iflag & ICRNL);
756#endif
757}
758
759/*
760 * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
761 */
762#if B4800 != 4800
763#define	DECODE_BAUD
764#endif
765
766#ifdef	DECODE_BAUD
767
768/*
769 * A table of available terminal speeds
770 */
771struct termspeeds {
772	int	speed;
773	int	value;
774} termspeeds[] = {
775	{ 0,      B0 },      { 50,    B50 },    { 75,     B75 },
776	{ 110,    B110 },    { 134,   B134 },   { 150,    B150 },
777	{ 200,    B200 },    { 300,   B300 },   { 600,    B600 },
778	{ 1200,   B1200 },   { 1800,  B1800 },  { 2400,   B2400 },
779	{ 4800,   B4800 },
780#ifdef	B7200
781	{ 7200,  B7200 },
782#endif
783	{ 9600,   B9600 },
784#ifdef	B14400
785	{ 14400,  B14400 },
786#endif
787#ifdef	B19200
788	{ 19200,  B19200 },
789#endif
790#ifdef	B28800
791	{ 28800,  B28800 },
792#endif
793#ifdef	B38400
794	{ 38400,  B38400 },
795#endif
796#ifdef	B57600
797	{ 57600,  B57600 },
798#endif
799#ifdef	B115200
800	{ 115200, B115200 },
801#endif
802#ifdef	B230400
803	{ 230400, B230400 },
804#endif
805	{ -1,     0 }
806};
807#endif	/* DECODE_BAUD */
808
809void
810tty_tspeed(int val)
811{
812#ifdef	DECODE_BAUD
813	struct termspeeds *tp;
814
815	for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
816		;
817	if (tp->speed == -1)	/* back up to last valid value */
818		--tp;
819	cfsetospeed(&termbuf, tp->value);
820#else	/* DECODE_BAUD */
821	cfsetospeed(&termbuf, val);
822#endif	/* DECODE_BAUD */
823}
824
825void
826tty_rspeed(int val)
827{
828#ifdef	DECODE_BAUD
829	struct termspeeds *tp;
830
831	for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
832		;
833	if (tp->speed == -1)	/* back up to last valid value */
834		--tp;
835	cfsetispeed(&termbuf, tp->value);
836#else	/* DECODE_BAUD */
837	cfsetispeed(&termbuf, val);
838#endif	/* DECODE_BAUD */
839}
840
841/*
842 * getptyslave()
843 *
844 * Open the slave side of the pty, and do any initialization
845 * that is necessary.
846 */
847static void
848getptyslave(void)
849{
850	int t = -1;
851	char erase;
852
853# ifdef	LINEMODE
854	int waslm;
855# endif
856# ifdef	TIOCGWINSZ
857	struct winsize ws;
858	extern int def_row, def_col;
859# endif
860	extern int def_tspeed, def_rspeed;
861	/*
862	 * Opening the slave side may cause initilization of the
863	 * kernel tty structure.  We need remember the state of
864	 * 	if linemode was turned on
865	 *	terminal window size
866	 *	terminal speed
867	 *	erase character
868	 * so that we can re-set them if we need to.
869	 */
870# ifdef	LINEMODE
871	waslm = tty_linemode();
872# endif
873	erase = termbuf.c_cc[VERASE];
874
875	/*
876	 * Make sure that we don't have a controlling tty, and
877	 * that we are the session (process group) leader.
878	 */
879# ifdef	TIOCNOTTY
880	t = open(_PATH_TTY, O_RDWR);
881	if (t >= 0) {
882		(void) ioctl(t, TIOCNOTTY, (char *)0);
883		(void) close(t);
884	}
885# endif
886
887	t = cleanopen(line);
888	if (t < 0)
889		fatalperror(net, line);
890
891
892	/*
893	 * set up the tty modes as we like them to be.
894	 */
895	init_termbuf();
896# ifdef	TIOCGWINSZ
897	if (def_row || def_col) {
898		memset((char *)&ws, 0, sizeof(ws));
899		ws.ws_col = def_col;
900		ws.ws_row = def_row;
901		(void)ioctl(t, TIOCSWINSZ, (char *)&ws);
902	}
903# endif
904
905	/*
906	 * Settings for sgtty based systems
907	 */
908# ifndef	USE_TERMIO
909	termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS;
910# endif	/* USE_TERMIO */
911
912	/*
913	 * Settings for all other termios/termio based
914	 * systems, other than 4.4BSD.  In 4.4BSD the
915	 * kernel does the initial terminal setup.
916	 */
917	tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);
918	tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);
919	if (erase)
920		termbuf.c_cc[VERASE] = erase;
921# ifdef	LINEMODE
922	if (waslm)
923		tty_setlinemode(1);
924# endif	/* LINEMODE */
925
926	/*
927	 * Set the tty modes, and make this our controlling tty.
928	 */
929	set_termbuf();
930	if (login_tty(t) == -1)
931		fatalperror(net, "login_tty");
932	if (net > 2)
933		(void) close(net);
934#ifdef	AUTHENTICATION
935#if	defined(NO_LOGIN_F) && defined(LOGIN_R)
936	/*
937	 * Leave the pty open so that we can write out the rlogin
938	 * protocol for /bin/login, if the authentication works.
939	 */
940#else
941	if (pty > 2) {
942		(void) close(pty);
943		pty = -1;
944	}
945#endif
946#endif /* AUTHENTICATION */
947}
948
949#ifndef	O_NOCTTY
950#define	O_NOCTTY	0
951#endif
952/*
953 * Open the specified slave side of the pty,
954 * making sure that we have a clean tty.
955 */
956int
957cleanopen(char *li)
958{
959	int t;
960
961	/*
962	 * Make sure that other people can't open the
963	 * slave side of the connection.
964	 */
965	(void) chown(li, 0, 0);
966	(void) chmod(li, 0600);
967
968	(void) revoke(li);
969
970	t = open(line, O_RDWR|O_NOCTTY);
971
972	if (t < 0)
973		return(-1);
974
975	return(t);
976}
977
978/*
979 * startslave(host)
980 *
981 * Given a hostname, do whatever
982 * is necessary to startup the login process on the slave side of the pty.
983 */
984
985/* ARGSUSED */
986void
987startslave(char *host, int autologin, char *autoname)
988{
989	int i;
990
991#ifdef	AUTHENTICATION
992	if (!autoname || !autoname[0])
993		autologin = 0;
994
995	if (autologin < auth_level) {
996		fatal(net, "Authorization failed");
997		exit(1);
998	}
999#endif
1000
1001
1002	if ((i = fork()) < 0)
1003		fatalperror(net, "fork");
1004	if (i) {
1005	} else {
1006		getptyslave();
1007		start_login(host, autologin, autoname);
1008		/*NOTREACHED*/
1009	}
1010}
1011
1012void
1013init_env(void)
1014{
1015	char **envp;
1016
1017	envp = envinit;
1018	if ((*envp = getenv("TZ")))
1019		*envp++ -= 3;
1020	*envp = 0;
1021	environ = envinit;
1022}
1023
1024
1025/*
1026 * start_login(host)
1027 *
1028 * Assuming that we are now running as a child processes, this
1029 * function will turn us into the login process.
1030 */
1031
1032#ifndef AUTHENTICATION
1033#define undef1 __unused
1034#else
1035#define undef1
1036#endif
1037
1038void
1039start_login(char *host undef1, int autologin undef1, char *name undef1)
1040{
1041	char **argv;
1042
1043	scrub_env();
1044
1045	/*
1046	 * -h : pass on name of host.
1047	 *		WARNING:  -h is accepted by login if and only if
1048	 *			getuid() == 0.
1049	 * -p : don't clobber the environment (so terminal type stays set).
1050	 *
1051	 * -f : force this login, he has already been authenticated
1052	 */
1053	argv = addarg(0, "login");
1054
1055#if	!defined(NO_LOGIN_H)
1056#ifdef	AUTHENTICATION
1057# if	defined(NO_LOGIN_F) && defined(LOGIN_R)
1058	/*
1059	 * Don't add the "-h host" option if we are going
1060	 * to be adding the "-r host" option down below...
1061	 */
1062	if ((auth_level < 0) || (autologin != AUTH_VALID))
1063# endif
1064	{
1065		argv = addarg(argv, "-h");
1066		argv = addarg(argv, host);
1067	}
1068#endif /* AUTHENTICATION */
1069#endif
1070#if	!defined(NO_LOGIN_P)
1071	argv = addarg(argv, "-p");
1072#endif
1073#ifdef	LINEMODE
1074	/*
1075	 * Set the environment variable "LINEMODE" to either
1076	 * "real" or "kludge" if we are operating in either
1077	 * real or kludge linemode.
1078	 */
1079	if (lmodetype == REAL_LINEMODE)
1080		setenv("LINEMODE", "real", 1);
1081# ifdef KLUDGELINEMODE
1082	else if (lmodetype == KLUDGE_LINEMODE || lmodetype == KLUDGE_OK)
1083		setenv("LINEMODE", "kludge", 1);
1084# endif
1085#endif
1086#ifdef	BFTPDAEMON
1087	/*
1088	 * Are we working as the bftp daemon?  If so, then ask login
1089	 * to start bftp instead of shell.
1090	 */
1091	if (bftpd) {
1092		argv = addarg(argv, "-e");
1093		argv = addarg(argv, BFTPPATH);
1094	} else
1095#endif
1096#ifdef	AUTHENTICATION
1097	if (auth_level >= 0 && autologin == AUTH_VALID) {
1098# if	!defined(NO_LOGIN_F)
1099		argv = addarg(argv, "-f");
1100		argv = addarg(argv, "--");
1101		argv = addarg(argv, name);
1102# else
1103#  if defined(LOGIN_R)
1104		/*
1105		 * We don't have support for "login -f", but we
1106		 * can fool /bin/login into thinking that we are
1107		 * rlogind, and allow us to log in without a
1108		 * password.  The rlogin protocol expects
1109		 *	local-user\0remote-user\0term/speed\0
1110		 */
1111
1112		if (pty > 2) {
1113			char *cp;
1114			char speed[128];
1115			int isecho, israw, xpty, len;
1116			extern int def_rspeed;
1117#  ifndef LOGIN_HOST
1118			/*
1119			 * Tell login that we are coming from "localhost".
1120			 * If we passed in the real host name, then the
1121			 * user would have to allow .rhost access from
1122			 * every machine that they want authenticated
1123			 * access to work from, which sort of defeats
1124			 * the purpose of an authenticated login...
1125			 * So, we tell login that the session is coming
1126			 * from "localhost", and the user will only have
1127			 * to have "localhost" in their .rhost file.
1128			 */
1129#			define LOGIN_HOST "localhost"
1130#  endif
1131			argv = addarg(argv, "-r");
1132			argv = addarg(argv, LOGIN_HOST);
1133
1134			xpty = pty;
1135			pty = 0;
1136			init_termbuf();
1137			isecho = tty_isecho();
1138			israw = tty_israw();
1139			if (isecho || !israw) {
1140				tty_setecho(0);		/* Turn off echo */
1141				tty_setraw(1);		/* Turn on raw */
1142				set_termbuf();
1143			}
1144			len = strlen(name)+1;
1145			write(xpty, name, len);
1146			write(xpty, name, len);
1147			snprintf(speed, sizeof(speed),
1148				"%s/%d", (cp = getenv("TERM")) ? cp : "",
1149				(def_rspeed > 0) ? def_rspeed : 9600);
1150			len = strlen(speed)+1;
1151			write(xpty, speed, len);
1152
1153			if (isecho || !israw) {
1154				init_termbuf();
1155				tty_setecho(isecho);
1156				tty_setraw(israw);
1157				set_termbuf();
1158				if (!israw) {
1159					/*
1160					 * Write a newline to ensure
1161					 * that login will be able to
1162					 * read the line...
1163					 */
1164					write(xpty, "\n", 1);
1165				}
1166			}
1167			pty = xpty;
1168		}
1169#  else
1170		argv = addarg(argv, "--");
1171		argv = addarg(argv, name);
1172#  endif
1173# endif
1174	} else
1175#endif
1176	if (getenv("USER")) {
1177 		argv = addarg(argv, "--");
1178		argv = addarg(argv, getenv("USER"));
1179#if	defined(LOGIN_ARGS) && defined(NO_LOGIN_P)
1180		{
1181			char **cpp;
1182			for (cpp = environ; *cpp; cpp++)
1183				argv = addarg(argv, *cpp);
1184		}
1185#endif
1186		/*
1187		 * Assume that login will set the USER variable
1188		 * correctly.  For SysV systems, this means that
1189		 * USER will no longer be set, just LOGNAME by
1190		 * login.  (The problem is that if the auto-login
1191		 * fails, and the user then specifies a different
1192		 * account name, he can get logged in with both
1193		 * LOGNAME and USER in his environment, but the
1194		 * USER value will be wrong.
1195		 */
1196		unsetenv("USER");
1197	}
1198#ifdef	AUTHENTICATION
1199#if	defined(NO_LOGIN_F) && defined(LOGIN_R)
1200	if (pty > 2)
1201		close(pty);
1202#endif
1203#endif /* AUTHENTICATION */
1204	closelog();
1205
1206	if (altlogin == NULL) {
1207		altlogin = _PATH_LOGIN;
1208	}
1209	execv(altlogin, argv);
1210
1211	syslog(LOG_ERR, "%s: %m", altlogin);
1212	fatalperror(net, altlogin);
1213	/*NOTREACHED*/
1214}
1215
1216static char **
1217addarg(char **argv, const char *val)
1218{
1219	char **cpp;
1220
1221	if (argv == NULL) {
1222		/*
1223		 * 10 entries, a leading length, and a null
1224		 */
1225		argv = (char **)malloc(sizeof(*argv) * 12);
1226		if (argv == NULL)
1227			return(NULL);
1228		*argv++ = (char *)10;
1229		*argv = (char *)0;
1230	}
1231	for (cpp = argv; *cpp; cpp++)
1232		;
1233	if (cpp == &argv[(long)argv[-1]]) {
1234		--argv;
1235		*argv = (char *)((long)(*argv) + 10);
1236		argv = (char **)realloc(argv, sizeof(*argv)*((long)(*argv) + 2));
1237		if (argv == NULL)
1238			return(NULL);
1239		argv++;
1240		cpp = &argv[(long)argv[-1] - 10];
1241	}
1242	*cpp++ = strdup(val);
1243	*cpp = 0;
1244	return(argv);
1245}
1246
1247/*
1248 * scrub_env()
1249 *
1250 * We only accept the environment variables listed below.
1251 */
1252void
1253scrub_env(void)
1254{
1255	static const char *rej[] = {
1256		"TERMCAP=/",
1257		NULL
1258	};
1259
1260	static const char *acc[] = {
1261		"XAUTH=", "XAUTHORITY=", "DISPLAY=",
1262		"TERM=",
1263		"EDITOR=",
1264		"PAGER=",
1265		"LOGNAME=",
1266		"POSIXLY_CORRECT=",
1267		"PRINTER=",
1268		NULL
1269	};
1270
1271	char **cpp, **cpp2;
1272	const char **p;
1273
1274 	for (cpp2 = cpp = environ; *cpp; cpp++) {
1275		int reject_it = 0;
1276
1277		for(p = rej; *p; p++)
1278			if(strncmp(*cpp, *p, strlen(*p)) == 0) {
1279				reject_it = 1;
1280				break;
1281			}
1282		if (reject_it)
1283			continue;
1284
1285		for(p = acc; *p; p++)
1286			if(strncmp(*cpp, *p, strlen(*p)) == 0)
1287				break;
1288		if(*p != NULL)
1289 			*cpp2++ = *cpp;
1290 	}
1291	*cpp2 = NULL;
1292}
1293
1294/*
1295 * cleanup()
1296 *
1297 * This is the routine to call when we are all through, to
1298 * clean up anything that needs to be cleaned up.
1299 */
1300/* ARGSUSED */
1301void
1302cleanup(int sig __unused)
1303{
1304	char *p;
1305	sigset_t mask;
1306
1307	p = line + sizeof(_PATH_DEV) - 1;
1308	/*
1309	 * Block all signals before clearing the utmp entry.  We don't want to
1310	 * be called again after calling logout() and then not add the wtmp
1311	 * entry because of not finding the corresponding entry in utmp.
1312	 */
1313	sigfillset(&mask);
1314	sigprocmask(SIG_SETMASK, &mask, NULL);
1315	if (logout(p))
1316		logwtmp(p, "", "");
1317	(void)chmod(line, 0666);
1318	(void)chown(line, 0, 0);
1319	*p = 'p';
1320	(void)chmod(line, 0666);
1321	(void)chown(line, 0, 0);
1322	(void) shutdown(net, 2);
1323	_exit(1);
1324}
1325