We send an initial request, and we get back a response which looks like this: HTTP/1.1 401 Unauthorized server: IA Web Server connection: close content-type: text/html; charset=UTF-8 www-authenticate: Negotiate www-authenticate: Negotiate ... It looks like curl sees the first WWW-Authenticate: header and quite sanely calls gss_init_sec_context() once... Breakpoint 1, gss_init_sec_context (minor_status=minor_status@entry=0x7fffffffd110, claimant_cred_handle=claimant_cred_handle@entry=0x0, context_handle=context_handle@entry=0x634af8, target_name=0x813520, req_mech_type=req_mech_type@entry=0x0, req_flags=6, time_req=time_req@entry=0, input_chan_bindings=input_chan_bindings@entry=0x0, input_token=input_token@entry=0x7fffffffd120, actual_mech_type=actual_mech_type@entry=0x0, output_token=output_token@entry=0x7fffffffd130, ret_flags=ret_flags@entry=0x0, time_rec=time_rec@entry=0x0) at g_init_sec_context.c:113 113 { (gdb) p *input_token $2 = {length = 0, value = 0x0} (gdb) fini Run till exit from #0 gss_init_sec_context (minor_status=minor_status@entry=0x7fffffffd110, claimant_cred_handle=claimant_cred_handle@entry=0x0, context_handle=context_handle@entry=0x634af8, target_name=0x813520, req_mech_type=req_mech_type@entry=0x0, req_flags=6, time_req=time_req@entry=0, input_chan_bindings=input_chan_bindings@entry=0x0, input_token=input_token@entry=0x7fffffffd120, actual_mech_type=actual_mech_type@entry=0x0, output_token=output_token@entry=0x7fffffffd130, ret_flags=ret_flags@entry=0x0, time_rec=time_rec@entry=0x0) at g_init_sec_context.c:113 Curl_gss_init_sec_context (data=data@entry=0x62c110, minor_status=minor_status@entry=0x7fffffffd110, context=context@entry=0x634af8, target_name=<optimized out>, input_chan_bindings=input_chan_bindings@entry=0x0, input_token=input_token@entry=0x7fffffffd120, output_token=output_token@entry=0x7fffffffd130, ret_flags=ret_flags@entry=0x0) at curl_gssapi.c:67 67 } Value returned is $3 = 1 It obtained a valid ticket for the corresponding HTTP service here, and generated a suitable token for sending to the HTTP server, returning GSS_S_CONTINUE_NEEDED. (gdb) p *output_token $5 = {length = 3671, value = 0x90f5b0} (gdb) x/40xb 0x90f5b0 0x90f5b0: 0x60 0x82 0x0e 0x53 0x06 0x09 0x2a 0x86 0x90f5b8: 0x48 0x86 0xf7 0x12 0x01 0x02 0x02 0x01 0x90f5c0: 0x00 0x6e 0x82 0x0e 0x42 0x30 0x82 0x0e 0x90f5c8: 0x3e 0xa0 0x03 0x02 0x01 0x05 0xa1 0x03 0x90f5d0: 0x02 0x01 0x0e 0xa2 0x07 0x03 0x05 0x00 OK, so far so good... (gdb) c Continuing. < www-authenticate: Negotiate www-authenticate: Negotiate Breakpoint 1, gss_init_sec_context (minor_status=minor_status@entry=0x7fffffffd110, claimant_cred_handle=claimant_cred_handle@entry=0x0, context_handle=context_handle@entry=0x634af8, target_name=0x813520, req_mech_type=req_mech_type@entry=0x0, req_flags=6, time_req=time_req@entry=0, input_chan_bindings=input_chan_bindings@entry=0x0, input_token=input_token@entry=0x7fffffffd120, actual_mech_type=actual_mech_type@entry=0x0, output_token=output_token@entry=0x7fffffffd130, ret_flags=ret_flags@entry=0x0, time_rec=time_rec@entry=0x0) at g_init_sec_context.c:113 Er, but now it hits the second WWW-Authenticate: header, still in the *first* (and only) HTTP response from the server. Invokes gss_init_sec_context() again, with the same context handle, and an empty input_token again. (gdb) p *input_token $6 = {length = 0, value = 0x0} (gdb) fini Run till exit from #0 gss_init_sec_context (minor_status=minor_status@entry=0x7fffffffd110, claimant_cred_handle=claimant_cred_handle@entry=0x0, context_handle=context_handle@entry=0x634af8, target_name=0x813520, req_mech_type=req_mech_type@entry=0x0, req_flags=6, time_req=time_req@entry=0, input_chan_bindings=input_chan_bindings@entry=0x0, input_token=input_token@entry=0x7fffffffd120, actual_mech_type=actual_mech_type@entry=0x0, output_token=output_token@entry=0x7fffffffd130, ret_flags=ret_flags@entry=0x0, time_rec=time_rec@entry=0x0) at g_init_sec_context.c:113 Curl_gss_init_sec_context (data=data@entry=0x62c110, minor_status=minor_status@entry=0x7fffffffd110, context=context@entry=0x634af8, target_name=<optimized out>, input_chan_bindings=input_chan_bindings@entry=0x0, input_token=input_token@entry=0x7fffffffd120, output_token=output_token@entry=0x7fffffffd130, ret_flags=ret_flags@entry=0x0) at curl_gssapi.c:67 67 } Value returned is $7 = 589824 (gdb) p/x 589824 $8 = 0x90000 This time we get GSS_S_DEFECTIVE_TOKEN. It wasn't expecting an empty token now. So we end up sending a further request to the server, with *no* Authentication: header. Get another response from the server with two 'WWW-Authenticate: Negotiate' headers, call gss_init_sec_context() for the same context another two times with empty input tokens, getting GSS_S_DEFECTIVE_TOKEN each time. And authentication fails.
FWIW firefox also fails, now the server has started doing this. I don't actually think the server is wrong, is it? Just misguided, perhaps. I haven't debugged the firefox behaviour; curl was easier...
(In reply to David Woodhouse from comment #1) > FWIW firefox also fails, now the server has started doing this. I don't > actually think the server is wrong, is it? If I understand it correctly, it is not curl's behavior what changed. The server in question just started to send duplicated HTTP headers for no apparent reason. I believe it makes sense to get curl ready for this. We should probably also notify the maintainers of the server as the change seems to break many clients.
Created attachment 892526 [details] http: avoid auth failure on a duplicated header [NOT TESTED]
David, could you please check whether the attached patch fixes the problem?
Yes, that fixes it. Thanks. (Firefox is *not* failing, btw. It did fail... and that's why I was looking with curl. But by the time I looked again, Firefox was working again and I don't know why it ever didn't).
Thanks you for testing the patch, David! I have proposed the patch upstream: http://thread.gmane.org/gmane.comp.web.curl.library/42368 Hopefully it was not a change on the server what made it work in both cases :-)
upstream commit: https://github.com/bagder/curl/commit/ec5fde24
fixed in curl-7.36.0-4.fc21
curl-7.29.0-19.fc19 has been submitted as an update for Fedora 19. https://admin.fedoraproject.org/updates/curl-7.29.0-19.fc19
curl-7.32.0-10.fc20 has been submitted as an update for Fedora 20. https://admin.fedoraproject.org/updates/curl-7.32.0-10.fc20
Package curl-7.32.0-10.fc20: * should fix your issue, * was pushed to the Fedora 20 testing repository, * should be available at your local mirror within two days. Update it with: # su -c 'yum update --enablerepo=updates-testing curl-7.32.0-10.fc20' as soon as you are able to. Please go to the following url: https://admin.fedoraproject.org/updates/FEDORA-2014-6241/curl-7.32.0-10.fc20 then log in and leave karma (feedback).
curl-7.32.0-10.fc20 has been pushed to the Fedora 20 stable repository. If problems still persist, please make note of it in this bug report.
curl-7.29.0-19.fc19 has been pushed to the Fedora 19 stable repository. If problems still persist, please make note of it in this bug report.