curl / Mailing Lists / curl-library / Single Mail

curl-library

HTTP POST/PUT with Negotiate Authentication (CURLAUTH_NEGOTIATE) and data specified with CURLOPT_UPLOAD/CURLOPT_INFILESIZE_LARGE/CURLOPT_READFUNCTION/CURLOPT_SEEKFUNCTION fails

From: Hölzl, Dominik <Dominik.Hoelzl_at_fabasoft.com>
Date: Tue, 7 Feb 2017 11:20:50 +0000

Hello!

I have found another issue when doing a challenge-based request:

On Windows I want to perform a POST (or another custom) request (CURLOPT_CUSTOMREQUEST) with some data specified with CURLOPT_UPLOAD/CURLOPT_INFILESIZE_LARGE/CURLOPT_READFUNCTION/CURLOPT_SEEKFUNCTION by using negotiate authentication (CURLOPT_HTTPAUTH CURLAUTH_NEGOTIATE, CURLOPT_USERNAME (empty for Windows credentials), CURLOPT_PASSWORD (empty for Windows credentials)), but the authentication fails.

Explicitly suppressing the "Expect: 100-continue" header seems to get the request working, but this is not an acceptable solution.

Using CURLOPT_POSTFIELDS instead of CURLOPT_UPLOAD, CURLOPT_READFUNCTION, CURLOPT_SEEKFUNCTION also works. But this is not the intended way to upload large amounts of data.

Using CURLOPT_POSTFIELDS with explicitly defining the "Expect: 100-continue" header fails.

Using CURLAUTH_NTLM instead of CURLAUTH_NEGOTIATE with the same cURL configuration works (also with the "Expect: 100-continue" mechanism). But this is less secure.

Used cURL Library: Version 7.52.1 64 Bit on Windows built with

-DBUILDING_LIBCURL -DHTTP_ONLY _DWITHOUT_MM_LIB -DUSE_SSLEAY -DUSE_OPENSSL -DCURL_WANTS_CA_BUNDLE_ENV -DENABLE_IPV6 -DUSE_WINDOWS_SSPI -DHAVE_STRUCT_POLLFD

Connecting to an IIS with all authentication methods disabled but "Windows Authentication"

Negotiate-Data in the output is masked with X, Y, Z for security reasons.

Am I doing something wrong?

Best Regards,

Dominik

=======================================================================

CODE I expect to be working, but fails

=======================================================================

size_t CURLheaderfunction(void *ptr, size_t size, size_t nmemb, void *stream)

{

  printf("RECEIVED HEADER: %s", (const char *)ptr);

  return size*nmemb;

}

static size_t CURLreadpos = 0;

size_t CURLreadfunction(void *ptr, size_t size, size_t nmemb, void *stream)

{

  size_t read = 0;

  for (; CURLreadpos < 10 && CURLreadpos < size * nmemb; CURLreadpos++) {

    ((char *)ptr)[CURLreadpos] = 'a';

    read++;

  }

  printf("READ REQUEST DATA: %llu -> %llu\n", size*nmemb, (UINT64)read);

  return read;

}

size_t CURLwritefunction(void *ptr, size_t size, size_t nmemb, void *stream)

{

  printf("WRITE RESPONSE DATA: %llu\n ", size*nmemb);

  return size*nmemb;

}

int CURLseekfunction(void *ptr, curl_off_t offset, int origin)

{

  printf("SEEK: %lld, %d\n ", (INT64)offset, origin);

  if (origin == SEEK_SET) {

    CURLreadpos = offset;

    return CURL_SEEKFUNC_OK;

  }

  printf("SEEK: NOT IMPL\n ");

  return CURL_SEEKFUNC_CANTSEEK;

}

int main(void)

{

  CURL *curl;

  CURLcode res;

  /* In windows, this will init the winsock stuff */

  curl_global_init(CURL_GLOBAL_ALL);

  /* get a curl handle */

  curl = curl_easy_init();

  if (curl) {

    curl_easy_setopt(curl, CURLOPT_URL, "http://url-to-windows-authentication-enabled-server-goes-here");

    /* Specify callbacks */

    curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, CURLheaderfunction);

    curl_easy_setopt(curl, CURLOPT_READFUNCTION, CURLreadfunction);

    curl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, CURLseekfunction);

    /* Specify Negotiate authentication method */

    curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_NEGOTIATE);

    curl_easy_setopt(curl, CURLOPT_USERNAME, "");

    curl_easy_setopt(curl, CURLOPT_PASSWORD, "");

    /* Specify upload */

    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");

    curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);

    curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, 10);

    /* Perform the request, res will get the return code */

    res = curl_easy_perform(curl);

    /* Check for errors */

    if (res != CURLE_OK) {

      printf("curl_easy_perform() failed: %s\n",

        curl_easy_strerror(res));

    }

    else {

      long http_code = 0;

      curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);

      printf("CURL STATUS: %ld", http_code);

    }

    /* always cleanup */

    curl_easy_cleanup(curl);

  }

  curl_global_cleanup();

  return 0;

}

