2
* Copyright (c) 1989 Regents of the University of California.
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
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.
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
35
* From: @(#)sys_term.c 5.16 (Berkeley) 3/22/91
38
"$Id: sys_term.c,v 1.17 1999/12/17 14:28:47 dholland Exp $";
43
#include "pathnames.h"
45
#if defined(__GLIBC__) && (__GLIBC__ >= 2)
46
/* mmm, nonstandard */
49
int openpty(int *, int *, char *, struct termios *, struct winsize *);
52
#define ARCH64 ((sizeof(void *)) == 8)
53
#define ARCH32 ((sizeof(void *)) == 4)
55
#if defined(AUTHENTICATE)
56
#include <libtelnet/auth.h>
59
static struct termios termbuf, termbuf2; /* pty control structure */
62
#define DO_SHUTDOWN(x,y) \
64
fprintf(stderr,"Doing SSL_shutdown\n");\
67
if (ssl_active_flag) \
68
SSL_shutdown(ssl_con); \
71
#define DO_SHUTDOWN(x,y) shutdown((x),(y))
74
/*static int cleanopen(char *line);*/
81
* These three routines are used to get and set the "termbuf" structure
82
* to and from the kernel. init_termbuf() gets the current settings.
83
* copy_termbuf() hands in a new "termbuf" to write to the kernel, and
84
* set_termbuf() writes the structure into the kernel.
87
void init_termbuf(void) {
88
tcgetattr(pty, &termbuf);
92
#if defined(LINEMODE) && defined(TIOCPKT_IOCTL)
96
void copy_termbuf(char *cp, int len) {
97
if (len > sizeof(termbuf)) len = sizeof(termbuf);
98
bcopy(cp, (char *)&termbuf, len);
101
#endif /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */
103
void set_termbuf(void) {
104
if (memcmp(&termbuf, &termbuf2, sizeof(termbuf))) {
105
tcsetattr(pty, TCSANOW, &termbuf);
111
* spcset(func, valp, valpp)
113
* This function takes various special characters (func), and
114
* sets *valp to the current value of that character, and
115
* *valpp to point to where in the "termbuf" structure that
118
* It returns the SLC_ level of support for this function.
122
int spcset(int func, cc_t *valp, cc_t **valpp) {
124
#define setval(a, b) *valp = termbuf.c_cc[a]; \
125
*valpp = &termbuf.c_cc[a]; \
127
#define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
131
setval(VEOF, SLC_VARIABLE);
133
setval(VERASE, SLC_VARIABLE);
135
setval(VKILL, SLC_VARIABLE);
137
setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
139
setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
142
setval(VSTART, SLC_VARIABLE);
148
setval(VSTOP, SLC_VARIABLE);
154
setval(VWERASE, SLC_VARIABLE);
160
setval(VREPRINT, SLC_VARIABLE);
166
setval(VLNEXT, SLC_VARIABLE);
171
#if !defined(VDISCARD) && defined(VFLUSHO)
172
# define VDISCARD VFLUSHO
175
setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT);
181
setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN);
187
setval(VEOL, SLC_VARIABLE);
191
setval(VEOL2, SLC_VARIABLE);
195
setval(VSTATUS, SLC_VARIABLE);
208
return(SLC_NOSUPPORT);
215
* Allocate a pty. As a side effect, the external character
216
* array "line" contains the name of the slave side.
218
* Returns the file descriptor of the opened pty.
222
static int ptyslavefd=-1;
227
if (openpty(&masterfd, &ptyslavefd, NULL, NULL, NULL)) {
230
line = ttyname(ptyslavefd);
236
* tty_flowmode() Find out if flow control is enabled or disabled.
237
* tty_linemode() Find out if linemode (external processing) is enabled.
238
* tty_setlinemod(on) Turn on/off linemode.
239
* tty_isecho() Find out if echoing is turned on.
240
* tty_setecho(on) Enable/disable character echoing.
241
* tty_israw() Find out if terminal is in RAW mode.
242
* tty_binaryin(on) Turn on/off BINARY on input.
243
* tty_binaryout(on) Turn on/off BINARY on output.
244
* tty_isediting() Find out if line editing is enabled.
245
* tty_istrapsig() Find out if signal trapping is enabled.
246
* tty_setedit(on) Turn on/off line editing.
247
* tty_setsig(on) Turn on/off signal trapping.
248
* tty_issofttab() Find out if tab expansion is enabled.
249
* tty_setsofttab(on) Turn on/off soft tab expansion.
250
* tty_islitecho() Find out if typed control chars are echoed literally
251
* tty_setlitecho() Turn on/off literal echo of control chars
252
* tty_tspeed(val) Set transmit speed to val.
253
* tty_rspeed(val) Set receive speed to val.
256
int tty_flowmode(void) {
257
return (termbuf.c_iflag & IXON ? 1 : 0);
260
int tty_linemode(void) {
261
return (termbuf.c_lflag & EXTPROC);
264
void tty_setlinemode(int on) {
267
ioctl(pty, TIOCEXT, (char *)&on);
271
if (on) termbuf.c_lflag |= EXTPROC;
272
else termbuf.c_lflag &= ~EXTPROC;
277
int tty_isecho(void) {
278
return (termbuf.c_lflag & ECHO);
280
#endif /* LINEMODE */
282
void tty_setecho(int on) {
283
if (on) termbuf.c_lflag |= ECHO;
284
else termbuf.c_lflag &= ~ECHO;
287
#if defined(LINEMODE) && defined(KLUDGELINEMODE)
288
int tty_israw(void) {
289
return(!(termbuf.c_lflag & ICANON));
291
#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
293
void tty_binaryin(int on) {
295
termbuf.c_iflag &= ~ISTRIP;
298
termbuf.c_iflag |= ISTRIP;
302
void tty_binaryout(int on) {
304
termbuf.c_cflag &= ~(CSIZE|PARENB);
305
termbuf.c_cflag |= CS8;
306
termbuf.c_oflag &= ~OPOST;
309
termbuf.c_cflag &= ~CSIZE;
310
termbuf.c_cflag |= CS7|PARENB;
311
termbuf.c_oflag |= OPOST;
315
int tty_isbinaryin(void) {
316
return (!(termbuf.c_iflag & ISTRIP));
319
int tty_isbinaryout(void) {
320
return (!(termbuf.c_oflag&OPOST));
324
int tty_isediting(void) {
325
return(termbuf.c_lflag & ICANON);
328
int tty_istrapsig(void) {
329
return(termbuf.c_lflag & ISIG);
332
void tty_setedit(int on) {
333
if (on) termbuf.c_lflag |= ICANON;
334
else termbuf.c_lflag &= ~ICANON;
337
void tty_setsig(int on) {
338
if (on) termbuf.c_lflag |= ISIG;
339
else termbuf.c_lflag &= ~ISIG;
341
#endif /* LINEMODE */
343
int tty_issofttab(void) {
345
return (termbuf.c_oflag & OXTABS);
348
return ((termbuf.c_oflag & TABDLY) == TAB3);
352
void tty_setsofttab(int on) {
355
termbuf.c_oflag |= OXTABS;
358
termbuf.c_oflag &= ~TABDLY;
359
termbuf.c_oflag |= TAB3;
364
termbuf.c_oflag &= ~OXTABS;
367
termbuf.c_oflag &= ~TABDLY;
368
termbuf.c_oflag |= TAB0;
373
int tty_islitecho(void) {
374
return (!(termbuf.c_lflag & ECHOCTL));
377
void tty_setlitecho(int on) {
378
if (on) termbuf.c_lflag &= ~ECHOCTL;
379
else termbuf.c_lflag |= ECHOCTL;
382
int tty_iscrnl(void) {
383
return (termbuf.c_iflag & ICRNL);
387
* A table of available terminal speeds
393
{ 0, B0 }, { 50, B50 }, { 75, B75 },
394
{ 110, B110 }, { 134, B134 }, { 150, B150 },
395
{ 200, B200 }, { 300, B300 }, { 600, B600 },
396
{ 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 },
397
{ 4800, B4800 }, { 9600, B9600 }, { 19200, B9600 },
398
{ 38400, B9600 }, { -1, B9600 }
401
void tty_tspeed(int val) {
402
struct termspeeds *tp;
403
for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++);
404
cfsetospeed(&termbuf, tp->value);
407
void tty_rspeed(int val) {
408
struct termspeeds *tp;
409
for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++);
410
cfsetispeed(&termbuf, tp->value);
416
* Open the slave side of the pty, and do any initialization
417
* that is necessary. The return value is a file descriptor
418
* for the slave side.
421
extern int def_row, def_col;
423
extern int def_tspeed, def_rspeed;
425
static int getptyslave(void) {
436
* Opening the slave side may cause initilization of the
437
* kernel tty structure. We need remember the state of
438
* if linemode was turned on
439
* terminal window size
441
* so that we can re-set them if we need to.
444
waslm = tty_linemode();
449
* Make sure that we don't have a controlling tty, and
450
* that we are the session (process group) leader.
452
t = open(_PATH_TTY, O_RDWR);
454
ioctl(t, TIOCNOTTY, (char *)0);
459
if (t < 0) fatalperror(net, line);
466
* set up the tty modes as we like them to be.
470
if (def_row || def_col) {
471
bzero((char *)&ws, sizeof(ws));
474
ioctl(t, TIOCSWINSZ, (char *)&ws);
479
* Settings for all other termios/termio based
480
* systems, other than 4.4BSD. In 4.4BSD the
481
* kernel does the initial terminal setup.
483
* XXX what about linux?
488
termbuf.c_lflag |= ECHO;
489
termbuf.c_oflag |= OPOST|ONLCR|OXTABS;
490
termbuf.c_iflag |= ICRNL;
491
termbuf.c_iflag &= ~IXOFF;
493
tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);
494
tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);
496
if (waslm) tty_setlinemode(1);
497
# endif /* LINEMODE */
500
* Set the tty modes, and make this our controlling tty.
503
if (login_tty(t) == -1) fatalperror(net, "login_tty");
505
if (net > 2) close(net);
506
if (pty > 2) close(pty);
515
* Open the specified slave side of the pty,
516
* making sure that we have a clean tty.
518
static int cleanopen(char *lyne) {
522
* Make sure that other people can't open the
523
* slave side of the connection.
532
t = open(lyne, O_RDWR|O_NOCTTY);
533
if (t < 0) return(-1);
536
* Hangup anybody else using this ttyp, then reopen it for
539
# if !defined(__linux__)
540
/* this looks buggy to me, our ctty is really a pty at this point */
541
signal(SIGHUP, SIG_IGN);
543
signal(SIGHUP, SIG_DFL);
544
t = open(lyne, O_RDWR|O_NOCTTY);
545
if (t < 0) return(-1);
551
int login_tty(int t) {
552
if (setsid() < 0) fatalperror(net, "setsid()");
553
if (ioctl(t, TIOCSCTTY, (char *)0) < 0) {
554
fatalperror(net, "ioctl(sctty)");
556
if (t != 0) dup2(t, 0);
557
if (t != 1) dup2(t, 1);
558
if (t != 2) dup2(t, 2);
566
* Given a hostname, do whatever
567
* is necessary to startup the login process on the slave side of the pty.
571
void startslave(const char *host, int autologin, char *autoname) {
574
#if defined(AUTHENTICATE)
575
if (!autoname || !autoname[0]) autologin = 0;
576
if (autologin < auth_level) {
577
fatal(net, "Authorization failed");
583
if (i < 0) fatalperror(net, "fork");
586
signal(SIGHUP,SIG_IGN);
591
signal(SIGHUP,SIG_IGN);
593
start_login(host, autologin, autoname);
600
void init_env(void) {
603
if ((*envp = getenv("TZ"))!=NULL)
612
* Assuming that we are now running as a child processes, this
613
* function will turn us into the login process.
622
static void addarg(struct argv_stuff *, const char *);
623
static void initarg(struct argv_stuff *);
625
void start_login(const char *host, int autologin, const char *name) {
626
struct argv_stuff avs;
627
char *const *argvfoo;
633
* -h : pass on name of host.
634
* WARNING: -h is accepted by login if and only if
636
* -p : don't clobber the environment (so terminal type stays set).
638
* -f : force this login, he has already been authenticated
640
addarg(&avs, loginprg);
643
#if !defined(NO_LOGIN_P)
648
* Are we working as the bftp daemon? If so, then ask login
649
* to start bftp instead of shell.
653
addarg(&avs, BFTPPATH);
658
#if defined (SecurID)
660
* don't worry about the -f that might get sent.
661
* A -s is supposed to override it anyhow.
663
if (require_SecurID) addarg(&avs, "-s");
666
syslog(LOG_ERR, "Attempt to login with an option!");
669
#if defined (AUTHENTICATE)
670
if (auth_level >= 0 && autologin == AUTH_VALID) {
671
# if !defined(NO_LOGIN_F)
679
if (getenv("USER")) {
680
addarg(&avs, getenv("USER"));
681
if (*getenv("USER") == '-') {
682
write(1,"I don't hear you!\r\n",19);
683
syslog(LOG_ERR,"Attempt to login with an option!");
690
/* execv() should really take char const* const *, but it can't */
692
memcpy(&argvfoo, &avs.argv, sizeof(argvfoo));
693
execv(loginprg, argvfoo);
695
openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
696
syslog(LOG_ERR, "%s: %m\n", loginprg);
698
fatalperror(net, loginprg);
701
static void initarg(struct argv_stuff *avs) {
703
* 10 entries and a null
706
avs->argv = malloc(sizeof(avs->argv[0]) * avs->argmax);
707
if (avs->argv == NULL) {
708
fprintf(stderr, "Out of memory\n");
715
static void addarg(struct argv_stuff *avs, const char *val) {
716
if (avs->argc>=avs->argmax-1) {
718
avs->argv = realloc(avs->argv, sizeof(avs->argv[0])*avs->argmax);
719
if (avs->argv == NULL) {
720
fprintf(stderr, "Out of memory\n");
725
avs->argv[avs->argc++] = val;
726
avs->argv[avs->argc] = NULL;
732
* This is the routine to call when we are all through, to
733
* clean up anything that needs to be cleaned up.
735
void cleanup(int sig) {
739
p = line + sizeof("/dev/") - 1;
740
if (logout(p)) logwtmp(p, "", "");