mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-25 09:12:24 +00:00
Fix `disconnect': arrange that we keep track of when we're expecting
to see the server slam the TCP connection shut (i.e. almost never, unless it's just sent us an SSH_MSG_DISCONNECT), and treat an unexpected closure as a non-clean session termination. Previously any server-initiated connection closure was being treated as a clean exit, which was a hangover from the good old Telnet-only days. [originally from svn r5098] [this svn revision also touched putty-wishlist]
This commit is contained in:
parent
95368801d3
commit
f3b5bddd32
40
ssh.c
40
ssh.c
@ -561,7 +561,7 @@ static void ssh2_add_channel_data(struct ssh_channel *c, char *buf, int len);
|
|||||||
static void ssh_throttle_all(Ssh ssh, int enable, int bufsize);
|
static void ssh_throttle_all(Ssh ssh, int enable, int bufsize);
|
||||||
static void ssh2_set_window(struct ssh_channel *c, unsigned newwin);
|
static void ssh2_set_window(struct ssh_channel *c, unsigned newwin);
|
||||||
static int ssh_sendbuffer(void *handle);
|
static int ssh_sendbuffer(void *handle);
|
||||||
static void ssh_do_close(Ssh ssh);
|
static int ssh_do_close(Ssh ssh, int notify_exit);
|
||||||
static unsigned long ssh_pkt_getuint32(struct Packet *pkt);
|
static unsigned long ssh_pkt_getuint32(struct Packet *pkt);
|
||||||
static int ssh2_pkt_getbool(struct Packet *pkt);
|
static int ssh2_pkt_getbool(struct Packet *pkt);
|
||||||
static void ssh_pkt_getstring(struct Packet *pkt, char **p, int *length);
|
static void ssh_pkt_getstring(struct Packet *pkt, char **p, int *length);
|
||||||
@ -642,6 +642,7 @@ struct ssh_tag {
|
|||||||
tree234 *channels; /* indexed by local id */
|
tree234 *channels; /* indexed by local id */
|
||||||
struct ssh_channel *mainchan; /* primary session channel */
|
struct ssh_channel *mainchan; /* primary session channel */
|
||||||
int exitcode;
|
int exitcode;
|
||||||
|
int close_expected;
|
||||||
|
|
||||||
tree234 *rportfwds, *portfwds;
|
tree234 *rportfwds, *portfwds;
|
||||||
|
|
||||||
@ -772,7 +773,7 @@ static void logeventf(Ssh ssh, const char *fmt, ...)
|
|||||||
#define bombout(msg) \
|
#define bombout(msg) \
|
||||||
do { \
|
do { \
|
||||||
char *text = dupprintf msg; \
|
char *text = dupprintf msg; \
|
||||||
ssh_do_close(ssh); \
|
ssh_do_close(ssh, FALSE); \
|
||||||
logevent(text); \
|
logevent(text); \
|
||||||
connection_fatal(ssh->frontend, "%s", text); \
|
connection_fatal(ssh->frontend, "%s", text); \
|
||||||
sfree(text); \
|
sfree(text); \
|
||||||
@ -2368,16 +2369,19 @@ static void ssh_gotdata(Ssh ssh, unsigned char *data, int datalen)
|
|||||||
crFinishV;
|
crFinishV;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ssh_do_close(Ssh ssh)
|
static int ssh_do_close(Ssh ssh, int notify_exit)
|
||||||
{
|
{
|
||||||
int i;
|
int i, ret = 0;
|
||||||
struct ssh_channel *c;
|
struct ssh_channel *c;
|
||||||
|
|
||||||
ssh->state = SSH_STATE_CLOSED;
|
ssh->state = SSH_STATE_CLOSED;
|
||||||
if (ssh->s) {
|
if (ssh->s) {
|
||||||
sk_close(ssh->s);
|
sk_close(ssh->s);
|
||||||
ssh->s = NULL;
|
ssh->s = NULL;
|
||||||
notify_remote_exit(ssh->frontend);
|
if (notify_exit)
|
||||||
|
notify_remote_exit(ssh->frontend);
|
||||||
|
else
|
||||||
|
ret = 1;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Now we must shut down any port and X forwardings going
|
* Now we must shut down any port and X forwardings going
|
||||||
@ -2399,20 +2403,29 @@ static void ssh_do_close(Ssh ssh)
|
|||||||
sfree(c);
|
sfree(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ssh_closing(Plug plug, const char *error_msg, int error_code,
|
static int ssh_closing(Plug plug, const char *error_msg, int error_code,
|
||||||
int calling_back)
|
int calling_back)
|
||||||
{
|
{
|
||||||
Ssh ssh = (Ssh) plug;
|
Ssh ssh = (Ssh) plug;
|
||||||
ssh_do_close(ssh);
|
int need_notify = ssh_do_close(ssh, FALSE);
|
||||||
|
|
||||||
|
if (!error_msg && !ssh->close_expected) {
|
||||||
|
error_msg = "Server unexpectedly closed network connection";
|
||||||
|
}
|
||||||
|
|
||||||
if (error_msg) {
|
if (error_msg) {
|
||||||
/* A socket error has occurred. */
|
/* A socket error has occurred. */
|
||||||
logevent(error_msg);
|
logevent(error_msg);
|
||||||
connection_fatal(ssh->frontend, "%s", error_msg);
|
connection_fatal(ssh->frontend, "%s", error_msg);
|
||||||
} else {
|
} else {
|
||||||
/* Otherwise, the remote side closed the connection normally. */
|
logevent("Server closed network connection");
|
||||||
}
|
}
|
||||||
|
if (need_notify)
|
||||||
|
notify_remote_exit(ssh->frontend);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2421,7 +2434,7 @@ static int ssh_receive(Plug plug, int urgent, char *data, int len)
|
|||||||
Ssh ssh = (Ssh) plug;
|
Ssh ssh = (Ssh) plug;
|
||||||
ssh_gotdata(ssh, (unsigned char *)data, len);
|
ssh_gotdata(ssh, (unsigned char *)data, len);
|
||||||
if (ssh->state == SSH_STATE_CLOSED) {
|
if (ssh->state == SSH_STATE_CLOSED) {
|
||||||
ssh_do_close(ssh);
|
ssh_do_close(ssh, TRUE);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
@ -2922,6 +2935,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,
|
|||||||
* Terminate.
|
* Terminate.
|
||||||
*/
|
*/
|
||||||
logevent("No username provided. Abandoning session.");
|
logevent("No username provided. Abandoning session.");
|
||||||
|
ssh->close_expected = TRUE;
|
||||||
ssh_closing((Plug)ssh, NULL, 0, 0);
|
ssh_closing((Plug)ssh, NULL, 0, 0);
|
||||||
crStop(1);
|
crStop(1);
|
||||||
}
|
}
|
||||||
@ -3270,6 +3284,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,
|
|||||||
PKT_END);
|
PKT_END);
|
||||||
logevent("Unable to authenticate");
|
logevent("Unable to authenticate");
|
||||||
connection_fatal(ssh->frontend, "Unable to authenticate");
|
connection_fatal(ssh->frontend, "Unable to authenticate");
|
||||||
|
ssh->close_expected = TRUE;
|
||||||
ssh_closing((Plug)ssh, NULL, 0, 0);
|
ssh_closing((Plug)ssh, NULL, 0, 0);
|
||||||
crStop(1);
|
crStop(1);
|
||||||
}
|
}
|
||||||
@ -4322,6 +4337,7 @@ static void ssh1_smsg_exit_status(Ssh ssh, struct Packet *pktin)
|
|||||||
* encrypted packet, we close the session once
|
* encrypted packet, we close the session once
|
||||||
* we've sent EXIT_CONFIRMATION.
|
* we've sent EXIT_CONFIRMATION.
|
||||||
*/
|
*/
|
||||||
|
ssh->close_expected = TRUE;
|
||||||
ssh_closing((Plug)ssh, NULL, 0, 0);
|
ssh_closing((Plug)ssh, NULL, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5600,6 +5616,7 @@ static void ssh2_msg_channel_close(Ssh ssh, struct Packet *pktin)
|
|||||||
ssh2_pkt_addstring(s->pktout, "en"); /* language tag */
|
ssh2_pkt_addstring(s->pktout, "en"); /* language tag */
|
||||||
ssh2_pkt_send_noqueue(ssh, s->pktout);
|
ssh2_pkt_send_noqueue(ssh, s->pktout);
|
||||||
#endif
|
#endif
|
||||||
|
ssh->close_expected = TRUE;
|
||||||
ssh_closing((Plug)ssh, NULL, 0, 0);
|
ssh_closing((Plug)ssh, NULL, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5700,6 +5717,7 @@ static void ssh2_msg_channel_request(Ssh ssh, struct Packet *pktin)
|
|||||||
ssh2_pkt_addstring(pktout, "en"); /* language tag */
|
ssh2_pkt_addstring(pktout, "en"); /* language tag */
|
||||||
ssh2_pkt_send_noqueue(ssh, pktout);
|
ssh2_pkt_send_noqueue(ssh, pktout);
|
||||||
connection_fatal(ssh->frontend, "%s", buf);
|
connection_fatal(ssh->frontend, "%s", buf);
|
||||||
|
ssh->close_expected = TRUE;
|
||||||
ssh_closing((Plug)ssh, NULL, 0, 0);
|
ssh_closing((Plug)ssh, NULL, 0, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -6053,6 +6071,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
|
|||||||
* Terminate.
|
* Terminate.
|
||||||
*/
|
*/
|
||||||
logevent("No username provided. Abandoning session.");
|
logevent("No username provided. Abandoning session.");
|
||||||
|
ssh->close_expected = TRUE;
|
||||||
ssh_closing((Plug)ssh, NULL, 0, 0);
|
ssh_closing((Plug)ssh, NULL, 0, 0);
|
||||||
crStopV;
|
crStopV;
|
||||||
}
|
}
|
||||||
@ -6614,6 +6633,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
|
|||||||
logevent("Unable to authenticate");
|
logevent("Unable to authenticate");
|
||||||
connection_fatal(ssh->frontend,
|
connection_fatal(ssh->frontend,
|
||||||
"Unable to authenticate");
|
"Unable to authenticate");
|
||||||
|
ssh->close_expected = TRUE;
|
||||||
ssh_closing((Plug)ssh, NULL, 0, 0);
|
ssh_closing((Plug)ssh, NULL, 0, 0);
|
||||||
crStopV;
|
crStopV;
|
||||||
}
|
}
|
||||||
@ -6812,6 +6832,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
|
|||||||
" methods available");
|
" methods available");
|
||||||
ssh2_pkt_addstring(s->pktout, "en"); /* language tag */
|
ssh2_pkt_addstring(s->pktout, "en"); /* language tag */
|
||||||
ssh2_pkt_send_noqueue(ssh, s->pktout);
|
ssh2_pkt_send_noqueue(ssh, s->pktout);
|
||||||
|
ssh->close_expected = TRUE;
|
||||||
ssh_closing((Plug)ssh, NULL, 0, 0);
|
ssh_closing((Plug)ssh, NULL, 0, 0);
|
||||||
crStopV;
|
crStopV;
|
||||||
}
|
}
|
||||||
@ -7393,6 +7414,7 @@ static const char *ssh_init(void *frontend_handle, void **backend_handle,
|
|||||||
ssh->kex_ctx = NULL;
|
ssh->kex_ctx = NULL;
|
||||||
ssh->hostkey = NULL;
|
ssh->hostkey = NULL;
|
||||||
ssh->exitcode = -1;
|
ssh->exitcode = -1;
|
||||||
|
ssh->close_expected = FALSE;
|
||||||
ssh->state = SSH_STATE_PREPACKET;
|
ssh->state = SSH_STATE_PREPACKET;
|
||||||
ssh->size_needed = FALSE;
|
ssh->size_needed = FALSE;
|
||||||
ssh->eof_needed = FALSE;
|
ssh->eof_needed = FALSE;
|
||||||
@ -7548,7 +7570,7 @@ static void ssh_free(void *handle)
|
|||||||
ssh->crcda_ctx = NULL;
|
ssh->crcda_ctx = NULL;
|
||||||
}
|
}
|
||||||
if (ssh->s)
|
if (ssh->s)
|
||||||
ssh_do_close(ssh);
|
ssh_do_close(ssh, TRUE);
|
||||||
expire_timer_context(ssh);
|
expire_timer_context(ssh);
|
||||||
if (ssh->pinger)
|
if (ssh->pinger)
|
||||||
pinger_free(ssh->pinger);
|
pinger_free(ssh->pinger);
|
||||||
|
Loading…
Reference in New Issue
Block a user