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.
Related
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);
}
I am trying to connect to server which demands client authentication. I am doing it in C with libcurl. The problem is when I try to connect I get:
curl_easy_perform() failed: SSL connect error
I read that I should add server certificate to ca-bundle.crt; however server's certificate is self signed so when I add it to ca-bundle I got SSL peer certificate or SSH remote key was not OK. After that I tried do set CURLOPT_SSL_VERIFYPEER to false; but I got the first error curl_easy_perform() failed: SSL connect error
This is my current code:
#define SKIP_HOSTNAME_VERIFICATION
#define SKIP_PEER_VERIFICATION
int authenticate(CURL *curl) {
char* pathToCert = "sslCert.pem";
char* pathToKey = "privateKey.pem";
curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM");
int res = curl_easy_setopt(curl, CURLOPT_SSLCERT, pathToCert);
if (res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
curl_easy_setopt(curl, CURLOPT_SSLKEY, pathToKey);
}
int main(int argc, char **argv) {
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, "https://localhost:8443/RemSig/status");
authenticate(curl);
#ifdef SKIP_PEER_VERIFICATION
/*
* If you want to connect to a site who isn't using a certificate that is
* signed by one of the certs in the CA bundle you have, you can skip the
* verification of the server's certificate. This makes the connection
* A LOT LESS SECURE.
*
* If you have a CA cert for the server stored someplace else than in the
* default bundle, then the CURLOPT_CAPATH option might come handy for
* you.
*/
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
#endif
#ifdef SKIP_HOSTNAME_VERIFICATION
/*
* If the site you're connecting to uses a different host name that what
* they have mentioned in their server certificate's commonName (or
* subjectAltName) fields, libcurl will refuse to connect. You can skip
* this check, but this will make the connection less secure.
*/
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
#endif
/* Perform the request, res will get the return code */
res = curl_easy_perform(curl);
/* Check for errors */
if (res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
/* always cleanup */
curl_easy_cleanup(curl);
}
curl_global_cleanup();
return 0;
}
Does someone know where could be problem? The server is running and can be accessed from different client and browser.
EDIT - SOLUTION
After adding curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); to my code I find out that the problem was in certificate path. In path to certificate ./ should be added, otherwise libcurl can not find the certificate.
I want to check FTP server connectivity using curl library in c program. Can anyone tell me how to do that without using any data transfer means i don't want to transfer any file to check that. I want is like CURLOPT_CONNECT_ONLY option which is available for only HTTP, SMTP and POP3 protocols not for FTP.
Curl version : 7.24
Requirement : FTP server connectivity test.
Here in below example, Only connect request will be delivered to FTP server and if server is pingable then it will give CURLE_OK return code other wise give failure response after specific timeout(60 sec). Other options you can set as per your requirement from http://curl.haxx.se/libcurl/c/ .
...
snprintf(ftp_url, BUF_LEN_512, "ftp://%s:%s#%s", uploadConf->username, uploadConf->password, uploadConf->ip);
// Reset curl lib
curl_easy_reset(curl);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, throw_away);
if (CURLE_OK != (res = curl_easy_setopt(curl, CURLOPT_URL, ftp_url)))
{
printf("Failed to check ftp url, Error : %s : %d\n", curl_easy_strerror(res), res);
}
curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
// Connection establishment timeout
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 60);
if (CURLE_OK != (res = curl_easy_perform(curl)))
{
/* If fail to connect */
}
else
{
/* If connected succesfully */
}
static size_t throw_away(void *ptr, size_t size, size_t nmemb, void *data)
{
size_t res;
res = (size_t)(size * nmemb);
/* we are not interested in the headers itself, so we only return the size we would have saved ... */
return res;
}
Hope it will help you all to test connectivity to FTP server using libcurl in c.
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.
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.