X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=ssh.c;h=0815ff3241112a2d355fe6d83f1a2f297401c8a0;hb=44239efc6bd47006b53c1a853a60f02501d61c6e;hp=e92eb1d7738779cdf4e1aacc154c9097ff64597f;hpb=d77102a8d535a7000d6d909529a61a1564f6d678;p=PuTTY.git diff --git a/ssh.c b/ssh.c index e92eb1d7..0815ff32 100644 --- a/ssh.c +++ b/ssh.c @@ -516,15 +516,18 @@ struct ssh_rportfwd { * it. */ struct ssh_portfwd { - int keep; + enum { DESTROY, KEEP, CREATE } status; int type; unsigned sport, dport; char *saddr, *daddr; + char *sserv, *dserv; struct ssh_rportfwd *remote; + int addressfamily; void *local; }; #define free_portfwd(pf) ( \ - ((pf) ? (sfree((pf)->saddr), sfree((pf)->daddr)) : (void)0 ), sfree(pf) ) + ((pf) ? (sfree((pf)->saddr), sfree((pf)->daddr), \ + sfree((pf)->sserv), sfree((pf)->dserv)) : (void)0 ), sfree(pf) ) struct Packet { long length; @@ -863,6 +866,10 @@ static int ssh_portcmp(void *av, void *bv) return +1; if (a->type < b->type) return -1; + if (a->addressfamily > b->addressfamily) + return +1; + if (a->addressfamily < b->addressfamily) + return -1; if ( (i = nullstrcmp(a->saddr, b->saddr)) != 0) return i < 0 ? -1 : +1; if (a->sport > b->sport) @@ -2449,8 +2456,11 @@ static const char *connect_to_host(Ssh ssh, char *host, int port, /* * Try to find host. */ - logeventf(ssh, "Looking up host \"%s\"", host); - addr = name_lookup(host, port, realhost, &ssh->cfg); + logeventf(ssh, "Looking up host \"%s\"%s", host, + (ssh->cfg.addressfamily == ADDRTYPE_IPV4 ? " (IPv4)" : + (ssh->cfg.addressfamily == ADDRTYPE_IPV6 ? " (IPv6)" : ""))); + addr = name_lookup(host, port, realhost, &ssh->cfg, + ssh->cfg.addressfamily); if ((err = sk_addr_error(addr)) != NULL) { sk_addr_free(addr); return err; @@ -3666,32 +3676,45 @@ static void ssh_rportfwd_succfail(Ssh ssh, struct Packet *pktin, void *ctx) static void ssh_setup_portfwd(Ssh ssh, const Config *cfg) { - char type; - int n; - int sport,dport,sserv,dserv; - char sports[256], dports[256], saddr[256], host[256]; - const char *portfwd_strptr; - - portfwd_strptr = cfg->portfwd; + const char *portfwd_strptr = cfg->portfwd; + struct ssh_portfwd *epf; + int i; if (!ssh->portfwds) { ssh->portfwds = newtree234(ssh_portcmp); } else { /* * Go through the existing port forwardings and tag them - * with keep==FALSE. Any that we want to keep will be - * re-enabled as we go through the configuration and find - * out which bits are the same as they were before. + * with status==DESTROY. Any that we want to keep will be + * re-enabled (status==KEEP) as we go through the + * configuration and find out which bits are the same as + * they were before. */ struct ssh_portfwd *epf; int i; for (i = 0; (epf = index234(ssh->portfwds, i)) != NULL; i++) - epf->keep = FALSE; + epf->status = DESTROY; } while (*portfwd_strptr) { - type = *portfwd_strptr++; + char address_family, type; + int sport,dport,sserv,dserv; + char sports[256], dports[256], saddr[256], host[256]; + int n; + + address_family = 'A'; + type = 'L'; + if (*portfwd_strptr == 'A' || + *portfwd_strptr == '4' || + *portfwd_strptr == '6') + address_family = *portfwd_strptr++; + if (*portfwd_strptr == 'L' || + *portfwd_strptr == 'R' || + *portfwd_strptr == 'D') + type = *portfwd_strptr++; + saddr[0] = '\0'; + n = 0; while (*portfwd_strptr && *portfwd_strptr != '\t') { if (*portfwd_strptr == ':') { @@ -3759,61 +3782,152 @@ static void ssh_setup_portfwd(Ssh ssh, const Config *cfg) if (sport && dport) { /* Set up a description of the source port. */ struct ssh_portfwd *pfrec, *epfrec; - char *sportdesc; - sportdesc = dupprintf("%.*s%.*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, ")"); pfrec = snew(struct ssh_portfwd); pfrec->type = type; pfrec->saddr = *saddr ? dupstr(saddr) : NULL; + pfrec->sserv = sserv ? dupstr(sports) : NULL; pfrec->sport = sport; - pfrec->daddr = dupstr(host); + pfrec->daddr = *host ? dupstr(host) : NULL; + pfrec->dserv = dserv ? dupstr(dports) : NULL; pfrec->dport = dport; pfrec->local = NULL; pfrec->remote = NULL; + pfrec->addressfamily = (address_family == '4' ? ADDRTYPE_IPV4 : + address_family == '6' ? ADDRTYPE_IPV6 : + ADDRTYPE_UNSPEC); epfrec = add234(ssh->portfwds, pfrec); if (epfrec != pfrec) { /* * We already have a port forwarding with precisely * these parameters. Hence, no need to do anything; - * simply tag the existing one as `keep'. + * simply tag the existing one as KEEP. */ - epfrec->keep = TRUE; + epfrec->status = KEEP; free_portfwd(pfrec); - } else if (type == 'L') { - /* Verbose description of the destination port */ - char *dportdesc = dupprintf("%s:%.*s%.*s%d%.*s", - host, - (int)(dserv ? strlen(dports) : 0), dports, - dserv, "(", dport, dserv, ")"); - const char *err = pfd_addforward(host, dport, - *saddr ? saddr : NULL, - sport, ssh, &ssh->cfg, - &pfrec->local); - if (err) { - logeventf(ssh, "Local port %s forward to %s" - " failed: %s", sportdesc, dportdesc, err); + } else { + pfrec->status = CREATE; + } + } + } + + /* + * Now go through and destroy any port forwardings which were + * not re-enabled. + */ + for (i = 0; (epf = index234(ssh->portfwds, i)) != NULL; i++) + if (epf->status == DESTROY) { + char *message; + + message = dupprintf("%s port forwarding from %s%s%d", + epf->type == 'L' ? "local" : + epf->type == 'R' ? "remote" : "dynamic", + epf->saddr ? epf->saddr : "", + epf->saddr ? ":" : "", + epf->sport); + + if (epf->type != 'D') { + char *msg2 = dupprintf("%s to %s:%d", message, + epf->daddr, epf->dport); + sfree(message); + message = msg2; + } + + logeventf(ssh, "Cancelling %s", message); + sfree(message); + + if (epf->remote) { + struct ssh_rportfwd *rpf = epf->remote; + struct Packet *pktout; + + /* + * Cancel the port forwarding at the server + * end. + */ + if (ssh->version == 1) { + /* + * We cannot cancel listening ports on the + * server side in SSH1! There's no message + * to support it. Instead, we simply remove + * the rportfwd record from the local end + * so that any connections the server tries + * to make on it are rejected. + */ } else { - logeventf(ssh, "Local port %s forwarding to %s", - sportdesc, dportdesc); + pktout = ssh2_pkt_init(SSH2_MSG_GLOBAL_REQUEST); + ssh2_pkt_addstring(pktout, "cancel-tcpip-forward"); + ssh2_pkt_addbool(pktout, 0);/* _don't_ want reply */ + if (epf->saddr) { + ssh2_pkt_addstring(pktout, epf->saddr); + } else if (ssh->cfg.rport_acceptall) { + ssh2_pkt_addstring(pktout, "0.0.0.0"); + } else { + ssh2_pkt_addstring(pktout, "127.0.0.1"); + } + ssh2_pkt_adduint32(pktout, epf->sport); + ssh2_pkt_send(ssh, pktout); } - sfree(dportdesc); - } else if (type == 'D') { + + del234(ssh->rportfwds, rpf); + free_rportfwd(rpf); + } else if (epf->local) { + pfd_terminate(epf->local); + } + + delpos234(ssh->portfwds, i); + free_portfwd(epf); + i--; /* so we don't skip one in the list */ + } + + /* + * And finally, set up any new port forwardings (status==CREATE). + */ + for (i = 0; (epf = index234(ssh->portfwds, i)) != NULL; i++) + if (epf->status == CREATE) { + char *sportdesc, *dportdesc; + sportdesc = dupprintf("%s%s%s%s%d%s", + epf->saddr ? epf->saddr : "", + epf->saddr ? ":" : "", + epf->sserv ? epf->sserv : "", + epf->sserv ? "(" : "", + epf->sport, + epf->sserv ? ")" : ""); + if (epf->type == 'D') { + dportdesc = NULL; + } else { + dportdesc = dupprintf("%s:%s%s%d%s", + epf->daddr, + epf->dserv ? epf->dserv : "", + epf->dserv ? "(" : "", + epf->dport, + epf->dserv ? ")" : ""); + } + + if (epf->type == 'L') { + const char *err = pfd_addforward(epf->daddr, epf->dport, + epf->saddr, epf->sport, + ssh, &ssh->cfg, + &epf->local, + epf->addressfamily); + + logeventf(ssh, "Local %sport %s forwarding to %s%s%s", + epf->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " : + epf->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "", + sportdesc, dportdesc, + err ? " failed: " : "", err ? err : ""); + } else if (epf->type == 'D') { const char *err = pfd_addforward(NULL, -1, - *saddr ? saddr : NULL, - sport, ssh, &ssh->cfg, - &pfrec->local); - if (err) { - logeventf(ssh, "Local port %s SOCKS dynamic forward" - " setup failed: %s", sportdesc, err); - } else { - logeventf(ssh, "Local port %s doing SOCKS" - " dynamic forwarding", sportdesc); - } + epf->saddr, epf->sport, + ssh, &ssh->cfg, + &epf->local, + epf->addressfamily); + + logeventf(ssh, "Local %sport %s SOCKS dynamic forwarding%s%s", + epf->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " : + epf->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "", + sportdesc, + err ? " failed: " : "", err ? err : ""); } else { struct ssh_rportfwd *pf; @@ -3828,30 +3942,28 @@ static void ssh_setup_portfwd(Ssh ssh, const Config *cfg) } pf = snew(struct ssh_rportfwd); - strcpy(pf->dhost, host); - pf->dport = dport; - pf->sport = sport; + strncpy(pf->dhost, epf->daddr, lenof(pf->dhost)-1); + pf->dhost[lenof(pf->dhost)-1] = '\0'; + pf->dport = epf->dport; + pf->sport = epf->sport; if (add234(ssh->rportfwds, pf) != pf) { logeventf(ssh, "Duplicate remote port forwarding to %s:%d", - host, dport); + epf->daddr, epf->dport); sfree(pf); } else { logeventf(ssh, "Requesting remote port %s" - " forward to %s:%.*s%.*s%d%.*s", - sportdesc, host, - (int)(dserv ? strlen(dports) : 0), dports, - dserv, "(", dport, dserv, ")"); + " forward to %s", sportdesc, dportdesc); pf->sportdesc = sportdesc; sportdesc = NULL; - pfrec->remote = pf; - pf->pfrec = pfrec; + epf->remote = pf; + pf->pfrec = epf; if (ssh->version == 1) { send_packet(ssh, SSH1_CMSG_PORT_FORWARD_REQUEST, - PKT_INT, sport, - PKT_STR, host, - PKT_INT, dport, + PKT_INT, epf->sport, + PKT_STR, epf->daddr, + PKT_INT, epf->dport, PKT_END); ssh_queue_handler(ssh, SSH1_SMSG_SUCCESS, SSH1_SMSG_FAILURE, @@ -3861,14 +3973,14 @@ static void ssh_setup_portfwd(Ssh ssh, const Config *cfg) pktout = ssh2_pkt_init(SSH2_MSG_GLOBAL_REQUEST); ssh2_pkt_addstring(pktout, "tcpip-forward"); ssh2_pkt_addbool(pktout, 1);/* want reply */ - if (*saddr) { - ssh2_pkt_addstring(pktout, saddr); + if (epf->saddr) { + ssh2_pkt_addstring(pktout, epf->saddr); } else if (ssh->cfg.rport_acceptall) { ssh2_pkt_addstring(pktout, "0.0.0.0"); } else { ssh2_pkt_addstring(pktout, "127.0.0.1"); } - ssh2_pkt_adduint32(pktout, sport); + ssh2_pkt_adduint32(pktout, epf->sport); ssh2_pkt_send(ssh, pktout); ssh_queue_handler(ssh, SSH2_MSG_REQUEST_SUCCESS, @@ -3878,80 +3990,8 @@ static void ssh_setup_portfwd(Ssh ssh, const Config *cfg) } } sfree(sportdesc); + sfree(dportdesc); } - } - - /* - * Now go through and destroy any port forwardings which were - * not re-enabled. - */ - { - struct ssh_portfwd *epf; - int i; - for (i = 0; (epf = index234(ssh->portfwds, i)) != NULL; i++) - if (!epf->keep) { - char *message; - - message = dupprintf("%s port forwarding from %s%s%d", - epf->type == 'L' ? "local" : - epf->type == 'R' ? "remote" : "dynamic", - epf->saddr ? epf->saddr : "", - epf->saddr ? ":" : "", - epf->sport); - - if (epf->type != 'D') { - char *msg2 = dupprintf("%s to %s:%d", message, - epf->daddr, epf->dport); - sfree(message); - message = msg2; - } - - logeventf(ssh, "Cancelling %s", message); - sfree(message); - - if (epf->remote) { - struct ssh_rportfwd *rpf = epf->remote; - struct Packet *pktout; - - /* - * Cancel the port forwarding at the server - * end. - */ - if (ssh->version == 1) { - /* - * We cannot cancel listening ports on the - * server side in SSH1! There's no message - * to support it. Instead, we simply remove - * the rportfwd record from the local end - * so that any connections the server tries - * to make on it are rejected. - */ - } else { - pktout = ssh2_pkt_init(SSH2_MSG_GLOBAL_REQUEST); - ssh2_pkt_addstring(pktout, "cancel-tcpip-forward"); - ssh2_pkt_addbool(pktout, 0);/* _don't_ want reply */ - if (epf->saddr) { - ssh2_pkt_addstring(pktout, epf->saddr); - } else if (ssh->cfg.rport_acceptall) { - ssh2_pkt_addstring(pktout, "0.0.0.0"); - } else { - ssh2_pkt_addstring(pktout, "127.0.0.1"); - } - ssh2_pkt_adduint32(pktout, epf->sport); - ssh2_pkt_send(ssh, pktout); - } - - del234(ssh->rportfwds, rpf); - free_rportfwd(rpf); - } else if (epf->local) { - pfd_terminate(epf->local); - } - - delpos234(ssh->portfwds, i); - free_portfwd(epf); - i--; /* so we don't skip one in the list */ - } - } } static void ssh1_smsg_stdout_stderr_data(Ssh ssh, struct Packet *pktin) @@ -4045,7 +4085,7 @@ static void ssh1_msg_port_open(Ssh ssh, struct Packet *pktin) /* Remote side is trying to open a channel to talk to a * forwarded port. Give them back a local channel number. */ struct ssh_channel *c; - struct ssh_rportfwd pf; + struct ssh_rportfwd pf, *pfp; int remoteid; int hostsize, port; char *host, buf[1024]; @@ -4062,8 +4102,9 @@ static void ssh1_msg_port_open(Ssh ssh, struct Packet *pktin) memcpy(pf.dhost, host, hostsize); pf.dhost[hostsize] = '\0'; pf.dport = port; + pfp = find234(ssh->rportfwds, &pf, NULL); - if (find234(ssh->rportfwds, &pf, NULL) == NULL) { + if (pfp == NULL) { sprintf(buf, "Rejected remote port open request for %s:%d", pf.dhost, port); logevent(buf); @@ -4074,7 +4115,7 @@ static void ssh1_msg_port_open(Ssh ssh, struct Packet *pktin) pf.dhost, port); logevent(buf); e = pfd_newconnect(&c->u.pfd.s, pf.dhost, port, - c, &ssh->cfg); + c, &ssh->cfg, pfp->pfrec->addressfamily); if (e != NULL) { char buf[256]; sprintf(buf, "Port open failed: %s", e); @@ -4185,7 +4226,7 @@ static void ssh1_msg_channel_data(Ssh ssh, struct Packet *pktin) /* Data sent down one of our channels. */ int i = ssh_pkt_getuint32(pktin); char *p; - int len; + unsigned int len; struct ssh_channel *c; ssh_pkt_getstring(pktin, &p, &len); @@ -4204,7 +4245,7 @@ static void ssh1_msg_channel_data(Ssh ssh, struct Packet *pktin) /* Data for an agent message. Buffer it. */ while (len > 0) { if (c->u.a.lensofar < 4) { - int l = min(4 - c->u.a.lensofar, len); + unsigned int l = min(4 - c->u.a.lensofar, len); memcpy(c->u.a.msglen + c->u.a.lensofar, p, l); p += l; @@ -4219,7 +4260,7 @@ static void ssh1_msg_channel_data(Ssh ssh, struct Packet *pktin) memcpy(c->u.a.message, c->u.a.msglen, 4); } if (c->u.a.lensofar >= 4 && len > 0) { - int l = + unsigned int l = min(c->u.a.totallen - c->u.a.lensofar, len); memcpy(c->u.a.message + c->u.a.lensofar, p, @@ -5335,7 +5376,7 @@ static void ssh2_msg_channel_window_adjust(Ssh ssh, struct Packet *pktin) static void ssh2_msg_channel_data(Ssh ssh, struct Packet *pktin) { char *data; - int length; + unsigned int length; unsigned i = ssh_pkt_getuint32(pktin); struct ssh_channel *c; c = find234(ssh->channels, &i, ssh_channelfind); @@ -5364,7 +5405,7 @@ static void ssh2_msg_channel_data(Ssh ssh, struct Packet *pktin) case CHAN_AGENT: while (length > 0) { if (c->u.a.lensofar < 4) { - int l = min(4 - c->u.a.lensofar, length); + unsigned int l = min(4 - c->u.a.lensofar, length); memcpy(c->u.a.msglen + c->u.a.lensofar, data, l); data += l; @@ -5379,7 +5420,7 @@ static void ssh2_msg_channel_data(Ssh ssh, struct Packet *pktin) memcpy(c->u.a.message, c->u.a.msglen, 4); } if (c->u.a.lensofar >= 4 && length > 0) { - int l = + unsigned int l = min(c->u.a.totallen - c->u.a.lensofar, length); memcpy(c->u.a.message + c->u.a.lensofar, @@ -5799,7 +5840,8 @@ static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin) const char *e = pfd_newconnect(&c->u.pfd.s, realpf->dhost, realpf->dport, c, - &ssh->cfg); + &ssh->cfg, + realpf->pfrec->addressfamily); logeventf(ssh, "Attempting to forward remote port to " "%s:%d", realpf->dhost, realpf->dport); if (e != NULL) { @@ -7338,6 +7380,7 @@ static const char *ssh_init(void *frontend_handle, void **backend_handle, ssh->channels = NULL; ssh->rportfwds = NULL; + ssh->portfwds = NULL; ssh->send_ok = 0; ssh->editing = 0; @@ -7793,7 +7836,7 @@ void ssh_send_port_open(void *channel, char *hostname, int port, char *org) PKT_INT, c->localid, PKT_STR, hostname, PKT_INT, port, - //PKT_STR, , + /* PKT_STR, , */ PKT_END); } else { pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN); @@ -7859,6 +7902,16 @@ static int ssh_return_exitcode(void *handle) return (ssh->exitcode >= 0 ? ssh->exitcode : 0); } +/* + * cfg_info for SSH is the currently running version of the + * protocol. (1 for 1; 2 for 2; 0 for not-decided-yet.) + */ +static int ssh_cfg_info(void *handle) +{ + Ssh ssh = (Ssh) handle; + return ssh->version; +} + /* * Gross hack: pscp will try to start SFTP but fall back to scp1 if * that fails. This variable is the means by which scp.c can reach @@ -7886,5 +7939,6 @@ Backend ssh_backend = { ssh_provide_ldisc, ssh_provide_logctx, ssh_unthrottle, + ssh_cfg_info, 22 };