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>
35 /* Structure that describes a session */
37 struct tsession *next;
38 int sockfd_read, sockfd_write, ptyfd;
41 /* two circular buffers */
42 /*char *buf1, *buf2;*/
43 /*#define TS_BUF1 ts->buf1*/
44 /*#define TS_BUF2 TS_BUF2*/
45 #define TS_BUF1 ((unsigned char*)(ts + 1))
46 #define TS_BUF2 (((unsigned char*)(ts + 1)) + BUFSIZE)
47 int rdidx1, wridx1, size1;
48 int rdidx2, wridx2, size2;
51 /* Two buffers are directly after tsession in malloced memory.
52 * Make whole thing fit in 4k */
53 enum { BUFSIZE = (4 * 1024 - sizeof(struct tsession)) / 2 };
58 static struct tsession *sessions;
60 static const char *loginpath = "/bin/login";
62 static const char *loginpath = DEFAULT_SHELL;
64 static const char *issuefile = "/etc/issue.net";
68 Remove all IAC's from buf1 (received IACs are ignored and must be removed
69 so as to not be interpreted by the terminal). Make an uninterrupted
70 string of characters fit for the terminal. Do this by packing
71 all characters meant for the terminal sequentially towards the end of buf.
73 Return a pointer to the beginning of the characters meant for the terminal.
74 and make *num_totty the number of characters that should be sent to
77 Note - If an IAC (3 byte quantity) starts before (bf + len) but extends
78 past (bf + len) then that IAC will be left unprocessed and *processed
79 will be less than len.
81 FIXME - if we mean to send 0xFF to the terminal then it will be escaped,
82 what is the escape character? We aren't handling that situation here.
84 CR-LF ->'s CR mapping is also done here, for convenience.
86 NB: may fail to remove iacs which wrap around buffer!
88 static unsigned char *
89 remove_iacs(struct tsession *ts, int *pnum_totty)
91 unsigned char *ptr0 = TS_BUF1 + ts->wridx1;
92 unsigned char *ptr = ptr0;
93 unsigned char *totty = ptr;
94 unsigned char *end = ptr + MIN(BUFSIZE - ts->wridx1, ts->size1);
103 /* We now map \r\n ==> \r for pragmatic reasons.
104 * Many client implementations send \r\n when
105 * the user hits the CarriageReturn key.
107 if (c == '\r' && ptr < end && (*ptr == '\n' || *ptr == '\0'))
111 * TELOPT_NAWS support!
113 if ((ptr+2) >= end) {
114 /* only the beginning of the IAC is in the
115 buffer we were asked to process, we can't
116 process this char. */
121 * IAC -> SB -> TELOPT_NAWS -> 4-byte -> IAC -> SE
123 else if (ptr[1] == SB && ptr[2] == TELOPT_NAWS) {
127 break; /* incomplete, can't process */
128 ws.ws_col = (ptr[3] << 8) | ptr[4];
129 ws.ws_row = (ptr[5] << 8) | ptr[6];
130 ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws);
133 /* skip 3-byte IAC non-SB cmd */
135 fprintf(stderr, "Ignoring IAC %s,%s\n",
136 TELCMD(ptr[1]), TELOPT(ptr[2]));
143 num_totty = totty - ptr0;
144 *pnum_totty = num_totty;
145 /* the difference between ptr and totty is number of iacs
146 we removed from the stream. Adjust buf1 accordingly. */
147 if ((ptr - totty) == 0) /* 99.999% of cases */
149 ts->wridx1 += ptr - totty;
150 ts->size1 -= ptr - totty;
151 /* move chars meant for the terminal towards the end of the buffer */
152 return memmove(ptr - num_totty, ptr0, num_totty);
157 getpty(char *line, int size)
160 #if ENABLE_FEATURE_DEVPTS
161 p = open("/dev/ptmx", O_RDWR);
168 bb_perror_msg("ptsname error (is /dev/pts mounted?)");
171 safe_strncpy(line, name, size);
179 strcpy(line, "/dev/ptyXX");
181 for (i = 0; i < 16; i++) {
182 line[8] = "pqrstuvwxyzabcde"[i];
184 if (stat(line, &stb) < 0) {
187 for (j = 0; j < 16; j++) {
188 line[9] = j < 10 ? j + '0' : j - 10 + 'a';
190 fprintf(stderr, "Trying to open device: %s\n", line);
191 p = open(line, O_RDWR | O_NOCTTY);
198 #endif /* FEATURE_DEVPTS */
203 static struct tsession *
205 USE_FEATURE_TELNETD_STANDALONE(int sock)
206 SKIP_FEATURE_TELNETD_STANDALONE(void)
208 const char *login_argv[2];
209 struct termios termbuf;
212 struct tsession *ts = xzalloc(sizeof(struct tsession) + BUFSIZE * 2);
214 /*ts->buf1 = (char *)(ts + 1);*/
215 /*ts->buf2 = ts->buf1 + BUFSIZE;*/
217 /* Got a new connection, set up a tty. */
218 fd = getpty(tty_name, 32);
220 bb_error_msg("can't create pty");
227 #if ENABLE_FEATURE_TELNETD_STANDALONE
228 ts->sockfd_read = sock;
230 if (!sock) { /* We are called with fd 0 - we are in inetd mode */
231 sock++; /* so use fd 1 for output */
234 ts->sockfd_write = sock;
238 /* ts->sockfd_read = 0; - done by xzalloc */
239 ts->sockfd_write = 1;
243 /* Make the telnet client understand we will echo characters so it
244 * should not do it locally. We don't tell the client to run linemode,
245 * because we want to handle line editing and tab completion and other
246 * stuff that requires char-by-char support. */
248 static const char iacs_to_send[] ALIGN1 = {
249 IAC, DO, TELOPT_ECHO,
250 IAC, DO, TELOPT_NAWS,
251 IAC, DO, TELOPT_LFLOW,
252 IAC, WILL, TELOPT_ECHO,
253 IAC, WILL, TELOPT_SGA
255 memcpy(TS_BUF2, iacs_to_send, sizeof(iacs_to_send));
256 ts->rdidx2 = sizeof(iacs_to_send);
257 ts->size2 = sizeof(iacs_to_send);
260 fflush(NULL); /* flush all streams */
261 pid = vfork(); /* NOMMU-friendly */
265 /* sock will be closed by caller */
266 bb_perror_msg("vfork");
276 /* Careful - we are after vfork! */
278 /* make new session and process group */
281 /* Restore default signal handling */
282 signal(SIGCHLD, SIG_DFL);
283 signal(SIGPIPE, SIG_DFL);
285 /* open the child's side of the tty. */
286 /* NB: setsid() disconnects from any previous ctty's. Therefore
287 * we must open child's side of the tty AFTER setsid! */
288 fd = xopen(tty_name, O_RDWR); /* becomes our ctty */
292 while (fd > 2) close(fd--);
293 tcsetpgrp(0, getpid()); /* switch this tty's process group to us */
295 /* The pseudo-terminal allocated to the client is configured to operate in
296 * cooked mode, and with XTABS CRMOD enabled (see tty(4)). */
297 tcgetattr(0, &termbuf);
298 termbuf.c_lflag |= ECHO; /* if we use readline we dont want this */
299 termbuf.c_oflag |= ONLCR | XTABS;
300 termbuf.c_iflag |= ICRNL;
301 termbuf.c_iflag &= ~IXOFF;
302 /*termbuf.c_lflag &= ~ICANON;*/
303 tcsetattr(0, TCSANOW, &termbuf);
305 /* Uses FILE-based I/O to stdout, but does fflush(stdout),
306 * so should be safe with vfork.
307 * I fear, though, that some users will have ridiculously big
308 * issue files, and they may block writing to fd 1,
309 * (parent is supposed to read it, but parent waits
310 * for vforked child to exec!) */
311 print_login_issue(issuefile, NULL);
313 /* Exec shell / login / whatever */
314 login_argv[0] = loginpath;
315 login_argv[1] = NULL;
316 /* exec busybox applet (if PREFER_APPLETS=y), if that fails,
317 * exec external program */
318 BB_EXECVP(loginpath, (char **)login_argv);
319 /* _exit is safer with vfork, and we shouldn't send message
320 * to remote clients anyway */
321 _exit(1); /*bb_perror_msg_and_die("execv %s", loginpath);*/
324 /* Must match getopt32 string */
326 OPT_WATCHCHILD = (1 << 2), /* -K */
327 OPT_INETD = (1 << 3) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -i */
328 OPT_PORT = (1 << 4) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -p */
329 OPT_FOREGROUND = (1 << 6) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -F */
332 #if ENABLE_FEATURE_TELNETD_STANDALONE
335 free_session(struct tsession *ts)
337 struct tsession *t = sessions;
339 if (option_mask32 & OPT_INETD)
342 /* Unlink this telnet session from the session list */
346 while (t->next != ts)
352 /* It was said that "normal" telnetd just closes ptyfd,
353 * doesn't send SIGKILL. When we close ptyfd,
354 * kernel sends SIGHUP to processes having slave side opened. */
355 kill(ts->shell_pid, SIGKILL);
356 wait4(ts->shell_pid, NULL, 0, NULL);
359 close(ts->sockfd_read);
360 /* We do not need to close(ts->sockfd_write), it's the same
361 * as sockfd_read unless we are in inetd mode. But in inetd mode
362 * we do not reach this */
365 /* Scan all sessions and find new maxfd */
369 if (maxfd < ts->ptyfd)
371 if (maxfd < ts->sockfd_read)
372 maxfd = ts->sockfd_read;
374 /* Again, sockfd_write == sockfd_read here */
375 if (maxfd < ts->sockfd_write)
376 maxfd = ts->sockfd_write;
382 #else /* !FEATURE_TELNETD_STANDALONE */
384 /* Used in main() only, thus "return 0" actually is exit(0). */
385 #define free_session(ts) return 0
389 static void handle_sigchld(int sig)
394 /* Looping: more than one child may have exited */
396 pid = wait_any_nohang(NULL);
401 if (ts->shell_pid == pid) {
410 int telnetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
411 int telnetd_main(int argc, char **argv)
413 fd_set rdfdset, wrfdset;
417 #if ENABLE_FEATURE_TELNETD_STANDALONE
418 #define IS_INETD (opt & OPT_INETD)
419 int master_fd = master_fd; /* be happy, gcc */
420 unsigned portnbr = 23;
421 char *opt_bindaddr = NULL;
430 /* Even if !STANDALONE, we accept (and ignore) -i, thus people
431 * don't need to guess whether it's ok to pass -i to us */
432 opt = getopt32(argv, "f:l:Ki" USE_FEATURE_TELNETD_STANDALONE("p:b:F"),
433 &issuefile, &loginpath
434 USE_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr));
435 if (!IS_INETD /*&& !re_execed*/) {
436 /* inform that we start in standalone mode?
437 * May be useful when people forget to give -i */
438 /*bb_error_msg("listening for connections");*/
439 if (!(opt & OPT_FOREGROUND)) {
440 /* DAEMON_CHDIR_ROOT was giving inconsistent
441 * behavior with/without -F, -i */
442 bb_daemonize_or_rexec(0 /*was DAEMON_CHDIR_ROOT*/, argv);
445 /* Redirect log to syslog early, if needed */
446 if (IS_INETD || !(opt & OPT_FOREGROUND)) {
447 openlog(applet_name, 0, LOG_USER);
448 logmode = LOGMODE_SYSLOG;
450 USE_FEATURE_TELNETD_STANDALONE(
452 portnbr = xatou16(opt_portnbr);
455 /* Used to check access(loginpath, X_OK) here. Pointless.
456 * exec will do this for us for free later. */
458 #if ENABLE_FEATURE_TELNETD_STANDALONE
460 sessions = make_new_session(0);
461 if (!sessions) /* pty opening or vfork problem, exit */
462 return 1; /* make_new_session prints error message */
464 master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr);
465 xlisten(master_fd, 1);
468 sessions = make_new_session();
469 if (!sessions) /* pty opening or vfork problem, exit */
470 return 1; /* make_new_session prints error message */
473 /* We don't want to die if just one session is broken */
474 signal(SIGPIPE, SIG_IGN);
476 if (opt & OPT_WATCHCHILD)
477 signal(SIGCHLD, handle_sigchld);
478 else /* prevent dead children from becoming zombies */
479 signal(SIGCHLD, SIG_IGN);
482 This is how the buffers are used. The arrows indicate the movement
484 +-------+ wridx1++ +------+ rdidx1++ +----------+
485 | | <-------------- | buf1 | <-------------- | |
486 | | size1-- +------+ size1++ | |
488 | | rdidx2++ +------+ wridx2++ | |
489 | | --------------> | buf2 | --------------> | |
490 +-------+ size2++ +------+ size2-- +----------+
492 size1: "how many bytes are buffered for pty between rdidx1 and wridx1?"
493 size2: "how many bytes are buffered for socket between rdidx2 and wridx2?"
495 Each session has got two buffers. Buffers are circular. If sizeN == 0,
496 buffer is empty. If sizeN == BUFSIZE, buffer is full. In both these cases
503 /* Select on the master socket, all telnet sockets and their
504 * ptys if there is room in their session buffers.
505 * NB: scalability problem: we recalculate entire bitmap
506 * before each select. Can be a problem with 500+ connections. */
509 struct tsession *next = ts->next; /* in case we free ts. */
510 if (ts->shell_pid == -1) {
511 /* Child died and we detected that */
514 if (ts->size1 > 0) /* can write to pty */
515 FD_SET(ts->ptyfd, &wrfdset);
516 if (ts->size1 < BUFSIZE) /* can read from socket */
517 FD_SET(ts->sockfd_read, &rdfdset);
518 if (ts->size2 > 0) /* can write to socket */
519 FD_SET(ts->sockfd_write, &wrfdset);
520 if (ts->size2 < BUFSIZE) /* can read from pty */
521 FD_SET(ts->ptyfd, &rdfdset);
526 FD_SET(master_fd, &rdfdset);
527 /* This is needed because free_session() does not
528 * take master_fd into account when it finds new
529 * maxfd among remaining fd's */
530 if (master_fd > maxfd)
534 count = select(maxfd + 1, &rdfdset, &wrfdset, NULL, NULL);
536 goto again; /* EINTR or ENOMEM */
538 #if ENABLE_FEATURE_TELNETD_STANDALONE
539 /* First check for and accept new sessions. */
540 if (!IS_INETD && FD_ISSET(master_fd, &rdfdset)) {
542 struct tsession *new_ts;
544 fd = accept(master_fd, NULL, NULL);
547 /* Create a new session and link it into our active list */
548 new_ts = make_new_session(fd);
550 new_ts->next = sessions;
558 /* Then check for data tunneling. */
560 while (ts) { /* For all sessions... */
561 struct tsession *next = ts->next; /* in case we free ts. */
563 if (/*ts->size1 &&*/ FD_ISSET(ts->ptyfd, &wrfdset)) {
566 /* Write to pty from buffer 1. */
567 ptr = remove_iacs(ts, &num_totty);
568 count = safe_write(ts->ptyfd, ptr, num_totty);
576 if (ts->wridx1 >= BUFSIZE) /* actually == BUFSIZE */
580 if (/*ts->size2 &&*/ FD_ISSET(ts->sockfd_write, &wrfdset)) {
581 /* Write to socket from buffer 2. */
582 count = MIN(BUFSIZE - ts->wridx2, ts->size2);
583 count = safe_write(ts->sockfd_write, TS_BUF2 + ts->wridx2, count);
591 if (ts->wridx2 >= BUFSIZE) /* actually == BUFSIZE */
595 /* Should not be needed, but... remove_iacs is actually buggy
596 * (it cannot process iacs which wrap around buffer's end)!
597 * Since properly fixing it requires writing bigger code,
598 * we rely instead on this code making it virtually impossible
599 * to have wrapped iac (people don't type at 2k/second).
600 * It also allows for bigger reads in common case. */
601 if (ts->size1 == 0) {
605 if (ts->size2 == 0) {
610 if (/*ts->size1 < BUFSIZE &&*/ FD_ISSET(ts->sockfd_read, &rdfdset)) {
611 /* Read from socket to buffer 1. */
612 count = MIN(BUFSIZE - ts->rdidx1, BUFSIZE - ts->size1);
613 count = safe_read(ts->sockfd_read, TS_BUF1 + ts->rdidx1, count);
615 if (count < 0 && errno == EAGAIN)
619 /* Ignore trailing NUL if it is there */
620 if (!TS_BUF1[ts->rdidx1 + count - 1]) {
625 if (ts->rdidx1 >= BUFSIZE) /* actually == BUFSIZE */
629 if (/*ts->size2 < BUFSIZE &&*/ FD_ISSET(ts->ptyfd, &rdfdset)) {
630 /* Read from pty to buffer 2. */
631 count = MIN(BUFSIZE - ts->rdidx2, BUFSIZE - ts->size2);
632 count = safe_read(ts->ptyfd, TS_BUF2 + ts->rdidx2, count);
634 if (count < 0 && errno == EAGAIN)
640 if (ts->rdidx2 >= BUFSIZE) /* actually == BUFSIZE */