# HG changeset patch # User Matt Johnston # Date 1170490845 0 # Node ID a5bca950120da94b1da0b8254a4caf5149a14f05 # Parent 4f2dbd1c36856240c4c34e01bba7a886c46f1324# Parent 2908122e9eedbdffcad221eca46601ef3d364f82 merge of '1dfbc5ef92391d01b576c8506061927869a89887' and '275426b7a4b94a0507c78327f86bcd2cd0b0f985' diff -r 2908122e9eed -r a5bca950120d CHANGES --- a/CHANGES Sat Feb 03 08:10:09 2007 +0000 +++ b/CHANGES Sat Feb 03 08:20:45 2007 +0000 @@ -1,3 +1,22 @@ +0.49 - Tues 13 June 2003 + +- Return immediately for "sleep 10 & echo foo", rather than waiting + for the sleep to return (pointed out by Rob Landley) + +- Added -P pidfile argument to the server (from Swen Schillig) + +- Compile fixes, make sure that all variable definitions are at the start + of a scope. + +- Use $HOME in preference to that from /etc/passwd, so that it + dbclient can still work on systems with a broken setup. + +- Add -N dbclient option for "no command" + +- Add -f dbclient option for "background after auth" + +- Try to finally fix ss_family compilation problems + 0.48.1 - Sat 11 March 2006 - Compile fix for scp diff -r 2908122e9eed -r a5bca950120d Makefile.in --- a/Makefile.in Sat Feb 03 08:10:09 2007 +0000 +++ b/Makefile.in Sat Feb 03 08:20:45 2007 +0000 @@ -64,13 +64,12 @@ sbindir=${exec_prefix}/sbin CC=@CC@ -LD=@LD@ AR=@AR@ RANLIB=@RANLIB@ STRIP=@STRIP@ INSTALL=@INSTALL@ CPPFLAGS=@CPPFLAGS@ -CFLAGS=-I. -I$(srcdir)/libtomcrypt/src/headers/ $(CPPFLAGS) @CFLAGS@ +CFLAGS=-I. -I$(srcdir) -I$(srcdir)/libtomcrypt/src/headers/ $(CPPFLAGS) @CFLAGS@ LIBS=$(LTC) $(LTM) @LIBS@ LDFLAGS=@LDFLAGS@ @@ -156,11 +155,11 @@ dropbear dbclient dropbearkey dropbearconvert: $(HEADERS) $(LTC) $(LTM) \ Makefile - $(LD) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBS) + $(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBS) # scp doesn't use the libs so is special. scp: $(SCPOBJS) $(HEADERS) Makefile - $(LD) $(LDFLAGS) -o $@$(EXEEXT) $(SCPOBJS) + $(CC) $(LDFLAGS) -o $@$(EXEEXT) $(SCPOBJS) # multi-binary compilation. @@ -173,7 +172,7 @@ dropbearmulti: multilink multibinary: $(HEADERS) $(MULTIOBJS) $(LTC) $(LTM) Makefile - $(LD) $(LDFLAGS) -o dropbearmulti$(EXEEXT) $(MULTIOBJS) $(LIBS) + $(CC) $(LDFLAGS) -o dropbearmulti$(EXEEXT) $(MULTIOBJS) $(LIBS) multilink: multibinary $(addprefix link, $(PROGRAMS)) @@ -187,6 +186,8 @@ $(LTM): options.h cd libtommath && $(MAKE) +.PHONY : clean sizes thisclean distclean tidy ltc-clean ltm-clean + ltc-clean: cd libtomcrypt && $(MAKE) clean diff -r 2908122e9eed -r a5bca950120d auth.h --- a/auth.h Sat Feb 03 08:10:09 2007 +0000 +++ b/auth.h Sat Feb 03 08:20:45 2007 +0000 @@ -52,7 +52,7 @@ void cli_auth_password(); int cli_auth_pubkey(); void cli_auth_interactive(); -char* getpass_or_cancel(); +char* getpass_or_cancel(char* prompt); #define MAX_USERNAME_LEN 25 /* arbitrary for the moment */ diff -r 2908122e9eed -r a5bca950120d channel.h --- a/channel.h Sat Feb 03 08:10:09 2007 +0000 +++ b/channel.h Sat Feb 03 08:20:45 2007 +0000 @@ -73,10 +73,9 @@ circbuffer *extrabuf; /* extended-data for the program - used like writebuf but for stderr */ - int sentclosed, recvclosed; - - /* this is set when we receive/send a channel eof packet */ - int recveof, senteof; + /* whether close/eof messages have been exchanged */ + int sent_close, recv_close; + int recv_eof, sent_eof; int initconn; /* used for TCP forwarding, whether the channel has been fully initialised */ @@ -94,7 +93,7 @@ int sepfds; /* Whether this channel has seperate pipes for in/out or not */ char *name; int (*inithandler)(struct Channel*); - int (*checkclose)(struct Channel*); + int (*check_close)(struct Channel*); void (*reqhandler)(struct Channel*); void (*closehandler)(struct Channel*); diff -r 2908122e9eed -r a5bca950120d cli-auth.c --- a/cli-auth.c Sat Feb 03 08:10:09 2007 +0000 +++ b/cli-auth.c Sat Feb 03 08:20:45 2007 +0000 @@ -281,11 +281,11 @@ /* A helper for getpass() that exits if the user cancels. The returned * password is statically allocated by getpass() */ -char* getpass_or_cancel() +char* getpass_or_cancel(char* prompt) { char* password = NULL; - password = getpass("Password: "); + password = getpass(prompt); /* 0x03 is a ctrl-c character in the buffer. */ if (password == NULL || strchr(password, '\3') != NULL) { diff -r 2908122e9eed -r a5bca950120d cli-authinteract.c --- a/cli-authinteract.c Sat Feb 03 08:10:09 2007 +0000 +++ b/cli-authinteract.c Sat Feb 03 08:20:45 2007 +0000 @@ -99,13 +99,14 @@ if (strlen(name) > 0) { cleantext(name); fprintf(stderr, "%s", name); - m_free(name); } + m_free(name); + if (strlen(instruction) > 0) { cleantext(instruction); fprintf(stderr, "%s", instruction); - m_free(instruction); } + m_free(instruction); for (i = 0; i < num_prompts; i++) { unsigned int response_len = 0; diff -r 2908122e9eed -r a5bca950120d cli-authpasswd.c --- a/cli-authpasswd.c Sat Feb 03 08:10:09 2007 +0000 +++ b/cli-authpasswd.c Sat Feb 03 08:20:45 2007 +0000 @@ -116,16 +116,19 @@ void cli_auth_password() { char* password = NULL; + char prompt[80]; TRACE(("enter cli_auth_password")) CHECKCLEARTOWRITE(); + snprintf(prompt, sizeof(prompt), "%s@%s's password: ", + cli_opts.username, cli_opts.remotehost); #ifdef ENABLE_CLI_ASKPASS_HELPER if (want_askpass()) - password = gui_getpass("Password: "); + password = gui_getpass(prompt); else #endif - password = getpass_or_cancel("Password: "); + password = getpass_or_cancel(prompt); buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST); diff -r 2908122e9eed -r a5bca950120d cli-authpubkey.c --- a/cli-authpubkey.c Sat Feb 03 08:10:09 2007 +0000 +++ b/cli-authpubkey.c Sat Feb 03 08:20:45 2007 +0000 @@ -112,6 +112,7 @@ /* Success */ break; } + buf_free(keybuf); if (keyitem != NULL) { TRACE(("matching key")) diff -r 2908122e9eed -r a5bca950120d cli-channel.c --- a/cli-channel.c Sat Feb 03 08:10:09 2007 +0000 +++ b/cli-channel.c Sat Feb 03 08:20:45 2007 +0000 @@ -39,9 +39,6 @@ TRACE(("enter recv_msg_channel_extended_data")) channel = getchannel(); - if (channel == NULL) { - dropbear_exit("Unknown channel"); - } if (channel->type != &clichansess) { TRACE(("leave recv_msg_channel_extended_data: chantype is wrong")) diff -r 2908122e9eed -r a5bca950120d cli-kex.c --- a/cli-kex.c Sat Feb 03 08:10:09 2007 +0000 +++ b/cli-kex.c Sat Feb 03 08:20:45 2007 +0000 @@ -122,6 +122,7 @@ fprintf(stderr, "\nHost '%s' is not in the trusted hosts file.\n(fingerprint %s)\nDo you want to continue connecting? (y/n)\n", cli_opts.remotehost, fp); + m_free(fp); tty = fopen(_PATH_TTY, "r"); if (tty) { @@ -132,7 +133,6 @@ } if (response == 'y') { - m_free(fp); return; } diff -r 2908122e9eed -r a5bca950120d cli-runopts.c --- a/cli-runopts.c Sat Feb 03 08:10:09 2007 +0000 +++ b/cli-runopts.c Sat Feb 03 08:20:45 2007 +0000 @@ -44,7 +44,7 @@ static void printhelp() { fprintf(stderr, "Dropbear client v%s\n" - "Usage: %s [options] [user@]host\n" + "Usage: %s [options] [user@]host [command]\n" "Options are:\n" "-p \n" "-l \n" diff -r 2908122e9eed -r a5bca950120d cli-service.c --- a/cli-service.c Sat Feb 03 08:10:09 2007 +0000 +++ b/cli-service.c Sat Feb 03 08:20:45 2007 +0000 @@ -82,6 +82,4 @@ } dropbear_exit("unrecognised service accept"); - /* m_free(servicename); not reached */ - } diff -r 2908122e9eed -r a5bca950120d common-channel.c --- a/common-channel.c Sat Feb 03 08:10:09 2007 +0000 +++ b/common-channel.c Sat Feb 03 08:20:45 2007 +0000 @@ -43,22 +43,22 @@ static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf); static void send_msg_channel_window_adjust(struct Channel *channel, unsigned int incr); -static void send_msg_channel_data(struct Channel *channel, int isextended, - unsigned int exttype); +static void send_msg_channel_data(struct Channel *channel, int isextended); static void send_msg_channel_eof(struct Channel *channel); static void send_msg_channel_close(struct Channel *channel); -static void removechannel(struct Channel *channel); -static void deletechannel(struct Channel *channel); -static void checkinitdone(struct Channel *channel); -static void checkclose(struct Channel *channel); - -static void closewritefd(struct Channel * channel); -static void closereadfd(struct Channel * channel, int fd); -static void closechanfd(struct Channel *channel, int fd, int how); +static void remove_channel(struct Channel *channel); +static void delete_channel(struct Channel *channel); +static void check_in_progress(struct Channel *channel); +static unsigned int write_pending(struct Channel * channel); +static void check_close(struct Channel *channel); +static void close_chan_fd(struct Channel *channel, int fd, int how); #define FD_UNINIT (-2) #define FD_CLOSED (-1) +#define ERRFD_IS_READ(channel) ((channel)->extrabuf == NULL) +#define ERRFD_IS_WRITE(channel) (!ERRFD_IS_READ(channel)) + /* Initialise all the channels */ void chaninitialise(const struct ChanType *chantypes[]) { @@ -85,7 +85,7 @@ for (i = 0; i < ses.chansize; i++) { if (ses.channels[i] != NULL) { TRACE(("channel %d closing", i)) - removechannel(ses.channels[i]); + remove_channel(ses.channels[i]); } } m_free(ses.channels); @@ -135,8 +135,8 @@ newchan = (struct Channel*)m_malloc(sizeof(struct Channel)); newchan->type = type; newchan->index = i; - newchan->sentclosed = newchan->recvclosed = 0; - newchan->senteof = newchan->recveof = 0; + newchan->sent_close = newchan->recv_close = 0; + newchan->sent_eof = newchan->recv_eof = 0; newchan->remotechan = remotechan; newchan->transwindow = transwindow; @@ -164,26 +164,58 @@ } /* Returns the channel structure corresponding to the channel in the current - * data packet (ses.payload must be positioned appropriately) */ -struct Channel* getchannel() { + * data packet (ses.payload must be positioned appropriately). + * A valid channel is always returns, it will fail fatally with an unknown + * channel */ +static struct Channel* getchannel_msg(const char* kind) { unsigned int chan; chan = buf_getint(ses.payload); if (chan >= ses.chansize || ses.channels[chan] == NULL) { - return NULL; + if (kind) { + dropbear_exit("%s for unknown channel %d", kind, chan); + } else { + dropbear_exit("Unknown channel %d", chan); + } } return ses.channels[chan]; } +struct Channel* getchannel() { + return getchannel_msg(NULL); +} + +/* In order to tell if a writefd is closed, we put it in the readfd FD_SET. + We then just try reading a single byte from it. It'll give EAGAIN or something + if the socket is still alive (but the FD probably shouldn't be set anyway?)*/ +static void check_closed_writefd(struct Channel* channel, int fd) { + char c; + int ret; + TRACE(("enter check_closed_writefd fd %d", fd)) + if (fd < 0) { + TRACE(("leave check_closed_writefd.")) + return; + } + + /* Read something. doing read(fd,x,0) seems to become a NOP on some platforms */ + ret = read(fd, &c, 1); + TRACE(("ret %d errno %d", ret, errno)) + if (ret > 0 || (ret < 0 && (errno == EINTR || errno == EAGAIN))) { + TRACE(("leave check_closed_writefd")) + return; + } + close_chan_fd(channel, fd, SHUT_WR); + TRACE(("leave check_closed_writefd after closing %d", fd)) +} + /* Iterate through the channels, performing IO if available */ void channelio(fd_set *readfds, fd_set *writefds) { struct Channel *channel; unsigned int i; - int ret; - /* iterate through all the possible channels */ + /* foreach channel */ for (i = 0; i < ses.chansize; i++) { channel = ses.channels[i]; @@ -194,54 +226,46 @@ /* read data and send it over the wire */ if (channel->readfd >= 0 && FD_ISSET(channel->readfd, readfds)) { - send_msg_channel_data(channel, 0, 0); + send_msg_channel_data(channel, 0); } /* read stderr data and send it over the wire */ - if (channel->extrabuf == NULL && + if (ERRFD_IS_READ(channel) && channel->errfd >= 0 && FD_ISSET(channel->errfd, readfds)) { - send_msg_channel_data(channel, 1, SSH_EXTENDED_DATA_STDERR); - } - - /* if we can read from the writefd, it might be closed, so we try to - * see if it has errors */ - if (IS_DROPBEAR_SERVER && channel->writefd >= 0 - && channel->writefd != channel->readfd - && FD_ISSET(channel->writefd, readfds)) { - if (channel->initconn) { - /* Handling for "in progress" connection - this is needed - * to avoid spinning 100% CPU when we connect to a server - * which doesn't send anything (tcpfwding) */ - checkinitdone(channel); - continue; /* Important not to use the channel after - checkinitdone(), as it may be NULL */ - } - ret = write(channel->writefd, NULL, 0); /* Fake write */ - if (ret < 0 && errno != EINTR && errno != EAGAIN) { - closewritefd(channel); - } + send_msg_channel_data(channel, 1); } /* write to program/pipe stdin */ if (channel->writefd >= 0 && FD_ISSET(channel->writefd, writefds)) { if (channel->initconn) { - checkinitdone(channel); + /* XXX should this go somewhere cleaner? */ + check_in_progress(channel); continue; /* Important not to use the channel after - checkinitdone(), as it may be NULL */ + check_in_progress(), as it may be NULL */ } writechannel(channel, channel->writefd, channel->writebuf); } /* stderr for client mode */ - if (channel->extrabuf != NULL + if (ERRFD_IS_WRITE(channel) && channel->errfd >= 0 && FD_ISSET(channel->errfd, writefds)) { writechannel(channel, channel->errfd, channel->extrabuf); } - /* now handle any of the channel-closing type stuff */ - checkclose(channel); + /* Check writefds for close, even if we don't have anything + to write into them. */ + if (channel->writefd >= 0) { + check_closed_writefd(channel, channel->writefd); + } + if (ERRFD_IS_WRITE(channel) && channel->errfd >= 0) { + check_closed_writefd(channel, channel->errfd); + } + + + /* handle any channel closing etc */ + check_close(channel); - } /* foreach channel */ + } /* Listeners such as TCP, X11, agent-auth */ #ifdef USING_LISTENERS @@ -250,57 +274,58 @@ } -/* do all the EOF/close type stuff checking for a channel */ -static void checkclose(struct Channel *channel) { +/* Returns true if there is data remaining to be written to stdin or + * stderr of a channel's endpoint. */ +static unsigned int write_pending(struct Channel * channel) { - TRACE(("checkclose: writefd %d, readfd %d, errfd %d, sentclosed %d, recvclosed %d", + if (channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0) { + return 1; + } else if (channel->errfd >= 0 && channel->extrabuf && + cbuf_getused(channel->extrabuf) > 0) { + return 1; + } + return 0; +} + + +/* EOF/close handling */ +static void check_close(struct Channel *channel) { + + TRACE(("check_close: writefd %d, readfd %d, errfd %d, sent_close %d, recv_close %d", channel->writefd, channel->readfd, - channel->errfd, channel->sentclosed, channel->recvclosed)) - TRACE(("writebuf size %d extrabuf ptr 0x%x extrabuf size %d", + channel->errfd, channel->sent_close, channel->recv_close)) + TRACE(("writebuf size %d extrabuf size %d", cbuf_getused(channel->writebuf), - channel->writebuf, - channel->writebuf ? 0 : cbuf_getused(channel->extrabuf))) + channel->extrabuf ? cbuf_getused(channel->extrabuf) : 0)) - /* server chansession channels are special, since readfd mightn't - * close in the case of "sleep 4 & echo blah" until the sleep is up */ - if (channel->type->checkclose) { - if (channel->type->checkclose(channel)) { - closewritefd(channel); - closereadfd(channel, channel->readfd); - closereadfd(channel, channel->errfd); + if (channel->recv_close && !write_pending(channel)) { + if (! channel->sent_close) { + TRACE(("Sending MSG_CHANNEL_CLOSE in response to same.")) + send_msg_channel_close(channel); } + remove_channel(channel); + return; } - if (!channel->senteof - && channel->readfd == FD_CLOSED - && (channel->extrabuf == NULL || channel->errfd == FD_CLOSED)) { + if (channel->recv_eof && !write_pending(channel)) { + close_chan_fd(channel, channel->writefd, SHUT_WR); + } + + /* If we're not going to send any more data, send EOF */ + if (!channel->sent_eof + && channel->readfd == FD_CLOSED + && (ERRFD_IS_WRITE(channel) || channel->errfd == FD_CLOSED)) { send_msg_channel_eof(channel); } - if (!channel->sentclosed - && channel->writefd == FD_CLOSED - && channel->readfd == FD_CLOSED - && (channel->extrabuf == NULL || channel->errfd == FD_CLOSED)) { + /* And if we can't receive any more data from them either, close up */ + if (!channel->sent_close + && channel->writefd == FD_CLOSED + && channel->readfd == FD_CLOSED + && channel->errfd == FD_CLOSED) { send_msg_channel_close(channel); } - /* When either party wishes to terminate the channel, it sends - * SSH_MSG_CHANNEL_CLOSE. Upon receiving this message, a party MUST - * send back a SSH_MSG_CHANNEL_CLOSE unless it has already sent this - * message for the channel. The channel is considered closed for a - * party when it has both sent and received SSH_MSG_CHANNEL_CLOSE, and - * the party may then reuse the channel number. A party MAY send - * SSH_MSG_CHANNEL_CLOSE without having sent or received - * SSH_MSG_CHANNEL_EOF. - * (from draft-ietf-secsh-connect) - */ - if (channel->recvclosed) { - if (! channel->sentclosed) { - TRACE(("Sending MSG_CHANNEL_CLOSE in response to same.")) - send_msg_channel_close(channel); - } - removechannel(channel); - } } @@ -308,36 +333,34 @@ * if so, set up the channel properly. Otherwise, the channel is cleaned up, so * it is important that the channel reference isn't used after a call to this * function */ -static void checkinitdone(struct Channel *channel) { +static void check_in_progress(struct Channel *channel) { int val; socklen_t vallen = sizeof(val); - TRACE(("enter checkinitdone")) + TRACE(("enter check_in_progress")) if (getsockopt(channel->writefd, SOL_SOCKET, SO_ERROR, &val, &vallen) || val != 0) { send_msg_channel_open_failure(channel->remotechan, SSH_OPEN_CONNECT_FAILED, "", ""); close(channel->writefd); - deletechannel(channel); - TRACE(("leave checkinitdone: fail")) + delete_channel(channel); + TRACE(("leave check_in_progress: fail")) } else { send_msg_channel_open_confirmation(channel, channel->recvwindow, channel->recvmaxpacket); channel->readfd = channel->writefd; channel->initconn = 0; - TRACE(("leave checkinitdone: success")) + TRACE(("leave check_in_progress: success")) } } - /* Send the close message and set the channel as closed */ static void send_msg_channel_close(struct Channel *channel) { TRACE(("enter send_msg_channel_close")) - /* XXX server */ if (channel->type->closehandler) { channel->type->closehandler(channel); } @@ -349,8 +372,8 @@ encrypt_packet(); - channel->senteof = 1; - channel->sentclosed = 1; + channel->sent_eof = 1; + channel->sent_close = 1; TRACE(("leave send_msg_channel_close")) } @@ -365,7 +388,7 @@ encrypt_packet(); - channel->senteof = 1; + channel->sent_eof = 1; TRACE(("leave send_msg_channel_eof")) } @@ -377,32 +400,25 @@ int len, maxlen; - TRACE(("enter writechannel")) + TRACE(("enter writechannel fd %d", fd)) maxlen = cbuf_readlen(cbuf); /* Write the data out */ len = write(fd, cbuf_readptr(cbuf, maxlen), maxlen); if (len <= 0) { + TRACE(("errno %d len %d", errno, len)) if (len < 0 && errno != EINTR) { - /* no more to write - we close it even if the fd was stderr, since - * that's a nasty failure too */ - closewritefd(channel); + close_chan_fd(channel, fd, SHUT_WR); } TRACE(("leave writechannel: len <= 0")) return; } + TRACE(("writechannel wrote %d", len)) cbuf_incrread(cbuf, len); channel->recvdonelen += len; - if (fd == channel->writefd && cbuf_getused(cbuf) == 0 && channel->recveof) { - /* Check if we're closing up */ - closewritefd(channel); - TRACE(("leave writechannel: recveof set")) - return; - } - /* Window adjust handling */ if (channel->recvdonelen >= RECV_WINDOWEXTEND) { /* Set it back to max window */ @@ -416,7 +432,6 @@ dropbear_assert(channel->extrabuf == NULL || channel->recvwindow <= cbuf_getavail(channel->extrabuf)); - TRACE(("leave writechannel")) } @@ -441,35 +456,32 @@ FD_SET(channel->readfd, readfds); } - if (channel->extrabuf == NULL && channel->errfd >= 0) { + if (ERRFD_IS_READ(channel) && channel->errfd >= 0) { FD_SET(channel->errfd, readfds); } } - TRACE(("writefd = %d, readfd %d, errfd %d, bufused %d", - channel->writefd, channel->readfd, - channel->errfd, - cbuf_getused(channel->writebuf) )) - - /* For checking FD status (ie closure etc) - we don't actually - * read data from writefd. We don't want to do this for the client, - * since redirection to /dev/null will make it spin in the select */ - if (IS_DROPBEAR_SERVER && channel->writefd >= 0 - && channel->writefd != channel->readfd) { - FD_SET(channel->writefd, readfds); - } - /* Stuff from the wire */ if ((channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0 ) || channel->initconn) { FD_SET(channel->writefd, writefds); } - if (channel->extrabuf != NULL && channel->errfd >= 0 + if (ERRFD_IS_WRITE(channel) != NULL && channel->errfd >= 0 && cbuf_getused(channel->extrabuf) > 0 ) { FD_SET(channel->errfd, writefds); } + /* We also set the writefds for reading, so that we will be notified of close */ + if (channel->writefd >= 0) { + FD_SET(channel->writefd, readfds); + } + if (ERRFD_IS_WRITE(channel) && channel->errfd >= 0) { + FD_SET(channel->errfd, readfds); + } + + + } /* foreach channel */ #ifdef USING_LISTENERS @@ -487,18 +499,11 @@ TRACE(("enter recv_msg_channel_eof")) - channel = getchannel(); - if (channel == NULL) { - dropbear_exit("EOF for unknown channel"); - } + channel = getchannel_msg("EOF"); - channel->recveof = 1; - if (cbuf_getused(channel->writebuf) == 0 - && (channel->extrabuf == NULL - || cbuf_getused(channel->extrabuf) == 0)) { - closewritefd(channel); - } + channel->recv_eof = 1; + check_close(channel); TRACE(("leave recv_msg_channel_eof")) } @@ -510,27 +515,20 @@ TRACE(("enter recv_msg_channel_close")) - channel = getchannel(); - if (channel == NULL) { - /* disconnect ? */ - dropbear_exit("Close for unknown channel"); - } + channel = getchannel_msg("Close"); - channel->recveof = 1; - channel->recvclosed = 1; + channel->recv_eof = 1; + channel->recv_close = 1; - if (channel->sentclosed) { - removechannel(channel); - } - + check_close(channel); TRACE(("leave recv_msg_channel_close")) } /* Remove a channel entry, this is only executed after both sides have sent * channel close */ -static void removechannel(struct Channel * channel) { +static void remove_channel(struct Channel * channel) { - TRACE(("enter removechannel")) + TRACE(("enter remove_channel")) TRACE(("channel index is %d", channel->index)) cbuf_free(channel->writebuf); @@ -543,20 +541,23 @@ /* close the FDs in case they haven't been done - * yet (ie they were shutdown etc */ + * yet (they might have been shutdown etc) */ + TRACE(("CLOSE writefd %d", channel->writefd)) close(channel->writefd); + TRACE(("CLOSE readfd %d", channel->readfd)) close(channel->readfd); + TRACE(("CLOSE errfd %d", channel->errfd)) close(channel->errfd); channel->typedata = NULL; - deletechannel(channel); + delete_channel(channel); - TRACE(("leave removechannel")) + TRACE(("leave remove_channel")) } /* Remove a channel entry */ -static void deletechannel(struct Channel *channel) { +static void delete_channel(struct Channel *channel) { ses.channels[channel->index] = NULL; m_free(channel); @@ -574,10 +575,6 @@ TRACE(("enter recv_msg_channel_request")) channel = getchannel(); - if (channel == NULL) { - /* disconnect ? */ - dropbear_exit("Unknown channel"); - } if (channel->type->reqhandler) { channel->type->reqhandler(channel); @@ -594,26 +591,22 @@ * chan is the remote channel, isextended is 0 if it is normal data, 1 * if it is extended data. if it is extended, then the type is in * exttype */ -static void send_msg_channel_data(struct Channel *channel, int isextended, - unsigned int exttype) { +static void send_msg_channel_data(struct Channel *channel, int isextended) { - buffer *buf; int len; - unsigned int maxlen; + size_t maxlen, size_pos; int fd; -/* TRACE(("enter send_msg_channel_data")) - TRACE(("extended = %d type = %d", isextended, exttype))*/ - CHECKCLEARTOWRITE(); - dropbear_assert(!channel->sentclosed); + dropbear_assert(!channel->sent_close); if (isextended) { fd = channel->errfd; } else { fd = channel->readfd; } + TRACE(("enter send_msg_channel_data isextended %d fd %d", isextended, fd)) dropbear_assert(fd >= 0); maxlen = MIN(channel->transwindow, channel->transmaxpacket); @@ -621,40 +614,37 @@ * exttype if is extended */ maxlen = MIN(maxlen, ses.writepayload->size - 1 - 4 - 4 - (isextended ? 4 : 0)); + TRACE(("maxlen %d", maxlen)) if (maxlen == 0) { TRACE(("leave send_msg_channel_data: no window")) - return; /* the data will get written later */ - } - - /* read the data */ - TRACE(("maxlen %d", maxlen)) - buf = buf_new(maxlen); - TRACE(("buf pos %d data %x", buf->pos, buf->data)) - len = read(fd, buf_getwriteptr(buf, maxlen), maxlen); - if (len <= 0) { - /* on error/eof, send eof */ - if (len == 0 || errno != EINTR) { - closereadfd(channel, fd); - } - buf_free(buf); - buf = NULL; - TRACE(("leave send_msg_channel_data: read err or EOF for fd %d", - channel->index)); return; } - buf_incrlen(buf, len); buf_putbyte(ses.writepayload, isextended ? SSH_MSG_CHANNEL_EXTENDED_DATA : SSH_MSG_CHANNEL_DATA); buf_putint(ses.writepayload, channel->remotechan); - if (isextended) { - buf_putint(ses.writepayload, exttype); + buf_putint(ses.writepayload, SSH_EXTENDED_DATA_STDERR); } + /* a dummy size first ...*/ + size_pos = ses.writepayload->pos; + buf_putint(ses.writepayload, 0); - buf_putstring(ses.writepayload, buf_getptr(buf, len), len); - buf_free(buf); - buf = NULL; + /* read the data */ + len = read(fd, buf_getwriteptr(ses.writepayload, maxlen), maxlen); + if (len <= 0) { + if (len == 0 || errno != EINTR) { + close_chan_fd(channel, fd, SHUT_RD); + } + ses.writepayload->len = ses.writepayload->pos = 0; + TRACE(("leave send_msg_channel_data: len %d read err or EOF for fd %d", + len, channel->index)); + return; + } + buf_incrwritepos(ses.writepayload, len); + /* ... real size here */ + buf_setpos(ses.writepayload, size_pos); + buf_putint(ses.writepayload, len); channel->transwindow -= len; @@ -668,9 +658,6 @@ struct Channel *channel; channel = getchannel(); - if (channel == NULL) { - dropbear_exit("Unknown channel"); - } common_recv_msg_channel_data(channel, channel->writefd, channel->writebuf); } @@ -687,16 +674,19 @@ TRACE(("enter recv_msg_channel_data")) - if (channel->recveof) { + if (channel->recv_eof) { dropbear_exit("received data after eof"); } if (fd < 0) { - dropbear_exit("received data with bad writefd"); + /* If we have encountered failed write, the far side might still + * be sending data without having yet received our close notification. + * We just drop the data. */ + return; } datalen = buf_getint(ses.payload); - + TRACE(("length %d", datalen)) maxdata = cbuf_getavail(cbuf); @@ -738,9 +728,6 @@ unsigned int incr; channel = getchannel(); - if (channel == NULL) { - dropbear_exit("Unknown channel"); - } incr = buf_getint(ses.payload); TRACE(("received window increment %d", incr)) @@ -767,7 +754,6 @@ } /* Handle a new channel request, performing any channel-type-specific setup */ -/* XXX server */ void recv_msg_channel_open() { unsigned char *type; @@ -824,13 +810,13 @@ if (channel->type->inithandler) { ret = channel->type->inithandler(channel); + if (ret == SSH_OPEN_IN_PROGRESS) { + /* We'll send the confirmation later */ + goto cleanup; + } if (ret > 0) { - if (ret == SSH_OPEN_IN_PROGRESS) { - /* We'll send the confirmation later */ - goto cleanup; - } errtype = ret; - deletechannel(channel); + delete_channel(channel); TRACE(("inithandler returned failure %d", ret)) goto failure; } @@ -914,6 +900,49 @@ TRACE(("leave send_msg_channel_open_confirmation")) } +/* close a fd, how is SHUT_RD or SHUT_WR */ +static void close_chan_fd(struct Channel *channel, int fd, int how) { + + int closein = 0, closeout = 0; + + if (channel->type->sepfds) { + TRACE(("SHUTDOWN(%d, %d)", fd, how)) + shutdown(fd, how); + if (how == 0) { + closeout = 1; + } else { + closein = 1; + } + } else { + TRACE(("CLOSE some fd %d", fd)) + close(fd); + closein = closeout = 1; + } + + if (closeout && (fd == channel->readfd)) { + channel->readfd = FD_CLOSED; + } + if (closeout && ERRFD_IS_READ(channel) && (fd == channel->errfd)) { + channel->errfd = FD_CLOSED; + } + + if (closein && fd == channel->writefd) { + channel->writefd = FD_CLOSED; + } + if (closein && ERRFD_IS_WRITE(channel) && (fd == channel->errfd)) { + channel->errfd = FD_CLOSED; + } + + /* if we called shutdown on it and all references are gone, then we + * need to close() it to stop it lingering */ + if (channel->type->sepfds && channel->readfd == FD_CLOSED + && channel->writefd == FD_CLOSED && channel->errfd == FD_CLOSED) { + TRACE(("CLOSE (finally) of %d", fd)) + close(fd); + } +} + + #if defined(USING_LISTENERS) || defined(DROPBEAR_CLIENT) /* Create a new channel, and start the open request. This is intended * for X11, agent, tcp forwarding, and should be filled with channel-specific @@ -962,9 +991,6 @@ TRACE(("enter recv_msg_channel_open_confirmation")) channel = getchannel(); - if (channel == NULL) { - dropbear_exit("Unknown channel"); - } if (!channel->await_open) { dropbear_exit("unexpected channel reply"); @@ -982,7 +1008,7 @@ if (channel->type->inithandler) { ret = channel->type->inithandler(channel); if (ret > 0) { - removechannel(channel); + remove_channel(channel); TRACE(("inithandler returned failure %d", ret)) } } @@ -997,74 +1023,12 @@ struct Channel * channel; channel = getchannel(); - if (channel == NULL) { - dropbear_exit("Unknown channel"); - } if (!channel->await_open) { dropbear_exit("unexpected channel reply"); } channel->await_open = 0; - removechannel(channel); + remove_channel(channel); } #endif /* USING_LISTENERS */ - -/* close a stdout/stderr fd */ -static void closereadfd(struct Channel * channel, int fd) { - - /* don't close it if it is the same as writefd, - * unless writefd is already set -1 */ - TRACE(("enter closereadfd")) - closechanfd(channel, fd, 0); - TRACE(("leave closereadfd")) -} - -/* close a stdin fd */ -static void closewritefd(struct Channel * channel) { - - TRACE(("enter closewritefd")) - closechanfd(channel, channel->writefd, 1); - TRACE(("leave closewritefd")) -} - -/* close a fd, how is 0 for stdout/stderr, 1 for stdin */ -static void closechanfd(struct Channel *channel, int fd, int how) { - - int closein = 0, closeout = 0; - - /* XXX server */ - if (channel->type->sepfds) { - TRACE(("shutdown((%d), %d)", fd, how)) - shutdown(fd, how); - if (how == 0) { - closeout = 1; - } else { - closein = 1; - } - } else { - close(fd); - closein = closeout = 1; - } - - if (closeout && fd == channel->readfd) { - channel->readfd = FD_CLOSED; - } - if (closeout && (channel->extrabuf == NULL) && (fd == channel->errfd)) { - channel->errfd = FD_CLOSED; - } - - if (closein && fd == channel->writefd) { - channel->writefd = FD_CLOSED; - } - if (closein && (channel->extrabuf != NULL) && (fd == channel->errfd)) { - channel->errfd = FD_CLOSED; - } - - /* if we called shutdown on it and all references are gone, then we - * need to close() it to stop it lingering */ - if (channel->type->sepfds && channel->readfd == FD_CLOSED - && channel->writefd == FD_CLOSED && channel->errfd == FD_CLOSED) { - close(fd); - } -} diff -r 2908122e9eed -r a5bca950120d common-kex.c --- a/common-kex.c Sat Feb 03 08:10:09 2007 +0000 +++ b/common-kex.c Sat Feb 03 08:20:45 2007 +0000 @@ -262,6 +262,7 @@ hash_state hs; unsigned int C2S_keysize, S2C_keysize; char mactransletter, macrecvletter; /* Client or server specific */ + int recv_cipher = 0, trans_cipher = 0; TRACE(("enter gen_new_keys")) /* the dh_K and hash are the start of all hashes, we make use of that */ @@ -298,17 +299,20 @@ hashkeys(C2S_key, C2S_keysize, &hs, 'C'); hashkeys(S2C_key, S2C_keysize, &hs, 'D'); - if (cbc_start( - find_cipher(ses.newkeys->recv_algo_crypt->cipherdesc->name), - recv_IV, recv_key, + recv_cipher = find_cipher(ses.newkeys->recv_algo_crypt->cipherdesc->name); + if (recv_cipher < 0) + dropbear_exit("crypto error"); + + if (cbc_start(recv_cipher, recv_IV, recv_key, ses.newkeys->recv_algo_crypt->keysize, 0, &ses.newkeys->recv_symmetric_struct) != CRYPT_OK) { dropbear_exit("crypto error"); } - - if (cbc_start( - find_cipher(ses.newkeys->trans_algo_crypt->cipherdesc->name), - trans_IV, trans_key, + trans_cipher = find_cipher(ses.newkeys->trans_algo_crypt->cipherdesc->name); + if (trans_cipher < 0) + dropbear_exit("crypto error"); + + if (cbc_start(trans_cipher, trans_IV, trans_key, ses.newkeys->trans_algo_crypt->keysize, 0, &ses.newkeys->trans_symmetric_struct) != CRYPT_OK) { dropbear_exit("crypto error"); @@ -517,7 +521,7 @@ hash_state hs; /* read the prime and generator*/ - mp_init(&dh_p); + m_mp_init(&dh_p); bytes_to_mp(&dh_p, dh_p_val, DH_P_LEN); /* Check that dh_pub_them (dh_e or dh_f) is in the range [1, p-1] */ diff -r 2908122e9eed -r a5bca950120d common-session.c --- a/common-session.c Sat Feb 03 08:10:09 2007 +0000 +++ b/common-session.c Sat Feb 03 08:20:45 2007 +0000 @@ -143,27 +143,21 @@ dropbear_exit("Terminated by signal"); } - if (val < 0) { - if (errno == EINTR) { - /* This must happen even if we've been interrupted, so that - * changed signal-handler vars can take effect etc */ - if (loophandler) { - loophandler(); - } - continue; - } else { - dropbear_exit("Error in select"); - } + if (val < 0 && errno != EINTR) { + dropbear_exit("Error in select"); + } + + if (val <= 0) { + /* If we were interrupted or the select timed out, we still + * want to iterate over channels etc for reading, to handle + * server processes exiting etc. + * We don't want to read/write FDs. */ + FD_ZERO(&writefd); + FD_ZERO(&readfd); } /* check for auth timeout, rekeying required etc */ checktimeouts(); - - if (val == 0) { - /* timeout */ - TRACE(("select timeout")) - continue; - } /* process session socket's incoming/outgoing data */ if (ses.sock != -1) { @@ -229,7 +223,7 @@ /* write our version string, this blocks */ if (atomicio(write, ses.sock, LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n")) == DROPBEAR_FAILURE) { - dropbear_exit("Error writing ident string"); + ses.remoteclosed(); } /* If they send more than 50 lines, something is wrong */ @@ -250,7 +244,7 @@ if (!done) { TRACE(("err: %s for '%s'\n", strerror(errno), linebuf)) - dropbear_exit("Failed to get remote version"); + ses.remoteclosed(); } else { /* linebuf is already null terminated */ ses.remoteident = m_malloc(len); diff -r 2908122e9eed -r a5bca950120d configure.in --- a/configure.in Sat Feb 03 08:10:09 2007 +0000 +++ b/configure.in Sat Feb 03 08:20:45 2007 +0000 @@ -342,7 +342,7 @@ #endif ]) -AC_CHECK_MEMBERS([struct utmpx.ut_host, struct utmpx.ut_syslen, struct utmpx.ut_type, struct utmpx.ut_id, struct utmpx.ut_addr, struct utmpx.ut_addr_v6, struct utmpx.ut_time, struct utmpx.ut_tv, struct sockaddr_storage.ss_family, struct sockadd_storage.__family],,,[ +AC_CHECK_MEMBERS([struct utmpx.ut_host, struct utmpx.ut_syslen, struct utmpx.ut_type, struct utmpx.ut_id, struct utmpx.ut_addr, struct utmpx.ut_addr_v6, struct utmpx.ut_time, struct utmpx.ut_tv],,,[ #include #include #if HAVE_UTMPX_H @@ -350,6 +350,11 @@ #endif ]) +AC_CHECK_MEMBERS([struct sockaddr_storage.ss_family],,,[ +#include +#include +]) + AC_CHECK_FUNCS(endutent getutent getutid getutline pututline setutent) AC_CHECK_FUNCS(utmpname) AC_CHECK_FUNCS(endutxent getutxent getutxid getutxline pututxline ) @@ -612,6 +617,49 @@ fi AC_EXEEXT + +# XXX there must be a nicer way to do this +AS_MKDIR_P(libtomcrypt/src/ciphers/aes) +AS_MKDIR_P(libtomcrypt/src/ciphers/safer) +AS_MKDIR_P(libtomcrypt/src/ciphers/twofish) +AS_MKDIR_P(libtomcrypt/src/encauth/ccm) +AS_MKDIR_P(libtomcrypt/src/encauth/eax) +AS_MKDIR_P(libtomcrypt/src/encauth/gcm) +AS_MKDIR_P(libtomcrypt/src/encauth/ocb) +AS_MKDIR_P(libtomcrypt/src/hashes) +AS_MKDIR_P(libtomcrypt/src/hashes/chc) +AS_MKDIR_P(libtomcrypt/src/hashes/helper) +AS_MKDIR_P(libtomcrypt/src/hashes/sha2) +AS_MKDIR_P(libtomcrypt/src/hashes/whirl) +AS_MKDIR_P(libtomcrypt/src/mac/hmac) +AS_MKDIR_P(libtomcrypt/src/mac/omac) +AS_MKDIR_P(libtomcrypt/src/mac/pelican) +AS_MKDIR_P(libtomcrypt/src/mac/pmac) +AS_MKDIR_P(libtomcrypt/src/misc/base64) +AS_MKDIR_P(libtomcrypt/src/misc/crypt) +AS_MKDIR_P(libtomcrypt/src/misc/mpi) +AS_MKDIR_P(libtomcrypt/src/misc/pkcs5) +AS_MKDIR_P(libtomcrypt/src/modes/cbc) +AS_MKDIR_P(libtomcrypt/src/modes/cfb) +AS_MKDIR_P(libtomcrypt/src/modes/ctr) +AS_MKDIR_P(libtomcrypt/src/modes/ecb) +AS_MKDIR_P(libtomcrypt/src/modes/ofb) +AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/bit) +AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/choice) +AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/ia5) +AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/integer) +AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/object_identifier) +AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/octet) +AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/printable_string) +AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/sequence) +AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/short_integer) +AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/utctime) +AS_MKDIR_P(libtomcrypt/src/pk/dh) +AS_MKDIR_P(libtomcrypt/src/pk/dsa) +AS_MKDIR_P(libtomcrypt/src/pk/ecc) +AS_MKDIR_P(libtomcrypt/src/pk/pkcs1) +AS_MKDIR_P(libtomcrypt/src/pk/rsa) +AS_MKDIR_P(libtomcrypt/src/prng) AC_CONFIG_HEADER(config.h) AC_OUTPUT(Makefile) AC_OUTPUT(libtomcrypt/Makefile) diff -r 2908122e9eed -r a5bca950120d dbutil.c --- a/dbutil.c Sat Feb 03 08:10:09 2007 +0000 +++ b/dbutil.c Sat Feb 03 08:20:45 2007 +0000 @@ -400,7 +400,10 @@ len = sizeof(struct sockaddr_storage); /* Some platforms such as Solaris 8 require that len is the length - * of the specific structure. */ + * of the specific structure. Some older linux systems (glibc 2.1.3 + * such as debian potato) have sockaddr_storage.__ss_family instead + * but we'll ignore them */ +#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY if (addr->ss_family == AF_INET) { len = sizeof(struct sockaddr_in); } @@ -409,6 +412,7 @@ len = sizeof(struct sockaddr_in6); } #endif +#endif ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICSERV | NI_NUMERICHOST); @@ -448,6 +452,7 @@ len = sizeof(struct sockaddr_storage); /* Some platforms such as Solaris 8 require that len is the length * of the specific structure. */ +#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY if (addr->ss_family == AF_INET) { len = sizeof(struct sockaddr_in); } @@ -456,6 +461,7 @@ len = sizeof(struct sockaddr_in6); } #endif +#endif ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf), @@ -521,26 +527,36 @@ * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ int buf_readfile(buffer* buf, const char* filename) { - int fd; + int fd = -1; int len; int maxlen; + int ret = DROPBEAR_FAILURE; fd = open(filename, O_RDONLY); if (fd < 0) { - close(fd); - return DROPBEAR_FAILURE; + goto out; } do { maxlen = buf->size - buf->pos; - len = read(fd, buf_getwriteptr(buf, maxlen), - maxlen); + len = read(fd, buf_getwriteptr(buf, maxlen), maxlen); + if (len < 0) { + if (errno == EINTR || errno == EAGAIN) { + continue; + } + goto out; + } buf_incrwritepos(buf, len); } while (len < maxlen && len > 0); - close(fd); - return DROPBEAR_SUCCESS; + ret = DROPBEAR_SUCCESS; + +out: + if (fd >= 0) { + m_close(fd); + } + return ret; } /* get a line from the file into buffer in the style expected for an diff -r 2908122e9eed -r a5bca950120d debian/changelog --- a/debian/changelog Sat Feb 03 08:10:09 2007 +0000 +++ b/debian/changelog Sat Feb 03 08:20:45 2007 +0000 @@ -1,3 +1,9 @@ +dropbear (0.49-0.1) unstable; urgency=low + + * New upstream release. + + -- Matt Johnston Tues, 13 June 2005 19:20:21 +0800 + dropbear (0.48.1-1) unstable; urgency=medium * new upstream point release. diff -r 2908122e9eed -r a5bca950120d debug.h --- a/debug.h Sat Feb 03 08:10:09 2007 +0000 +++ b/debug.h Sat Feb 03 08:20:45 2007 +0000 @@ -39,13 +39,15 @@ * Caution: Don't use this in an unfriendly environment (ie unfirewalled), * since the printing may not sanitise strings etc. This will add a reasonable * amount to your executable size. */ -/*#define DEBUG_TRACE */ +#define DEBUG_TRACE /* All functions writing to the cleartext payload buffer call * CHECKCLEARTOWRITE() before writing. This is only really useful if you're * attempting to track down a problem */ -#define CHECKCLEARTOWRITE() assert(ses.writepayload->len == 0 && \ - ses.writepayload->pos == 0) +/*#define CHECKCLEARTOWRITE() assert(ses.writepayload->len == 0 && \ + ses.writepayload->pos == 0)*/ + +#define CHECKCLEARTOWRITE() /* Define this, compile with -pg and set GMON_OUT_PREFIX=gmon to get gmon * output when Dropbear forks. This will allow it gprof to be used. diff -r 2908122e9eed -r a5bca950120d dropbearkey.c --- a/dropbearkey.c Sat Feb 03 08:10:09 2007 +0000 +++ b/dropbearkey.c Sat Feb 03 08:20:45 2007 +0000 @@ -283,8 +283,10 @@ buf_burn(buf); buf_free(buf); buf = NULL; - sign_key_free(key); - key = NULL; + if (key) { + sign_key_free(key); + key = NULL; + } exit(err); } diff -r 2908122e9eed -r a5bca950120d dss.c --- a/dss.c Sat Feb 03 08:10:09 2007 +0000 +++ b/dss.c Sat Feb 03 08:20:45 2007 +0000 @@ -338,7 +338,9 @@ /* generate k */ m_mp_init(&dss_protok); bytes_to_mp(&dss_protok, proto_k, SHA512_HASH_SIZE); - mp_mod(&dss_protok, key->q, &dss_k); + if (mp_mod(&dss_protok, key->q, &dss_k) != MP_OKAY) { + dropbear_exit("dss error"); + } mp_clear(&dss_protok); m_burn(proto_k, SHA512_HASH_SIZE); #else /* DSS_PROTOK not defined*/ diff -r 2908122e9eed -r a5bca950120d includes.h --- a/includes.h Sat Feb 03 08:10:09 2007 +0000 +++ b/includes.h Sat Feb 03 08:20:45 2007 +0000 @@ -135,13 +135,6 @@ #define LOG_AUTHPRIV LOG_AUTH #endif -/* glibc 2.1.3 systems have sockaddr_storage.__ss_family rather than - * sockaddr_storage.ss_family */ -#if !defined(HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY) \ - && defined(HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY) -#define ss_family __ss_family -#endif - /* so we can avoid warnings about unused params (ie in signal handlers etc) */ #ifdef UNUSED #elif defined(__GNUC__) diff -r 2908122e9eed -r a5bca950120d keyimport.c --- a/keyimport.c Sat Feb 03 08:10:09 2007 +0000 +++ b/keyimport.c Sat Feb 03 08:20:45 2007 +0000 @@ -361,7 +361,7 @@ static struct openssh_key *load_openssh_key(const char *filename) { struct openssh_key *ret; - FILE *fp; + FILE *fp = NULL; char buffer[256]; char *errmsg = NULL, *p = NULL; int headers_done; @@ -482,6 +482,9 @@ memset(&ret, 0, sizeof(ret)); m_free(ret); } + if (fp) { + fclose(fp); + } if (errmsg) { fprintf(stderr, "Error: %s\n", errmsg); } @@ -926,40 +929,6 @@ if (passphrase) { fprintf(stderr, "Encrypted keys aren't supported currently\n"); goto error; -#if 0 - /* - * Invent an iv. Then derive encryption key from passphrase - * and iv/salt: - * - * - let block A equal MD5(passphrase || iv) - * - let block B equal MD5(A || passphrase || iv) - * - block C would be MD5(B || passphrase || iv) and so on - * - encryption key is the first N bytes of A || B - */ - struct MD5Context md5c; - unsigned char keybuf[32]; - - for (i = 0; i < 8; i++) iv[i] = random_byte(); - - MD5Init(&md5c); - MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); - MD5Update(&md5c, iv, 8); - MD5Final(keybuf, &md5c); - - MD5Init(&md5c); - MD5Update(&md5c, keybuf, 16); - MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); - MD5Update(&md5c, iv, 8); - MD5Final(keybuf+16, &md5c); - - /* - * Now encrypt the key blob. - */ - des3_encrypt_pubkey_ossh(keybuf, iv, outblob, outlen); - - memset(&md5c, 0, sizeof(md5c)); - memset(keybuf, 0, sizeof(keybuf)); -#endif } /* @@ -976,12 +945,6 @@ goto error; } fputs(header, fp); - if (passphrase) { - fprintf(fp, "Proc-Type: 4,ENCRYPTED\nDEK-Info: DES-EDE3-CBC,"); - for (i = 0; i < 8; i++) - fprintf(fp, "%02X", iv[i]); - fprintf(fp, "\n\n"); - } base64_encode_fp(fp, outblob, outlen, 64); fputs(footer, fp); fclose(fp); diff -r 2908122e9eed -r a5bca950120d libtomcrypt/Makefile.in --- a/libtomcrypt/Makefile.in Sat Feb 03 08:10:09 2007 +0000 +++ b/libtomcrypt/Makefile.in Sat Feb 03 08:20:45 2007 +0000 @@ -158,7 +158,7 @@ #ciphers come in two flavours... enc+dec and enc src/ciphers/aes/aes_enc.o: src/ciphers/aes/aes.c src/ciphers/aes/aes_tab.c - $(CC) $(CFLAGS) -DENCRYPT_ONLY -c src/ciphers/aes/aes.c -o src/ciphers/aes/aes_enc.o + $(CC) $(CFLAGS) -DENCRYPT_ONLY -c $< -o src/ciphers/aes/aes_enc.o #These are the rules to make certain object files. src/ciphers/aes/aes.o: src/ciphers/aes/aes.c src/ciphers/aes/aes_tab.c diff -r 2908122e9eed -r a5bca950120d libtommath/bn_mp_div.c --- a/libtommath/bn_mp_div.c Sat Feb 03 08:10:09 2007 +0000 +++ b/libtommath/bn_mp_div.c Sat Feb 03 08:20:45 2007 +0000 @@ -269,7 +269,9 @@ } if (d != NULL) { - mp_div_2d (&x, norm, &x, NULL); + if ((res = mp_div_2d (&x, norm, &x, NULL)) != MP_OKAY) { + goto LBL_Y; + } mp_exch (&x, d); } diff -r 2908122e9eed -r a5bca950120d options.h --- a/options.h Sat Feb 03 08:10:09 2007 +0000 +++ b/options.h Sat Feb 03 08:20:45 2007 +0000 @@ -128,7 +128,7 @@ * You can't enable both PASSWORD and PAM. */ #define ENABLE_SVR_PASSWORD_AUTH -/* #define ENABLE_SVR_PAM_AUTH */ /* requires ./configure --enable-pam */ +/*#define ENABLE_SVR_PAM_AUTH */ #define ENABLE_SVR_PUBKEY_AUTH #define ENABLE_CLI_PASSWORD_AUTH @@ -199,15 +199,17 @@ * not using the Dropbear client, you'll need to change it */ #define _PATH_SSH_PROGRAM "/usr/bin/dbclient" -/* Multi-purpose binary configuration has now moved. Look at the top - * of the Makefile for instructions, or INSTALL */ +/* Whether to log commands executed by a client. This only logs the + * (single) command sent to the server, not what a user did in a + * shell/sftp session etc. */ +/* #define LOG_COMMANDS */ /******************************************************************* * You shouldn't edit below here unless you know you need to. *******************************************************************/ #ifndef DROPBEAR_VERSION -#define DROPBEAR_VERSION "0.48" +#define DROPBEAR_VERSION "0.49" #endif #define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION diff -r 2908122e9eed -r a5bca950120d rsa.c --- a/rsa.c Sat Feb 03 08:10:09 2007 +0000 +++ b/rsa.c Sat Feb 03 08:20:45 2007 +0000 @@ -285,18 +285,29 @@ /* rsa_tmp1 is em */ /* em' = em * r^e mod n */ - mp_exptmod(&rsa_tmp2, key->e, key->n, &rsa_s); /* rsa_s used as a temp var*/ - mp_invmod(&rsa_tmp2, key->n, &rsa_tmp3); - mp_mulmod(&rsa_tmp1, &rsa_s, key->n, &rsa_tmp2); + /* rsa_s used as a temp var*/ + if (mp_exptmod(&rsa_tmp2, key->e, key->n, &rsa_s) != MP_OKAY) { + dropbear_exit("rsa error"); + } + if (mp_invmod(&rsa_tmp2, key->n, &rsa_tmp3) != MP_OKAY) { + dropbear_exit("rsa error"); + } + if (mp_mulmod(&rsa_tmp1, &rsa_s, key->n, &rsa_tmp2) != MP_OKAY) { + dropbear_exit("rsa error"); + } /* rsa_tmp2 is em' */ /* s' = (em')^d mod n */ - mp_exptmod(&rsa_tmp2, key->d, key->n, &rsa_tmp1); + if (mp_exptmod(&rsa_tmp2, key->d, key->n, &rsa_tmp1) != MP_OKAY) { + dropbear_exit("rsa error"); + } /* rsa_tmp1 is s' */ /* rsa_tmp3 is r^(-1) mod n */ /* s = (s')r^(-1) mod n */ - mp_mulmod(&rsa_tmp1, &rsa_tmp3, key->n, &rsa_s); + if (mp_mulmod(&rsa_tmp1, &rsa_tmp3, key->n, &rsa_s) != MP_OKAY) { + dropbear_exit("rsa error"); + } #else diff -r 2908122e9eed -r a5bca950120d svr-chansession.c --- a/svr-chansession.c Sat Feb 03 08:10:09 2007 +0000 +++ b/svr-chansession.c Sat Feb 03 08:20:45 2007 +0000 @@ -59,7 +59,6 @@ struct ChanSess * chansess); static void send_msg_chansess_exitsignal(struct Channel * channel, struct ChanSess * chansess); -static int sesscheckclose(struct Channel *channel); static void get_termmodes(struct ChanSess *chansess); @@ -67,7 +66,8 @@ extern char** environ; static int sesscheckclose(struct Channel *channel) { - return channel->writefd == -1; + struct ChanSess *chansess = (struct ChanSess*)channel->typedata; + return chansess->exit.exitpid != -1; } /* Handler for childs exiting, store the state for return to the client */ @@ -88,6 +88,8 @@ TRACE(("enter sigchld handler")) while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { + + exit = NULL; /* find the corresponding chansess */ for (i = 0; i < svr_ses.childpidsize; i++) { if (svr_ses.childpids[i].pid == pid) { @@ -99,7 +101,7 @@ /* If the pid wasn't matched, then we might have hit the race mentioned * above. So we just store the info for the parent to deal with */ - if (i == svr_ses.childpidsize) { + if (!exit) { exit = &svr_ses.lastexit; } @@ -118,7 +120,6 @@ /* we use this to determine how pid exited */ exit->exitsignal = -1; } - exit = NULL; } @@ -587,6 +588,16 @@ } } +#ifdef LOG_COMMANDS + if (chansess->cmd) { + dropbear_log(LOG_INFO, "user %s executing '%s'", + ses.authstate.printableuser, chansess->cmd); + } else { + dropbear_log(LOG_INFO, "user %s executing login shell", + ses.authstate.printableuser); + } +#endif + if (chansess->term == NULL) { /* no pty */ ret = noptycommand(channel, chansess); diff -r 2908122e9eed -r a5bca950120d svr-kex.c --- a/svr-kex.c Sat Feb 03 08:10:09 2007 +0000 +++ b/svr-kex.c Sat Feb 03 08:20:45 2007 +0000 @@ -52,7 +52,9 @@ } m_mp_init(&dh_e); - buf_getmpint(ses.payload, &dh_e); + if (buf_getmpint(ses.payload, &dh_e) != DROPBEAR_SUCCESS) { + dropbear_exit("Failed to get kex value"); + } send_msg_kexdh_reply(&dh_e); diff -r 2908122e9eed -r a5bca950120d svr-tcpfwd.c --- a/svr-tcpfwd.c Sat Feb 03 08:10:09 2007 +0000 +++ b/svr-tcpfwd.c Sat Feb 03 08:20:45 2007 +0000 @@ -216,7 +216,7 @@ if (ret == DROPBEAR_FAILURE) { /* we only free it if a listener wasn't created, since the listener * has to remember it if it's to be cancelled */ - m_free(tcpinfo->listenaddr); + m_free(bindaddr); m_free(tcpinfo); } TRACE(("leave remotetcpreq")) diff -r 2908122e9eed -r a5bca950120d tcp-accept.c --- a/tcp-accept.c Sat Feb 03 08:10:09 2007 +0000 +++ b/tcp-accept.c Sat Feb 03 08:20:45 2007 +0000 @@ -131,7 +131,6 @@ tcp_acceptor, cleanup_tcp); if (listener == NULL) { - m_free(tcpinfo); TRACE(("leave listen_tcpfwd: listener failed")) return DROPBEAR_FAILURE; }