X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/d6430b975d14ddbd53c40126fa9d00bea3c2d08b..fabd1805a8f429ca83b4271aabd1206ac3537ebb:/ssh.c diff --git a/ssh.c b/ssh.c index 588c8c3e..1d9b1ed1 100644 --- a/ssh.c +++ b/ssh.c @@ -166,7 +166,7 @@ static const char *const ssh2_disconnect_reasons[] = { #define translate(x) if (type == x) return #x #define translatec(x,ctx) if (type == x && (pkt_ctx & ctx)) return #x -char *ssh1_pkt_type(int type) +static char *ssh1_pkt_type(int type) { translate(SSH1_MSG_DISCONNECT); translate(SSH1_SMSG_PUBLIC_KEY); @@ -211,7 +211,7 @@ char *ssh1_pkt_type(int type) translate(SSH1_CMSG_AUTH_CCARD_RESPONSE); return "unknown"; } -char *ssh2_pkt_type(int pkt_ctx, int type) +static char *ssh2_pkt_type(int pkt_ctx, int type) { translate(SSH2_MSG_DISCONNECT); translate(SSH2_MSG_IGNORE); @@ -291,22 +291,6 @@ enum { PKT_END, PKT_INT, PKT_CHAR, PKT_DATA, PKT_STR, PKT_BIGNUM }; typedef struct ssh_tag *Ssh; -extern char *x11_init(Socket *, char *, void *, void *); -extern void x11_close(Socket); -extern int x11_send(Socket, char *, int); -extern void *x11_invent_auth(char *, int, char *, int); -extern void x11_unthrottle(Socket s); -extern void x11_override_throttle(Socket s, int enable); - -extern char *pfd_newconnect(Socket * s, char *hostname, int port, void *c); -extern char *pfd_addforward(char *desthost, int destport, int port, - void *backhandle); -extern void pfd_close(Socket s); -extern int pfd_send(Socket s, char *data, int len); -extern void pfd_confirm(Socket s); -extern void pfd_unthrottle(Socket s); -extern void pfd_override_throttle(Socket s, int enable); - static void ssh2_pkt_init(Ssh, int pkt_type); static void ssh2_pkt_addbool(Ssh, unsigned char value); static void ssh2_pkt_adduint32(Ssh, unsigned long value); @@ -314,7 +298,7 @@ static void ssh2_pkt_addstring_start(Ssh); static void ssh2_pkt_addstring_str(Ssh, char *data); static void ssh2_pkt_addstring_data(Ssh, char *data, int len); static void ssh2_pkt_addstring(Ssh, char *data); -static char *ssh2_mpint_fmt(Bignum b, int *len); +static unsigned char *ssh2_mpint_fmt(Bignum b, int *len); static void ssh2_pkt_addmp(Ssh, Bignum b); static int ssh2_pkt_construct(Ssh); static void ssh2_pkt_send(Ssh); @@ -636,18 +620,20 @@ struct ssh_tag { void (*protocol) (Ssh ssh, unsigned char *in, int inlen, int ispkt); int (*s_rdpkt) (Ssh ssh, unsigned char **data, int *datalen); + + /* + * We maintain a full _copy_ of a Config structure here, not + * merely a pointer to it. That way, when we're passed a new + * one for reconfiguration, we can check the differences and + * potentially reconfigure port forwardings etc in mid-session. + */ + Config cfg; }; -#define logevent(s) do { \ - logevent(ssh->frontend, s); \ - if ((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)) { \ - fprintf(stderr, "%s\n", s); \ - fflush(stderr); \ - } \ -} while (0) +#define logevent(s) logevent(ssh->frontend, s) /* logevent, only printf-formatted. */ -void logeventf(Ssh ssh, char *fmt, ...) +static void logeventf(Ssh ssh, char *fmt, ...) { va_list ap; char *buf; @@ -656,10 +642,6 @@ void logeventf(Ssh ssh, char *fmt, ...) buf = dupvprintf(fmt, ap); va_end(ap); logevent(buf); - if ((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)) { - fprintf(stderr, "%s\n", buf); - fflush(stderr); - } sfree(buf); } @@ -1225,7 +1207,7 @@ static void s_wrpkt(Ssh ssh) { int len, backlog; len = s_wrpkt_prepare(ssh); - backlog = sk_write(ssh->s, ssh->pktout.data, len); + backlog = sk_write(ssh->s, (char *)ssh->pktout.data, len); if (backlog > SSH_MAX_BACKLOG) ssh_throttle_all(ssh, 1, backlog); } @@ -1271,7 +1253,7 @@ static void construct_packet(Ssh ssh, int pkttype, va_list ap1, va_list ap2) break; case PKT_STR: argp = va_arg(ap1, unsigned char *); - arglen = strlen(argp); + arglen = strlen((char *)argp); pktlen += 4 + arglen; break; case PKT_BIGNUM: @@ -1306,7 +1288,7 @@ static void construct_packet(Ssh ssh, int pkttype, va_list ap1, va_list ap2) break; case PKT_STR: argp = va_arg(ap2, unsigned char *); - arglen = strlen(argp); + arglen = strlen((char *)argp); PUT_32BIT(p, arglen); memcpy(p + 4, argp, arglen); p += 4 + arglen; @@ -1437,7 +1419,7 @@ static void ssh2_pkt_addstring(Ssh ssh, char *data) ssh2_pkt_addstring_start(ssh); ssh2_pkt_addstring_str(ssh, data); } -static char *ssh2_mpint_fmt(Bignum b, int *len) +static unsigned char *ssh2_mpint_fmt(Bignum b, int *len) { unsigned char *p; int i, n = (bignum_bitcount(b) + 7) / 8; @@ -1460,7 +1442,7 @@ static void ssh2_pkt_addmp(Ssh ssh, Bignum b) int len; p = ssh2_mpint_fmt(b, &len); ssh2_pkt_addstring_start(ssh); - ssh2_pkt_addstring_data(ssh, p, len); + ssh2_pkt_addstring_data(ssh, (char *)p, len); sfree(p); } @@ -1531,7 +1513,7 @@ static void ssh2_pkt_send(Ssh ssh) int len; int backlog; len = ssh2_pkt_construct(ssh); - backlog = sk_write(ssh->s, ssh->pktout.data, len); + backlog = sk_write(ssh->s, (char *)ssh->pktout.data, len); if (backlog > SSH_MAX_BACKLOG) ssh_throttle_all(ssh, 1, backlog); } @@ -1566,7 +1548,8 @@ static void ssh2_pkt_defer(Ssh ssh) static void ssh_pkt_defersend(Ssh ssh) { int backlog; - backlog = sk_write(ssh->s, ssh->deferred_send_data, ssh->deferred_len); + backlog = sk_write(ssh->s, (char *)ssh->deferred_send_data, + ssh->deferred_len); ssh->deferred_len = ssh->deferred_size = 0; sfree(ssh->deferred_send_data); ssh->deferred_send_data = NULL; @@ -1632,7 +1615,7 @@ static void ssh2_pkt_getstring(Ssh ssh, char **p, int *length) ssh->pktin.savedpos += 4; if (ssh->pktin.length - ssh->pktin.savedpos < *length) return; - *p = ssh->pktin.data + ssh->pktin.savedpos; + *p = (char *)(ssh->pktin.data + ssh->pktin.savedpos); ssh->pktin.savedpos += *length; } static Bignum ssh2_pkt_getmp(Ssh ssh) @@ -1648,7 +1631,7 @@ static Bignum ssh2_pkt_getmp(Ssh ssh) bombout((ssh,"internal error: Can't handle negative mpints")); return NULL; } - b = bignum_from_bytes(p, length); + b = bignum_from_bytes((unsigned char *)p, length); return b; } @@ -1698,18 +1681,18 @@ static void ssh2_add_sigblob(Ssh ssh, void *pkblob_v, int pkblob_len, if (len != siglen) { unsigned char newlen[4]; ssh2_pkt_addstring_start(ssh); - ssh2_pkt_addstring_data(ssh, sigblob, pos); + ssh2_pkt_addstring_data(ssh, (char *)sigblob, pos); /* dmemdump(sigblob, pos); */ pos += 4; /* point to start of actual sig */ PUT_32BIT(newlen, len); - ssh2_pkt_addstring_data(ssh, newlen, 4); + ssh2_pkt_addstring_data(ssh, (char *)newlen, 4); /* dmemdump(newlen, 4); */ newlen[0] = 0; while (len-- > siglen) { - ssh2_pkt_addstring_data(ssh, newlen, 1); + ssh2_pkt_addstring_data(ssh, (char *)newlen, 1); /* dmemdump(newlen, 1); */ } - ssh2_pkt_addstring_data(ssh, sigblob+pos, siglen); + ssh2_pkt_addstring_data(ssh, (char *)(sigblob+pos), siglen); /* dmemdump(sigblob+pos, siglen); */ return; } @@ -1718,7 +1701,7 @@ static void ssh2_add_sigblob(Ssh ssh, void *pkblob_v, int pkblob_len, } ssh2_pkt_addstring_start(ssh); - ssh2_pkt_addstring_data(ssh, sigblob, sigblob_len); + ssh2_pkt_addstring_data(ssh, (char *)sigblob, sigblob_len); } /* @@ -1736,8 +1719,8 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) ssh->remote_bugs = 0; - if (cfg.sshbug_ignore1 == BUG_ON || - (cfg.sshbug_ignore1 == BUG_AUTO && + if (ssh->cfg.sshbug_ignore1 == BUG_ON || + (ssh->cfg.sshbug_ignore1 == BUG_AUTO && (!strcmp(imp, "1.2.18") || !strcmp(imp, "1.2.19") || !strcmp(imp, "1.2.20") || !strcmp(imp, "1.2.21") || !strcmp(imp, "1.2.22") || !strcmp(imp, "Cisco-1.25")))) { @@ -1750,8 +1733,8 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) logevent("We believe remote version has SSH1 ignore bug"); } - if (cfg.sshbug_plainpw1 == BUG_ON || - (cfg.sshbug_plainpw1 == BUG_AUTO && + if (ssh->cfg.sshbug_plainpw1 == BUG_ON || + (ssh->cfg.sshbug_plainpw1 == BUG_AUTO && (!strcmp(imp, "Cisco-1.25")))) { /* * These versions need a plain password sent; they can't @@ -1762,8 +1745,8 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) logevent("We believe remote version needs a plain SSH1 password"); } - if (cfg.sshbug_rsa1 == BUG_ON || - (cfg.sshbug_rsa1 == BUG_AUTO && + if (ssh->cfg.sshbug_rsa1 == BUG_ON || + (ssh->cfg.sshbug_rsa1 == BUG_AUTO && (!strcmp(imp, "Cisco-1.25")))) { /* * These versions apparently have no clue whatever about @@ -1774,8 +1757,8 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) logevent("We believe remote version can't handle RSA authentication"); } - if (cfg.sshbug_hmac2 == BUG_ON || - (cfg.sshbug_hmac2 == BUG_AUTO && + if (ssh->cfg.sshbug_hmac2 == BUG_ON || + (ssh->cfg.sshbug_hmac2 == BUG_AUTO && (wc_match("2.1.0*", imp) || wc_match("2.0.*", imp) || wc_match("2.2.0*", imp) || wc_match("2.3.0*", imp) || wc_match("2.1 *", imp)))) { @@ -1786,8 +1769,8 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) logevent("We believe remote version has SSH2 HMAC bug"); } - if (cfg.sshbug_derivekey2 == BUG_ON || - (cfg.sshbug_derivekey2 == BUG_AUTO && + if (ssh->cfg.sshbug_derivekey2 == BUG_ON || + (ssh->cfg.sshbug_derivekey2 == BUG_AUTO && (wc_match("2.0.0*", imp) || wc_match("2.0.1[01]*", imp) ))) { /* * These versions have the key-derivation bug (failing to @@ -1798,8 +1781,8 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) logevent("We believe remote version has SSH2 key-derivation bug"); } - if (cfg.sshbug_rsapad2 == BUG_ON || - (cfg.sshbug_rsapad2 == BUG_AUTO && + if (ssh->cfg.sshbug_rsapad2 == BUG_ON || + (ssh->cfg.sshbug_rsapad2 == BUG_AUTO && (wc_match("OpenSSH_2.[5-9]*", imp) || wc_match("OpenSSH_3.[0-2]*", imp)))) { /* @@ -1809,7 +1792,7 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) logevent("We believe remote version has SSH2 RSA padding bug"); } - if (cfg.sshbug_dhgex2 == BUG_ON) { + if (ssh->cfg.sshbug_dhgex2 == BUG_ON) { /* * User specified the SSH2 DH GEX bug. */ @@ -1869,7 +1852,7 @@ static int do_ssh_init(Ssh ssh, unsigned char c) s->i = -1; } else if (s->i < sizeof(s->version) - 1) s->version[s->i++] = c; - } else if (c == '\n') + } else if (c == '\012') break; } @@ -1896,16 +1879,16 @@ static int do_ssh_init(Ssh ssh, unsigned char c) /* Anything greater or equal to "1.99" means protocol 2 is supported. */ s->proto2 = ssh_versioncmp(s->version, "1.99") >= 0; - if (cfg.sshprot == 0 && !s->proto1) { + if (ssh->cfg.sshprot == 0 && !s->proto1) { bombout((ssh,"SSH protocol version 1 required by user but not provided by server")); crReturn(0); } - if (cfg.sshprot == 3 && !s->proto2) { + if (ssh->cfg.sshprot == 3 && !s->proto2) { bombout((ssh,"SSH protocol version 2 required by user but not provided by server")); crReturn(0); } - if (s->proto2 && (cfg.sshprot >= 2 || !s->proto1)) { + if (s->proto2 && (ssh->cfg.sshprot >= 2 || !s->proto1)) { /* * Use v2 protocol. */ @@ -1919,7 +1902,7 @@ static int do_ssh_init(Ssh ssh, unsigned char c) sha_string(&ssh->exhashbase, s->vstring, strcspn(s->vstring, "\r\n")); sprintf(vlog, "We claim version: %s", verstring); logevent(vlog); - strcat(verstring, "\n"); + strcat(verstring, "\012"); logevent("Using SSH protocol version 2"); sk_write(ssh->s, verstring, strlen(verstring)); ssh->protocol = ssh2_protocol; @@ -1935,7 +1918,7 @@ static int do_ssh_init(Ssh ssh, unsigned char c) sshver); sprintf(vlog, "We claim version: %s", verstring); logevent(vlog); - strcat(verstring, "\n"); + strcat(verstring, "\012"); logevent("Using SSH protocol version 1"); sk_write(ssh->s, verstring, strlen(verstring)); @@ -2018,7 +2001,7 @@ static int ssh_closing(Plug plug, char *error_msg, int error_code, static int ssh_receive(Plug plug, int urgent, char *data, int len) { Ssh ssh = (Ssh) plug; - ssh_gotdata(ssh, data, len); + ssh_gotdata(ssh, (unsigned char *)data, len); if (ssh->state == SSH_STATE_CLOSED) { if (ssh->s) { sk_close(ssh->s); @@ -2072,8 +2055,8 @@ static char *connect_to_host(Ssh ssh, char *host, int port, * Try to find host. */ logeventf(ssh, "Looking up host \"%s\"", host); - addr = sk_namelookup(host, realhost); - if ((err = sk_addr_error(addr))) + addr = name_lookup(host, port, realhost, &ssh->cfg); + if ((err = sk_addr_error(addr)) != NULL) return err; /* @@ -2085,8 +2068,9 @@ static char *connect_to_host(Ssh ssh, char *host, int port, logeventf(ssh, "Connecting to %s port %d", addrbuf, port); } ssh->fn = &fn_table; - ssh->s = new_connection(addr, *realhost, port, 0, 1, nodelay, (Plug) ssh); - if ((err = sk_socket_error(ssh->s))) { + ssh->s = new_connection(addr, *realhost, port, + 0, 1, nodelay, (Plug) ssh, &ssh->cfg); + if ((err = sk_socket_error(ssh->s)) != NULL) { ssh->s = NULL; return err; } @@ -2150,7 +2134,7 @@ static void ssh_throttle_all(Ssh ssh, int enable, int bufsize) */ /* Set up a username or password input loop on a given buffer. */ -void setup_userpass_input(Ssh ssh, char *buffer, int buflen, int echo) +static void setup_userpass_input(Ssh ssh, char *buffer, int buflen, int echo) { ssh->userpass_input_buffer = buffer; ssh->userpass_input_buflen = buflen; @@ -2164,7 +2148,7 @@ void setup_userpass_input(Ssh ssh, char *buffer, int buflen, int echo) * buffer), <0 for failure (user hit ^C/^D, bomb out and exit), 0 * for inconclusive (keep waiting for more input please). */ -int process_userpass_input(Ssh ssh, unsigned char *in, int inlen) +static int process_userpass_input(Ssh ssh, unsigned char *in, int inlen) { char c; @@ -2340,7 +2324,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) char *cipher_string = NULL; int i; for (i = 0; !cipher_chosen && i < CIPHER_MAX; i++) { - int next_cipher = cfg.ssh_cipherlist[i]; + int next_cipher = ssh->cfg.ssh_cipherlist[i]; if (next_cipher == CIPHER_WARN) { /* If/when we choose a cipher, warn about it */ warn = 1; @@ -2419,7 +2403,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) fflush(stdout); { - if ((flags & FLAG_INTERACTIVE) && !*cfg.username) { + if ((flags & FLAG_INTERACTIVE) && !*ssh->cfg.username) { if (ssh_get_line && !ssh_getline_pw_only) { if (!ssh_get_line("login as: ", s->username, sizeof(s->username), FALSE)) { @@ -2446,7 +2430,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) c_write_str(ssh, "\r\n"); } } else { - strncpy(s->username, cfg.username, sizeof(s->username)); + strncpy(s->username, ssh->cfg.username, sizeof(s->username)); s->username[sizeof(s->username)-1] = '\0'; } @@ -2472,9 +2456,9 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) s->tried_publickey = s->tried_agent = 0; } s->tis_auth_refused = s->ccard_auth_refused = 0; - /* Load the public half of cfg.keyfile so we notice if it's in Pageant */ - if (*cfg.keyfile) { - if (!rsakey_pubblob(cfg.keyfile, + /* Load the public half of ssh->cfg.keyfile so we notice if it's in Pageant */ + if (*ssh->cfg.keyfile) { + if (!rsakey_pubblob(ssh->cfg.keyfile, &s->publickey_blob, &s->publickey_bloblen)) s->publickey_blob = NULL; } else @@ -2525,7 +2509,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) s->p += ssh1_read_bignum(s->p, &s->key.modulus); s->commentlen = GET_32BIT(s->p); s->p += 4; - s->commentp = s->p; + s->commentp = (char *)s->p; s->p += s->commentlen; send_packet(ssh, SSH1_CMSG_AUTH_RSA, PKT_BIGNUM, s->key.modulus, PKT_END); @@ -2602,10 +2586,10 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (s->authed) break; } - if (*cfg.keyfile && !s->tried_publickey) + if (*ssh->cfg.keyfile && !s->tried_publickey) s->pwpkt_type = SSH1_CMSG_AUTH_RSA; - if (cfg.try_tis_auth && + if (ssh->cfg.try_tis_auth && (s->supported_auths_mask & (1 << SSH1_AUTH_TIS)) && !s->tis_auth_refused) { s->pwpkt_type = SSH1_CMSG_AUTH_TIS_RESPONSE; @@ -2632,7 +2616,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) s->prompt[(sizeof s->prompt) - 1] = '\0'; } } - if (cfg.try_tis_auth && + if (ssh->cfg.try_tis_auth && (s->supported_auths_mask & (1 << SSH1_AUTH_CCARD)) && !s->ccard_auth_refused) { s->pwpkt_type = SSH1_CMSG_AUTH_CCARD_RESPONSE; @@ -2667,8 +2651,8 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) char msgbuf[256]; if (flags & FLAG_VERBOSE) c_write_str(ssh, "Trying public key authentication.\r\n"); - logeventf(ssh, "Trying public key \"%s\"", cfg.keyfile); - type = key_type(cfg.keyfile); + logeventf(ssh, "Trying public key \"%s\"", ssh->cfg.keyfile); + type = key_type(ssh->cfg.keyfile); if (type != SSH_KEYTYPE_SSH1) { sprintf(msgbuf, "Key is of wrong type (%s)", key_type_to_str(type)); @@ -2678,7 +2662,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) s->tried_publickey = 1; continue; } - if (!rsakey_encrypted(cfg.keyfile, &comment)) { + if (!rsakey_encrypted(ssh->cfg.keyfile, &comment)) { if (flags & FLAG_VERBOSE) c_write_str(ssh, "No passphrase required.\r\n"); goto tryauth; @@ -2734,10 +2718,10 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) s->tried_publickey = 1; { - int ret = loadrsakey(cfg.keyfile, &s->key, s->password); + int ret = loadrsakey(ssh->cfg.keyfile, &s->key, s->password); if (ret == 0) { c_write_str(ssh, "Couldn't load private key from "); - c_write_str(ssh, cfg.keyfile); + c_write_str(ssh, ssh->cfg.keyfile); c_write_str(ssh, ".\r\n"); continue; /* go and try password */ } @@ -3021,7 +3005,7 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (ssh->state == SSH_STATE_CLOSED) crReturnV; - if (cfg.agentfwd && agent_exists()) { + if (ssh->cfg.agentfwd && agent_exists()) { logevent("Requesting agent forwarding"); send_packet(ssh, SSH1_CMSG_AGENT_REQUEST_FORWARDING, PKT_END); do { @@ -3039,15 +3023,17 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) } } - if (cfg.x11_forward) { + if (ssh->cfg.x11_forward) { char proto[20], data[64]; logevent("Requesting X11 forwarding"); ssh->x11auth = x11_invent_auth(proto, sizeof(proto), - data, sizeof(data)); + data, sizeof(data), ssh->cfg.x11_auth); + x11_get_real_auth(ssh->x11auth, ssh->cfg.x11_display); if (ssh->v1_local_protoflags & SSH1_PROTOFLAG_SCREEN_NUMBER) { send_packet(ssh, SSH1_CMSG_X11_REQUEST_FORWARDING, PKT_STR, proto, PKT_STR, data, - PKT_INT, 0, PKT_END); + PKT_INT, x11_get_screen_number(ssh->cfg.x11_display), + PKT_END); } else { send_packet(ssh, SSH1_CMSG_X11_REQUEST_FORWARDING, PKT_STR, proto, PKT_STR, data, PKT_END); @@ -3071,28 +3057,46 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) char type; int n; int sport,dport,sserv,dserv; - char sports[256], dports[256], host[256]; + char sports[256], dports[256], saddr[256], host[256]; ssh->rportfwds = newtree234(ssh_rportcmp_ssh1); /* Add port forwardings. */ - ssh->portfwd_strptr = cfg.portfwd; + ssh->portfwd_strptr = ssh->cfg.portfwd; while (*ssh->portfwd_strptr) { type = *ssh->portfwd_strptr++; + saddr[0] = '\0'; n = 0; - while (*ssh->portfwd_strptr && *ssh->portfwd_strptr != '\t') - sports[n++] = *ssh->portfwd_strptr++; + while (*ssh->portfwd_strptr && *ssh->portfwd_strptr != '\t') { + if (*ssh->portfwd_strptr == ':') { + /* + * We've seen a colon in the middle of the + * source port number. This means that + * everything we've seen until now is the + * source _address_, so we'll move it into + * saddr and start sports from the beginning + * again. + */ + ssh->portfwd_strptr++; + sports[n] = '\0'; + strcpy(saddr, sports); + n = 0; + } + if (n < 255) sports[n++] = *ssh->portfwd_strptr++; + } sports[n] = 0; if (*ssh->portfwd_strptr == '\t') ssh->portfwd_strptr++; n = 0; - while (*ssh->portfwd_strptr && *ssh->portfwd_strptr != ':') - host[n++] = *ssh->portfwd_strptr++; + while (*ssh->portfwd_strptr && *ssh->portfwd_strptr != ':') { + if (n < 255) host[n++] = *ssh->portfwd_strptr++; + } host[n] = 0; if (*ssh->portfwd_strptr == ':') ssh->portfwd_strptr++; n = 0; - while (*ssh->portfwd_strptr) - dports[n++] = *ssh->portfwd_strptr++; + while (*ssh->portfwd_strptr) { + if (n < 255) dports[n++] = *ssh->portfwd_strptr++; + } dports[n] = 0; ssh->portfwd_strptr++; dport = atoi(dports); @@ -3117,9 +3121,12 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) } if (sport && dport) { if (type == 'L') { - pfd_addforward(host, dport, sport, ssh); - logeventf(ssh, "Local port %.*s%.*s%d%.*s forwarding to" - " %s:%.*s%.*s%d%.*s", + pfd_addforward(host, dport, *saddr ? saddr : NULL, + sport, ssh, &ssh->cfg); + logeventf(ssh, "Local port %.*s%.*s%.*s%.*s%d%.*s" + " forwarding to %s:%.*s%.*s%d%.*s", + (int)(*saddr?strlen(saddr):0), *saddr?saddr:NULL, + (int)(*saddr?1:0), ":", (int)(sserv ? strlen(sports) : 0), sports, sserv, "(", sport, sserv, ")", host, @@ -3130,6 +3137,11 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) pf = smalloc(sizeof(*pf)); strcpy(pf->dhost, host); pf->dport = dport; + if (saddr) { + logeventf(ssh, + "SSH1 cannot handle source address spec \"%s:%d\"; ignoring", + saddr, sport); + } if (add234(ssh->rportfwds, pf) != pf) { logeventf(ssh, "Duplicate remote port forwarding to %s:%d", @@ -3166,9 +3178,9 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) } } - if (!cfg.nopty) { + if (!ssh->cfg.nopty) { send_packet(ssh, SSH1_CMSG_REQUEST_PTY, - PKT_STR, cfg.termtype, + PKT_STR, ssh->cfg.termtype, PKT_INT, ssh->term_height, PKT_INT, ssh->term_width, PKT_INT, 0, PKT_INT, 0, PKT_CHAR, 0, PKT_END); @@ -3189,7 +3201,7 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) ssh->editing = ssh->echoing = 1; } - if (cfg.compression) { + if (ssh->cfg.compression) { send_packet(ssh, SSH1_CMSG_REQUEST_COMPRESSION, PKT_INT, 6, PKT_END); do { crReturnV; @@ -3217,10 +3229,10 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) * exists, we fall straight back to that. */ { - char *cmd = cfg.remote_cmd_ptr; + char *cmd = ssh->cfg.remote_cmd_ptr; - if (cfg.ssh_subsys && cfg.remote_cmd_ptr2) { - cmd = cfg.remote_cmd_ptr2; + if (ssh->cfg.ssh_subsys && ssh->cfg.remote_cmd_ptr2) { + cmd = ssh->cfg.remote_cmd_ptr2; ssh->fallback_cmd = TRUE; } if (*cmd) @@ -3249,7 +3261,7 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) int bufsize = from_backend(ssh->frontend, ssh->pktin.type == SSH1_SMSG_STDERR_DATA, - ssh->pktin.body + 4, len); + (char *)(ssh->pktin.body) + 4, len); if (!ssh->v1_stdout_throttling && bufsize > SSH1_BUFFER_LIMIT) { ssh->v1_stdout_throttling = 1; ssh1_throttle(ssh, +1); @@ -3273,8 +3285,8 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) c = smalloc(sizeof(struct ssh_channel)); c->ssh = ssh; - if (x11_init(&c->u.x11.s, cfg.x11_display, c, - ssh->x11auth) != NULL) { + if (x11_init(&c->u.x11.s, ssh->cfg.x11_display, c, + ssh->x11auth, NULL, -1, &ssh->cfg) != NULL) { logevent("opening X11 forward connection failed"); sfree(c); send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE, @@ -3330,7 +3342,8 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) c->ssh = ssh; hostsize = GET_32BIT(ssh->pktin.body+4); - for(h = host, p = ssh->pktin.body+8; hostsize != 0; hostsize--) { + for (h = host, p = (char *)(ssh->pktin.body+8); + hostsize != 0; hostsize--) { if (h+1 < host+sizeof(host)) *h++ = *p; p++; @@ -3351,7 +3364,7 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) sprintf(buf, "Received remote port open request for %s:%d", host, port); logevent(buf); - e = pfd_newconnect(&c->u.pfd.s, host, port, c); + e = pfd_newconnect(&c->u.pfd.s, host, port, c, &ssh->cfg); if (e != NULL) { char buf[256]; sprintf(buf, "Port open failed: %s", e); @@ -3462,10 +3475,10 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) int bufsize; switch (c->type) { case CHAN_X11: - bufsize = x11_send(c->u.x11.s, p, len); + bufsize = x11_send(c->u.x11.s, (char *)p, len); break; case CHAN_SOCKDATA: - bufsize = pfd_send(c->u.pfd.s, p, len); + bufsize = pfd_send(c->u.pfd.s, (char *)p, len); break; case CHAN_AGENT: /* Data for an agent message. Buffer it. */ @@ -3599,8 +3612,9 @@ static int in_commasep_string(char *needle, char *haystack, int haylen) /* * SSH2 key creation method. */ -static void ssh2_mkkey(Ssh ssh, Bignum K, char *H, char *sessid, char chr, - char *keyspace) +static void ssh2_mkkey(Ssh ssh, Bignum K, unsigned char *H, + unsigned char *sessid, char chr, + unsigned char *keyspace) { SHA_State s; /* First 20 bytes. */ @@ -3664,12 +3678,12 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, int ispkt) */ s->n_preferred_ciphers = 0; for (i = 0; i < CIPHER_MAX; i++) { - switch (cfg.ssh_cipherlist[i]) { + switch (ssh->cfg.ssh_cipherlist[i]) { case CIPHER_BLOWFISH: s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_blowfish; break; case CIPHER_DES: - if (cfg.ssh2_des_cbc) { + if (ssh->cfg.ssh2_des_cbc) { s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_des; } break; @@ -3693,7 +3707,7 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, int ispkt) /* * Set up preferred compression. */ - if (cfg.compression) + if (ssh->cfg.compression) s->preferred_comp = &ssh_zlib; else s->preferred_comp = &ssh_comp_none; @@ -4017,6 +4031,7 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, int ispkt) SHA_Final(&ssh->exhash, s->exchange_hash); dh_cleanup(ssh->kex_ctx); + ssh->kex_ctx = NULL; #if 0 debug(("Exchange hash is:\n")); @@ -4026,7 +4041,7 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, int ispkt) s->hkey = ssh->hostkey->newkey(s->hostkeydata, s->hostkeylen); if (!s->hkey || !ssh->hostkey->verifysig(s->hkey, s->sigdata, s->siglen, - s->exchange_hash, 20)) { + (char *)s->exchange_hash, 20)) { bombout((ssh,"Server's host key did not match the signature supplied")); crReturn(0); } @@ -4308,13 +4323,13 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) /* * Get a username. */ - if (s->got_username && !cfg.change_username) { + if (s->got_username && !ssh->cfg.change_username) { /* * We got a username last time round this loop, and * with change_username turned off we don't try to get * it again. */ - } else if ((flags & FLAG_INTERACTIVE) && !*cfg.username) { + } else if ((flags & FLAG_INTERACTIVE) && !*ssh->cfg.username) { if (ssh_get_line && !ssh_getline_pw_only) { if (!ssh_get_line("login as: ", s->username, sizeof(s->username), FALSE)) { @@ -4342,7 +4357,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) s->username[strcspn(s->username, "\n\r")] = '\0'; } else { char *stuff; - strncpy(s->username, cfg.username, sizeof(s->username)); + strncpy(s->username, ssh->cfg.username, sizeof(s->username)); s->username[sizeof(s->username)-1] = '\0'; if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) { stuff = dupprintf("Using username \"%s\".\r\n", s->username); @@ -4372,21 +4387,21 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) s->tried_agent = FALSE; s->tried_keyb_inter = FALSE; s->kbd_inter_running = FALSE; - /* Load the pub half of cfg.keyfile so we notice if it's in Pageant */ - if (*cfg.keyfile) { + /* Load the pub half of ssh->cfg.keyfile so we notice if it's in Pageant */ + if (*ssh->cfg.keyfile) { int keytype; - logeventf(ssh, "Reading private key file \"%.150s\"", cfg.keyfile); - keytype = key_type(cfg.keyfile); + logeventf(ssh, "Reading private key file \"%.150s\"", ssh->cfg.keyfile); + keytype = key_type(ssh->cfg.keyfile); if (keytype == SSH_KEYTYPE_SSH2) { s->publickey_blob = - ssh2_userkey_loadpub(cfg.keyfile, NULL, + ssh2_userkey_loadpub(ssh->cfg.keyfile, NULL, &s->publickey_bloblen); } else { char *msgbuf; logeventf(ssh, "Unable to use this key file (%s)", key_type_to_str(keytype)); msgbuf = dupprintf("Unable to use key file \"%.150s\"" - " (%s)\r\n", cfg.keyfile, + " (%s)\r\n", ssh->cfg.keyfile, key_type_to_str(keytype)); c_write_str(ssh, msgbuf); sfree(msgbuf); @@ -4502,7 +4517,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) in_commasep_string("publickey", methods, methlen); s->can_passwd = in_commasep_string("password", methods, methlen); - s->can_keyb_inter = cfg.try_ki_auth && + s->can_keyb_inter = ssh->cfg.try_ki_auth && in_commasep_string("keyboard-interactive", methods, methlen); } @@ -4564,13 +4579,13 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) logevent("This key matches configured key file"); s->tried_pubkey_config = 1; } - s->pkblob = s->p; + 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 = s->p; + s->commentp = (char *)s->p; s->p += s->commentlen; ssh2_pkt_init(ssh, SSH2_MSG_USERAUTH_REQUEST); ssh2_pkt_addstring(ssh, s->username); @@ -4676,8 +4691,10 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) * First, offer the public blob to see if the server is * willing to accept it. */ - pub_blob = ssh2_userkey_loadpub(cfg.keyfile, &algorithm, - &pub_blob_len); + pub_blob = + (unsigned char *)ssh2_userkey_loadpub(ssh->cfg.keyfile, + &algorithm, + &pub_blob_len); if (pub_blob) { ssh2_pkt_init(ssh, SSH2_MSG_USERAUTH_REQUEST); ssh2_pkt_addstring(ssh, s->username); @@ -4686,7 +4703,8 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) ssh2_pkt_addbool(ssh, FALSE); /* no signature included */ ssh2_pkt_addstring(ssh, algorithm); ssh2_pkt_addstring_start(ssh); - ssh2_pkt_addstring_data(ssh, pub_blob, pub_blob_len); + ssh2_pkt_addstring_data(ssh, (char *)pub_blob, + pub_blob_len); ssh2_pkt_send(ssh); logevent("Offered public key"); /* FIXME */ @@ -4702,7 +4720,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) * Actually attempt a serious authentication using * the key. */ - if (ssh2_userkey_encrypted(cfg.keyfile, &comment)) { + if (ssh2_userkey_encrypted(ssh->cfg.keyfile, &comment)) { sprintf(s->pwprompt, "Passphrase for key \"%.100s\": ", comment); @@ -4854,7 +4872,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) */ struct ssh2_userkey *key; - key = ssh2_load_userkey(cfg.keyfile, s->password); + key = ssh2_load_userkey(ssh->cfg.keyfile, s->password); if (key == SSH2_WRONG_PASSPHRASE || key == NULL) { if (key == SSH2_WRONG_PASSPHRASE) { c_write_str(ssh, "Wrong passphrase\r\n"); @@ -4887,7 +4905,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) ssh2_pkt_addstring(ssh, key->alg->name); pkblob = key->alg->public_blob(key->data, &pkblob_len); ssh2_pkt_addstring_start(ssh); - ssh2_pkt_addstring_data(ssh, pkblob, pkblob_len); + ssh2_pkt_addstring_data(ssh, (char *)pkblob, pkblob_len); /* * The data to be signed is: @@ -4903,7 +4921,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) memcpy(sigdata + 4, ssh->v2_session_id, 20); memcpy(sigdata + 24, ssh->pktout.data + 5, ssh->pktout.length - 5); - sigblob = key->alg->sign(key->data, sigdata, + sigblob = key->alg->sign(key->data, (char *)sigdata, sigdata_len, &sigblob_len); ssh2_add_sigblob(ssh, pkblob, pkblob_len, sigblob, sigblob_len); @@ -4935,6 +4953,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) ssh2_pkt_addstring(ssh, "password"); ssh2_pkt_addbool(ssh, FALSE); ssh2_pkt_addstring(ssh, s->password); + memset(s->password, 0, sizeof(s->password)); ssh2_pkt_defer(ssh); /* * We'll include a string that's an exact multiple of the @@ -5055,11 +5074,12 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) /* * Potentially enable X11 forwarding. */ - if (cfg.x11_forward) { + if (ssh->cfg.x11_forward) { char proto[20], data[64]; logevent("Requesting X11 forwarding"); ssh->x11auth = x11_invent_auth(proto, sizeof(proto), - data, sizeof(data)); + data, sizeof(data), ssh->cfg.x11_auth); + x11_get_real_auth(ssh->x11auth, ssh->cfg.x11_display); ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_REQUEST); ssh2_pkt_adduint32(ssh, ssh->mainchan->remoteid); ssh2_pkt_addstring(ssh, "x11-req"); @@ -5067,7 +5087,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) ssh2_pkt_addbool(ssh, 0); /* many connections */ ssh2_pkt_addstring(ssh, proto); ssh2_pkt_addstring(ssh, data); - ssh2_pkt_adduint32(ssh, 0); /* screen number */ + ssh2_pkt_adduint32(ssh, x11_get_screen_number(ssh->cfg.x11_display)); ssh2_pkt_send(ssh); do { @@ -5102,28 +5122,46 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) char type; int n; int sport,dport,sserv,dserv; - char sports[256], dports[256], host[256]; + char sports[256], dports[256], saddr[256], host[256]; ssh->rportfwds = newtree234(ssh_rportcmp_ssh2); /* Add port forwardings. */ - ssh->portfwd_strptr = cfg.portfwd; + ssh->portfwd_strptr = ssh->cfg.portfwd; while (*ssh->portfwd_strptr) { type = *ssh->portfwd_strptr++; + saddr[0] = '\0'; n = 0; - while (*ssh->portfwd_strptr && *ssh->portfwd_strptr != '\t') - sports[n++] = *ssh->portfwd_strptr++; + while (*ssh->portfwd_strptr && *ssh->portfwd_strptr != '\t') { + if (*ssh->portfwd_strptr == ':') { + /* + * We've seen a colon in the middle of the + * source port number. This means that + * everything we've seen until now is the + * source _address_, so we'll move it into + * saddr and start sports from the beginning + * again. + */ + ssh->portfwd_strptr++; + sports[n] = '\0'; + strcpy(saddr, sports); + n = 0; + } + if (n < 255) sports[n++] = *ssh->portfwd_strptr++; + } sports[n] = 0; if (*ssh->portfwd_strptr == '\t') ssh->portfwd_strptr++; n = 0; - while (*ssh->portfwd_strptr && *ssh->portfwd_strptr != ':') - host[n++] = *ssh->portfwd_strptr++; + while (*ssh->portfwd_strptr && *ssh->portfwd_strptr != ':') { + if (n < 255) host[n++] = *ssh->portfwd_strptr++; + } host[n] = 0; if (*ssh->portfwd_strptr == ':') ssh->portfwd_strptr++; n = 0; - while (*ssh->portfwd_strptr) - dports[n++] = *ssh->portfwd_strptr++; + while (*ssh->portfwd_strptr) { + if (n < 255) dports[n++] = *ssh->portfwd_strptr++; + } dports[n] = 0; ssh->portfwd_strptr++; dport = atoi(dports); @@ -5148,9 +5186,12 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) } if (sport && dport) { if (type == 'L') { - pfd_addforward(host, dport, sport, ssh); - logeventf(ssh, "Local port %.*s%.*s%d%.*s forwarding to" - " %s:%.*s%.*s%d%.*s", + pfd_addforward(host, dport, *saddr ? saddr : NULL, + sport, ssh, &ssh->cfg); + logeventf(ssh, "Local port %.*s%.*s%.*s%.*s%d%.*s" + " forwarding to %s:%.*s%.*s%d%.*s", + (int)(*saddr?strlen(saddr):0), *saddr?saddr:NULL, + (int)(*saddr?1:0), ":", (int)(sserv ? strlen(sports) : 0), sports, sserv, "(", sport, sserv, ")", host, @@ -5167,8 +5208,12 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) " to %s:%d", host, dport); sfree(pf); } else { - logeventf(ssh, "Requesting remote port %.*s%.*s%d%.*s" + logeventf(ssh, "Requesting remote port " + "%.*s%.*s%.*s%.*s%d%.*s" " forward to %s:%.*s%.*s%d%.*s", + (int)(*saddr?strlen(saddr):0), + *saddr?saddr:NULL, + (int)(*saddr?1:0), ":", (int)(sserv ? strlen(sports) : 0), sports, sserv, "(", sport, sserv, ")", host, @@ -5177,7 +5222,9 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) ssh2_pkt_init(ssh, SSH2_MSG_GLOBAL_REQUEST); ssh2_pkt_addstring(ssh, "tcpip-forward"); ssh2_pkt_addbool(ssh, 1);/* want reply */ - if (cfg.rport_acceptall) + if (*saddr) + ssh2_pkt_addstring(ssh, saddr); + if (ssh->cfg.rport_acceptall) ssh2_pkt_addstring(ssh, "0.0.0.0"); else ssh2_pkt_addstring(ssh, "127.0.0.1"); @@ -5216,7 +5263,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) /* * Potentially enable agent forwarding. */ - if (cfg.agentfwd && agent_exists()) { + if (ssh->cfg.agentfwd && agent_exists()) { logevent("Requesting OpenSSH-style agent forwarding"); ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_REQUEST); ssh2_pkt_adduint32(ssh, ssh->mainchan->remoteid); @@ -5252,12 +5299,12 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) /* * Now allocate a pty for the session. */ - if (!cfg.nopty) { + if (!ssh->cfg.nopty) { ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_REQUEST); ssh2_pkt_adduint32(ssh, ssh->mainchan->remoteid); /* recipient channel */ ssh2_pkt_addstring(ssh, "pty-req"); ssh2_pkt_addbool(ssh, 1); /* want reply */ - ssh2_pkt_addstring(ssh, cfg.termtype); + ssh2_pkt_addstring(ssh, ssh->cfg.termtype); ssh2_pkt_adduint32(ssh, ssh->term_width); ssh2_pkt_adduint32(ssh, ssh->term_height); ssh2_pkt_adduint32(ssh, 0); /* pixel width */ @@ -5304,11 +5351,11 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) char *cmd; if (ssh->fallback_cmd) { - subsys = cfg.ssh_subsys2; - cmd = cfg.remote_cmd_ptr2; + subsys = ssh->cfg.ssh_subsys2; + cmd = ssh->cfg.remote_cmd_ptr2; } else { - subsys = cfg.ssh_subsys; - cmd = cfg.remote_cmd_ptr; + subsys = ssh->cfg.ssh_subsys; + cmd = ssh->cfg.remote_cmd_ptr; } ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_REQUEST); @@ -5349,7 +5396,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) * not, and if the fallback command exists, try falling * back to it before complaining. */ - if (!ssh->fallback_cmd && cfg.remote_cmd_ptr2 != NULL) { + if (!ssh->fallback_cmd && ssh->cfg.remote_cmd_ptr2 != NULL) { logevent("Primary command failed; attempting fallback"); ssh->fallback_cmd = TRUE; continue; @@ -5552,8 +5599,8 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) unsigned i = ssh2_pkt_getuint32(ssh); struct ssh_channel *c; c = find234(ssh->channels, &i, ssh_channelfind); - if (!c) - continue; /* nonexistent channel */ + if (!c || c->closes) + continue; /* nonexistent or closing channel */ c->v.v2.remwindow += ssh2_pkt_getuint32(ssh); s->try_send = TRUE; } else if (ssh->pktin.type == SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) { @@ -5677,6 +5724,9 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) } else if (ssh->pktin.type == SSH2_MSG_CHANNEL_OPEN) { char *type; int typelen; + char *peeraddr; + int peeraddrlen; + int port; char *error = NULL; struct ssh_channel *c; unsigned remid, winsize, pktsize; @@ -5687,16 +5737,25 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) remid = ssh2_pkt_getuint32(ssh); winsize = ssh2_pkt_getuint32(ssh); pktsize = ssh2_pkt_getuint32(ssh); + ssh2_pkt_getstring(ssh, &peeraddr, &peeraddrlen); + port = ssh2_pkt_getuint32(ssh); if (typelen == 3 && !memcmp(type, "x11", 3)) { + char *addrstr = smalloc(peeraddrlen+1); + memcpy(addrstr, peeraddr, peeraddrlen); + peeraddr[peeraddrlen] = '\0'; + if (!ssh->X11_fwd_enabled) error = "X11 forwarding is not enabled"; - else if (x11_init(&c->u.x11.s, cfg.x11_display, c, - ssh->x11auth) != NULL) { + else if (x11_init(&c->u.x11.s, ssh->cfg.x11_display, c, + ssh->x11auth, addrstr, port, + &ssh->cfg) != NULL) { error = "Unable to open an X11 connection"; } else { c->type = CHAN_X11; } + + sfree(addrstr); } else if (typelen == 15 && !memcmp(type, "forwarded-tcpip", 15)) { struct ssh_rportfwd pf, *realpf; @@ -5709,7 +5768,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) error = "Remote port is not recognised"; } else { char *e = pfd_newconnect(&c->u.pfd.s, realpf->dhost, - realpf->dport, c); + realpf->dport, c, &ssh->cfg); logeventf(ssh, "Received remote port open request" " for %s:%d", realpf->dhost, realpf->dport); if (e != NULL) { @@ -5764,7 +5823,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) /* * We have spare data. Add it to the channel buffer. */ - ssh2_add_channel_data(ssh->mainchan, in, inlen); + ssh2_add_channel_data(ssh->mainchan, (char *)in, inlen); s->try_send = TRUE; } if (s->try_send) { @@ -5774,7 +5833,10 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) * Try to send data on all channels if we can. */ for (i = 0; NULL != (c = index234(ssh->channels, i)); i++) { - int bufsize = ssh2_try_send(c); + int bufsize; + if (c->closes) + continue; /* don't send on closing channels */ + bufsize = ssh2_try_send(c); if (bufsize == 0) { switch (c->type) { case CHAN_MAINSESSION: @@ -5816,12 +5878,14 @@ static void ssh2_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) * Returns an error message, or NULL on success. */ static char *ssh_init(void *frontend_handle, void **backend_handle, + Config *cfg, char *host, int port, char **realhost, int nodelay) { char *p; Ssh ssh; ssh = smalloc(sizeof(*ssh)); + ssh->cfg = *cfg; /* STRUCTURE COPY */ ssh->s = NULL; ssh->cipher = NULL; ssh->v1_cipher_ctx = NULL; @@ -5882,8 +5946,11 @@ static char *ssh_init(void *frontend_handle, void **backend_handle, #endif ssh->frontend = frontend_handle; - ssh->term_width = cfg.width; - ssh->term_height = cfg.height; + ssh->term_width = ssh->cfg.width; + ssh->term_height = ssh->cfg.height; + + ssh->channels = NULL; + ssh->rportfwds = NULL; ssh->send_ok = 0; ssh->editing = 0; @@ -5892,6 +5959,8 @@ static char *ssh_init(void *frontend_handle, void **backend_handle, ssh->overall_bufsize = 0; ssh->fallback_cmd = 0; + ssh->protocol = NULL; + p = connect_to_host(ssh, host, port, realhost, nodelay); if (p != NULL) return p; @@ -5899,6 +5968,80 @@ static char *ssh_init(void *frontend_handle, void **backend_handle, return NULL; } +static void ssh_free(void *handle) +{ + Ssh ssh = (Ssh) handle; + struct ssh_channel *c; + struct ssh_rportfwd *pf; + + if (ssh->v1_cipher_ctx) + ssh->cipher->free_context(ssh->v1_cipher_ctx); + if (ssh->cs_cipher_ctx) + ssh->cscipher->free_context(ssh->cs_cipher_ctx); + if (ssh->sc_cipher_ctx) + ssh->sccipher->free_context(ssh->sc_cipher_ctx); + if (ssh->cs_mac_ctx) + ssh->csmac->free_context(ssh->cs_mac_ctx); + if (ssh->sc_mac_ctx) + ssh->scmac->free_context(ssh->sc_mac_ctx); + if (ssh->cs_comp_ctx) + ssh->cscomp->compress_cleanup(ssh->cs_comp_ctx); + if (ssh->sc_comp_ctx) + ssh->sccomp->compress_cleanup(ssh->sc_comp_ctx); + if (ssh->kex_ctx) + dh_cleanup(ssh->kex_ctx); + sfree(ssh->savedhost); + + if (ssh->channels) { + while ((c = delpos234(ssh->channels, 0)) != NULL) { + switch (c->type) { + case CHAN_X11: + if (c->u.x11.s != NULL) + x11_close(c->u.x11.s); + break; + case CHAN_SOCKDATA: + if (c->u.pfd.s != NULL) + pfd_close(c->u.pfd.s); + break; + } + sfree(c); + } + freetree234(ssh->channels); + } + + if (ssh->rportfwds) { + while ((pf = delpos234(ssh->rportfwds, 0)) != NULL) + sfree(pf); + freetree234(ssh->rportfwds); + } + sfree(ssh->deferred_send_data); + if (ssh->x11auth) + x11_free_auth(ssh->x11auth); + sfree(ssh->do_ssh_init_state); + sfree(ssh->do_ssh1_login_state); + sfree(ssh->do_ssh2_transport_state); + sfree(ssh->do_ssh2_authconn_state); + + if (ssh->s) + sk_close(ssh->s); + sfree(ssh); +} + +/* + * Reconfigure the SSH backend. + * + * Currently, this function does nothing very useful. In future, + * however, we could do some handy things with it. For example, we + * could make the port forwarding configurer active in the Change + * Settings box, and this routine could close down existing + * forwardings and open up new ones in response to changes. + */ +static void ssh_reconfig(void *handle, Config *cfg) +{ + Ssh ssh = (Ssh) handle; + ssh->cfg = *cfg; /* STRUCTURE COPY */ +} + /* * Called to send data down the Telnet connection. */ @@ -5909,7 +6052,7 @@ static int ssh_send(void *handle, char *buf, int len) if (ssh == NULL || ssh->s == NULL || ssh->protocol == NULL) return 0; - ssh->protocol(ssh, buf, len, 0); + ssh->protocol(ssh, (unsigned char *)buf, len, 0); return ssh_sendbuffer(ssh); } @@ -5965,7 +6108,7 @@ static void ssh_size(void *handle, int width, int height) ssh->size_needed = TRUE; /* buffer for later */ break; case SSH_STATE_SESSION: - if (!cfg.nopty) { + if (!ssh->cfg.nopty) { if (ssh->version == 1) { send_packet(ssh, SSH1_CMSG_WINDOW_SIZE, PKT_INT, ssh->term_height, @@ -6053,7 +6196,7 @@ void *new_sock_channel(void *handle, Socket s) * This is called when stdout/stderr (the entity to which * from_backend sends data) manages to clear some backlog. */ -void ssh_unthrottle(void *handle, int bufsize) +static void ssh_unthrottle(void *handle, int bufsize) { Ssh ssh = (Ssh) handle; if (ssh->version == 1) { @@ -6156,6 +6299,8 @@ extern int ssh_fallback_cmd(void *handle) Backend ssh_backend = { ssh_init, + ssh_free, + ssh_reconfig, ssh_send, ssh_sendbuffer, ssh_size,