From e955d3480bd67cef2c634c8ad011ee58e9ff7a78 Mon Sep 17 00:00:00 2001 From: jacob Date: Fri, 4 Nov 2005 14:49:22 +0000 Subject: [PATCH] Fix for `ssh2-password-expiry'. Success case tested. (Much easier since r6437, and actually works to boot.) git-svn-id: svn://svn.tartarus.org/sgt/putty@6445 cda61777-01e9-0310-a592-d414129be87e --- ssh.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 146 insertions(+), 10 deletions(-) diff --git a/ssh.c b/ssh.c index cad04570..7936fd0e 100644 --- a/ssh.c +++ b/ssh.c @@ -6490,6 +6490,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, prompts_t *cur_prompt; int num_prompts; char username[100]; + char *password; int got_username; void *publickey_blob; int publickey_bloblen; @@ -6726,13 +6727,9 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, break; } - if (pktin->type == SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ) { - /* FIXME: perhaps we should support this? */ - bombout(("PASSWD_CHANGEREQ not yet supported")); - crStopV; - } else if (pktin->type != SSH2_MSG_USERAUTH_FAILURE) { - bombout(("Strange packet received during authentication: type %d", - pktin->type)); + if (pktin->type != SSH2_MSG_USERAUTH_FAILURE) { + bombout(("Strange packet received during authentication: " + "type %d", pktin->type)); crStopV; } @@ -7277,6 +7274,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, * Plain old password authentication. */ int ret; /* not live over crReturn */ + int changereq_first_time; /* not live over crReturn */ ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK; ssh->pkt_ctx |= SSH2_PKTCTX_PASSWORD; @@ -7306,6 +7304,12 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, TRUE); crStopV; } + /* + * Squirrel away the password. (We may need it later if + * asked to change it.) + */ + s->password = dupstr(s->cur_prompt->prompts[0]->result); + free_prompts(s->cur_prompt); /* * Send the password packet. @@ -7326,14 +7330,146 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, ssh2_pkt_addstring(s->pktout, "password"); ssh2_pkt_addbool(s->pktout, FALSE); dont_log_password(ssh, s->pktout, PKTLOG_BLANK); - ssh2_pkt_addstring(s->pktout, - s->cur_prompt->prompts[0]->result); - free_prompts(s->cur_prompt); + ssh2_pkt_addstring(s->pktout, s->password); end_log_omission(ssh, s->pktout); ssh2_pkt_send(ssh, s->pktout); logevent("Sent password"); s->type = AUTH_TYPE_PASSWORD; + /* + * Wait for next packet, in case it's a password change + * request. + */ + crWaitUntilV(pktin); + changereq_first_time = TRUE; + + while (pktin->type == SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ) { + + /* + * We're being asked for a new password + * (perhaps not for the first time). + * Loop until the server accepts it. + */ + + int got_new = FALSE; /* not live over crReturn */ + char *prompt; /* not live over crReturn */ + int prompt_len; /* not live over crReturn */ + + { + char *msg; + if (changereq_first_time) + msg = "Server requested password change"; + else + msg = "Server rejected new password"; + logevent(msg); + c_write_str(ssh, msg); + c_write_str(ssh, "\r\n"); + } + + ssh_pkt_getstring(pktin, &prompt, &prompt_len); + + s->cur_prompt = new_prompts(ssh->frontend); + s->cur_prompt->to_server = TRUE; + s->cur_prompt->name = dupstr("New SSH password"); + s->cur_prompt->instruction = + dupprintf("%.*s", prompt_len, prompt); + s->cur_prompt->instr_reqd = TRUE; + add_prompt(s->cur_prompt, dupstr("Enter new password: "), + FALSE, SSH_MAX_PASSWORD_LEN); + add_prompt(s->cur_prompt, dupstr("Confirm new password: "), + FALSE, SSH_MAX_PASSWORD_LEN); + + /* + * Loop until the user manages to enter the same + * password twice. + */ + while (!got_new) { + + ret = get_userpass_input(s->cur_prompt, NULL, 0); + while (ret < 0) { + ssh->send_ok = 1; + crWaitUntilV(!pktin); + ret = get_userpass_input(s->cur_prompt, in, inlen); + ssh->send_ok = 0; + } + if (!ret) { + /* + * Failed to get responses. Terminate. + */ + /* burn the evidence */ + free_prompts(s->cur_prompt); + memset(s->password, 0, strlen(s->password)); + sfree(s->password); + ssh_disconnect(ssh, NULL, "Unable to authenticate", + SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER, + TRUE); + crStopV; + } + + /* + * Check the two passwords match. + */ + got_new = (strcmp(s->cur_prompt->prompts[0]->result, + s->cur_prompt->prompts[1]->result) + == 0); + if (!got_new) + /* They don't. Silly user. */ + c_write_str(ssh, "Passwords do not match\r\n"); + + } + + /* + * Send the new password (along with the old one). + * (see above for padding rationale) + */ + s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); + s->pktout->forcepad = 256; + ssh2_pkt_addstring(s->pktout, s->username); + ssh2_pkt_addstring(s->pktout, "ssh-connection"); + /* service requested */ + ssh2_pkt_addstring(s->pktout, "password"); + ssh2_pkt_addbool(s->pktout, TRUE); + dont_log_password(ssh, s->pktout, PKTLOG_BLANK); + ssh2_pkt_addstring(s->pktout, s->password); + ssh2_pkt_addstring(s->pktout, + s->cur_prompt->prompts[0]->result); + free_prompts(s->cur_prompt); + end_log_omission(ssh, s->pktout); + ssh2_pkt_send(ssh, s->pktout); + logevent("Sent new password"); + + /* + * Now see what the server has to say about it. + * (If it's CHANGEREQ again, it's not happy with the + * new password.) + */ + crWaitUntilV(pktin); + changereq_first_time = FALSE; + + } + + /* + * We need to reexamine the current pktin at the top + * of the loop. Either: + * - we weren't asked to change password at all, in + * which case it's a SUCCESS or FAILURE with the + * usual meaning + * - we sent a new password, and the server was + * either OK with it (SUCCESS or FAILURE w/partial + * success) or unhappy with the _old_ password + * (FAILURE w/o partial success) + * In any of these cases, we go back to the top of + * the loop and start again. + */ + s->gotit = TRUE; + + /* + * We don't need the old password any more, in any + * case. Burn the evidence. + */ + memset(s->password, 0, strlen(s->password)); + sfree(s->password); + } else { ssh_disconnect(ssh, NULL, -- 2.11.0