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
32 #include <arpa/telnet.h>
33 #include <sys/syslog.h>
36 /* Structure that describes a session */
38 struct tsession *next;
39 int sockfd_read, sockfd_write, ptyfd;
42 /* two circular buffers */
43 /*char *buf1, *buf2;*/
44 /*#define TS_BUF1 ts->buf1*/
45 /*#define TS_BUF2 TS_BUF2*/
46 #define TS_BUF1 ((unsigned char*)(ts + 1))
47 #define TS_BUF2 (((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 static struct tsession *sessions;
61 static const char *loginpath = "/bin/login";
63 static const char *loginpath = DEFAULT_SHELL;
65 static const char *issuefile = "/etc/issue.net";
69 Remove all IAC's from buf1 (received IACs are ignored and must be removed
70 so as to not be interpreted by the terminal). Make an uninterrupted
71 string of characters fit for the terminal. Do this by packing
72 all characters meant for the terminal sequentially towards the end of buf.
74 Return a pointer to the beginning of the characters meant for the terminal.
75 and make *num_totty the number of characters that should be sent to
78 Note - If an IAC (3 byte quantity) starts before (bf + len) but extends
79 past (bf + len) then that IAC will be left unprocessed and *processed
80 will be less than len.
82 FIXME - if we mean to send 0xFF to the terminal then it will be escaped,
83 what is the escape character? We aren't handling that situation here.
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->wridx1;
93 unsigned char *ptr = ptr0;
94 unsigned char *totty = ptr;
95 unsigned char *end = ptr + MIN(BUFSIZE - ts->wridx1, ts->size1);
104 /* We now 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'))
112 * TELOPT_NAWS support!
114 if ((ptr+2) >= end) {
115 /* only the beginning of the IAC is in the
116 buffer we were asked to process, we can't
117 process this char. */
122 * IAC -> SB -> TELOPT_NAWS -> 4-byte -> IAC -> SE
124 else if (ptr[1] == SB && ptr[2] == TELOPT_NAWS) {
128 break; /* incomplete, can't process */
129 ws.ws_col = (ptr[3] << 8) | ptr[4];
130 ws.ws_row = (ptr[5] << 8) | ptr[6];
131 ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws);
134 /* skip 3-byte IAC non-SB cmd */
136 fprintf(stderr, "Ignoring IAC %s,%s\n",
137 TELCMD(ptr[1]), TELOPT(ptr[2]));
144 num_totty = totty - ptr0;
145 *pnum_totty = num_totty;
146 /* the difference between ptr and totty is number of iacs
147 we removed from the stream. Adjust buf1 accordingly. */
148 if ((ptr - totty) == 0) /* 99.999% of cases */
150 ts->wridx1 += ptr - totty;
151 ts->size1 -= ptr - totty;
152 /* move chars meant for the terminal towards the end of the buffer */
153 return memmove(ptr - num_totty, ptr0, num_totty);
158 getpty(char *line, int size)
161 #if ENABLE_FEATURE_DEVPTS
162 p = open("/dev/ptmx", O_RDWR);
169 bb_perror_msg("ptsname error (is /dev/pts mounted?)");
172 safe_strncpy(line, name, size);
180 strcpy(line, "/dev/ptyXX");
182 for (i = 0; i < 16; i++) {
183 line[8] = "pqrstuvwxyzabcde"[i];
185 if (stat(line, &stb) < 0) {
188 for (j = 0; j < 16; j++) {
189 line[9] = j < 10 ? j + '0' : j - 10 + 'a';
191 fprintf(stderr, "Trying to open device: %s\n", line);
192 p = open(line, O_RDWR | O_NOCTTY);
199 #endif /* FEATURE_DEVPTS */
204 static struct tsession *
206 USE_FEATURE_TELNETD_STANDALONE(int sock)
207 SKIP_FEATURE_TELNETD_STANDALONE(void)
209 const char *login_argv[2];
210 struct termios termbuf;
213 struct tsession *ts = xzalloc(sizeof(struct tsession) + BUFSIZE * 2);
215 /*ts->buf1 = (char *)(ts + 1);*/
216 /*ts->buf2 = ts->buf1 + BUFSIZE;*/
218 /* Got a new connection, set up a tty. */
219 fd = getpty(tty_name, 32);
221 bb_error_msg("can't create pty");
228 #if ENABLE_FEATURE_TELNETD_STANDALONE
229 ts->sockfd_read = sock;
231 if (!sock) { /* We are called with fd 0 - we are in inetd mode */
232 sock++; /* so use fd 1 for output */
235 ts->sockfd_write = sock;
239 /* ts->sockfd_read = 0; - done by xzalloc */
240 ts->sockfd_write = 1;
244 /* Make the telnet client understand we will echo characters so it
245 * should not do it locally. We don't tell the client to run linemode,
246 * because we want to handle line editing and tab completion and other
247 * stuff that requires char-by-char support. */
249 static const char iacs_to_send[] ALIGN1 = {
250 IAC, DO, TELOPT_ECHO,
251 IAC, DO, TELOPT_NAWS,
252 IAC, DO, TELOPT_LFLOW,
253 IAC, WILL, TELOPT_ECHO,
254 IAC, WILL, TELOPT_SGA
256 memcpy(TS_BUF2, iacs_to_send, sizeof(iacs_to_send));
257 ts->rdidx2 = sizeof(iacs_to_send);
258 ts->size2 = sizeof(iacs_to_send);
261 fflush(NULL); /* flush all streams */
262 pid = vfork(); /* NOMMU-friendly */
266 /* sock will be closed by caller */
267 bb_perror_msg("vfork");
277 /* Careful - we are after vfork! */
279 /* make new session and process group */
282 /* Restore default signal handling */
283 signal(SIGCHLD, SIG_DFL);
284 signal(SIGPIPE, SIG_DFL);
286 /* open the child's side of the tty. */
287 /* NB: setsid() disconnects from any previous ctty's. Therefore
288 * we must open child's side of the tty AFTER setsid! */
289 fd = xopen(tty_name, O_RDWR); /* becomes our ctty */
293 while (fd > 2) close(fd--);
294 tcsetpgrp(0, getpid()); /* switch this tty's process group to us */
296 /* The pseudo-terminal allocated to the client is configured to operate in
297 * cooked mode, and with XTABS CRMOD enabled (see tty(4)). */
298 tcgetattr(0, &termbuf);
299 termbuf.c_lflag |= ECHO; /* if we use readline we dont want this */
300 termbuf.c_oflag |= ONLCR | XTABS;
301 termbuf.c_iflag |= ICRNL;
302 termbuf.c_iflag &= ~IXOFF;
303 /*termbuf.c_lflag &= ~ICANON;*/
304 tcsetattr(0, TCSANOW, &termbuf);
306 /* Uses FILE-based I/O to stdout, but does fflush(stdout),
307 * so should be safe with vfork.
308 * I fear, though, that some users will have ridiculously big
309 * issue files, and they may block writing to fd 1,
310 * (parent is supposed to read it, but parent waits
311 * for vforked child to exec!) */
312 print_login_issue(issuefile, NULL);
314 /* Exec shell / login / whatever */
315 login_argv[0] = loginpath;
316 login_argv[1] = NULL;
317 /* exec busybox applet (if PREFER_APPLETS=y), if that fails,
318 * exec external program */
319 BB_EXECVP(loginpath, (char **)login_argv);
320 /* _exit is safer with vfork, and we shouldn't send message
321 * to remote clients anyway */
322 _exit(1); /*bb_perror_msg_and_die("execv %s", loginpath);*/
325 /* Must match getopt32 string */
327 OPT_WATCHCHILD = (1 << 2), /* -K */
328 OPT_INETD = (1 << 3) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -i */
329 OPT_PORT = (1 << 4) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -p */
330 OPT_FOREGROUND = (1 << 6) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -F */
333 #if ENABLE_FEATURE_TELNETD_STANDALONE
336 free_session(struct tsession *ts)
338 struct tsession *t = sessions;
340 if (option_mask32 & OPT_INETD)
343 /* Unlink this telnet session from the session list */
347 while (t->next != ts)
353 /* It was said that "normal" telnetd just closes ptyfd,
354 * doesn't send SIGKILL. When we close ptyfd,
355 * kernel sends SIGHUP to processes having slave side opened. */
356 kill(ts->shell_pid, SIGKILL);
357 wait4(ts->shell_pid, NULL, 0, NULL);
360 close(ts->sockfd_read);
361 /* We do not need to close(ts->sockfd_write), it's the same
362 * as sockfd_read unless we are in inetd mode. But in inetd mode
363 * we do not reach this */
366 /* Scan all sessions and find new maxfd */
370 if (maxfd < ts->ptyfd)
372 if (maxfd < ts->sockfd_read)
373 maxfd = ts->sockfd_read;
375 /* Again, sockfd_write == sockfd_read here */
376 if (maxfd < ts->sockfd_write)
377 maxfd = ts->sockfd_write;
383 #else /* !FEATURE_TELNETD_STANDALONE */
385 /* Used in main() only, thus "return 0" actually is exit(0). */
386 #define free_session(ts) return 0
390 static void handle_sigchld(int sig)
395 /* Looping: more than one child may have exited */
397 pid = waitpid(-1, NULL, WNOHANG);
402 if (ts->shell_pid == pid) {
411 int telnetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
412 int telnetd_main(int argc, char **argv)
414 fd_set rdfdset, wrfdset;
418 #if ENABLE_FEATURE_TELNETD_STANDALONE
419 #define IS_INETD (opt & OPT_INETD)
420 int master_fd = master_fd; /* be happy, gcc */
421 unsigned portnbr = 23;
422 char *opt_bindaddr = NULL;
431 /* Even if !STANDALONE, we accept (and ignore) -i, thus people
432 * don't need to guess whether it's ok to pass -i to us */
433 opt = getopt32(argv, "f:l:Ki" USE_FEATURE_TELNETD_STANDALONE("p:b:F"),
434 &issuefile, &loginpath
435 USE_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr));
436 if (!IS_INETD /*&& !re_execed*/) {
437 /* inform that we start in standalone mode?
438 * May be useful when people forget to give -i */
439 /*bb_error_msg("listening for connections");*/
440 if (!(opt & OPT_FOREGROUND)) {
441 /* DAEMON_CHDIR_ROOT was giving inconsistent
442 * behavior with/without -F, -i */
443 bb_daemonize_or_rexec(0 /*was DAEMON_CHDIR_ROOT*/, argv);
446 /* Redirect log to syslog early, if needed */
447 if (IS_INETD || !(opt & OPT_FOREGROUND)) {
448 openlog(applet_name, 0, LOG_USER);
449 logmode = LOGMODE_SYSLOG;
451 USE_FEATURE_TELNETD_STANDALONE(
453 portnbr = xatou16(opt_portnbr);
456 /* Used to check access(loginpath, X_OK) here. Pointless.
457 * exec will do this for us for free later. */
459 #if ENABLE_FEATURE_TELNETD_STANDALONE
461 sessions = make_new_session(0);
462 if (!sessions) /* pty opening or vfork problem, exit */
463 return 1; /* make_new_session prints error message */
465 master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr);
466 xlisten(master_fd, 1);
469 sessions = make_new_session();
470 if (!sessions) /* pty opening or vfork problem, exit */
471 return 1; /* make_new_session prints error message */
474 /* We don't want to die if just one session is broken */
475 signal(SIGPIPE, SIG_IGN);
477 if (opt & OPT_WATCHCHILD)
478 signal(SIGCHLD, handle_sigchld);
479 else /* prevent dead children from becoming zombies */
480 signal(SIGCHLD, SIG_IGN);
483 This is how the buffers are used. The arrows indicate the movement
485 +-------+ wridx1++ +------+ rdidx1++ +----------+
486 | | <-------------- | buf1 | <-------------- | |
487 | | size1-- +------+ size1++ | |
489 | | rdidx2++ +------+ wridx2++ | |
490 | | --------------> | buf2 | --------------> | |
491 +-------+ size2++ +------+ size2-- +----------+
493 size1: "how many bytes are buffered for pty between rdidx1 and wridx1?"
494 size2: "how many bytes are buffered for socket between rdidx2 and wridx2?"
496 Each session has got two buffers. Buffers are circular. If sizeN == 0,
497 buffer is empty. If sizeN == BUFSIZE, buffer is full. In both these cases
504 /* Select on the master socket, all telnet sockets and their
505 * ptys if there is room in their session buffers.
506 * NB: scalability problem: we recalculate entire bitmap
507 * before each select. Can be a problem with 500+ connections. */
510 struct tsession *next = ts->next; /* in case we free ts. */
511 if (ts->shell_pid == -1) {
512 /* Child died and we detected that */
515 if (ts->size1 > 0) /* can write to pty */
516 FD_SET(ts->ptyfd, &wrfdset);
517 if (ts->size1 < BUFSIZE) /* can read from socket */
518 FD_SET(ts->sockfd_read, &rdfdset);
519 if (ts->size2 > 0) /* can write to socket */
520 FD_SET(ts->sockfd_write, &wrfdset);
521 if (ts->size2 < BUFSIZE) /* can read from pty */
522 FD_SET(ts->ptyfd, &rdfdset);
527 FD_SET(master_fd, &rdfdset);
528 /* This is needed because free_session() does not
529 * take master_fd into account when it finds new
530 * maxfd among remaining fd's */
531 if (master_fd > maxfd)
535 count = select(maxfd + 1, &rdfdset, &wrfdset, NULL, NULL);
537 goto again; /* EINTR or ENOMEM */
539 #if ENABLE_FEATURE_TELNETD_STANDALONE
540 /* First check for and accept new sessions. */
541 if (!IS_INETD && FD_ISSET(master_fd, &rdfdset)) {
543 struct tsession *new_ts;
545 fd = accept(master_fd, NULL, NULL);
548 /* Create a new session and link it into our active list */
549 new_ts = make_new_session(fd);
551 new_ts->next = sessions;
559 /* Then check for data tunneling. */
561 while (ts) { /* For all sessions... */
562 struct tsession *next = ts->next; /* in case we free ts. */
564 if (/*ts->size1 &&*/ FD_ISSET(ts->ptyfd, &wrfdset)) {
567 /* Write to pty from buffer 1. */
568 ptr = remove_iacs(ts, &num_totty);
569 count = safe_write(ts->ptyfd, ptr, num_totty);
577 if (ts->wridx1 >= BUFSIZE) /* actually == BUFSIZE */
581 if (/*ts->size2 &&*/ FD_ISSET(ts->sockfd_write, &wrfdset)) {
582 /* Write to socket from buffer 2. */
583 count = MIN(BUFSIZE - ts->wridx2, ts->size2);
584 count = safe_write(ts->sockfd_write, TS_BUF2 + ts->wridx2, count);
592 if (ts->wridx2 >= BUFSIZE) /* actually == BUFSIZE */
596 /* Should not be needed, but... remove_iacs is actually buggy
597 * (it cannot process iacs which wrap around buffer's end)!
598 * Since properly fixing it requires writing bigger code,
599 * we rely instead on this code making it virtually impossible
600 * to have wrapped iac (people don't type at 2k/second).
601 * It also allows for bigger reads in common case. */
602 if (ts->size1 == 0) {
606 if (ts->size2 == 0) {
611 if (/*ts->size1 < BUFSIZE &&*/ FD_ISSET(ts->sockfd_read, &rdfdset)) {
612 /* Read from socket to buffer 1. */
613 count = MIN(BUFSIZE - ts->rdidx1, BUFSIZE - ts->size1);
614 count = safe_read(ts->sockfd_read, TS_BUF1 + ts->rdidx1, count);
616 if (count < 0 && errno == EAGAIN)
620 /* Ignore trailing NUL if it is there */
621 if (!TS_BUF1[ts->rdidx1 + count - 1]) {
626 if (ts->rdidx1 >= BUFSIZE) /* actually == BUFSIZE */
630 if (/*ts->size2 < BUFSIZE &&*/ FD_ISSET(ts->ptyfd, &rdfdset)) {
631 /* Read from pty to buffer 2. */
632 count = MIN(BUFSIZE - ts->rdidx2, BUFSIZE - ts->size2);
633 count = safe_read(ts->ptyfd, TS_BUF2 + ts->rdidx2, count);
635 if (count < 0 && errno == EAGAIN)
641 if (ts->rdidx2 >= BUFSIZE) /* actually == BUFSIZE */