How to use libssh's SCP with ssh::Session - c++

I am using libssh's C++ wrapper (libsshpp.hpp) and I'm trying to call ssh_scp_new for an SCP routine by giving it my ssh::Session variable but I get the following error:
cannot convert ‘ssh::Session’ to ‘ssh_session {aka ssh_session_struct*}’ for argument ‘1’ to ‘ssh_scp_struct* ssh_scp_new(ssh_session, int, const char*)’
I am able to get SCP working by completely not using the C++ ssh::Session class and going with the C example but obviously this is not my preferred workaround. Looking at libsshpp.hpp I was able to find a getCSession() function but it is only privately accessible and I'm not sure how to use it (or if it's even what I think it is).
Here is my sample code:
#include <iostream>
#include <fstream>
#include <libssh/libsshpp.hpp>
int main()
{
int port = 22;
int verbosity = SSH_LOG_PROTOCOL;
ssh::Session session;
try
{
session.setOption(SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
session.setOption(SSH_OPTIONS_PORT, &port);
session.setOption(SSH_OPTIONS_USER, "user");
session.setOption(SSH_OPTIONS_HOST, "host");
session.connect();
if (session.isServerKnown() != SSH_SERVER_KNOWN_OK)
{
if (session.writeKnownhost() != SSH_OK)
{
std::cout << "writeKnownHost failed" << std::endl;
}
else
{
session.connect();
}
}
if (session.userauthPassword("password") !=
SSH_AUTH_SUCCESS)
{
std::cout << "Authentication Error" << std::endl;
}
ssh_scp scp;
int rc;
// error cannot convert ‘ssh::Session’ to ‘ssh_session {aka ssh_session_struct*}’
scp = ssh_scp_new(session, SSH_SCP_WRITE | SSH_SCP_RECURSIVE, ".");
}
catch (ssh::SshException e)
{
std::cout << "Error during connection : ";
std::cout << e.getError() << std::endl;
}
return 0;
}
How do I SCP send or receive a file with libssh using C++ methods?
Thanks!

As you can see the error. You have to decide to weather use ssh::Session class or ssh_session structure. The libssh library is a C library, and it has just a C++ wrapper (that may not contain all functionalities like in the original language)
Here is how to send connect and send files using libssh library (current stable version 0.7.3) according to official documentation.
Using ssh_session: (in C)
-use ssh_new() to create a ssh_session pointer.
-use int ssh_connect(ssh_session session) to connect.
-use *int ssh_options_set ( ssh_session session, enum ssh_options_e type,const void * value )* Take a look on this documentation http://api.libssh.org/stable/group__libssh__session.html#ga7a801b85800baa3f4e16f5b47db0a73d
-add your controls
-send file using ssh_scp_new(session, SSH_SCP_WRITE | SSH_SCP_RECURSIVE, ".");
-free the connection using ssh_free(ssh_session session)
//You can try this simple program (from official libssh tutorials)
#include <libssh/libssh.h>
#include <stdlib.h>
#include <stdio.h>
int scp_write(ssh_session session)
{
ssh_scp scp;
int rc;
scp = ssh_scp_new
(session, SSH_SCP_WRITE | SSH_SCP_RECURSIVE, ".");
if (scp == NULL)
{
fprintf(stderr, "Error allocating scp session: %s\n", ssh_get_error(session));
return SSH_ERROR;
}
rc = ssh_scp_init(scp);
if (rc != SSH_OK)
{
fprintf(stderr, "Error initializing scp session: %s\n", ssh_get_error(session));
ssh_scp_free(scp);
return rc;
}
ssh_scp_close(scp);
ssh_scp_free(scp);
return SSH_OK;
}
int main(int argc, char* argv[])
ssh_session my_ssh_session = ssh_new();
if (my_ssh_session == NULL)
return 1;
scp_write(my_ssh_session );
ssh_free(my_ssh_session);
return 0;
}
Using ssh::Session (in C++) well, no wrapper allows this currently :( .
Here is some useful examples for the use of libssh library. Hope it helps !
http://api.libssh.org/master/libssh_tutorial.html

Related

How can I inherit a socket in a child process on Windows using Boost.Asio and Boost.Procees?

I am writing a multiprocess socket server, and on Linux it works perfectly, but on Windows it just crashes without any error. I believe it is because it does not actually inherit the socket file descriptor correctly.
Below is a stripped down version of my code that just prints all the file descriptors in the child process. On my windows VM it prints a list of FDs, but the FD that it gets passed from the parent process is not in the list, it's higher than any of the listed ones.
I found this windows documentation about how to inherit a socket: https://learn.microsoft.com/en-us/windows/win32/sysinfo/handle-inheritance
I also found that Boost.Process has this property, that suggests by default handlers are inherited: https://www.boost.org/doc/libs/1_78_0/doc/html/boost/process/limit_handles.html
But It's not clear why my socket isn't getting inherited, and what to do about it.
#include <stdio.h>
#include <string>
#include <boost/asio.hpp>
#include <boost/process.hpp>
#include <boost/process/handles.hpp>
using boost::this_process::native_handle_type;
using namespace boost::asio;
using ip::tcp;
int main(int argc, char const *argv[])
{
int port = 5923;
if (argc == 2 && strcmp(argv[1], "--help")==0) {
printf("%s [port]\n", argv[0]);
return 0;
} else if (argc == 3 && strcmp(argv[1], "--child")==0) {
printf("child process\n");
int fd = std::stoi(argv[2]);
auto hds = boost::this_process::get_handles();
for (auto h : hds) {
std::cout << h << std::endl;
}
printf("got FD %d\n", fd);
return 0;
} else if (argc == 2)
{
port = std::stoi(argv[1]);
}
boost::asio::io_service io_service;
tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v6(), port));
while (1)
{
printf("waiting for clients\n");
tcp::socket peersocket(io_service);
acceptor.accept(peersocket);
auto endpoint = peersocket.remote_endpoint();
printf("Accepted new connection from a client %s:%d\n", endpoint.address(), endpoint.port());
std::string fd = std::to_string(peersocket.release());
std::cout << fd << std::endl;
boost::process::spawn(argv[0], "--child", fd);
}
return 0;
}
Okay I found the answer, it's actually super simple
EOF
Jk, I'll leave the solution for future me or other lost souls.
You have to write an "extension" to make Windows inherit the handles.
https://www.boost.org/doc/libs/1_78_0/doc/html/boost_process/extend.html
The properties of the windows_executor are explained here:
https://www.boost.org/doc/libs/1_78_0/doc/html/boost/process/extend/windows_executor.html
So all we need to do is register a on_setup extension and set inherit_handles to true. Something like this:
struct do_inherit : boost::process::extend::handler
{
template<typename Char, typename Sequence>
void on_setup(ex::windows_executor<Char, Sequence> & exec)
{
std::cout << "windows setup" << std::endl;
exec.inherit_handles = 1;
}
template<typename Sequence>
void on_setup(ex::posix_executor<Sequence> & exec)
{
std::cout << "unix setup" << std::endl;
}
};
And with all this modern technology we can finally do what inetd did decades ago, but now with more template generics and on Windows.

