1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
|
From 795a6b48946f22d4562e6ad859306ac62eb3f6a0 Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Fri, 3 Nov 2006 12:43:55 +0000
Subject: [PATCH 1/4] Olaf Stueben provided a patch that I edited slightly. It
fixes the notorious KNOWN_BUGS #25, which happens when
a proxy closes the connection when libcurl has sent
CONNECT, as part of an authentication negotiation.
Starting now, libcurl will re-connect accordingly and
continue the authentication as it should.
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
lib/http.c | 15 +++++++++++++++
lib/url.c | 54 +++++++++++++++++++++++++++++++++---------------------
lib/urldata.h | 3 +++
3 files changed, 51 insertions(+), 21 deletions(-)
diff --git a/lib/http.c b/lib/http.c
index 0fd0cbe..4d39a98 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -1095,6 +1095,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
curl_socket_t tunnelsocket = conn->sock[sockindex];
send_buffer *req_buffer;
curl_off_t cl=0;
+ bool closeConnection = FALSE;
#define SELECT_OK 0
#define SELECT_ERROR 1
@@ -1102,6 +1103,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
int error = SELECT_OK;
infof(data, "Establish HTTP proxy tunnel to %s:%d\n", hostname, remote_port);
+ conn->bits.proxy_connect_closed = FALSE;
do {
if(conn->newurl) {
@@ -1295,6 +1297,9 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
cl = curlx_strtoofft(line_start + strlen("Content-Length:"),
NULL, 10);
}
+ else if(Curl_compareheader(line_start,
+ "Connection:", "close"))
+ closeConnection = TRUE;
else if(2 == sscanf(line_start, "HTTP/1.%d %d",
&subversion,
&k->httpcode)) {
@@ -1321,11 +1326,21 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
headers. 'newurl' is set to a new URL if we must loop. */
Curl_http_auth_act(conn);
+ if (closeConnection && conn->newurl) {
+ /* Connection closed by server. Don't use it anymore */
+ sclose(conn->sock[sockindex]);
+ conn->sock[sockindex] = CURL_SOCKET_BAD;
+ break;
+ }
} while(conn->newurl);
if(200 != k->httpcode) {
failf(data, "Received HTTP code %d from proxy after CONNECT",
k->httpcode);
+
+ if (closeConnection && conn->newurl)
+ conn->bits.proxy_connect_closed = TRUE;
+
return CURLE_RECV_ERROR;
}
diff --git a/lib/url.c b/lib/url.c
index 1a0c206..bf4a3dd 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -2484,7 +2484,8 @@ CURLcode Curl_protocol_connect(struct connectdata *conn, bool *protocol_done)
/* it has started, possibly even completed but that knowledge isn't stored
in this bit! */
- conn->bits.protoconnstart = TRUE;
+ if (!result)
+ conn->bits.protoconnstart = TRUE;
}
return result; /* pass back status */
@@ -3981,30 +3982,41 @@ static CURLcode SetupConnection(struct connectdata *conn,
data->state.crlf_conversions = 0; /* reset CRLF conversion counter */
#endif /* CURL_DO_LINEEND_CONV */
- if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) {
- bool connected = FALSE;
+ for(;;) {
+ /* loop for CURL_SERVER_CLOSED_CONNECTION */
- /* Connect only if not already connected! */
- result = ConnectPlease(conn, hostaddr, &connected);
+ if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) {
+ bool connected = FALSE;
- if(connected) {
- result = Curl_protocol_connect(conn, protocol_done);
- if(CURLE_OK == result)
- conn->bits.tcpconnect = TRUE;
- }
- else
- conn->bits.tcpconnect = FALSE;
+ /* Connect only if not already connected! */
+ result = ConnectPlease(conn, hostaddr, &connected);
+ if(connected) {
+ result = Curl_protocol_connect(conn, protocol_done);
+ if(CURLE_OK == result)
+ conn->bits.tcpconnect = TRUE;
+ }
+ else
+ conn->bits.tcpconnect = FALSE;
- if(CURLE_OK != result)
- return result;
- }
- else {
- Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */
- conn->bits.tcpconnect = TRUE;
- *protocol_done = TRUE;
- if(data->set.verbose)
- verboseconnect(conn);
+ /* if the connection was closed by the server while exchanging
+ authentication informations, retry with the new set
+ authentication information */
+ if(conn->bits.proxy_connect_closed)
+ continue;
+
+ if(CURLE_OK != result)
+ return result;
+ }
+ else {
+ Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */
+ conn->bits.tcpconnect = TRUE;
+ *protocol_done = TRUE;
+ if(data->set.verbose)
+ verboseconnect(conn);
+ }
+ /* Stop the loop now */
+ break;
}
conn->now = Curl_tvnow(); /* time this *after* the connect is done, we
diff --git a/lib/urldata.h b/lib/urldata.h
index d092113..3ac8fbf 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -454,6 +454,9 @@ struct ConnectBits {
when Curl_done() is called, to prevent Curl_done() to
get invoked twice when the multi interface is
used. */
+ bool proxy_connect_closed; /* set true if a proxy disconnected the
+ connection in a CONNECT request with auth, so
+ that libcurl should reconnect and continue. */
};
struct hostname {
--
1.7.4.4
From e3c76c19fd8d61f41b4025c4f085413dd9935e28 Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Tue, 10 Jul 2007 22:31:13 +0000
Subject: [PATCH 2/4] Giancarlo Formicuccia reported and fixed a problem with
a closed connection to a proxy during CONNECT auth
negotiation.
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
lib/http.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/lib/http.c b/lib/http.c
index 4d39a98..6481fa0 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -1300,6 +1300,9 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
else if(Curl_compareheader(line_start,
"Connection:", "close"))
closeConnection = TRUE;
+ else if(Curl_compareheader(line_start,
+ "Proxy-Connection:", "close"))
+ closeConnection = TRUE;
else if(2 == sscanf(line_start, "HTTP/1.%d %d",
&subversion,
&k->httpcode)) {
--
1.7.4.4
From c1bfdb84733e58b11dce10eb2c99bf4c1f5c8806 Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Fri, 21 Sep 2007 11:05:31 +0000
Subject: [PATCH 3/4] Mark Davies fixed Negotiate authentication over proxy,
and also introduced the --proxy-negotiate command line
option to allow a user to explicitly select it.
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
docs/curl.1 | 11 +++++++++++
lib/http.c | 16 ++++++++++++++--
lib/http_negotiate.c | 14 +++++++-------
lib/http_negotiate.h | 4 ++--
src/main.c | 11 +++++++++++
5 files changed, 45 insertions(+), 11 deletions(-)
diff --git a/docs/curl.1 b/docs/curl.1
index e62be55..2658954 100644
--- a/docs/curl.1
+++ b/docs/curl.1
@@ -688,6 +688,9 @@ meant as a support for Kerberos5 authentication but may be also used along
with another authentication methods. For more information see IETF draft
draft-brezak-spnego-http-04.txt.
+If you want to enable Negotiate for your proxy authentication, then use
+\fI--proxy-negotiate\fP.
+
This option requires that the library was built with GSSAPI support. This is
not very common. Use \fI-V/--version\fP to see if your version supports
GSS-Negotiate.
@@ -768,6 +771,14 @@ Tells curl to use HTTP Digest authentication when communicating with the given
proxy. Use \fI--digest\fP for enabling HTTP Digest with a remote host.
If this option is used twice, the second will again disable proxy HTTP Digest.
+.IP "--proxy-negotiate"
+Tells curl to use HTTP Negotiate authentication when communicating
+with the given proxy. Use \fI--negotiate\fP for enabling HTTP Negotiate
+with a remote host.
+
+If this option is used twice, the second will again disable proxy HTTP
+Negotiate.
+
.IP "--proxy-ntlm"
Tells curl to use HTTP NTLM authentication when communicating with the given
proxy. Use \fI--ntlm\fP for enabling NTLM with a remote host.
diff --git a/lib/http.c b/lib/http.c
index 6481fa0..033ee9b 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -416,6 +416,18 @@ Curl_http_output_auth(struct connectdata *conn,
/* Send proxy authentication header if needed */
if (conn->bits.httpproxy &&
(conn->bits.tunnel_proxy == proxytunnel)) {
+#ifdef HAVE_GSSAPI
+ if((authproxy->picked == CURLAUTH_GSSNEGOTIATE) &&
+ data->state.negotiate.context &&
+ !GSS_ERROR(data->state.negotiate.status)) {
+ auth="GSS-Negotiate";
+ result = Curl_output_negotiate(conn, TRUE);
+ if (result)
+ return result;
+ authproxy->done = TRUE;
+ }
+ else
+#endif
#ifdef USE_NTLM
if(authproxy->picked == CURLAUTH_NTLM) {
auth=(char *)"NTLM";
@@ -478,7 +490,7 @@ Curl_http_output_auth(struct connectdata *conn,
data->state.negotiate.context &&
!GSS_ERROR(data->state.negotiate.status)) {
auth=(char *)"GSS-Negotiate";
- result = Curl_output_negotiate(conn);
+ result = Curl_output_negotiate(conn, FALSE);
if (result)
return result;
authhost->done = TRUE;
@@ -585,7 +597,7 @@ CURLcode Curl_http_input_auth(struct connectdata *conn,
authp->avail |= CURLAUTH_GSSNEGOTIATE;
if(authp->picked == CURLAUTH_GSSNEGOTIATE) {
/* if exactly this is wanted, go */
- int neg = Curl_input_negotiate(conn, start);
+ int neg = Curl_input_negotiate(conn, (bool)(httpcode == 407), start);
if (neg == 0) {
conn->newurl = strdup(data->change.url);
data->state.authproblem = (conn->newurl == NULL);
diff --git a/lib/http_negotiate.c b/lib/http_negotiate.c
index 3fc678f..73deda5 100644
--- a/lib/http_negotiate.c
+++ b/lib/http_negotiate.c
@@ -49,7 +49,7 @@
#include "memdebug.h"
static int
-get_gss_name(struct connectdata *conn, gss_name_t *server)
+get_gss_name(struct connectdata *conn, bool proxy, gss_name_t *server)
{
struct negotiatedata *neg_ctx = &conn->data->state.negotiate;
OM_uint32 major_status, minor_status;
@@ -69,11 +69,11 @@ get_gss_name(struct connectdata *conn, gss_name_t *server)
else
service = "HTTP";
- token.length = strlen(service) + 1 + strlen(conn->host.name) + 1;
+ token.length = strlen(service) + 1 + strlen(proxy ? conn->proxy.name : conn->host.name) + 1;
if (token.length + 1 > sizeof(name))
return EMSGSIZE;
- snprintf(name, sizeof(name), "%s@%s", service, conn->host.name);
+ snprintf(name, sizeof(name), "%s@%s", service, proxy ? conn->proxy.name : conn->host.name);
token.value = (void *) name;
major_status = gss_import_name(&minor_status,
@@ -113,7 +113,7 @@ log_gss_error(struct connectdata *conn, OM_uint32 error_status, char *prefix)
infof(conn->data, "%s", buf);
}
-int Curl_input_negotiate(struct connectdata *conn, char *header)
+int Curl_input_negotiate(struct connectdata *conn, bool proxy, char *header)
{
struct negotiatedata *neg_ctx = &conn->data->state.negotiate;
OM_uint32 major_status, minor_status, minor_status2;
@@ -169,7 +169,7 @@ int Curl_input_negotiate(struct connectdata *conn, char *header)
}
if (neg_ctx->server_name == NULL &&
- (ret = get_gss_name(conn, &neg_ctx->server_name)))
+ (ret = get_gss_name(conn, proxy, &neg_ctx->server_name)))
return ret;
header += strlen(neg_ctx->protocol);
@@ -258,7 +258,7 @@ int Curl_input_negotiate(struct connectdata *conn, char *header)
}
-CURLcode Curl_output_negotiate(struct connectdata *conn)
+CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy)
{
struct negotiatedata *neg_ctx = &conn->data->state.negotiate;
char *encoded = NULL;
@@ -310,7 +310,7 @@ CURLcode Curl_output_negotiate(struct connectdata *conn)
return CURLE_OUT_OF_MEMORY;
conn->allocptr.userpwd =
- aprintf("Authorization: %s %s\r\n", neg_ctx->protocol, encoded);
+ aprintf("%sAuthorization: %s %s\r\n", proxy ? "Proxy-" : "", neg_ctx->protocol, encoded);
free(encoded);
Curl_cleanup_negotiate (conn->data);
return (conn->allocptr.userpwd == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK;
diff --git a/lib/http_negotiate.h b/lib/http_negotiate.h
index cf8b048..8604a0c 100644
--- a/lib/http_negotiate.h
+++ b/lib/http_negotiate.h
@@ -27,10 +27,10 @@
#ifdef HAVE_GSSAPI
/* this is for Negotiate header input */
-int Curl_input_negotiate(struct connectdata *conn, char *header);
+int Curl_input_negotiate(struct connectdata *conn, bool proxy, char *header);
/* this is for creating Negotiate header output */
-CURLcode Curl_output_negotiate(struct connectdata *conn);
+CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy);
void Curl_cleanup_negotiate(struct SessionHandle *data);
diff --git a/src/main.c b/src/main.c
index 9f378db..44dd2c4 100644
--- a/src/main.c
+++ b/src/main.c
@@ -309,6 +309,7 @@ struct Configurable {
bool create_dirs;
bool ftp_create_dirs;
bool ftp_skip_ip;
+ bool proxynegotiate;
bool proxyntlm;
bool proxydigest;
bool proxybasic;
@@ -555,6 +556,7 @@ static void help(void)
" --proxy-anyauth Pick \"any\" proxy authentication method (H)",
" --proxy-basic Use Basic authentication on the proxy (H)",
" --proxy-digest Use Digest authentication on the proxy (H)",
+ " --proxy-negotiate Use Negotiate authentication on the proxy (H)",
" --proxy-ntlm Use NTLM authentication on the proxy (H)",
" -P/--ftp-port <address> Use PORT with address instead of PASV (F)",
" -q If used as the first parameter disables .curlrc",
@@ -1347,6 +1349,7 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
{"$t", "socks4", TRUE},
{"$u", "ftp-alternative-to-user", TRUE},
{"$v", "ftp-ssl-reqd", FALSE},
+ {"$w", "proxy-negotiate", FALSE},
{"0", "http1.0", FALSE},
{"1", "tlsv1", FALSE},
@@ -1789,6 +1792,12 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
case 'v': /* --ftp-ssl-reqd */
config->ftp_ssl_reqd ^= TRUE;
break;
+ case 'w': /* --proxy-negotiate */
+ if(curlinfo->features & CURL_VERSION_GSSNEGOTIATE)
+ config->proxynegotiate ^= TRUE;
+ else
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
}
break;
case '#': /* --progress-bar */
@@ -3960,6 +3969,8 @@ operate(struct Configurable *config, int argc, char *argv[])
config->ftp_create_dirs);
if(config->proxyanyauth)
curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
+ else if(config->proxynegotiate)
+ curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_GSSNEGOTIATE);
else if(config->proxyntlm)
curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_NTLM);
else if(config->proxydigest)
--
1.7.4.4
From 88507544781155092ccee225bff92a0177e0f4df Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Mon, 16 Aug 2010 22:19:38 +0200
Subject: [PATCH 4/4] negotiation: Wrong proxy authorization
There's an error in http_negotiation.c where a mistake is using only
userpwd even for proxy requests. Ludek provided a patch, but I decided
to write the fix slightly different using his patch as inspiration.
Reported by: Ludek Finstrle
Bug: http://curl.haxx.se/bug/view.cgi?id=3046066
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
lib/http_negotiate.c | 12 +++++++++---
1 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/lib/http_negotiate.c b/lib/http_negotiate.c
index 73deda5..1d6119d 100644
--- a/lib/http_negotiate.c
+++ b/lib/http_negotiate.c
@@ -263,6 +263,7 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy)
struct negotiatedata *neg_ctx = &conn->data->state.negotiate;
char *encoded = NULL;
int len;
+ char *userp;
#ifdef HAVE_SPNEGO /* Handle SPNEGO */
if (checkprefix("Negotiate",neg_ctx->protocol)) {
@@ -309,11 +310,16 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy)
if (len < 0)
return CURLE_OUT_OF_MEMORY;
- conn->allocptr.userpwd =
- aprintf("%sAuthorization: %s %s\r\n", proxy ? "Proxy-" : "", neg_ctx->protocol, encoded);
+ userp = aprintf("%sAuthorization: %s %s\r\n", proxy ? "Proxy-" : "",
+ neg_ctx->protocol, encoded);
+
+ if(proxy)
+ conn->allocptr.proxyuserpwd = userp;
+ else
+ conn->allocptr.userpwd = userp;
free(encoded);
Curl_cleanup_negotiate (conn->data);
- return (conn->allocptr.userpwd == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK;
+ return (userp == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK;
}
void Curl_cleanup_negotiate(struct SessionHandle *data)
--
1.7.4.4
|