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 source tree.
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
24 //usage:#define telnetd_trivial_usage
26 //usage:#define telnetd_full_usage "\n\n"
27 //usage: "Handle incoming telnet connections"
28 //usage: IF_NOT_FEATURE_TELNETD_STANDALONE(" via inetd") "\n"
29 //usage: "\n -l LOGIN Exec LOGIN on connect"
30 //usage: "\n -f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue"
31 //usage: "\n -K Close connection as soon as login exits"
32 //usage: "\n (normally wait until all programs close slave pty)"
33 //usage: IF_FEATURE_TELNETD_STANDALONE(
34 //usage: "\n -p PORT Port to listen on"
35 //usage: "\n -b ADDR[:PORT] Address to bind to"
36 //usage: "\n -F Run in foreground"
37 //usage: "\n -i Inetd mode"
38 //usage: IF_FEATURE_TELNETD_INETD_WAIT(
39 //usage: "\n -w SEC Inetd 'wait' mode, linger time SEC"
40 //usage: "\n -S Log to syslog (implied by -i or without -F and -w)"
53 #include <arpa/telnet.h>
57 struct tsession *next;
63 /* two circular buffers */
64 /*char *buf1, *buf2;*/
65 /*#define TS_BUF1(ts) ts->buf1*/
66 /*#define TS_BUF2(ts) TS_BUF2(ts)*/
67 #define TS_BUF1(ts) ((unsigned char*)(ts + 1))
68 #define TS_BUF2(ts) (((unsigned char*)(ts + 1)) + BUFSIZE)
69 int rdidx1, wridx1, size1;
70 int rdidx2, wridx2, size2;
73 /* Two buffers are directly after tsession in malloced memory.
74 * Make whole thing fit in 4k */
75 enum { BUFSIZE = (4 * 1024 - sizeof(struct tsession)) / 2 };
80 struct tsession *sessions;
81 const char *loginpath;
82 const char *issuefile;
85 #define G (*(struct globals*)&bb_common_bufsiz1)
86 #define INIT_G() do { \
87 G.loginpath = "/bin/login"; \
88 G.issuefile = "/etc/issue.net"; \
93 Remove all IAC's from buf1 (received IACs are ignored and must be removed
94 so as to not be interpreted by the terminal). Make an uninterrupted
95 string of characters fit for the terminal. Do this by packing
96 all characters meant for the terminal sequentially towards the end of buf.
98 Return a pointer to the beginning of the characters meant for the terminal
99 and make *num_totty the number of characters that should be sent to
102 Note - if an IAC (3 byte quantity) starts before (bf + len) but extends
103 past (bf + len) then that IAC will be left unprocessed and *processed
104 will be less than len.
106 CR-LF ->'s CR mapping is also done here, for convenience.
108 NB: may fail to remove iacs which wrap around buffer!
110 static unsigned char *
111 remove_iacs(struct tsession *ts, int *pnum_totty)
113 unsigned char *ptr0 = TS_BUF1(ts) + ts->wridx1;
114 unsigned char *ptr = ptr0;
115 unsigned char *totty = ptr;
116 unsigned char *end = ptr + MIN(BUFSIZE - ts->wridx1, ts->size1);
125 /* We map \r\n ==> \r for pragmatic reasons.
126 * Many client implementations send \r\n when
127 * the user hits the CarriageReturn key.
129 if (c == '\r' && ptr < end && (*ptr == '\n' || *ptr == '\0'))
136 if (ptr[1] == NOP) { /* Ignore? (putty keepalive, etc.) */
140 if (ptr[1] == IAC) { /* Literal IAC? (emacs M-DEL) */
147 * TELOPT_NAWS support!
149 if ((ptr+2) >= end) {
150 /* Only the beginning of the IAC is in the
151 buffer we were asked to process, we can't
156 * IAC -> SB -> TELOPT_NAWS -> 4-byte -> IAC -> SE
158 if (ptr[1] == SB && ptr[2] == TELOPT_NAWS) {
161 break; /* incomplete, can't process */
162 ws.ws_col = (ptr[3] << 8) | ptr[4];
163 ws.ws_row = (ptr[5] << 8) | ptr[6];
164 ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws);
168 /* skip 3-byte IAC non-SB cmd */
170 fprintf(stderr, "Ignoring IAC %s,%s\n",
171 TELCMD(ptr[1]), TELOPT(ptr[2]));
176 num_totty = totty - ptr0;
177 *pnum_totty = num_totty;
178 /* The difference between ptr and totty is number of iacs
179 we removed from the stream. Adjust buf1 accordingly */
180 if ((ptr - totty) == 0) /* 99.999% of cases */
182 ts->wridx1 += ptr - totty;
183 ts->size1 -= ptr - totty;
184 /* Move chars meant for the terminal towards the end of the buffer */
185 return memmove(ptr - num_totty, ptr0, num_totty);
189 * Converting single IAC into double on output
191 static size_t iac_safe_write(int fd, const char *buf, size_t count)
194 size_t wr, rc, total;
200 if (*buf == (char)IAC) {
201 static const char IACIAC[] ALIGN1 = { IAC, IAC };
202 rc = safe_write(fd, IACIAC, 2);
210 /* count != 0, *buf != IAC */
211 IACptr = memchr(buf, IAC, count);
215 rc = safe_write(fd, buf, wr);
222 /* here: rc - result of last short write */
223 if ((ssize_t)rc < 0) { /* error? */
231 /* Must match getopt32 string */
233 OPT_WATCHCHILD = (1 << 2), /* -K */
234 OPT_INETD = (1 << 3) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -i */
235 OPT_PORT = (1 << 4) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -p PORT */
236 OPT_FOREGROUND = (1 << 6) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -F */
237 OPT_SYSLOG = (1 << 7) * ENABLE_FEATURE_TELNETD_INETD_WAIT, /* -S */
238 OPT_WAIT = (1 << 8) * ENABLE_FEATURE_TELNETD_INETD_WAIT, /* -w SEC */
241 static struct tsession *
243 IF_FEATURE_TELNETD_STANDALONE(int sock)
244 IF_NOT_FEATURE_TELNETD_STANDALONE(void)
246 #if !ENABLE_FEATURE_TELNETD_STANDALONE
249 const char *login_argv[2];
250 struct termios termbuf;
252 char tty_name[GETPTY_BUFSIZE];
253 struct tsession *ts = xzalloc(sizeof(struct tsession) + BUFSIZE * 2);
255 /*ts->buf1 = (char *)(ts + 1);*/
256 /*ts->buf2 = ts->buf1 + BUFSIZE;*/
258 /* Got a new connection, set up a tty */
259 fd = xgetpty(tty_name);
264 close_on_exec_on(fd);
266 /* SO_KEEPALIVE by popular demand */
267 setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1));
268 #if ENABLE_FEATURE_TELNETD_STANDALONE
269 ts->sockfd_read = sock;
271 if (sock == 0) { /* We are called with fd 0 - we are in inetd mode */
272 sock++; /* so use fd 1 for output */
275 ts->sockfd_write = sock;
279 /* ts->sockfd_read = 0; - done by xzalloc */
280 ts->sockfd_write = 1;
285 /* Make the telnet client understand we will echo characters so it
286 * should not do it locally. We don't tell the client to run linemode,
287 * because we want to handle line editing and tab completion and other
288 * stuff that requires char-by-char support. */
290 static const char iacs_to_send[] ALIGN1 = {
291 IAC, DO, TELOPT_ECHO,
292 IAC, DO, TELOPT_NAWS,
293 /* This requires telnetd.ctrlSQ.patch (incomplete) */
294 /*IAC, DO, TELOPT_LFLOW,*/
295 IAC, WILL, TELOPT_ECHO,
296 IAC, WILL, TELOPT_SGA
298 /* This confuses iac_safe_write(), it will try to duplicate
300 //memcpy(TS_BUF2(ts), iacs_to_send, sizeof(iacs_to_send));
301 //ts->rdidx2 = sizeof(iacs_to_send);
302 //ts->size2 = sizeof(iacs_to_send);
303 /* So just stuff it into TCP stream! (no error check...) */
304 #if ENABLE_FEATURE_TELNETD_STANDALONE
305 safe_write(sock, iacs_to_send, sizeof(iacs_to_send));
307 safe_write(1, iacs_to_send, sizeof(iacs_to_send));
309 /*ts->rdidx2 = 0; - xzalloc did it */
314 pid = vfork(); /* NOMMU-friendly */
318 /* sock will be closed by caller */
319 bb_perror_msg("vfork");
329 /* Careful - we are after vfork! */
331 /* Restore default signal handling ASAP */
332 bb_signals((1 << SIGCHLD) + (1 << SIGPIPE), SIG_DFL);
336 if (ENABLE_FEATURE_UTMP) {
337 len_and_sockaddr *lsa = get_peer_lsa(sock);
338 char *hostname = NULL;
340 hostname = xmalloc_sockaddr2dotted(&lsa->u.sa);
343 write_new_utmp(pid, LOGIN_PROCESS, tty_name, /*username:*/ "LOGIN", hostname);
347 /* Make new session and process group */
350 /* Open the child's side of the tty */
351 /* NB: setsid() disconnects from any previous ctty's. Therefore
352 * we must open child's side of the tty AFTER setsid! */
354 xopen(tty_name, O_RDWR); /* becomes our ctty */
357 tcsetpgrp(0, pid); /* switch this tty's process group to us */
359 /* The pseudo-terminal allocated to the client is configured to operate
360 * in cooked mode, and with XTABS CRMOD enabled (see tty(4)) */
361 tcgetattr(0, &termbuf);
362 termbuf.c_lflag |= ECHO; /* if we use readline we dont want this */
363 termbuf.c_oflag |= ONLCR | XTABS;
364 termbuf.c_iflag |= ICRNL;
365 termbuf.c_iflag &= ~IXOFF;
366 /*termbuf.c_lflag &= ~ICANON;*/
367 tcsetattr_stdin_TCSANOW(&termbuf);
369 /* Uses FILE-based I/O to stdout, but does fflush_all(),
370 * so should be safe with vfork.
371 * I fear, though, that some users will have ridiculously big
372 * issue files, and they may block writing to fd 1,
373 * (parent is supposed to read it, but parent waits
374 * for vforked child to exec!) */
375 print_login_issue(G.issuefile, tty_name);
377 /* Exec shell / login / whatever */
378 login_argv[0] = G.loginpath;
379 login_argv[1] = NULL;
380 /* exec busybox applet (if PREFER_APPLETS=y), if that fails,
381 * exec external program.
382 * NB: sock is either 0 or has CLOEXEC set on it.
383 * fd has CLOEXEC set on it too. These two fds will be closed here.
385 BB_EXECVP(G.loginpath, (char **)login_argv);
386 /* _exit is safer with vfork, and we shouldn't send message
387 * to remote clients anyway */
388 _exit(EXIT_FAILURE); /*bb_perror_msg_and_die("execv %s", G.loginpath);*/
391 #if ENABLE_FEATURE_TELNETD_STANDALONE
394 free_session(struct tsession *ts)
398 if (option_mask32 & OPT_INETD)
401 /* Unlink this telnet session from the session list */
404 G.sessions = ts->next;
406 while (t->next != ts)
412 /* It was said that "normal" telnetd just closes ptyfd,
413 * doesn't send SIGKILL. When we close ptyfd,
414 * kernel sends SIGHUP to processes having slave side opened. */
415 kill(ts->shell_pid, SIGKILL);
416 waitpid(ts->shell_pid, NULL, 0);
419 close(ts->sockfd_read);
420 /* We do not need to close(ts->sockfd_write), it's the same
421 * as sockfd_read unless we are in inetd mode. But in inetd mode
422 * we do not reach this */
425 /* Scan all sessions and find new maxfd */
429 if (G.maxfd < ts->ptyfd)
431 if (G.maxfd < ts->sockfd_read)
432 G.maxfd = ts->sockfd_read;
434 /* Again, sockfd_write == sockfd_read here */
435 if (G.maxfd < ts->sockfd_write)
436 G.maxfd = ts->sockfd_write;
442 #else /* !FEATURE_TELNETD_STANDALONE */
444 /* Used in main() only, thus "return 0" actually is exit(EXIT_SUCCESS). */
445 #define free_session(ts) return 0
449 static void handle_sigchld(int sig UNUSED_PARAM)
453 int save_errno = errno;
455 /* Looping: more than one child may have exited */
457 pid = wait_any_nohang(NULL);
462 if (ts->shell_pid == pid) {
465 // When init(8) finds that a process has exited, it locates its utmp entry
466 // by ut_pid, sets ut_type to DEAD_PROCESS, and clears ut_user, ut_host
467 // and ut_time with null bytes.
468 // [same applies to other processes which maintain utmp entries, like telnetd]
470 // We do not bother actually clearing fields:
471 // it might be interesting to know who was logged in and from where
472 update_utmp(pid, DEAD_PROCESS, /*tty_name:*/ NULL, /*username:*/ NULL, /*hostname:*/ NULL);
482 int telnetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
483 int telnetd_main(int argc UNUSED_PARAM, char **argv)
485 fd_set rdfdset, wrfdset;
489 #if ENABLE_FEATURE_TELNETD_STANDALONE
490 #define IS_INETD (opt & OPT_INETD)
491 int master_fd = master_fd; /* for compiler */
492 int sec_linger = sec_linger;
493 char *opt_bindaddr = NULL;
503 /* -w NUM, and implies -F. -w and -i don't mix */
504 IF_FEATURE_TELNETD_INETD_WAIT(opt_complementary = "wF:w+:i--w:w--i";)
505 /* Even if !STANDALONE, we accept (and ignore) -i, thus people
506 * don't need to guess whether it's ok to pass -i to us */
507 opt = getopt32(argv, "f:l:Ki"
508 IF_FEATURE_TELNETD_STANDALONE("p:b:F")
509 IF_FEATURE_TELNETD_INETD_WAIT("Sw:"),
510 &G.issuefile, &G.loginpath
511 IF_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr)
512 IF_FEATURE_TELNETD_INETD_WAIT(, &sec_linger)
514 if (!IS_INETD /*&& !re_execed*/) {
515 /* inform that we start in standalone mode?
516 * May be useful when people forget to give -i */
517 /*bb_error_msg("listening for connections");*/
518 if (!(opt & OPT_FOREGROUND)) {
519 /* DAEMON_CHDIR_ROOT was giving inconsistent
520 * behavior with/without -F, -i */
521 bb_daemonize_or_rexec(0 /*was DAEMON_CHDIR_ROOT*/, argv);
524 /* Redirect log to syslog early, if needed */
525 if (IS_INETD || (opt & OPT_SYSLOG) || !(opt & OPT_FOREGROUND)) {
526 openlog(applet_name, LOG_PID, LOG_DAEMON);
527 logmode = LOGMODE_SYSLOG;
529 #if ENABLE_FEATURE_TELNETD_STANDALONE
531 G.sessions = make_new_session(0);
532 if (!G.sessions) /* pty opening or vfork problem, exit */
533 return 1; /* make_new_session printed error message */
536 if (!(opt & OPT_WAIT)) {
537 unsigned portnbr = 23;
539 portnbr = xatou16(opt_portnbr);
540 master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr);
541 xlisten(master_fd, 1);
543 close_on_exec_on(master_fd);
546 G.sessions = make_new_session();
547 if (!G.sessions) /* pty opening or vfork problem, exit */
548 return 1; /* make_new_session printed error message */
551 /* We don't want to die if just one session is broken */
552 signal(SIGPIPE, SIG_IGN);
554 if (opt & OPT_WATCHCHILD)
555 signal(SIGCHLD, handle_sigchld);
556 else /* prevent dead children from becoming zombies */
557 signal(SIGCHLD, SIG_IGN);
560 This is how the buffers are used. The arrows indicate data flow.
562 +-------+ wridx1++ +------+ rdidx1++ +----------+
563 | | <-------------- | buf1 | <-------------- | |
564 | | size1-- +------+ size1++ | |
566 | | rdidx2++ +------+ wridx2++ | |
567 | | --------------> | buf2 | --------------> | |
568 +-------+ size2++ +------+ size2-- +----------+
570 size1: "how many bytes are buffered for pty between rdidx1 and wridx1?"
571 size2: "how many bytes are buffered for socket between rdidx2 and wridx2?"
573 Each session has got two buffers. Buffers are circular. If sizeN == 0,
574 buffer is empty. If sizeN == BUFSIZE, buffer is full. In both these cases
581 /* Select on the master socket, all telnet sockets and their
582 * ptys if there is room in their session buffers.
583 * NB: scalability problem: we recalculate entire bitmap
584 * before each select. Can be a problem with 500+ connections. */
587 struct tsession *next = ts->next; /* in case we free ts */
588 if (ts->shell_pid == -1) {
589 /* Child died and we detected that */
592 if (ts->size1 > 0) /* can write to pty */
593 FD_SET(ts->ptyfd, &wrfdset);
594 if (ts->size1 < BUFSIZE) /* can read from socket */
595 FD_SET(ts->sockfd_read, &rdfdset);
596 if (ts->size2 > 0) /* can write to socket */
597 FD_SET(ts->sockfd_write, &wrfdset);
598 if (ts->size2 < BUFSIZE) /* can read from pty */
599 FD_SET(ts->ptyfd, &rdfdset);
604 FD_SET(master_fd, &rdfdset);
605 /* This is needed because free_session() does not
606 * take master_fd into account when it finds new
607 * maxfd among remaining fd's */
608 if (master_fd > G.maxfd)
613 struct timeval *tv_ptr = NULL;
614 #if ENABLE_FEATURE_TELNETD_INETD_WAIT
616 if ((opt & OPT_WAIT) && !G.sessions) {
617 tv.tv_sec = sec_linger;
622 count = select(G.maxfd + 1, &rdfdset, &wrfdset, NULL, tv_ptr);
624 if (count == 0) /* "telnetd -w SEC" timed out */
627 goto again; /* EINTR or ENOMEM */
629 #if ENABLE_FEATURE_TELNETD_STANDALONE
630 /* Check for and accept new sessions */
631 if (!IS_INETD && FD_ISSET(master_fd, &rdfdset)) {
633 struct tsession *new_ts;
635 fd = accept(master_fd, NULL, NULL);
638 close_on_exec_on(fd);
640 /* Create a new session and link it into active list */
641 new_ts = make_new_session(fd);
643 new_ts->next = G.sessions;
651 /* Then check for data tunneling */
653 while (ts) { /* For all sessions... */
654 struct tsession *next = ts->next; /* in case we free ts */
656 if (/*ts->size1 &&*/ FD_ISSET(ts->ptyfd, &wrfdset)) {
659 /* Write to pty from buffer 1 */
660 ptr = remove_iacs(ts, &num_totty);
661 count = safe_write(ts->ptyfd, ptr, num_totty);
669 if (ts->wridx1 >= BUFSIZE) /* actually == BUFSIZE */
673 if (/*ts->size2 &&*/ FD_ISSET(ts->sockfd_write, &wrfdset)) {
674 /* Write to socket from buffer 2 */
675 count = MIN(BUFSIZE - ts->wridx2, ts->size2);
676 count = iac_safe_write(ts->sockfd_write, (void*)(TS_BUF2(ts) + ts->wridx2), count);
684 if (ts->wridx2 >= BUFSIZE) /* actually == BUFSIZE */
688 /* Should not be needed, but... remove_iacs is actually buggy
689 * (it cannot process iacs which wrap around buffer's end)!
690 * Since properly fixing it requires writing bigger code,
691 * we rely instead on this code making it virtually impossible
692 * to have wrapped iac (people don't type at 2k/second).
693 * It also allows for bigger reads in common case. */
694 if (ts->size1 == 0) {
698 if (ts->size2 == 0) {
703 if (/*ts->size1 < BUFSIZE &&*/ FD_ISSET(ts->sockfd_read, &rdfdset)) {
704 /* Read from socket to buffer 1 */
705 count = MIN(BUFSIZE - ts->rdidx1, BUFSIZE - ts->size1);
706 count = safe_read(ts->sockfd_read, TS_BUF1(ts) + ts->rdidx1, count);
708 if (count < 0 && errno == EAGAIN)
712 /* Ignore trailing NUL if it is there */
713 if (!TS_BUF1(ts)[ts->rdidx1 + count - 1]) {
718 if (ts->rdidx1 >= BUFSIZE) /* actually == BUFSIZE */
722 if (/*ts->size2 < BUFSIZE &&*/ FD_ISSET(ts->ptyfd, &rdfdset)) {
723 /* Read from pty to buffer 2 */
724 count = MIN(BUFSIZE - ts->rdidx2, BUFSIZE - ts->size2);
725 count = safe_read(ts->ptyfd, TS_BUF2(ts) + ts->rdidx2, count);
727 if (count < 0 && errno == EAGAIN)
733 if (ts->rdidx2 >= BUFSIZE) /* actually == BUFSIZE */
740 if (ts->shell_pid > 0)
741 update_utmp(ts->shell_pid, DEAD_PROCESS, /*tty_name:*/ NULL, /*username:*/ NULL, /*hostname:*/ NULL);