=======================================================================

OUTPUT of code I expect to be working, but fails

=======================================================================

RECEIVED HEADER: HTTP/1.1 401 Unauthorized

RECEIVED HEADER: Server: Microsoft-IIS/8.5

RECEIVED HEADER: WWW-Authenticate: Negotiate

RECEIVED HEADER: WWW-Authenticate: NTLM

RECEIVED HEADER: X-Powered-By: ASP.NET

RECEIVED HEADER: Date: Tue, 07 Feb 2017 08:18:17 GMT

RECEIVED HEADER: Content-Length: 0

RECEIVED HEADER:

RECEIVED HEADER: HTTP/1.1 401 Unauthorized

RECEIVED HEADER: Server: Microsoft-IIS/8.5

RECEIVED HEADER: WWW-Authenticate: Negotiate XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

RECEIVED HEADER: WWW-Authenticate: NTLM

RECEIVED HEADER: X-Powered-By: ASP.NET

RECEIVED HEADER: Date: Tue, 07 Feb 2017 08:18:17 GMT

RECEIVED HEADER: Content-Length: 0

RECEIVED HEADER:

RECEIVED HEADER: HTTP/1.1 401 Unauthorized

RECEIVED HEADER: Server: Microsoft-IIS/8.5

RECEIVED HEADER: WWW-Authenticate: Negotiate

RECEIVED HEADER: WWW-Authenticate: NTLM

RECEIVED HEADER: X-Powered-By: ASP.NET

RECEIVED HEADER: Date: Tue, 07 Feb 2017 08:18:17 GMT

RECEIVED HEADER: Content-Length: 0

RECEIVED HEADER:

CURL STATUS: 401

=======================================================================

CODE with workaround: Suppress Expect: 100-continue

=======================================================================

size_t CURLheaderfunction(void *ptr, size_t size, size_t nmemb, void *stream)

{

  printf("RECEIVED HEADER: %s", (const char *)ptr);

  return size*nmemb;

}

static size_t CURLreadpos = 0;

size_t CURLreadfunction(void *ptr, size_t size, size_t nmemb, void *stream)

{

  size_t read = 0;

  for (; CURLreadpos < 10 && CURLreadpos < size * nmemb; CURLreadpos++) {

    ((char *)ptr)[CURLreadpos] = 'a';

    read++;

  }

  printf("READ REQUEST DATA: %llu -> %llu\n", size*nmemb, (UINT64)read);

  return read;

}

size_t CURLwritefunction(void *ptr, size_t size, size_t nmemb, void *stream)

{

  printf("WRITE RESPONSE DATA: %llu\n", size*nmemb);

  return size*nmemb;

}

int CURLseekfunction(void *ptr, curl_off_t offset, int origin)

{

  printf("SEEK: %lld, %d\n", (INT64)offset, origin);

  if (origin == SEEK_SET) {

    CURLreadpos = offset;

    return CURL_SEEKFUNC_OK;

  }

  printf("SEEK: NOT IMPL\n");

  return CURL_SEEKFUNC_CANTSEEK;

}

int main(void)

{

  CURL *curl;

  CURLcode res;

  /* In windows, this will init the winsock stuff */

  curl_global_init(CURL_GLOBAL_ALL);

  /* get a curl handle */

  curl = curl_easy_init();

 if (curl) {

    curl_easy_setopt(curl, CURLOPT_URL, " http://url-to-windows-authentication-enabled-server-goes-here");

    /* Specify callbacks */

    curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, CURLheaderfunction);

    curl_easy_setopt(curl, CURLOPT_READFUNCTION, CURLreadfunction);

    curl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, CURLseekfunction);

    /* Specify Negotiate authentication method */

    curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_NEGOTIATE);

    curl_easy_setopt(curl, CURLOPT_USERNAME, "");

    curl_easy_setopt(curl, CURLOPT_PASSWORD, "");

    /* Specify upload */

    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");

    curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);

    curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, 10);

    /* Suppress Expect: 100-continue */

    struct curl_slist *headers = NULL;

    headers = curl_slist_append(headers, "Expect:");

    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

    /* Perform the request, res will get the return code */

    res = curl_easy_perform(curl);

    /* Check for errors */

    if (res != CURLE_OK) {

      printf("curl_easy_perform() failed: %s\n",

        curl_easy_strerror(res));

    }

    else {

      long http_code = 0;

      curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);

      printf("CURL STATUS: %ld", http_code);

    }

    /* always cleanup */

    curl_easy_cleanup(curl);

  }

  curl_global_cleanup();

  return 0;

}