TeamSpeak 3 SDK Connection problems

I´m trying to use the TeamSpeak SDK for a personal project, but the code I wrote gives me weird errors.
I read the documentation many times to find an error but I can´t see why my program is not able to connect to the TeamSpeak Server.
Here is the output from the program:
Client library version: 3.0.3.2 [Build: 1433933257] SDK
Connection Status changed to: 1, errorNumber: 0
Connection Status changed to: 0, errorNumber: 1797
failed connection initialization
Here is the program code
#include <iostream>
#include <fstream>
#include <cstring>
#include <teamspeak/clientlib.h>
#include <teamspeak/public_errors.h>
uint64 connectionHandler;
void destroy();
void event_connectStatusChanged(uint64 serverConnectionIDHandler, int newStatus, unsigned int errorNumber);
void event_serverError(uint64 serverConnectionHandlerID, const char* errorMessage, unsigned int error, const char* returnCode, const char* extraMessage);
int main()
{
ClientUIFunctions uiFunctions;
memset(&uiFunctions, 0, sizeof(struct ClientUIFunctions));
uiFunctions.onConnectStatusChangeEvent = event_connectStatusChanged;
uiFunctions.onServerErrorEvent = event_serverError;
unsigned int error = ts3client_initClientLib(&uiFunctions, NULL, LogType_FILE, NULL, "./");
if (error != ERROR_ok)
printf("Error initializing clientlib: %i\n", error);
char* version;
error = ts3client_getClientLibVersion(&version);
if (error != ERROR_ok) {
printf("Error querying clientlib version: %d\n", error);
return 0;
}
printf("Client library version: %s\n", version); /* Print version */
ts3client_freeMemory(version); /* Release string */
if (ts3client_spawnNewServerConnectionHandler(0, &connectionHandler) != ERROR_ok)
{
destroy();
return 0;
}
char* identity;
ts3client_createIdentity(&identity);
error = ts3client_startConnection(connectionHandler, identity, "127.0.0.1", 9987, "test", NULL, "", "");
ts3client_freeMemory(identity);
if (error != ERROR_ok)
std::cout << "Connection failed!" << std::endl;
getchar();
ts3client_stopConnection(connectionHandler, "...");
destroy();
return 0;
}
void event_connectStatusChanged(uint64 serverConnectionIDHandler, int newStatus, unsigned int errorNumber)
{
printf("Connection Status changed to: %i, errorNumber: %i\n", newStatus, errorNumber);
if (errorNumber != ERROR_ok)
{
char* error;
ts3client_getErrorMessage(errorNumber, &error);
std::cout << error << std::endl;
ts3client_freeMemory(error);
}
}
void event_serverError(uint64 serverConnectionHandlerID, const char* errorMessage, unsigned int error, const char* returnCode, const char* extraMessage)
{
std::cout << "ERROR: " << errorMessage << std::endl << "Extra Message: " << extraMessage << std::endl;
}
void destroy()
{
ts3client_destroyServerConnectionHandler(connectionHandler);
ts3client_destroyClientLib();
}
It appears your client crashes immediately on connecting.
Here are some common causes to check:
Server doesn't exist at that address.
Server password is wrong.
Default channel doesn't exist.
Client has been banned.
Server is an illegal installation.
Security level of your identity is too low.
Also, this error can be triggered when a component such as client, server, etc need to be updated:
I updated to the latest version because the bot wouldn't launch and
figured I'd give the install on my other server another try. It's
working flawlessly now.
Ref: https://forum.sinusbot.com/threads/new-connection-status-0-error-1797.2508/

