BB telnetd doesn't properly handle 2-byte IAC
sequences.  (Both in the 1.10 and 1.11 we've used.)
The following diff is what we've applied, it fixes
both IAC-IAC (emacs M-DEL) and IAC-NOP (putty keepalive):

$ diff -c networking/telnetd.c~ networking/telnetd.c
*** networking/telnetd.c~    2008-11-04 14:40:31.000000000 -0800
--- networking/telnetd.c     2008-11-06 14:16:51.000000000 -0800
***************
*** 74,82 ****
     past (bf + len) then that IAC will be left unprocessed and
*processed
     will be less than len.
  
-    FIXME - if we mean to send 0xFF to the terminal then it will be
escaped,
-    what is the escape character?  We aren't handling that situation
here.
- 
     CR-LF ->'s CR mapping is also done here, for convenience.
  
     NB: may fail to remove iacs which wrap around buffer!
--- 74,79 ----
***************
*** 103,108 ****
--- 100,113 ----
                        if (c == '\r' && ptr < end && (*ptr == '\n' ||
*ptr == '\0'))
                                ptr++;
                } else {
+                       if ((ptr+1) >= end)     // Need at least 2
bytes.
+                               break;
+                       if (ptr[1] == NOP)      // Ignore?  (Keepalive,
etc.)
+                               ptr += 2;
+                       else if (ptr[1] == IAC){// Literal IAC?
+                               *totty++ = ptr[1];
+                               ptr += 2;
+                       } else
                        /*
                         * TELOPT_NAWS support!
                         */
***************
$ 

The bracing/indention stinks a bit, but this minimized
the diff's so that's how we went with it.  A fully incorporated
fix would probably add a brace and an indention level.

We've also found a need to enable the stack's keepalive probes, our
embedded system will not tolerate an indefinite hung telnet session.
So we included the more-or-less standard telnetd -n disable option
in case the prior behavior was ever desired by our customers.
The diffs (continued from the invocation above) for that are:

*** 269,276 ****
  enum {
        OPT_WATCHCHILD = (1 << 2), /* -K */
        OPT_INETD      = (1 << 3) * ENABLE_FEATURE_TELNETD_STANDALONE,
/* -i */
!       OPT_PORT       = (1 << 4) * ENABLE_FEATURE_TELNETD_STANDALONE,
/* -p */
!       OPT_FOREGROUND = (1 << 6) * ENABLE_FEATURE_TELNETD_STANDALONE,
/* -F */
  };
  
  #if ENABLE_FEATURE_TELNETD_STANDALONE
--- 293,301 ----
  enum {
        OPT_WATCHCHILD = (1 << 2), /* -K */
        OPT_INETD      = (1 << 3) * ENABLE_FEATURE_TELNETD_STANDALONE,
/* -i */
!       OPT_NKEEPALIVE = (1 << 4) * ENABLE_FEATURE_TELNETD_STANDALONE,
/* -n */
!       OPT_PORT       = (1 << 5) * ENABLE_FEATURE_TELNETD_STANDALONE,
/* -p */
!       OPT_FOREGROUND = (1 << 7) * ENABLE_FEATURE_TELNETD_STANDALONE,
/* -F */
  };
  
  #if ENABLE_FEATURE_TELNETD_STANDALONE
***************
*** 373,379 ****
  #endif
        /* Even if !STANDALONE, we accept (and ignore) -i, thus people
         * don't need to guess whether it's ok to pass -i to us */
