X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/1ece9da72e9dd60b598bc8e2958ddc3ef8094d28..d74d141c2daed084c8a62c5dc5b88e801b81ee5a:/ssh.c diff --git a/ssh.c b/ssh.c index a41e3bf4..cbcf439f 100644 --- a/ssh.c +++ b/ssh.c @@ -196,6 +196,12 @@ extern void x11_close(Socket); extern void x11_send(Socket, char *, int); extern void x11_invent_auth(char *, int, char *, int); +extern char *pfd_newconnect(Socket * s, char *hostname, int port, void *c); +extern char *pfd_addforward(char *desthost, int destport, int port); +extern void pfd_close(Socket s); +extern void pfd_send(Socket s, char *data, int len); +extern void pfd_confirm(Socket s); + /* * Ciphers for SSH2. We miss out single-DES because it isn't * supported; also 3DES and Blowfish are both done differently from @@ -263,6 +269,7 @@ enum { /* channel types */ CHAN_MAINSESSION, CHAN_X11, CHAN_AGENT, + CHAN_SOCKDATA }; /* @@ -286,9 +293,22 @@ struct ssh_channel { struct ssh_x11_channel { Socket s; } x11; + struct ssh_pfd_channel { + Socket s; + } pfd; } u; }; +/* + * 2-3-4 tree storing remote->local port forwardings (so we can + * reject any attempt to open a port we didn't explicitly ask to + * have forwarded). + */ +struct ssh_rportfwd { + unsigned port; + char host[256]; +}; + struct Packet { long length; int type; @@ -330,6 +350,8 @@ static int ssh_echoing, ssh_editing; static tree234 *ssh_channels; /* indexed by local id */ static struct ssh_channel *mainchan; /* primary session channel */ +static tree234 *ssh_rportfwds; + static enum { SSH_STATE_PREPACKET, SSH_STATE_BEFORE_SIZE, @@ -393,6 +415,18 @@ static int ssh_channelfind(void *av, void *bv) return 0; } +static int ssh_rportcmp(void *av, void *bv) +{ + struct ssh_rportfwd *a = (struct ssh_rportfwd *) av; + struct ssh_rportfwd *b = (struct ssh_rportfwd *) bv; + int i; + if ( (i = strcmp(a->host, b->host)) != 0) + return i < 0 ? -1 : +1; + if (a->port > b->port) + return +1; + return 0; +} + static int alloc_channel_id(void) { const unsigned CHANNEL_NUMBER_OFFSET = 256; @@ -2263,7 +2297,10 @@ void sshfwd_close(struct ssh_channel *c) c->closes = 1; if (c->type == CHAN_X11) { c->u.x11.s = NULL; - logevent("X11 connection terminated"); + logevent("Forwarded X11 connection terminated"); + } else if (c->type == CHAN_SOCKDATA) { + c->u.pfd.s = NULL; + logevent("Forwarded port closed"); } } } @@ -2337,6 +2374,68 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt) } } + { + char type, *e; + int n; + int sport,dport; + char sports[256], dports[256], host[256]; + char buf[1024]; + + ssh_rportfwds = newtree234(ssh_rportcmp); + /* Add port forwardings. */ + e = cfg.portfwd; + while (*e) { + type = *e++; + n = 0; + while (*e && *e != '\t') + sports[n++] = *e++; + sports[n] = 0; + if (*e == '\t') + e++; + n = 0; + while (*e && *e != ':') + host[n++] = *e++; + host[n] = 0; + if (*e == ':') + e++; + n = 0; + while (*e) + dports[n++] = *e++; + dports[n] = 0; + e++; + dport = atoi(dports); + sport = atoi(sports); + if (sport && dport) { + if (type == 'L') { + pfd_addforward(host, dport, sport); + sprintf(buf, "Local port %d forwarding to %s:%d", + sport, host, dport); + logevent(buf); + } else { + struct ssh_rportfwd *pf; + pf = smalloc(sizeof(*pf)); + strcpy(pf->host, host); + pf->port = dport; + if (add234(ssh_rportfwds, pf) != pf) { + sprintf(buf, + "Duplicate remote port forwarding to %s:%s", + host, dport); + logevent(buf); + } else { + sprintf(buf, "Requesting remote port %d forward to %s:%d", + sport, host, dport); + logevent(buf); + send_packet(SSH1_CMSG_PORT_FORWARD_REQUEST, + PKT_INT, sport, + PKT_STR, host, + PKT_INT, dport, + PKT_END); + } + } + } + } + } + if (!cfg.nopty) { send_packet(SSH1_CMSG_REQUEST_PTY, PKT_STR, cfg.termtype, @@ -2460,6 +2559,73 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt) PKT_INT, c->remoteid, PKT_INT, c->localid, PKT_END); } + } else if (pktin.type == SSH1_MSG_PORT_OPEN) { + /* 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; + int hostsize, port; + char host[256], buf[1024]; + char *p, *h, *e; + c = smalloc(sizeof(struct ssh_channel)); + + hostsize = GET_32BIT(pktin.body+4); + for(h = host, p = pktin.body+8; hostsize != 0; hostsize--) { + if (h+1 < host+sizeof(host)) + *h++ = *p; + *p++; + } + *h = 0; + port = GET_32BIT(p); + + strcpy(pf.host, host); + pf.port = port; + + if (find234(ssh_rportfwds, &pf, NULL) == NULL) { + sprintf(buf, "Rejected remote port open request for %s:%d", + host, port); + logevent(buf); + send_packet(SSH1_MSG_CHANNEL_OPEN_FAILURE, + PKT_INT, GET_32BIT(pktin.body), PKT_END); + } else { + sprintf(buf, "Received remote port open request for %s:%d", + host, port); + logevent(buf); + e = pfd_newconnect(&c->u.pfd.s, host, port, c); + if (e != NULL) { + char buf[256]; + sprintf(buf, "Port open failed: %s", e); + logevent(buf); + sfree(c); + send_packet(SSH1_MSG_CHANNEL_OPEN_FAILURE, + PKT_INT, GET_32BIT(pktin.body), + PKT_END); + } else { + c->remoteid = GET_32BIT(pktin.body); + c->localid = alloc_channel_id(); + c->closes = 0; + c->type = CHAN_SOCKDATA; /* identify channel type */ + add234(ssh_channels, c); + send_packet(SSH1_MSG_CHANNEL_OPEN_CONFIRMATION, + PKT_INT, c->remoteid, PKT_INT, + c->localid, PKT_END); + logevent("Forwarded port opened successfully"); + } + } + + } else if (pktin.type == SSH1_MSG_CHANNEL_OPEN_CONFIRMATION) { + unsigned int remoteid = GET_32BIT(pktin.body); + unsigned int localid = GET_32BIT(pktin.body+4); + struct ssh_channel *c; + + c = find234(ssh_channels, &remoteid, ssh_channelfind); + if (c) { + c->remoteid = localid; + pfd_confirm(c->u.pfd.s); + } else { + sshfwd_close(c); + } + } else if (pktin.type == SSH1_MSG_CHANNEL_CLOSE || pktin.type == SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION) { /* Remote side closes a channel. */ @@ -2474,11 +2640,17 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt) send_packet(pktin.type, PKT_INT, c->remoteid, PKT_END); if ((c->closes == 0) && (c->type == CHAN_X11)) { - logevent("X11 connection closed"); + logevent("Forwarded X11 connection terminated"); assert(c->u.x11.s != NULL); x11_close(c->u.x11.s); c->u.x11.s = NULL; } + if ((c->closes == 0) && (c->type == CHAN_SOCKDATA)) { + logevent("Forwarded port closed"); + assert(c->u.pfd.s != NULL); + pfd_close(c->u.pfd.s); + c->u.pfd.s = NULL; + } c->closes |= closetype; if (c->closes == 3) { del234(ssh_channels, c); @@ -2497,6 +2669,9 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt) case CHAN_X11: x11_send(c->u.x11.s, p, len); break; + case CHAN_SOCKDATA: + pfd_send(c->u.pfd.s, p, len); + break; case CHAN_AGENT: /* Data for an agent message. Buffer it. */ while (len > 0) { @@ -3976,6 +4151,9 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt) case CHAN_X11: x11_send(c->u.x11.s, data, length); break; + case CHAN_SOCKDATA: + pfd_send(c->u.pfd.s, data, length); + break; case CHAN_AGENT: while (length > 0) { if (c->u.a.lensofar < 4) { @@ -4059,6 +4237,9 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt) sshfwd_close(c); } else if (c->type == CHAN_AGENT) { sshfwd_close(c); + } else if (c->type == CHAN_SOCKDATA) { + pfd_close(c->u.pfd.s); + sshfwd_close(c); } } else if (pktin.type == SSH2_MSG_CHANNEL_CLOSE) { unsigned i = ssh2_pkt_getuint32(); @@ -4080,6 +4261,8 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt) break; case CHAN_AGENT: break; + case CHAN_SOCKDATA: + break; } del234(ssh_channels, c); sfree(c->v2.outbuffer); @@ -4306,6 +4489,39 @@ static void ssh_special(Telnet_Special code) } } +void *new_sock_channel(Socket s) +{ + struct ssh_channel *c; + c = smalloc(sizeof(struct ssh_channel)); + + if (c) { + c->remoteid = GET_32BIT(pktin.body); + c->localid = alloc_channel_id(); + c->closes = 0; + c->type = CHAN_SOCKDATA; /* identify channel type */ + c->u.pfd.s = s; + add234(ssh_channels, c); + } + return c; +} + +void ssh_send_port_open(void *channel, char *hostname, int port, char *org) +{ + struct ssh_channel *c = (struct ssh_channel *)channel; + char buf[1024]; + + sprintf(buf, "Opening forwarded connection to %.512s:%d", hostname, port); + logevent(buf); + + send_packet(SSH1_MSG_PORT_OPEN, + PKT_INT, c->localid, + PKT_STR, hostname, + PKT_INT, port, + //PKT_STR, org, + PKT_END); +} + + static Socket ssh_socket(void) { return s; @@ -4334,4 +4550,4 @@ Backend ssh_backend = { ssh_sendok, ssh_ldisc, 22 -}; +}; \ No newline at end of file