MySQL C++ Connector crashes my app at ResultSet->getString()

It's me again probably asking noob C++ questions
I had MAJOR headaches making the darn (sorry for the language) MySQL C++ connector work. I don't know if it is poorly written or something, but for my experience yet I've never had so much trouble making something to work.
Anyhow I got it to connect and throw exceptions on failed connect/query which for me is quite big thing :U :P . The actual problem comes out of me obtaining the result of the query. Regardless of what I do my application always crashes :S
I used the 32-bit installer and the libmysql.dll/lib from the 32-bit MySQL server (since i'm compiling a 32-bit application i figured this is the right thing to do)
Here's some code so you could imagine what I'm talking about
DBManager.h
#ifndef DBMANAGER_H
#define DBMANAGER_H
#define CPPCONN_PUBLIC_FUNC
#define CPPCONN_LIB_BUILD True
#include <string>
#include "mysql_connection.h"
#include "mysql_driver.h"
#include <cppconn/driver.h>
#include <cppconn/exception.h>
#include <cppconn/resultset.h>
#include <cppconn/statement.h>
#include <cppconn/prepared_statement.h>
class DBManager
{
public:
static DBManager* Instance();
bool Query(const char* Query);
void Connect(const char* DbHost, unsigned short DbPort, const char* DbUser, const char* DbPass, const char* DbName);
bool ValidCredentials(const char* Username, const char* Password);
void ManageException(sql::SQLException &e);
~DBManager();
protected:
static DBManager* pInstance;
private:
DBManager() {};
DBManager(DBManager const&){};
DBManager& operator=(DBManager const&){};
sql::mysql::MySQL_Driver* driver;
sql::Connection *Con;
sql::PreparedStatement *pstmt;
sql::ResultSet *res;
sql::Statement *stmt;
bool isConnected;
};
#endif
And now the cpp file DBManager.cpp
#include "DBManager.h"
DBManager* DBManager::pInstance = NULL;
DBManager* DBManager::Instance()
{
if (!pInstance)
{
pInstance = new DBManager();
}
return pInstance;
}
bool DBManager::Query(const char* Query)
{
return true;
}
DBManager::~DBManager()
{
delete Con;
delete pstmt;
delete res;
delete stmt;
}
void DBManager::ManageException(sql::SQLException& e)
{
if (e.getErrorCode() != 0) {
std::cout << "# ERR: SQLException in " << __FILE__;
std::cout << "(" << __FUNCTION__ << ") on line " << __LINE__ << std::endl;
std::cout << "# ERR: " << e.what();
std::cout << " (MySQL error code: " << e.getErrorCode();
std::cout << ", SQLState: " << e.getSQLState() << " )" << std::endl;
}
}
void DBManager::Connect(const char* DbHost, unsigned short DbPort, const char* DbUser, const char* DbPass, const char* DbName)
{
try {
driver = sql::mysql::get_mysql_driver_instance();
std::string connDSN = "tcp://" + std::string(DbHost) + ":3306";
Con = driver->connect(connDSN, sql::SQLString(DbUser), sql::SQLString(DbPass));
Con->setSchema(sql::SQLString(DbName));
isConnected = true;
std::cout<<"Database connection successul."<<std::endl;
} catch(sql::SQLException &e) {
ManageException(e);
isConnected = false;
return;
}
}
bool DBManager::ValidCredentials(const char* Username, const char* Password)
{
bool cred = false;
try {
pstmt = Con->prepareStatement("SELECT * FROM account WHERE account_name=? LIMIT 1"); // Smart use of indexing
pstmt->setString(1, Username);
res = pstmt->executeQuery();
while(res->next())
{
if (res->getString("password") == Password)
{
cred = true;
}
}
}
catch(sql::SQLException &e) {
ManageException(e);
return false;
}
return cred;
}
Basically, It compiles without a problem, Connects without a problem, Executes queries without a problem, but the second I try to retrieve data some breakpoint exception is thrown in a file "xutils.cpp". I really have no idea what I'm doing wrong. I'm using the DEBUG libraries while compiling for debug. Hmm libmysql.dll should be release since I extracted it from the server bundle, but I don't seem to find it as a source to compile my own.
I really have no idea why it crashes and burn like that :/
PS: Don't mind the no hashing of the password, it really is just a proof of concept to me in the way of ... getting it to work first, then securing it :U
PS: I also have Boost libraries compiled and ready in the project, if that would help :U
EDIT: Main function
bool ServerRunning = true;
int main(int argc, char** argv)
{
#ifdef _WIN32
std::string title = TEXT("Window Title Change");
SetConsoleTitle(title.c_str());
#endif;
std::cout<<"Loading Configuration File..."<<std::endl<<std::endl;
std::string path = boost::filesystem::path(boost::filesystem::current_path()).string();
path += "\\Config.ini";
INIParser* Config = new INIParser(path.c_str()); //MinINI
// Sockets data
std::string listenIP = Config->GetString("Network", "ListenIP", "127.0.0.1");
unsigned short listenPort = Config->GetInt("Network", "ListenPort", 5000);
// Database data
std::string dbHost = Config->GetString("Database", "Host", "localhost");
std::string dbUser = Config->GetString("Database", "User", "root");
std::string dbPass = Config->GetString("Database", "Password", "");
std::string dbName = Config->GetString("Database", "Database", "authserv");
unsigned short dbPort = Config->GetInt("Database", "Post", 1000);
// General settings
int sessionTimeout = Config->GetInt("Settings", "SessionTimeout", 10);
int maxClients = Config->GetInt("Settings", "MaxClients", 10);
int serverTimeout = Config->GetInt("Settings", "GameserverTimeout", 1);
// Begin Initialization
DBManager::Instance()->Connect(dbHost.c_str(), dbPort, dbUser.c_str(), dbPass.c_str(), dbName.c_str());
bool loginSuccess = DBManager::Instance()->ValidCredentials("Username", "Password");
char c;
while (ServerRunning)
{
std::cin>>c;
if (c == 'q')
{
ServerRunning = false;
}
}
return 0;
}
Assuming the password field is defined as varchar in the database, you cannot use getString() to retrieve it. You must instead use the blob function, getBlob().
This is how the while loop would look:
while(res->next())
{
std::istream * retrievedPassword_stream = res->getBlob("password");
if (retrievedPassword_stream)
{
char pws[PASSWORD_LENGTH+1]; // PASSWORD_LENGTH defined elsewhere; or use other functions to retrieve it
retrievedPassword_stream->getline(pws, PASSWORD_LENGTH);
std::string retrievedPassword(pws); // also, should handle case where Password length > PASSWORD_LENGTH
if (retrievedPassword == std::string(Password))
{
cred = true;
}
}
}
Side comments: Note that there are some other issues with the code.
The statement handle must be deleted, so you should do a delete pstmt; at the appropriate place in the ValidCredentials() function (rather than in the destructor). (But, why use a prepared statement in that case anyways? Better to initialize the prepared statement in the constructor (or somewhere else outside the function the query is called), as well as delete in the destructor or elsewhere, if you do use a prepared statement. Instead of a prepared statement, though, note that prepared statements are most useful for very high-use and high-CPU intensive queries, so using it for password validation might not be important here (you could just execute a regular query, instead of a prepared statement).)
Likewise, the ResultSet needs to be deleted (delete res) at the end of the try block, rather than in the destructor.
Be sure to check for NULL before using pstmt, res, or Con.
stmt appears to be unused and should not be deleted.
download mysql c++ connector
compile mysqlcppconn-static project use mt or mtd
your project add CPPCONN_LIB_BUILD
your project add (2) built static library

How to get domain ip address using domain name in C++?

i am using visual c++,
I want to get a domain ip address from domain name..
how do i get it..
i already tried gethostbyname function...
here my code...
HOSTENT* remoteHost;
IN_ADDR addr;
hostName = "domainname.com";
printf("Calling gethostbyname with %s\n", hostName);
remoteHost =gethostbyname(hostName);
memcpy(&addr.S_un.S_addr, remoteHost->h_addr, remoteHost->h_length);
printf("The IP address is: %s\n", inet_ntoa(addr));
But i get a wrong ip address.
Here's complete source code to a little utility I find handy at times (I've named it "resolve"). All it does is resolve a domain name to a numeric IP (v4) address, and print it out. As-is, it's for Windows -- for Linux (or similar) you'd just need to get rid of the use_WSA class (and object thereof).
#include <windows.h>
#include <winsock.h>
#include <iostream>
#include <iterator>
#include <exception>
#include <algorithm>
#include <iomanip>
#include "infix_iterator.h"
class use_WSA {
WSADATA d;
WORD ver;
public:
use_WSA() : ver(MAKEWORD(1,1)) {
if ((WSAStartup(ver, &d)!=0) || (ver != d.wVersion))
throw(std::runtime_error("Error starting Winsock"));
}
~use_WSA() { WSACleanup(); }
};
int main(int argc, char **argv) {
if ( argc < 2 ) {
std::cerr << "Usage: resolve <host-name>";
return EXIT_FAILURE;
}
try {
use_WSA x;
hostent *h = gethostbyname(argv[1]);
unsigned char *addr = reinterpret_cast<unsigned char *>(h->h_addr_list[0]);
std::copy(addr, addr+4, infix_ostream_iterator<unsigned int>(std::cout, "."));
}
catch (std::exception const &exc) {
std::cerr << exc.what() << "\n";
return EXIT_FAILURE;
}
return 0;
}
This also uses the infix_ostream_iterator I've posted previously.

