Improved the ability of http-auth "auto" flag to dynamically detect
the auth method required by the proxy.
Added http-auth "auto-nct" flag to reject weak proxy auth methods.
Added HTTP proxy digest authentication method.
Removed extraneous openvpn_sleep calls from proxy.c.
git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@5628 e7ae566f-a301-0410-adde-c780ea21d3b5
| 297 | 298 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,143 @@ |
| 0 |
+/* |
|
| 1 |
+ * OpenVPN -- An application to securely tunnel IP networks |
|
| 2 |
+ * over a single TCP/UDP port, with support for SSL/TLS-based |
|
| 3 |
+ * session authentication and key exchange, |
|
| 4 |
+ * packet encryption, packet authentication, and |
|
| 5 |
+ * packet compression. |
|
| 6 |
+ * |
|
| 7 |
+ * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net> |
|
| 8 |
+ * |
|
| 9 |
+ * This program is free software; you can redistribute it and/or modify |
|
| 10 |
+ * it under the terms of the GNU General Public License version 2 |
|
| 11 |
+ * as published by the Free Software Foundation. |
|
| 12 |
+ * |
|
| 13 |
+ * This program is distributed in the hope that it will be useful, |
|
| 14 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 15 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 16 |
+ * GNU General Public License for more details. |
|
| 17 |
+ * |
|
| 18 |
+ * You should have received a copy of the GNU General Public License |
|
| 19 |
+ * along with this program (see the file COPYING included with this |
|
| 20 |
+ * distribution); if not, write to the Free Software Foundation, Inc., |
|
| 21 |
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
| 22 |
+ */ |
|
| 23 |
+ |
|
| 24 |
+#include "syshead.h" |
|
| 25 |
+ |
|
| 26 |
+#if PROXY_DIGEST_AUTH |
|
| 27 |
+ |
|
| 28 |
+#include "crypto.h" |
|
| 29 |
+#include "httpdigest.h" |
|
| 30 |
+ |
|
| 31 |
+static void |
|
| 32 |
+CvtHex( |
|
| 33 |
+ IN HASH Bin, |
|
| 34 |
+ OUT HASHHEX Hex |
|
| 35 |
+ ) |
|
| 36 |
+{
|
|
| 37 |
+ unsigned short i; |
|
| 38 |
+ unsigned char j; |
|
| 39 |
+ |
|
| 40 |
+ for (i = 0; i < HASHLEN; i++) {
|
|
| 41 |
+ j = (Bin[i] >> 4) & 0xf; |
|
| 42 |
+ if (j <= 9) |
|
| 43 |
+ Hex[i*2] = (j + '0'); |
|
| 44 |
+ else |
|
| 45 |
+ Hex[i*2] = (j + 'a' - 10); |
|
| 46 |
+ j = Bin[i] & 0xf; |
|
| 47 |
+ if (j <= 9) |
|
| 48 |
+ Hex[i*2+1] = (j + '0'); |
|
| 49 |
+ else |
|
| 50 |
+ Hex[i*2+1] = (j + 'a' - 10); |
|
| 51 |
+ }; |
|
| 52 |
+ Hex[HASHHEXLEN] = '\0'; |
|
| 53 |
+}; |
|
| 54 |
+ |
|
| 55 |
+/* calculate H(A1) as per spec */ |
|
| 56 |
+void |
|
| 57 |
+DigestCalcHA1( |
|
| 58 |
+ IN char * pszAlg, |
|
| 59 |
+ IN char * pszUserName, |
|
| 60 |
+ IN char * pszRealm, |
|
| 61 |
+ IN char * pszPassword, |
|
| 62 |
+ IN char * pszNonce, |
|
| 63 |
+ IN char * pszCNonce, |
|
| 64 |
+ OUT HASHHEX SessionKey |
|
| 65 |
+ ) |
|
| 66 |
+{
|
|
| 67 |
+ MD5_CTX Md5Ctx; |
|
| 68 |
+ HASH HA1; |
|
| 69 |
+ |
|
| 70 |
+ MD5_Init(&Md5Ctx); |
|
| 71 |
+ MD5_Update(&Md5Ctx, pszUserName, strlen(pszUserName)); |
|
| 72 |
+ MD5_Update(&Md5Ctx, ":", 1); |
|
| 73 |
+ MD5_Update(&Md5Ctx, pszRealm, strlen(pszRealm)); |
|
| 74 |
+ MD5_Update(&Md5Ctx, ":", 1); |
|
| 75 |
+ MD5_Update(&Md5Ctx, pszPassword, strlen(pszPassword)); |
|
| 76 |
+ MD5_Final(HA1, &Md5Ctx); |
|
| 77 |
+ if (pszAlg && stricmp(pszAlg, "md5-sess") == 0) |
|
| 78 |
+ {
|
|
| 79 |
+ MD5_Init(&Md5Ctx); |
|
| 80 |
+ MD5_Update(&Md5Ctx, HA1, HASHLEN); |
|
| 81 |
+ MD5_Update(&Md5Ctx, ":", 1); |
|
| 82 |
+ MD5_Update(&Md5Ctx, pszNonce, strlen(pszNonce)); |
|
| 83 |
+ MD5_Update(&Md5Ctx, ":", 1); |
|
| 84 |
+ MD5_Update(&Md5Ctx, pszCNonce, strlen(pszCNonce)); |
|
| 85 |
+ MD5_Final(HA1, &Md5Ctx); |
|
| 86 |
+ }; |
|
| 87 |
+ CvtHex(HA1, SessionKey); |
|
| 88 |
+} |
|
| 89 |
+ |
|
| 90 |
+/* calculate request-digest/response-digest as per HTTP Digest spec */ |
|
| 91 |
+void |
|
| 92 |
+DigestCalcResponse( |
|
| 93 |
+ IN HASHHEX HA1, /* H(A1) */ |
|
| 94 |
+ IN char * pszNonce, /* nonce from server */ |
|
| 95 |
+ IN char * pszNonceCount, /* 8 hex digits */ |
|
| 96 |
+ IN char * pszCNonce, /* client nonce */ |
|
| 97 |
+ IN char * pszQop, /* qop-value: "", "auth", "auth-int" */ |
|
| 98 |
+ IN char * pszMethod, /* method from the request */ |
|
| 99 |
+ IN char * pszDigestUri, /* requested URL */ |
|
| 100 |
+ IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */ |
|
| 101 |
+ OUT HASHHEX Response /* request-digest or response-digest */ |
|
| 102 |
+ ) |
|
| 103 |
+{
|
|
| 104 |
+ MD5_CTX Md5Ctx; |
|
| 105 |
+ HASH HA2; |
|
| 106 |
+ HASH RespHash; |
|
| 107 |
+ HASHHEX HA2Hex; |
|
| 108 |
+ |
|
| 109 |
+ // calculate H(A2) |
|
| 110 |
+ MD5_Init(&Md5Ctx); |
|
| 111 |
+ MD5_Update(&Md5Ctx, pszMethod, strlen(pszMethod)); |
|
| 112 |
+ MD5_Update(&Md5Ctx, ":", 1); |
|
| 113 |
+ MD5_Update(&Md5Ctx, pszDigestUri, strlen(pszDigestUri)); |
|
| 114 |
+ if (stricmp(pszQop, "auth-int") == 0) |
|
| 115 |
+ {
|
|
| 116 |
+ MD5_Update(&Md5Ctx, ":", 1); |
|
| 117 |
+ MD5_Update(&Md5Ctx, HEntity, HASHHEXLEN); |
|
| 118 |
+ }; |
|
| 119 |
+ MD5_Final(HA2, &Md5Ctx); |
|
| 120 |
+ CvtHex(HA2, HA2Hex); |
|
| 121 |
+ |
|
| 122 |
+ // calculate response |
|
| 123 |
+ MD5_Init(&Md5Ctx); |
|
| 124 |
+ MD5_Update(&Md5Ctx, HA1, HASHHEXLEN); |
|
| 125 |
+ MD5_Update(&Md5Ctx, ":", 1); |
|
| 126 |
+ MD5_Update(&Md5Ctx, pszNonce, strlen(pszNonce)); |
|
| 127 |
+ MD5_Update(&Md5Ctx, ":", 1); |
|
| 128 |
+ if (*pszQop) |
|
| 129 |
+ {
|
|
| 130 |
+ MD5_Update(&Md5Ctx, pszNonceCount, strlen(pszNonceCount)); |
|
| 131 |
+ MD5_Update(&Md5Ctx, ":", 1); |
|
| 132 |
+ MD5_Update(&Md5Ctx, pszCNonce, strlen(pszCNonce)); |
|
| 133 |
+ MD5_Update(&Md5Ctx, ":", 1); |
|
| 134 |
+ MD5_Update(&Md5Ctx, pszQop, strlen(pszQop)); |
|
| 135 |
+ MD5_Update(&Md5Ctx, ":", 1); |
|
| 136 |
+ }; |
|
| 137 |
+ MD5_Update(&Md5Ctx, HA2Hex, HASHHEXLEN); |
|
| 138 |
+ MD5_Final(RespHash, &Md5Ctx); |
|
| 139 |
+ CvtHex(RespHash, Response); |
|
| 140 |
+} |
|
| 141 |
+ |
|
| 142 |
+#endif |
| 0 | 143 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,60 @@ |
| 0 |
+/* |
|
| 1 |
+ * OpenVPN -- An application to securely tunnel IP networks |
|
| 2 |
+ * over a single TCP/UDP port, with support for SSL/TLS-based |
|
| 3 |
+ * session authentication and key exchange, |
|
| 4 |
+ * packet encryption, packet authentication, and |
|
| 5 |
+ * packet compression. |
|
| 6 |
+ * |
|
| 7 |
+ * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net> |
|
| 8 |
+ * |
|
| 9 |
+ * This program is free software; you can redistribute it and/or modify |
|
| 10 |
+ * it under the terms of the GNU General Public License version 2 |
|
| 11 |
+ * as published by the Free Software Foundation. |
|
| 12 |
+ * |
|
| 13 |
+ * This program is distributed in the hope that it will be useful, |
|
| 14 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 15 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 16 |
+ * GNU General Public License for more details. |
|
| 17 |
+ * |
|
| 18 |
+ * You should have received a copy of the GNU General Public License |
|
| 19 |
+ * along with this program (see the file COPYING included with this |
|
| 20 |
+ * distribution); if not, write to the Free Software Foundation, Inc., |
|
| 21 |
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
| 22 |
+ */ |
|
| 23 |
+ |
|
| 24 |
+#if PROXY_DIGEST_AUTH |
|
| 25 |
+ |
|
| 26 |
+#define HASHLEN 16 |
|
| 27 |
+typedef char HASH[HASHLEN]; |
|
| 28 |
+#define HASHHEXLEN 32 |
|
| 29 |
+typedef char HASHHEX[HASHHEXLEN+1]; |
|
| 30 |
+#undef IN |
|
| 31 |
+#undef OUT |
|
| 32 |
+#define IN const |
|
| 33 |
+#define OUT |
|
| 34 |
+ |
|
| 35 |
+/* calculate H(A1) as per HTTP Digest spec */ |
|
| 36 |
+void DigestCalcHA1( |
|
| 37 |
+ IN char * pszAlg, |
|
| 38 |
+ IN char * pszUserName, |
|
| 39 |
+ IN char * pszRealm, |
|
| 40 |
+ IN char * pszPassword, |
|
| 41 |
+ IN char * pszNonce, |
|
| 42 |
+ IN char * pszCNonce, |
|
| 43 |
+ OUT HASHHEX SessionKey |
|
| 44 |
+ ); |
|
| 45 |
+ |
|
| 46 |
+/* calculate request-digest/response-digest as per HTTP Digest spec */ |
|
| 47 |
+void DigestCalcResponse( |
|
| 48 |
+ IN HASHHEX HA1, /* H(A1) */ |
|
| 49 |
+ IN char * pszNonce, /* nonce from server */ |
|
| 50 |
+ IN char * pszNonceCount, /* 8 hex digits */ |
|
| 51 |
+ IN char * pszCNonce, /* client nonce */ |
|
| 52 |
+ IN char * pszQop, /* qop-value: "", "auth", "auth-int" */ |
|
| 53 |
+ IN char * pszMethod, /* method from the request */ |
|
| 54 |
+ IN char * pszDigestUri, /* requested URL */ |
|
| 55 |
+ IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */ |
|
| 56 |
+ OUT HASHHEX Response /* request-digest or response-digest */ |
|
| 57 |
+ ); |
|
| 58 |
+ |
|
| 59 |
+#endif |
| ... | ... |
@@ -474,7 +474,7 @@ InternetQueryOption API. |
| 474 | 474 |
This option exists in OpenVPN 2.1 or higher. |
| 475 | 475 |
.\"********************************************************* |
| 476 | 476 |
.TP |
| 477 |
-.B --http-proxy server port [authfile|'auto'] [auth-method] |
|
| 477 |
+.B --http-proxy server port [authfile|'auto'|'auto-nct'] [auth-method] |
|
| 478 | 478 |
Connect to remote host through an HTTP proxy at address |
| 479 | 479 |
.B server |
| 480 | 480 |
and port |
| ... | ... |
@@ -487,6 +487,13 @@ is a file containing a username and password on 2 lines, or |
| 487 | 487 |
.B auth-method |
| 488 | 488 |
should be one of "none", "basic", or "ntlm". |
| 489 | 489 |
|
| 490 |
+HTTP Digest authentication is supported as well, but only via |
|
| 491 |
+the |
|
| 492 |
+.B auto |
|
| 493 |
+or |
|
| 494 |
+.B auto-nct |
|
| 495 |
+flags (below). |
|
| 496 |
+ |
|
| 490 | 497 |
The |
| 491 | 498 |
.B auto |
| 492 | 499 |
flag causes OpenVPN to automatically determine the |
| ... | ... |
@@ -494,6 +501,12 @@ flag causes OpenVPN to automatically determine the |
| 494 | 494 |
and query stdin or the management interface for |
| 495 | 495 |
username/password credentials, if required. This flag |
| 496 | 496 |
exists on OpenVPN 2.1 or higher. |
| 497 |
+ |
|
| 498 |
+The |
|
| 499 |
+.B auto-nct |
|
| 500 |
+flag (no clear-text auth) instructs OpenVPN to automatically |
|
| 501 |
+determine the authentication method, but to reject weak |
|
| 502 |
+authentication protocols such as HTTP Basic Authentication. |
|
| 497 | 503 |
.\"********************************************************* |
| 498 | 504 |
.TP |
| 499 | 505 |
.B --http-proxy-retry |
| ... | ... |
@@ -108,8 +108,9 @@ static const char usage_message[] = |
| 108 | 108 |
" up is a file containing username/password on 2 lines, or\n" |
| 109 | 109 |
" 'stdin' to prompt from console. Add auth='ntlm' if\n" |
| 110 | 110 |
" the proxy requires NTLM authentication.\n" |
| 111 |
- "--http-proxy s p 'auto': Like the above directive, but automatically determine\n" |
|
| 112 |
- " auth method and query for username/password if needed.\n" |
|
| 111 |
+ "--http-proxy s p 'auto[-nct]' : Like the above directive, but automatically\n" |
|
| 112 |
+ " determine auth method and query for username/password\n" |
|
| 113 |
+ " if needed. auto-nct disables weak proxy auth methods.\n" |
|
| 113 | 114 |
"--http-proxy-retry : Retry indefinitely on HTTP proxy errors.\n" |
| 114 | 115 |
"--http-proxy-timeout n : Proxy timeout in seconds, default=5.\n" |
| 115 | 116 |
"--http-proxy-option type [parm] : Set extended HTTP proxy options.\n" |
| ... | ... |
@@ -4197,8 +4198,13 @@ add_option (struct options *options, |
| 4197 | 4197 |
|
| 4198 | 4198 |
if (p[3]) |
| 4199 | 4199 |
{
|
| 4200 |
+ /* auto -- try to figure out proxy addr, port, and type automatically */ |
|
| 4201 |
+ /* semiauto -- given proxy addr:port, try to figure out type automatically */ |
|
| 4202 |
+ /* (auto|semiauto)-nct -- disable proxy auth cleartext protocols (i.e. basic auth) */ |
|
| 4200 | 4203 |
if (streq (p[3], "auto")) |
| 4201 |
- ho->auth_retry = true; |
|
| 4204 |
+ ho->auth_retry = PAR_ALL; |
|
| 4205 |
+ else if (streq (p[3], "auto-nct")) |
|
| 4206 |
+ ho->auth_retry = PAR_NCT; |
|
| 4202 | 4207 |
else |
| 4203 | 4208 |
{
|
| 4204 | 4209 |
ho->auth_method_string = "basic"; |
| ... | ... |
@@ -26,11 +26,13 @@ |
| 26 | 26 |
|
| 27 | 27 |
#include "common.h" |
| 28 | 28 |
#include "misc.h" |
| 29 |
+#include "crypto.h" |
|
| 29 | 30 |
#include "win32.h" |
| 30 | 31 |
#include "socket.h" |
| 31 | 32 |
#include "fdmisc.h" |
| 32 | 33 |
#include "proxy.h" |
| 33 | 34 |
#include "base64.h" |
| 35 |
+#include "httpdigest.h" |
|
| 34 | 36 |
#include "ntlm.h" |
| 35 | 37 |
|
| 36 | 38 |
#ifdef WIN32 |
| ... | ... |
@@ -229,6 +231,189 @@ get_user_pass_http (struct http_proxy_info *p, const bool force) |
| 229 | 229 |
p->up = static_proxy_user_pass; |
| 230 | 230 |
} |
| 231 | 231 |
} |
| 232 |
+static void |
|
| 233 |
+clear_user_pass_http (void) |
|
| 234 |
+{
|
|
| 235 |
+ purge_user_pass (&static_proxy_user_pass, true); |
|
| 236 |
+} |
|
| 237 |
+ |
|
| 238 |
+static void |
|
| 239 |
+dump_residual (socket_descriptor_t sd, |
|
| 240 |
+ int timeout, |
|
| 241 |
+ volatile int *signal_received) |
|
| 242 |
+{
|
|
| 243 |
+ char buf[256]; |
|
| 244 |
+ while (true) |
|
| 245 |
+ {
|
|
| 246 |
+ if (!recv_line (sd, buf, sizeof (buf), timeout, true, NULL, signal_received)) |
|
| 247 |
+ return; |
|
| 248 |
+ chomp (buf); |
|
| 249 |
+ msg (D_PROXY, "PROXY HEADER: '%s'", buf); |
|
| 250 |
+ } |
|
| 251 |
+} |
|
| 252 |
+ |
|
| 253 |
+/* |
|
| 254 |
+ * Extract the Proxy-Authenticate header from the stream. |
|
| 255 |
+ * Consumes all headers. |
|
| 256 |
+ */ |
|
| 257 |
+static int |
|
| 258 |
+get_proxy_authenticate (socket_descriptor_t sd, |
|
| 259 |
+ int timeout, |
|
| 260 |
+ char **data, |
|
| 261 |
+ struct gc_arena *gc, |
|
| 262 |
+ volatile int *signal_received) |
|
| 263 |
+{
|
|
| 264 |
+ char buf[256]; |
|
| 265 |
+ int ret = HTTP_AUTH_NONE; |
|
| 266 |
+ while (true) |
|
| 267 |
+ {
|
|
| 268 |
+ if (!recv_line (sd, buf, sizeof (buf), timeout, true, NULL, signal_received)) |
|
| 269 |
+ {
|
|
| 270 |
+ *data = NULL; |
|
| 271 |
+ return HTTP_AUTH_NONE; |
|
| 272 |
+ } |
|
| 273 |
+ chomp (buf); |
|
| 274 |
+ if (!strlen(buf)) |
|
| 275 |
+ return ret; |
|
| 276 |
+ if (ret == HTTP_AUTH_NONE && !strncmp(buf, "Proxy-Authenticate: ", 20)) |
|
| 277 |
+ {
|
|
| 278 |
+ if (!strncmp(buf+20, "Basic ", 6)) |
|
| 279 |
+ {
|
|
| 280 |
+ msg (D_PROXY, "PROXY AUTH BASIC: '%s'", buf); |
|
| 281 |
+ *data = string_alloc(buf+26, gc); |
|
| 282 |
+ ret = HTTP_AUTH_BASIC; |
|
| 283 |
+ } |
|
| 284 |
+#if PROXY_DIGEST_AUTH |
|
| 285 |
+ else if (!strncmp(buf+20, "Digest ", 7)) |
|
| 286 |
+ {
|
|
| 287 |
+ msg (D_PROXY, "PROXY AUTH DIGEST: '%s'", buf); |
|
| 288 |
+ *data = string_alloc(buf+27, gc); |
|
| 289 |
+ ret = HTTP_AUTH_DIGEST; |
|
| 290 |
+ } |
|
| 291 |
+#endif |
|
| 292 |
+#if NTLM |
|
| 293 |
+ else if (!strncmp(buf+20, "NTLM", 4)) |
|
| 294 |
+ {
|
|
| 295 |
+ msg (D_PROXY, "PROXY AUTH HTLM: '%s'", buf); |
|
| 296 |
+ *data = NULL; |
|
| 297 |
+ ret = HTTP_AUTH_NTLM; |
|
| 298 |
+ } |
|
| 299 |
+#endif |
|
| 300 |
+ } |
|
| 301 |
+ } |
|
| 302 |
+} |
|
| 303 |
+ |
|
| 304 |
+static void |
|
| 305 |
+store_proxy_authenticate (struct http_proxy_info *p, char *data) |
|
| 306 |
+{
|
|
| 307 |
+ if (p->proxy_authenticate) |
|
| 308 |
+ free (p->proxy_authenticate); |
|
| 309 |
+ p->proxy_authenticate = data; |
|
| 310 |
+} |
|
| 311 |
+ |
|
| 312 |
+/* |
|
| 313 |
+ * Parse out key/value pairs from Proxy-Authenticate string. |
|
| 314 |
+ * Return true on success, or false on parse failure. |
|
| 315 |
+ */ |
|
| 316 |
+static bool |
|
| 317 |
+get_key_value(const char *str, /* source string */ |
|
| 318 |
+ char *key, /* key stored here */ |
|
| 319 |
+ char *value, /* value stored here */ |
|
| 320 |
+ int max_key_len, |
|
| 321 |
+ int max_value_len, |
|
| 322 |
+ const char **endptr) /* next search position */ |
|
| 323 |
+{
|
|
| 324 |
+ int c; |
|
| 325 |
+ bool starts_with_quote = false; |
|
| 326 |
+ bool escape = false; |
|
| 327 |
+ |
|
| 328 |
+ for (c = max_key_len-1; (*str && (*str != '=') && c--); ) |
|
| 329 |
+ *key++ = *str++; |
|
| 330 |
+ *key = '\0'; |
|
| 331 |
+ |
|
| 332 |
+ if('=' != *str++)
|
|
| 333 |
+ /* no key/value found */ |
|
| 334 |
+ return false; |
|
| 335 |
+ |
|
| 336 |
+ if('\"' == *str)
|
|
| 337 |
+ {
|
|
| 338 |
+ /* quoted string */ |
|
| 339 |
+ str++; |
|
| 340 |
+ starts_with_quote = true; |
|
| 341 |
+ } |
|
| 342 |
+ |
|
| 343 |
+ for (c = max_value_len-1; *str && c--; str++) |
|
| 344 |
+ {
|
|
| 345 |
+ switch (*str) |
|
| 346 |
+ {
|
|
| 347 |
+ case '\\': |
|
| 348 |
+ if (!escape) |
|
| 349 |
+ {
|
|
| 350 |
+ /* possibly the start of an escaped quote */ |
|
| 351 |
+ escape = true; |
|
| 352 |
+ *value++ = '\\'; /* even though this is an escape character, we still |
|
| 353 |
+ store it as-is in the target buffer */ |
|
| 354 |
+ continue; |
|
| 355 |
+ } |
|
| 356 |
+ break; |
|
| 357 |
+ case ',': |
|
| 358 |
+ if (!starts_with_quote) |
|
| 359 |
+ {
|
|
| 360 |
+ /* this signals the end of the value if we didn't get a starting quote |
|
| 361 |
+ and then we do "sloppy" parsing */ |
|
| 362 |
+ c=0; /* the end */ |
|
| 363 |
+ continue; |
|
| 364 |
+ } |
|
| 365 |
+ break; |
|
| 366 |
+ case '\r': |
|
| 367 |
+ case '\n': |
|
| 368 |
+ /* end of string */ |
|
| 369 |
+ c=0; |
|
| 370 |
+ continue; |
|
| 371 |
+ case '\"': |
|
| 372 |
+ if (!escape && starts_with_quote) |
|
| 373 |
+ {
|
|
| 374 |
+ /* end of string */ |
|
| 375 |
+ c=0; |
|
| 376 |
+ continue; |
|
| 377 |
+ } |
|
| 378 |
+ break; |
|
| 379 |
+ } |
|
| 380 |
+ escape = false; |
|
| 381 |
+ *value++ = *str; |
|
| 382 |
+ } |
|
| 383 |
+ *value = '\0'; |
|
| 384 |
+ |
|
| 385 |
+ *endptr = str; |
|
| 386 |
+ |
|
| 387 |
+ return true; /* success */ |
|
| 388 |
+} |
|
| 389 |
+ |
|
| 390 |
+static char * |
|
| 391 |
+get_pa_var (const char *key, const char *pa, struct gc_arena *gc) |
|
| 392 |
+{
|
|
| 393 |
+ char k[64]; |
|
| 394 |
+ char v[256]; |
|
| 395 |
+ const char *content = pa; |
|
| 396 |
+ |
|
| 397 |
+ while (true) |
|
| 398 |
+ {
|
|
| 399 |
+ const int status = get_key_value(content, k, v, sizeof(k), sizeof(v), &content); |
|
| 400 |
+ if (status) |
|
| 401 |
+ {
|
|
| 402 |
+ if (!strcmp(key, k)) |
|
| 403 |
+ return string_alloc(v, gc); |
|
| 404 |
+ } |
|
| 405 |
+ else |
|
| 406 |
+ return NULL; |
|
| 407 |
+ |
|
| 408 |
+ /* advance to start of next key */ |
|
| 409 |
+ if (*content == ',') |
|
| 410 |
+ ++content; |
|
| 411 |
+ while (*content && isspace(*content)) |
|
| 412 |
+ ++content; |
|
| 413 |
+ } |
|
| 414 |
+} |
|
| 232 | 415 |
|
| 233 | 416 |
struct http_proxy_info * |
| 234 | 417 |
http_proxy_new (const struct http_proxy_options *o, |
| ... | ... |
@@ -265,7 +450,8 @@ http_proxy_new (const struct http_proxy_options *o, |
| 265 | 265 |
|
| 266 | 266 |
opt.server = auto_proxy_info->http.server; |
| 267 | 267 |
opt.port = auto_proxy_info->http.port; |
| 268 |
- opt.auth_retry = true; |
|
| 268 |
+ if (!opt.auth_retry) |
|
| 269 |
+ opt.auth_retry = PAR_ALL; |
|
| 269 | 270 |
|
| 270 | 271 |
o = &opt; |
| 271 | 272 |
} |
| ... | ... |
@@ -287,12 +473,14 @@ http_proxy_new (const struct http_proxy_options *o, |
| 287 | 287 |
p->auth_method = HTTP_AUTH_NONE; |
| 288 | 288 |
else if (!strcmp (o->auth_method_string, "basic")) |
| 289 | 289 |
p->auth_method = HTTP_AUTH_BASIC; |
| 290 |
+#if NTLM |
|
| 290 | 291 |
else if (!strcmp (o->auth_method_string, "ntlm")) |
| 291 | 292 |
p->auth_method = HTTP_AUTH_NTLM; |
| 292 | 293 |
else if (!strcmp (o->auth_method_string, "ntlm2")) |
| 293 | 294 |
p->auth_method = HTTP_AUTH_NTLM2; |
| 295 |
+#endif |
|
| 294 | 296 |
else |
| 295 |
- msg (M_FATAL, "ERROR: unknown HTTP authentication method: '%s' -- only the 'none', 'basic', 'ntlm', or 'ntlm2' methods are currently supported", |
|
| 297 |
+ msg (M_FATAL, "ERROR: unknown HTTP authentication method: '%s'", |
|
| 296 | 298 |
o->auth_method_string); |
| 297 | 299 |
} |
| 298 | 300 |
|
| ... | ... |
@@ -326,101 +514,110 @@ establish_http_proxy_passthru (struct http_proxy_info *p, |
| 326 | 326 |
volatile int *signal_received) |
| 327 | 327 |
{
|
| 328 | 328 |
struct gc_arena gc = gc_new (); |
| 329 |
- char buf[256]; |
|
| 329 |
+ char buf[512]; |
|
| 330 | 330 |
char buf2[128]; |
| 331 | 331 |
char get[80]; |
| 332 | 332 |
int status; |
| 333 | 333 |
int nparms; |
| 334 | 334 |
bool ret = false; |
| 335 |
+ bool processed = false; |
|
| 335 | 336 |
|
| 336 | 337 |
/* get user/pass if not previously given or if --auto-proxy is being used */ |
| 337 | 338 |
if (p->auth_method == HTTP_AUTH_BASIC |
| 339 |
+ || p->auth_method == HTTP_AUTH_DIGEST |
|
| 338 | 340 |
|| p->auth_method == HTTP_AUTH_NTLM) |
| 339 | 341 |
get_user_pass_http (p, false); |
| 340 | 342 |
|
| 341 |
- /* format HTTP CONNECT message */ |
|
| 342 |
- openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s", |
|
| 343 |
- host, |
|
| 344 |
- port, |
|
| 345 |
- p->options.http_version); |
|
| 346 |
- |
|
| 347 |
- msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); |
|
| 348 |
- |
|
| 349 |
- /* send HTTP CONNECT message to proxy */ |
|
| 350 |
- if (!send_line_crlf (sd, buf)) |
|
| 351 |
- goto error; |
|
| 352 |
- |
|
| 353 |
- /* send User-Agent string if provided */ |
|
| 354 |
- if (p->options.user_agent) |
|
| 343 |
+ /* are we being called again after getting the digest server nonce in the previous transaction? */ |
|
| 344 |
+ if (p->auth_method == HTTP_AUTH_DIGEST && p->proxy_authenticate) |
|
| 355 | 345 |
{
|
| 356 |
- openvpn_snprintf (buf, sizeof(buf), "User-Agent: %s", |
|
| 357 |
- p->options.user_agent); |
|
| 358 |
- if (!send_line_crlf (sd, buf)) |
|
| 359 |
- goto error; |
|
| 346 |
+ nparms = 1; |
|
| 347 |
+ status = 407; |
|
| 360 | 348 |
} |
| 361 |
- |
|
| 362 |
- /* auth specified? */ |
|
| 363 |
- switch (p->auth_method) |
|
| 349 |
+ else |
|
| 364 | 350 |
{
|
| 365 |
- case HTTP_AUTH_NONE: |
|
| 366 |
- break; |
|
| 351 |
+ /* format HTTP CONNECT message */ |
|
| 352 |
+ openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s", |
|
| 353 |
+ host, |
|
| 354 |
+ port, |
|
| 355 |
+ p->options.http_version); |
|
| 367 | 356 |
|
| 368 |
- case HTTP_AUTH_BASIC: |
|
| 369 |
- openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: Basic %s", |
|
| 370 |
- username_password_as_base64 (p, &gc)); |
|
| 371 |
- msg (D_PROXY, "Attempting Basic Proxy-Authorization"); |
|
| 372 |
- dmsg (D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf); |
|
| 373 |
- openvpn_sleep (1); |
|
| 357 |
+ msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); |
|
| 358 |
+ |
|
| 359 |
+ /* send HTTP CONNECT message to proxy */ |
|
| 374 | 360 |
if (!send_line_crlf (sd, buf)) |
| 375 | 361 |
goto error; |
| 376 |
- break; |
|
| 362 |
+ |
|
| 363 |
+ /* send User-Agent string if provided */ |
|
| 364 |
+ if (p->options.user_agent) |
|
| 365 |
+ {
|
|
| 366 |
+ openvpn_snprintf (buf, sizeof(buf), "User-Agent: %s", |
|
| 367 |
+ p->options.user_agent); |
|
| 368 |
+ if (!send_line_crlf (sd, buf)) |
|
| 369 |
+ goto error; |
|
| 370 |
+ } |
|
| 371 |
+ |
|
| 372 |
+ /* auth specified? */ |
|
| 373 |
+ switch (p->auth_method) |
|
| 374 |
+ {
|
|
| 375 |
+ case HTTP_AUTH_NONE: |
|
| 376 |
+ break; |
|
| 377 |
+ |
|
| 378 |
+ case HTTP_AUTH_BASIC: |
|
| 379 |
+ openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: Basic %s", |
|
| 380 |
+ username_password_as_base64 (p, &gc)); |
|
| 381 |
+ msg (D_PROXY, "Attempting Basic Proxy-Authorization"); |
|
| 382 |
+ dmsg (D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf); |
|
| 383 |
+ if (!send_line_crlf (sd, buf)) |
|
| 384 |
+ goto error; |
|
| 385 |
+ break; |
|
| 377 | 386 |
|
| 378 | 387 |
#if NTLM |
| 379 |
- case HTTP_AUTH_NTLM: |
|
| 380 |
- case HTTP_AUTH_NTLM2: |
|
| 381 |
- /* keep-alive connection */ |
|
| 382 |
- openvpn_snprintf (buf, sizeof(buf), "Proxy-Connection: Keep-Alive"); |
|
| 383 |
- if (!send_line_crlf (sd, buf)) |
|
| 384 |
- goto error; |
|
| 388 |
+ case HTTP_AUTH_NTLM: |
|
| 389 |
+ case HTTP_AUTH_NTLM2: |
|
| 390 |
+ /* keep-alive connection */ |
|
| 391 |
+ openvpn_snprintf (buf, sizeof(buf), "Proxy-Connection: Keep-Alive"); |
|
| 392 |
+ if (!send_line_crlf (sd, buf)) |
|
| 393 |
+ goto error; |
|
| 385 | 394 |
|
| 386 |
- openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: NTLM %s", |
|
| 387 |
- ntlm_phase_1 (p, &gc)); |
|
| 388 |
- msg (D_PROXY, "Attempting NTLM Proxy-Authorization phase 1"); |
|
| 389 |
- dmsg (D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf); |
|
| 390 |
- openvpn_sleep (1); |
|
| 391 |
- if (!send_line_crlf (sd, buf)) |
|
| 392 |
- goto error; |
|
| 393 |
- break; |
|
| 395 |
+ openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: NTLM %s", |
|
| 396 |
+ ntlm_phase_1 (p, &gc)); |
|
| 397 |
+ msg (D_PROXY, "Attempting NTLM Proxy-Authorization phase 1"); |
|
| 398 |
+ dmsg (D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf); |
|
| 399 |
+ if (!send_line_crlf (sd, buf)) |
|
| 400 |
+ goto error; |
|
| 401 |
+ break; |
|
| 394 | 402 |
#endif |
| 395 | 403 |
|
| 396 |
- default: |
|
| 397 |
- ASSERT (0); |
|
| 398 |
- } |
|
| 404 |
+ default: |
|
| 405 |
+ ASSERT (0); |
|
| 406 |
+ } |
|
| 399 | 407 |
|
| 400 |
- /* send empty CR, LF */ |
|
| 401 |
- openvpn_sleep (1); |
|
| 402 |
- if (!send_crlf (sd)) |
|
| 403 |
- goto error; |
|
| 408 |
+ /* send empty CR, LF */ |
|
| 409 |
+ if (!send_crlf (sd)) |
|
| 410 |
+ goto error; |
|
| 404 | 411 |
|
| 405 |
- /* receive reply from proxy */ |
|
| 406 |
- if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) |
|
| 407 |
- goto error; |
|
| 412 |
+ /* receive reply from proxy */ |
|
| 413 |
+ if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) |
|
| 414 |
+ goto error; |
|
| 415 |
+ |
|
| 416 |
+ /* remove trailing CR, LF */ |
|
| 417 |
+ chomp (buf); |
|
| 408 | 418 |
|
| 409 |
- /* remove trailing CR, LF */ |
|
| 410 |
- chomp (buf); |
|
| 419 |
+ msg (D_PROXY, "HTTP proxy returned: '%s'", buf); |
|
| 411 | 420 |
|
| 412 |
- msg (D_PROXY, "HTTP proxy returned: '%s'", buf); |
|
| 421 |
+ /* parse return string */ |
|
| 422 |
+ nparms = sscanf (buf, "%*s %d", &status); |
|
| 413 | 423 |
|
| 414 |
- /* parse return string */ |
|
| 415 |
- nparms = sscanf (buf, "%*s %d", &status); |
|
| 424 |
+ } |
|
| 416 | 425 |
|
| 417 | 426 |
/* check for a "407 Proxy Authentication Required" response */ |
| 418 |
- if (nparms >= 1 && status == 407) |
|
| 427 |
+ while (nparms >= 1 && status == 407) |
|
| 419 | 428 |
{
|
| 420 | 429 |
msg (D_PROXY, "Proxy requires authentication"); |
| 421 | 430 |
|
| 422 | 431 |
/* check for NTLM */ |
| 423 |
- if (p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2) |
|
| 432 |
+ if ((p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2) && !processed) |
|
| 424 | 433 |
{
|
| 425 | 434 |
#if NTLM |
| 426 | 435 |
/* look for the phase 2 response */ |
| ... | ... |
@@ -448,7 +645,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p, |
| 448 | 448 |
msg (D_PROXY, "Received NTLM Proxy-Authorization phase 2 response"); |
| 449 | 449 |
|
| 450 | 450 |
/* receive and discard everything else */ |
| 451 |
- while (recv_line (sd, NULL, 0, p->options.timeout, true, NULL, signal_received)) |
|
| 451 |
+ while (recv_line (sd, NULL, 0, 2, true, NULL, signal_received)) |
|
| 452 | 452 |
; |
| 453 | 453 |
|
| 454 | 454 |
/* now send the phase 3 reply */ |
| ... | ... |
@@ -472,7 +669,6 @@ establish_http_proxy_passthru (struct http_proxy_info *p, |
| 472 | 472 |
|
| 473 | 473 |
|
| 474 | 474 |
/* send HOST etc, */ |
| 475 |
- openvpn_sleep (1); |
|
| 476 | 475 |
openvpn_snprintf (buf, sizeof(buf), "Host: %s", host); |
| 477 | 476 |
msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); |
| 478 | 477 |
if (!send_line_crlf (sd, buf)) |
| ... | ... |
@@ -490,12 +686,10 @@ establish_http_proxy_passthru (struct http_proxy_info *p, |
| 490 | 490 |
} |
| 491 | 491 |
|
| 492 | 492 |
msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); |
| 493 |
- openvpn_sleep (1); |
|
| 494 | 493 |
if (!send_line_crlf (sd, buf)) |
| 495 | 494 |
goto error; |
| 496 | 495 |
/* ok so far... */ |
| 497 | 496 |
/* send empty CR, LF */ |
| 498 |
- openvpn_sleep (1); |
|
| 499 | 497 |
if (!send_crlf (sd)) |
| 500 | 498 |
goto error; |
| 501 | 499 |
|
| ... | ... |
@@ -510,27 +704,167 @@ establish_http_proxy_passthru (struct http_proxy_info *p, |
| 510 | 510 |
|
| 511 | 511 |
/* parse return string */ |
| 512 | 512 |
nparms = sscanf (buf, "%*s %d", &status); |
| 513 |
-#else |
|
| 514 |
- ASSERT (0); /* No NTLM support */ |
|
| 513 |
+ processed = true; |
|
| 515 | 514 |
#endif |
| 516 | 515 |
} |
| 517 |
- else if (p->auth_method == HTTP_AUTH_NONE && p->options.auth_retry) |
|
| 516 |
+#if PROXY_DIGEST_AUTH |
|
| 517 |
+ else if (p->auth_method == HTTP_AUTH_DIGEST && !processed) |
|
| 518 |
+ {
|
|
| 519 |
+ char *pa = p->proxy_authenticate; |
|
| 520 |
+ const int method = p->auth_method; |
|
| 521 |
+ ASSERT(pa); |
|
| 522 |
+ |
|
| 523 |
+ if (method == HTTP_AUTH_DIGEST) |
|
| 524 |
+ {
|
|
| 525 |
+ const char *http_method = "CONNECT"; |
|
| 526 |
+ const char *nonce_count = "00000001"; |
|
| 527 |
+ const char *qop = "auth"; |
|
| 528 |
+ const char *username = p->up.username; |
|
| 529 |
+ const char *password = p->up.password; |
|
| 530 |
+ char *opaque_kv = ""; |
|
| 531 |
+ char uri[128]; |
|
| 532 |
+ uint8_t cnonce_raw[8]; |
|
| 533 |
+ uint8_t *cnonce; |
|
| 534 |
+ HASHHEX session_key; |
|
| 535 |
+ HASHHEX response; |
|
| 536 |
+ |
|
| 537 |
+ const char *realm = get_pa_var("realm", pa, &gc);
|
|
| 538 |
+ const char *nonce = get_pa_var("nonce", pa, &gc);
|
|
| 539 |
+ const char *algor = get_pa_var("algorithm", pa, &gc);
|
|
| 540 |
+ const char *opaque = get_pa_var("opaque", pa, &gc);
|
|
| 541 |
+ |
|
| 542 |
+ /* generate a client nonce */ |
|
| 543 |
+ ASSERT(RAND_bytes(cnonce_raw, sizeof(cnonce_raw))); |
|
| 544 |
+ cnonce = make_base64_string2(cnonce_raw, sizeof(cnonce_raw), &gc); |
|
| 545 |
+ |
|
| 546 |
+ |
|
| 547 |
+ /* build the digest response */ |
|
| 548 |
+ openvpn_snprintf (uri, sizeof(uri), "%s:%d", |
|
| 549 |
+ host, |
|
| 550 |
+ port); |
|
| 551 |
+ |
|
| 552 |
+ if (opaque) |
|
| 553 |
+ {
|
|
| 554 |
+ const int len = strlen(opaque)+16; |
|
| 555 |
+ opaque_kv = gc_malloc(len, false, &gc); |
|
| 556 |
+ openvpn_snprintf (opaque_kv, len, ", opaque=\"%s\"", opaque); |
|
| 557 |
+ } |
|
| 558 |
+ |
|
| 559 |
+ DigestCalcHA1(algor, |
|
| 560 |
+ username, |
|
| 561 |
+ realm, |
|
| 562 |
+ password, |
|
| 563 |
+ nonce, |
|
| 564 |
+ cnonce, |
|
| 565 |
+ session_key); |
|
| 566 |
+ DigestCalcResponse(session_key, |
|
| 567 |
+ nonce, |
|
| 568 |
+ nonce_count, |
|
| 569 |
+ cnonce, |
|
| 570 |
+ qop, |
|
| 571 |
+ http_method, |
|
| 572 |
+ uri, |
|
| 573 |
+ NULL, |
|
| 574 |
+ response); |
|
| 575 |
+ |
|
| 576 |
+ /* format HTTP CONNECT message */ |
|
| 577 |
+ openvpn_snprintf (buf, sizeof(buf), "%s %s HTTP/%s", |
|
| 578 |
+ http_method, |
|
| 579 |
+ uri, |
|
| 580 |
+ p->options.http_version); |
|
| 581 |
+ |
|
| 582 |
+ msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); |
|
| 583 |
+ |
|
| 584 |
+ /* send HTTP CONNECT message to proxy */ |
|
| 585 |
+ if (!send_line_crlf (sd, buf)) |
|
| 586 |
+ goto error; |
|
| 587 |
+ |
|
| 588 |
+ /* send HOST etc, */ |
|
| 589 |
+ openvpn_snprintf (buf, sizeof(buf), "Host: %s", host); |
|
| 590 |
+ msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); |
|
| 591 |
+ if (!send_line_crlf (sd, buf)) |
|
| 592 |
+ goto error; |
|
| 593 |
+ |
|
| 594 |
+ /* send digest response */ |
|
| 595 |
+ openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", qop=%s, nc=%s, cnonce=\"%s\", response=\"%s\"%s", |
|
| 596 |
+ username, |
|
| 597 |
+ realm, |
|
| 598 |
+ nonce, |
|
| 599 |
+ uri, |
|
| 600 |
+ qop, |
|
| 601 |
+ nonce_count, |
|
| 602 |
+ cnonce, |
|
| 603 |
+ response, |
|
| 604 |
+ opaque_kv |
|
| 605 |
+ ); |
|
| 606 |
+ msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); |
|
| 607 |
+ if (!send_line_crlf (sd, buf)) |
|
| 608 |
+ goto error; |
|
| 609 |
+ if (!send_crlf (sd)) |
|
| 610 |
+ goto error; |
|
| 611 |
+ |
|
| 612 |
+ /* receive reply from proxy */ |
|
| 613 |
+ if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) |
|
| 614 |
+ goto error; |
|
| 615 |
+ |
|
| 616 |
+ /* remove trailing CR, LF */ |
|
| 617 |
+ chomp (buf); |
|
| 618 |
+ |
|
| 619 |
+ msg (D_PROXY, "HTTP proxy returned: '%s'", buf); |
|
| 620 |
+ |
|
| 621 |
+ /* parse return string */ |
|
| 622 |
+ nparms = sscanf (buf, "%*s %d", &status); |
|
| 623 |
+ processed = true; |
|
| 624 |
+ } |
|
| 625 |
+ else |
|
| 626 |
+ {
|
|
| 627 |
+ msg (D_PROXY, "HTTP proxy: digest method not supported"); |
|
| 628 |
+ goto error; |
|
| 629 |
+ } |
|
| 630 |
+ } |
|
| 631 |
+#endif |
|
| 632 |
+ else if (p->options.auth_retry) |
|
| 518 | 633 |
{
|
| 519 |
- /* |
|
| 520 |
- * Proxy needs authentication, but we don't have a user/pass. |
|
| 521 |
- * Now we will change p->auth_method and return true so that |
|
| 522 |
- * our caller knows to call us again on a newly opened socket. |
|
| 523 |
- * JYFIXME: This code needs to check proxy error output and set |
|
| 524 |
- * JYFIXME: p->auth_method = HTTP_AUTH_NTLM if necessary. |
|
| 525 |
- */ |
|
| 526 |
- p->auth_method = HTTP_AUTH_BASIC; |
|
| 527 |
- ret = true; |
|
| 528 |
- goto done; |
|
| 634 |
+ /* figure out what kind of authentication the proxy needs */ |
|
| 635 |
+ char *pa = NULL; |
|
| 636 |
+ const int method = get_proxy_authenticate(sd, |
|
| 637 |
+ p->options.timeout, |
|
| 638 |
+ &pa, |
|
| 639 |
+ NULL, |
|
| 640 |
+ signal_received); |
|
| 641 |
+ if (method != HTTP_AUTH_NONE) |
|
| 642 |
+ {
|
|
| 643 |
+ if (pa) |
|
| 644 |
+ msg (D_PROXY, "HTTP proxy authenticate '%s'", pa); |
|
| 645 |
+ if (p->options.auth_retry == PAR_NCT && method == HTTP_AUTH_BASIC) |
|
| 646 |
+ {
|
|
| 647 |
+ msg (D_PROXY, "HTTP proxy: support for basic auth and other cleartext proxy auth methods is disabled"); |
|
| 648 |
+ goto error; |
|
| 649 |
+ } |
|
| 650 |
+ p->auth_method = method; |
|
| 651 |
+ store_proxy_authenticate(p, pa); |
|
| 652 |
+ ret = true; |
|
| 653 |
+ goto done; |
|
| 654 |
+ } |
|
| 655 |
+ else |
|
| 656 |
+ {
|
|
| 657 |
+ msg (D_PROXY, "HTTP proxy: do not recognize the authentication method required by proxy"); |
|
| 658 |
+ free (pa); |
|
| 659 |
+ goto error; |
|
| 660 |
+ } |
|
| 529 | 661 |
} |
| 530 | 662 |
else |
| 531 |
- goto error; |
|
| 532 |
- } |
|
| 663 |
+ {
|
|
| 664 |
+ if (!processed) |
|
| 665 |
+ msg (D_PROXY, "HTTP proxy: no support for proxy authentication method"); |
|
| 666 |
+ goto error; |
|
| 667 |
+ } |
|
| 533 | 668 |
|
| 669 |
+ /* clear state */ |
|
| 670 |
+ if (p->options.auth_retry) |
|
| 671 |
+ clear_user_pass_http(); |
|
| 672 |
+ store_proxy_authenticate(p, NULL); |
|
| 673 |
+ } |
|
| 534 | 674 |
|
| 535 | 675 |
/* check return code, success = 200 */ |
| 536 | 676 |
if (nparms < 1 || status != 200) |
| ... | ... |
@@ -538,13 +872,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p, |
| 538 | 538 |
msg (D_LINK_ERRORS, "HTTP proxy returned bad status"); |
| 539 | 539 |
#if 0 |
| 540 | 540 |
/* DEBUGGING -- show a multi-line HTTP error response */ |
| 541 |
- while (true) |
|
| 542 |
- {
|
|
| 543 |
- if (!recv_line (sd, buf, sizeof (buf), p->options.timeout, true, NULL, signal_received)) |
|
| 544 |
- goto error; |
|
| 545 |
- chomp (buf); |
|
| 546 |
- msg (D_PROXY, "HTTP proxy returned: '%s'", buf); |
|
| 547 |
- } |
|
| 541 |
+ dump_residual(sd, p->options.timeout, signal_received); |
|
| 548 | 542 |
#endif |
| 549 | 543 |
goto error; |
| 550 | 544 |
} |
| ... | ... |
@@ -55,18 +55,24 @@ void show_win_proxy_settings (const int msglevel); |
| 55 | 55 |
#ifdef ENABLE_HTTP_PROXY |
| 56 | 56 |
|
| 57 | 57 |
/* HTTP CONNECT authentication methods */ |
| 58 |
-#define HTTP_AUTH_NONE 0 |
|
| 59 |
-#define HTTP_AUTH_BASIC 1 |
|
| 60 |
-#define HTTP_AUTH_NTLM 2 |
|
| 61 |
-#define HTTP_AUTH_N 3 |
|
| 62 |
-#define HTTP_AUTH_NTLM2 4 |
|
| 58 |
+#define HTTP_AUTH_NONE 0 |
|
| 59 |
+#define HTTP_AUTH_BASIC 1 |
|
| 60 |
+#define HTTP_AUTH_DIGEST 2 |
|
| 61 |
+#define HTTP_AUTH_NTLM 3 |
|
| 62 |
+#define HTTP_AUTH_NTLM2 4 |
|
| 63 |
+#define HTTP_AUTH_N 5 /* number of HTTP_AUTH methods */ |
|
| 63 | 64 |
|
| 64 | 65 |
struct http_proxy_options {
|
| 65 | 66 |
const char *server; |
| 66 | 67 |
int port; |
| 67 | 68 |
bool retry; |
| 68 | 69 |
int timeout; |
| 70 |
+ |
|
| 71 |
+# define PAR_NO 0 /* don't support any auth retries */ |
|
| 72 |
+# define PAR_ALL 1 /* allow all proxy auth protocols */ |
|
| 73 |
+# define PAR_NCT 2 /* disable cleartext proxy auth protocols */ |
|
| 69 | 74 |
bool auth_retry; |
| 75 |
+ |
|
| 70 | 76 |
const char *auth_method_string; |
| 71 | 77 |
const char *auth_file; |
| 72 | 78 |
const char *http_version; |
| ... | ... |
@@ -78,6 +84,7 @@ struct http_proxy_info {
|
| 78 | 78 |
int auth_method; |
| 79 | 79 |
struct http_proxy_options options; |
| 80 | 80 |
struct user_pass up; |
| 81 |
+ char *proxy_authenticate; |
|
| 81 | 82 |
}; |
| 82 | 83 |
|
| 83 | 84 |
struct http_proxy_info *http_proxy_new (const struct http_proxy_options *o, |
| ... | ... |
@@ -572,6 +572,15 @@ socket_defined (const socket_descriptor_t sd) |
| 572 | 572 |
#endif |
| 573 | 573 |
|
| 574 | 574 |
/* |
| 575 |
+ * Should we include proxy digest auth functionality |
|
| 576 |
+ */ |
|
| 577 |
+#if defined(USE_CRYPTO) && defined(ENABLE_HTTP_PROXY) |
|
| 578 |
+#define PROXY_DIGEST_AUTH 1 |
|
| 579 |
+#else |
|
| 580 |
+#define PROXY_DIGEST_AUTH 0 |
|
| 581 |
+#endif |
|
| 582 |
+ |
|
| 583 |
+/* |
|
| 575 | 584 |
* Should we include code common to all proxy methods? |
| 576 | 585 |
*/ |
| 577 | 586 |
#if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_SOCKS) |
| ... | ... |
@@ -1,4 +1,4 @@ |
| 1 |
-import os |
|
| 1 |
+import os, sys |
|
| 2 | 2 |
from wb import system, config, home_fn, cd_home |
| 3 | 3 |
|
| 4 | 4 |
os.environ['PATH'] += ";%s\\VC" % (os.path.normpath(config['MSVC']),) |
| ... | ... |
@@ -10,6 +10,13 @@ def main(): |
| 10 | 10 |
cd_home() |
| 11 | 11 |
build_vc("nmake /f %s" % (home_fn('msvc.mak'),))
|
| 12 | 12 |
|
| 13 |
+def clean(): |
|
| 14 |
+ cd_home() |
|
| 15 |
+ build_vc("nmake /f %s clean" % (home_fn('msvc.mak'),))
|
|
| 16 |
+ |
|
| 13 | 17 |
# if we are run directly, and not loaded as a module |
| 14 | 18 |
if __name__ == "__main__": |
| 15 |
- main() |
|
| 19 |
+ if len(sys.argv) == 2 and sys.argv[1] == 'clean': |
|
| 20 |
+ clean() |
|
| 21 |
+ else: |
|
| 22 |
+ main() |