diff -ru putty-src20110216/CMDLINE.C putty-src20110216p/CMDLINE.C --- putty-src20110216/CMDLINE.C 2010-12-23 17:32:28.000000000 +0100 +++ putty-src20110216p/CMDLINE.C 2011-02-16 00:46:34.029296800 +0100 @@ -266,9 +266,9 @@ * this means we must find the second-to-last colon in * the string. */ - q = qq = strchr(ptr, ':'); + q = qq = strcolon(ptr); while (qq) { - char *qqq = strchr(qq+1, ':'); + char *qqq = strcolon(qq+1); if (qqq) q = qq; qq = qqq; @@ -287,9 +287,8 @@ SAVEABLE(0); host = portp = value; - while (*portp && *portp != ':') - portp++; - if (*portp) { + portp = strcolon(portp); + if (portp && *portp && !strcolon(portp+1)) { unsigned len = portp - host; if (len >= sizeof(cfg->ssh_nc_host)) len = sizeof(cfg->ssh_nc_host) - 1; diff -ru putty-src20110216/LOGGING.C putty-src20110216p/LOGGING.C --- putty-src20110216/LOGGING.C 2009-08-30 13:09:22.000000000 +0200 +++ putty-src20110216p/LOGGING.C 2011-02-16 00:46:34.035156200 +0100 @@ -29,7 +29,8 @@ * isn't open, buffering data if it's in the process of being * opened asynchronously, etc. */ -static void logwrite(struct LogContext *ctx, void *data, int len) +static void logwrite(struct LogContext *ctx, void *data, size_t len) + { /* * In state L_CLOSED, we call logfopen, which will set the state @@ -126,7 +127,7 @@ assert(ctx->state != L_OPENING); /* make _sure_ it won't be requeued */ while (bufchain_size(&ctx->queue)) { void *data; - int len; + size_t len; bufchain_prefix(&ctx->queue, &data, &len); logwrite(ctx, data, len); bufchain_consume(&ctx->queue, len); diff -ru putty-src20110216/MISC.C putty-src20110216p/MISC.C --- putty-src20110216/MISC.C 2009-01-04 22:24:08.000000000 +0100 +++ putty-src20110216p/MISC.C 2011-02-16 01:14:51.395507800 +0100 @@ -653,3 +653,73 @@ else return cfg->host; } + +char *strcolon(char *str) +{ + while (*str) { + if (*str == '[') { + /* Skip over IPv6 literal addresses */ + char *ipv6_end = strchr(str, ']'); + if (ipv6_end) { + str = ipv6_end; + } + } + if (*str == ':') + return (char *)str; + str++; + } + return NULL; +} + +/* + * Find a colon in str and return a pointer to the colon. + * This is used to separate hostname from filename. + */ +char *colon(char *str) +{ + /* We ignore a leading colon, since the hostname cannot be + empty. We also ignore a colon as second character because + of filenames like f:myfile.txt. */ + if (str[0] == '\0' || str[0] == ':' || + (str[0] != '[' && str[1] == ':')) + return (NULL); + while (*str != '\0' && *str != ':' && *str != '/' && *str != '\\') { + if (*str == '[') { + /* Skip over IPv6 literal addresses + * (eg: 'jeroen@[2001:db8::1]:myfile.txt') */ + char *ipv6_end = strchr(str, ']'); + if (ipv6_end) { + str = ipv6_end; + } + } + str++; + } + if (*str == ':') + return (str); + else + return (NULL); +} + +/* + * Return a pointer to the portion of str that comes after the last + * slash (or backslash or colon, if `local' is TRUE). + */ +char *stripslashes(char *str, int local) +{ + char *p; + + if (local) { + p = strchr(str, ':'); + if (p) str = p+1; + } + + p = strrchr(str, '/'); + if (p) str = p+1; + + if (local) { + p = strrchr(str, '\\'); + if (p) str = p+1; + } + + return str; +} diff -ru putty-src20110216/MISC.H putty-src20110216p/MISC.H --- putty-src20110216/MISC.H 2006-04-23 20:26:04.000000000 +0200 +++ putty-src20110216p/MISC.H 2011-02-16 00:46:34.042968700 +0100 @@ -29,6 +29,10 @@ char *dupprintf(const char *fmt, ...); char *dupvprintf(const char *fmt, va_list ap); +char *strcolon(char *str); +char *colon(char *str); +char *stripslashes(char *str, int local); + char *fgetline(FILE *fp); void base64_encode_atom(unsigned char *data, int n, char *out); diff -ru putty-src20110216/NETWORK.H putty-src20110216p/NETWORK.H --- putty-src20110216/NETWORK.H 2009-02-24 01:01:24.000000000 +0100 +++ putty-src20110216p/NETWORK.H 2011-02-16 00:46:34.046875000 +0100 @@ -115,6 +115,7 @@ SockAddr sk_namelookup(const char *host, char **canonicalname, int address_family); SockAddr sk_nonamelookup(const char *host); void sk_getaddr(SockAddr addr, char *buf, int buflen); +char *sk_inet_ntop(int af, void *src, char *dst, int cnt); int sk_hostname_is_local(char *name); int sk_address_is_local(SockAddr addr); int sk_addrtype(SockAddr addr); diff -ru putty-src20110216/PORTFWD.C putty-src20110216p/PORTFWD.C --- putty-src20110216/PORTFWD.C 2009-04-23 19:33:42.000000000 +0200 +++ putty-src20110216p/PORTFWD.C 2011-02-16 00:46:34.051757800 +0100 @@ -199,7 +199,7 @@ /* * We're receiving a SOCKS request. */ - unsigned char reply[10]; /* SOCKS5 atyp=1 reply */ + unsigned char reply[23]; /* SOCKS5 atyp=1 reply */ int atype, alen = 0; /* @@ -220,7 +220,10 @@ if (atype == 4) /* IPv6 address */ alen = 16; if (atype == 3) /* domain name has leading length */ + { alen = 1 + (unsigned char)pr->hostname[4]; + reply[3] = 3; /* ATYP = 4 (IPv6, [::0]:0) */ + } if (pr->port < 6 + alen) continue; if (pr->hostname[1] != 1 || pr->hostname[2] != 0) { /* Not CONNECT or reserved field nonzero - error */ @@ -249,9 +252,24 @@ memmove(pr->hostname, pr->hostname + 5, alen-1); pr->hostname[alen-1] = '\0'; goto connect; + } else if (atype == 4) { /* IPv6 address */ + /* REP=0 (success) already */ + sk_write(pr->s, (char *) reply, lenof(reply)); + { +#define INET6_ADDRSTRLEN 65 + unsigned char dest_addr[255+1]; + unsigned int addrlen, af; + + addrlen = 16; + af = AF_INET6; + memcpy(&dest_addr, &pr->hostname[4], addrlen); + if (sk_inet_ntop(af, dest_addr, pr->hostname, sizeof(pr->hostname)) == NULL) + return 1; + } + goto connect; } else { /* - * Unknown address type. (FIXME: support IPv6!) + * Unknown address type. */ reply[1] = 8; /* atype not supported */ sk_write(pr->s, (char *) reply, lenof(reply)); diff -ru putty-src20110216/PSCP.C putty-src20110216p/PSCP.C --- putty-src20110216/PSCP.C 2009-08-07 02:19:04.000000000 +0200 +++ putty-src20110216p/PSCP.C 2011-02-16 00:46:34.058593700 +0100 @@ -538,59 +538,6 @@ } /* - * Find a colon in str and return a pointer to the colon. - * This is used to separate hostname from filename. - */ -static char *colon(char *str) -{ - /* We ignore a leading colon, since the hostname cannot be - empty. We also ignore a colon as second character because - of filenames like f:myfile.txt. */ - if (str[0] == '\0' || str[0] == ':' || - (str[0] != '[' && str[1] == ':')) - return (NULL); - while (*str != '\0' && *str != ':' && *str != '/' && *str != '\\') { - if (*str == '[') { - /* Skip over IPv6 literal addresses - * (eg: 'jeroen@[2001:db8::1]:myfile.txt') */ - char *ipv6_end = strchr(str, ']'); - if (ipv6_end) { - str = ipv6_end; - } - } - str++; - } - if (*str == ':') - return (str); - else - return (NULL); -} - -/* - * Return a pointer to the portion of str that comes after the last - * slash (or backslash or colon, if `local' is TRUE). - */ -static char *stripslashes(char *str, int local) -{ - char *p; - - if (local) { - p = strchr(str, ':'); - if (p) str = p+1; - } - - p = strrchr(str, '/'); - if (p) str = p+1; - - if (local) { - p = strrchr(str, '\\'); - if (p) str = p+1; - } - - return str; -} - -/* * Determine whether a string is entirely composed of dots. */ static int is_dots(char *str) diff -ru putty-src20110216/PSFTP.C putty-src20110216p/PSFTP.C --- putty-src20110216/PSFTP.C 2009-08-07 02:19:04.000000000 +0200 +++ putty-src20110216p/PSFTP.C 2011-02-16 00:46:34.063476500 +0100 @@ -151,30 +151,6 @@ } /* - * Return a pointer to the portion of str that comes after the last - * slash (or backslash or colon, if `local' is TRUE). - */ -static char *stripslashes(char *str, int local) -{ - char *p; - - if (local) { - p = strchr(str, ':'); - if (p) str = p+1; - } - - p = strrchr(str, '/'); - if (p) str = p+1; - - if (local) { - p = strrchr(str, '\\'); - if (p) str = p+1; - } - - return str; -} - -/* * qsort comparison routine for fxp_name structures. Sorts by real * file name. */ @@ -2727,11 +2703,21 @@ } } - /* - * Trim a colon suffix off the hostname if it's there. - */ - cfg.host[strcspn(cfg.host, ":")] = '\0'; - + /* + * Trim a colon suffix off the hostname if it's there. + * In order to protect IPv6 address literals against this + * treatment, we do not do this if there's _more_ than one + * colon. + */ + { + char *c = strcolon(cfg.host); + if (c) { + char *d = strchr(c+1, ':'); + if (!d) + *c = '\0'; + } + } + /* * Remove any remaining whitespace from the hostname. */ diff -ru putty-src20110216/RAW.C putty-src20110216p/RAW.C --- putty-src20110216/RAW.C 2008-06-01 13:16:32.000000000 +0200 +++ putty-src20110216p/RAW.C 2011-02-16 00:46:34.067382800 +0100 @@ -146,12 +146,9 @@ *realhost = dupstr(cfg->loghost); colon = strrchr(*realhost, ':'); if (colon) { - /* - * FIXME: if we ever update this aspect of ssh.c for - * IPv6 literal management, this should change in line - * with it. - */ - *colon++ = '\0'; + char *d = strchr(colon+1, ':'); + if (!d) + *colon++ = '\0'; } } diff -ru putty-src20110216/RLOGIN.C putty-src20110216p/RLOGIN.C --- putty-src20110216/RLOGIN.C 2008-11-24 17:51:42.000000000 +0100 +++ putty-src20110216p/RLOGIN.C 2011-02-16 00:46:34.069335900 +0100 @@ -206,12 +206,9 @@ *realhost = dupstr(cfg->loghost); colon = strrchr(*realhost, ':'); if (colon) { - /* - * FIXME: if we ever update this aspect of ssh.c for - * IPv6 literal management, this should change in line - * with it. - */ - *colon++ = '\0'; + char *d = strchr(colon+1, ':'); + if (!d) + *colon++ = '\0'; } } diff -ru putty-src20110216/SSH.C putty-src20110216p/SSH.C --- putty-src20110216/SSH.C 2011-01-03 16:50:42.000000000 +0100 +++ putty-src20110216p/SSH.C 2011-02-16 00:46:34.085937500 +0100 @@ -2903,7 +2903,11 @@ if (type == 0) msg = dupprintf("Connecting to %s port %d", addrbuf, port); else - msg = dupprintf("Failed to connect to %s: %s", addrbuf, error_msg); + msg = dupprintf("Failed to connect to %s%s%s:%d : %s", + strchr(addrbuf, ':')? "[" : "", + addrbuf, + strchr(addrbuf, ':')? "]" : "", + port, error_msg); logevent(msg); sfree(msg); @@ -2987,9 +2991,9 @@ * A colon suffix on savedhost also lets us affect * savedport. * - * (FIXME: do something about IPv6 address literals here.) */ - colon = strrchr(ssh->savedhost, ':'); + colon = strcolon(ssh->savedhost); + if (colon) { *colon++ = '\0'; if (*colon) @@ -4390,6 +4394,7 @@ int sport,dport,sserv,dserv; char sports[256], dports[256], saddr[256], host[256]; int n; + int no_ipv6_lit; address_family = 'A'; type = 'L'; @@ -4405,8 +4410,18 @@ saddr[0] = '\0'; n = 0; + no_ipv6_lit = 1; /* No IPv6 literal addresses yet */ while (*portfwd_strptr && *portfwd_strptr != '\t') { - if (*portfwd_strptr == ':') { + /* IPv6 literal addresses */ + if (*portfwd_strptr == '[') { + portfwd_strptr++; + no_ipv6_lit = 0; /* IPv6 literal addresses yet, wait for ']' */ + } + if (*portfwd_strptr == ']') { + portfwd_strptr++; + no_ipv6_lit = 1; /* IPv6 literal addresses yet, wait for ']' */ + } + if ( (no_ipv6_lit) && (*portfwd_strptr == ':') ) { /* * We've seen a colon in the middle of the * source port number. This means that @@ -4431,10 +4446,22 @@ if (*portfwd_strptr == '\t') portfwd_strptr++; n = 0; + if (*portfwd_strptr == '[') { + /* IPv6 literal addresses ? */ + portfwd_strptr++; /* Skip '[' */ + while (*portfwd_strptr && *portfwd_strptr != ']') { + if (n < lenof(host)-1) host[n++] = *portfwd_strptr++; + } + } else { while (*portfwd_strptr && *portfwd_strptr != ':') { if (n < lenof(host)-1) host[n++] = *portfwd_strptr++; } + } host[n] = 0; + + if (*portfwd_strptr == ']') /* Skip ']' */ + portfwd_strptr++; + if (*portfwd_strptr == ':') portfwd_strptr++; n = 0; @@ -4518,16 +4545,21 @@ if (epf->status == DESTROY) { char *message; - message = dupprintf("%s port forwarding from %s%s%d", + message = dupprintf("%s port forwarding from %s%s%s%s%d", epf->type == 'L' ? "local" : epf->type == 'R' ? "remote" : "dynamic", + strchr(epf->saddr ? epf->saddr : "", ':')? "[" : "", epf->saddr ? epf->saddr : "", + strchr(epf->saddr ? epf->saddr : "", ':')? "]" : "", epf->saddr ? ":" : "", epf->sport); if (epf->type != 'D') { char *msg2 = dupprintf("%s to %s:%d", message, - epf->daddr, epf->dport); + strchr(epf->daddr, ':')? "[" : "", + epf->daddr, + strchr(epf->daddr, ':')? "]" : "", + epf->dport); sfree(message); message = msg2; } @@ -4564,7 +4596,18 @@ /* XXX: ssh->cfg.rport_acceptall may not represent * what was used to open the original connection, * since it's reconfigurable. */ - ssh2_pkt_addstring(pktout, "0.0.0.0"); +#ifdef NO_IPV6 + ssh2_pkt_addstring(pktout, "0.0.0.0"); +#else + if (strchr(epf->saddr, ':')) + { + ssh2_pkt_addstring(pktout, "::"); + } + else + { + ssh2_pkt_addstring(pktout, "0.0.0.0"); + } +#endif } else { ssh2_pkt_addstring(pktout, "127.0.0.1"); } @@ -4589,8 +4632,10 @@ 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", + sportdesc = dupprintf("%s%s%s%s%s%s%d%s", + strchr( (epf->saddr ? epf->saddr : ""), ':')? "[" : "", epf->saddr ? epf->saddr : "", + strchr( (epf->saddr ? epf->saddr : ""), ':')? "]" : "", epf->saddr ? ":" : "", epf->sserv ? epf->sserv : "", epf->sserv ? "(" : "", @@ -4599,8 +4644,10 @@ if (epf->type == 'D') { dportdesc = NULL; } else { - dportdesc = dupprintf("%s:%s%s%d%s", + dportdesc = dupprintf("%s%s%s:%s%s%d%s", + strchr(epf->daddr, ':')? "[" : "", epf->daddr, + strchr(epf->daddr, ':')? "]" : "", epf->dserv ? epf->dserv : "", epf->dserv ? "(" : "", epf->dport, @@ -4650,13 +4697,19 @@ pf->dport = epf->dport; pf->sport = epf->sport; if (add234(ssh->rportfwds, pf) != pf) { - logeventf(ssh, "Duplicate remote port forwarding to %s:%d", - epf->daddr, epf->dport); + logeventf(ssh, "Duplicate remote port forwarding to %s%s%s:%d", + strchr(epf->daddr, ':')? "[" : "", + epf->daddr, + strchr(epf->daddr, ':')? "]" : "", + epf->dport); sfree(pf); } else { - logeventf(ssh, "Requesting remote port %s" - " forward to %s", sportdesc, dportdesc); - + logeventf(ssh, "Requesting %s remote port %s" + " forward to %s", + epf->addressfamily == ADDRTYPE_IPV4 ? "IPv4" : + epf->addressfamily == ADDRTYPE_IPV6 ? "IPv6" : "", + sportdesc, dportdesc); + pf->sportdesc = sportdesc; sportdesc = NULL; epf->remote = pf; @@ -4679,9 +4732,27 @@ if (epf->saddr) { ssh2_pkt_addstring(pktout, epf->saddr); } else if (cfg->rport_acceptall) { +#ifdef NO_IPV6 ssh2_pkt_addstring(pktout, "0.0.0.0"); +#else + if (strchr(epf->saddr, ':')) + { + ssh2_pkt_addstring(pktout, "::"); + } + else + { + ssh2_pkt_addstring(pktout, "0.0.0.0"); + } +#endif } else { + if (strchr(epf->saddr, ':')) + { + ssh2_pkt_addstring(pktout, "::1"); + } + else + { ssh2_pkt_addstring(pktout, "127.0.0.1"); + } } ssh2_pkt_adduint32(pktout, epf->sport); ssh2_pkt_send(ssh, pktout); @@ -4812,13 +4883,19 @@ pfp = find234(ssh->rportfwds, &pf, NULL); if (pfp == NULL) { - logeventf(ssh, "Rejected remote port open request for %s:%d", - pf.dhost, port); + logeventf(ssh, "Rejected remote port open request for %s%s%s:%d", + strchr(pf.dhost, ':')? "[" : "", + pf.dhost, + strchr(pf.dhost, ':')? "]" : "", + port); send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE, PKT_INT, remoteid, PKT_END); } else { - logeventf(ssh, "Received remote port open request for %s:%d", - pf.dhost, port); + logeventf(ssh, "Received remote port open request for %s%s%s:%d", + strchr(pf.dhost, ':')? "[" : "", + pf.dhost, + strchr(pf.dhost, ':')? "]" : "", + port); e = pfd_newconnect(&c->u.pfd.s, pf.dhost, port, c, &ssh->cfg, pfp->pfrec->addressfamily); if (e != NULL) { @@ -7112,8 +7189,11 @@ addrstr[peeraddrlen] = '\0'; peerport = ssh_pkt_getuint32(pktin); - logeventf(ssh, "Received X11 connect request from %s:%d", - addrstr, peerport); + logeventf(ssh, "Received X11 connect request from %s%s%s:%d", + strchr(addrstr, ':')? "[" : "", + addrstr, + strchr(addrstr, ':')? "[" : "", + peerport); if (!ssh->X11_fwd_enabled) error = "X11 forwarding is not enabled"; @@ -7137,8 +7217,13 @@ ssh_pkt_getstring(pktin, &peeraddr, &peeraddrlen); peerport = ssh_pkt_getuint32(pktin); realpf = find234(ssh->rportfwds, &pf, NULL); - logeventf(ssh, "Received remote port %d open request " - "from %s:%d", pf.sport, peeraddr, peerport); + logeventf(ssh, "Received remote port %d open request " + "from %s%s%s:%d", + pf.sport, + strchr(peeraddr, ':')? "[" : "", + peeraddr, + strchr(peeraddr, ':')? "]" : "", + peerport); if (realpf == NULL) { error = "Remote port is not recognised"; } else { @@ -7148,7 +7233,11 @@ &ssh->cfg, realpf->pfrec->addressfamily); logeventf(ssh, "Attempting to forward remote port to " - "%s:%d", realpf->dhost, realpf->dport); + "%s%s%s:%d", + strchr(realpf->dhost, ':')? "[" : "", + realpf->dhost, + strchr(realpf->dhost, ':')? "]" : "", + realpf->dport); if (e != NULL) { logeventf(ssh, "Port open failed: %s", e); error = "Port open failed"; @@ -8619,8 +8708,11 @@ ssh->mainchan->ssh = ssh; ssh2_channel_init(ssh->mainchan); logeventf(ssh, - "Opening direct-tcpip channel to %s:%d in place of session", - ssh->cfg.ssh_nc_host, ssh->cfg.ssh_nc_port); + "Opening direct-tcpip channel to %s%s%s:%d in place of session", + strchr(ssh->cfg.ssh_nc_host, ':')? "[" : "", + ssh->cfg.ssh_nc_host, + strchr(ssh->cfg.ssh_nc_host, ':')? "]" : "", + ssh->cfg.ssh_nc_port); s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN); ssh2_pkt_addstring(s->pktout, "direct-tcpip"); ssh2_pkt_adduint32(s->pktout, ssh->mainchan->localid); @@ -8633,7 +8725,18 @@ * fields, but some servers insist on syntactically correct * information. */ +#ifdef NO_IPV6 ssh2_pkt_addstring(s->pktout, "0.0.0.0"); +#else + if (strchr(ssh->cfg.ssh_nc_host, ':')) + { + ssh2_pkt_addstring(s->pktout, "::"); + } + else + { + ssh2_pkt_addstring(s->pktout, "0.0.0.0"); + } +#endif ssh2_pkt_adduint32(s->pktout, 0); ssh2_pkt_send(ssh, s->pktout); @@ -9770,7 +9873,11 @@ Ssh ssh = c->ssh; struct Packet *pktout; - logeventf(ssh, "Opening forwarded connection to %s:%d", hostname, port); + logeventf(ssh, "Opening forwarded connection to %s%s%s:%d", + strchr(hostname, ':')? "[" : "", + hostname, + strchr(hostname, ':')? "]" : "", + port); // AVOIR if (ssh->version == 1) { send_packet(ssh, SSH1_MSG_PORT_OPEN, @@ -9796,7 +9903,18 @@ * IP address, and some servers (e.g., Tectia) get upset * if it doesn't match this syntax. */ +#ifdef NO_IPV6 ssh2_pkt_addstring(pktout, "0.0.0.0"); +#else + if (strchr(hostname, ':')) + { + ssh2_pkt_addstring(pktout, "::"); + } + else + { + ssh2_pkt_addstring(pktout, "0.0.0.0"); + } +#endif ssh2_pkt_adduint32(pktout, 0); ssh2_pkt_send(ssh, pktout); } diff -ru putty-src20110216/TELNET.C putty-src20110216p/TELNET.C --- putty-src20110216/TELNET.C 2008-11-24 17:51:42.000000000 +0100 +++ putty-src20110216p/TELNET.C 2011-02-16 00:46:34.089843700 +0100 @@ -775,12 +775,9 @@ *realhost = dupstr(telnet->cfg.loghost); colon = strrchr(*realhost, ':'); if (colon) { - /* - * FIXME: if we ever update this aspect of ssh.c for - * IPv6 literal management, this should change in line - * with it. - */ - *colon++ = '\0'; + char *d = strchr(colon+1, ':'); + if (!d) + *colon++ = '\0'; } } diff -ru putty-src20110216/UNIX/UXPLINK.C putty-src20110216p/UNIX/UXPLINK.C --- putty-src20110216/UNIX/UXPLINK.C 2009-09-14 23:26:48.000000000 +0200 +++ putty-src20110216p/UNIX/UXPLINK.C 2011-02-16 00:47:25.416015600 +0100 @@ -677,8 +677,18 @@ q += 2; cfg.protocol = PROT_TELNET; p = q; - while (*p && *p != ':' && *p != '/') - p++; + while (*p) { + if (*p == '[') { + /* Skip over IPv6 literal addresses */ + char *ipv6_end = strchr(p, ']'); + if (ipv6_end) { + p = ipv6_end; + } + } + if ((*p == ':') || (*p == '/')) + break; + p++; + } c = *p; if (*p) *p++ = '\0'; @@ -826,7 +836,8 @@ /* * Trim a colon suffix off the hostname if it's there. */ - cfg.host[strcspn(cfg.host, ":")] = '\0'; + cfg.host[strcolon(cfg.host)] = '\0'; + /* * Remove any remaining whitespace from the hostname. diff -ru putty-src20110216/WINDOWS/MAKEFILE.VC putty-src20110216p/WINDOWS/MAKEFILE.VC --- putty-src20110216/WINDOWS/MAKEFILE.VC 2011-02-15 00:30:20.000000000 +0100 +++ putty-src20110216p/WINDOWS/MAKEFILE.VC 2011-02-16 01:20:28.361328100 +0100 @@ -108,9 +108,9 @@ MAKEFILE = Makefile.vc # C compilation flags -CFLAGS = /nologo /W3 /O1 -I..\./ -I..\charset/ -I..\windows/ -I..\unix/ -I..\macosx/ /D_WINDOWS /D_WIN32_WINDOWS=0x500 /DWINVER=0x500 +CFLAGS = /nologo /W3 /O1 -I..\./ -I..\charset/ -I..\windows/ -I..\unix/ -I..\macosx/ /D_WINDOWS /D_WIN32_WINDOWS=0x501 /DWINVER=0x501 /D_CRT_SECURE_NO_WARNINGS LFLAGS = /incremental:no /fixed -RCFLAGS = -DWIN32 -D_WIN32 -DWINVER=0x0400 +RCFLAGS = -DWIN32 -D_WIN32 -DWINVER=0x0500 CFLAGS = $(CFLAGS) /DHAS_GSSAPI /DSECURITY_WIN32 RCFLAGS = $(RCFLAGS) $(VER) diff -ru putty-src20110216/WINDOWS/WINDOW.C putty-src20110216p/WINDOWS/WINDOW.C --- putty-src20110216/WINDOWS/WINDOW.C 2010-12-30 00:06:44.000000000 +0100 +++ putty-src20110216p/WINDOWS/WINDOW.C 2011-02-16 00:47:58.541992100 +0100 @@ -528,8 +528,18 @@ q += 2; cfg.protocol = PROT_TELNET; p = q; - while (*p && *p != ':' && *p != '/') + while (*p) { + if (*p == '[') { + /* Skip over IPv6 literal addresses */ + char *ipv6_end = strchr(p, ']'); + if (ipv6_end) { + p = ipv6_end; + } + } + if ((*p == ':') || (*p == '/')) + break; p++; + } c = *p; if (*p) *p++ = '\0'; diff -ru putty-src20110216/WINDOWS/WINNET.C putty-src20110216p/WINDOWS/WINNET.C --- putty-src20110216/WINDOWS/WINNET.C 2010-09-13 10:29:46.000000000 +0200 +++ putty-src20110216p/WINDOWS/WINNET.C 2011-02-16 00:48:09.338867100 +0100 @@ -561,6 +561,32 @@ } } +char *sk_inet_ntop(int af, void *src, char *dst, int cnt) +{ + + if (af == AF_INET) + { + struct sockaddr_in in; + memset(&in, 0, sizeof(in)); + in.sin_family = AF_INET; + memcpy(&in.sin_addr, src, sizeof(struct in_addr)); + p_getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST); + return dst; + } +#ifndef NO_IPV6 + else if (af == AF_INET6) + { + struct sockaddr_in6 in; + memset(&in, 0, sizeof(in)); + in.sin6_family = AF_INET6; + memcpy(&in.sin6_addr, src, sizeof(struct in_addr6)); + p_getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in6), dst, cnt, NULL, 0, NI_NUMERICHOST); + return dst; + } +#endif + return NULL; +} + void sk_getaddr(SockAddr addr, char *buf, int buflen) { SockAddrStep step; @@ -1681,7 +1707,7 @@ char *get_hostname(void) { - int len = 128; + size_t len = 128; char *hostname = NULL; do { len *= 2; diff -ru putty-src20110216/WINDOWS/WINPLINK.C putty-src20110216p/WINDOWS/WINPLINK.C --- putty-src20110216/WINDOWS/WINPLINK.C 2009-09-14 23:26:48.000000000 +0200 +++ putty-src20110216p/WINDOWS/WINPLINK.C 2011-02-16 00:58:23.579101500 +0100 @@ -273,6 +273,36 @@ } } +/* + * CtrlHandler + * + * handle control events to provide graceful cleanup + */ +BOOL WINAPI CtrlHandler(DWORD dwCtrlType) +{ + printf("\n\nStop Event Received... \n\n"); // "^C" + switch (dwCtrlType) + { + case CTRL_C_EVENT: + case CTRL_BREAK_EVENT: + case CTRL_SHUTDOWN_EVENT: + case CTRL_LOGOFF_EVENT: + case CTRL_CLOSE_EVENT: + printf("CtrlHandler: cleaning up...\n"); + /* close connections */ + back->free(backhandle); + /* close log */ + if (logctx) + log_free(logctx); + + cleanup_exit(0); + break; + default: + return FALSE; + } + return TRUE; +} + int main(int argc, char **argv) { int sending; @@ -285,6 +315,14 @@ int use_subsystem = 0; long now, next; + if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) + { + printf("SetConsoleCtrlHandler failed to install console handler: %d\n", + GetLastError()); + cleanup_exit(1); + return 0; + } + sklist = NULL; skcount = sksize = 0; /* @@ -329,6 +367,13 @@ --argc, ++argv; } else if (ret == 1) { continue; + } else if (!strcmp(p, "-vvvv")) { + flags |= FLAG_VERBOSE; + cfg.logtype=LGTYP_SSHRAW; + cfg.logxfovr=LGXF_OVR; + } else if (!strcmp(p, "-vvv")) { + flags |= FLAG_VERBOSE; + cfg.logtype=LGTYP_DEBUG; } else if (!strcmp(p, "-batch")) { console_batch_mode = 1; } else if (!strcmp(p, "-s")) { @@ -359,8 +404,18 @@ q += 2; cfg.protocol = PROT_TELNET; p = q; - while (*p && *p != ':' && *p != '/') - p++; + while (*p) { + if (*p == '[') { + /* Skip over IPv6 literal addresses */ + char *ipv6_end = strchr(p, ']'); + if (ipv6_end) { + p = ipv6_end; + } + } + if ((*p == ':') || (*p == '/')) + break; + p++; + } c = *p; if (*p) *p++ = '\0'; @@ -505,11 +560,19 @@ if (use_subsystem) cfg.ssh_subsys = TRUE; - /* - * Trim a colon suffix off the hostname if it's there. - */ - cfg.host[strcspn(cfg.host, ":")] = '\0'; - + /* + * Trim a colon suffix off the hostname if it's there. + * In order to protect IPv6 address literals against this + * treatment, we do not do this if there's _more_ than one + * colon. + */ + { + char *c; + c = strcolon(cfg.host); + if (c) + *c = '\0'; + } + /* * Remove any remaining whitespace from the hostname. */ @@ -548,6 +611,7 @@ sk_init(); if (p_WSAEventSelect == NULL) { fprintf(stderr, "Plink requires WinSock 2\n"); + sk_cleanup(); return 1; } @@ -560,7 +624,7 @@ netevent = CreateEvent(NULL, FALSE, FALSE, NULL); { const char *error; - char *realhost; + char *realhost= NULL; /* nodelay is only useful if stdin is a character device (console) */ int nodelay = cfg.tcp_nodelay && (GetFileType(GetStdHandle(STD_INPUT_HANDLE)) == FILE_TYPE_CHAR); @@ -568,7 +632,8 @@ error = back->init(NULL, &backhandle, &cfg, cfg.host, cfg.port, &realhost, nodelay, cfg.tcp_keepalives); if (error) { - fprintf(stderr, "Unable to open connection:\n%s", error); + fprintf(stderr, "Unable to open connection: %s\n", error); + sk_cleanup(); return 1; } back->provide_logctx(backhandle, logctx); diff -ru putty-src20110216/WINDOWS/WINSFTP.C putty-src20110216p/WINDOWS/WINSFTP.C --- putty-src20110216/WINDOWS/WINSFTP.C 2009-09-27 17:52:14.000000000 +0200 +++ putty-src20110216p/WINDOWS/WINSFTP.C 2011-02-16 00:48:29.737304600 +0100 @@ -336,30 +336,6 @@ char *srcpath; }; -/* - * Return a pointer to the portion of str that comes after the last - * slash (or backslash or colon, if `local' is TRUE). - */ -static char *stripslashes(char *str, int local) -{ - char *p; - - if (local) { - p = strchr(str, ':'); - if (p) str = p+1; - } - - p = strrchr(str, '/'); - if (p) str = p+1; - - if (local) { - p = strrchr(str, '\\'); - if (p) str = p+1; - } - - return str; -} - WildcardMatcher *begin_wildcard_matching(char *name) { HANDLE h; diff -ru putty-src20110216/X11FWD.C putty-src20110216p/X11FWD.C --- putty-src20110216/X11FWD.C 2009-04-23 19:39:36.000000000 +0200 +++ putty-src20110216p/X11FWD.C 2011-02-16 00:48:29.741210900 +0100 @@ -110,7 +110,7 @@ char *colon, *dot, *slash; char *protocol, *hostname; - colon = strrchr(localcopy, ':'); + colon = strcolon(localcopy); if (!colon) { sfree(disp); sfree(localcopy);