mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-10 01:48:00 +00:00
userauth: factor out the keyboard-interactive code.
No functional change, but I've pulled the bulk of the k-i setup and prompting code out of ssh2_userauth_process_queue and into subroutines, in preparation for wanting to do the same work in more than one place in the main coroutine's control flow.
This commit is contained in:
parent
eec350c38b
commit
1f32a16dc8
@ -117,6 +117,11 @@ static void ssh2_userauth_add_session_id(
|
|||||||
static PktOut *ssh2_userauth_gss_packet(
|
static PktOut *ssh2_userauth_gss_packet(
|
||||||
struct ssh2_userauth_state *s, const char *authtype);
|
struct ssh2_userauth_state *s, const char *authtype);
|
||||||
#endif
|
#endif
|
||||||
|
static bool ssh2_userauth_ki_setup_prompts(
|
||||||
|
struct ssh2_userauth_state *s, BinarySource *src);
|
||||||
|
static bool ssh2_userauth_ki_run_prompts(struct ssh2_userauth_state *s);
|
||||||
|
static void ssh2_userauth_ki_write_responses(
|
||||||
|
struct ssh2_userauth_state *s, BinarySink *bs);
|
||||||
|
|
||||||
static const PacketProtocolLayerVtable ssh2_userauth_vtable = {
|
static const PacketProtocolLayerVtable ssh2_userauth_vtable = {
|
||||||
.free = ssh2_userauth_free,
|
.free = ssh2_userauth_free,
|
||||||
@ -1362,126 +1367,11 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
|
|||||||
* Loop while the server continues to send INFO_REQUESTs.
|
* Loop while the server continues to send INFO_REQUESTs.
|
||||||
*/
|
*/
|
||||||
while (pktin->type == SSH2_MSG_USERAUTH_INFO_REQUEST) {
|
while (pktin->type == SSH2_MSG_USERAUTH_INFO_REQUEST) {
|
||||||
ptrlen name, inst;
|
if (!ssh2_userauth_ki_setup_prompts(
|
||||||
strbuf *sb;
|
s, BinarySource_UPCAST(pktin)))
|
||||||
|
return;
|
||||||
|
crMaybeWaitUntilV(ssh2_userauth_ki_run_prompts(s));
|
||||||
|
|
||||||
/*
|
|
||||||
* We've got a fresh USERAUTH_INFO_REQUEST.
|
|
||||||
* Get the preamble and start building a prompt.
|
|
||||||
*/
|
|
||||||
name = get_string(pktin);
|
|
||||||
inst = get_string(pktin);
|
|
||||||
get_string(pktin); /* skip language tag */
|
|
||||||
s->cur_prompt = ssh_ppl_new_prompts(&s->ppl);
|
|
||||||
s->cur_prompt->to_server = true;
|
|
||||||
s->cur_prompt->from_server = true;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get any prompt(s) from the packet.
|
|
||||||
*/
|
|
||||||
s->num_prompts = get_uint32(pktin);
|
|
||||||
for (uint32_t i = 0; i < s->num_prompts; i++) {
|
|
||||||
s->is_trivial_auth = false;
|
|
||||||
ptrlen prompt = get_string(pktin);
|
|
||||||
bool echo = get_bool(pktin);
|
|
||||||
|
|
||||||
if (get_err(pktin)) {
|
|
||||||
ssh_proto_error(
|
|
||||||
s->ppl.ssh, "Server sent truncated "
|
|
||||||
"SSH_MSG_USERAUTH_INFO_REQUEST packet");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sb = strbuf_new();
|
|
||||||
if (!prompt.len) {
|
|
||||||
put_datapl(sb, PTRLEN_LITERAL(
|
|
||||||
"<server failed to send prompt>: "));
|
|
||||||
} else if (s->ki_scc) {
|
|
||||||
stripctrl_retarget(
|
|
||||||
s->ki_scc, BinarySink_UPCAST(sb));
|
|
||||||
put_datapl(s->ki_scc, prompt);
|
|
||||||
stripctrl_retarget(s->ki_scc, NULL);
|
|
||||||
} else {
|
|
||||||
put_datapl(sb, prompt);
|
|
||||||
}
|
|
||||||
add_prompt(s->cur_prompt, strbuf_to_str(sb), echo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Make the header strings. This includes the
|
|
||||||
* 'name' (optional dialog-box title) and
|
|
||||||
* 'instruction' from the server.
|
|
||||||
*
|
|
||||||
* First, display our disambiguating header line
|
|
||||||
* if this is the first time round the loop -
|
|
||||||
* _unless_ the server has sent a completely empty
|
|
||||||
* k-i packet with no prompts _or_ text, which
|
|
||||||
* apparently some do. In that situation there's
|
|
||||||
* no need to alert the user that the following
|
|
||||||
* text is server- supplied, because, well, _what_
|
|
||||||
* text?
|
|
||||||
*
|
|
||||||
* We also only do this if we got a stripctrl,
|
|
||||||
* because if we didn't, that suggests this is all
|
|
||||||
* being done via dialog boxes anyway.
|
|
||||||
*/
|
|
||||||
if (!s->ki_printed_header && s->ki_scc &&
|
|
||||||
(s->num_prompts || name.len || inst.len)) {
|
|
||||||
seat_antispoof_msg(
|
|
||||||
ppl_get_iseat(&s->ppl), "Keyboard-interactive "
|
|
||||||
"authentication prompts from server:");
|
|
||||||
s->ki_printed_header = true;
|
|
||||||
seat_set_trust_status(s->ppl.seat, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
sb = strbuf_new();
|
|
||||||
if (name.len) {
|
|
||||||
if (s->ki_scc) {
|
|
||||||
stripctrl_retarget(s->ki_scc,
|
|
||||||
BinarySink_UPCAST(sb));
|
|
||||||
put_datapl(s->ki_scc, name);
|
|
||||||
stripctrl_retarget(s->ki_scc, NULL);
|
|
||||||
} else {
|
|
||||||
put_datapl(sb, name);
|
|
||||||
}
|
|
||||||
s->cur_prompt->name_reqd = true;
|
|
||||||
} else {
|
|
||||||
put_datapl(sb, PTRLEN_LITERAL(
|
|
||||||
"SSH server authentication"));
|
|
||||||
s->cur_prompt->name_reqd = false;
|
|
||||||
}
|
|
||||||
s->cur_prompt->name = strbuf_to_str(sb);
|
|
||||||
|
|
||||||
sb = strbuf_new();
|
|
||||||
if (inst.len) {
|
|
||||||
if (s->ki_scc) {
|
|
||||||
stripctrl_retarget(s->ki_scc,
|
|
||||||
BinarySink_UPCAST(sb));
|
|
||||||
put_datapl(s->ki_scc, inst);
|
|
||||||
stripctrl_retarget(s->ki_scc, NULL);
|
|
||||||
} else {
|
|
||||||
put_datapl(sb, inst);
|
|
||||||
}
|
|
||||||
s->cur_prompt->instr_reqd = true;
|
|
||||||
} else {
|
|
||||||
s->cur_prompt->instr_reqd = false;
|
|
||||||
}
|
|
||||||
if (sb->len)
|
|
||||||
s->cur_prompt->instruction = strbuf_to_str(sb);
|
|
||||||
else
|
|
||||||
strbuf_free(sb);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Our prompts_t is fully constructed now. Get the
|
|
||||||
* user's response(s).
|
|
||||||
*/
|
|
||||||
s->spr = seat_get_userpass_input(
|
|
||||||
ppl_get_iseat(&s->ppl), s->cur_prompt);
|
|
||||||
while (s->spr.kind == SPRK_INCOMPLETE) {
|
|
||||||
crReturnV;
|
|
||||||
s->spr = seat_get_userpass_input(
|
|
||||||
ppl_get_iseat(&s->ppl), s->cur_prompt);
|
|
||||||
}
|
|
||||||
if (spr_is_abort(s->spr)) {
|
if (spr_is_abort(s->spr)) {
|
||||||
/*
|
/*
|
||||||
* Failed to get responses. Terminate.
|
* Failed to get responses. Terminate.
|
||||||
@ -1501,22 +1391,11 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
|
|||||||
*/
|
*/
|
||||||
s->pktout = ssh_bpp_new_pktout(
|
s->pktout = ssh_bpp_new_pktout(
|
||||||
s->ppl.bpp, SSH2_MSG_USERAUTH_INFO_RESPONSE);
|
s->ppl.bpp, SSH2_MSG_USERAUTH_INFO_RESPONSE);
|
||||||
put_uint32(s->pktout, s->num_prompts);
|
ssh2_userauth_ki_write_responses(
|
||||||
for (uint32_t i = 0; i < s->num_prompts; i++) {
|
s, BinarySink_UPCAST(s->pktout));
|
||||||
put_stringz(s->pktout, prompt_get_result_ref(
|
|
||||||
s->cur_prompt->prompts[i]));
|
|
||||||
}
|
|
||||||
s->pktout->minlen = 256;
|
s->pktout->minlen = 256;
|
||||||
pq_push(s->ppl.out_pq, s->pktout);
|
pq_push(s->ppl.out_pq, s->pktout);
|
||||||
|
|
||||||
/*
|
|
||||||
* Free the prompts structure from this iteration.
|
|
||||||
* If there's another, a new one will be allocated
|
|
||||||
* when we return to the top of this while loop.
|
|
||||||
*/
|
|
||||||
free_prompts(s->cur_prompt);
|
|
||||||
s->cur_prompt = NULL;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the next packet in case it's another
|
* Get the next packet in case it's another
|
||||||
* INFO_REQUEST.
|
* INFO_REQUEST.
|
||||||
@ -1815,6 +1694,134 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
|
|||||||
crFinishV;
|
crFinishV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ssh2_userauth_ki_setup_prompts(
|
||||||
|
struct ssh2_userauth_state *s, BinarySource *src)
|
||||||
|
{
|
||||||
|
ptrlen name, inst;
|
||||||
|
strbuf *sb;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We've got a fresh USERAUTH_INFO_REQUEST. Get the preamble and
|
||||||
|
* start building a prompt.
|
||||||
|
*/
|
||||||
|
name = get_string(src);
|
||||||
|
inst = get_string(src);
|
||||||
|
get_string(src); /* skip language tag */
|
||||||
|
s->cur_prompt = ssh_ppl_new_prompts(&s->ppl);
|
||||||
|
s->cur_prompt->to_server = true;
|
||||||
|
s->cur_prompt->from_server = true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get any prompt(s) from the packet.
|
||||||
|
*/
|
||||||
|
s->num_prompts = get_uint32(src);
|
||||||
|
for (uint32_t i = 0; i < s->num_prompts; i++) {
|
||||||
|
s->is_trivial_auth = false;
|
||||||
|
ptrlen prompt = get_string(src);
|
||||||
|
bool echo = get_bool(src);
|
||||||
|
|
||||||
|
if (get_err(src)) {
|
||||||
|
ssh_proto_error(s->ppl.ssh, "Server sent truncated "
|
||||||
|
"SSH_MSG_USERAUTH_INFO_REQUEST packet");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sb = strbuf_new();
|
||||||
|
if (!prompt.len) {
|
||||||
|
put_datapl(sb, PTRLEN_LITERAL("<server failed to send prompt>: "));
|
||||||
|
} else if (s->ki_scc) {
|
||||||
|
stripctrl_retarget(s->ki_scc, BinarySink_UPCAST(sb));
|
||||||
|
put_datapl(s->ki_scc, prompt);
|
||||||
|
stripctrl_retarget(s->ki_scc, NULL);
|
||||||
|
} else {
|
||||||
|
put_datapl(sb, prompt);
|
||||||
|
}
|
||||||
|
add_prompt(s->cur_prompt, strbuf_to_str(sb), echo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make the header strings. This includes the 'name' (optional
|
||||||
|
* dialog-box title) and 'instruction' from the server.
|
||||||
|
*
|
||||||
|
* First, display our disambiguating header line if this is the
|
||||||
|
* first time round the loop - _unless_ the server has sent a
|
||||||
|
* completely empty k-i packet with no prompts _or_ text, which
|
||||||
|
* apparently some do. In that situation there's no need to alert
|
||||||
|
* the user that the following text is server- supplied, because,
|
||||||
|
* well, _what_ text?
|
||||||
|
*
|
||||||
|
* We also only do this if we got a stripctrl, because if we
|
||||||
|
* didn't, that suggests this is all being done via dialog boxes
|
||||||
|
* anyway.
|
||||||
|
*/
|
||||||
|
if (!s->ki_printed_header && s->ki_scc &&
|
||||||
|
(s->num_prompts || name.len || inst.len)) {
|
||||||
|
seat_antispoof_msg(ppl_get_iseat(&s->ppl), "Keyboard-interactive "
|
||||||
|
"authentication prompts from server:");
|
||||||
|
s->ki_printed_header = true;
|
||||||
|
seat_set_trust_status(s->ppl.seat, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
sb = strbuf_new();
|
||||||
|
if (name.len) {
|
||||||
|
if (s->ki_scc) {
|
||||||
|
stripctrl_retarget(s->ki_scc, BinarySink_UPCAST(sb));
|
||||||
|
put_datapl(s->ki_scc, name);
|
||||||
|
stripctrl_retarget(s->ki_scc, NULL);
|
||||||
|
} else {
|
||||||
|
put_datapl(sb, name);
|
||||||
|
}
|
||||||
|
s->cur_prompt->name_reqd = true;
|
||||||
|
} else {
|
||||||
|
put_datapl(sb, PTRLEN_LITERAL("SSH server authentication"));
|
||||||
|
s->cur_prompt->name_reqd = false;
|
||||||
|
}
|
||||||
|
s->cur_prompt->name = strbuf_to_str(sb);
|
||||||
|
|
||||||
|
sb = strbuf_new();
|
||||||
|
if (inst.len) {
|
||||||
|
if (s->ki_scc) {
|
||||||
|
stripctrl_retarget(s->ki_scc, BinarySink_UPCAST(sb));
|
||||||
|
put_datapl(s->ki_scc, inst);
|
||||||
|
stripctrl_retarget(s->ki_scc, NULL);
|
||||||
|
} else {
|
||||||
|
put_datapl(sb, inst);
|
||||||
|
}
|
||||||
|
s->cur_prompt->instr_reqd = true;
|
||||||
|
} else {
|
||||||
|
s->cur_prompt->instr_reqd = false;
|
||||||
|
}
|
||||||
|
if (sb->len)
|
||||||
|
s->cur_prompt->instruction = strbuf_to_str(sb);
|
||||||
|
else
|
||||||
|
strbuf_free(sb);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ssh2_userauth_ki_run_prompts(struct ssh2_userauth_state *s)
|
||||||
|
{
|
||||||
|
s->spr = seat_get_userpass_input(
|
||||||
|
ppl_get_iseat(&s->ppl), s->cur_prompt);
|
||||||
|
return s->spr.kind != SPRK_INCOMPLETE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ssh2_userauth_ki_write_responses(
|
||||||
|
struct ssh2_userauth_state *s, BinarySink *bs)
|
||||||
|
{
|
||||||
|
put_uint32(bs, s->num_prompts);
|
||||||
|
for (uint32_t i = 0; i < s->num_prompts; i++)
|
||||||
|
put_stringz(bs, prompt_get_result_ref(s->cur_prompt->prompts[i]));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free the prompts structure from this iteration. If there's
|
||||||
|
* another, a new one will be allocated when we return to the top
|
||||||
|
* of this while loop.
|
||||||
|
*/
|
||||||
|
free_prompts(s->cur_prompt);
|
||||||
|
s->cur_prompt = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void ssh2_userauth_add_session_id(
|
static void ssh2_userauth_add_session_id(
|
||||||
struct ssh2_userauth_state *s, strbuf *sigdata)
|
struct ssh2_userauth_state *s, strbuf *sigdata)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user