mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-03-22 14:39:24 -05:00
Fix culpable lack of generality in keyboard-interactive
authentication: a k-i request packet can contain any number of auth prompts (including zero!) and we must ask the user all of them and send back a packet containing the same number of responses. FreeBSD systems were sending a zero-prompts packet which was crashing us; this now appears fixed (we correctly return a zero-responses packet) but I haven't tested a multiple-prompts packet because I can't immediately think of a server that generates them. [originally from svn r1797]
This commit is contained in:
parent
73e32fb7c0
commit
949cecd569
88
ssh.c
88
ssh.c
@ -1541,6 +1541,7 @@ static int ssh2_pkt_getbool(void)
|
|||||||
static void ssh2_pkt_getstring(char **p, int *length)
|
static void ssh2_pkt_getstring(char **p, int *length)
|
||||||
{
|
{
|
||||||
*p = NULL;
|
*p = NULL;
|
||||||
|
*length = 0;
|
||||||
if (pktin.length - pktin.savedpos < 4)
|
if (pktin.length - pktin.savedpos < 4)
|
||||||
return;
|
return;
|
||||||
*length = GET_32BIT(pktin.data + pktin.savedpos);
|
*length = GET_32BIT(pktin.data + pktin.savedpos);
|
||||||
@ -4034,7 +4035,7 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
|
|||||||
static int tried_pubkey_config, tried_agent, tried_keyb_inter;
|
static int tried_pubkey_config, tried_agent, tried_keyb_inter;
|
||||||
static int kbd_inter_running;
|
static int kbd_inter_running;
|
||||||
static int we_are_in;
|
static int we_are_in;
|
||||||
static int num_prompts, echo;
|
static int num_prompts, curr_prompt, echo;
|
||||||
static char username[100];
|
static char username[100];
|
||||||
static int got_username;
|
static int got_username;
|
||||||
static char pwprompt[200];
|
static char pwprompt[200];
|
||||||
@ -4235,9 +4236,14 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
|
|||||||
if (kbd_inter_running &&
|
if (kbd_inter_running &&
|
||||||
pktin.type == SSH2_MSG_USERAUTH_INFO_REQUEST) {
|
pktin.type == SSH2_MSG_USERAUTH_INFO_REQUEST) {
|
||||||
/*
|
/*
|
||||||
* This is a further prompt in keyboard-interactive
|
* This is either a further set-of-prompts packet
|
||||||
* authentication. Do nothing.
|
* in keyboard-interactive authentication, or it's
|
||||||
|
* the same one and we came back here with `gotit'
|
||||||
|
* set. In the former case, we must reset the
|
||||||
|
* curr_prompt variable.
|
||||||
*/
|
*/
|
||||||
|
if (!gotit)
|
||||||
|
curr_prompt = 0;
|
||||||
} else if (pktin.type != SSH2_MSG_USERAUTH_FAILURE) {
|
} else if (pktin.type != SSH2_MSG_USERAUTH_FAILURE) {
|
||||||
bombout(("Strange packet received during authentication: type %d",
|
bombout(("Strange packet received during authentication: type %d",
|
||||||
pktin.type));
|
pktin.type));
|
||||||
@ -4537,6 +4543,7 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
kbd_inter_running = TRUE;
|
kbd_inter_running = TRUE;
|
||||||
|
curr_prompt = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kbd_inter_running) {
|
if (kbd_inter_running) {
|
||||||
@ -4546,28 +4553,50 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
|
|||||||
|
|
||||||
ssh_pkt_ctx |= SSH2_PKTCTX_KBDINTER;
|
ssh_pkt_ctx |= SSH2_PKTCTX_KBDINTER;
|
||||||
|
|
||||||
/* We've got packet with that "interactive" info
|
if (curr_prompt == 0) {
|
||||||
dump banners, and set its prompt as ours */
|
/*
|
||||||
{
|
* We've got a fresh USERAUTH_INFO_REQUEST.
|
||||||
char *name, *inst, *lang, *prompt;
|
* Display header data, and start going through
|
||||||
int name_len, inst_len, lang_len, prompt_len;
|
* the prompts.
|
||||||
|
*/
|
||||||
|
char *name, *inst, *lang;
|
||||||
|
int name_len, inst_len, lang_len;
|
||||||
|
|
||||||
ssh2_pkt_getstring(&name, &name_len);
|
ssh2_pkt_getstring(&name, &name_len);
|
||||||
ssh2_pkt_getstring(&inst, &inst_len);
|
ssh2_pkt_getstring(&inst, &inst_len);
|
||||||
ssh2_pkt_getstring(&lang, &lang_len);
|
ssh2_pkt_getstring(&lang, &lang_len);
|
||||||
if (name_len > 0)
|
if (name_len > 0) {
|
||||||
c_write_untrusted(name, name_len);
|
c_write_untrusted(name, name_len);
|
||||||
if (inst_len > 0)
|
c_write_str("\n");
|
||||||
|
}
|
||||||
|
if (inst_len > 0) {
|
||||||
c_write_untrusted(inst, inst_len);
|
c_write_untrusted(inst, inst_len);
|
||||||
|
c_write_str("\n");
|
||||||
|
}
|
||||||
num_prompts = ssh2_pkt_getuint32();
|
num_prompts = ssh2_pkt_getuint32();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there are prompts remaining in the packet,
|
||||||
|
* display one and get a response.
|
||||||
|
*/
|
||||||
|
if (curr_prompt < num_prompts) {
|
||||||
|
char *prompt;
|
||||||
|
int prompt_len;
|
||||||
|
|
||||||
ssh2_pkt_getstring(&prompt, &prompt_len);
|
ssh2_pkt_getstring(&prompt, &prompt_len);
|
||||||
strncpy(pwprompt, prompt, sizeof(pwprompt));
|
if (prompt_len > 0) {
|
||||||
pwprompt[prompt_len < sizeof(pwprompt) ?
|
strncpy(pwprompt, prompt, sizeof(pwprompt));
|
||||||
prompt_len : sizeof(pwprompt)-1] = '\0';
|
pwprompt[prompt_len < sizeof(pwprompt) ?
|
||||||
need_pw = TRUE;
|
prompt_len : sizeof(pwprompt)-1] = '\0';
|
||||||
|
} else {
|
||||||
|
strcpy(pwprompt,
|
||||||
|
"<server failed to send prompt>: ");
|
||||||
|
}
|
||||||
echo = ssh2_pkt_getbool();
|
echo = ssh2_pkt_getbool();
|
||||||
}
|
need_pw = TRUE;
|
||||||
|
} else
|
||||||
|
need_pw = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!method && can_passwd) {
|
if (!method && can_passwd) {
|
||||||
@ -4763,11 +4792,28 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
|
|||||||
logevent("Sent password");
|
logevent("Sent password");
|
||||||
type = AUTH_TYPE_PASSWORD;
|
type = AUTH_TYPE_PASSWORD;
|
||||||
} else if (method == AUTH_KEYBOARD_INTERACTIVE) {
|
} else if (method == AUTH_KEYBOARD_INTERACTIVE) {
|
||||||
ssh2_pkt_init(SSH2_MSG_USERAUTH_INFO_RESPONSE);
|
if (curr_prompt == 0) {
|
||||||
ssh2_pkt_adduint32(num_prompts);
|
ssh2_pkt_init(SSH2_MSG_USERAUTH_INFO_RESPONSE);
|
||||||
ssh2_pkt_addstring(password);
|
ssh2_pkt_adduint32(num_prompts);
|
||||||
memset(password, 0, sizeof(password));
|
}
|
||||||
ssh2_pkt_send();
|
if (need_pw) { /* only add pw if we just got one! */
|
||||||
|
ssh2_pkt_addstring(password);
|
||||||
|
memset(password, 0, sizeof(password));
|
||||||
|
curr_prompt++;
|
||||||
|
}
|
||||||
|
if (curr_prompt >= num_prompts) {
|
||||||
|
ssh2_pkt_send();
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* If there are prompts remaining, we set
|
||||||
|
* `gotit' so that we won't attempt to get
|
||||||
|
* another packet. Then we go back round the
|
||||||
|
* loop and will end up retrieving another
|
||||||
|
* prompt out of the existing packet. Funky or
|
||||||
|
* what?
|
||||||
|
*/
|
||||||
|
gotit = TRUE;
|
||||||
|
}
|
||||||
type = AUTH_TYPE_KEYBOARD_INTERACTIVE;
|
type = AUTH_TYPE_KEYBOARD_INTERACTIVE;
|
||||||
} else {
|
} else {
|
||||||
c_write_str
|
c_write_str
|
||||||
|
Loading…
x
Reference in New Issue
Block a user