Hi,
I've got what I think is a reasonably stable version of dropbear's SSH server working in a non-posix, thread-based embedded system. I'd like to review the changes I made for anyone that may be considering doing this, but also to see if any flags
get raised by the folks that have been using this for a while.

Since I don't really know if there's much interest in this within the group, I'll skip a lot of detail for this pass and just note the main points. Then if it turns out that this is of interest we can dig in more (and I'll probably learn something)...

GOAL:
- A single ssh login at any given time, to connect to an embedded command line interface
  (no shell, no processes, no posix, etc..).

ASSUMPTIONS:
- Running a small kernel that supports threads;
- Using GCC for powerpc.
- I assume very little about any OS support for anything other than libc (in my case I do have an embedded FS, but that's easily bypassed). In other words: no shell process, no fork(), no exec(), no pipes, etc.. This includes no use of fprintf(...) as well. - I do have a TCP/IP stack; using a non-standard select (doesn't support multiple FDs)
  plus recv/send instead of read/write.
- I loosely base this on the "no-inetd" option; and I heavily chopped away at things in
  options.h (hopefully without breaking anything).
- Since there is no shell, this simply hooks to an internal command line processor. - Currently the server is built to run as if the following command line were invoked:
  ./dropbear -s -F -b "yada yada" -r dropbear_rsa_host_key
and since I do have an FS, I created the dropbear_rsa_host_key file using dropbearkey on my host machine, and simply copied it to my embedded system's FS for now. The need
  for the FS could easily be eliminated.

DETAILS:
My build puts the two math directories into a library, and then builds the server using portions of ~25 of the ~65 .c files that are in the main dropbear directory.

As a session starts up, I call loadhostkeys() and a hacked version of seedrandom() prior to svr_session(). The session_loop() function just blocks waiting for incoming packets from the network. User authentication is handled with a local function that simply verifies that the incoming login and password match; and the majority of
the code that forks off the shell is just bypassed.

I simulate interaction with a shell by intercepting incoming characters in common_recv_msg_channel_data(). Each line of text is simply passed to a command line parser. While that command line is being processed, all output from that
embedded command is sent through the function ssh_putchar():

static void
ssh_putcharc(struct Channel *channel,char c)
{
    CHECKCLEARTOWRITE();
    buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_DATA);
    buf_putint(ses.writepayload, channel->remotechan);
    buf_putint(ses.writepayload, 1);
    buf_putbyte(ses.writepayload, c);
    encrypt_packet();
}

and one other important thing...
At the bottom of encrypt_packet(), I call write_packet() so that the data
is immediately pushed out the socket.


SUMMARY:
Thats about it in the nutshell. The two big gotchas with this were issues that
would not necessarily be important in a process-based environment:

1. The use of dropbear_exit() for errors requires the use of setjmp/longjmp because
   its in a thread that needs to cleanup properly.
2. The heap is clean when exits are clean; but things get messy in a lot of
   exception cases; hence, the need for a dropbear-specific heap which
allows me to force a clean heap when the session ends (simulating the cleanup that
   is automatically done when the process exits).

I'm guessing that this would be a mess to integrate back into the distribution; however, I'm up for it if folks wanna go for it. Perhaps a "cub" version for embedded systems would be a peer to the main source directory and that would allow both the process and thread based versions to use as much of the same code as possible; but keep
the "mess" isolated a bit more.

Lemme know what you think,
Ed


Reply via email to