Support username/password authentication in SOCKS 5.
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Sat, 21 Sep 2002 16:07:43 +0000 (16:07 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Sat, 21 Sep 2002 16:07:43 +0000 (16:07 +0000)
git-svn-id: svn://svn.tartarus.org/sgt/putty@1972 cda61777-01e9-0310-a592-d414129be87e

doc/config.but
proxy.c

index c2383b6..50f16e7 100644 (file)
@@ -1,4 +1,4 @@
-\versionid $Id: config.but,v 1.39 2002/09/21 14:03:05 simon Exp $
+\versionid $Id: config.but,v 1.40 2002/09/21 16:07:43 simon Exp $
 
 \C{config} Configuring PuTTY
 
@@ -1433,15 +1433,14 @@ This excludes both of the above ranges at once.
 If your proxy requires authentication, you can enter a username and
 a password in the \q{Username} and \q{Password} boxes.
 
-Authentication is not supported for all forms of proxy. Currently:
+Authentication is not supported for all forms of proxy:
 
-\b Username and password authentication is supported for HTTP proxies.
+\b Username and password authentication is supported for HTTP
+proxies and SOCKS 5 proxies.
 
 \b SOCKS 4 can use the \q{Username} field, but does not support
 passwords.
 
-\b PuTTY does not support authentication in SOCKS 5 at all.
-
 \b Authentication is meaningless in Telnet proxies.
 
 \S{config-proxy-command} Specifying the Telnet proxy command
diff --git a/proxy.c b/proxy.c
index f73b9ad..408552a 100644 (file)
--- a/proxy.c
+++ b/proxy.c
@@ -683,6 +683,7 @@ int proxy_socks4_negotiate (Proxy_Socket p, int change)
 
                return 1;
            }
+           bufchain_consume(&p->pending_input_data, 2);
 
            /* we're done */
            proxy_activate(p);
@@ -713,13 +714,22 @@ int proxy_socks5_negotiate (Proxy_Socket p, int change)
         *     0x03 = CHAP
         */
 
-       char command[3];
+       char command[4];
+       int len;
 
        command[0] = 5; /* version 5 */
-       command[1] = 1; /* TODO: we don't currently support any auth methods */
-       command[2] = 0x00; /* no authentication */
+       if (cfg.proxy_username[0] || cfg.proxy_password[0]) {
+           command[1] = 2;            /* two methods supported: */
+           command[2] = 0x00;         /* no authentication */
+           command[3] = 0x02;         /* username/password */
+           len = 4;
+       } else {
+           command[1] = 1;            /* one methods supported: */
+           command[2] = 0x00;         /* no authentication */
+           len = 3;
+       }
 
-       sk_write(p->sub_socket, command, 3);
+       sk_write(p->sub_socket, command, len);
 
        p->state = 1;
        return 0;
@@ -795,6 +805,36 @@ int proxy_socks5_negotiate (Proxy_Socket p, int change)
                             PROXY_ERROR_GENERAL, 0);
                return 1;
            }
+           bufchain_consume(&p->pending_input_data, 2);
+       }
+
+       if (p->state == 7) {
+
+           /* password authentication reply format:
+            *  version number (1 bytes) = 1
+            *  reply code (1 byte)
+            *    0 = succeeded
+            *    >0 = failed
+            */
+
+           /* get the response */
+           bufchain_prefix(&p->pending_input_data, &data, &len);
+
+           if (data[0] != 1) {
+               plug_closing(p->plug, "Network error: Error while communicating with proxy",
+                            PROXY_ERROR_GENERAL, 0);
+               return 1;
+           }
+
+           if (data[1] != 0) {
+
+               plug_closing(p->plug, "Network error: Proxy refused authentication",
+                            PROXY_ERROR_GENERAL, 0);
+               return 1;
+           }
+
+           bufchain_consume(&p->pending_input_data, 2);
+           p->state = 2;              /* now proceed as authenticated */
        }
 
        if (p->state == 2) {
@@ -909,9 +949,24 @@ int proxy_socks5_negotiate (Proxy_Socket p, int change)
        }
 
        if (p->state == 5) {
-           /* TODO: Handle username/password authentication */
-           plug_closing(p->plug, "Network error: We don't support username/password "
-                                 "authentication",
+           if (cfg.proxy_username[0] || cfg.proxy_password[0]) {
+               char userpwbuf[514];
+               int ulen, plen;
+               ulen = strlen(cfg.proxy_username);
+               if (ulen > 255) ulen = 255; if (ulen < 1) ulen = 1;
+               plen = strlen(cfg.proxy_password);
+               if (plen > 255) plen = 255; if (plen < 1) plen = 1;
+               userpwbuf[0] = 1;      /* version number of subnegotiation */
+               userpwbuf[1] = ulen;
+               memcpy(userpwbuf+2, cfg.proxy_username, ulen);
+               userpwbuf[ulen+2] = plen;
+               memcpy(userpwbuf+ulen+3, cfg.proxy_password, plen);
+               sk_write(p->sub_socket, userpwbuf, ulen + plen + 3);
+               p->state = 7;
+           } else 
+               plug_closing(p->plug, "Network error: Server chose "
+                            "username/password authentication but we "
+                            "didn't offer it!",
                         PROXY_ERROR_GENERAL, 0);
            return 1;
        }
@@ -922,6 +977,7 @@ int proxy_socks5_negotiate (Proxy_Socket p, int change)
                         PROXY_ERROR_GENERAL, 0);
            return 1;
        }
+
     }
 
     plug_closing(p->plug, "Network error: Unexpected proxy error",