How to scp(transfer) file by a libssh? - c++

I am trying to transfer compiled executable file (compiled code c++, that prints 'Hello World!') to openssh linux server by using library libssh(I cant use terminal scp of openssh). I know, that libssh has a scp functions to transfer file from and to remoted ssh server. However there is some errors. This is a code of scp:
void ext(const char*c){
std::cout<<c;
exit(-5);
}
int scp_do(ssh_session session);
int scp_copy(ssh_session session, ssh_scp scp);
int main(){
int p = 22;
ssh_session session = ssh_new();
if (session == NULL)
exit(-1);
ssh_options_set(session, SSH_OPTIONS_HOST, "192.168.0.106");
ssh_options_set(session, SSH_OPTIONS_PORT, &p);
ssh_options_set(session, SSH_OPTIONS_USER, "user");
int rc = ssh_connect(session);
if (rc != SSH_OK){ //if not connected - exit
ssh_disconnect(session);
ext("Error connecting");
}
rc = ssh_userauth_password(session, NULL, "passwd");
if(rc != SSH_AUTH_SUCCESS){ //if not authed - exit
ssh_disconnect(session);
ssh_free(session);
return 0;
}
scp_do(session); //copying file, main task of this code
ssh_disconnect(session);
ssh_free(session);
return 0 ;
}
int scp_do(ssh_session session){ //copying file, main task of this code
ssh_scp scp;
int rc;
scp = ssh_scp_new(session, SSH_SCP_WRITE | SSH_SCP_RECURSIVE, ".");
if (scp == NULL)
ext("Error allocating scp session");
rc = ssh_scp_init(scp);
if (rc != SSH_OK)
ext("Error initializing scp session");
char buffer[1024];
std::ifstream fin("hello"); // compiled executable file('hello world'), that I want to sent to server
rc = ssh_scp_push_file(scp, "hello", 1024, S_IRUSR | S_IWUSR); //creating server's file to copy there
if (rc != SSH_OK)
ext("Can't open remote file");
fin.get(buffer, 1024); //reading from client's file
rc = ssh_scp_write(scp, buffer, 1024); //copying all compiled code to server file
if (rc != SSH_OK)
ext("Can't write to remote file");
ssh_scp_close(scp);
ssh_scp_free(scp);
return SSH_OK;
}
When I am trying to execute a transferred file on server, Firstly, I discover it is not
executable. So I am doing chmod +x for file. Secondly, When i am executing file, I am getting error:
[1] 6867 segmentation fault ./hello
However, when I am using scp of openssh to transfer file, there's no errors and it's executable. What can I do to solve my problems?

The size of file is like
4 62 17168 hello
I was thinking it will be less 1024 bytes, bcs it's a just hello world). So, i need only to send 17168 bytes.

Related

Transferring Sqlite DB file using libcurl functions but unable to open db file immediately to send the data to database

