From 69282617fd9c40395d57edf0ed6587def6131de7 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Fri, 27 Aug 2004 14:39:01 +0000 Subject: [PATCH] merge of 50be59810e462f9f44f55e421227d6aa0b31982b and 69b007796063cb5f042be7cca2d479e90db869c3 --HG-- extra : convert_revision : 5d0dfaa8c0ee6c728a3b4f0f0855199ba729db83 --- cli-chansession.c | 6 ++++++ cli-main.c | 4 ++++ common-channel.c | 51 +++++++++++++++++++++++++++++------------------ dbutil.c | 10 ++++++++++ dbutil.h | 1 + debug.h | 8 +++++--- svr-agentfwd.c | 4 +--- svr-chansession.c | 13 +++++------- svr-x11fwd.c | 4 +--- 9 files changed, 65 insertions(+), 36 deletions(-) diff --git a/cli-chansession.c b/cli-chansession.c index 50226dd..35be671 100644 --- a/cli-chansession.c +++ b/cli-chansession.c @@ -341,8 +341,14 @@ static int cli_initchansess(struct Channel *channel) { channel->infd = STDOUT_FILENO; + setnonblocking(STDOUT_FILENO); + channel->outfd = STDIN_FILENO; + setnonblocking(STDIN_FILENO); + channel->errfd = STDERR_FILENO; + setnonblocking(STDERR_FILENO); + channel->extrabuf = cbuf_new(RECV_MAXWINDOW); if (cli_opts.wantpty) { diff --git a/cli-main.c b/cli-main.c index 34a1e42..def2c72 100644 --- a/cli-main.c +++ b/cli-main.c @@ -52,6 +52,10 @@ int main(int argc, char ** argv) { TRACE(("user='%s' host='%s' port='%s'", cli_opts.username, cli_opts.remotehost, cli_opts.remoteport)); + if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { + dropbear_exit("signal() error"); + } + sock = connect_remote(cli_opts.remotehost, cli_opts.remoteport, 0, &error); diff --git a/common-channel.c b/common-channel.c index a4cc44b..d30528c 100644 --- a/common-channel.c +++ b/common-channel.c @@ -192,7 +192,8 @@ void channelio(fd_set *readfd, fd_set *writefd) { } /* read from program/pipe stderr */ - if (channel->errfd >= 0 && FD_ISSET(channel->errfd, readfd)) { + if (channel->extrabuf == NULL && + channel->errfd >= 0 && FD_ISSET(channel->errfd, readfd)) { send_msg_channel_data(channel, 1, SSH_EXTENDED_DATA_STDERR); } @@ -245,6 +246,14 @@ void channelio(fd_set *readfd, fd_set *writefd) { /* do all the EOF/close type stuff checking for a channel */ static void checkclose(struct Channel *channel) { + TRACE(("checkclose: infd %d, outfd %d, errfd %d, sentclosed %d, recvclosed %d", + channel->infd, channel->outfd, + channel->errfd, channel->sentclosed, channel->recvclosed)); + TRACE(("writebuf %d extrabuf %s extrabuf %d", + cbuf_getused(channel->writebuf), + channel->writebuf, + channel->writebuf ? 0 : cbuf_getused(channel->extrabuf))); + if (!channel->sentclosed) { /* check for exited - currently only used for server sessions, @@ -257,13 +266,13 @@ static void checkclose(struct Channel *channel) { if (!channel->senteof && channel->outfd == FD_CLOSED - && channel->errfd == FD_CLOSED) { + && (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) { send_msg_channel_eof(channel); } if (channel->infd == FD_CLOSED - && channel->outfd == FD_CLOSED - && channel->errfd == FD_CLOSED) { + && channel->outfd == FD_CLOSED + && (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) { send_msg_channel_close(channel); } } @@ -383,9 +392,8 @@ static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf) { if (fd == channel->infd && len == maxlen && channel->recveof) { /* Check if we're closing up */ closeinfd(channel); - return; TRACE(("leave writechannel: recveof set")); - + return; } /* Window adjust handling */ @@ -433,7 +441,9 @@ void setchannelfds(fd_set *readfd, fd_set *writefd) { /* For checking FD status (ie closure etc) - we don't actually * read data from infd */ - TRACE(("infd = %d, outfd %d, bufused %d", channel->infd, channel->outfd, + TRACE(("infd = %d, outfd %d, errfd %d, bufused %d", + channel->infd, channel->outfd, + channel->errfd, cbuf_getused(channel->writebuf) )); if (channel->infd >= 0 && channel->infd != channel->outfd) { FD_SET(channel->infd, readfd); @@ -534,9 +544,8 @@ static void removechannel(struct Channel * channel) { * yet (ie they were shutdown etc */ close(channel->infd); close(channel->outfd); - if (channel->errfd >= 0) { - close(channel->errfd); - } + close(channel->errfd); + channel->typedata = NULL; deletechannel(channel); @@ -619,16 +628,19 @@ static void send_msg_channel_data(struct Channel *channel, int isextended, } /* 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) { closeoutfd(channel, fd); - TRACE(("leave send_msg_channel_data: read err %d", channel->index)); } 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); @@ -714,7 +726,7 @@ void common_recv_msg_channel_data(struct Channel *channel, int fd, len -= buflen; } - assert(channel->recvwindow > datalen); + assert(channel->recvwindow >= datalen); channel->recvwindow -= datalen; assert(channel->recvwindow <= RECV_MAXWINDOW); @@ -927,10 +939,7 @@ int send_msg_channel_open_init(int fd, const struct ChanType *type) { } /* set fd non-blocking */ - if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { - TRACE(("leave send_msg_channel_open_init() - FAILED in fcntl()")); - return DROPBEAR_FAILURE; - } + setnonblocking(fd); chan->infd = chan->outfd = fd; ses.maxfd = MAX(ses.maxfd, fd); @@ -1034,15 +1043,19 @@ static void closechanfd(struct Channel *channel, int fd, int how) { closein = closeout = 1; } - if (closeout && fd == channel->errfd) { - channel->errfd = FD_CLOSED; - } if (closeout && fd == channel->outfd) { channel->outfd = FD_CLOSED; } + if (closeout && (channel->extrabuf == NULL) && (fd == channel->errfd)) { + channel->errfd = FD_CLOSED; + } + if (closein && fd == channel->infd) { channel->infd = FD_CLOSED; } + if (closein && (channel->extrabuf != NULL) && (fd == channel->errfd)) { + channel->errfd = FD_CLOSED; + } } #endif /* USING_LISTENERS */ diff --git a/dbutil.c b/dbutil.c index a1ec3ed..c126a2f 100644 --- a/dbutil.c +++ b/dbutil.c @@ -595,3 +595,13 @@ void m_burn(void *data, unsigned int len) { } } + +void setnonblocking(int fd) { + + TRACE(("setnonblocking: %d", fd)); + + if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { + dropbear_exit("Couldn't set nonblocking"); + } + TRACE(("leave setnonblocking")); +} diff --git a/dbutil.h b/dbutil.h index 0409e36..6363f70 100644 --- a/dbutil.h +++ b/dbutil.h @@ -61,6 +61,7 @@ void * m_realloc(void* ptr, size_t size); #define m_free(X) __m_free(X); (X) = NULL; void __m_free(void* ptr); void m_burn(void* data, unsigned int len); +void setnonblocking(int fd); /* Used to force mp_ints to be initialised */ #define DEF_MP_INT(X) mp_int X = {0, 0, 0, NULL} diff --git a/debug.h b/debug.h index cc161dc..37f51ac 100644 --- a/debug.h +++ b/debug.h @@ -33,12 +33,13 @@ * etc. Don't use this normally, it might cause problems */ /* #define DEBUG_VALGRIND */ -/* Define this to compile in trace debugging printf()s. You'll need to - * run programs with "-v" to turn this on. +/* Define this to compile in trace debugging printf()s. + * You'll need to run programs with "-v" to turn this on. + * * 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 @@ -49,6 +50,7 @@ /* 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. * It's useful to run dropbear -F, so you don't fork as much */ +/* (This is Linux specific) */ /*#define DEBUG_FORKGPROF*/ /* A couple of flags, not usually useful, and mightn't do anything */ diff --git a/svr-agentfwd.c b/svr-agentfwd.c index 2674138..60c23f7 100644 --- a/svr-agentfwd.c +++ b/svr-agentfwd.c @@ -73,9 +73,7 @@ int agentreq(struct ChanSess * chansess) { } /* set non-blocking */ - if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { - goto fail; - } + setnonblocking(fd); /* pass if off to listener */ chansess->agentlistener = new_listener( &fd, 1, 0, chansess, diff --git a/svr-chansession.c b/svr-chansession.c index 8c9fa3b..be6678d 100644 --- a/svr-chansession.c +++ b/svr-chansession.c @@ -651,11 +651,10 @@ static int noptycommand(struct Channel *channel, struct ChanSess *chansess) { ses.maxfd = MAX(ses.maxfd, channel->outfd); ses.maxfd = MAX(ses.maxfd, channel->errfd); - if ((fcntl(channel->outfd, F_SETFL, O_NONBLOCK) < 0) || - (fcntl(channel->infd, F_SETFL, O_NONBLOCK) < 0) || - (fcntl(channel->errfd, F_SETFL, O_NONBLOCK) < 0)) { - dropbear_exit("Couldn't set nonblocking"); - } + setnonblocking(channel->outfd); + setnonblocking(channel->infd); + setnonblocking(channel->errfd); + } #undef FDIN #undef FDOUT @@ -761,9 +760,7 @@ static int ptycommand(struct Channel *channel, struct ChanSess *chansess) { /* don't need to set stderr here */ ses.maxfd = MAX(ses.maxfd, chansess->master); - if (fcntl(chansess->master, F_SETFL, O_NONBLOCK) < 0) { - dropbear_exit("Couldn't set nonblocking"); - } + setnonblocking(chansess->master); } diff --git a/svr-x11fwd.c b/svr-x11fwd.c index 75e94b8..45c9060 100644 --- a/svr-x11fwd.c +++ b/svr-x11fwd.c @@ -75,9 +75,7 @@ int x11req(struct ChanSess * chansess) { } /* set non-blocking */ - if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { - goto fail; - } + setnonblocking(fd); /* listener code will handle the socket now. * No cleanup handler needed, since listener_remove only happens