1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-27 02:02:26 +00:00

do_ssh2_authconn: get packets from a PacketQueue.

Just like do_ssh1_login, do_ssh2_authconn is now no longer receiving
its packets via function arguments; instead, it's pulling them off a
dedicated PacketQueue populated by particular dispatch table entries,
with the same reference-counting system to stop them being freed when
the pq_full processing function regains control.

This eliminates further ugly bombout()s from the code while waiting
for authentication responses from the user or the SSH agent.

As I mentioned in the previous commit, I've had to keep
ssh2_authconn_input separate from do_ssh2_authconn, and this time the
reason why is thoroughly annoying: it's because do_ssh2_authconn has
changed its prototype to take the Ssh structure as a void * so that it
can be called from the idempotent callback system, whereas
ssh2_authconn_input has to have the type of ssh->current_user_input_fn
which takes the more sensible pointer type 'Ssh'.
This commit is contained in:
Simon Tatham 2018-05-18 07:22:58 +01:00
parent 364b3a2838
commit e2b7f4f374

76
ssh.c
View File

@ -385,7 +385,7 @@ static int ssh2_pkt_construct(Ssh, struct Packet *);
static void ssh2_pkt_send(Ssh, struct Packet *); static void ssh2_pkt_send(Ssh, struct Packet *);
static void ssh2_pkt_send_noqueue(Ssh, struct Packet *); static void ssh2_pkt_send_noqueue(Ssh, struct Packet *);
static void do_ssh1_login(void *vctx); static void do_ssh1_login(void *vctx);
static void do_ssh2_authconn(Ssh ssh, struct Packet *pktin); static void do_ssh2_authconn(void *vctx);
static void ssh_channel_init(struct ssh_channel *c); static void ssh_channel_init(struct ssh_channel *c);
static struct ssh_channel *ssh_channel_msg(Ssh ssh, struct Packet *pktin); static struct ssh_channel *ssh_channel_msg(Ssh ssh, struct Packet *pktin);
static void ssh_channel_got_eof(struct ssh_channel *c); static void ssh_channel_got_eof(struct ssh_channel *c);
@ -969,6 +969,9 @@ struct ssh_tag {
struct PacketQueue pq_ssh1_login; struct PacketQueue pq_ssh1_login;
struct IdempotentCallback ssh1_login_icb; struct IdempotentCallback ssh1_login_icb;
struct PacketQueue pq_ssh2_authconn;
struct IdempotentCallback ssh2_authconn_icb;
bufchain user_input; bufchain user_input;
struct IdempotentCallback user_input_consumer; struct IdempotentCallback user_input_consumer;
@ -3514,7 +3517,7 @@ static void do_ssh_connection_init(Ssh ssh)
/* /*
* Get authconn (really just conn) under way. * Get authconn (really just conn) under way.
*/ */
do_ssh2_authconn(ssh, NULL); do_ssh2_authconn(ssh);
sfree(s->vstring); sfree(s->vstring);
@ -3956,7 +3959,7 @@ static void ssh_agent_callback(void *sshv, void *reply, int replylen)
if (ssh->version == 1) if (ssh->version == 1)
do_ssh1_login(ssh); do_ssh1_login(ssh);
else else
do_ssh2_authconn(ssh, NULL); do_ssh2_authconn(ssh);
} }
static void ssh_dialog_callback(void *sshv, int ret) static void ssh_dialog_callback(void *sshv, int ret)
@ -8432,8 +8435,8 @@ static void do_ssh2_transport(Ssh ssh, const void *vin, int inlen,
/* /*
* Allow authconn to initialise itself. * Allow authconn to initialise itself.
*/ */
do_ssh2_authconn(ssh, NULL);
ssh->current_user_input_fn = ssh2_authconn_input; ssh->current_user_input_fn = ssh2_authconn_input;
do_ssh2_authconn(ssh);
} }
crReturnV; crReturnV;
} }
@ -9985,18 +9988,23 @@ static void ssh2_setup_env(struct ssh_channel *c, struct Packet *pktin,
*/ */
static void ssh2_msg_authconn(Ssh ssh, struct Packet *pktin) static void ssh2_msg_authconn(Ssh ssh, struct Packet *pktin)
{ {
do_ssh2_authconn(ssh, pktin); pktin->refcount++; /* avoid packet being freed when we return */
pq_push(&ssh->pq_ssh2_authconn, pktin);
queue_idempotent_callback(&ssh->ssh2_authconn_icb);
} }
static void ssh2_response_authconn(struct ssh_channel *c, struct Packet *pktin, static void ssh2_response_authconn(struct ssh_channel *c, struct Packet *pktin,
void *ctx) void *ctx)
{ {
if (pktin) if (pktin)
do_ssh2_authconn(c->ssh, pktin); ssh2_msg_authconn(c->ssh, pktin);
} }
static void do_ssh2_authconn(Ssh ssh, struct Packet *pktin) static void do_ssh2_authconn(void *vctx)
{ {
Ssh ssh = (Ssh)vctx;
struct Packet *pktin;
struct do_ssh2_authconn_state { struct do_ssh2_authconn_state {
int crLine; int crLine;
enum { enum {
@ -10091,7 +10099,7 @@ static void do_ssh2_authconn(Ssh ssh, struct Packet *pktin)
s->pktout = ssh2_pkt_init(SSH2_MSG_SERVICE_REQUEST); s->pktout = ssh2_pkt_init(SSH2_MSG_SERVICE_REQUEST);
ssh2_pkt_addstring(s->pktout, "ssh-userauth"); ssh2_pkt_addstring(s->pktout, "ssh-userauth");
ssh2_pkt_send(ssh, s->pktout); ssh2_pkt_send(ssh, s->pktout);
crWaitUntilV(pktin); crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_authconn)) != NULL);
if (pktin->type == SSH2_MSG_SERVICE_ACCEPT) if (pktin->type == SSH2_MSG_SERVICE_ACCEPT)
s->done_service_req = TRUE; s->done_service_req = TRUE;
} }
@ -10102,7 +10110,7 @@ static void do_ssh2_authconn(Ssh ssh, struct Packet *pktin)
s->pktout = ssh2_pkt_init(SSH2_MSG_SERVICE_REQUEST); s->pktout = ssh2_pkt_init(SSH2_MSG_SERVICE_REQUEST);
ssh2_pkt_addstring(s->pktout, "ssh-connection"); ssh2_pkt_addstring(s->pktout, "ssh-connection");
ssh2_pkt_send(ssh, s->pktout); ssh2_pkt_send(ssh, s->pktout);
crWaitUntilV(pktin); crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_authconn)) != NULL);
if (pktin->type == SSH2_MSG_SERVICE_ACCEPT) { if (pktin->type == SSH2_MSG_SERVICE_ACCEPT) {
s->we_are_in = TRUE; /* no auth required */ s->we_are_in = TRUE; /* no auth required */
} else { } else {
@ -10197,14 +10205,7 @@ static void do_ssh2_authconn(Ssh ssh, struct Packet *pktin)
ssh_agent_callback, ssh); ssh_agent_callback, ssh);
if (ssh->auth_agent_query) { if (ssh->auth_agent_query) {
ssh->agent_response = NULL; ssh->agent_response = NULL;
do { crWaitUntilV(ssh->agent_response);
crReturnV;
if (pktin) {
bombout(("Unexpected data from server while"
" waiting for agent response"));
crStopV;
}
} while (!ssh->agent_response);
r = ssh->agent_response; r = ssh->agent_response;
s->agent_responselen = ssh->agent_response_len; s->agent_responselen = ssh->agent_response_len;
} }
@ -10399,7 +10400,7 @@ static void do_ssh2_authconn(Ssh ssh, struct Packet *pktin)
* Wait for the result of the last authentication request. * Wait for the result of the last authentication request.
*/ */
if (!s->gotit) if (!s->gotit)
crWaitUntilV(pktin); crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_authconn)) != NULL);
/* /*
* Now is a convenient point to spew any banner material * Now is a convenient point to spew any banner material
* that we've accumulated. (This should ensure that when * that we've accumulated. (This should ensure that when
@ -10593,7 +10594,7 @@ static void do_ssh2_authconn(Ssh ssh, struct Packet *pktin)
ssh2_pkt_send(ssh, s->pktout); ssh2_pkt_send(ssh, s->pktout);
s->type = AUTH_TYPE_PUBLICKEY_OFFER_QUIET; s->type = AUTH_TYPE_PUBLICKEY_OFFER_QUIET;
crWaitUntilV(pktin); crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_authconn)) != NULL);
if (pktin->type != SSH2_MSG_USERAUTH_PK_OK) { if (pktin->type != SSH2_MSG_USERAUTH_PK_OK) {
/* Offer of key refused. */ /* Offer of key refused. */
@ -10663,15 +10664,7 @@ static void do_ssh2_authconn(Ssh ssh, struct Packet *pktin)
ssh_agent_callback, ssh); ssh_agent_callback, ssh);
if (ssh->auth_agent_query) { if (ssh->auth_agent_query) {
ssh->agent_response = NULL; ssh->agent_response = NULL;
do { crWaitUntilV(ssh->agent_response);
crReturnV;
if (pktin) {
bombout(("Unexpected data from server"
" while waiting for agent"
" response"));
crStopV;
}
} while (!ssh->agent_response);
vret = ssh->agent_response; vret = ssh->agent_response;
s->retlen = ssh->agent_response_len; s->retlen = ssh->agent_response_len;
} }
@ -10737,7 +10730,7 @@ static void do_ssh2_authconn(Ssh ssh, struct Packet *pktin)
ssh2_pkt_send(ssh, s->pktout); ssh2_pkt_send(ssh, s->pktout);
logevent("Offered public key"); logevent("Offered public key");
crWaitUntilV(pktin); crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_authconn)) != NULL);
if (pktin->type != SSH2_MSG_USERAUTH_PK_OK) { if (pktin->type != SSH2_MSG_USERAUTH_PK_OK) {
/* Key refused. Give up. */ /* Key refused. Give up. */
s->gotit = TRUE; /* reconsider message next loop */ s->gotit = TRUE; /* reconsider message next loop */
@ -10929,7 +10922,7 @@ static void do_ssh2_authconn(Ssh ssh, struct Packet *pktin)
ssh_pkt_adddata(s->pktout, s->gss_buf.value, ssh_pkt_adddata(s->pktout, s->gss_buf.value,
s->gss_buf.length); s->gss_buf.length);
ssh2_pkt_send(ssh, s->pktout); ssh2_pkt_send(ssh, s->pktout);
crWaitUntilV(pktin); crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_authconn)) != NULL);
if (pktin->type != SSH2_MSG_USERAUTH_GSSAPI_RESPONSE) { if (pktin->type != SSH2_MSG_USERAUTH_GSSAPI_RESPONSE) {
logevent("GSSAPI authentication request refused"); logevent("GSSAPI authentication request refused");
continue; continue;
@ -11021,7 +11014,7 @@ static void do_ssh2_authconn(Ssh ssh, struct Packet *pktin)
} }
if (s->gss_stat == SSH_GSS_S_CONTINUE_NEEDED) { if (s->gss_stat == SSH_GSS_S_CONTINUE_NEEDED) {
crWaitUntilV(pktin); crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_authconn)) != NULL);
if (pktin->type != SSH2_MSG_USERAUTH_GSSAPI_TOKEN) { if (pktin->type != SSH2_MSG_USERAUTH_GSSAPI_TOKEN) {
logevent("GSSAPI authentication -" logevent("GSSAPI authentication -"
" bad server response"); " bad server response");
@ -11073,7 +11066,7 @@ static void do_ssh2_authconn(Ssh ssh, struct Packet *pktin)
logevent("Attempting keyboard-interactive authentication"); logevent("Attempting keyboard-interactive authentication");
crWaitUntilV(pktin); crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_authconn)) != NULL);
if (pktin->type != SSH2_MSG_USERAUTH_INFO_REQUEST) { if (pktin->type != SSH2_MSG_USERAUTH_INFO_REQUEST) {
/* Server is not willing to do keyboard-interactive /* Server is not willing to do keyboard-interactive
* at all (or, bizarrely but legally, accepts the * at all (or, bizarrely but legally, accepts the
@ -11201,7 +11194,7 @@ static void do_ssh2_authconn(Ssh ssh, struct Packet *pktin)
* Get the next packet in case it's another * Get the next packet in case it's another
* INFO_REQUEST. * INFO_REQUEST.
*/ */
crWaitUntilV(pktin); crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_authconn)) != NULL);
} }
@ -11281,7 +11274,7 @@ static void do_ssh2_authconn(Ssh ssh, struct Packet *pktin)
* Wait for next packet, in case it's a password change * Wait for next packet, in case it's a password change
* request. * request.
*/ */
crWaitUntilV(pktin); crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_authconn)) != NULL);
changereq_first_time = TRUE; changereq_first_time = TRUE;
while (pktin->type == SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ) { while (pktin->type == SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ) {
@ -11417,7 +11410,7 @@ static void do_ssh2_authconn(Ssh ssh, struct Packet *pktin)
* (If it's CHANGEREQ again, it's not happy with the * (If it's CHANGEREQ again, it's not happy with the
* new password.) * new password.)
*/ */
crWaitUntilV(pktin); crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_authconn)) != NULL);
changereq_first_time = FALSE; changereq_first_time = FALSE;
} }
@ -11525,7 +11518,7 @@ static void do_ssh2_authconn(Ssh ssh, struct Packet *pktin)
ssh2_pkt_send(ssh, s->pktout); ssh2_pkt_send(ssh, s->pktout);
ssh->ncmode = FALSE; ssh->ncmode = FALSE;
} }
crWaitUntilV(pktin); crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_authconn)) != NULL);
if (pktin->type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION && if (pktin->type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION &&
pktin->type != SSH2_MSG_CHANNEL_OPEN_FAILURE) { pktin->type != SSH2_MSG_CHANNEL_OPEN_FAILURE) {
bombout(("Server sent strange packet %d in response to main " bombout(("Server sent strange packet %d in response to main "
@ -11665,7 +11658,7 @@ static void do_ssh2_authconn(Ssh ssh, struct Packet *pktin)
} }
ssh2_pkt_send(ssh, s->pktout); ssh2_pkt_send(ssh, s->pktout);
crWaitUntilV(pktin); crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh2_authconn)) != NULL);
if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) { if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) {
if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) { if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) {
@ -11711,7 +11704,7 @@ static void do_ssh2_authconn(Ssh ssh, struct Packet *pktin)
ssh->send_ok = 1; ssh->send_ok = 1;
while (1) { while (1) {
crReturnV; crReturnV;
if (pktin) { if ((pktin = pq_pop(&ssh->pq_ssh2_authconn)) != NULL) {
/* /*
* _All_ the connection-layer packets we expect to * _All_ the connection-layer packets we expect to
@ -12229,7 +12222,7 @@ static void ssh2_general_packet_processing(Ssh ssh, struct Packet *pktin)
static void ssh2_authconn_input(Ssh ssh) static void ssh2_authconn_input(Ssh ssh)
{ {
do_ssh2_authconn(ssh, NULL); do_ssh2_authconn(ssh);
} }
static void ssh_cache_conf_values(Ssh ssh) static void ssh_cache_conf_values(Ssh ssh)
@ -12316,6 +12309,10 @@ static const char *ssh_init(void *frontend_handle, void **backend_handle,
ssh->ssh1_login_icb.fn = do_ssh1_login; ssh->ssh1_login_icb.fn = do_ssh1_login;
ssh->ssh1_login_icb.ctx = ssh; ssh->ssh1_login_icb.ctx = ssh;
ssh->ssh1_login_icb.queued = FALSE; ssh->ssh1_login_icb.queued = FALSE;
pq_init(&ssh->pq_ssh2_authconn);
ssh->ssh2_authconn_icb.fn = do_ssh2_authconn;
ssh->ssh2_authconn_icb.ctx = ssh;
ssh->ssh2_authconn_icb.queued = FALSE;
bufchain_init(&ssh->user_input); bufchain_init(&ssh->user_input);
ssh->user_input_consumer.fn = ssh_process_user_input; ssh->user_input_consumer.fn = ssh_process_user_input;
ssh->user_input_consumer.ctx = ssh; ssh->user_input_consumer.ctx = ssh;
@ -12495,6 +12492,7 @@ static void ssh_free(void *handle)
sfree(ssh->incoming_data_eof_message); sfree(ssh->incoming_data_eof_message);
pq_clear(&ssh->pq_full); pq_clear(&ssh->pq_full);
pq_clear(&ssh->pq_ssh1_login); pq_clear(&ssh->pq_ssh1_login);
pq_clear(&ssh->pq_ssh2_authconn);
bufchain_clear(&ssh->user_input); bufchain_clear(&ssh->user_input);
sfree(ssh->v_c); sfree(ssh->v_c);
sfree(ssh->v_s); sfree(ssh->v_s);