=======================================================================

OUTPUT with workaround: suppress Expect: 100-continue (The final 204 status is OK here as it was a sample request without valid data)

=======================================================================

READ REQUEST DATA: 16384 -> 10

RECEIVED HEADER: HTTP/1.1 401 Unauthorized

RECEIVED HEADER: Server: Microsoft-IIS/8.5

RECEIVED HEADER: WWW-Authenticate: Negotiate

RECEIVED HEADER: WWW-Authenticate: NTLM

RECEIVED HEADER: X-Powered-By: ASP.NET

RECEIVED HEADER: Date: Tue, 07 Feb 2017 08:23:46 GMT

RECEIVED HEADER: Content-Length: 0

RECEIVED HEADER:

SEEK: 0, 0

READ REQUEST DATA: 16384 -> 10

RECEIVED HEADER: HTTP/1.1 401 Unauthorized

RECEIVED HEADER: Server: Microsoft-IIS/8.5

RECEIVED HEADER: WWW-Authenticate: Negotiate XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

RECEIVED HEADER: WWW-Authenticate: NTLM

RECEIVED HEADER: X-Powered-By: ASP.NET

RECEIVED HEADER: Date: Tue, 07 Feb 2017 08:23:46 GMT

RECEIVED HEADER: Content-Length: 0

RECEIVED HEADER:

SEEK: 0, 0

READ REQUEST DATA: 16384 -> 10

RECEIVED HEADER: HTTP/1.1 401 Unauthorized

RECEIVED HEADER: Server: Microsoft-IIS/8.5

RECEIVED HEADER: WWW-Authenticate: Negotiate ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ

RECEIVED HEADER: WWW-Authenticate: NTLM

RECEIVED HEADER: X-Powered-By: ASP.NET

RECEIVED HEADER: Date: Tue, 07 Feb 2017 08:23:46 GMT

RECEIVED HEADER: Content-Length: 0

RECEIVED HEADER:

SEEK: 0, 0

READ REQUEST DATA: 16384 -> 10

RECEIVED HEADER: HTTP/1.1 204 No Content

RECEIVED HEADER: Allow: OPTIONS,GET,HEAD,DELETE,PUT,POST,PROPFIND,PROPPATCH,LOCK,UNLOCK

RECEIVED HEADER: Content-Length: 0

RECEIVED HEADER: Server: Microsoft-IIS/8.5

RECEIVED HEADER: Content-Disposition: attachment

RECEIVED HEADER: WWW-Authenticate: Negotiate YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY

RECEIVED HEADER: Persistent-Auth: true

RECEIVED HEADER: X-Powered-By: ASP.NET

RECEIVED HEADER: Date: Tue, 07 Feb 2017 08:23:46 GMT

RECEIVED HEADER:

CURL STATUS: 204

=======================================================================

CODE with CURLOPT_POSTFIELDS (working)

=======================================================================

size_t CURLheaderfunction(void *ptr, size_t size, size_t nmemb, void *stream)

{

  printf("RECEIVED HEADER: %s", (const char *)ptr);

  return size*nmemb;

}

static size_t CURLreadpos = 0;

size_t CURLreadfunction(void *ptr, size_t size, size_t nmemb, void *stream)

{

  size_t read = 0;

  for (; CURLreadpos < 10 && CURLreadpos < size * nmemb; CURLreadpos++) {

    ((char *)ptr)[CURLreadpos] = 'a';

    read++;

  }

  printf("READ REQUEST DATA: %llu -> %llu\n", size*nmemb, (UINT64)read);

  return read;

}

size_t CURLwritefunction(void *ptr, size_t size, size_t nmemb, void *stream)

{

  printf("WRITE RESPONSE DATA: %llu\n", size*nmemb);

  return size*nmemb;

}

int CURLseekfunction(void *ptr, curl_off_t offset, int origin)

