telnet: move winsize detection closer to I/O loop, delete non-functioning debug code
[oweals/busybox.git] / networking / telnetd.c
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
129 struct 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 */
149 enum { BUFSIZE = (4 * 1024 - sizeof(struct tsession)) / 2 };
150
151
152 /* Globals */
153 struct 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  */
171 static ssize_t
172 safe_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  */
357 static 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 */
399 enum {
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
408 static struct tsession *
409 make_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
560 static void
561 free_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
616 static 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
641 int telnetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
642 int 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 }