I am trying to access a company internal webpage that requires authentication using libcurl. When the code is run, it says "401 UNAUTHORIZED". I am providing the login credentials via curl_easy_setopt(curl, CURLOPT_USERPWD, "usr:pwd"), but still get the above message.
I read on this and found that 401 means it requires a SERVER authentication. However, I do not receive any available authentication schemes. My winhttp config settings are on 'Auto-detect'.
int wmain()
{
std::string content;
curl_global_init(CURL_GLOBAL_ALL);
CURL *curl = curl_easy_init();
if (curl)
{
curl_easy_setopt(curl, CURLOPT_URL, "company internal URL");
curl_easy_setopt(curl, CURLOPT_USERPWD, "usr:pwd");
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &content);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writer);
CURLcode code = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
curl_global_cleanup();
std::cout << content;
std::cin.get();
return 0;
}
I am very new to using libcurl and have limited working experience with C/C++. Your help is appreciated to identify the problem. Thanks!
Try to add curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
Also of course "usr:pwd"should be replaced, but I assume you did that.
Example below
https://curl.haxx.se/libcurl/c/CURLOPT_HTTPAUTH.html
CURL *curl = curl_easy_init();
if(curl) {
CURLcode ret;
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
/* allow whatever auth the server speaks */
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_easy_setopt(curl, CURLOPT_USERPWD, "james:bond");
ret = curl_easy_perform(curl);
}
Related
I'm writing my server code in C on my Mac, and I need it to access Facebook's Graph API at the URL "https://graph.facebook.com/app?access_token=[insert access token here]". I'm getting a CURLE_COULDNT_RESOLVE_HOST error, maybe because I've never done this before and am probably doing something totally wrong. I'm setting up a CURL* and connecting like this:
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.8) Gecko/2009032609 Firefox/3.0.8");
char* httpURLFormat = "https://graph.facebook.com/app?access_token=%s";
char* httpURL = emalloc(sizeof(char)*(strlen(httpURLFormat)+MAX_TOKEN_LENGTH)); //emalloc is just malloc that makes sure there is free memory
sprintf(httpURL, httpURLFormat, data->password); //data->password is the access token
curl_easy_setopt(curl, CURLOPT_URL, &httpURL);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
struct url_data response; //this struct contains int size and char* data
response.size = 0;
response.data = emalloc(4096);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
CURLcode curlCode = curl_easy_perform(curl);
if (curlCode!=CURLE_OK){
printf("curl failed!!!\n"); //this ends up printing
free(response.data);
free(httpURL);
free(httpURLFormat);
return false;
}
//Yes, I free everything left over afterwards...
I tested the URL it's connecting to in my web browser using the same user agent my code uses, and it connects without trouble. I tried adding a '\n' character to the end of the URL, and my code still won't work.
I found the problem: The httpURLFormat should be "https://graph.facebook.com:443/app?access_token=%s". You need to specify the port in the URL. CURL apparently doesn't use the default 443 otherwise.
I have developed a ‘C’ application on a Linux box using the libcurl example http://curl.askapache.com/c/ftpupload.html I work fine. I have been asked to use SSL for both “data encryption for both the control channel and data channel.” I am not been able to find an example of adding SSL to the example I followed. Here is the core of the FTP program:
// get a FILE * of the same file
hd_src = fopen(local_file, "rb");
// curl init
curl_global_init(CURL_GLOBAL_ALL);
// get a curl handle
curl = curl_easy_init();
if (curl) { // build a list of commands to pass to libcurl
headerlist = curl_slist_append(headerlist, buf_1);
#ifdef DEBUG
// we want to use our own read function
curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
#endif
// enable uploading
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
// specify target
curl_easy_setopt(curl, CURLOPT_URL, ftp_url);
curl_easy_setopt(curl, CURLOPT_USERPWD, user_password);
curl_easy_setopt(curl, CURLOPT_PORT, 21);
// pass in that last of FTP commands to run after the transfer
curl_easy_setopt(curl, CURLOPT_POSTQUOTE, headerlist);
// now specify which file to upload
curl_easy_setopt(curl, CURLOPT_READDATA, hd_src);
// Set the size of the file to upload
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t) fsize);
// Now run off and do what you've been told!
res = curl_easy_perform(curl);
// Check for errors
if (res != CURLE_OK) {
char *s;
s = malloc((sizeof(char) * 100) + 1);
sprintf(s, "curl_easy_perform() failed: %s - Error Number: %d\n",
curl_easy_strerror(res), res);
returnResults->error = true;
returnResults->errorMessage = s;
return returnResults;
}
// clean up the FTP commands list
curl_slist_free_all(headerlist);
// always cleanup
curl_easy_cleanup(curl);
}
fclose(hd_src); // close the local file
curl_global_cleanup();
There's however an existing example code on the libcurl site showing how you do FTP-SSL to download a file: ftpsget.c - it shows the very little SSL magic you need to add. That magic is the same for uploads:
/* We activate SSL and we require it for both control and data */
curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
In fact, you can add this single line into the FTP upload example. and it'll do FTPS uploads for you.
When I post to a certain URL via libcURL most of the time the status code will be a 401, but sometimes it will return the 200 I expect even though the credentials I pass are the same. The weird thing is that if I use the same code ported to python and using urllib2 I will get a 200 ok and I will get the data I need. Here is the relevant code that I am using to post to the website. libcURL also works fine for me to get the needed credentials for this function such as the xut_sid key and cookie, it is just this url that sometimes 401s and sometimes 200s.
CURL *curl_handle;
CURLcode res;
struct curl_slist *header = NULL;
MemoryStruct chunk;
...
header = curl_slist_append(header, l->cookie);// l just contains the data I need
header = curl_slist_append(header, l->xut_sid);
header = curl_slist_append(header, "Content-Type: application/json;charset=utf-8");
header = curl_slist_append(header, "x-http-method-override: GET");
curl_handle = curl_easy_init();
curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl_handle, CURLOPT_URL, searchString);
curl_easy_setopt(curl_handle, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, header);
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &chunk);
res = curl_easy_perform(curl_handle);
EDIT: I fixed it, twas a dumb mistake by me where the xut_sid would get overwritten(I'm new to C lol and didn't use strdup to copy the string) and not be sent. I don't know why it showed up in the verbose log as there, but it wasn't being sent.
I have the following code:
CURL *curl;
void http_init()
{
curl = curl_easy_init();
if (!curl) return -1;
}
void http_send_message(char *msg_out, char **msg_in)
{
CURLcode res;
curl_easy_setopt(curl, CURLOPT_URL, "http://192.168.1.133:8080/tawtaw");
curl_easy_setopt(curl, CURLOPT_USERNAME, "tawtaw");
curl_easy_setopt(curl, CURLOPT_PASSWORD, "tawtaw");
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC|CURLAUTH_DIGEST);
.
.
.
curl_easy_reset(curl);
}
void http_exit()
{
curl_easy_cleanup(curl);
}
int main()
{
char *msgin=NULL;
http_init();
http_send_message("message number 1", &msg_in);
free(msgin);msgin=NULL;
http_send_message("message number 2", &msg_in);
free(msgin);msgin=NULL;
http_exit();
}
If I call
curl_easy_setopt(curl, CURLOPT_URL, "http://192.168.1.133:8080/tawtaw");
and then
curl_easy_reset(curl)
and then
curl_easy_setopt(curl, CURLOPT_URL, "http://192.168.1.133:8080/tawtaw");
again, does the allocated memory in the first curl_easy_setopt get freed by curl_easy_reset(curl) or by the second call of curl_easy_setopt?
Or the memory is not freed and there is a memory leak?
Does the allocated memory in the first curl_easy_setopt() get freed by curl_easy_reset(curl) or by the second call to curl_easy_setopt()?
The thing is that:
It's an implementation detail.
Arising from the preceding fact, it does not/should not matter. Either one is true, proper memory management is possible in both cases.
I'm trying to connect to a google api.
This works fine in my terminal, there I'm doing:
curl https://www.googleapis.com/tasks/v1/users/#me/lists --header "Authorization: Bearer myAccessCode".
This works fine, but now I want to make this inside a c program.
For this I have:
CURL *curl;
char *header = "Authorization: Bearer myAccessCode";
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, header);
curl = curl_easy_init();
char *response = NULL;
curl_easy_setopt(curl, CURLOPT_URL, "https://www.googleapis.com/tasks/v1/users/#me/lists");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, httpsCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
curl_easy_perform(curl);
curl_easy_cleanup(curl);
But here I'm just getting a message that a login is required.
I have no idea what I'm doing wrong, is there someone who sees my failure?
Like I wrote in the comment above:
I just realized that I made: curl_slist_append(headers, header);
instead of: headers = curl_slist_append(headers, header);
So headers was always NULL and I made the get request without a header.
(I edited it in my question above, so the code works, if some)