{

  printf("SEEK: %lld, %d\n", (INT64)offset, origin);

  if (origin == SEEK_SET) {

    CURLreadpos = offset;

    return CURL_SEEKFUNC_OK;

  }

  printf("SEEK: NOT IMPL\n");

  return CURL_SEEKFUNC_CANTSEEK;

}

int main(void)

{

  CURL *curl;

  CURLcode res;

  /* In windows, this will init the winsock stuff */

  curl_global_init(CURL_GLOBAL_ALL);

  /* get a curl handle */

  curl = curl_easy_init();

  if (curl) {

    curl_easy_setopt(curl, CURLOPT_URL, " http://url-to-windows-authentication-enabled-server-goes-here");

    /* Specify callbacks */

    curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, CURLheaderfunction);

    curl_easy_setopt(curl, CURLOPT_READFUNCTION, CURLreadfunction);

    curl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, CURLseekfunction);

    /* Specify Negotiate authentication method */

    curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_NEGOTIATE);

    curl_easy_setopt(curl, CURLOPT_USERNAME, "");

    curl_easy_setopt(curl, CURLOPT_PASSWORD, "");

    /* Specify upload */

    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "0123456789");

    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");

    /* Perform the request, res will get the return code */

    res = curl_easy_perform(curl);

    /* Check for errors */

    if (res != CURLE_OK) {

      printf("curl_easy_perform() failed: %s\n",

        curl_easy_strerror(res));

    }

    else {

      long http_code = 0;

      curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);

      printf("CURL STATUS: %ld", http_code);

    }

    /* always cleanup */

    curl_easy_cleanup(curl);

  }

  curl_global_cleanup();

  return 0;

}

=======================================================================

OUTPUT of code with CURLOPT_POSTFIELDS (The final 204 status is OK here as it was a sample request without valid data)

=======================================================================

RECEIVED HEADER: HTTP/1.1 401 Unauthorized

RECEIVED HEADER: Server: Microsoft-IIS/8.5

RECEIVED HEADER: WWW-Authenticate: Negotiate

RECEIVED HEADER: WWW-Authenticate: NTLM

RECEIVED HEADER: X-Powered-By: ASP.NET

RECEIVED HEADER: Date: Tue, 07 Feb 2017 08:37:51 GMT

RECEIVED HEADER: Content-Length: 0

RECEIVED HEADER:

RECEIVED HEADER: HTTP/1.1 401 Unauthorized

RECEIVED HEADER: Server: Microsoft-IIS/8.5

RECEIVED HEADER: WWW-Authenticate: Negotiate XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

RECEIVED HEADER: WWW-Authenticate: NTLM

RECEIVED HEADER: X-Powered-By: ASP.NET

RECEIVED HEADER: Date: Tue, 07 Feb 2017 08:37:51 GMT

RECEIVED HEADER: Content-Length: 0

RECEIVED HEADER:

RECEIVED HEADER: HTTP/1.1 401 Unauthorized

RECEIVED HEADER: Server: Microsoft-IIS/8.5

RECEIVED HEADER: WWW-Authenticate: Negotiate ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ

RECEIVED HEADER: WWW-Authenticate: NTLM

RECEIVED HEADER: X-Powered-By: ASP.NET

RECEIVED HEADER: Date: Tue, 07 Feb 2017 08:37:51 GMT

RECEIVED HEADER: Content-Length: 0

RECEIVED HEADER:

RECEIVED HEADER: HTTP/1.1 204 No Content

RECEIVED HEADER: Allow: OPTIONS,GET,HEAD,DELETE,PUT,POST,PROPFIND,PROPPATCH,LOCK,UNLOCK

RECEIVED HEADER: Content-Length: 0

RECEIVED HEADER: Server: Microsoft-IIS/8.5

RECEIVED HEADER: Content-Disposition: attachment

RECEIVED HEADER: WWW-Authenticate: Negotiate YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY

RECEIVED HEADER: Persistent-Auth: true

RECEIVED HEADER: X-Powered-By: ASP.NET

RECEIVED HEADER: Date: Tue, 07 Feb 2017 08:37:51 GMT

RECEIVED HEADER:

CURL STATUS: 204

=======================================================================

CODE with CURLOPT_POSTFIELDS and "Expect: 100-continue" header (not working)

=======================================================================

size_t CURLheaderfunction(void *ptr, size_t size, size_t nmemb, void *stream)

{

  printf("RECEIVED HEADER: %s", (const char *)ptr);

  return size*nmemb;

}

