libcurl implementation on public-private key authentication on SSH [closed] - c++

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
Created public and private key
ssh-keygen -t rsa <-- performed the operation in the SSH client
ssh-copy-id #
Note: no passphrase on the creation of the key
Can someone please help me on how to implement libcurl PutFile method using
- username
- private key
- public key
- sftp
Tried to browse on libcurl examples, but sadly this is the most similar example https://curl.haxx.se/libcurl/c/usercertinmem.html

Forget about usercertinmem.c, just take fileupload.c and add SSH options as needed.
Something like this:
curl_easy_setopt(curl, CURLOPT_URL, "sftp://username#host/path/file");
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(curl, CURLOPT_READDATA, fd);
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_size);
curl_easy_setopt(curl, CURLOPT_SSH_AUTH_TYPES, CURLSSH_AUTH_PUBLICKEY);
curl_easy_setopt(curl, CURLOPT_SSH_PUBLIC_KEYFILE, pubkey_filename);
curl_easy_setopt(curl, CURLOPT_SSH_PRIVATE_KEYFILE, privkey_filename);
curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "");
curl_easy_setopt(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, known_host_sign);
res = curl_easy_perform(curl);
You can read about these SSH-specific and other options in the options documentation.
Instead of CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 you can also use CURLOPT_SSH_KNOWNHOSTS or CURLOPT_SSH_KEYFUNCTION.

Related

Using CURL in C++/C to issue a GET HTTP Request with a data file

Using the CURL at the command line:
curl -d #%1 -X GET https://blah-blah
This is in a Windows batch file and I pass the name of the file on the command line. Using this, I can issue a service call sending in a file with a whole lot of input parameters and I receive a substantial output.
For the life of me, when I try pro \grammatically, I can't make it work. It must be possible, since it can be done on the command. However, when I set
curl_easy_setopt(m_Curl, CURLOPT_HTTPGET, 1);
I can't upload a file, even if I set the callback
If I use:
curl_easy_setopt(m_Curl, CURLOPT_UPLOAD, 1L);
the call becomes 'PUT', even though I try and force the header to be a GET. I follow the documentation and can see that this is the documented behavior. However, what is the pathway for avoiding this default?
Any guidance would be most appreciated.
Thanks,
Stan
AFAIK it's not strictly forbidden but you shouldn't send a body with a GET request. On the other side a server should be able to handle a GET request with body but the response shouldn't be dependent of the content of the body.
If you really need to send a request containing a body with GET you can change the value of the method with CURLOPT_CUSTOMREQUEST. This won't change the behavior of curl. This snippet will upload data with GET:
CURL* curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_PORT, port);
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
const auto* file = fopen(filename.c_str(), "r");
curl_easy_setopt(curl, CURLOPT_READDATA, file);
curl_easy_setopt(
curl, CURLOPT_INFILESIZE_LARGE, static_cast<curl_off_t>(filesize));
curl_easy_perform(curl);
}
You can also use the CURLOPT_POSTFIELDS command, to paste the body as a string. Afterwards you change the request to GET like in #Thomas Sablik s answer.
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
// Set target URL
curl_easy_setopt(curl, CURLOPT_URL, requestURL.c_str());
// Set HTTP version
curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, (long) CURL_HTTP_VERSION_3);
// Set POST fields
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, requestBody.c_str());
// Set request to get
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
// Set response target
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
// Perform CURL request
CURLcode res = curl_easy_perform(curl);

HTTP POST with LibCurl

Sending POST request using libcurl C++. I have tried almost all combination except the right one which I could not figure out.
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE); /*Not Recommended to use but since certificates are not available this is a workaround added*/
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, FALSE); /*Not Recommended to use but since certificates are not available this is a workaround added*/
curl_easy_setopt(curl, CURLOPT_HTTPPOST, TRUE); //CURLOPT_POST does not work as well
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, sJson);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, bytesCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, bytesCallback);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, &headBuffer);
sJson is a std::string which has the body that is created by pb2json.
I cannot figure out why the body is not sent ?
Is there some API i am missing if libcurl, any lead is appreciated !
I would prefer using custom request here CURLOPT_CUSTOMREQUEST below is the code snippet that works fine!
When you use custom requests nothing implies and you have to explicitly define the CURLOPT_HTTPHEADER
Use a list here, for brevity I have used the minimal code here.
Also when you pass sJson pass it as a c type string using c_str() and remember to use +1 while passing the content length (which I somehow missed initially) as in C, strings are just char arrays which, by convention, end with a NULL byte.
struct curl_slist* slist = NULL;
slist = curl_slist_append(slist, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, sJson.c_str()); /* data goes here */
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, sJson.length() + 1); /* data goes here */
EDIT: Use of curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); might create problems in redirection, use it according to your use case.

C++ curl POST for LiFx Control

