- static int pwpkt_type;
- /*
- * Show password prompt, having first obtained it via a TIS
- * or CryptoCard exchange if we're doing TIS or CryptoCard
- * authentication.
- */
- pwpkt_type = SSH1_CMSG_AUTH_PASSWORD;
- if (agent_exists()) {
- /*
- * Attempt RSA authentication using Pageant.
- */
- static unsigned char request[5], *response, *p;
- static int responselen;
- static int i, nkeys;
- static int authed = FALSE;
- void *r;
-
- logevent("Pageant is running. Requesting keys.");
-
- /* Request the keys held by the agent. */
- PUT_32BIT(request, 1);
- request[4] = SSH1_AGENTC_REQUEST_RSA_IDENTITIES;
- agent_query(request, 5, &r, &responselen);
- response = (unsigned char *)r;
- if (response && responselen >= 5 &&
- response[4] == SSH1_AGENT_RSA_IDENTITIES_ANSWER) {
- p = response + 5;
- nkeys = GET_32BIT(p); p += 4;
- { char buf[64]; sprintf(buf, "Pageant has %d SSH1 keys", nkeys);
- logevent(buf); }
- for (i = 0; i < nkeys; i++) {
- static struct RSAKey key;
- static Bignum challenge;
- static char *commentp;
- static int commentlen;
-
- { char buf[64]; sprintf(buf, "Trying Pageant key #%d", i);
- logevent(buf); }
- p += 4;
- p += ssh1_read_bignum(p, &key.exponent);
- p += ssh1_read_bignum(p, &key.modulus);
- commentlen = GET_32BIT(p); p += 4;
- commentp = p; p += commentlen;
- send_packet(SSH1_CMSG_AUTH_RSA,
- PKT_BIGNUM, key.modulus, PKT_END);
- crWaitUntil(ispkt);
- if (pktin.type != SSH1_SMSG_AUTH_RSA_CHALLENGE) {
- logevent("Key refused");
- continue;
- }
- logevent("Received RSA challenge");
- ssh1_read_bignum(pktin.body, &challenge);
- {
- char *agentreq, *q, *ret;
- int len, retlen;
- len = 1 + 4; /* message type, bit count */
- len += ssh1_bignum_length(key.exponent);
- len += ssh1_bignum_length(key.modulus);
- len += ssh1_bignum_length(challenge);
- len += 16; /* session id */
- len += 4; /* response format */
- agentreq = smalloc(4 + len);
- PUT_32BIT(agentreq, len);
- q = agentreq + 4;
- *q++ = SSH1_AGENTC_RSA_CHALLENGE;
- PUT_32BIT(q, ssh1_bignum_bitcount(key.modulus));
- q += 4;
- q += ssh1_write_bignum(q, key.exponent);
- q += ssh1_write_bignum(q, key.modulus);
- q += ssh1_write_bignum(q, challenge);
- memcpy(q, session_id, 16); q += 16;
- PUT_32BIT(q, 1); /* response format */
- agent_query(agentreq, len+4, &ret, &retlen);
- sfree(agentreq);
- if (ret) {
- if (ret[4] == SSH1_AGENT_RSA_RESPONSE) {
- logevent("Sending Pageant's response");
- send_packet(SSH1_CMSG_AUTH_RSA_RESPONSE,
- PKT_DATA, ret+5, 16, PKT_END);
- sfree(ret);
- crWaitUntil(ispkt);
- if (pktin.type == SSH1_SMSG_SUCCESS) {
- logevent("Pageant's response accepted");
- if (flags & FLAG_VERBOSE) {
- c_write_str("Authenticated using RSA key \"");
- c_write(commentp, commentlen);
- c_write_str("\" from agent\r\n");
- }
- authed = TRUE;
- } else
- logevent("Pageant's response not accepted");
- } else {
- logevent("Pageant failed to answer challenge");
- sfree(ret);
- }
- } else {
- logevent("No reply received from Pageant");
- }
- }
- freebn(key.exponent);
- freebn(key.modulus);
- freebn(challenge);
- if (authed)
- break;
- }
- }
- if (authed)
- break;
- }
- if (*cfg.keyfile && !tried_publickey)
- pwpkt_type = SSH1_CMSG_AUTH_RSA;
-
- if (pktin.type == SSH1_SMSG_FAILURE &&
- cfg.try_tis_auth &&
- (supported_auths_mask & (1<<SSH1_AUTH_TIS))) {
- pwpkt_type = SSH1_CMSG_AUTH_TIS_RESPONSE;
- logevent("Requested TIS authentication");
- send_packet(SSH1_CMSG_AUTH_TIS, PKT_END);
- crWaitUntil(ispkt);
- if (pktin.type != SSH1_SMSG_AUTH_TIS_CHALLENGE) {
- logevent("TIS authentication declined");
- if (flags & FLAG_INTERACTIVE)
- c_write_str("TIS authentication refused.\r\n");
- } else {
- int challengelen = ((pktin.body[0] << 24) |
- (pktin.body[1] << 16) |
- (pktin.body[2] << 8) |
- (pktin.body[3]));
- logevent("Received TIS challenge");
- if (challengelen > sizeof(prompt)-1)
- challengelen = sizeof(prompt)-1; /* prevent overrun */
- memcpy(prompt, pktin.body+4, challengelen);
- prompt[challengelen] = '\0';
- }
- }
- if (pktin.type == SSH1_SMSG_FAILURE &&
- cfg.try_tis_auth &&
- (supported_auths_mask & (1<<SSH1_AUTH_CCARD))) {
- pwpkt_type = SSH1_CMSG_AUTH_CCARD_RESPONSE;
- logevent("Requested CryptoCard authentication");
- send_packet(SSH1_CMSG_AUTH_CCARD, PKT_END);
- crWaitUntil(ispkt);
- if (pktin.type != SSH1_SMSG_AUTH_CCARD_CHALLENGE) {
- logevent("CryptoCard authentication declined");
- c_write_str("CryptoCard authentication refused.\r\n");
- } else {
- int challengelen = ((pktin.body[0] << 24) |
- (pktin.body[1] << 16) |
- (pktin.body[2] << 8) |
- (pktin.body[3]));
- logevent("Received CryptoCard challenge");
- if (challengelen > sizeof(prompt)-1)
- challengelen = sizeof(prompt)-1; /* prevent overrun */
- memcpy(prompt, pktin.body+4, challengelen);
- strncpy(prompt + challengelen, "\r\nResponse : ",
- sizeof(prompt)-challengelen);
- prompt[sizeof(prompt)-1] = '\0';
- }
- }
- if (pwpkt_type == SSH1_CMSG_AUTH_PASSWORD) {
- sprintf(prompt, "%.90s@%.90s's password: ",
- username, savedhost);
- }
- if (pwpkt_type == SSH1_CMSG_AUTH_RSA) {
- char *comment = NULL;
- if (flags & FLAG_VERBOSE)
- c_write_str("Trying public key authentication.\r\n");
- if (!rsakey_encrypted(cfg.keyfile, &comment)) {
- if (flags & FLAG_VERBOSE)
- c_write_str("No passphrase required.\r\n");
- goto tryauth;
- }
- sprintf(prompt, "Passphrase for key \"%.100s\": ", comment);
- sfree(comment);
- }
-
- if (ssh_get_line) {
- if (!ssh_get_line(prompt, password, sizeof(password), TRUE)) {
- /*
- * get_line failed to get a password (for example
- * because one was supplied on the command line
- * which has already failed to work). Terminate.
- */
- logevent("No more passwords to try");
- ssh_state = SSH_STATE_CLOSED;
- crReturn(1);
- }
- } else {
- c_write_str(prompt);
- pos = 0;
- ssh_send_ok = 1;
- while (pos >= 0) {
- crWaitUntil(!ispkt);
- while (inlen--) switch (c = *in++) {
- case 10: case 13:
- password[pos] = 0;
- pos = -1;
- break;
- case 8: case 127:
- if (pos > 0)
- pos--;
- break;
- case 21: case 27:
- pos = 0;
- break;
- case 3: case 4:
- random_save_seed();
- exit(0);
- break;
- default:
- if (((c >= ' ' && c <= '~') ||
- ((unsigned char)c >= 160)) && pos < sizeof(password))
- password[pos++] = c;
- break;
- }
- }
- c_write_str("\r\n");
- }
-
- tryauth:
- if (pwpkt_type == SSH1_CMSG_AUTH_RSA) {
- /*
- * Try public key authentication with the specified
- * key file.
- */
- static struct RSAKey pubkey;
- static Bignum challenge, response;
- static int i;
- static unsigned char buffer[32];
-
- tried_publickey = 1;
- i = loadrsakey(cfg.keyfile, &pubkey, password);
- if (i == 0) {
- c_write_str("Couldn't load public key from ");
- c_write_str(cfg.keyfile);
- c_write_str(".\r\n");
- continue; /* go and try password */
- }
- if (i == -1) {
- c_write_str("Wrong passphrase.\r\n");
- tried_publickey = 0;
- continue; /* try again */
- }
-
- /*
- * Send a public key attempt.
- */
- send_packet(SSH1_CMSG_AUTH_RSA,
- PKT_BIGNUM, pubkey.modulus, PKT_END);
-
- crWaitUntil(ispkt);
- if (pktin.type == SSH1_SMSG_FAILURE) {
- c_write_str("Server refused our public key.\r\n");
- continue; /* go and try password */
- }
- if (pktin.type != SSH1_SMSG_AUTH_RSA_CHALLENGE) {
- bombout(("Bizarre response to offer of public key"));
- crReturn(0);
- }
- ssh1_read_bignum(pktin.body, &challenge);
- response = rsadecrypt(challenge, &pubkey);
- freebn(pubkey.private_exponent); /* burn the evidence */
-
- for (i = 0; i < 32; i++) {
- buffer[i] = bignum_byte(response, 31-i);
- }
-
- MD5Init(&md5c);
- MD5Update(&md5c, buffer, 32);
- MD5Update(&md5c, session_id, 16);
- MD5Final(buffer, &md5c);
-
- send_packet(SSH1_CMSG_AUTH_RSA_RESPONSE,
- PKT_DATA, buffer, 16, PKT_END);
-
- crWaitUntil(ispkt);
- if (pktin.type == SSH1_SMSG_FAILURE) {
- if (flags & FLAG_VERBOSE)
- c_write_str("Failed to authenticate with our public key.\r\n");
- continue; /* go and try password */
- } else if (pktin.type != SSH1_SMSG_SUCCESS) {
- bombout(("Bizarre response to RSA authentication response"));
- crReturn(0);
- }
-
- break; /* we're through! */
- } else {
- if (pwpkt_type == SSH1_CMSG_AUTH_PASSWORD) {
- /*
- * Defence against traffic analysis: we send a
- * whole bunch of packets containing strings of
- * different lengths. One of these strings is the
- * password, in a SSH1_CMSG_AUTH_PASSWORD packet.
- * The others are all random data in
- * SSH1_MSG_IGNORE packets. This way a passive
- * listener can't tell which is the password, and
- * hence can't deduce the password length.
- *
- * Anybody with a password length greater than 16
- * bytes is going to have enough entropy in their
- * password that a listener won't find it _that_
- * much help to know how long it is. So what we'll
- * do is:
- *
- * - if password length < 16, we send 15 packets
- * containing string lengths 1 through 15
- *
- * - otherwise, we let N be the nearest multiple
- * of 8 below the password length, and send 8
- * packets containing string lengths N through
- * N+7. This won't obscure the order of
- * magnitude of the password length, but it will
- * introduce a bit of extra uncertainty.
- *
- * A few servers (the old 1.2.18 through 1.2.22)
- * can't deal with SSH1_MSG_IGNORE. For these
- * servers, we need an alternative defence. We make
- * use of the fact that the password is interpreted
- * as a C string: so we can append a NUL, then some
- * random data.
- */
- if (ssh_remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE) {
- char string[64];
- char *s;
- int len;
-
- len = strlen(password);
- if (len < sizeof(string)) {
- s = string;
- strcpy(string, password);
- len++; /* cover the zero byte */
- while (len < sizeof(string)) {
- string[len++] = (char)random_byte();
- }
- } else {
- s = password;
- }
- send_packet(pwpkt_type, PKT_INT, len,
- PKT_DATA, s, len, PKT_END);
- } else {
- int bottom, top, pwlen, i;
- char *randomstr;
-
- pwlen = strlen(password);
- if (pwlen < 16) {
- bottom = 0; /* zero length passwords are OK! :-) */
- top = 15;
- } else {
- bottom = pwlen &~ 7;
- top = bottom + 7;
- }
-
- assert(pwlen >= bottom && pwlen <= top);
-
- randomstr = smalloc(top+1);
-
- for (i = bottom; i <= top; i++) {
- if (i == pwlen)
- defer_packet(pwpkt_type, PKT_STR, password, PKT_END);
- else {
- for (j = 0; j < i; j++) {
- do {
- randomstr[j] = random_byte();
- } while (randomstr[j] == '\0');
- }
- randomstr[i] = '\0';
- defer_packet(SSH1_MSG_IGNORE,
- PKT_STR, randomstr, PKT_END);
- }
- }
- ssh_pkt_defersend();
- }
- } else {
- send_packet(pwpkt_type, PKT_STR, password, PKT_END);
- }
- }
- logevent("Sent password");
- memset(password, 0, strlen(password));
- crWaitUntil(ispkt);
- if (pktin.type == SSH1_SMSG_FAILURE) {
- if (flags & FLAG_VERBOSE)
- c_write_str("Access denied\r\n");
- logevent("Authentication refused");
- } else if (pktin.type == SSH1_MSG_DISCONNECT) {
- logevent("Received disconnect request");
- ssh_state = SSH_STATE_CLOSED;
- crReturn(1);
- } else if (pktin.type != SSH1_SMSG_SUCCESS) {
- bombout(("Strange packet received, type %d", pktin.type));
- crReturn(0);
- }
- }
-
- logevent("Authentication successful");
-
- crFinish(1);
-}
-
-void sshfwd_close(struct ssh_channel *c) {
- if (c && !c->closes) {
- if (ssh_version == 1) {
- send_packet(SSH1_MSG_CHANNEL_CLOSE, PKT_INT, c->remoteid, PKT_END);
- } else {
- ssh2_pkt_init(SSH2_MSG_CHANNEL_CLOSE);
- ssh2_pkt_adduint32(c->remoteid);
- ssh2_pkt_send();
- }
- c->closes = 1;
- if (c->type == CHAN_X11) {
- c->u.x11.s = NULL;
- logevent("X11 connection terminated");
- }
- }
-}
-
-void sshfwd_write(struct ssh_channel *c, char *buf, int len) {
- if (ssh_version == 1) {
- send_packet(SSH1_MSG_CHANNEL_DATA,
- PKT_INT, c->remoteid,
- PKT_INT, len,
- PKT_DATA, buf, len,
- PKT_END);
- } else {
- ssh2_add_channel_data(c, buf, len);
- ssh2_try_send(c);
- }
-}
-
-static void ssh1_protocol(unsigned char *in, int inlen, int ispkt) {
- crBegin;
-
- random_init();
-
- while (!do_ssh1_login(in, inlen, ispkt)) {
- crReturnV;
+ static int pwpkt_type;
+ /*
+ * Show password prompt, having first obtained it via a TIS
+ * or CryptoCard exchange if we're doing TIS or CryptoCard
+ * authentication.
+ */
+ pwpkt_type = SSH1_CMSG_AUTH_PASSWORD;
+ if (agent_exists()) {
+ /*
+ * Attempt RSA authentication using Pageant.
+ */
+ static unsigned char request[5], *response, *p;
+ static int responselen;
+ static int i, nkeys;
+ static int authed = FALSE;
+ void *r;
+
+ logevent("Pageant is running. Requesting keys.");
+
+ /* Request the keys held by the agent. */
+ PUT_32BIT(request, 1);
+ request[4] = SSH1_AGENTC_REQUEST_RSA_IDENTITIES;
+ agent_query(request, 5, &r, &responselen);
+ response = (unsigned char *) r;
+ if (response && responselen >= 5 &&
+ response[4] == SSH1_AGENT_RSA_IDENTITIES_ANSWER) {
+ p = response + 5;
+ nkeys = GET_32BIT(p);
+ p += 4;
+ {
+ char buf[64];
+ sprintf(buf, "Pageant has %d SSH1 keys", nkeys);
+ logevent(buf);
+ }
+ for (i = 0; i < nkeys; i++) {
+ static struct RSAKey key;
+ static Bignum challenge;
+ static char *commentp;
+ static int commentlen;
+
+ {
+ char buf[64];
+ sprintf(buf, "Trying Pageant key #%d", i);
+ logevent(buf);
+ }
+ p += 4;
+ p += ssh1_read_bignum(p, &key.exponent);
+ p += ssh1_read_bignum(p, &key.modulus);
+ commentlen = GET_32BIT(p);
+ p += 4;
+ commentp = p;
+ p += commentlen;
+ send_packet(SSH1_CMSG_AUTH_RSA,
+ PKT_BIGNUM, key.modulus, PKT_END);
+ crWaitUntil(ispkt);
+ if (pktin.type != SSH1_SMSG_AUTH_RSA_CHALLENGE) {
+ logevent("Key refused");
+ continue;
+ }
+ logevent("Received RSA challenge");
+ ssh1_read_bignum(pktin.body, &challenge);
+ {
+ char *agentreq, *q, *ret;
+ void *vret;
+ int len, retlen;
+ len = 1 + 4; /* message type, bit count */
+ len += ssh1_bignum_length(key.exponent);
+ len += ssh1_bignum_length(key.modulus);
+ len += ssh1_bignum_length(challenge);
+ len += 16; /* session id */
+ len += 4; /* response format */
+ agentreq = smalloc(4 + len);
+ PUT_32BIT(agentreq, len);
+ q = agentreq + 4;
+ *q++ = SSH1_AGENTC_RSA_CHALLENGE;
+ PUT_32BIT(q, bignum_bitcount(key.modulus));
+ q += 4;
+ q += ssh1_write_bignum(q, key.exponent);
+ q += ssh1_write_bignum(q, key.modulus);
+ q += ssh1_write_bignum(q, challenge);
+ memcpy(q, session_id, 16);
+ q += 16;
+ PUT_32BIT(q, 1); /* response format */
+ agent_query(agentreq, len + 4, &vret, &retlen);
+ ret = vret;
+ sfree(agentreq);
+ if (ret) {
+ if (ret[4] == SSH1_AGENT_RSA_RESPONSE) {
+ logevent("Sending Pageant's response");
+ send_packet(SSH1_CMSG_AUTH_RSA_RESPONSE,
+ PKT_DATA, ret + 5, 16,
+ PKT_END);
+ sfree(ret);
+ crWaitUntil(ispkt);
+ if (pktin.type == SSH1_SMSG_SUCCESS) {
+ logevent
+ ("Pageant's response accepted");
+ if (flags & FLAG_VERBOSE) {
+ c_write_str
+ ("Authenticated using RSA key \"");
+ c_write(commentp, commentlen);
+ c_write_str("\" from agent\r\n");
+ }
+ authed = TRUE;
+ } else
+ logevent
+ ("Pageant's response not accepted");
+ } else {
+ logevent
+ ("Pageant failed to answer challenge");
+ sfree(ret);
+ }
+ } else {
+ logevent("No reply received from Pageant");
+ }
+ }
+ freebn(key.exponent);
+ freebn(key.modulus);
+ freebn(challenge);
+ if (authed)
+ break;
+ }
+ }
+ if (authed)
+ break;
+ }
+ if (*cfg.keyfile && !tried_publickey)
+ pwpkt_type = SSH1_CMSG_AUTH_RSA;
+
+ if (pktin.type == SSH1_SMSG_FAILURE &&
+ cfg.try_tis_auth &&
+ (supported_auths_mask & (1 << SSH1_AUTH_TIS))) {
+ pwpkt_type = SSH1_CMSG_AUTH_TIS_RESPONSE;
+ logevent("Requested TIS authentication");
+ send_packet(SSH1_CMSG_AUTH_TIS, PKT_END);
+ crWaitUntil(ispkt);
+ if (pktin.type != SSH1_SMSG_AUTH_TIS_CHALLENGE) {
+ logevent("TIS authentication declined");
+ if (flags & FLAG_INTERACTIVE)
+ c_write_str("TIS authentication refused.\r\n");
+ } else {
+ int challengelen = ((pktin.body[0] << 24) |
+ (pktin.body[1] << 16) |
+ (pktin.body[2] << 8) |
+ (pktin.body[3]));
+ logevent("Received TIS challenge");
+ if (challengelen > sizeof(prompt) - 1)
+ challengelen = sizeof(prompt) - 1; /* prevent overrun */
+ memcpy(prompt, pktin.body + 4, challengelen);
+ prompt[challengelen] = '\0';
+ }
+ }
+ if (pktin.type == SSH1_SMSG_FAILURE &&
+ cfg.try_tis_auth &&
+ (supported_auths_mask & (1 << SSH1_AUTH_CCARD))) {
+ pwpkt_type = SSH1_CMSG_AUTH_CCARD_RESPONSE;
+ logevent("Requested CryptoCard authentication");
+ send_packet(SSH1_CMSG_AUTH_CCARD, PKT_END);
+ crWaitUntil(ispkt);
+ if (pktin.type != SSH1_SMSG_AUTH_CCARD_CHALLENGE) {
+ logevent("CryptoCard authentication declined");
+ c_write_str("CryptoCard authentication refused.\r\n");
+ } else {
+ int challengelen = ((pktin.body[0] << 24) |
+ (pktin.body[1] << 16) |
+ (pktin.body[2] << 8) |
+ (pktin.body[3]));
+ logevent("Received CryptoCard challenge");
+ if (challengelen > sizeof(prompt) - 1)
+ challengelen = sizeof(prompt) - 1; /* prevent overrun */
+ memcpy(prompt, pktin.body + 4, challengelen);
+ strncpy(prompt + challengelen, "\r\nResponse : ",
+ sizeof(prompt) - challengelen);
+ prompt[sizeof(prompt) - 1] = '\0';
+ }
+ }
+ if (pwpkt_type == SSH1_CMSG_AUTH_PASSWORD) {
+ sprintf(prompt, "%.90s@%.90s's password: ",
+ username, savedhost);
+ }
+ if (pwpkt_type == SSH1_CMSG_AUTH_RSA) {
+ char *comment = NULL;
+ if (flags & FLAG_VERBOSE)
+ c_write_str("Trying public key authentication.\r\n");
+ if (!rsakey_encrypted(cfg.keyfile, &comment)) {
+ if (flags & FLAG_VERBOSE)
+ c_write_str("No passphrase required.\r\n");
+ goto tryauth;
+ }
+ sprintf(prompt, "Passphrase for key \"%.100s\": ", comment);
+ sfree(comment);
+ }
+
+ if (ssh_get_line) {
+ if (!ssh_get_line(prompt, password, sizeof(password), TRUE)) {
+ /*
+ * get_line failed to get a password (for example
+ * because one was supplied on the command line
+ * which has already failed to work). Terminate.
+ */
+ send_packet(SSH1_MSG_DISCONNECT,
+ PKT_STR, "No more passwords available to try",
+ PKT_END);
+ connection_fatal("Unable to authenticate");
+ ssh_state = SSH_STATE_CLOSED;
+ crReturn(1);
+ }
+ } else {
+ c_write_str(prompt);
+ pos = 0;
+ ssh_send_ok = 1;
+ while (pos >= 0) {
+ crWaitUntil(!ispkt);
+ while (inlen--)
+ switch (c = *in++) {
+ case 10:
+ case 13:
+ password[pos] = 0;
+ pos = -1;
+ break;
+ case 8:
+ case 127:
+ if (pos > 0)
+ pos--;
+ break;
+ case 21:
+ case 27:
+ pos = 0;
+ break;
+ case 3:
+ case 4:
+ random_save_seed();
+ exit(0);
+ break;
+ default:
+ if (pos < sizeof(password)-1)
+ password[pos++] = c;
+ break;
+ }
+ }
+ c_write_str("\r\n");
+ }
+
+ tryauth:
+ if (pwpkt_type == SSH1_CMSG_AUTH_RSA) {
+ /*
+ * Try public key authentication with the specified
+ * key file.
+ */
+ static struct RSAKey pubkey;
+ static Bignum challenge, response;
+ static int i;
+ static unsigned char buffer[32];
+
+ tried_publickey = 1;
+ i = loadrsakey(cfg.keyfile, &pubkey, password);
+ if (i == 0) {
+ c_write_str("Couldn't load public key from ");
+ c_write_str(cfg.keyfile);
+ c_write_str(".\r\n");
+ continue; /* go and try password */
+ }
+ if (i == -1) {
+ c_write_str("Wrong passphrase.\r\n");
+ tried_publickey = 0;
+ continue; /* try again */
+ }
+
+ /*
+ * Send a public key attempt.
+ */
+ send_packet(SSH1_CMSG_AUTH_RSA,
+ PKT_BIGNUM, pubkey.modulus, PKT_END);
+
+ crWaitUntil(ispkt);
+ if (pktin.type == SSH1_SMSG_FAILURE) {
+ c_write_str("Server refused our public key.\r\n");
+ continue; /* go and try password */
+ }
+ if (pktin.type != SSH1_SMSG_AUTH_RSA_CHALLENGE) {
+ bombout(("Bizarre response to offer of public key"));
+ crReturn(0);
+ }
+ ssh1_read_bignum(pktin.body, &challenge);
+ response = rsadecrypt(challenge, &pubkey);
+ freebn(pubkey.private_exponent); /* burn the evidence */
+
+ for (i = 0; i < 32; i++) {
+ buffer[i] = bignum_byte(response, 31 - i);
+ }
+
+ MD5Init(&md5c);
+ MD5Update(&md5c, buffer, 32);
+ MD5Update(&md5c, session_id, 16);
+ MD5Final(buffer, &md5c);
+
+ send_packet(SSH1_CMSG_AUTH_RSA_RESPONSE,
+ PKT_DATA, buffer, 16, PKT_END);
+
+ crWaitUntil(ispkt);
+ if (pktin.type == SSH1_SMSG_FAILURE) {
+ if (flags & FLAG_VERBOSE)
+ c_write_str
+ ("Failed to authenticate with our public key.\r\n");
+ continue; /* go and try password */
+ } else if (pktin.type != SSH1_SMSG_SUCCESS) {
+ bombout(
+ ("Bizarre response to RSA authentication response"));
+ crReturn(0);
+ }
+
+ break; /* we're through! */
+ } else {
+ if (pwpkt_type == SSH1_CMSG_AUTH_PASSWORD) {
+ /*
+ * Defence against traffic analysis: we send a
+ * whole bunch of packets containing strings of
+ * different lengths. One of these strings is the
+ * password, in a SSH1_CMSG_AUTH_PASSWORD packet.
+ * The others are all random data in
+ * SSH1_MSG_IGNORE packets. This way a passive
+ * listener can't tell which is the password, and
+ * hence can't deduce the password length.
+ *
+ * Anybody with a password length greater than 16
+ * bytes is going to have enough entropy in their
+ * password that a listener won't find it _that_
+ * much help to know how long it is. So what we'll
+ * do is:
+ *
+ * - if password length < 16, we send 15 packets
+ * containing string lengths 1 through 15
+ *
+ * - otherwise, we let N be the nearest multiple
+ * of 8 below the password length, and send 8
+ * packets containing string lengths N through
+ * N+7. This won't obscure the order of
+ * magnitude of the password length, but it will
+ * introduce a bit of extra uncertainty.
+ *
+ * A few servers (the old 1.2.18 through 1.2.22)
+ * can't deal with SSH1_MSG_IGNORE. For these
+ * servers, we need an alternative defence. We make
+ * use of the fact that the password is interpreted
+ * as a C string: so we can append a NUL, then some
+ * random data.
+ */
+ if (ssh_remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE) {
+ char string[64];
+ char *s;
+ int len;
+
+ len = strlen(password);
+ if (len < sizeof(string)) {
+ s = string;
+ strcpy(string, password);
+ len++; /* cover the zero byte */
+ while (len < sizeof(string)) {
+ string[len++] = (char) random_byte();
+ }
+ } else {
+ s = password;
+ }
+ send_packet(pwpkt_type, PKT_INT, len,
+ PKT_DATA, s, len, PKT_END);
+ } else {
+ int bottom, top, pwlen, i;
+ char *randomstr;
+
+ pwlen = strlen(password);
+ if (pwlen < 16) {
+ bottom = 0; /* zero length passwords are OK! :-) */
+ top = 15;
+ } else {
+ bottom = pwlen & ~7;
+ top = bottom + 7;
+ }
+
+ assert(pwlen >= bottom && pwlen <= top);
+
+ randomstr = smalloc(top + 1);
+
+ for (i = bottom; i <= top; i++) {
+ if (i == pwlen)
+ defer_packet(pwpkt_type, PKT_STR, password,
+ PKT_END);
+ else {
+ for (j = 0; j < i; j++) {
+ do {
+ randomstr[j] = random_byte();
+ } while (randomstr[j] == '\0');
+ }
+ randomstr[i] = '\0';
+ defer_packet(SSH1_MSG_IGNORE,
+ PKT_STR, randomstr, PKT_END);
+ }
+ }
+ ssh_pkt_defersend();
+ }
+ } else {
+ send_packet(pwpkt_type, PKT_STR, password, PKT_END);
+ }
+ }
+ logevent("Sent password");
+ memset(password, 0, strlen(password));
+ crWaitUntil(ispkt);
+ if (pktin.type == SSH1_SMSG_FAILURE) {
+ if (flags & FLAG_VERBOSE)
+ c_write_str("Access denied\r\n");
+ logevent("Authentication refused");
+ } else if (pktin.type == SSH1_MSG_DISCONNECT) {
+ logevent("Received disconnect request");
+ ssh_state = SSH_STATE_CLOSED;
+ crReturn(1);
+ } else if (pktin.type != SSH1_SMSG_SUCCESS) {
+ bombout(("Strange packet received, type %d", pktin.type));
+ crReturn(0);
+ }
+ }
+
+ logevent("Authentication successful");
+
+ crFinish(1);
+}
+
+void sshfwd_close(struct ssh_channel *c)
+{
+ if (c && !c->closes) {
+ if (ssh_version == 1) {
+ send_packet(SSH1_MSG_CHANNEL_CLOSE, PKT_INT, c->remoteid,
+ PKT_END);
+ } else {
+ ssh2_pkt_init(SSH2_MSG_CHANNEL_CLOSE);
+ ssh2_pkt_adduint32(c->remoteid);
+ ssh2_pkt_send();
+ }
+ c->closes = 1;
+ if (c->type == CHAN_X11) {
+ c->u.x11.s = NULL;
+ logevent("Forwarded X11 connection terminated");
+ } else if (c->type == CHAN_SOCKDATA) {
+ c->u.pfd.s = NULL;
+ logevent("Forwarded port closed");
+ }
+ }
+}
+
+int sshfwd_write(struct ssh_channel *c, char *buf, int len)
+{
+ if (ssh_version == 1) {
+ send_packet(SSH1_MSG_CHANNEL_DATA,
+ PKT_INT, c->remoteid,
+ PKT_INT, len, PKT_DATA, buf, len, PKT_END);
+ /*
+ * In SSH1 we can return 0 here - implying that forwarded
+ * connections are never individually throttled - because
+ * the only circumstance that can cause throttling will be
+ * the whole SSH connection backing up, in which case
+ * _everything_ will be throttled as a whole.
+ */
+ return 0;
+ } else {
+ ssh2_add_channel_data(c, buf, len);
+ return ssh2_try_send(c);
+ }
+}
+
+void sshfwd_unthrottle(struct ssh_channel *c, int bufsize)
+{
+ if (ssh_version == 1) {
+ if (c->v.v1.throttling && bufsize < SSH1_BUFFER_LIMIT) {
+ c->v.v1.throttling = 0;
+ ssh1_throttle(-1);
+ }
+ } else {
+ ssh2_set_window(c, OUR_V2_WINSIZE - bufsize);
+ }
+}
+
+static void ssh1_protocol(unsigned char *in, int inlen, int ispkt)
+{
+ crBegin;
+
+ random_init();
+
+ while (!do_ssh1_login(in, inlen, ispkt)) {
+ crReturnV;