busybox/networking/telnetd.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * Simple telnet server
   4 * Bjorn Wesen, Axis Communications AB (bjornw@axis.com)
   5 *
   6 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
   7 *
   8 * ---------------------------------------------------------------------------
   9 * (C) Copyright 2000, Axis Communications AB, LUND, SWEDEN
  10 ****************************************************************************
  11 *
  12 * The telnetd manpage says it all:
  13 *
  14 * Telnetd operates by allocating a pseudo-terminal device (see pty(4)) for
  15 * a client, then creating a login process which has the slave side of the
  16 * pseudo-terminal as stdin, stdout, and stderr. Telnetd manipulates the
  17 * master side of the pseudo-terminal, implementing the telnet protocol and
  18 * passing characters between the remote client and the login process.
  19 *
  20 * Vladimir Oleynik <dzo@simtreas.ru> 2001
  21 * Set process group corrections, initial busybox port
  22 */
  23//config:config TELNETD
  24//config:       bool "telnetd (12 kb)"
  25//config:       default y
  26//config:       select FEATURE_SYSLOG
  27//config:       help
  28//config:       A daemon for the TELNET protocol, allowing you to log onto the host
  29//config:       running the daemon. Please keep in mind that the TELNET protocol
  30//config:       sends passwords in plain text. If you can't afford the space for an
  31//config:       SSH daemon and you trust your network, you may say 'y' here. As a
  32//config:       more secure alternative, you should seriously consider installing the
  33//config:       very small Dropbear SSH daemon instead:
  34//config:               http://matt.ucc.asn.au/dropbear/dropbear.html
  35//config:
  36//config:       Note that for busybox telnetd to work you need several things:
  37//config:       First of all, your kernel needs:
  38//config:                 CONFIG_UNIX98_PTYS=y
  39//config:
  40//config:       Next, you need a /dev/pts directory on your root filesystem:
  41//config:
  42//config:                 $ ls -ld /dev/pts
  43//config:                 drwxr-xr-x  2 root root 0 Sep 23 13:21 /dev/pts/
  44//config:
  45//config:       Next you need the pseudo terminal master multiplexer /dev/ptmx:
  46//config:
  47//config:                 $ ls -la /dev/ptmx
  48//config:                 crw-rw-rw-  1 root tty 5, 2 Sep 23 13:55 /dev/ptmx
  49//config:
  50//config:       Any /dev/ttyp[0-9]* files you may have can be removed.
  51//config:       Next, you need to mount the devpts filesystem on /dev/pts using:
  52//config:
  53//config:                 mount -t devpts devpts /dev/pts
  54//config:
  55//config:       You need to be sure that busybox has LOGIN and
  56//config:       FEATURE_SUID enabled. And finally, you should make
  57//config:       certain that busybox has been installed setuid root:
  58//config:
  59//config:               chown root.root /bin/busybox
  60//config:               chmod 4755 /bin/busybox
  61//config:
  62//config:       with all that done, telnetd _should_ work....
  63//config:
  64//config:config FEATURE_TELNETD_STANDALONE
  65//config:       bool "Support standalone telnetd (not inetd only)"
  66//config:       default y
  67//config:       depends on TELNETD
  68//config:       help
  69//config:       Selecting this will make telnetd able to run standalone.
  70//config:
  71//config:config FEATURE_TELNETD_INETD_WAIT
  72//config:       bool "Support -w SEC option (inetd wait mode)"
  73//config:       default y
  74//config:       depends on FEATURE_TELNETD_STANDALONE
  75//config:       help
  76//config:       This option allows you to run telnetd in "inet wait" mode.
  77//config:       Example inetd.conf line (note "wait", not usual "nowait"):
  78//config:
  79//config:       telnet stream tcp wait root /bin/telnetd telnetd -w10
  80//config:
  81//config:       In this example, inetd passes _listening_ socket_ as fd 0
  82//config:       to telnetd when connection appears.
  83//config:       telnetd will wait for connections until all existing
  84//config:       connections are closed, and no new connections
  85//config:       appear during 10 seconds. Then it exits, and inetd continues
  86//config:       to listen for new connections.
  87//config:
  88//config:       This option is rarely used. "tcp nowait" is much more usual
  89//config:       way of running tcp services, including telnetd.
  90//config:       You most probably want to say N here.
  91
  92//applet:IF_TELNETD(APPLET(telnetd, BB_DIR_USR_SBIN, BB_SUID_DROP))
  93
  94//kbuild:lib-$(CONFIG_TELNETD) += telnetd.o
  95
  96//usage:#define telnetd_trivial_usage
  97//usage:       "[OPTIONS]"
  98//usage:#define telnetd_full_usage "\n\n"
  99//usage:       "Handle incoming telnet connections"
 100//usage:        IF_NOT_FEATURE_TELNETD_STANDALONE(" via inetd") "\n"
 101//usage:     "\n        -l LOGIN        Exec LOGIN on connect"
 102//usage:     "\n        -f ISSUE_FILE   Display ISSUE_FILE instead of /etc/issue"
 103//usage:     "\n        -K              Close connection as soon as login exits"
 104//usage:     "\n                        (normally wait until all programs close slave pty)"
 105//usage:        IF_FEATURE_TELNETD_STANDALONE(
 106//usage:     "\n        -p PORT         Port to listen on"
 107//usage:     "\n        -b ADDR[:PORT]  Address to bind to"
 108//usage:     "\n        -F              Run in foreground"
 109//usage:     "\n        -i              Inetd mode"
 110//usage:        IF_FEATURE_TELNETD_INETD_WAIT(
 111//usage:     "\n        -w SEC          Inetd 'wait' mode, linger time SEC"
 112//usage:     "\n        -S              Log to syslog (implied by -i or without -F and -w)"
 113//usage:        )
 114//usage:        )
 115
 116#define DEBUG 0
 117
 118#include "libbb.h"
 119#include "common_bufsiz.h"
 120#include <syslog.h>
 121
 122#if DEBUG
 123# define TELCMDS
 124# define TELOPTS
 125#endif
 126#include <arpa/telnet.h>
 127
 128
 129struct tsession {
 130        struct tsession *next;
 131        pid_t shell_pid;
 132        int sockfd_read;
 133        int sockfd_write;
 134        int ptyfd;
 135        smallint buffered_IAC_for_pty;
 136
 137        /* two circular buffers */
 138        /*char *buf1, *buf2;*/
 139/*#define TS_BUF1(ts) ts->buf1*/
 140/*#define TS_BUF2(ts) TS_BUF2(ts)*/
 141#define TS_BUF1(ts) ((unsigned char*)(ts + 1))
 142#define TS_BUF2(ts) (((unsigned char*)(ts + 1)) + BUFSIZE)
 143        int rdidx1, wridx1, size1;
 144        int rdidx2, wridx2, size2;
 145};
 146
 147/* Two buffers are directly after tsession in malloced memory.
 148 * Make whole thing fit in 4k */
 149enum { BUFSIZE = (4 * 1024 - sizeof(struct tsession)) / 2 };
 150
 151
 152/* Globals */
 153struct globals {
 154        struct tsession *sessions;
 155        const char *loginpath;
 156        const char *issuefile;
 157        int maxfd;
 158} FIX_ALIASING;
 159#define G (*(struct globals*)bb_common_bufsiz1)
 160#define INIT_G() do { \
 161        setup_common_bufsiz(); \
 162        G.loginpath = "/bin/login"; \
 163        G.issuefile = "/etc/issue.net"; \
 164} while (0)
 165
 166
 167/* Write some buf1 data to pty, processing IACs.
 168 * Update wridx1 and size1. Return < 0 on error.
 169 * Buggy if IAC is present but incomplete: skips them.
 170 */
 171static ssize_t
 172safe_write_to_pty_decode_iac(struct tsession *ts)
 173{
 174        unsigned wr;
 175        ssize_t rc;
 176        unsigned char *buf;
 177        unsigned char *found;
 178
 179        buf = TS_BUF1(ts) + ts->wridx1;
 180        wr = MIN(BUFSIZE - ts->wridx1, ts->size1);
 181        /* wr is at least 1 here */
 182
 183        if (ts->buffered_IAC_for_pty) {
 184                /* Last time we stopped on a "dangling" IAC byte.
 185                 * We removed it from the buffer back then.
 186                 * Now pretend it's still there, and jump to IAC processing.
 187                 */
 188                ts->buffered_IAC_for_pty = 0;
 189                wr++;
 190                ts->size1++;
 191                buf--; /* Yes, this can point before the buffer. It's ok */
 192                ts->wridx1--;
 193                goto handle_iac;
 194        }
 195
 196        found = memchr(buf, IAC, wr);
 197        if (found != buf) {
 198                /* There is a "prefix" of non-IAC chars.
 199                 * Write only them, and return.
 200                 */
 201                if (found)
 202                        wr = found - buf;
 203
 204                /* We map \r\n ==> \r for pragmatic reasons:
 205                 * many client implementations send \r\n when
 206                 * the user hits the CarriageReturn key.
 207                 * See RFC 1123 3.3.1 Telnet End-of-Line Convention.
 208                 */
 209                rc = wr;
 210                found = memchr(buf, '\r', wr);
 211                if (found)
 212                        rc = found - buf + 1;
 213                rc = safe_write(ts->ptyfd, buf, rc);
 214                if (rc <= 0)
 215                        return rc;
 216                if (rc < wr /* don't look past available data */
 217                 && buf[rc-1] == '\r' /* need this: imagine that write was _short_ */
 218                 && (buf[rc] == '\n' || buf[rc] == '\0')
 219                ) {
 220                        rc++;
 221                }
 222                goto update_and_return;
 223        }
 224
 225        /* buf starts with IAC char. Process that sequence.
 226         * Example: we get this from our own (bbox) telnet client:
 227         * read(5, "\377\374\1""\377\373\37""\377\372\37\0\262\0@\377\360""\377\375\1""\377\375\3"):
 228         * IAC WONT ECHO, IAC WILL NAWS, IAC SB NAWS <cols> <rows> IAC SE, IAC DO SGA
 229         * Another example (telnet-0.17 from old-netkit):
 230         * read(4, "\377\375\3""\377\373\30""\377\373\37""\377\373 ""\377\373!""\377\373\"""\377\373'"
 231         * "\377\375\5""\377\373#""\377\374\1""\377\372\37\0\257\0I\377\360""\377\375\1"):
 232         * IAC DO SGA, IAC WILL TTYPE, IAC WILL NAWS, IAC WILL TSPEED, IAC WILL LFLOW, IAC WILL LINEMODE, IAC WILL NEW_ENVIRON,
 233         * IAC DO STATUS, IAC WILL XDISPLOC, IAC WONT ECHO, IAC SB NAWS <cols> <rows> IAC SE, IAC DO ECHO
 234         */
 235        if (wr <= 1) {
 236                /* Only the single IAC byte is in the buffer, eat it
 237                 * and set a flag "process the rest of the sequence
 238                 * next time we are here".
 239                 */
 240                //bb_error_msg("dangling IAC!");
 241                ts->buffered_IAC_for_pty = 1;
 242                rc = 1;
 243                goto update_and_return;
 244        }
 245
 246 handle_iac:
 247        /* 2-byte commands (240..250 and 255):
 248         * IAC IAC (255) Literal 255. Supported.
 249         * IAC SE  (240) End of subnegotiation. Treated as NOP.
 250         * IAC NOP (241) NOP. Supported.
 251         * IAC BRK (243) Break. Like serial line break. TODO via tcsendbreak()?
 252         * IAC AYT (246) Are you there. Send back evidence that AYT was seen. TODO (send NOP back)?
 253         *  These don't look useful:
 254         * IAC DM  (242) Data mark. What is this?
 255         * IAC IP  (244) Suspend, interrupt or abort the process. (Ancient cousin of ^C).
 256         * IAC AO  (245) Abort output. "You can continue running, but do not send me the output".
 257         * IAC EC  (247) Erase character. The receiver should delete the last received char.
 258         * IAC EL  (248) Erase line. The receiver should delete everything up tp last newline.
 259         * IAC GA  (249) Go ahead. For half-duplex lines: "now you talk".
 260         *  Implemented only as part of NAWS:
 261         * IAC SB  (250) Subnegotiation of an option follows.
 262         */
 263        if (buf[1] == IAC) {
 264                /* Literal 255 (emacs M-DEL) */
 265                //bb_error_msg("255!");
 266                rc = safe_write(ts->ptyfd, &buf[1], 1);
 267                /*
 268                 * If we went through buffered_IAC_for_pty==1 path,
 269                 * bailing out on error like below messes up the buffer.
 270                 * EAGAIN is highly unlikely here, other errors will be
 271                 * repeated on next write, let's just skip error check.
 272                 */
 273#if 0
 274                if (rc <= 0)
 275                        return rc;
 276#endif
 277                rc = 2;
 278                goto update_and_return;
 279        }
 280        if (buf[1] >= 240 && buf[1] <= 249) {
 281                /* NOP (241). Ignore (putty keepalive, etc) */
 282                /* All other 2-byte commands also treated as NOPs here */
 283                rc = 2;
 284                goto update_and_return;
 285        }
 286
 287        if (wr <= 2) {
 288/* BUG: only 2 bytes of the IAC is in the buffer, we just eat them.
 289 * This is not a practical problem since >2 byte IACs are seen only
 290 * in initial negotiation, when buffer is empty
 291 */
 292                rc = 2;
 293                goto update_and_return;
 294        }
 295
 296        if (buf[1] == SB) {
 297                if (buf[2] == TELOPT_NAWS) {
 298                        /* IAC SB, TELOPT_NAWS, 4-byte, IAC SE */
 299                        struct winsize ws;
 300                        if (wr <= 6) {
 301/* BUG: incomplete, can't process */
 302                                rc = wr;
 303                                goto update_and_return;
 304                        }
 305                        memset(&ws, 0, sizeof(ws)); /* pixel sizes are set to 0 */
 306                        ws.ws_col = (buf[3] << 8) | buf[4];
 307                        ws.ws_row = (buf[5] << 8) | buf[6];
 308                        ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws);
 309                        rc = 7;
 310                        /* trailing IAC SE will be eaten separately, as 2-byte NOP */
 311                        goto update_and_return;
 312                }
 313                /* else: other subnegs not supported yet */
 314        }
 315
 316        /* Assume it is a 3-byte WILL/WONT/DO/DONT 251..254 command and skip it */
 317#if DEBUG
 318        fprintf(stderr, "Ignoring IAC %s,%s\n",
 319                        TELCMD(buf[1]), TELOPT(buf[2]));
 320#endif
 321        rc = 3;
 322
 323 update_and_return:
 324        ts->wridx1 += rc;
 325        if (ts->wridx1 >= BUFSIZE) /* actually == BUFSIZE */
 326                ts->wridx1 = 0;
 327        ts->size1 -= rc;
 328        /*
 329         * Hack. We cannot process IACs which wrap around buffer's end.
 330         * Since properly fixing it requires writing bigger code,
 331         * we rely instead on this code making it virtually impossible
 332         * to have wrapped IAC (people don't type at 2k/second).
 333         * It also allows for bigger reads in common case.
 334         */
 335        if (ts->size1 == 0) { /* very typical */
 336                //bb_error_msg("zero size1");
 337                ts->rdidx1 = 0;
 338                ts->wridx1 = 0;
 339                return rc;
 340        }
 341        wr = ts->wridx1;
 342        if (wr != 0 && wr < ts->rdidx1) {
 343                /* Buffer is not wrapped yet.
 344                 * We can easily move it to the beginning.
 345                 */
 346                //bb_error_msg("moved %d", wr);
 347                memmove(TS_BUF1(ts), TS_BUF1(ts) + wr, ts->size1);
 348                ts->rdidx1 -= wr;
 349                ts->wridx1 = 0;
 350        }
 351        return rc;
 352}
 353
 354/*
 355 * Converting single IAC into double on output
 356 */
 357static size_t safe_write_double_iac(int fd, const char *buf, size_t count)
 358{
 359        const char *IACptr;
 360        size_t wr, rc, total;
 361
 362        total = 0;
 363        while (1) {
 364                if (count == 0)
 365                        return total;
 366                if (*buf == (char)IAC) {
 367                        static const char IACIAC[] ALIGN1 = { IAC, IAC };
 368                        rc = safe_write(fd, IACIAC, 2);
 369/* BUG: if partial write was only 1 byte long, we end up emitting just one IAC */
 370                        if (rc != 2)
 371                                break;
 372                        buf++;
 373                        total++;
 374                        count--;
 375                        continue;
 376                }
 377                /* count != 0, *buf != IAC */
 378                IACptr = memchr(buf, IAC, count);
 379                wr = count;
 380                if (IACptr)
 381                        wr = IACptr - buf;
 382                rc = safe_write(fd, buf, wr);
 383                if (rc != wr)
 384                        break;
 385                buf += rc;
 386                total += rc;
 387                count -= rc;
 388        }
 389        /* here: rc - result of last short write */
 390        if ((ssize_t)rc < 0) { /* error? */
 391                if (total == 0)
 392                        return rc;
 393                rc = 0;
 394        }
 395        return total + rc;
 396}
 397
 398/* Must match getopt32 string */
 399enum {
 400        OPT_WATCHCHILD = (1 << 2), /* -K */
 401        OPT_INETD      = (1 << 3) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -i */
 402        OPT_PORT       = (1 << 4) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -p PORT */
 403        OPT_FOREGROUND = (1 << 6) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -F */
 404        OPT_SYSLOG     = (1 << 7) * ENABLE_FEATURE_TELNETD_INETD_WAIT, /* -S */
 405        OPT_WAIT       = (1 << 8) * ENABLE_FEATURE_TELNETD_INETD_WAIT, /* -w SEC */
 406};
 407
 408static struct tsession *
 409make_new_session(
 410                IF_FEATURE_TELNETD_STANDALONE(int sock)
 411                IF_NOT_FEATURE_TELNETD_STANDALONE(void)
 412) {
 413#if !ENABLE_FEATURE_TELNETD_STANDALONE
 414        enum { sock = 0 };
 415#endif
 416        const char *login_argv[2];
 417        struct termios termbuf;
 418        int fd, pid;
 419        char tty_name[GETPTY_BUFSIZE];
 420        struct tsession *ts = xzalloc(sizeof(struct tsession) + BUFSIZE * 2);
 421
 422        /*ts->buf1 = (char *)(ts + 1);*/
 423        /*ts->buf2 = ts->buf1 + BUFSIZE;*/
 424
 425        /* Got a new connection, set up a tty */
 426        fd = xgetpty(tty_name);
 427        if (fd > G.maxfd)
 428                G.maxfd = fd;
 429        ts->ptyfd = fd;
 430        ndelay_on(fd);
 431        close_on_exec_on(fd);
 432
 433        /* SO_KEEPALIVE by popular demand */
 434        setsockopt_keepalive(sock);
 435#if ENABLE_FEATURE_TELNETD_STANDALONE
 436        ts->sockfd_read = sock;
 437        ndelay_on(sock);
 438        if (sock == 0) { /* We are called with fd 0 - we are in inetd mode */
 439                sock++; /* so use fd 1 for output */
 440                ndelay_on(sock);
 441        }
 442        ts->sockfd_write = sock;
 443        if (sock > G.maxfd)
 444                G.maxfd = sock;
 445#else
 446        /* ts->sockfd_read = 0; - done by xzalloc */
 447        ts->sockfd_write = 1;
 448        ndelay_on(0);
 449        ndelay_on(1);
 450#endif
 451
 452        /* Make the telnet client understand we will echo characters so it
 453         * should not do it locally. We don't tell the client to run linemode,
 454         * because we want to handle line editing and tab completion and other
 455         * stuff that requires char-by-char support. */
 456        {
 457                static const char iacs_to_send[] ALIGN1 = {
 458                        IAC, DO, TELOPT_ECHO,
 459                        IAC, DO, TELOPT_NAWS,
 460                        /* This requires telnetd.ctrlSQ.patch (incomplete) */
 461                        /*IAC, DO, TELOPT_LFLOW,*/
 462                        IAC, WILL, TELOPT_ECHO,
 463                        IAC, WILL, TELOPT_SGA
 464                };
 465                /* This confuses safe_write_double_iac(), it will try to duplicate
 466                 * each IAC... */
 467                //memcpy(TS_BUF2(ts), iacs_to_send, sizeof(iacs_to_send));
 468                //ts->rdidx2 = sizeof(iacs_to_send);
 469                //ts->size2 = sizeof(iacs_to_send);
 470                /* So just stuff it into TCP stream! (no error check...) */
 471#if ENABLE_FEATURE_TELNETD_STANDALONE
 472                safe_write(sock, iacs_to_send, sizeof(iacs_to_send));
 473#else
 474                safe_write(1, iacs_to_send, sizeof(iacs_to_send));
 475#endif
 476                /*ts->rdidx2 = 0; - xzalloc did it */
 477                /*ts->size2 = 0;*/
 478        }
 479
 480        fflush_all();
 481        pid = vfork(); /* NOMMU-friendly */
 482        if (pid < 0) {
 483                free(ts);
 484                close(fd);
 485                /* sock will be closed by caller */
 486                bb_perror_msg("vfork");
 487                return NULL;
 488        }
 489        if (pid > 0) {
 490                /* Parent */
 491                ts->shell_pid = pid;
 492                return ts;
 493        }
 494
 495        /* Child */
 496        /* Careful - we are after vfork! */
 497
 498        /* Restore default signal handling ASAP */
 499        bb_signals((1 << SIGCHLD) + (1 << SIGPIPE), SIG_DFL);
 500
 501        pid = getpid();
 502
 503        if (ENABLE_FEATURE_UTMP) {
 504                len_and_sockaddr *lsa = get_peer_lsa(sock);
 505                char *hostname = NULL;
 506                if (lsa) {
 507                        hostname = xmalloc_sockaddr2dotted(&lsa->u.sa);
 508                        free(lsa);
 509                }
 510                write_new_utmp(pid, LOGIN_PROCESS, tty_name, /*username:*/ "LOGIN", hostname);
 511                free(hostname);
 512        }
 513
 514        /* Make new session and process group */
 515        setsid();
 516
 517        /* Open the child's side of the tty */
 518        /* NB: setsid() disconnects from any previous ctty's. Therefore
 519         * we must open child's side of the tty AFTER setsid! */
 520        close(0);
 521        xopen(tty_name, O_RDWR); /* becomes our ctty */
 522        xdup2(0, 1);
 523        xdup2(0, 2);
 524        tcsetpgrp(0, pid); /* switch this tty's process group to us */
 525
 526        /* The pseudo-terminal allocated to the client is configured to operate
 527         * in cooked mode, and with XTABS CRMOD enabled (see tty(4)) */
 528        tcgetattr(0, &termbuf);
 529        termbuf.c_lflag |= ECHO; /* if we use readline we dont want this */
 530        termbuf.c_oflag |= ONLCR | XTABS;
 531        termbuf.c_iflag |= ICRNL;
 532        termbuf.c_iflag &= ~IXOFF;
 533        /*termbuf.c_lflag &= ~ICANON;*/
 534        tcsetattr_stdin_TCSANOW(&termbuf);
 535
 536        /* Uses FILE-based I/O to stdout, but does fflush_all(),
 537         * so should be safe with vfork.
 538         * I fear, though, that some users will have ridiculously big
 539         * issue files, and they may block writing to fd 1,
 540         * (parent is supposed to read it, but parent waits
 541         * for vforked child to exec!) */
 542        print_login_issue(G.issuefile, tty_name);
 543
 544        /* Exec shell / login / whatever */
 545        login_argv[0] = G.loginpath;
 546        login_argv[1] = NULL;
 547        /* exec busybox applet (if PREFER_APPLETS=y), if that fails,
 548         * exec external program.
 549         * NB: sock is either 0 or has CLOEXEC set on it.
 550         * fd has CLOEXEC set on it too. These two fds will be closed here.
 551         */
 552        BB_EXECVP(G.loginpath, (char **)login_argv);
 553        /* _exit is safer with vfork, and we shouldn't send message
 554         * to remote clients anyway */
 555        _exit(EXIT_FAILURE); /*bb_perror_msg_and_die("execv %s", G.loginpath);*/
 556}
 557
 558#if ENABLE_FEATURE_TELNETD_STANDALONE
 559
 560static void
 561free_session(struct tsession *ts)
 562{
 563        struct tsession *t;
 564
 565        if (option_mask32 & OPT_INETD)
 566                exit(EXIT_SUCCESS);
 567
 568        /* Unlink this telnet session from the session list */
 569        t = G.sessions;
 570        if (t == ts)
 571                G.sessions = ts->next;
 572        else {
 573                while (t->next != ts)
 574                        t = t->next;
 575                t->next = ts->next;
 576        }
 577
 578#if 0
 579        /* It was said that "normal" telnetd just closes ptyfd,
 580         * doesn't send SIGKILL. When we close ptyfd,
 581         * kernel sends SIGHUP to processes having slave side opened. */
 582        kill(ts->shell_pid, SIGKILL);
 583        waitpid(ts->shell_pid, NULL, 0);
 584#endif
 585        close(ts->ptyfd);
 586        close(ts->sockfd_read);
 587        /* We do not need to close(ts->sockfd_write), it's the same
 588         * as sockfd_read unless we are in inetd mode. But in inetd mode
 589         * we do not reach this */
 590        free(ts);
 591
 592        /* Scan all sessions and find new maxfd */
 593        G.maxfd = 0;
 594        ts = G.sessions;
 595        while (ts) {
 596                if (G.maxfd < ts->ptyfd)
 597                        G.maxfd = ts->ptyfd;
 598                if (G.maxfd < ts->sockfd_read)
 599                        G.maxfd = ts->sockfd_read;
 600#if 0
 601                /* Again, sockfd_write == sockfd_read here */
 602                if (G.maxfd < ts->sockfd_write)
 603                        G.maxfd = ts->sockfd_write;
 604#endif
 605                ts = ts->next;
 606        }
 607}
 608
 609#else /* !FEATURE_TELNETD_STANDALONE */
 610
 611/* Used in main() only, thus "return 0" actually is exit(EXIT_SUCCESS). */
 612#define free_session(ts) return 0
 613
 614#endif
 615
 616static void handle_sigchld(int sig UNUSED_PARAM)
 617{
 618        pid_t pid;
 619        struct tsession *ts;
 620        int save_errno = errno;
 621
 622        /* Looping: more than one child may have exited */
 623        while (1) {
 624                pid = wait_any_nohang(NULL);
 625                if (pid <= 0)
 626                        break;
 627                ts = G.sessions;
 628                while (ts) {
 629                        if (ts->shell_pid == pid) {
 630                                ts->shell_pid = -1;
 631                                update_utmp_DEAD_PROCESS(pid);
 632                                break;
 633                        }
 634                        ts = ts->next;
 635                }
 636        }
 637
 638        errno = save_errno;
 639}
 640
 641int telnetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 642int telnetd_main(int argc UNUSED_PARAM, char **argv)
 643{
 644        fd_set rdfdset, wrfdset;
 645        unsigned opt;
 646        int count;
 647        struct tsession *ts;
 648#if ENABLE_FEATURE_TELNETD_STANDALONE
 649#define IS_INETD (opt & OPT_INETD)
 650        int master_fd = master_fd; /* for compiler */
 651        int sec_linger = sec_linger;
 652        char *opt_bindaddr = NULL;
 653        char *opt_portnbr;
 654#else
 655        enum {
 656                IS_INETD = 1,
 657                master_fd = -1,
 658        };
 659#endif
 660        INIT_G();
 661
 662        /* Even if !STANDALONE, we accept (and ignore) -i, thus people
 663         * don't need to guess whether it's ok to pass -i to us */
 664        opt = getopt32(argv, "^"
 665                        "f:l:Ki"
 666                        IF_FEATURE_TELNETD_STANDALONE("p:b:F")
 667                        IF_FEATURE_TELNETD_INETD_WAIT("Sw:+") /* -w NUM */
 668                        "\0"
 669                        /* -w implies -F. -w and -i don't mix */
 670                        IF_FEATURE_TELNETD_INETD_WAIT("wF:i--w:w--i"),
 671                        &G.issuefile, &G.loginpath
 672                        IF_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr)
 673                        IF_FEATURE_TELNETD_INETD_WAIT(, &sec_linger)
 674        );
 675        if (!IS_INETD /*&& !re_execed*/) {
 676                /* inform that we start in standalone mode?
 677                 * May be useful when people forget to give -i */
 678                /*bb_error_msg("listening for connections");*/
 679                if (!(opt & OPT_FOREGROUND)) {
 680                        /* DAEMON_CHDIR_ROOT was giving inconsistent
 681                         * behavior with/without -F, -i */
 682                        bb_daemonize_or_rexec(0 /*was DAEMON_CHDIR_ROOT*/, argv);
 683                }
 684        }
 685        /* Redirect log to syslog early, if needed */
 686        if (IS_INETD || (opt & OPT_SYSLOG) || !(opt & OPT_FOREGROUND)) {
 687                openlog(applet_name, LOG_PID, LOG_DAEMON);
 688                logmode = LOGMODE_SYSLOG;
 689        }
 690#if ENABLE_FEATURE_TELNETD_STANDALONE
 691        if (IS_INETD) {
 692                G.sessions = make_new_session(0);
 693                if (!G.sessions) /* pty opening or vfork problem, exit */
 694                        return 1; /* make_new_session printed error message */
 695        } else {
 696                master_fd = 0;
 697                if (!(opt & OPT_WAIT)) {
 698                        unsigned portnbr = 23;
 699                        if (opt & OPT_PORT)
 700                                portnbr = xatou16(opt_portnbr);
 701                        master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr);
 702                        xlisten(master_fd, 1);
 703                }
 704                close_on_exec_on(master_fd);
 705        }
 706#else
 707        G.sessions = make_new_session();
 708        if (!G.sessions) /* pty opening or vfork problem, exit */
 709                return 1; /* make_new_session printed error message */
 710#endif
 711
 712        /* We don't want to die if just one session is broken */
 713        signal(SIGPIPE, SIG_IGN);
 714
 715        if (opt & OPT_WATCHCHILD)
 716                signal(SIGCHLD, handle_sigchld);
 717        else /* prevent dead children from becoming zombies */
 718                signal(SIGCHLD, SIG_IGN);
 719
 720/*
 721   This is how the buffers are used. The arrows indicate data flow.
 722
 723   +-------+     wridx1++     +------+     rdidx1++     +----------+
 724   |       | <--------------  | buf1 | <--------------  |          |
 725   |       |     size1--      +------+     size1++      |          |
 726   |  pty  |                                            |  socket  |
 727   |       |     rdidx2++     +------+     wridx2++     |          |
 728   |       |  --------------> | buf2 |  --------------> |          |
 729   +-------+     size2++      +------+     size2--      +----------+
 730
 731   size1: "how many bytes are buffered for pty between rdidx1 and wridx1?"
 732   size2: "how many bytes are buffered for socket between rdidx2 and wridx2?"
 733
 734   Each session has got two buffers. Buffers are circular. If sizeN == 0,
 735   buffer is empty. If sizeN == BUFSIZE, buffer is full. In both these cases
 736   rdidxN == wridxN.
 737*/
 738 again:
 739        FD_ZERO(&rdfdset);
 740        FD_ZERO(&wrfdset);
 741
 742        /* Select on the master socket, all telnet sockets and their
 743         * ptys if there is room in their session buffers.
 744         * NB: scalability problem: we recalculate entire bitmap
 745         * before each select. Can be a problem with 500+ connections. */
 746        ts = G.sessions;
 747        while (ts) {
 748                struct tsession *next = ts->next; /* in case we free ts */
 749                if (ts->shell_pid == -1) {
 750                        /* Child died and we detected that */
 751                        free_session(ts);
 752                } else {
 753                        if (ts->size1 > 0)       /* can write to pty */
 754                                FD_SET(ts->ptyfd, &wrfdset);
 755                        if (ts->size1 < BUFSIZE) /* can read from socket */
 756                                FD_SET(ts->sockfd_read, &rdfdset);
 757                        if (ts->size2 > 0)       /* can write to socket */
 758                                FD_SET(ts->sockfd_write, &wrfdset);
 759                        if (ts->size2 < BUFSIZE) /* can read from pty */
 760                                FD_SET(ts->ptyfd, &rdfdset);
 761                }
 762                ts = next;
 763        }
 764        if (!IS_INETD) {
 765                FD_SET(master_fd, &rdfdset);
 766                /* This is needed because free_session() does not
 767                 * take master_fd into account when it finds new
 768                 * maxfd among remaining fd's */
 769                if (master_fd > G.maxfd)
 770                        G.maxfd = master_fd;
 771        }
 772
 773        {
 774                struct timeval *tv_ptr = NULL;
 775#if ENABLE_FEATURE_TELNETD_INETD_WAIT
 776                struct timeval tv;
 777                if ((opt & OPT_WAIT) && !G.sessions) {
 778                        tv.tv_sec = sec_linger;
 779                        tv.tv_usec = 0;
 780                        tv_ptr = &tv;
 781                }
 782#endif
 783                count = select(G.maxfd + 1, &rdfdset, &wrfdset, NULL, tv_ptr);
 784        }
 785        if (count == 0) /* "telnetd -w SEC" timed out */
 786                return 0;
 787        if (count < 0)
 788                goto again; /* EINTR or ENOMEM */
 789
 790#if ENABLE_FEATURE_TELNETD_STANDALONE
 791        /* Check for and accept new sessions */
 792        if (!IS_INETD && FD_ISSET(master_fd, &rdfdset)) {
 793                int fd;
 794                struct tsession *new_ts;
 795
 796                fd = accept(master_fd, NULL, NULL);
 797                if (fd < 0)
 798                        goto again;
 799                close_on_exec_on(fd);
 800
 801                /* Create a new session and link it into active list */
 802                new_ts = make_new_session(fd);
 803                if (new_ts) {
 804                        new_ts->next = G.sessions;
 805                        G.sessions = new_ts;
 806                } else {
 807                        close(fd);
 808                }
 809        }
 810#endif
 811
 812        /* Then check for data tunneling */
 813        ts = G.sessions;
 814        while (ts) { /* For all sessions... */
 815                struct tsession *next = ts->next; /* in case we free ts */
 816
 817                if (/*ts->size1 &&*/ FD_ISSET(ts->ptyfd, &wrfdset)) {
 818                        /* Write to pty from buffer 1 */
 819                        count = safe_write_to_pty_decode_iac(ts);
 820                        if (count < 0) {
 821                                if (errno == EAGAIN)
 822                                        goto skip1;
 823                                goto kill_session;
 824                        }
 825                }
 826 skip1:
 827                if (/*ts->size2 &&*/ FD_ISSET(ts->sockfd_write, &wrfdset)) {
 828                        /* Write to socket from buffer 2 */
 829                        count = MIN(BUFSIZE - ts->wridx2, ts->size2);
 830                        count = safe_write_double_iac(ts->sockfd_write, (void*)(TS_BUF2(ts) + ts->wridx2), count);
 831                        if (count < 0) {
 832                                if (errno == EAGAIN)
 833                                        goto skip2;
 834                                goto kill_session;
 835                        }
 836                        ts->wridx2 += count;
 837                        if (ts->wridx2 >= BUFSIZE) /* actually == BUFSIZE */
 838                                ts->wridx2 = 0;
 839                        ts->size2 -= count;
 840                        if (ts->size2 == 0) {
 841                                ts->rdidx2 = 0;
 842                                ts->wridx2 = 0;
 843                        }
 844                }
 845 skip2:
 846
 847                if (/*ts->size1 < BUFSIZE &&*/ FD_ISSET(ts->sockfd_read, &rdfdset)) {
 848                        /* Read from socket to buffer 1 */
 849                        count = MIN(BUFSIZE - ts->rdidx1, BUFSIZE - ts->size1);
 850                        count = safe_read(ts->sockfd_read, TS_BUF1(ts) + ts->rdidx1, count);
 851                        if (count <= 0) {
 852                                if (count < 0 && errno == EAGAIN)
 853                                        goto skip3;
 854                                goto kill_session;
 855                        }
 856                        /* Ignore trailing NUL if it is there */
 857                        if (!TS_BUF1(ts)[ts->rdidx1 + count - 1]) {
 858                                --count;
 859                        }
 860                        ts->size1 += count;
 861                        ts->rdidx1 += count;
 862                        if (ts->rdidx1 >= BUFSIZE) /* actually == BUFSIZE */
 863                                ts->rdidx1 = 0;
 864                }
 865 skip3:
 866                if (/*ts->size2 < BUFSIZE &&*/ FD_ISSET(ts->ptyfd, &rdfdset)) {
 867                        /* Read from pty to buffer 2 */
 868                        count = MIN(BUFSIZE - ts->rdidx2, BUFSIZE - ts->size2);
 869                        count = safe_read(ts->ptyfd, TS_BUF2(ts) + ts->rdidx2, count);
 870                        if (count <= 0) {
 871                                if (count < 0 && errno == EAGAIN)
 872                                        goto skip4;
 873                                goto kill_session;
 874                        }
 875                        ts->size2 += count;
 876                        ts->rdidx2 += count;
 877                        if (ts->rdidx2 >= BUFSIZE) /* actually == BUFSIZE */
 878                                ts->rdidx2 = 0;
 879                }
 880 skip4:
 881                ts = next;
 882                continue;
 883 kill_session:
 884                if (ts->shell_pid > 0)
 885                        update_utmp_DEAD_PROCESS(ts->shell_pid);
 886                free_session(ts);
 887                ts = next;
 888        }
 889
 890        goto again;
 891}
 892