summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--CHANGES19
-rw-r--r--Makefile.in11
-rw-r--r--auth.h2
-rw-r--r--channel.h9
-rw-r--r--cli-auth.c4
-rw-r--r--cli-authinteract.c5
-rw-r--r--cli-authpasswd.c7
-rw-r--r--cli-authpubkey.c1
-rw-r--r--cli-channel.c3
-rw-r--r--cli-kex.c2
-rw-r--r--cli-runopts.c2
-rw-r--r--cli-service.c2
-rw-r--r--common-channel.c496
-rw-r--r--common-kex.c20
-rw-r--r--common-session.c32
-rw-r--r--configure.in50
-rw-r--r--dbutil.c32
-rw-r--r--debian/changelog6
-rw-r--r--debug.h8
-rw-r--r--dropbearkey.c6
-rw-r--r--dss.c4
-rw-r--r--includes.h7
-rw-r--r--keyimport.c45
-rw-r--r--libtomcrypt/Makefile.in2
-rw-r--r--libtommath/bn_mp_div.c4
-rw-r--r--options.h10
-rw-r--r--rsa.c21
-rw-r--r--svr-chansession.c19
-rw-r--r--svr-kex.c4
-rw-r--r--svr-tcpfwd.c2
-rw-r--r--tcp-accept.c1
31 files changed, 438 insertions, 398 deletions
diff --git a/CHANGES b/CHANGES
index 5e07ffd..41d25ba 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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 --git a/Makefile.in b/Makefile.in
index 1ce13d2..f5b111f 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -64,13 +64,12 @@ bindir=${exec_prefix}/bin
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 @@ dropbearconvert: $(dropbearconvertobjs)
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 @@ endif
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 @@ $(LTC): options.h
$(LTM): options.h
cd libtommath && $(MAKE)
+.PHONY : clean sizes thisclean distclean tidy ltc-clean ltm-clean
+
ltc-clean:
cd libtomcrypt && $(MAKE) clean
diff --git a/auth.h b/auth.h
index c407ad5..661265a 100644
--- a/auth.h
+++ b/auth.h
@@ -52,7 +52,7 @@ void cli_pubkeyfail();
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 --git a/channel.h b/channel.h
index 7030a0f..fc3cb90 100644
--- a/channel.h
+++ b/channel.h
@@ -73,10 +73,9 @@ struct Channel {
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 @@ struct ChanType {
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 --git a/cli-auth.c b/cli-auth.c
index ba4cf6c..4c17a21 100644
--- a/cli-auth.c
+++ b/cli-auth.c
@@ -281,11 +281,11 @@ void cli_auth_try() {
/* 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 --git a/cli-authinteract.c b/cli-authinteract.c
index 5a169cb..5fe5bf1 100644
--- a/cli-authinteract.c
+++ b/cli-authinteract.c
@@ -99,13 +99,14 @@ void recv_msg_userauth_info_request() {
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 --git a/cli-authpasswd.c b/cli-authpasswd.c
index 5dffac4..2500a25 100644
--- a/cli-authpasswd.c
+++ b/cli-authpasswd.c
@@ -116,16 +116,19 @@ static char *gui_getpass(const char *prompt) {
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 --git a/cli-authpubkey.c b/cli-authpubkey.c
index 9d36bc3..8a8fb42 100644
--- a/cli-authpubkey.c
+++ b/cli-authpubkey.c
@@ -112,6 +112,7 @@ void recv_msg_userauth_pk_ok() {
/* Success */
break;
}
+ buf_free(keybuf);
if (keyitem != NULL) {
TRACE(("matching key"))
diff --git a/cli-channel.c b/cli-channel.c
index 1bd49ab..b88e913 100644
--- a/cli-channel.c
+++ b/cli-channel.c
@@ -39,9 +39,6 @@ void recv_msg_channel_extended_data() {
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 --git a/cli-kex.c b/cli-kex.c
index 3548f1c..467ae23 100644
--- a/cli-kex.c
+++ b/cli-kex.c
@@ -122,6 +122,7 @@ static void ask_to_confirm(unsigned char* keyblob, unsigned int keybloblen) {
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 @@ static void ask_to_confirm(unsigned char* keyblob, unsigned int keybloblen) {
}
if (response == 'y') {
- m_free(fp);
return;
}
diff --git a/cli-runopts.c b/cli-runopts.c
index a4a8a58..7a672da 100644
--- a/cli-runopts.c
+++ b/cli-runopts.c
@@ -44,7 +44,7 @@ static void addforward(char* str, struct TCPFwdList** fwdlist);
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 <remoteport>\n"
"-l <username>\n"
diff --git a/cli-service.c b/cli-service.c
index 87b6ed2..57807be 100644
--- a/cli-service.c
+++ b/cli-service.c
@@ -82,6 +82,4 @@ void recv_msg_service_accept() {
}
dropbear_exit("unrecognised service accept");
- /* m_free(servicename); not reached */
-
}
diff --git a/common-channel.c b/common-channel.c
index 0cd6ef8..8159477 100644
--- a/common-channel.c
+++ b/common-channel.c
@@ -43,22 +43,22 @@ static void send_msg_channel_open_confirmation(struct Channel* channel,
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 @@ void chancleanup() {
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 @@ struct Channel* newchannel(unsigned int remotechan,
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 @@ struct Channel* newchannel(unsigned int remotechan,
}
/* 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 @@ void channelio(fd_set *readfds, fd_set *writefds) {
/* 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 @@ void channelio(fd_set *readfds, fd_set *writefds) {
}
-/* 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) {
+
+ 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(("checkclose: writefd %d, readfd %d, errfd %d, sentclosed %d, recvclosed %d",
+ 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)))
-
- /* 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);
+ channel->extrabuf ? cbuf_getused(channel->extrabuf) : 0))
+
+ 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->recv_eof && !write_pending(channel)) {
+ close_chan_fd(channel, channel->writefd, SHUT_WR);
}
- if (!channel->senteof
- && channel->readfd == FD_CLOSED
- && (channel->extrabuf == NULL || channel->errfd == FD_CLOSED)) {
+ /* 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 @@ static void checkclose(struct Channel *channel) {
* 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 @@ static void send_msg_channel_close(struct Channel *channel) {
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 @@ static void send_msg_channel_eof(struct Channel *channel) {
encrypt_packet();
- channel->senteof = 1;
+ channel->sent_eof = 1;
TRACE(("leave send_msg_channel_eof"))
}
@@ -377,32 +400,25 @@ static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf) {
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 @@ static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf) {
dropbear_assert(channel->extrabuf == NULL ||
channel->recvwindow <= cbuf_getavail(channel->extrabuf));
-
TRACE(("leave writechannel"))
}
@@ -441,35 +456,32 @@ void setchannelfds(fd_set *readfds, fd_set *writefds) {
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 @@ void recv_msg_channel_eof() {
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 @@ void recv_msg_channel_close() {
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;
-
- if (channel->sentclosed) {
- removechannel(channel);
- }
+ channel->recv_eof = 1;
+ channel->recv_close = 1;
+ 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 @@ static void removechannel(struct Channel * channel) {
/* 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 @@ void recv_msg_channel_request() {
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 @@ void recv_msg_channel_request() {
* 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 @@ static void send_msg_channel_data(struct Channel *channel, int isextended,
* 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 @@ void recv_msg_channel_data() {
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 @@ void common_recv_msg_channel_data(struct Channel *channel, int fd,
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 @@ void recv_msg_channel_window_adjust() {
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 @@ static void send_msg_channel_window_adjust(struct Channel* channel,
}
/* 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 @@ void recv_msg_channel_open() {
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 @@ static void send_msg_channel_open_confirmation(struct Channel* channel,
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 @@ void recv_msg_channel_open_confirmation() {
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 @@ void recv_msg_channel_open_confirmation() {
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 @@ void recv_msg_channel_open_failure() {
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 --git a/common-kex.c b/common-kex.c
index 5db8e52..af39d1a 100644
--- a/common-kex.c
+++ b/common-kex.c
@@ -262,6 +262,7 @@ void gen_new_keys() {
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 @@ void gen_new_keys() {
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 @@ void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them,
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 --git a/common-session.c b/common-session.c
index 4c15391..a16d1f9 100644
--- a/common-session.c
+++ b/common-session.c
@@ -143,27 +143,21 @@ void session_loop(void(*loophandler)()) {
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 @@ void session_identification() {
/* 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 @@ void session_identification() {
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 --git a/configure.in b/configure.in
index 571c457..798becc 100644
--- a/configure.in
+++ b/configure.in
@@ -342,7 +342,7 @@ AC_CHECK_MEMBERS([struct utmp.ut_host, struct utmp.ut_pid, struct utmp.ut_type,
#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 <sys/types.h>
#include <sys/socket.h>
#if HAVE_UTMPX_H
@@ -350,6 +350,11 @@ AC_CHECK_MEMBERS([struct utmpx.ut_host, struct utmpx.ut_syslen, struct utmpx.ut_
#endif
])
+AC_CHECK_MEMBERS([struct sockaddr_storage.ss_family],,,[
+#include <sys/types.h>
+#include <sys/socket.h>
+])
+
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 @@ if test -z "$no_ptc_check" ; then
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 --git a/dbutil.c b/dbutil.c
index 15f51ba..9445f0e 100644
--- a/dbutil.c
+++ b/dbutil.c
@@ -400,7 +400,10 @@ unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport) {
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 @@ unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport) {
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 @@ char* getaddrhostname(struct sockaddr_storage * addr) {
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 @@ char* getaddrhostname(struct sockaddr_storage * addr) {
len = sizeof(struct sockaddr_in6);
}
#endif
+#endif
ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf),
@@ -521,26 +527,36 @@ char * stripcontrol(const char * text) {
* 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 --git a/debian/changelog b/debian/changelog
index 7152341..acebcef 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+dropbear (0.49-0.1) unstable; urgency=low
+
+ * New upstream release.
+
+ -- Matt Johnston <matt@ucc.asn.au> Tues, 13 June 2005 19:20:21 +0800
+
dropbear (0.48.1-1) unstable; urgency=medium
* new upstream point release.
diff --git a/debug.h b/debug.h
index 93cb891..ecc9d4a 100644
--- a/debug.h
+++ b/debug.h
@@ -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 --git a/dropbearkey.c b/dropbearkey.c
index 280e1b3..2433381 100644
--- a/dropbearkey.c
+++ b/dropbearkey.c
@@ -283,8 +283,10 @@ out:
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 --git a/dss.c b/dss.c
index 84a093c..95062c6 100644
--- a/dss.c
+++ b/dss.c
@@ -338,7 +338,9 @@ void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data,
/* 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 --git a/includes.h b/includes.h
index 06c9692..02e8877 100644
--- a/includes.h
+++ b/includes.h
@@ -135,13 +135,6 @@ typedef u_int16_t uint16_t;
#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 --git a/keyimport.c b/keyimport.c
index a0474f3..1d3e3f5 100644
--- a/keyimport.c
+++ b/keyimport.c
@@ -361,7 +361,7 @@ struct openssh_key {
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 @@ static struct openssh_key *load_openssh_key(const char *filename)
memset(&ret, 0, sizeof(ret));
m_free(ret);
}
+ if (fp) {
+ fclose(fp);
+ }
if (errmsg) {
fprintf(stderr, "Error: %s\n", errmsg);
}
@@ -926,40 +929,6 @@ static int openssh_write(const char *filename, sign_key *key,
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 @@ static int openssh_write(const char *filename, sign_key *key,
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 --git a/libtomcrypt/Makefile.in b/libtomcrypt/Makefile.in
index e1bee57..f1cfdad 100644
--- a/libtomcrypt/Makefile.in
+++ b/libtomcrypt/Makefile.in
@@ -158,7 +158,7 @@ default:library
#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 --git a/libtommath/bn_mp_div.c b/libtommath/bn_mp_div.c
index 6b2b8f0..6e1e0fb 100644
--- a/libtommath/bn_mp_div.c
+++ b/libtommath/bn_mp_div.c
@@ -269,7 +269,9 @@ int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
}
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 --git a/options.h b/options.h
index 6d22168..ad82f8b 100644
--- a/options.h
+++ b/options.h
@@ -128,7 +128,7 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
* 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 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
* 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 --git a/rsa.c b/rsa.c
index 005e4ca..8665673 100644
--- a/rsa.c
+++ b/rsa.c
@@ -285,18 +285,29 @@ void buf_put_rsa_sign(buffer* buf, rsa_key *key, const unsigned char* data,
/* 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 --git a/svr-chansession.c b/svr-chansession.c
index fed8240..99a67e9 100644
--- a/svr-chansession.c
+++ b/svr-chansession.c
@@ -59,7 +59,6 @@ static void send_msg_chansess_exitstatus(struct Channel * channel,
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 @@ static void get_termmodes(struct ChanSess *chansess);
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 @@ static void sesssigchild_handler(int UNUSED(dummy)) {
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 @@ static void sesssigchild_handler(int UNUSED(dummy)) {
/* 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 @@ static void sesssigchild_handler(int UNUSED(dummy)) {
/* we use this to determine how pid exited */
exit->exitsignal = -1;
}
- exit = NULL;
}
@@ -587,6 +588,16 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
}
}
+#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 --git a/svr-kex.c b/svr-kex.c
index a9954bb..75cb090 100644
--- a/svr-kex.c
+++ b/svr-kex.c
@@ -52,7 +52,9 @@ void recv_msg_kexdh_init() {
}
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 --git a/svr-tcpfwd.c b/svr-tcpfwd.c
index 6391c4c..d4dca6b 100644
--- a/svr-tcpfwd.c
+++ b/svr-tcpfwd.c
@@ -216,7 +216,7 @@ out:
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 --git a/tcp-accept.c b/tcp-accept.c
index ffb175e..c2fb2fe 100644
--- a/tcp-accept.c
+++ b/tcp-accept.c
@@ -131,7 +131,6 @@ int listen_tcpfwd(struct TCPListener* tcpinfo) {
tcp_acceptor, cleanup_tcp);
if (listener == NULL) {
- m_free(tcpinfo);
TRACE(("leave listen_tcpfwd: listener failed"))
return DROPBEAR_FAILURE;
}