506
* Output the correct authentication header depending on the auth type
507
* and whether or not it is to a proxy.
510
output_auth_headers(struct connectdata *conn,
511
struct auth *authstatus,
516
struct SessionHandle *data = conn->data;
517
const char *auth=NULL;
518
CURLcode result = CURLE_OK;
520
struct negotiatedata *negdata = proxy?
521
&data->state.proxyneg:&data->state.negotiate;
524
#ifndef CURL_DISABLE_CRYPTO_AUTH
530
if((authstatus->picked == CURLAUTH_GSSNEGOTIATE) &&
531
negdata->context && !GSS_ERROR(negdata->status)) {
532
auth="GSS-Negotiate";
533
result = Curl_output_negotiate(conn, proxy);
536
authstatus->done = TRUE;
537
negdata->state = GSS_AUTHSENT;
542
if(authstatus->picked == CURLAUTH_NTLM) {
544
result = Curl_output_ntlm(conn, proxy);
550
#ifndef CURL_DISABLE_CRYPTO_AUTH
551
if(authstatus->picked == CURLAUTH_DIGEST) {
553
result = Curl_output_digest(conn,
555
(const unsigned char *)request,
556
(const unsigned char *)path);
562
if(authstatus->picked == CURLAUTH_BASIC) {
564
if((proxy && conn->bits.proxy_user_passwd &&
565
!checkheaders(data, "Proxy-authorization:")) ||
566
(!proxy && conn->bits.user_passwd &&
567
!checkheaders(data, "Authorization:"))) {
569
result = http_output_basic(conn, proxy);
573
/* NOTE: this function should set 'done' TRUE, as the other auth
574
functions work that way */
575
authstatus->done = TRUE;
579
infof(data, "%s auth using %s with user '%s'\n",
580
proxy?"Proxy":"Server", auth,
581
proxy?(conn->proxyuser?conn->proxyuser:""):
582
(conn->user?conn->user:""));
583
authstatus->multi = (bool)(!authstatus->done);
586
authstatus->multi = FALSE;
433
592
* Curl_http_output_auth() setups the authentication headers for the
434
593
* host/proxy and the correct authentication
482
640
and if this is one single bit it'll be used instantly. */
483
641
authproxy->picked = authproxy->want;
643
#ifndef CURL_DISABLE_PROXY
485
644
/* Send proxy authentication header if needed */
486
645
if(conn->bits.httpproxy &&
487
646
(conn->bits.tunnel_proxy == proxytunnel)) {
489
if((authproxy->picked == CURLAUTH_GSSNEGOTIATE) &&
490
data->state.negotiate.context &&
491
!GSS_ERROR(data->state.negotiate.status)) {
492
auth="GSS-Negotiate";
493
result = Curl_output_negotiate(conn, TRUE);
496
authproxy->done = TRUE;
501
if(authproxy->picked == CURLAUTH_NTLM) {
503
result = Curl_output_ntlm(conn, TRUE);
509
if(authproxy->picked == CURLAUTH_BASIC) {
511
if(conn->bits.proxy_user_passwd &&
512
!checkheaders(data, "Proxy-authorization:")) {
514
result = http_output_basic(conn, TRUE);
518
/* NOTE: http_output_basic() should set 'done' TRUE, as the other auth
519
functions work that way */
520
authproxy->done = TRUE;
522
#ifndef CURL_DISABLE_CRYPTO_AUTH
523
else if(authproxy->picked == CURLAUTH_DIGEST) {
525
result = Curl_output_digest(conn,
527
(const unsigned char *)request,
528
(const unsigned char *)path);
534
infof(data, "Proxy auth using %s with user '%s'\n",
535
auth, conn->proxyuser?conn->proxyuser:"");
536
authproxy->multi = (bool)(!authproxy->done);
539
authproxy->multi = FALSE;
647
result = output_auth_headers(conn, authproxy, request, path, TRUE);
654
#endif /* CURL_DISABLE_PROXY */
542
655
/* we have no proxy so let's pretend we're done authenticating
544
657
authproxy->done = TRUE;
548
661
if(!data->state.this_is_a_follow ||
549
662
conn->bits.netrc ||
550
663
!data->state.first_host ||
551
curl_strequal(data->state.first_host, conn->host.name) ||
552
data->set.http_disable_hostname_check_before_authentication) {
554
/* Send web authentication header if needed */
558
if((authhost->picked == CURLAUTH_GSSNEGOTIATE) &&
559
data->state.negotiate.context &&
560
!GSS_ERROR(data->state.negotiate.status)) {
561
auth="GSS-Negotiate";
562
result = Curl_output_negotiate(conn, FALSE);
565
authhost->done = TRUE;
570
if(authhost->picked == CURLAUTH_NTLM) {
572
result = Curl_output_ntlm(conn, FALSE);
579
#ifndef CURL_DISABLE_CRYPTO_AUTH
580
if(authhost->picked == CURLAUTH_DIGEST) {
582
result = Curl_output_digest(conn,
583
FALSE, /* not a proxy */
584
(const unsigned char *)request,
585
(const unsigned char *)path);
590
if(authhost->picked == CURLAUTH_BASIC) {
591
if(conn->bits.user_passwd &&
592
!checkheaders(data, "Authorization:")) {
594
result = http_output_basic(conn, FALSE);
598
/* basic is always ready */
599
authhost->done = TRUE;
603
infof(data, "Server auth using %s with user '%s'\n",
606
authhost->multi = (bool)(!authhost->done);
609
authhost->multi = FALSE;
664
data->set.http_disable_hostname_check_before_authentication ||
665
Curl_raw_equal(data->state.first_host, conn->host.name)) {
666
result = output_auth_headers(conn, authhost, request, path, FALSE);
613
669
authhost->done = TRUE;
657
713
* If the provided authentication is wanted as one out of several accepted
658
714
* types (using &), we OR this authentication type to the authavail
719
* ->picked is first set to the 'want' value (one or more bits) before the
720
* request is sent, and then it is again set _after_ all response 401/407
721
* headers have been received but then only to a single preferred method
662
726
#ifdef HAVE_GSSAPI
663
727
if(checkprefix("GSS-Negotiate", start) ||
664
728
checkprefix("Negotiate", start)) {
665
730
*availp |= CURLAUTH_GSSNEGOTIATE;
666
731
authp->avail |= CURLAUTH_GSSNEGOTIATE;
667
if(authp->picked == CURLAUTH_GSSNEGOTIATE) {
668
/* if exactly this is wanted, go */
669
int neg = Curl_input_negotiate(conn, (bool)(httpcode == 407), start);
733
if(data->state.negotiate.state == GSS_AUTHSENT) {
734
/* if we sent GSS authentication in the outgoing request and we get this
735
back, we're in trouble */
736
infof(data, "Authentication problem. Ignoring this.\n");
737
data->state.authproblem = TRUE;
740
neg = Curl_input_negotiate(conn, (bool)(httpcode == 407), start);
742
DEBUGASSERT(!data->req.newurl);
671
743
data->req.newurl = strdup(data->change.url);
672
data->state.authproblem = (data->req.newurl == NULL);
675
infof(data, "Authentication problem. Ignoring this.\n");
676
data->state.authproblem = TRUE;
744
if(!data->req.newurl)
745
return CURLE_OUT_OF_MEMORY;
746
data->state.authproblem = FALSE;
747
/* we received GSS auth info and we dealt with it fine */
748
data->state.negotiate.state = GSS_AUTHRECV;
2088
2182
ptr = checkheaders(data, "Host:");
2089
2183
if(ptr && (!data->state.this_is_a_follow ||
2090
curl_strequal(data->state.first_host, conn->host.name))) {
2184
Curl_raw_equal(data->state.first_host, conn->host.name))) {
2091
2185
#if !defined(CURL_DISABLE_COOKIES)
2092
2186
/* If we have a given custom Host: header, we extract the host name in
2093
2187
order to possibly use it for cookie reasons later on. We only allow the
2094
2188
custom Host: header if this is NOT a redirect, as setting Host: in the
2095
2189
redirected request is being out on thin ice. Except if the host name
2096
2190
is the same as the first one! */
2097
char *start = ptr+strlen("Host:");
2098
while(*start && ISSPACE(*start ))
2100
ptr = start; /* start host-scanning here */
2102
/* scan through the string to find the end (space or colon) */
2103
while(*ptr && !ISSPACE(*ptr) && !(':'==*ptr))
2107
size_t len=ptr-start;
2191
char *cookiehost = Curl_copy_header_value(ptr);
2193
return CURLE_OUT_OF_MEMORY;
2195
/* ignore empty data */
2198
char *colon = strchr(cookiehost, ':');
2200
*colon = 0; /* The host must not include an embedded port number */
2108
2201
Curl_safefree(conn->allocptr.cookiehost);
2109
conn->allocptr.cookiehost = malloc(len+1);
2110
if(!conn->allocptr.cookiehost)
2111
return CURLE_OUT_OF_MEMORY;
2112
memcpy(conn->allocptr.cookiehost, start, len);
2113
conn->allocptr.cookiehost[len]=0;
2202
conn->allocptr.cookiehost = cookiehost;
2664
2760
if(conn->bits.authneg)
2667
2763
/* figure out the size of the postfields */
2668
2764
postsize = (data->set.postfieldsize != -1)?
2669
2765
data->set.postfieldsize:
2670
2766
(data->set.postfields? (curl_off_t)strlen(data->set.postfields):0);
2768
if(!data->req.upload_chunky) {
2769
/* We only set Content-Length and allow a custom Content-Length if
2770
we don't upload data chunked, as RFC2616 forbids us to set both
2771
kinds of headers (Transfer-Encoding: chunked and Content-Length) */
2773
if(!checkheaders(data, "Content-Length:")) {
2774
/* we allow replacing this header, although it isn't very wise to
2775
actually set your own */
2776
result = add_bufferf(req_buffer,
2777
"Content-Length: %" FORMAT_OFF_T"\r\n",
2784
if(!checkheaders(data, "Content-Type:")) {
2785
result = add_bufferf(req_buffer,
2786
"Content-Type: application/x-www-form-urlencoded\r\n");
2791
/* For really small posts we don't use Expect: headers at all, and for
2792
the somewhat bigger ones we allow the app to disable it. Just make
2793
sure that the expect100header is always set to the preferred value
2795
if(postsize > TINY_INITIAL_POST_SIZE) {
2796
result = expect100(data, conn, req_buffer);
2801
data->state.expect100header = FALSE;
2803
if(data->set.postfields) {
2805
if(!data->state.expect100header &&
2806
(postsize < MAX_INITIAL_POST_SIZE)) {
2807
/* if we don't use expect: 100 AND
2808
postsize is less than MAX_INITIAL_POST_SIZE
2810
then append the post data to the HTTP request header. This limit
2811
is no magic limit but only set to prevent really huge POSTs to
2812
get the data duplicated with malloc() and family. */
2814
result = add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
2672
2818
if(!data->req.upload_chunky) {
2673
/* We only set Content-Length and allow a custom Content-Length if
2674
we don't upload data chunked, as RFC2616 forbids us to set both
2675
kinds of headers (Transfer-Encoding: chunked and Content-Length) */
2677
if(!checkheaders(data, "Content-Length:")) {
2678
/* we allow replacing this header, although it isn't very wise to
2679
actually set your own */
2680
result = add_bufferf(req_buffer,
2681
"Content-Length: %" FORMAT_OFF_T"\r\n",
2688
if(!checkheaders(data, "Content-Type:")) {
2689
result = add_bufferf(req_buffer,
2690
"Content-Type: application/x-www-form-urlencoded\r\n");
2695
/* For really small posts we don't use Expect: headers at all, and for
2696
the somewhat bigger ones we allow the app to disable it. Just make
2697
sure that the expect100header is always set to the preferred value
2699
if(postsize > TINY_INITIAL_POST_SIZE) {
2700
result = expect100(data, req_buffer);
2705
data->state.expect100header = FALSE;
2707
if(data->set.postfields) {
2709
if(!data->state.expect100header &&
2710
(postsize < MAX_INITIAL_POST_SIZE)) {
2711
/* if we don't use expect: 100 AND
2712
postsize is less than MAX_INITIAL_POST_SIZE
2714
then append the post data to the HTTP request header. This limit
2715
is no magic limit but only set to prevent really huge POSTs to
2716
get the data duplicated with malloc() and family. */
2718
result = add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
2722
if(!data->req.upload_chunky) {
2723
/* We're not sending it 'chunked', append it to the request
2724
already now to reduce the number if send() calls */
2725
result = add_buffer(req_buffer, data->set.postfields,
2727
included_body = postsize;
2730
/* Append the POST data chunky-style */
2731
result = add_bufferf(req_buffer, "%x\r\n", (int)postsize);
2732
if(CURLE_OK == result)
2733
result = add_buffer(req_buffer, data->set.postfields,
2735
if(CURLE_OK == result)
2736
result = add_buffer(req_buffer,
2737
"\x0d\x0a\x30\x0d\x0a\x0d\x0a", 7);
2738
/* CR LF 0 CR LF CR LF */
2739
included_body = postsize + 7;
2745
/* A huge POST coming up, do data separate from the request */
2746
http->postsize = postsize;
2747
http->postdata = data->set.postfields;
2749
http->sending = HTTPSEND_BODY;
2751
conn->fread_func = (curl_read_callback)readmoredata;
2752
conn->fread_in = (void *)conn;
2754
/* set the upload size to the progress meter */
2755
Curl_pgrsSetUploadSize(data, http->postsize);
2757
result = add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
2819
/* We're not sending it 'chunked', append it to the request
2820
already now to reduce the number if send() calls */
2821
result = add_buffer(req_buffer, data->set.postfields,
2823
included_body = postsize;
2763
result = add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
2767
if(data->set.postfieldsize) {
2768
/* set the upload size to the progress meter */
2769
Curl_pgrsSetUploadSize(data, postsize?postsize:-1);
2771
/* set the pointer to mark that we will send the post body using the
2772
read callback, but only if we're not in authenticate
2774
if(!conn->bits.authneg) {
2775
http->postdata = (char *)&http->postdata;
2776
http->postsize = postsize;
2780
/* issue the request */
2781
result = add_buffer_send(req_buffer, conn, &data->info.request_size,
2782
(size_t)included_body, FIRSTSOCKET);
2785
failf(data, "Failed sending HTTP POST request");
2788
Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
2789
&http->readbytecount,
2790
http->postdata?FIRSTSOCKET:-1,
2791
http->postdata?&http->writebytecount:NULL);
2826
/* Append the POST data chunky-style */
2827
result = add_bufferf(req_buffer, "%x\r\n", (int)postsize);
2828
if(CURLE_OK == result)
2829
result = add_buffer(req_buffer, data->set.postfields,
2831
if(CURLE_OK == result)
2832
result = add_buffer(req_buffer,
2833
"\x0d\x0a\x30\x0d\x0a\x0d\x0a", 7);
2834
/* CR LF 0 CR LF CR LF */
2835
included_body = postsize + 7;
2841
/* A huge POST coming up, do data separate from the request */
2842
http->postsize = postsize;
2843
http->postdata = data->set.postfields;
2845
http->sending = HTTPSEND_BODY;
2847
conn->fread_func = (curl_read_callback)readmoredata;
2848
conn->fread_in = (void *)conn;
2850
/* set the upload size to the progress meter */
2851
Curl_pgrsSetUploadSize(data, http->postsize);
2853
result = add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
2859
result = add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
2863
if(data->set.postfieldsize) {
2864
/* set the upload size to the progress meter */
2865
Curl_pgrsSetUploadSize(data, postsize?postsize:-1);
2867
/* set the pointer to mark that we will send the post body using the
2868
read callback, but only if we're not in authenticate
2870
if(!conn->bits.authneg) {
2871
http->postdata = (char *)&http->postdata;
2872
http->postsize = postsize;
2876
/* issue the request */
2877
result = add_buffer_send(req_buffer, conn, &data->info.request_size,
2878
(size_t)included_body, FIRSTSOCKET);
2881
failf(data, "Failed sending HTTP POST request");
2884
Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
2885
&http->readbytecount,
2886
http->postdata?FIRSTSOCKET:-1,
2887
http->postdata?&http->writebytecount:NULL);
2795
2891
result = add_buffer(req_buffer, "\r\n", 2);