curl-library
HTTP POST/PUT with Negotiate Authentication (CURLAUTH_NEGOTIATE) and data specified with CURLOPT_UPLOAD/CURLOPT_INFILESIZE_LARGE/CURLOPT_READFUNCTION/CURLOPT_SEEKFUNCTION fails
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