I'm using curl with c++ to list all the bulbs successfully
curl_easy_setopt(curl,CURLOPT_USERNAME, MY_API_key);
curl_easy_setopt(curl, CURLOPT_URL, "https://api.lifx.com/v1beta1/lights/all/");
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &Data);
res = curl_easy_perform(curl);
To toggle power to all light the documentation http://developer.lifx.com/#toggle-power says to use
curl -u "c87c73a896b554367fac61f71dd3656af8d93a525a4e87df5952c6078a89d192:" -X POST "https://api.lifx.com/v1beta1/lights/all/toggle"
I've tested this via the pre-built curl binary it works fine. I can't figure out how to construct the POST format in the C++ code.
curl_easy_setopt(curl,CURLOPT_USERNAME, MY_API_key);
curl_easy_setopt(curl,CURLOPT_POST,"https://api.lifx.com/v1beta1/lights/all/toggle");
curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER, FALSE);
curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl,CURLOPT_WRITEDATA, &Data);
res = curl_easy_perform(curl);
However, res returns CURLE_URL_MALFORMAT, I think this is because I haven't set the CURLOPT_URL property... but I'm not sure what it needs to be set to.
I tried using a similar format to this PHP question (PHP HTTP CURL PUT request for LIFX Power On/Off) but with no luck, it still returns CURLE_URL_MALFORMAT.
CURLOPT_POST is wrongly used there. It should be set to 0 or 1 only. You set the URL with CURLOPT_URL.
You could use --libcurl sample.c added to your (working) curl command line to get a good sample source code to start from.
To mimic that command line closer, you can probably skip CURLOPT_POST and just have CURLOPT_CUSTOMREQUEST set to "POST"

libcURL and Google Docs

I'm trying to download a file needed for my application off the internet (as part of installation) so that the first time the app starts up, the needed files get downloaded. For now I'm putting them on Google Drive and making them public, then I'm going to use libcURL to download them. The problem is, I just can't get the data.
I use the following link: https://docs.google.com/uc?id=documentID&export=download and replace documentID with the id. When I try connecting to the site though, it keeps giving me a small snippet of HTML code that basically says "Moved Temporarily" and gives me a link to the new URL. When I use the new link in my program, I get no output whatsoever. However, both links work just fine in my web browser, even when I'm not signed in. So Why don't they work in my program? Am I not setting up SSL options correctly, or is Google Drive simply not meant for this kind of thing?
Here's my code:
#include <curl/curl.h>
int main()
{
curl_global_init(CURL_GLOBAL_ALL);
CURL *curl;
CURLcode res;
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "https://docs.google.com/uc?id=documentID&export=download");
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
res = curl_easy_perform(curl);
}
curl_easy_cleanup(curl);
return 0;
}
Any help would be appreciated.
You'll need to set the CURLOPT_FOLLOWLOCATION option to tell cURL to follow redirects.
I do not know if this helps directly but I have always made the call
curl_global_init(CURL_GLOBAL_ALL);
which I see you don't use. I have seen this call made here in the threaded SSL code example http://curl.haxx.se/libcurl/c/threaded-ssl.html. This `curl_global_init() call will perform SSL initialisation amongst other things. It is discussed in this link http://curl.haxx.se/libcurl and also in the libcurl tutorial here http://curl.haxx.se/libcurl/c/libcurl-tutorial.html

Using libcurl & SSL

I've found there is really very little information around on this topic. I already have a dll making successful posts using libcurl.
I've compiled libcurl with openssl for ssl functionality.
Here is an exert of my original curl setup.
curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, errorBuffer);
//curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER , 1);
//curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST , 1);
//curl_easy_setopt(curl, CURLOPT_CAINFO , "./ca.cert");
curl_easy_setopt(handle, CURLOPT_POSTFIELDS, cParam);
curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, strlen(cParam));
curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, Request::writer);
curl_easy_setopt(handle, CURLOPT_WRITEDATA, &buffer);
curl_easy_setopt(handle, CURLOPT_URL, cURL);
My question to those who've done this before, is it as easy as just adding those lines above to get SSL to work (as long as the certificate exists)? Or is it more complicated?
The funny thing is I'm not completely sure how SSL works. I've never worked with it before. Do I need to store a key in my application and send it with each request? Anyway my main question was the first. Thank you in advance.
Yes, it is that simple. Just make sure that the "ca.cert" file you have is a true CA cert that can verify your server's certificate.
All you need to do to use SSL with libcurl is give an https url instead of an http url. The only option you need to set with curl_easy_setopt is CURLOPT_URL, although it will just print the received data to stdout if you don't specify a write callback.
CURL *handle = curl_easy_init();
char url[] = "https://google.com";
curl_easy_setopt(handle, CURLOPT_URL, url);
curl_easy_perform(handle);
Make sure that when using CURLOPT_SSL_VERIFYHOST you set the actual value to 2L (which is the default) instead of 1 (as shown as a comment in that example), if you really want to check the hostname matches, otherwise it would just check for the existence of a "Common name" (CN) in the certificate.