I am running a C++ application which communicates with a PLC based machine.
PLC based machine creates a .db(SQLITE) file once the machine processes the parts.
I wrote a function to transfer the sqlite db from PLC machine to PC using libcurl functions.
After the transfer is complete, i need to loop through the db file and transfer the data to the company network database table.
I have an issue with looping through the file once the transfer is done.
The file when reading throws an exception "(11) SQLITE_CORRUPT" - "Disk Image is Malformed".
But once i close my c++ application and open again, the last sqlite db file is able to open and loop through.
I am attaching the code below, let me know if there is a way to make the db file available to read once transferred through libcurl library. Should i be using some extra commands to make it available.
Information of the ftp server.
char dbfile[128];
char ofile[512];
//Pulling all the information about the ftp server information from parsed.xml -> Request/DataBlock/LogFile/Host, Path, File
char *host = tagTextValue(doc, "REQUEST.DATABLOCK.LOGFILE.HOST");// -- 172.16.1.100
if (host)
{
if (char *path = tagTextValue(doc, "REQUEST.DATABLOCK.LOGFILE.PATH")) // -- /pub/export/mdt
{
if (char *file= tagTextValue(doc, "REQUEST.DATABLOCK.LOGFILE.FILE"))// -- 20200226_004636_90180.db
{
sprintf_s( dbfile, sizeof(dbfile), "ftp://%s/%s/%s", host, path, file );//Host Address
sprintf_s(ofile, sizeof(ofile), "c:\\xxxxx\\xxxxx\\%s", file);//Destination Address
}
}
}
///////////Start of FTP///////////////////
struct FtpFile
{
const char *filename;
FILE *stream;
};
FtpFile ftp =
{
ofile, /* name to store the file as if successful */
NULL
};
CURL *url = curl_easy_init();
curl_easy_setopt(url, CURLOPT_URL, dbfile);// dbfile has the complete path where to pull the file from.
FILE *ffp = fopen(ofile, "w"); // ofile mentions the destination on the receiving end
curl_easy_setopt(url, CURLOPT_WRITEFUNCTION, my_fwrite);
curl_easy_setopt(url, CURLOPT_WRITEDATA, &ftp);
curl_easy_setopt(url, CURLOPT_USERPWD, "ftpuser:xxxx");// Passing the login details to FTP server to pull the information from the 'server/machine'
CURLcode res = curl_easy_perform(url);
fclose(ffp);
curl_easy_cleanup(url);
////////////////End of FTP/////////////////////////
sqlite3 *db;
sqlite3_stmt *stmt;
char sql[1024];
Sleep(20000);
WireBondDataUploadType rec = rec2;
const char* sql1 = "select xxxxxxxxxx";
bool storeSuccessful = false;
const char *ofile2 = "c:\\xxxxx\\xxxxxxx\\20200310_021605_20039.db";
int rc;
rc = sqlite3_open(ofile, &db); //ST Opening a new Database connection
if (rc == SQLITE_OK)
{
rc=sqlite3_prepare(db, sql1, -1, &stmt, NULL);
if(rc != 0)
{
sqlite3_close(db);
}
else if(rc == SQLITE_OK)
{
//Process the information by reading the db file.
xxxxxxxx
xxxxxxxx
}
}
The solution to the problem was we forgot to the close the "opened" ftp file(ofile) in the above mentioned code.
Reference link - [https://curl.haxx.se/libcurl/c/ftpget.html][1]

How to fix 'Address already in use' returned by bind() in AF_UNIX

I'm familiarising myself with Unix Sockets for Inter-Process Communication, and following a guide here. Each time I run the program that acts as a server (referred to as echos.c in the guide), I am getting an error that says bind: Address already in use, except for the first time I run it after deleting all build files.
The error is coming from this section of code:
#define SOCK_PATH "echo_socket"
int main(void)
{
int s, s2, len;
socklen_t t;
struct sockaddr_un local, remote;
char str[100];
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
local.sun_family = AF_UNIX;
strcpy(local.sun_path, SOCK_PATH);
unlink(local.sun_path);
len = strlen(local.sun_path) + sizeof(local.sun_family);
if (bind(s, (struct sockaddr *)&local, len) == -1) {
perror("bind");
exit(1);
}
// ...
In the initial run, the program creates a socket file called echo_socke (I have checked this with ls -l, and it is strange that the name is missing the 't' to make it echo_socket), and then goes on to successfully bind and listen for the client process.
However, in subsequent runs where I do not delete the build files, I get the error bind: Address already in use, coming from the lines
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
Doing additional testing I found that unlink(local.sun_path) is returning a No such file or directory error, so I figure the socket file that the bind is attempting to access is not being found. Could this be due to the file name missing a character as mentioned earlier? (But it works on the first time around, so it can't be?). Any help figuring out what is going on would be much appreciated.

How to link .so file to a cpp program

I have libssh2.so.1.0.1(.so) binary on my local machine and I don't have any header files present on my machine.
This is the basic ssh program I have been trying to connect to my server through ssh protocol.
Reference: How to establish a simple ssh connection with c++
Now I am unable to link library (libssh2.so.1.0.1) to the below sample program.
Following is the sample program I have written and followed by errors.
sshsample.cpp:
#include <stdlib.h>
#include <stdio.h>
int main()
{
ssh_session my_ssh_session;
int rc;
int port = 22;
int verbosity = SSH_LOG_PROTOCOL;
char *password;
// Open session and set options
my_ssh_session = ssh_new();
if (my_ssh_session == NULL)
exit(-1);
ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, "192.168.1.6");
ssh_options_set(my_ssh_session, SSH_OPTIONS_USER, "john");
ssh_options_set(my_ssh_session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
// Connect to server
rc = ssh_connect(my_ssh_session);
if (rc != SSH_OK)
{
fprintf(stderr, "Error: %s\n", ssh_get_error(my_ssh_session));
ssh_free(my_ssh_session);
exit(-1);
}
// Authenticate ourselves
password = "pass";
rc = ssh_userauth_password(my_ssh_session, NULL, password);
if (rc != SSH_AUTH_SUCCESS)
{
fprintf(stderr, "Error authenticating with password: %s\n",
ssh_get_error(my_ssh_session));
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
exit(-1);
}
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
}
I have compiled the above file with below command
g++ -L. -llibssh2 -o main sshsample.cpp
but I get the following error
sshsample.cpp: In function 'int main()':
sshsample.cpp:8: error: 'ssh_session' was not declared in this scope
sshsample.cpp:8: error: expected `;' before 'my_ssh_session'
sshsample.cpp:11: error: 'SSH_LOG_PROTOCOL' was not declared in this scope
sshsample.cpp:14: error: 'my_ssh_session' was not declared in this scope
sshsample.cpp:14: error: 'ssh_new' was not declared in this scope
Any suggestions/help would be of great use
Thanks in advance ...
You need to include the libssh2 header file into your compilation units where ssh APIs are invoked. You cannot expect the compiler to resolve what an ssh_session is without this. If you have the library properly installed, you should have access to the header files to invoke it.
#include <libssh2.h>
Edit: Honestly the APIs you are using in your example belong to the original libssh library I don't see anything in your example that would need to link with libssh2.
#include <libssh/libssh.h>

How to establish a simple ssh connection with c++

I am trying to make a c++ program which will connect to an ssh server (my laptop). The server is ok because I can get connected via putty. Although the program I wrote so far can not. In my code I am using the library libssh.h and for development I used visual studio 2015. The error I get is: crypt_set_algorithms2: no crypto algorithm function found for 3des-cbc
I haven't found anything so far so I hope to your help.
The code I use:
#include <libssh/libssh.h>
#include <stdlib.h>
#include <stdio.h>
int main()
{
ssh_session my_ssh_session;
int rc;
int port = 22;
int verbosity = SSH_LOG_PROTOCOL;
char *password;
// Open session and set options
my_ssh_session = ssh_new();
if (my_ssh_session == NULL)
exit(-1);
ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, "192.168.1.6");
ssh_options_set(my_ssh_session, SSH_OPTIONS_USER, "john");
ssh_options_set(my_ssh_session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
ssh_options_set(my_ssh_session, SSH_OPTIONS_CIPHERS_C_S,"aes128-ctr");
//ssh_options_set(my_ssh_session, SSH_OPTIONS_PORT, &port);
// Connect to server
rc = ssh_connect(my_ssh_session);
if (rc != SSH_OK)
{
fprintf(stderr, "Error: %s\n", ssh_get_error(my_ssh_session)); //HERE IS WHERE I GET THE ERROR
ssh_free(my_ssh_session);
exit(-1);
}
// Verify the server's identity
// For the source code of verify_knowhost(), check previous example
/* if (verify_knownhost(my_ssh_session) < 0)
{
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
exit(-1);
}
*/
// Authenticate ourselves
password = "pass";
rc = ssh_userauth_password(my_ssh_session, NULL, password);
if (rc != SSH_AUTH_SUCCESS)
{
fprintf(stderr, "Error authenticating with password: %s\n",
ssh_get_error(my_ssh_session));
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
exit(-1);
}
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
}
Try to use different cipher. 3des-cbc is broken and probably disabled on your server already.
There is really nice tutorial with simple session.
Removing the line makes it working for me on Ubuntu (don't know where you found it):
ssh_options_set(my_ssh_session, SSH_OPTIONS_CIPHERS_C_S,"aes128-ctr");
If not, what version of libssh are you using? Isn't it some obsolete one?
Finally got it! I removed the line
ssh_options_set(my_ssh_session, SSH_OPTIONS_CIPHERS_C_S,"aes128-ctr");
Then I used the ssh.dll from libssh v0-7.2 instead of the ssh.dll of v0-7.1 I used before. The ssh.dll is located in libssh-0.7.2\bin. If you take an error like the msvcr120d.dll is missing try to change from debug to release in visual studio.

How to copy a file in C/C++ with libssh and SFTP

I want to copy a file from a client to a remote server, but I don't understand how to do it with the libssh library SFTP API.
The situation is that: The SSH session is open and the SFTP session is open too, I can create a file and write in it from the client to the server with the integrated function of libssh.
I did not find an easy way to copy a file from the client to the server with a simple function like sftp_transfer(sourceFile(like c:\my document\hello world.txt),RemoteFile(/home/user/hello world.txt),right(read and write)) ?
With what I have understood from the tutorial it is first creating a file in the remote location (server) then it is opening this file with this line of code:
file = sftp_open(sftp, "/home/helloworld.txt",access_type,1);
After that the file is created on the server, and then it is writing into this created file with a buffer:
const char *helloworld = "Hello, World!\n";
int length = strlen(helloworld);
nwritten = sftp_write(file, helloworld, length);
My question is now if I have a file for example a .doc file and I want to transfer/upload that file from c:\mydocument\document.doc to remote the remote server /home/user/document.doc, how can I do it with this method ?
How can I put this file into the sftp_write() function to send it like the helloworld in the sample function?
I may be not good enough in programming to understand, but I really tried to understand it and I'm stuck with it.
Thanks in advance for your help
See below a sample of the code I used to test:
// Set variable for the communication
char buffer[256];
unsigned int nbytes;
//create a file to send by SFTP
int access_type = O_WRONLY | O_CREAT | O_TRUNC;
const char *helloworld = "Hello, World!\n";
int length = strlen(helloworld);
//Open a SFTP session
sftp = sftp_new(my_ssh_session);
if (sftp == NULL)
{
fprintf(stderr, "Error allocating SFTP session: %s\n",
ssh_get_error(my_ssh_session));
return SSH_ERROR;
}
// Initialize the SFTP session
rc = sftp_init(sftp);
if (rc != SSH_OK)
{
fprintf(stderr, "Error initializing SFTP session: %s.\n",
sftp_get_error(sftp));
sftp_free(sftp);
return rc;
}
//Open the file into the remote side
file = sftp_open(sftp, "/home/helloworld.txt",access_type,1);
if (file == NULL)
{
fprintf(stderr, "Can't open file for writing: %s\n",ssh_get_error(my_ssh_session));
return SSH_ERROR;
}
//Write the file created with what's into the buffer
nwritten = sftp_write(file, helloworld, length);
if (nwritten != length)
{
fprintf(stderr, "Can't write data to file: %s\n",
ssh_get_error(my_ssh_session));
sftp_close(file);
return SSH_ERROR;
}
Open the file in the usual way (using C++'s fstream or C's stdio.h), read its contents to a buffer, and pass the buffer to sftp_write.
Something like this:
ifstream fin("file.doc", ios::binary);
if (fin) {
fin.seekg(0, ios::end);
ios::pos_type bufsize = fin.tellg(); // get file size in bytes
fin.seekg(0); // rewind to beginning of file
std::vector<char> buf(bufsize); // allocate buffer
fin.read(buf.data(), bufsize); // read file contents into buffer
sftp_write(file, buf.data(), bufsize); // write buffer to remote file
}
Note that this is a very simple implementation. You should probably open the remote file in append mode, then write the data in chunks instead of sending single huge blob of data.
The following example uses ifstream in a loop to avoid loading a whole file into a memory (what the accepted answer is doing):
ifstream fin("C:\\myfile.zip", ios::binary);
while (fin)
{
constexpr size_t max_xfer_buf_size = 10240
char buffer[max_xfer_buf_size];
fin.read(buffer, sizeof(buffer));
if (fin.gcount() > 0)
{
ssize_t nwritten = sftp_write(NULL, buffer, fin.gcount());
if (nwritten != fin.gcount())
{
fprintf(
stderr, "Error writing to file: %s\n", ssh_get_error(ssh_session));
sftp_close(file);
return 1;
}
}
}
I used followed the example here.
sftp_read_sync uses an infinite loop to read a file from a server into /path/to/profile
from server path /etc/profile.