!       opt = getopt32(argv, "f:l:Ki"
USE_FEATURE_TELNETD_STANDALONE("p:b:F"),
                        &issuefile, &loginpath
                        USE_FEATURE_TELNETD_STANDALONE(, &opt_portnbr,
&opt_bindaddr));
        if (!IS_INETD /*&& !re_execed*/) {
--- 398,404 ----
  #endif
        /* Even if !STANDALONE, we accept (and ignore) -i, thus people
         * don't need to guess whether it's ok to pass -i to us */
!       opt = getopt32(argv, "f:l:Kin"
USE_FEATURE_TELNETD_STANDALONE("p:b:F"),
                        &issuefile, &loginpath
                        USE_FEATURE_TELNETD_STANDALONE(, &opt_portnbr,
&opt_bindaddr));
        if (!IS_INETD /*&& !re_execed*/) {
***************
*** 401,406 ****
--- 426,434 ----
  
  #if ENABLE_FEATURE_TELNETD_STANDALONE
        if (IS_INETD) {
+               if (!(opt & OPT_NKEEPALIVE))
+                       setsockopt(0, SOL_SOCKET, SO_KEEPALIVE,
+                       &const_int_1, sizeof(const_int_1));
                sessions = make_new_session(0);
                if (!sessions) /* pty opening or vfork problem, exit */
                        return 1; /* make_new_session prints error
message */
***************
*** 409,414 ****
--- 437,445 ----
                xlisten(master_fd, 1);
        }
  #else
+       if (!(opt & OPT_NKEEPALIVE))
+               setsockopt(0, SOL_SOCKET, SO_KEEPALIVE,
+               &const_int_1, sizeof(const_int_1));
        sessions = make_new_session();
        if (!sessions) /* pty opening or vfork problem, exit */
                return 1; /* make_new_session prints error message */
***************
*** 489,494 ****
--- 520,528 ----
                if (fd < 0)
                        goto again;
                /* Create a new session and link it into our active list
*/
+               if (!(opt & OPT_NKEEPALIVE))
+                       setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
+                       &const_int_1, sizeof(const_int_1));
                new_ts = make_new_session(fd);
                if (new_ts) {
                        new_ts->next = sessions;

Basically just add a new -n option, and everywhere that
make_new_session()
is called you check first to see if you need the setsockopt() call.  The
usage.h file got this too:

     "\n        -l LOGIN        Exec LOGIN on connect" \
+    "\n        -n              No session keepalive probes" \
     "\n        -f issue_file   Display issue_file instead of
/etc/issue" \

This might make a nice configurable option, if there's enough associated
code to trip the bloat-o-meter.

We also found a need to send the peer connection name into login's -h
argument so that successive programs could know to whom they were
talking.
I think that ssh already did this.  (I wasn't the one to put in this
code.)
Here are those diffs (part of the invocation above):

*** 154,164 ****
                USE_FEATURE_TELNETD_STANDALONE(int sock)
                SKIP_FEATURE_TELNETD_STANDALONE(void)
  ) {
!       const char *login_argv[2];
        struct termios termbuf;
        int fd, pid;
        char tty_name[GETPTY_BUFSIZE];
        struct tsession *ts = xzalloc(sizeof(struct tsession) + BUFSIZE
* 2);
  
        /*ts->buf1 = (char *)(ts + 1);*/
        /*ts->buf2 = ts->buf1 + BUFSIZE;*/
--- 159,187 ----
                USE_FEATURE_TELNETD_STANDALONE(int sock)
                SKIP_FEATURE_TELNETD_STANDALONE(void)
  ) {
!       const char *login_argv[3];
        struct termios termbuf;
        int fd, pid;
        char tty_name[GETPTY_BUFSIZE];
        struct tsession *ts = xzalloc(sizeof(struct tsession) + BUFSIZE
* 2);
+       struct sockaddr_in ir_sin;
+       socklen_t size;
+       char envBuf[32];
+ 
+       size = sizeof(ir_sin);
+ 
+       memset(envBuf,0, sizeof envBuf);
+ 
+       // grab the peer IP address before it's gone
+       if (getpeername(sock, (struct sockaddr *) &ir_sin, &size) < 0) {
+          fprintf(stdout, "%s %d getsockname
error\n\r",__FUNCTION__,__LINE__);
+          bb_perror_msg("getsockname");
+       }
+       else
+       {
+          //fprintf(stdout, "%s %d
0x%s\n\r",__FUNCTION__,__LINE__,inet_ntoa(ir_sin.sin_addr));
+          snprintf(envBuf, sizeof envBuf - 1,
"-h%s",inet_ntoa(ir_sin.sin_addr));
+       }
  
        /*ts->buf1 = (char *)(ts + 1);*/
        /*ts->buf2 = ts->buf1 + BUFSIZE;*/
***************
*** 256,262 ****
  
        /* Exec shell / login / whatever */
        login_argv[0] = loginpath;
!       login_argv[1] = NULL;
        /* exec busybox applet (if PREFER_APPLETS=y), if that fails,
         * exec external program */
        BB_EXECVP(loginpath, (char **)login_argv);
--- 279,286 ----
  
        /* Exec shell / login / whatever */
        login_argv[0] = loginpath;
!       login_argv[1] = envBuf;
!       login_argv[2] = NULL;
        /* exec busybox applet (if PREFER_APPLETS=y), if that fails,
         * exec external program */
        BB_EXECVP(loginpath, (char **)login_argv);
***************

Another configurable feature?

-- Jim




_______________________________________________
busybox mailing list
[email protected]
http://busybox.net/cgi-bin/mailman/listinfo/busybox

Reply via email to