static size_t CURLreadpos = 0;

size_t CURLreadfunction(void *ptr, size_t size, size_t nmemb, void *stream)

{

  size_t read = 0;

  for (; CURLreadpos < 10 && CURLreadpos < size * nmemb; CURLreadpos++) {

    ((char *)ptr)[CURLreadpos] = 'a';

    read++;

  }

  printf("READ REQUEST DATA: %llu -> %llu\n", size*nmemb, (UINT64)read);

  return read;

}

size_t CURLwritefunction(void *ptr, size_t size, size_t nmemb, void *stream)

{

  printf("WRITE RESPONSE DATA: %llu\n", size*nmemb);

  return size*nmemb;

}

int CURLseekfunction(void *ptr, curl_off_t offset, int origin)

{

  printf("SEEK: %lld, %d\n", (INT64)offset, origin);

  if (origin == SEEK_SET) {

    CURLreadpos = offset;

    return CURL_SEEKFUNC_OK;

  }

  printf("SEEK: NOT IMPL\n");

  return CURL_SEEKFUNC_CANTSEEK;

}

int main(void)

{

  CURL *curl;

  CURLcode res;

  /* In windows, this will init the winsock stuff */

  curl_global_init(CURL_GLOBAL_ALL);

  /* get a curl handle */

  curl = curl_easy_init();

  if (curl) {

    curl_easy_setopt(curl, CURLOPT_URL, " http://url-to-windows-authentication-enabled-server-goes-here ");

    /* Specify callbacks */

    curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, CURLheaderfunction);

    curl_easy_setopt(curl, CURLOPT_READFUNCTION, CURLreadfunction);

    curl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, CURLseekfunction);

    /* Specify Negotiate authentication method */

    curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_NEGOTIATE);

    curl_easy_setopt(curl, CURLOPT_USERNAME, "");

    curl_easy_setopt(curl, CURLOPT_PASSWORD, "");

    /* Specify upload */

    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "0123456789");

    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");

    /* Explicitly define Expect: 100-continue */

    struct curl_slist *headers = NULL;

    headers = curl_slist_append(headers, "Expect: 100-continue");

    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

    /* Perform the request, res will get the return code */

    res = curl_easy_perform(curl);

    /* Check for errors */

    if (res != CURLE_OK) {

      printf("curl_easy_perform() failed: %s\n",

        curl_easy_strerror(res));

    }

    else {

      long http_code = 0;

      curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);

      printf("CURL STATUS: %ld", http_code);

    }

    /* always cleanup */

    curl_easy_cleanup(curl);

  }

  curl_global_cleanup();

  return 0;

}

=======================================================================

OUTPUT of code with CURLOPT_POSTFIELDS and "Expect: 100-continue" header (not working)

=======================================================================

RECEIVED HEADER: HTTP/1.1 401 Unauthorized

RECEIVED HEADER: Server: Microsoft-IIS/8.5

RECEIVED HEADER: WWW-Authenticate: Negotiate

RECEIVED HEADER: WWW-Authenticate: NTLM

RECEIVED HEADER: X-Powered-By: ASP.NET

RECEIVED HEADER: Date: Tue, 07 Feb 2017 09:05:13 GMT

RECEIVED HEADER: Content-Length: 0

RECEIVED HEADER:

RECEIVED HEADER: HTTP/1.1 401 Unauthorized

RECEIVED HEADER: Server: Microsoft-IIS/8.5

RECEIVED HEADER: WWW-Authenticate: Negotiate XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

RECEIVED HEADER: WWW-Authenticate: NTLM

RECEIVED HEADER: X-Powered-By: ASP.NET

RECEIVED HEADER: Date: Tue, 07 Feb 2017 09:05:13 GMT

RECEIVED HEADER: Content-Length: 0

RECEIVED HEADER:

RECEIVED HEADER: HTTP/1.1 401 Unauthorized

RECEIVED HEADER: Server: Microsoft-IIS/8.5

RECEIVED HEADER: WWW-Authenticate: Negotiate

RECEIVED HEADER: WWW-Authenticate: NTLM

RECEIVED HEADER: X-Powered-By: ASP.NET

RECEIVED HEADER: Date: Tue, 07 Feb 2017 09:05:13 GMT

RECEIVED HEADER: Content-Length: 0

RECEIVED HEADER:

CURL STATUS: 401

=======================================================================

CODE with NTLM-Authentication (working)

=======================================================================

size_t CURLheaderfunction(void *ptr, size_t size, size_t nmemb, void *stream)

