Split ChanType closehandler() and cleanup() so that dbclient doesn't

lose exit status messages
This commit is contained in:
Matt Johnston 2018-11-14 22:57:56 +08:00
parent ffde4a524f
commit fe992bf4ea
10 changed files with 58 additions and 31 deletions

View File

@ -69,10 +69,6 @@ struct Channel {
int sent_close, recv_close; int sent_close, recv_close;
int recv_eof, sent_eof; int recv_eof, sent_eof;
/* Set after running the ChanType-specific close hander
* to ensure we don't run it twice (nor type->checkclose()). */
int close_handler_done;
struct dropbear_progress_connection *conn_pending; struct dropbear_progress_connection *conn_pending;
int initconn; /* used for TCP forwarding, whether the channel has been int initconn; /* used for TCP forwarding, whether the channel has been
fully initialised */ fully initialised */
@ -95,10 +91,17 @@ struct ChanType {
int sepfds; /* Whether this channel has separate pipes for in/out or not */ int sepfds; /* Whether this channel has separate pipes for in/out or not */
const char *name; const char *name;
/* Sets up the channel */
int (*inithandler)(struct Channel*); int (*inithandler)(struct Channel*);
/* Called to check whether a channel should close, separately from the FD being closed.
Used for noticing process exiting */
int (*check_close)(const struct Channel*); int (*check_close)(const struct Channel*);
/* Handler for ssh_msg_channel_request */
void (*reqhandler)(struct Channel*); void (*reqhandler)(struct Channel*);
/* Called prior to sending ssh_msg_channel_close, used for sending exit status */
void (*closehandler)(const struct Channel*); void (*closehandler)(const struct Channel*);
/* Frees resources, called just prior to channel being removed */
void (*cleanup)(const struct Channel*);
}; };
/* Callback for connect_remote */ /* Callback for connect_remote */

View File

@ -52,6 +52,7 @@ const struct ChanType cli_chan_agent = {
new_agent_chan, new_agent_chan,
NULL, NULL,
NULL, NULL,
NULL,
NULL NULL
}; };

View File

