X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/7b5753240c81b4f27adc8518cc4b31bf58f67fec..c6daaa1a4842b06f4eb0f7fef5f969d12b5020ce:/ssh.c diff --git a/ssh.c b/ssh.c index 71388a36..ba3dfad6 100644 --- a/ssh.c +++ b/ssh.c @@ -3222,7 +3222,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, while (pktin->type == SSH1_SMSG_FAILURE) { s->pwpkt_type = SSH1_CMSG_AUTH_PASSWORD; - if (agent_exists() && !s->tried_agent) { + if (ssh->cfg.tryagent && agent_exists() && !s->tried_agent) { /* * Attempt RSA authentication using Pageant. */ @@ -3256,13 +3256,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, s->p += 4; logeventf(ssh, "Pageant has %d SSH-1 keys", s->nkeys); for (s->keyi = 0; s->keyi < s->nkeys; s->keyi++) { - logeventf(ssh, "Trying Pageant key #%d", s->keyi); - if (s->publickey_blob && - !memcmp(s->p, s->publickey_blob, - s->publickey_bloblen)) { - logevent("This key matches configured key file"); - s->tried_publickey = 1; - } + unsigned char *pkblob = s->p; s->p += 4; { int n, ok = FALSE; @@ -3295,6 +3289,17 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, break; } } + if (s->publickey_blob) { + if (!memcmp(pkblob, s->publickey_blob, + s->publickey_bloblen)) { + logeventf(ssh, "Pageant key #%d matches " + "configured key file", s->keyi); + s->tried_publickey = 1; + } else + /* Skip non-configured key */ + continue; + } + logeventf(ssh, "Trying Pageant key #%d", s->keyi); send_packet(ssh, SSH1_CMSG_AUTH_RSA, PKT_BIGNUM, s->key.modulus, PKT_END); crWaitUntil(pktin); @@ -3385,6 +3390,8 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, break; } sfree(s->response); + if (s->publickey_blob && !s->tried_publickey) + logevent("Configured key file not in Pageant"); } if (s->authed) break; @@ -5512,7 +5519,8 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, ssh->kex->groupname); } - logevent("Doing Diffie-Hellman key exchange"); + logeventf(ssh, "Doing Diffie-Hellman key exchange with hash %s", + ssh->kex->hash->text_name); /* * Now generate and send e for Diffie-Hellman. */ @@ -6485,7 +6493,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, } type; int done_service_req; int gotit, need_pw, can_pubkey, can_passwd, can_keyb_inter; - int tried_pubkey_config, tried_agent; + int tried_pubkey_config, done_agent; int kbd_inter_refused; int we_are_in; prompts_t *cur_prompt; @@ -6498,10 +6506,10 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int publickey_encrypted; char *publickey_algorithm; char *publickey_comment; - unsigned char request[5], *response, *p; - int responselen; + unsigned char agent_request[5], *agent_response, *agentp; + int agent_responselen; + unsigned char *pkblob_in_agent; int keyi, nkeys; - int authed; char *pkblob, *alg, *commentp; int pklen, alglen, commentlen; int siglen, retlen, len; @@ -6543,6 +6551,12 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, } } + /* Arrange to be able to deal with any BANNERs that come in. + * (We do this now as packets may come in during the next bit.) */ + bufchain_init(&ssh->banner); + ssh->packet_dispatch[SSH2_MSG_USERAUTH_BANNER] = + ssh2_msg_userauth_banner; + /* * Misc one-time setup for authentication. */ @@ -6593,6 +6607,68 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, } } + /* + * Find out about any keys Pageant has (but if there's a + * public key configured, filter out all others). + */ + s->nkeys = 0; + s->agent_response = NULL; + s->pkblob_in_agent = NULL; + if (ssh->cfg.tryagent && agent_exists()) { + + void *r; + + logevent("Pageant is running. Requesting keys."); + + /* Request the keys held by the agent. */ + PUT_32BIT(s->agent_request, 1); + s->agent_request[4] = SSH2_AGENTC_REQUEST_IDENTITIES; + if (!agent_query(s->agent_request, 5, &r, &s->agent_responselen, + ssh_agent_callback, ssh)) { + do { + crReturnV; + if (pktin) { + bombout(("Unexpected data from server while" + " waiting for agent response")); + crStopV; + } + } while (pktin || inlen > 0); + r = ssh->agent_response; + s->agent_responselen = ssh->agent_response_len; + } + s->agent_response = (unsigned char *) r; + if (s->agent_response && s->agent_responselen >= 5 && + s->agent_response[4] == SSH2_AGENT_IDENTITIES_ANSWER) { + int keyi; + unsigned char *p; + p = s->agent_response + 5; + s->nkeys = GET_32BIT(p); + p += 4; + logeventf(ssh, "Pageant has %d SSH-2 keys", s->nkeys); + if (s->publickey_blob) { + /* See if configured key is in agent. */ + for (keyi = 0; keyi < s->nkeys; keyi++) { + s->pklen = GET_32BIT(p); + if (s->pklen == s->publickey_bloblen && + !memcmp(p+4, s->publickey_blob, + s->publickey_bloblen)) { + logeventf(ssh, "Pageant key #%d matches " + "configured key file", keyi); + s->keyi = keyi; + s->pkblob_in_agent = p; + break; + } + p += 4 + s->pklen; + p += GET_32BIT(p) + 4; /* comment */ + } + if (!s->pkblob_in_agent) { + logevent("Configured key file not in Pageant"); + s->nkeys = 0; + } + } + } + } + } /* @@ -6621,9 +6697,6 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, */ s->username[0] = '\0'; s->got_username = FALSE; - bufchain_init(&ssh->banner); - ssh->packet_dispatch[SSH2_MSG_USERAUTH_BANNER] = - ssh2_msg_userauth_banner; while (!s->we_are_in) { /* * Get a username. @@ -6689,9 +6762,19 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, s->we_are_in = FALSE; s->tried_pubkey_config = FALSE; - s->tried_agent = FALSE; s->kbd_inter_refused = FALSE; + /* Reset agent request state. */ + s->done_agent = FALSE; + if (s->agent_response) { + if (s->pkblob_in_agent) { + s->agentp = s->pkblob_in_agent; + } else { + s->agentp = s->agent_response + 5 + 4; + s->keyi = 0; + } + } + while (1) { /* * Wait for the result of the last authentication request. @@ -6803,172 +6886,153 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK; - if (s->can_pubkey && agent_exists() && !s->tried_agent) { + if (s->can_pubkey && !s->done_agent && s->nkeys) { /* - * Attempt public-key authentication using Pageant. + * Attempt public-key authentication using a key from Pageant. */ - void *r; - s->authed = FALSE; ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK; ssh->pkt_ctx |= SSH2_PKTCTX_PUBLICKEY; - s->tried_agent = TRUE; + logeventf(ssh, "Trying Pageant key #%d", s->keyi); + + /* Unpack key from agent response */ + s->pklen = GET_32BIT(s->agentp); + s->agentp += 4; + s->pkblob = (char *)s->agentp; + s->agentp += s->pklen; + s->alglen = GET_32BIT(s->pkblob); + s->alg = s->pkblob + 4; + s->commentlen = GET_32BIT(s->agentp); + s->agentp += 4; + s->commentp = (char *)s->agentp; + s->agentp += s->commentlen; + /* s->agentp now points at next key, if any */ + + /* See if server will accept it */ + s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); + ssh2_pkt_addstring(s->pktout, s->username); + ssh2_pkt_addstring(s->pktout, "ssh-connection"); + /* service requested */ + ssh2_pkt_addstring(s->pktout, "publickey"); + /* method */ + ssh2_pkt_addbool(s->pktout, FALSE); /* no signature included */ + ssh2_pkt_addstring_start(s->pktout); + ssh2_pkt_addstring_data(s->pktout, s->alg, s->alglen); + ssh2_pkt_addstring_start(s->pktout); + ssh2_pkt_addstring_data(s->pktout, s->pkblob, s->pklen); + ssh2_pkt_send(ssh, s->pktout); + s->type = AUTH_TYPE_PUBLICKEY_OFFER_QUIET; - logevent("Pageant is running. Requesting keys."); + crWaitUntilV(pktin); + if (pktin->type != SSH2_MSG_USERAUTH_PK_OK) { - /* Request the keys held by the agent. */ - PUT_32BIT(s->request, 1); - s->request[4] = SSH2_AGENTC_REQUEST_IDENTITIES; - if (!agent_query(s->request, 5, &r, &s->responselen, - ssh_agent_callback, ssh)) { - do { - crReturnV; - if (pktin) { - bombout(("Unexpected data from server while" - " waiting for agent response")); - crStopV; - } - } while (pktin || inlen > 0); - r = ssh->agent_response; - s->responselen = ssh->agent_response_len; - } - s->response = (unsigned char *) r; - if (s->response && s->responselen >= 5 && - s->response[4] == SSH2_AGENT_IDENTITIES_ANSWER) { - s->p = s->response + 5; - s->nkeys = GET_32BIT(s->p); - s->p += 4; - logeventf(ssh, "Pageant has %d SSH-2 keys", s->nkeys); - for (s->keyi = 0; s->keyi < s->nkeys; s->keyi++) { - void *vret; + /* Offer of key refused. */ + s->gotit = TRUE; - logeventf(ssh, "Trying Pageant key #%d", s->keyi); - s->pklen = GET_32BIT(s->p); - s->p += 4; - if (s->publickey_blob && - s->pklen == s->publickey_bloblen && - !memcmp(s->p, s->publickey_blob, - s->publickey_bloblen)) { - logevent("This key matches configured key file"); - s->tried_pubkey_config = 1; - } - s->pkblob = (char *)s->p; - s->p += s->pklen; - s->alglen = GET_32BIT(s->pkblob); - s->alg = s->pkblob + 4; - s->commentlen = GET_32BIT(s->p); - s->p += 4; - s->commentp = (char *)s->p; - s->p += s->commentlen; - s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); - ssh2_pkt_addstring(s->pktout, s->username); - ssh2_pkt_addstring(s->pktout, "ssh-connection"); /* service requested */ - ssh2_pkt_addstring(s->pktout, "publickey"); /* method */ - ssh2_pkt_addbool(s->pktout, FALSE); /* no signature included */ - ssh2_pkt_addstring_start(s->pktout); - ssh2_pkt_addstring_data(s->pktout, s->alg, s->alglen); - ssh2_pkt_addstring_start(s->pktout); - ssh2_pkt_addstring_data(s->pktout, s->pkblob, s->pklen); - ssh2_pkt_send(ssh, s->pktout); - - crWaitUntilV(pktin); - if (pktin->type != SSH2_MSG_USERAUTH_PK_OK) { - logevent("Key refused"); - continue; - } + } else { + + void *vret; - if (flags & FLAG_VERBOSE) { - c_write_str(ssh, "Authenticating with " - "public key \""); - c_write(ssh, s->commentp, s->commentlen); - c_write_str(ssh, "\" from agent\r\n"); - } + if (flags & FLAG_VERBOSE) { + c_write_str(ssh, "Authenticating with " + "public key \""); + c_write(ssh, s->commentp, s->commentlen); + c_write_str(ssh, "\" from agent\r\n"); + } - /* - * Server is willing to accept the key. - * Construct a SIGN_REQUEST. - */ - s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); - ssh2_pkt_addstring(s->pktout, s->username); - ssh2_pkt_addstring(s->pktout, "ssh-connection"); /* service requested */ - ssh2_pkt_addstring(s->pktout, "publickey"); /* method */ - ssh2_pkt_addbool(s->pktout, TRUE); - ssh2_pkt_addstring_start(s->pktout); - ssh2_pkt_addstring_data(s->pktout, s->alg, s->alglen); - ssh2_pkt_addstring_start(s->pktout); - ssh2_pkt_addstring_data(s->pktout, s->pkblob, s->pklen); - - s->siglen = s->pktout->length - 5 + 4 + - ssh->v2_session_id_len; - if (ssh->remote_bugs & BUG_SSH2_PK_SESSIONID) - s->siglen -= 4; - s->len = 1; /* message type */ - s->len += 4 + s->pklen; /* key blob */ - s->len += 4 + s->siglen; /* data to sign */ - s->len += 4; /* flags */ - s->agentreq = snewn(4 + s->len, char); - PUT_32BIT(s->agentreq, s->len); - s->q = s->agentreq + 4; - *s->q++ = SSH2_AGENTC_SIGN_REQUEST; - PUT_32BIT(s->q, s->pklen); - s->q += 4; - memcpy(s->q, s->pkblob, s->pklen); - s->q += s->pklen; - PUT_32BIT(s->q, s->siglen); + /* + * Server is willing to accept the key. + * Construct a SIGN_REQUEST. + */ + s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); + ssh2_pkt_addstring(s->pktout, s->username); + ssh2_pkt_addstring(s->pktout, "ssh-connection"); + /* service requested */ + ssh2_pkt_addstring(s->pktout, "publickey"); + /* method */ + ssh2_pkt_addbool(s->pktout, TRUE); /* signature included */ + ssh2_pkt_addstring_start(s->pktout); + ssh2_pkt_addstring_data(s->pktout, s->alg, s->alglen); + ssh2_pkt_addstring_start(s->pktout); + ssh2_pkt_addstring_data(s->pktout, s->pkblob, s->pklen); + + /* Ask agent for signature. */ + s->siglen = s->pktout->length - 5 + 4 + + ssh->v2_session_id_len; + if (ssh->remote_bugs & BUG_SSH2_PK_SESSIONID) + s->siglen -= 4; + s->len = 1; /* message type */ + s->len += 4 + s->pklen; /* key blob */ + s->len += 4 + s->siglen; /* data to sign */ + s->len += 4; /* flags */ + s->agentreq = snewn(4 + s->len, char); + PUT_32BIT(s->agentreq, s->len); + s->q = s->agentreq + 4; + *s->q++ = SSH2_AGENTC_SIGN_REQUEST; + PUT_32BIT(s->q, s->pklen); + s->q += 4; + memcpy(s->q, s->pkblob, s->pklen); + s->q += s->pklen; + PUT_32BIT(s->q, s->siglen); + s->q += 4; + /* Now the data to be signed... */ + if (!(ssh->remote_bugs & BUG_SSH2_PK_SESSIONID)) { + PUT_32BIT(s->q, ssh->v2_session_id_len); s->q += 4; - /* Now the data to be signed... */ - if (!(ssh->remote_bugs & BUG_SSH2_PK_SESSIONID)) { - PUT_32BIT(s->q, ssh->v2_session_id_len); - s->q += 4; - } - memcpy(s->q, ssh->v2_session_id, - ssh->v2_session_id_len); - s->q += ssh->v2_session_id_len; - memcpy(s->q, s->pktout->data + 5, - s->pktout->length - 5); - s->q += s->pktout->length - 5; - /* And finally the (zero) flags word. */ - PUT_32BIT(s->q, 0); - if (!agent_query(s->agentreq, s->len + 4, - &vret, &s->retlen, - ssh_agent_callback, ssh)) { - do { - crReturnV; - if (pktin) { - bombout(("Unexpected data from server" - " while waiting for agent" - " response")); - crStopV; - } - } while (pktin || inlen > 0); - vret = ssh->agent_response; - s->retlen = ssh->agent_response_len; - } - s->ret = vret; - sfree(s->agentreq); - if (s->ret) { - if (s->ret[4] == SSH2_AGENT_SIGN_RESPONSE) { - logevent("Sending Pageant's response"); - ssh2_add_sigblob(ssh, s->pktout, - s->pkblob, s->pklen, - s->ret + 9, - GET_32BIT(s->ret + 5)); - ssh2_pkt_send(ssh, s->pktout); - s->authed = TRUE; - break; - } else { - logevent - ("Pageant failed to answer challenge"); - sfree(s->ret); + } + memcpy(s->q, ssh->v2_session_id, + ssh->v2_session_id_len); + s->q += ssh->v2_session_id_len; + memcpy(s->q, s->pktout->data + 5, + s->pktout->length - 5); + s->q += s->pktout->length - 5; + /* And finally the (zero) flags word. */ + PUT_32BIT(s->q, 0); + if (!agent_query(s->agentreq, s->len + 4, + &vret, &s->retlen, + ssh_agent_callback, ssh)) { + do { + crReturnV; + if (pktin) { + bombout(("Unexpected data from server" + " while waiting for agent" + " response")); + crStopV; } + } while (pktin || inlen > 0); + vret = ssh->agent_response; + s->retlen = ssh->agent_response_len; + } + s->ret = vret; + sfree(s->agentreq); + if (s->ret) { + if (s->ret[4] == SSH2_AGENT_SIGN_RESPONSE) { + logevent("Sending Pageant's response"); + ssh2_add_sigblob(ssh, s->pktout, + s->pkblob, s->pklen, + s->ret + 9, + GET_32BIT(s->ret + 5)); + ssh2_pkt_send(ssh, s->pktout); + s->type = AUTH_TYPE_PUBLICKEY; + } else { + /* FIXME: less drastic response */ + bombout(("Pageant failed to answer challenge")); + crStopV; } } - if (s->authed) - continue; } - sfree(s->response); + + /* Do we have any keys left to try? */ + if (s->pkblob_in_agent) { + s->done_agent = TRUE; + s->tried_pubkey_config = TRUE; + } else { + s->keyi++; + if (s->keyi >= s->nkeys) + s->done_agent = TRUE; + } } else if (s->can_pubkey && s->publickey_blob && !s->tried_pubkey_config) { @@ -7153,9 +7217,6 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, /* * Keyboard-interactive authentication. */ - char *name, *inst, *lang; - int name_len, inst_len, lang_len; - int i; s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE; @@ -7175,7 +7236,9 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, crWaitUntilV(pktin); if (pktin->type != SSH2_MSG_USERAUTH_INFO_REQUEST) { /* Server is not willing to do keyboard-interactive - * at all. Give up on it entirely. */ + * at all (or, bizarrely but legally, accepts the + * user without actually issuing any prompts). + * Give up on it entirely. */ s->gotit = TRUE; if (pktin->type == SSH2_MSG_USERAUTH_FAILURE) logevent("Keyboard-interactive authentication refused"); @@ -7185,89 +7248,113 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, } /* - * We've got a fresh USERAUTH_INFO_REQUEST. - * Get the preamble and start building a prompt. + * Loop while the server continues to send INFO_REQUESTs. */ - ssh_pkt_getstring(pktin, &name, &name_len); - ssh_pkt_getstring(pktin, &inst, &inst_len); - ssh_pkt_getstring(pktin, &lang, &lang_len); - s->cur_prompt = new_prompts(ssh->frontend); - s->cur_prompt->to_server = TRUE; - if (name_len) { - /* FIXME: better prefix to distinguish from - * local prompts? */ - s->cur_prompt->name = dupprintf("SSH server: %.*s", - name_len, name); - s->cur_prompt->name_reqd = TRUE; - } else { - s->cur_prompt->name = dupstr("SSH server authentication"); - s->cur_prompt->name_reqd = FALSE; - } - s->cur_prompt->instruction = - dupprintf("Using keyboard-interactive authentication.%s%.*s", - inst_len ? "\n" : "", inst_len, inst); - s->cur_prompt->instr_reqd = TRUE; + while (pktin->type == SSH2_MSG_USERAUTH_INFO_REQUEST) { - /* - * Get the prompts from the packet. - */ - s->num_prompts = ssh_pkt_getuint32(pktin); - for (i = 0; i < s->num_prompts; i++) { - char *prompt; - int prompt_len; - int echo; - static char noprompt[] = - ": "; + char *name, *inst, *lang; + int name_len, inst_len, lang_len; + int i; - ssh_pkt_getstring(pktin, &prompt, &prompt_len); - echo = ssh2_pkt_getbool(pktin); - if (!prompt_len) { - prompt = noprompt; - prompt_len = lenof(noprompt)-1; + /* + * We've got a fresh USERAUTH_INFO_REQUEST. + * Get the preamble and start building a prompt. + */ + ssh_pkt_getstring(pktin, &name, &name_len); + ssh_pkt_getstring(pktin, &inst, &inst_len); + ssh_pkt_getstring(pktin, &lang, &lang_len); + s->cur_prompt = new_prompts(ssh->frontend); + s->cur_prompt->to_server = TRUE; + if (name_len) { + /* FIXME: better prefix to distinguish from + * local prompts? */ + s->cur_prompt->name = + dupprintf("SSH server: %.*s", name_len, name); + s->cur_prompt->name_reqd = TRUE; + } else { + s->cur_prompt->name = + dupstr("SSH server authentication"); + s->cur_prompt->name_reqd = FALSE; } - add_prompt(s->cur_prompt, - dupprintf("%.*s", prompt_len, prompt), - echo, SSH_MAX_PASSWORD_LEN); - } + /* FIXME: ugly to print "Using..." in prompt _every_ + * time round. Can this be done more subtly? */ + s->cur_prompt->instruction = + dupprintf("Using keyboard-interactive authentication.%s%.*s", + inst_len ? "\n" : "", inst_len, inst); + s->cur_prompt->instr_reqd = TRUE; - /* - * Get the user's responses. - */ - if (s->num_prompts) { - int ret; /* not live over crReturn */ - 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; + /* + * Get the prompts from the packet. + */ + s->num_prompts = ssh_pkt_getuint32(pktin); + for (i = 0; i < s->num_prompts; i++) { + char *prompt; + int prompt_len; + int echo; + static char noprompt[] = + ": "; + + ssh_pkt_getstring(pktin, &prompt, &prompt_len); + echo = ssh2_pkt_getbool(pktin); + if (!prompt_len) { + prompt = noprompt; + prompt_len = lenof(noprompt)-1; + } + add_prompt(s->cur_prompt, + dupprintf("%.*s", prompt_len, prompt), + echo, SSH_MAX_PASSWORD_LEN); } - if (!ret) { - /* - * Failed to get responses. Terminate. - */ - free_prompts(s->cur_prompt); - ssh_disconnect(ssh, NULL, "Unable to authenticate", - SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER, - TRUE); - crStopV; + + /* + * Get the user's responses. + */ + if (s->num_prompts) { + int ret; /* not live over crReturn */ + 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. + */ + free_prompts(s->cur_prompt); + ssh_disconnect(ssh, NULL, "Unable to authenticate", + SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER, + TRUE); + crStopV; + } + } + + /* + * Send the responses to the server. + */ + s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_INFO_RESPONSE); + s->pktout->forcepad = 256; + ssh2_pkt_adduint32(s->pktout, s->num_prompts); + for (i=0; i < s->num_prompts; i++) { + dont_log_password(ssh, s->pktout, PKTLOG_BLANK); + ssh2_pkt_addstring(s->pktout, + s->cur_prompt->prompts[i]->result); + end_log_omission(ssh, s->pktout); } + ssh2_pkt_send(ssh, s->pktout); + + /* + * Get the next packet in case it's another + * INFO_REQUEST. + */ + crWaitUntilV(pktin); + } /* - * Send the responses to the server. + * We should have SUCCESS or FAILURE now. */ - s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_INFO_RESPONSE); - s->pktout->forcepad = 256; - ssh2_pkt_adduint32(s->pktout, s->num_prompts); - for (i=0; i < s->num_prompts; i++) { - dont_log_password(ssh, s->pktout, PKTLOG_BLANK); - ssh2_pkt_addstring(s->pktout, - s->cur_prompt->prompts[i]->result); - end_log_omission(ssh, s->pktout); - } - ssh2_pkt_send(ssh, s->pktout); - s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE; + s->gotit = TRUE; } else if (s->can_passwd) { @@ -7490,6 +7577,8 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, sfree(s->publickey_blob); sfree(s->publickey_comment); } + if (s->agent_response) + sfree(s->agent_response); /* * Now the connection protocol has started, one way or another. @@ -8602,8 +8691,11 @@ void ssh_send_port_open(void *channel, char *hostname, int port, char *org) * too much hassle to keep track, and partly I'm not * convinced the server should be told details like that * about my local network configuration. + * The "originator IP address" is syntactically a numeric + * IP address, and some servers (e.g., Tectia) get upset + * if it doesn't match this syntax. */ - ssh2_pkt_addstring(pktout, "client-side-connection"); + ssh2_pkt_addstring(pktout, "0.0.0.0"); ssh2_pkt_adduint32(pktout, 0); ssh2_pkt_send(ssh, pktout); }