1 /* vi: set sw=4 ts=4: */
4 * Bjorn Wesen, Axis Communications AB (bjornw@axis.com)
6 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 * ---------------------------------------------------------------------------
9 * (C) Copyright 2000, Axis Communications AB, LUND, SWEDEN
10 ****************************************************************************
12 * The telnetd manpage says it all:
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.
20 * Vladimir Oleynik <dzo@simtreas.ru> 2001
21 * Set process group corrections, initial busybox port
33 #include <arpa/telnet.h>
36 struct tsession *next;
42 /* two circular buffers */
43 /*char *buf1, *buf2;*/
44 /*#define TS_BUF1(ts) ts->buf1*/
45 /*#define TS_BUF2(ts) TS_BUF2(ts)*/
46 #define TS_BUF1(ts) ((unsigned char*)(ts + 1))
47 #define TS_BUF2(ts) (((unsigned char*)(ts + 1)) + BUFSIZE)
48 int rdidx1, wridx1, size1;
49 int rdidx2, wridx2, size2;
52 /* Two buffers are directly after tsession in malloced memory.
53 * Make whole thing fit in 4k */
54 enum { BUFSIZE = (4 * 1024 - sizeof(struct tsession)) / 2 };
59 struct tsession *sessions;
60 const char *loginpath;
61 const char *issuefile;
64 #define G (*(struct globals*)&bb_common_bufsiz1)
65 #define INIT_G() do { \
66 G.loginpath = "/bin/login"; \
67 G.issuefile = "/etc/issue.net"; \
72 Remove all IAC's from buf1 (received IACs are ignored and must be removed
73 so as to not be interpreted by the terminal). Make an uninterrupted
74 string of characters fit for the terminal. Do this by packing
75 all characters meant for the terminal sequentially towards the end of buf.
77 Return a pointer to the beginning of the characters meant for the terminal.
78 and make *num_totty the number of characters that should be sent to
81 Note - If an IAC (3 byte quantity) starts before (bf + len) but extends
82 past (bf + len) then that IAC will be left unprocessed and *processed
83 will be less than len.
85 CR-LF ->'s CR mapping is also done here, for convenience.
87 NB: may fail to remove iacs which wrap around buffer!
89 static unsigned char *
90 remove_iacs(struct tsession *ts, int *pnum_totty)
92 unsigned char *ptr0 = TS_BUF1(ts) + ts->wridx1;
93 unsigned char *ptr = ptr0;
94 unsigned char *totty = ptr;
95 unsigned char *end = ptr + MIN(BUFSIZE - ts->wridx1, ts->size1);
104 /* We map \r\n ==> \r for pragmatic reasons.
105 * Many client implementations send \r\n when
106 * the user hits the CarriageReturn key.
108 if (c == '\r' && ptr < end && (*ptr == '\n' || *ptr == '\0'))
115 if (ptr[1] == NOP) { /* Ignore? (putty keepalive, etc.) */
119 if (ptr[1] == IAC) { /* Literal IAC? (emacs M-DEL) */
126 * TELOPT_NAWS support!
128 if ((ptr+2) >= end) {
129 /* Only the beginning of the IAC is in the
130 buffer we were asked to process, we can't
135 * IAC -> SB -> TELOPT_NAWS -> 4-byte -> IAC -> SE
137 if (ptr[1] == SB && ptr[2] == TELOPT_NAWS) {
140 break; /* incomplete, can't process */
141 ws.ws_col = (ptr[3] << 8) | ptr[4];
142 ws.ws_row = (ptr[5] << 8) | ptr[6];
143 ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws);
147 /* skip 3-byte IAC non-SB cmd */
149 fprintf(stderr, "Ignoring IAC %s,%s\n",
150 TELCMD(ptr[1]), TELOPT(ptr[2]));
155 num_totty = totty - ptr0;
156 *pnum_totty = num_totty;
157 /* The difference between ptr and totty is number of iacs
158 we removed from the stream. Adjust buf1 accordingly */
159 if ((ptr - totty) == 0) /* 99.999% of cases */
161 ts->wridx1 += ptr - totty;
162 ts->size1 -= ptr - totty;
163 /* Move chars meant for the terminal towards the end of the buffer */
164 return memmove(ptr - num_totty, ptr0, num_totty);
168 * Converting single IAC into double on output
170 static size_t iac_safe_write(int fd, const char *buf, size_t count)
173 size_t wr, rc, total;
179 if (*buf == (char)IAC) {
180 static const char IACIAC[] ALIGN1 = { IAC, IAC };
181 rc = safe_write(fd, IACIAC, 2);
189 /* count != 0, *buf != IAC */
190 IACptr = memchr(buf, IAC, count);
194 rc = safe_write(fd, buf, wr);
201 /* here: rc - result of last short write */
202 if ((ssize_t)rc < 0) { /* error? */
210 /* Must match getopt32 string */
212 OPT_WATCHCHILD = (1 << 2), /* -K */
213 OPT_INETD = (1 << 3) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -i */
214 OPT_PORT = (1 << 4) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -p */
215 OPT_FOREGROUND = (1 << 6) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -F */
218 static struct tsession *
220 IF_FEATURE_TELNETD_STANDALONE(int sock)
221 IF_NOT_FEATURE_TELNETD_STANDALONE(void)
223 const char *login_argv[2];
224 struct termios termbuf;
226 char tty_name[GETPTY_BUFSIZE];
227 struct tsession *ts = xzalloc(sizeof(struct tsession) + BUFSIZE * 2);
229 /*ts->buf1 = (char *)(ts + 1);*/
230 /*ts->buf2 = ts->buf1 + BUFSIZE;*/
232 /* Got a new connection, set up a tty */
233 fd = xgetpty(tty_name);
238 close_on_exec_on(fd);
240 #if ENABLE_FEATURE_TELNETD_STANDALONE
241 /* SO_KEEPALIVE by popular demand */
242 setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1));
243 ts->sockfd_read = sock;
245 if (sock == 0) { /* We are called with fd 0 - we are in inetd mode */
246 sock++; /* so use fd 1 for output */
249 ts->sockfd_write = sock;
253 /* SO_KEEPALIVE by popular demand */
254 setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1));
255 /* ts->sockfd_read = 0; - done by xzalloc */
256 ts->sockfd_write = 1;
261 /* Make the telnet client understand we will echo characters so it
262 * should not do it locally. We don't tell the client to run linemode,
263 * because we want to handle line editing and tab completion and other
264 * stuff that requires char-by-char support. */
266 static const char iacs_to_send[] ALIGN1 = {
267 IAC, DO, TELOPT_ECHO,
268 IAC, DO, TELOPT_NAWS,
269 /* This requires telnetd.ctrlSQ.patch (incomplete) */
270 /* IAC, DO, TELOPT_LFLOW, */
271 IAC, WILL, TELOPT_ECHO,
272 IAC, WILL, TELOPT_SGA
274 /* This confuses iac_safe_write(), it will try to duplicate
276 //memcpy(TS_BUF2(ts), iacs_to_send, sizeof(iacs_to_send));
277 //ts->rdidx2 = sizeof(iacs_to_send);
278 //ts->size2 = sizeof(iacs_to_send);
279 /* So just stuff it into TCP stream! (no error check...) */
280 #if ENABLE_FEATURE_TELNETD_STANDALONE
281 safe_write(sock, iacs_to_send, sizeof(iacs_to_send));
283 safe_write(1, iacs_to_send, sizeof(iacs_to_send));
285 /*ts->rdidx2 = 0; - xzalloc did it */
289 fflush(NULL); /* flush all streams */
290 pid = vfork(); /* NOMMU-friendly */
294 /* sock will be closed by caller */
295 bb_perror_msg("vfork");
305 /* Careful - we are after vfork! */
307 /* Restore default signal handling ASAP */
308 bb_signals((1 << SIGCHLD) + (1 << SIGPIPE), SIG_DFL);
310 /* Make new session and process group */
313 /* Open the child's side of the tty */
314 /* NB: setsid() disconnects from any previous ctty's. Therefore
315 * we must open child's side of the tty AFTER setsid! */
317 xopen(tty_name, O_RDWR); /* becomes our ctty */
320 tcsetpgrp(0, getpid()); /* switch this tty's process group to us */
322 /* The pseudo-terminal allocated to the client is configured to operate
323 * in cooked mode, and with XTABS CRMOD enabled (see tty(4)) */
324 tcgetattr(0, &termbuf);
325 termbuf.c_lflag |= ECHO; /* if we use readline we dont want this */
326 termbuf.c_oflag |= ONLCR | XTABS;
327 termbuf.c_iflag |= ICRNL;
328 termbuf.c_iflag &= ~IXOFF;
329 /*termbuf.c_lflag &= ~ICANON;*/
330 tcsetattr_stdin_TCSANOW(&termbuf);
332 /* Uses FILE-based I/O to stdout, but does fflush(stdout),
333 * so should be safe with vfork.
334 * I fear, though, that some users will have ridiculously big
335 * issue files, and they may block writing to fd 1,
336 * (parent is supposed to read it, but parent waits
337 * for vforked child to exec!) */
338 print_login_issue(G.issuefile, tty_name);
340 /* Exec shell / login / whatever */
341 login_argv[0] = G.loginpath;
342 login_argv[1] = NULL;
343 /* exec busybox applet (if PREFER_APPLETS=y), if that fails,
344 * exec external program.
345 * NB: sock is either 0 or has CLOEXEC set on it.
346 * fd has CLOEXEC set on it too. These two fds will be closed here.
348 BB_EXECVP(G.loginpath, (char **)login_argv);
349 /* _exit is safer with vfork, and we shouldn't send message
350 * to remote clients anyway */
351 _exit(EXIT_FAILURE); /*bb_perror_msg_and_die("execv %s", G.loginpath);*/
354 #if ENABLE_FEATURE_TELNETD_STANDALONE
357 free_session(struct tsession *ts)
359 struct tsession *t = G.sessions;
361 if (option_mask32 & OPT_INETD)
364 /* Unlink this telnet session from the session list */
366 G.sessions = ts->next;
368 while (t->next != ts)
374 /* It was said that "normal" telnetd just closes ptyfd,
375 * doesn't send SIGKILL. When we close ptyfd,
376 * kernel sends SIGHUP to processes having slave side opened. */
377 kill(ts->shell_pid, SIGKILL);
378 waitpid(ts->shell_pid, NULL, 0);
381 close(ts->sockfd_read);
382 /* We do not need to close(ts->sockfd_write), it's the same
383 * as sockfd_read unless we are in inetd mode. But in inetd mode
384 * we do not reach this */
387 /* Scan all sessions and find new maxfd */
391 if (G.maxfd < ts->ptyfd)
393 if (G.maxfd < ts->sockfd_read)
394 G.maxfd = ts->sockfd_read;
396 /* Again, sockfd_write == sockfd_read here */
397 if (G.maxfd < ts->sockfd_write)
398 G.maxfd = ts->sockfd_write;
404 #else /* !FEATURE_TELNETD_STANDALONE */
406 /* Used in main() only, thus "return 0" actually is exit(EXIT_SUCCESS). */
407 #define free_session(ts) return 0
411 static void handle_sigchld(int sig UNUSED_PARAM)
416 /* Looping: more than one child may have exited */
418 pid = wait_any_nohang(NULL);
423 if (ts->shell_pid == pid) {
432 int telnetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
433 int telnetd_main(int argc UNUSED_PARAM, char **argv)
435 fd_set rdfdset, wrfdset;
439 #if ENABLE_FEATURE_TELNETD_STANDALONE
440 #define IS_INETD (opt & OPT_INETD)
441 int master_fd = master_fd; /* be happy, gcc */
442 unsigned portnbr = 23;
443 char *opt_bindaddr = NULL;
454 /* Even if !STANDALONE, we accept (and ignore) -i, thus people
455 * don't need to guess whether it's ok to pass -i to us */
456 opt = getopt32(argv, "f:l:Ki" IF_FEATURE_TELNETD_STANDALONE("p:b:F"),
457 &G.issuefile, &G.loginpath
458 IF_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr));
459 if (!IS_INETD /*&& !re_execed*/) {
460 /* inform that we start in standalone mode?
461 * May be useful when people forget to give -i */
462 /*bb_error_msg("listening for connections");*/
463 if (!(opt & OPT_FOREGROUND)) {
464 /* DAEMON_CHDIR_ROOT was giving inconsistent
465 * behavior with/without -F, -i */
466 bb_daemonize_or_rexec(0 /*was DAEMON_CHDIR_ROOT*/, argv);
469 /* Redirect log to syslog early, if needed */
470 if (IS_INETD || !(opt & OPT_FOREGROUND)) {
471 openlog(applet_name, LOG_PID, LOG_DAEMON);
472 logmode = LOGMODE_SYSLOG;
474 IF_FEATURE_TELNETD_STANDALONE(
476 portnbr = xatou16(opt_portnbr);
479 /* Used to check access(G.loginpath, X_OK) here. Pointless.
480 * exec will do this for us for free later. */
482 #if ENABLE_FEATURE_TELNETD_STANDALONE
484 G.sessions = make_new_session(0);
485 if (!G.sessions) /* pty opening or vfork problem, exit */
486 return 1; /* make_new_session prints error message */
488 master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr);
489 xlisten(master_fd, 1);
490 close_on_exec_on(master_fd);
493 G.sessions = make_new_session();
494 if (!G.sessions) /* pty opening or vfork problem, exit */
495 return 1; /* make_new_session prints error message */
498 /* We don't want to die if just one session is broken */
499 signal(SIGPIPE, SIG_IGN);
501 if (opt & OPT_WATCHCHILD)
502 signal(SIGCHLD, handle_sigchld);
503 else /* prevent dead children from becoming zombies */
504 signal(SIGCHLD, SIG_IGN);
507 This is how the buffers are used. The arrows indicate data flow.
509 +-------+ wridx1++ +------+ rdidx1++ +----------+
510 | | <-------------- | buf1 | <-------------- | |
511 | | size1-- +------+ size1++ | |
513 | | rdidx2++ +------+ wridx2++ | |
514 | | --------------> | buf2 | --------------> | |
515 +-------+ size2++ +------+ size2-- +----------+
517 size1: "how many bytes are buffered for pty between rdidx1 and wridx1?"
518 size2: "how many bytes are buffered for socket between rdidx2 and wridx2?"
520 Each session has got two buffers. Buffers are circular. If sizeN == 0,
521 buffer is empty. If sizeN == BUFSIZE, buffer is full. In both these cases
528 /* Select on the master socket, all telnet sockets and their
529 * ptys if there is room in their session buffers.
530 * NB: scalability problem: we recalculate entire bitmap
531 * before each select. Can be a problem with 500+ connections. */
534 struct tsession *next = ts->next; /* in case we free ts */
535 if (ts->shell_pid == -1) {
536 /* Child died and we detected that */
539 if (ts->size1 > 0) /* can write to pty */
540 FD_SET(ts->ptyfd, &wrfdset);
541 if (ts->size1 < BUFSIZE) /* can read from socket */
542 FD_SET(ts->sockfd_read, &rdfdset);
543 if (ts->size2 > 0) /* can write to socket */
544 FD_SET(ts->sockfd_write, &wrfdset);
545 if (ts->size2 < BUFSIZE) /* can read from pty */
546 FD_SET(ts->ptyfd, &rdfdset);
551 FD_SET(master_fd, &rdfdset);
552 /* This is needed because free_session() does not
553 * take master_fd into account when it finds new
554 * maxfd among remaining fd's */
555 if (master_fd > G.maxfd)
559 count = select(G.maxfd + 1, &rdfdset, &wrfdset, NULL, NULL);
561 goto again; /* EINTR or ENOMEM */
563 #if ENABLE_FEATURE_TELNETD_STANDALONE
564 /* Check for and accept new sessions */
565 if (!IS_INETD && FD_ISSET(master_fd, &rdfdset)) {
567 struct tsession *new_ts;
569 fd = accept(master_fd, NULL, NULL);
572 close_on_exec_on(fd);
574 /* Create a new session and link it into active list */
575 new_ts = make_new_session(fd);
577 new_ts->next = G.sessions;
585 /* Then check for data tunneling */
587 while (ts) { /* For all sessions... */
588 struct tsession *next = ts->next; /* in case we free ts */
590 if (/*ts->size1 &&*/ FD_ISSET(ts->ptyfd, &wrfdset)) {
593 /* Write to pty from buffer 1 */
594 ptr = remove_iacs(ts, &num_totty);
595 count = safe_write(ts->ptyfd, ptr, num_totty);
603 if (ts->wridx1 >= BUFSIZE) /* actually == BUFSIZE */
607 if (/*ts->size2 &&*/ FD_ISSET(ts->sockfd_write, &wrfdset)) {
608 /* Write to socket from buffer 2 */
609 count = MIN(BUFSIZE - ts->wridx2, ts->size2);
610 count = iac_safe_write(ts->sockfd_write, (void*)(TS_BUF2(ts) + ts->wridx2), count);
618 if (ts->wridx2 >= BUFSIZE) /* actually == BUFSIZE */
622 /* Should not be needed, but... remove_iacs is actually buggy
623 * (it cannot process iacs which wrap around buffer's end)!
624 * Since properly fixing it requires writing bigger code,
625 * we rely instead on this code making it virtually impossible
626 * to have wrapped iac (people don't type at 2k/second).
627 * It also allows for bigger reads in common case. */
628 if (ts->size1 == 0) {
632 if (ts->size2 == 0) {
637 if (/*ts->size1 < BUFSIZE &&*/ FD_ISSET(ts->sockfd_read, &rdfdset)) {
638 /* Read from socket to buffer 1 */
639 count = MIN(BUFSIZE - ts->rdidx1, BUFSIZE - ts->size1);
640 count = safe_read(ts->sockfd_read, TS_BUF1(ts) + ts->rdidx1, count);
642 if (count < 0 && errno == EAGAIN)
646 /* Ignore trailing NUL if it is there */
647 if (!TS_BUF1(ts)[ts->rdidx1 + count - 1]) {
652 if (ts->rdidx1 >= BUFSIZE) /* actually == BUFSIZE */
656 if (/*ts->size2 < BUFSIZE &&*/ FD_ISSET(ts->ptyfd, &rdfdset)) {
657 /* Read from pty to buffer 2 */
658 count = MIN(BUFSIZE - ts->rdidx2, BUFSIZE - ts->size2);
659 count = safe_read(ts->ptyfd, TS_BUF2(ts) + ts->rdidx2, count);
661 if (count < 0 && errno == EAGAIN)
667 if (ts->rdidx2 >= BUFSIZE) /* actually == BUFSIZE */