1 /* $NetBSD: sys_term.c,v 1.43 2005/05/05 01:28:57 lukem Exp $ */
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
35 static char sccsid
[] = "@(#)sys_term.c 8.4+1 (Berkeley) 5/30/95";
37 __RCSID("$NetBSD: sys_term.c,v 1.43 2005/05/05 01:28:57 lukem Exp $");
42 #include "pathnames.h"
50 #define SCPYN(a, b) (void) strncpy(a, b, sizeof(a))
51 #define SCMPN(a, b) strncmp(a, b, sizeof(a))
53 struct termios termbuf
, termbuf2
; /* pty control structure */
55 void getptyslave(void);
56 int cleanopen(char *);
57 char **addarg(char **, char *);
59 int getent(char *, char *);
60 char *getstr(const char *, char **);
62 extern void kerberos5_cleanup(void);
70 * These three routines are used to get and set the "termbuf" structure
71 * to and from the kernel. init_termbuf() gets the current settings.
72 * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
73 * set_termbuf() writes the structure into the kernel.
79 (void) tcgetattr(pty
, &termbuf
);
83 #if defined(LINEMODE) && defined(TIOCPKT_IOCTL)
85 copy_termbuf(char *cp
, int len
)
87 if (len
> sizeof(termbuf
))
88 len
= sizeof(termbuf
);
89 memmove((char *)&termbuf
, cp
, len
);
92 #endif /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */
98 * Only make the necessary changes.
100 if (memcmp((char *)&termbuf
, (char *)&termbuf2
, sizeof(termbuf
)))
101 (void) tcsetattr(pty
, TCSANOW
, &termbuf
);
106 * spcset(func, valp, valpp)
108 * This function takes various special characters (func), and
109 * sets *valp to the current value of that character, and
110 * *valpp to point to where in the "termbuf" structure that
113 * It returns the SLC_ level of support for this function.
118 spcset(int func
, cc_t
*valp
, cc_t
**valpp
)
121 #define setval(a, b) *valp = termbuf.c_cc[a]; \
122 *valpp = &termbuf.c_cc[a]; \
124 #define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
128 setval(VEOF
, SLC_VARIABLE
);
130 setval(VERASE
, SLC_VARIABLE
);
132 setval(VKILL
, SLC_VARIABLE
);
134 setval(VINTR
, SLC_VARIABLE
|SLC_FLUSHIN
|SLC_FLUSHOUT
);
136 setval(VQUIT
, SLC_VARIABLE
|SLC_FLUSHIN
|SLC_FLUSHOUT
);
138 setval(VSTART
, SLC_VARIABLE
);
140 setval(VSTOP
, SLC_VARIABLE
);
142 setval(VWERASE
, SLC_VARIABLE
);
144 setval(VREPRINT
, SLC_VARIABLE
);
146 setval(VLNEXT
, SLC_VARIABLE
);
148 setval(VDISCARD
, SLC_VARIABLE
|SLC_FLUSHOUT
);
150 setval(VSUSP
, SLC_VARIABLE
|SLC_FLUSHIN
);
152 setval(VEOL
, SLC_VARIABLE
);
154 setval(VEOL2
, SLC_VARIABLE
);
156 setval(VSTATUS
, SLC_VARIABLE
);
166 return(SLC_NOSUPPORT
);
174 * Allocate a pty. As a side effect, the external character
175 * array "line" contains the name of the slave side.
177 * Returns the file descriptor of the opened pty.
180 char *line
= NULL16STR
;
182 static char Xline
[] = NULL16STR
;
187 static int ptyslavefd
; /* for cleanopen() */
194 ptyfd
= openpty(ptynum
, &ptyslavefd
, line
, NULL
, NULL
);
203 * tty_flowmode() Find out if flow control is enabled or disabled.
204 * tty_linemode() Find out if linemode (external processing) is enabled.
205 * tty_setlinemod(on) Turn on/off linemode.
206 * tty_isecho() Find out if echoing is turned on.
207 * tty_setecho(on) Enable/disable character echoing.
208 * tty_israw() Find out if terminal is in RAW mode.
209 * tty_binaryin(on) Turn on/off BINARY on input.
210 * tty_binaryout(on) Turn on/off BINARY on output.
211 * tty_isediting() Find out if line editing is enabled.
212 * tty_istrapsig() Find out if signal trapping is enabled.
213 * tty_setedit(on) Turn on/off line editing.
214 * tty_setsig(on) Turn on/off signal trapping.
215 * tty_issofttab() Find out if tab expansion is enabled.
216 * tty_setsofttab(on) Turn on/off soft tab expansion.
217 * tty_islitecho() Find out if typed control chars are echoed literally
218 * tty_setlitecho() Turn on/off literal echo of control chars
219 * tty_tspeed(val) Set transmit speed to val.
220 * tty_rspeed(val) Set receive speed to val.
227 return(termbuf
.c_lflag
& EXTPROC
);
231 tty_setlinemode(int on
)
234 (void) ioctl(pty
, TIOCEXT
, (char *)&on
);
237 #endif /* LINEMODE */
242 return (termbuf
.c_lflag
& ECHO
);
248 return((termbuf
.c_iflag
& IXON
) ? 1 : 0);
254 return((termbuf
.c_iflag
& IXANY
) ? 1 : 0);
261 termbuf
.c_lflag
|= ECHO
;
263 termbuf
.c_lflag
&= ~ECHO
;
269 return(!(termbuf
.c_lflag
& ICANON
));
276 termbuf
.c_iflag
&= ~ISTRIP
;
278 termbuf
.c_iflag
|= ISTRIP
;
283 tty_binaryout(int on
)
286 termbuf
.c_cflag
&= ~(CSIZE
|PARENB
);
287 termbuf
.c_cflag
|= CS8
;
288 termbuf
.c_oflag
&= ~OPOST
;
290 termbuf
.c_cflag
&= ~CSIZE
;
291 termbuf
.c_cflag
|= CS7
|PARENB
;
292 termbuf
.c_oflag
|= OPOST
;
299 return(!(termbuf
.c_iflag
& ISTRIP
));
303 tty_isbinaryout(void)
305 return(!(termbuf
.c_oflag
&OPOST
));
312 return(termbuf
.c_lflag
& ICANON
);
318 return(termbuf
.c_lflag
& ISIG
);
325 termbuf
.c_lflag
|= ICANON
;
327 termbuf
.c_lflag
&= ~ICANON
;
334 termbuf
.c_lflag
|= ISIG
;
336 termbuf
.c_lflag
&= ~ISIG
;
338 #endif /* LINEMODE */
344 return (termbuf
.c_oflag
& OXTABS
);
347 return ((termbuf
.c_oflag
& TABDLY
) == TAB3
);
352 tty_setsofttab(int on
)
356 termbuf
.c_oflag
|= OXTABS
;
359 termbuf
.c_oflag
&= ~TABDLY
;
360 termbuf
.c_oflag
|= TAB3
;
364 termbuf
.c_oflag
&= ~OXTABS
;
367 termbuf
.c_oflag
&= ~TABDLY
;
368 termbuf
.c_oflag
|= TAB0
;
377 return (!(termbuf
.c_lflag
& ECHOCTL
));
380 return (!(termbuf
.c_lflag
& TCTLECH
));
382 # if !defined(ECHOCTL) && !defined(TCTLECH)
383 return (0); /* assumes ctl chars are echoed '^x' */
388 tty_setlitecho(int on
)
392 termbuf
.c_lflag
&= ~ECHOCTL
;
394 termbuf
.c_lflag
|= ECHOCTL
;
398 termbuf
.c_lflag
&= ~TCTLECH
;
400 termbuf
.c_lflag
|= TCTLECH
;
407 return (termbuf
.c_iflag
& ICRNL
);
413 cfsetospeed(&termbuf
, val
);
419 cfsetispeed(&termbuf
, val
);
428 * Open the slave side of the pty, and do any initialization
429 * that is necessary. The return value is a file descriptor
430 * for the slave side.
432 extern int def_tspeed
, def_rspeed
;
433 extern int def_row
, def_col
;
445 * Opening the slave side may cause initilization of the
446 * kernel tty structure. We need remember the state of
447 * if linemode was turned on
448 * terminal window size
450 * so that we can re-set them if we need to.
453 waslm
= tty_linemode();
457 * Make sure that we don't have a controlling tty, and
458 * that we are the session (process group) leader.
460 t
= open(_PATH_TTY
, O_RDWR
);
462 (void) ioctl(t
, TIOCNOTTY
, (char *)0);
470 fatalperror(net
, line
);
474 * set up the tty modes as we like them to be.
477 if (def_row
|| def_col
) {
478 memset((char *)&ws
, 0, sizeof(ws
));
481 (void)ioctl(t
, TIOCSWINSZ
, (char *)&ws
);
485 * Settings for sgtty based systems
489 * Settings for all other termios/termio based
490 * systems, other than 4.4BSD. In 4.4BSD the
491 * kernel does the initial terminal setup.
493 tty_rspeed((def_rspeed
> 0) ? def_rspeed
: 9600);
494 tty_tspeed((def_tspeed
> 0) ? def_tspeed
: 9600);
498 #endif /* LINEMODE */
501 * Set the tty modes, and make this our controlling tty.
504 if (login_tty(t
) == -1)
505 fatalperror(net
, "login_tty");
515 * Open the specified slave side of the pty,
516 * making sure that we have a clean tty.
519 cleanopen(char *ttyline
)
527 * Given a hostname, do whatever
528 * is necessary to startup the login process on the slave side of the pty.
533 startslave(char *host
, int autologin
, char *autoname
)
537 #ifdef AUTHENTICATION
538 if (!autoname
|| !autoname
[0])
541 if (autologin
< auth_level
) {
542 fatal(net
, "Authorization failed");
548 if ((i
= fork()) < 0)
549 fatalperror(net
, "fork");
553 start_login(host
, autologin
, autoname
);
566 if ((*envp
= getenv("TZ")))
576 * Assuming that we are now running as a child processes, this
577 * function will turn us into the login process.
579 extern char *gettyname
;
582 start_login(char *host
, int autologin
, char *name
)
585 #define TABBUFSIZ 512
586 char defent
[TABBUFSIZ
];
587 char defstrs
[TABBUFSIZ
];
589 const char *loginprog
= NULL
;
590 extern struct sockaddr_storage from
;
591 char buf
[sizeof(from
) * 4 + 1];
596 * -a : pass on the address of the host.
597 * -h : pass on name of host.
598 * WARNING: -h and -a are accepted by login
599 * if and only if getuid() == 0.
600 * -p : don't clobber the environment (so terminal type stays set).
602 * -f : force this login, he has already been authenticated
604 argv
= addarg(0, "login");
606 argv
= addarg(argv
, "-a");
607 (void)strvisx(buf
, (const char *)(const void *)&from
, sizeof(from
),
609 argv
= addarg(argv
, buf
);
611 argv
= addarg(argv
, "-h");
612 argv
= addarg(argv
, host
);
614 argv
= addarg(argv
, "-p");
617 * Set the environment variable "LINEMODE" to either
618 * "real" or "kludge" if we are operating in either
619 * real or kludge linemode.
621 if (lmodetype
== REAL_LINEMODE
)
622 setenv("LINEMODE", "real", 1);
623 # ifdef KLUDGELINEMODE
624 else if (lmodetype
== KLUDGE_LINEMODE
|| lmodetype
== KLUDGE_OK
)
625 setenv("LINEMODE", "kludge", 1);
630 * don't worry about the -f that might get sent.
631 * A -s is supposed to override it anyhow.
633 if (require_secure_login
)
634 argv
= addarg(argv
, "-s");
636 #ifdef AUTHENTICATION
637 if (auth_level
>= 0 && autologin
== AUTH_VALID
) {
638 argv
= addarg(argv
, "-f");
639 argv
= addarg(argv
, "--");
640 argv
= addarg(argv
, name
);
643 if (getenv("USER")) {
644 argv
= addarg(argv
, "--");
645 argv
= addarg(argv
, getenv("USER"));
647 * Assume that login will set the USER variable
648 * correctly. For SysV systems, this means that
649 * USER will no longer be set, just LOGNAME by
650 * login. (The problem is that if the auto-login
651 * fails, and the user then specifies a different
652 * account name, he can get logged in with both
653 * LOGNAME and USER in his environment, but the
654 * USER value will be wrong.
658 if (getent(defent
, gettyname
) == 1) {
661 loginprog
= getstr("lo", &cp
);
663 if (loginprog
== NULL
)
664 loginprog
= _PATH_LOGIN
;
667 * This sleep(1) is in here so that telnetd can
668 * finish up with the tty. There's a race condition
669 * the login banner message gets lost...
672 execv(loginprog
, argv
);
674 syslog(LOG_ERR
, "%s: %m", loginprog
);
675 fatalperror(net
, loginprog
);
680 addarg(char **argv
, char *val
)
687 * 10 entries, a leading length, and a null
689 argv
= (char **)malloc(sizeof(*argv
) * 12);
692 *argv
++ = (char *)10;
695 for (cpp
= argv
; *cpp
; cpp
++)
697 if (cpp
== &argv
[(long)argv
[-1]]) {
699 nargv
= (char **)realloc(argv
,
700 sizeof(*argv
) * ((long)(*argv
) + 10 + 2));
702 fatal(net
, "not enough memory");
706 *argv
= (char *)((long)(*argv
) + 10);
708 cpp
= &argv
[(long)argv
[-1] - 10];
718 * We only accept the environment variables listed below.
724 static const char *reject
[] = {
729 static const char *acceptstr
[] = {
730 "XAUTH=", "XAUTHORITY=", "DISPLAY=",
744 for (cpp2
= cpp
= environ
; *cpp
; cpp
++) {
747 for(p
= reject
; *p
; p
++)
748 if(strncmp(*cpp
, *p
, strlen(*p
)) == 0) {
755 for(p
= acceptstr
; *p
; p
++)
756 if(strncmp(*cpp
, *p
, strlen(*p
)) == 0)
767 * This is the routine to call when we are all through, to
768 * clean up anything that needs to be cleaned up.
776 p
= line
+ sizeof(_PATH_DEV
) - 1;
782 if (logoutx(p
, 0, DEAD_PROCESS
))
783 logwtmpx(p
, "", "", 0, DEAD_PROCESS
);
785 (void)chmod(line
, 0666);
786 (void)chown(line
, 0, 0);
788 (void)chmod(line
, 0666);
789 (void)chown(line
, 0, 0);
791 if (ttyaction(line
, "telnetd", "root"))
792 syslog(LOG_ERR
, "%s: ttyaction failed", line
);
793 (void) shutdown(net
, 2);