Using select without listen()ing, possible?

I am building a client that:
Should be able to recieve information from both the server and the standart input
Should be able to recieve information from the server without asking, for example when another client sends a message.
To do so I tried using select to monitor both possible inputs.
What happens is that when a keyboard input is monitored I send a message to the client and I expect one back, so there's no problem. But when the server sends an unexpected message nothing happens, and I don't know why. Is using select() the proper way to do so? Is it even possible to use select() without listen()ing?
Here's my code (compileable):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <cstring>
#include <arpa/inet.h>
#include <iostream>
#include <fstream>
#define MAX_CLIENT_NAME 30
#define MAX_TWIT_SIZE 140
#define NUM_OF_ARG 4
#define ERROR -1
#define GREAT_SUCCESS 0
#define OK "OK"
#define EXIT "EXIT"
using std::string;
using std::cerr;
using std::endl;
using std::cout;
string clientName;
int srverfd, numbytes, status, maxSock ;
fd_set inputFdSet; /* Socket file descriptors we want to wake
up for, using select() */
int establishConnection(char * serverAddress,char * port){
if ((srverfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
return ERROR;
}
struct sockaddr_in server;
server.sin_family = AF_INET;
inet_aton(serverAddress, &server.sin_addr);
server.sin_port = htons(atoi(port));
memset(&(server.sin_zero), '\0', 8);
if (connect(srverfd,(const struct sockaddr *)&server,sizeof(struct sockaddr)) == -1) {
perror("connect");
close(srverfd);
return ERROR;
}
maxSock = srverfd;
return GREAT_SUCCESS;
}
const char * getUserTweet(){
string temp;
getline(std::cin,temp);
return temp.c_str();
}
void sendMessage(string message){
if ((numbytes = send(srverfd, message.c_str(), message.length(), 0)) == -1) {
perror("sendMessage");
close(srverfd);
}
cout<<"Message sent: "<< message << endl;
return;
}
const char * getMessage(){
char buf[MAX_TWIT_SIZE];
memset(buf,'\0',MAX_TWIT_SIZE);
if ((numbytes = recv(srverfd, buf, 140, 0)) == -1) {
perror("getMessage");
close(srverfd);
}
string temp = buf;
return temp.c_str();
}
void build_select_list() {
FD_ZERO(&inputFdSet);
FD_SET(srverfd,&inputFdSet);
FD_SET(STDIN_FILENO,&inputFdSet);
if (STDIN_FILENO > maxSock)
maxSock = STDIN_FILENO;
return;
}
void readSocket(fd_set tempfd) {
const char * tweet, * inMessage;
if (FD_ISSET(srverfd,&tempfd)) {
inMessage = getMessage();
cout << inMessage << endl;
}
if (FD_ISSET(STDIN_FILENO,&tempfd)) {
tweet = getUserTweet();
sendMessage(tweet);
inMessage = getMessage();
if (strcmp(inMessage,OK) != 0) {
cout << inMessage << endl;
}
if (strcmp(inMessage,EXIT) == 0) {
return;
}
}
return;
}
int main (int argc, char *argv[] ){
int value;
bool clientON = false;
if(establishConnection(argv[2],argv[3])){
cerr << "usage: failed to make connection" << endl << "exiting..." << endl;
exit(EXIT_FAILURE);
}
cout << "Connected successfully" << endl;
sendMessage("CONNECT "+clientName); //Connect
if(strcmp(getMessage(),OK) == 0){
clientON = true;
}
while(clientON){
build_select_list();
value = select(maxSock, &inputFdSet, NULL, NULL, NULL);
if (value < 0) {
perror("select");
exit(EXIT_FAILURE);
}
if (value == 0) {
continue;
}
else {
readSocket(inputFdSet);
}
}
sendMessage("DISCONNECT");
if(strcmp(getMessage(),OK) == 0){
// do nothing
}
close(srverfd);
return 0;
}
Your select call is invalid. The first parameter must be the highest file descriptor in any of the sets, plus one.
As you have it, an event on srverfd will not "wake up" the select call (unless STDIN_FILENO was somehow less than srverfd, in which case stdin events wouldn't unlock select - but that won't happen in practice).
There are quite a few other problems with your code. (It doesn't really look like C++.)
getUserTweet is unreliable (undefined behavior - temp is destroyed as soon as the function returns, so the char* you return has disappeared by the time its caller will try to use it). Same for getMessage. To remedy that, use std::string everywhere, and only extract the char* when you call into C library functions).
readSocket needlessly copies the FD set (can be expensive).
You should really get rid of all those globals - build one or two classes to encapsulate that state and the networking functions, or something like that.