{

  printf("RECEIVED HEADER: %s", (const char *)ptr);

  return size*nmemb;

}

static size_t CURLreadpos = 0;

size_t CURLreadfunction(void *ptr, size_t size, size_t nmemb, void *stream)

{

  size_t read = 0;

  for (; CURLreadpos < 10 && CURLreadpos < size * nmemb; CURLreadpos++) {

    ((char *)ptr)[CURLreadpos] = 'a';

    read++;

  }

  printf("READ REQUEST DATA: %llu -> %llu\n", size*nmemb, (UINT64)read);

  return read;

}

size_t CURLwritefunction(void *ptr, size_t size, size_t nmemb, void *stream)

{

  printf("WRITE RESPONSE DATA: %llu\n", size*nmemb);

  return size*nmemb;

}

int CURLseekfunction(void *ptr, curl_off_t offset, int origin)

{

  printf("SEEK: %lld, %d\n", (INT64)offset, origin);

  if (origin == SEEK_SET) {

    CURLreadpos = offset;

    return CURL_SEEKFUNC_OK;

  }

  printf("SEEK: NOT IMPL\n");

  return CURL_SEEKFUNC_CANTSEEK;

}

int main(void)

{

  CURL *curl;

  CURLcode res;

  /* In windows, this will init the winsock stuff */

  curl_global_init(CURL_GLOBAL_ALL);

  /* get a curl handle */

  curl = curl_easy_init();

  if (curl) {

    curl_easy_setopt(curl, CURLOPT_URL, " http://url-to-windows-authentication-enabled-server-goes-here");

    /* Specify callbacks */

    curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, CURLheaderfunction);

    curl_easy_setopt(curl, CURLOPT_READFUNCTION, CURLreadfunction);

    curl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, CURLseekfunction);

    /* Specify NTLM authentication method */

    curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_NTLM);

    curl_easy_setopt(curl, CURLOPT_USERNAME, "<NTLM-Username>");

    curl_easy_setopt(curl, CURLOPT_PASSWORD, "<NTLM-Password>");

    /* Specify upload */

    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");

    curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);

    curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, 10);

    /* Suppress Expect: 100-continue */

    /*struct curl_slist *headers = NULL;

    headers = curl_slist_append(headers, "Expect:");

    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);*/

    /* Perform the request, res will get the return code */

    res = curl_easy_perform(curl);

    /* Check for errors */

    if (res != CURLE_OK) {

      printf("curl_easy_perform() failed: %s\n",

        curl_easy_strerror(res));

    }

    else {

      long http_code = 0;

      curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);

      printf("CURL STATUS: %ld", http_code);

    }

    /* always cleanup */

    curl_easy_cleanup(curl);

  }

  curl_global_cleanup();

  return 0;

}

=======================================================================

OUTPUT of code with NTLM-Authentication (The final 204 status is OK here as it was a sample request without valid data)

=======================================================================

RECEIVED HEADER: HTTP/1.1 401 Unauthorized

RECEIVED HEADER: Server: Microsoft-IIS/8.5

RECEIVED HEADER: WWW-Authenticate: NTLM XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

RECEIVED HEADER: WWW-Authenticate: Negotiate

RECEIVED HEADER: X-Powered-By: ASP.NET

RECEIVED HEADER: Date: Tue, 07 Feb 2017 08:51:03 GMT

RECEIVED HEADER: Content-Length: 0

RECEIVED HEADER:

RECEIVED HEADER: HTTP/1.1 100 Continue

RECEIVED HEADER:

READ REQUEST DATA: 16384 -> 10

RECEIVED HEADER: HTTP/1.1 204 No Content

RECEIVED HEADER: Allow: OPTIONS,GET,HEAD,DELETE,PUT,POST,PROPFIND,PROPPATCH,LOCK,UNLOCK

RECEIVED HEADER: Content-Length: 0

RECEIVED HEADER: Server: Microsoft-IIS/8.5

RECEIVED HEADER: Content-Disposition: attachment

RECEIVED HEADER: Persistent-Auth: true

RECEIVED HEADER: X-Powered-By: ASP.NET

RECEIVED HEADER: Date: Tue, 07 Feb 2017 08:51:03 GMT

RECEIVED HEADER:

CURL STATUS: 204

-------------------------------------------------------------------
Unsubscribe: https://cool.haxx.se/list/listinfo/curl-library
Etiquette: https://curl.haxx.se/mail/etiquette.html
Received on 2017-02-07