@ -35,7 +35,7 @@
#include "chansession.h" #include "chansession.h"
#include "agentfwd.h" #include "agentfwd.h"
static void cli_closechansess(const struct Channel *channel); static void cli_cleanupchansess(const struct Channel *channel);
static int cli_initchansess(struct Channel *channel); static int cli_initchansess(struct Channel *channel);
static void cli_chansessreq(struct Channel *channel); static void cli_chansessreq(struct Channel *channel);
static void send_chansess_pty_req(const struct Channel *channel); static void send_chansess_pty_req(const struct Channel *channel);
@ -51,7 +51,8 @@ const struct ChanType clichansess = {
cli_initchansess, /* inithandler */ cli_initchansess, /* inithandler */
NULL, /* checkclosehandler */ NULL, /* checkclosehandler */
cli_chansessreq, /* reqhandler */ cli_chansessreq, /* reqhandler */
cli_closechansess, /* closehandler */ NULL, /* closehandler */
cli_cleanupchansess, /* cleanup */
}; };
static void cli_chansessreq(struct Channel *channel) { static void cli_chansessreq(struct Channel *channel) {
@ -83,7 +84,7 @@ out:
/* If the main session goes, we close it up */ /* If the main session goes, we close it up */
static void cli_closechansess(const struct Channel *UNUSED(channel)) { static void cli_cleanupchansess(const struct Channel *UNUSED(channel)) {
cli_tty_cleanup(); /* Restore tty modes etc */ cli_tty_cleanup(); /* Restore tty modes etc */
/* This channel hasn't gone yet, so we have > 1 */ /* This channel hasn't gone yet, so we have > 1 */
@ -387,7 +388,8 @@ static const struct ChanType cli_chan_netcat = {
cli_init_netcat, /* inithandler */ cli_init_netcat, /* inithandler */
NULL, NULL,
NULL, NULL,
cli_closechansess NULL,
cli_cleanupchansess
}; };
void cli_send_netcat_request() { void cli_send_netcat_request() {

View File

@ -356,6 +356,7 @@ static void cli_session_cleanup(void) {
} }
static void cli_finished() { static void cli_finished() {
TRACE(("cli_finised()"))
session_cleanup(); session_cleanup();
fprintf(stderr, "Connection to %s@%s:%s closed.\n", cli_opts.username, fprintf(stderr, "Connection to %s@%s:%s closed.\n", cli_opts.username,

View File

@ -40,6 +40,7 @@ const struct ChanType cli_chan_tcpremote = {
newtcpforwarded, newtcpforwarded,
NULL, NULL,
NULL, NULL,
NULL,
NULL NULL
}; };
#endif #endif
@ -55,6 +56,7 @@ static const struct ChanType cli_chan_tcplocal = {
tcp_prio_inithandler, tcp_prio_inithandler,
NULL, NULL,
NULL, NULL,
NULL,
NULL NULL
}; };
#endif #endif

View File

@ -144,7 +144,6 @@ static struct Channel* newchannel(unsigned int remotechan,
newchan->index = i; newchan->index = i;
newchan->sent_close = newchan->recv_close = 0; newchan->sent_close = newchan->recv_close = 0;
newchan->sent_eof = newchan->recv_eof = 0; newchan->sent_eof = newchan->recv_eof = 0;
newchan->close_handler_done = 0;
newchan->remotechan = remotechan; newchan->remotechan = remotechan;
newchan->transwindow = transwindow; newchan->transwindow = transwindow;
@ -286,7 +285,7 @@ static void check_close(struct Channel *channel) {
channel->extrabuf ? cbuf_getused(channel->extrabuf) : 0)) channel->extrabuf ? cbuf_getused(channel->extrabuf) : 0))
if (!channel->flushing if (!channel->flushing
&& !channel->close_handler_done && !channel->sent_close
&& channel->type->check_close && channel->type->check_close
&& channel->type->check_close(channel)) && channel->type->check_close(channel))
{ {
@ -298,7 +297,7 @@ static void check_close(struct Channel *channel) {
channel, to ensure that the shell has exited (and the exit status channel, to ensure that the shell has exited (and the exit status
retrieved) before we close things up. */ retrieved) before we close things up. */
if (!channel->type->check_close if (!channel->type->check_close
|| channel->close_handler_done || channel->sent_close
|| channel->type->check_close(channel)) { || channel->type->check_close(channel)) {
close_allowed = 1; close_allowed = 1;
} }
@ -385,10 +384,8 @@ void channel_connect_done(int result, int sock, void* user_data, const char* UNU
static void send_msg_channel_close(struct Channel *channel) { static void send_msg_channel_close(struct Channel *channel) {
TRACE(("enter send_msg_channel_close %p", (void*)channel)) TRACE(("enter send_msg_channel_close %p", (void*)channel))
if (channel->type->closehandler if (channel->type->closehandler) {
&& !channel->close_handler_done) {
channel->type->closehandler(channel); channel->type->closehandler(channel);
channel->close_handler_done = 1;
} }
CHECKCLEARTOWRITE(); CHECKCLEARTOWRITE();
@ -661,10 +658,8 @@ static void remove_channel(struct Channel * channel) {
m_close(channel->errfd); m_close(channel->errfd);
} }
if (!channel->close_handler_done if (channel->type->cleanup) {
&& channel->type->closehandler) { channel->type->cleanup(channel);
channel->type->closehandler(channel);
channel->close_handler_done = 1;
} }
if (channel->conn_pending) { if (channel->conn_pending) {
@ -690,13 +685,7 @@ void recv_msg_channel_request() {
TRACE(("enter recv_msg_channel_request %p", (void*)channel)) TRACE(("enter recv_msg_channel_request %p", (void*)channel))
if (channel->sent_close) { if (channel->type->reqhandler) {
TRACE(("leave recv_msg_channel_request: already closed channel"))
return;
}
if (channel->type->reqhandler
&& !channel->close_handler_done) {
channel->type->reqhandler(channel); channel->type->reqhandler(channel);
} else { } else {
int wantreply; int wantreply;
@ -1011,6 +1000,11 @@ cleanup:
void send_msg_channel_failure(const struct Channel *channel) { void send_msg_channel_failure(const struct Channel *channel) {
TRACE(("enter send_msg_channel_failure")) TRACE(("enter send_msg_channel_failure"))
if (channel->sent_close) {
TRACE(("Skipping sending msg_channel_failure for closed channel"))
return;
}
CHECKCLEARTOWRITE(); CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_FAILURE); buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_FAILURE);
@ -1024,6 +1018,10 @@ void send_msg_channel_failure(const struct Channel *channel) {
void send_msg_channel_success(const struct Channel *channel) { void send_msg_channel_success(const struct Channel *channel) {
TRACE(("enter send_msg_channel_success")) TRACE(("enter send_msg_channel_success"))
if (channel->sent_close) {
TRACE(("Skipping sending msg_channel_success for closed channel"))
return;
}
CHECKCLEARTOWRITE(); CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_SUCCESS); buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_SUCCESS);

View File

@ -187,6 +187,7 @@ static const struct ChanType chan_svr_agent = {
NULL, NULL,
NULL, NULL,
NULL, NULL,
NULL,
NULL NULL
}; };

View File

@ -51,6 +51,7 @@ static void execchild(const void *user_data_chansess);
static void addchildpid(struct ChanSess *chansess, pid_t pid); static void addchildpid(struct ChanSess *chansess, pid_t pid);
static void sesssigchild_handler(int val); static void sesssigchild_handler(int val);
static void closechansess(const struct Channel *channel); static void closechansess(const struct Channel *channel);
static void cleanupchansess(const struct Channel *channel);
static int newchansess(struct Channel *channel); static int newchansess(struct Channel *channel);
static void chansessionrequest(struct Channel *channel); static void chansessionrequest(struct Channel *channel);
static int sesscheckclose(const struct Channel *channel); static int sesscheckclose(const struct Channel *channel);
@ -69,6 +70,7 @@ const struct ChanType svrchansess = {
sesscheckclose, /* checkclosehandler */ sesscheckclose, /* checkclosehandler */
chansessionrequest, /* reqhandler */ chansessionrequest, /* reqhandler */
closechansess, /* closehandler */ closechansess, /* closehandler */
cleanupchansess /* cleanup */
}; };
/* required to clear environment */ /* required to clear environment */
@ -91,7 +93,7 @@ void svr_chansess_checksignal(void) {
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
unsigned int i; unsigned int i;
struct exitinfo *ex = NULL; struct exitinfo *ex = NULL;
TRACE(("sigchld handler: pid %d", pid)) TRACE(("svr_chansess_checksignal : pid %d", pid))
ex = NULL; ex = NULL;
/* find the corresponding chansess */ /* find the corresponding chansess */
@ -285,8 +287,25 @@ chansess_login_alloc(const struct ChanSess *chansess) {
return li; return li;
} }
/* clean a session channel */ /* send exit status message before the channel is closed */
static void closechansess(const struct Channel *channel) { static void closechansess(const struct Channel *channel) {
struct ChanSess *chansess;
TRACE(("enter closechansess"))
chansess = (struct ChanSess*)channel->typedata;
if (chansess == NULL) {
TRACE(("leave closechansess: chansess == NULL"))
return;
}
send_exitsignalstatus(channel);
TRACE(("leave closechansess"))
}
/* clean a session channel */
static void cleanupchansess(const struct Channel *channel) {
struct ChanSess *chansess; struct ChanSess *chansess;
unsigned int i; unsigned int i;
@ -301,8 +320,6 @@ static void closechansess(const struct Channel *channel) {
return; return;
} }
send_exitsignalstatus(channel);
m_free(chansess->cmd); m_free(chansess->cmd);
m_free(chansess->term); m_free(chansess->term);

View File

@ -238,7 +238,8 @@ const struct ChanType svr_chan_tcpdirect = {
newtcpdirect, /* init */ newtcpdirect, /* init */
NULL, /* checkclose */ NULL, /* checkclose */
NULL, /* reqhandler */ NULL, /* reqhandler */
NULL /* closehandler */ NULL, /* closehandler */
NULL /* cleanup */
}; };
/* Called upon creating a new direct tcp channel (ie we connect out to an /* Called upon creating a new direct tcp channel (ie we connect out to an

View File

@ -216,7 +216,8 @@ static const struct ChanType chan_x11 = {
x11_inithandler, /* inithandler */ x11_inithandler, /* inithandler */
NULL, /* checkclose */ NULL, /* checkclose */
NULL, /* reqhandler */ NULL, /* reqhandler */
NULL /* closehandler */ NULL, /* closehandler */
NULL /* cleanup */
}; };