# HG changeset patch # User Matt Johnston # Date 1633938409 -28800 # Node ID c32976db772fee6f3699a3524301dae7584bcd38 # Parent a7cc3332d8abea9dc420c2b4b9b2ffb2b627c4a8# Parent 1edf4f143e12d2b0d3a15ddbca9a38425e58e77e Merge diff -r 1edf4f143e12 -r c32976db772f channel.h --- a/channel.h Thu Aug 19 18:49:52 2021 +0300 +++ b/channel.h Mon Oct 11 15:46:49 2021 +0800 @@ -60,6 +60,9 @@ int readfd; /* read from insecure side, written to wire */ int errfd; /* used like writefd or readfd, depending if it's client or server. Doesn't exactly belong here, but is cleaner here */ + int bidir_fd; /* a boolean indicating that writefd/readfd are the same + file descriptor (bidirectional), such as a network socket or PTY. + That is handled differently when closing FDs */ circbuffer *writebuf; /* data from the wire, for local consumption. Can be initially NULL */ circbuffer *extrabuf; /* extended-data for the program - used like writebuf @@ -77,8 +80,6 @@ for this channel (and are awaiting a confirmation or failure). */ - int flushing; - /* Used by client chansession to handle ~ escaping, NULL ignored otherwise */ void (*read_mangler)(const struct Channel*, const unsigned char* bytes, int *len); @@ -89,7 +90,6 @@ struct ChanType { - int sepfds; /* Whether this channel has separate pipes for in/out or not */ const char *name; /* Sets up the channel */ int (*inithandler)(struct Channel*); diff -r 1edf4f143e12 -r c32976db772f cli-agentfwd.c --- a/cli-agentfwd.c Thu Aug 19 18:49:52 2021 +0300 +++ b/cli-agentfwd.c Mon Oct 11 15:46:49 2021 +0800 @@ -47,7 +47,6 @@ static int new_agent_chan(struct Channel * channel); const struct ChanType cli_chan_agent = { - 0, /* sepfds */ "auth-agent@openssh.com", new_agent_chan, NULL, @@ -94,6 +93,7 @@ channel->readfd = fd; channel->writefd = fd; + channel->bidir_fd = 1; return 0; } diff -r 1edf4f143e12 -r c32976db772f cli-chansession.c --- a/cli-chansession.c Thu Aug 19 18:49:52 2021 +0300 +++ b/cli-chansession.c Mon Oct 11 15:46:49 2021 +0800 @@ -46,7 +46,6 @@ static void cli_tty_setup(void); const struct ChanType clichansess = { - 0, /* sepfds */ "session", /* name */ cli_initchansess, /* inithandler */ NULL, /* checkclosehandler */ @@ -344,6 +343,7 @@ setnonblocking(STDERR_FILENO); channel->extrabuf = cbuf_new(opts.recv_window); + channel->bidir_fd = 0; return 0; } @@ -383,7 +383,6 @@ #if DROPBEAR_CLI_NETCAT static const struct ChanType cli_chan_netcat = { - 0, /* sepfds */ "direct-tcpip", cli_init_netcat, /* inithandler */ NULL, diff -r 1edf4f143e12 -r c32976db772f cli-session.c --- a/cli-session.c Thu Aug 19 18:49:52 2021 +0300 +++ b/cli-session.c Mon Oct 11 15:46:49 2021 +0800 @@ -246,6 +246,9 @@ /* We've got the transport layer sorted, we now need to request * userauth */ send_msg_service_request(SSH_SERVICE_USERAUTH); + /* We aren't using any "implicit server authentication" methods, + so don't need to wait for a response for SSH_SERVICE_USERAUTH + before sending the auth messages (rfc4253 10) */ cli_auth_getmethods(); cli_ses.state = USERAUTH_REQ_SENT; TRACE(("leave cli_sessionloop: sent userauth methods req")) diff -r 1edf4f143e12 -r c32976db772f cli-tcpfwd.c --- a/cli-tcpfwd.c Thu Aug 19 18:49:52 2021 +0300 +++ b/cli-tcpfwd.c Mon Oct 11 15:46:49 2021 +0800 @@ -35,7 +35,6 @@ static int newtcpforwarded(struct Channel * channel); const struct ChanType cli_chan_tcpremote = { - 1, /* sepfds */ "forwarded-tcpip", newtcpforwarded, NULL, @@ -51,7 +50,6 @@ const char* remoteaddr, unsigned int remoteport); static const struct ChanType cli_chan_tcplocal = { - 1, /* sepfds */ "direct-tcpip", tcp_prio_inithandler, NULL, @@ -275,10 +273,10 @@ } channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE; - + snprintf(portstring, sizeof(portstring), "%u", fwd->connectport); channel->conn_pending = connect_remote(fwd->connectaddr, portstring, channel_connect_done, channel, NULL, NULL); - + err = SSH_OPEN_IN_PROGRESS; out: diff -r 1edf4f143e12 -r c32976db772f common-channel.c --- a/common-channel.c Thu Aug 19 18:49:52 2021 +0300 +++ b/common-channel.c Mon Oct 11 15:46:49 2021 +0800 @@ -154,7 +154,6 @@ newchan->readfd = FD_UNINIT; newchan->errfd = FD_CLOSED; /* this isn't always set to start with */ newchan->await_open = 0; - newchan->flushing = 0; newchan->writebuf = cbuf_new(opts.recv_window); newchan->recvwindow = opts.recv_window; @@ -284,14 +283,6 @@ channel->writebuf ? cbuf_getused(channel->writebuf) : 0, channel->extrabuf ? cbuf_getused(channel->extrabuf) : 0)) - if (!channel->flushing - && !channel->sent_close - && channel->type->check_close - && channel->type->check_close(channel)) - { - channel->flushing = 1; - } - /* if a type-specific check_close is defined we will only exit once that has been triggered. this is only used for a server "session" channel, to ensure that the shell has exited (and the exit status @@ -317,22 +308,6 @@ close_chan_fd(channel, channel->writefd, SHUT_WR); } - /* Special handling for flushing read data after an exit. We - read regardless of whether the select FD was set, - and if there isn't data available, the channel will get closed. */ - if (channel->flushing) { - TRACE(("might send data, flushing")) - if (channel->readfd >= 0 && channel->transwindow > 0) { - TRACE(("send data readfd")) - send_msg_channel_data(channel, 0); - } - if (ERRFD_IS_READ(channel) && channel->errfd >= 0 - && channel->transwindow > 0) { - TRACE(("send data errfd")) - send_msg_channel_data(channel, 1); - } - } - /* If we're not going to send any more data, send EOF */ if (!channel->sent_eof && channel->readfd == FD_CLOSED @@ -364,6 +339,7 @@ if (result == DROPBEAR_SUCCESS) { channel->readfd = channel->writefd = sock; + channel->bidir_fd = 1; channel->conn_pending = NULL; send_msg_channel_open_confirmation(channel, channel->recvwindow, channel->recvmaxpacket); @@ -779,14 +755,6 @@ channel->transwindow -= len; encrypt_packet(); - - /* If we receive less data than we requested when flushing, we've - reached the equivalent of EOF */ - if (channel->flushing && len < (ssize_t)maxlen) - { - TRACE(("closing from channel, flushing out.")) - close_chan_fd(channel, fd, SHUT_RD); - } TRACE(("leave send_msg_channel_data")) } @@ -1072,7 +1040,7 @@ int closein = 0, closeout = 0; - if (channel->type->sepfds) { + if (channel->bidir_fd) { TRACE(("SHUTDOWN(%d, %d)", fd, how)) shutdown(fd, how); if (how == 0) { @@ -1102,7 +1070,7 @@ /* 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 + if (channel->bidir_fd && channel->readfd == FD_CLOSED && channel->writefd == FD_CLOSED && channel->errfd == FD_CLOSED) { TRACE(("CLOSE (finally) of %d", fd)) m_close(fd); @@ -1135,6 +1103,7 @@ chan->writefd = chan->readfd = fd; ses.maxfd = MAX(ses.maxfd, fd); + chan->bidir_fd = 1; chan->await_open = 1; @@ -1151,7 +1120,7 @@ return DROPBEAR_SUCCESS; } -/* Confirmation that our channel open request (for forwardings) was +/* Confirmation that our channel open request was * successful*/ void recv_msg_channel_open_confirmation() { diff -r 1edf4f143e12 -r c32976db772f svr-agentfwd.c --- a/svr-agentfwd.c Thu Aug 19 18:49:52 2021 +0300 +++ b/svr-agentfwd.c Mon Oct 11 15:46:49 2021 +0800 @@ -186,7 +186,6 @@ } static const struct ChanType chan_svr_agent = { - 0, /* sepfds */ "auth-agent@openssh.com", NULL, NULL, diff -r 1edf4f143e12 -r c32976db772f svr-chansession.c --- a/svr-chansession.c Thu Aug 19 18:49:52 2021 +0300 +++ b/svr-chansession.c Mon Oct 11 15:46:49 2021 +0800 @@ -64,7 +64,6 @@ static void get_termmodes(const struct ChanSess *chansess); const struct ChanType svrchansess = { - 0, /* sepfds */ "session", /* name */ newchansess, /* inithandler */ sesscheckclose, /* checkclosehandler */ @@ -76,12 +75,22 @@ /* required to clear environment */ extern char** environ; +/* Returns whether the channel is ready to close. The child process + must not be running (has never started, or has exited) */ static int sesscheckclose(const struct Channel *channel) { struct ChanSess *chansess = (struct ChanSess*)channel->typedata; - TRACE(("sesscheckclose, pid is %d", chansess->exit.exitpid)) - return chansess->exit.exitpid != -1; + TRACE(("sesscheckclose, pid %d, exitpid %d", chansess->pid, chansess->exit.exitpid)) + return chansess->pid == 0 || chansess->exit.exitpid != -1; } +/* Handler for childs exiting, store the state for return to the client */ + +/* There's a particular race we have to watch out for: if the forked child + * executes, exits, and this signal-handler is called, all before the parent + * gets to run, then the childpids[] array won't have the pid in it. Hence we + * use the svr_ses.lastexit struct to hold the exit, which is then compared by + * the parent when it runs. This work correctly at least in the case of a + * single shell spawned (ie the usual case) */ void svr_chansess_checksignal(void) { int status; pid_t pid; @@ -127,18 +136,9 @@ /* we use this to determine how pid exited */ ex->exitsignal = -1; } - } } -/* Handler for childs exiting, store the state for return to the client */ - -/* There's a particular race we have to watch out for: if the forked child - * executes, exits, and this signal-handler is called, all before the parent - * gets to run, then the childpids[] array won't have the pid in it. Hence we - * use the svr_ses.lastexit struct to hold the exit, which is then compared by - * the parent when it runs. This work correctly at least in the case of a - * single shell spawned (ie the usual case) */ static void sesssigchild_handler(int UNUSED(dummy)) { struct sigaction sa_chld; @@ -768,6 +768,7 @@ ses.maxfd = MAX(ses.maxfd, channel->writefd); ses.maxfd = MAX(ses.maxfd, channel->readfd); ses.maxfd = MAX(ses.maxfd, channel->errfd); + channel->bidir_fd = 0; addchildpid(chansess, chansess->pid); @@ -894,6 +895,7 @@ channel->readfd = chansess->master; /* don't need to set stderr here */ ses.maxfd = MAX(ses.maxfd, chansess->master); + channel->bidir_fd = 1; setnonblocking(chansess->master); diff -r 1edf4f143e12 -r c32976db772f svr-session.c --- a/svr-session.c Thu Aug 19 18:49:52 2021 +0300 +++ b/svr-session.c Mon Oct 11 15:46:49 2021 +0800 @@ -201,8 +201,7 @@ } #endif - /* Run the main for loop. NULL is for the dispatcher - only the client - * code makes use of it */ + /* Run the main for-loop. */ session_loop(svr_chansess_checksignal); /* Not reached */ diff -r 1edf4f143e12 -r c32976db772f svr-tcpfwd.c --- a/svr-tcpfwd.c Thu Aug 19 18:49:52 2021 +0300 +++ b/svr-tcpfwd.c Mon Oct 11 15:46:49 2021 +0800 @@ -59,7 +59,6 @@ #if DROPBEAR_SVR_REMOTETCPFWD static const struct ChanType svr_chan_tcpremote = { - 1, /* sepfds */ "forwarded-tcpip", tcp_prio_inithandler, NULL, @@ -241,7 +240,6 @@ #if DROPBEAR_SVR_LOCALTCPFWD const struct ChanType svr_chan_tcpdirect = { - 1, /* sepfds */ "direct-tcpip", newtcpdirect, /* init */ NULL, /* checkclose */ diff -r 1edf4f143e12 -r c32976db772f svr-x11fwd.c --- a/svr-x11fwd.c Thu Aug 19 18:49:52 2021 +0300 +++ b/svr-x11fwd.c Mon Oct 11 15:46:49 2021 +0800 @@ -211,7 +211,6 @@ } static const struct ChanType chan_x11 = { - 0, /* sepfds */ "x11", x11_inithandler, /* inithandler */ NULL, /* checkclose */