Avoid hanging on GSSAPI acquire_cred failure.

If GSSAPI authentication fails because we call the GSS acquire_cred
function on the client side and find it doesn't give us anything
useful, then that authentication attempt has to terminate - but since
_we_ decided to terminate it, on the client side, the server will be
sending us neither a formal USERAUTH_FAILURE nor any other kind of
packet.

So when we go back round to the top of the auth loop, we have to avoid
_either_ assuming we're sitting on a USERAUTH_FAILURE we can parse for
its method list, _or_ waiting to receive one. Instead we just have to
push on and try the next auth method in the list from the last
USERAUTH_FAILURE we did see.

Hence, a new flag lets us suppress the usual behaviour of waiting
until we have a response packet on the queue, and then all references
to pktin after that are tested for NULL.
This commit is contained in:
Simon Tatham 2018-12-06 18:08:56 +00:00
Родитель 6002b272f4
Коммит c99d37a7fe
1 изменённых файлов: 18 добавлений и 5 удалений

Просмотреть файл

@ -53,6 +53,7 @@ struct ssh2_userauth_state {
Ssh_gss_buf gss_rcvtok, gss_sndtok;
Ssh_gss_stat gss_stat;
#endif
bool suppress_wait_for_response_packet;
strbuf *last_methods_string;
bool kbd_inter_refused;
prompts_t *cur_prompt;
@ -431,9 +432,16 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
while (1) {
/*
* Wait for the result of the last authentication request.
* Wait for the result of the last authentication request,
* unless the request terminated for some reason on our
* own side.
*/
crMaybeWaitUntilV((pktin = ssh2_userauth_pop(s)) != NULL);
if (s->suppress_wait_for_response_packet) {
pktin = NULL;
s->suppress_wait_for_response_packet = false;
} else {
crMaybeWaitUntilV((pktin = ssh2_userauth_pop(s)) != NULL);
}
/*
* Now is a convenient point to spew any banner material
@ -466,12 +474,12 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
}
bufchain_clear(&s->banner);
}
if (pktin->type == SSH2_MSG_USERAUTH_SUCCESS) {
if (pktin && pktin->type == SSH2_MSG_USERAUTH_SUCCESS) {
ppl_logevent(("Access granted"));
goto userauth_success;
}
if (pktin->type != SSH2_MSG_USERAUTH_FAILURE &&
if (pktin && pktin->type != SSH2_MSG_USERAUTH_FAILURE &&
s->type != AUTH_TYPE_GSSAPI) {
ssh_proto_error(s->ppl.ssh, "Received unexpected packet "
"in response to authentication request, "
@ -487,7 +495,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
* we can look at the string in it and know what we can
* helpfully try next.
*/
if (pktin->type == SSH2_MSG_USERAUTH_FAILURE) {
if (pktin && pktin->type == SSH2_MSG_USERAUTH_FAILURE) {
ptrlen methods = get_string(pktin);
bool partial_success = get_bool(pktin);
@ -969,6 +977,11 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
if (s->gss_stat != SSH_GSS_OK) {
ppl_logevent(("GSSAPI authentication failed to get "
"credentials"));
/* The failure was on our side, so the server
* won't be sending a response packet indicating
* failure. Avoid waiting for it next time round
* the loop. */
s->suppress_wait_for_response_packet = true;
continue;
}