Ssh command from Qt - c++

I have a problem with ssh in my Qt application. I need to run a command which removes a file on a remote server. I tried to use a QProcess class to achieve it. So I pass "ssh" as a name of command and necessary args. In common it looks like this:
QStringList params;
params.append(" user#" + ::host +
" \"rm /tmp/" + ::fileName + "\"");
d->impDelProcess->start("ssh", params);
But after all it keeps asking a password, though I generated ssh keys and copied a public key to the remote server. Moreover, when I run the command above in the terminal like this:
ssh user#host "rm /path/fileName"
it works perfect. The file is deleted and no password is asked. So, the problem is somwhere in QProcess. Is any way to get rid of asking a password? Thank you!

Those are separate arguments, when you use string list. Try this:
params.append("user#" + ::host");
params.append("rm /tmp/" + ::fileName);
That will make Qt pass two arguments for ssh, the login string and the command to execute at remote host.
Important note! Above assumes ::filename does not contain spaces or anything else nasty!. You can get around spaces with this:
params.append("rm '/tmp/" + ::fileName + "'");
But it won't help against wild cards or .. in path... Imagine if file name was ../home/user/* for example... So that is better be trusted input, or you need to sanitize it (but that is beyond scope of this answer).
What you do in the question code is to construct a single argument, equivalent to this shell command line:
ssh 'user#host "rm /path/filename"'

Related

Qt5 QProcess handling arguments with "special" characters

I'm maintaining a Qt5 program that uses QProcess to execute ncftpget on Linux.
The command that I'm attempting to execute is:
ncftpget -E -Z -u username -p 'a#$b1379' 1.1.1.1 /x/y/temp/ update/file
Which simply transfers a file from a server into a local directory. If I execute the above command on the bash command line it works properly.
However, when my Qt5 application executes the same command using QProcess the ftp server replies saying the username/password is not correct. When the password doesn't contain any "special" characters it works properly.
As mentioned by S.M. QProcess isn't executing the command in a shell. So I'm assuming fork() and some version of the exec() call is made. How do I make QProcess do the correct thing here?
I'm assuming that the problem has do to with the special character(s) in the password. When I build my QProcess argument list I specifically make sure the password is surrounded by ' so that the special characters are escaped.
Code snippet:
processFTP.setParent(this->parent());
processFTP.setProcessChannelMode(QProcess::MergedChannels);
// ncftpArgs is a QStringList
// snippet doesn't show complete argument list
ncftpArgs->push_back("-Z");
ncftpArgs->push_back("-u");//username
ncftpArgs->push_back(QString((*phashSettings)[FTPUSERNAME]));
ncftpArgs->push_back("-p");//pw
// password can have special characters when shell executes command.
QString password((*phashSettings)[FTPPASSWORD]);
password.prepend("'");
password.append("'");
ncftpArgs->push_back(password);
ncftpArgs->push_back(QString((*phashSettings)[FTPSERVERIP]));
ncftpArgs->push_back(QString((*phashSettings)[FTPTEMPDIR]));
//beging the ncftpget session
QString sExe = "ncftpget"; //process name
// processFTP is a QProcess object
processFTP.start(sExe, (*ncftpArgs));
bSuccess = processFTP.waitForStarted();
// .... more code to monitor process etc...
The code logs the command and arguments that will passed to processFTP and everything looks correct.
How do I properly set up the arguments and start the QProcess object so that the password argument containing the special characters are properly passed to the executable ncftpget?
And/or how do I go about debugging the problem?
When I build my QProcess argument list I specifically make sure the password is surrounded by ' so that the special characters are escaped.
Do not append or prepend the password with ', remove these lines
password.prepend("'");
password.append("'");
QProcess::start is responsible for proper way of program arguments passing. Besides bash interpreter is not run by this call in your code.

ssh remote login to server using system(char * command), and excute commands?

Someone familiar with SSH and System(const char * command) to execute shell command!??
Am trying to remotely login to multiple servers/machines from my C++ code, and i have to execute some commands remotely. To the best of my experience, i decided to use ssh. But, now i want to load and send all my commands through the System(const char * command). pls see my code below..
#include "all my headers"
int main()
{
system("ssh 172.10.10.1");//login to server_one, password=123
system("ssh 172.10.10.2");//login to server_two, password=1234
system("ssh 172.10.10.3");//login to server_three,password=12345
system("ssh 172.10.10.4");//login to server_four, password=123456
return 0;
}
Now,my Question is:
can i load and send the remote_ip of the servers and password at the
same time, something like: system("ssh 172.10.10.4 ,123456")
password=123456? if yes, how?
if am done with (1) above, i will have another question. thanks.
Calling system("ssh ...") will ONLY work if you have set up public keys for the machine you want to log in on.
The reason is that the system() does not allow you to interact with the process you started, it will just spawn a new shell and pass the relevant string to the shell for execution, and ssh does not itself have a way to pass the password to the application, you have to actually type it in (or send it to the stdin side of ssh if you use popen - but I would really suggest that public keys are the right way to go in an automated system).
If you still need to interact with the created process, you will need to use something like popen, which will allow you to read stdout or write to stdin on the - or even pipe() and fork() if you need the ability to do stuff to both stdin and stdout.

Mkdir over SSH with Python does not work

I'm trying to create a new dir via SSH with a python script. When i try my commands by using the Python command line it just works. But when I try to do the same by a script it does not create the new 'test' folder (I even copy/paste the commands in the script into the Python cmd to verify they are right and there they work). So any ideas why it does not work by script?
The used code:
child = pexpect.spawn('ssh 192.168.56.101 -oStrictHostKeyChecking=no')
child.expect=('password:')
child.sendline('MyPwd')
child.sendline('mkdir /home/myUser/Desktop/test')
Seems to work when I just add another line
for example
child.sendline('\n')
so the entire script is
child = pexpect.spawn('ssh 192.168.56.101 -oStrictHostKeyChecking=no')
child.expect=('password:')
child.sendline('MyPwd')
child.sendline('mkdir /home/myUser/Desktop/test')
child.sendline('\n')
What I usually do to solve this issue is sync-ing with host machine. After I send something to the machine, I expect an answer, which usually translates in the machine's prompt. So, in your case, I would go for something like this:
child = pexpect.spawn('ssh 192.168.56.101 -oStrictHostKeyChecking=no')
child.expect('password:')
child.sendline('MyPwd')
child.expect('YourPromptHere')
child.sendline('mkdir /home/myUser/Desktop/test')
child.expect('YourPromptHere')
You can just replace YourPromptHere with the prompt of the machine, if you are running the script on a single target, or with a regular expression (eg. "(\$ )|(# )|(> )").
tl;dr : To summarize what I said, you need to wait until the previous action was finished until sending a new one.

popen and system behaves unexpectedly with multiple quoted file paths

I am trying to execute a dos command from within my C++ program, however soon as I add quotes to the output filepath (of a redirection) the command no longer gets executed and returns instantly. I've shown an example below of a path without spaces, but since paths may have spaces and thus be quoted for the shell to understand it properly I need to solve this dilemma - and I'm trying to get the simplest case working first.
i.e.
The following WORKS:
sprintf(exec_cmd,"\"C:/MySQL Server 5.5/bin/mysqldump.exe\" -u%s -p%s %s > C:/backup.bak",user,password,db_name);
system(exec_cmd);
The following does NOT work (notice the quotes around the output):
sprintf(exec_cmd,"\"C:/MySQL Server 5.5/bin/mysqldump.exe\" -u%s -p%s %s > \"C:/backup.bak\"",user,password,db_name);
system(exec_cmd);
I'm guessing it is choking somewhere. I've tried the same "exec_cmd" in popen to no avail.
Any help/advice is greatly appreciated.
I don't think your shell (cmd.exe) allows redirection to a file name with spaces. I couldn't make my command.com from DOS 6.22 accept it (I don't have a cmd.exe nearby to test).
Anyway, you can use the --result-file option to pass the redirection to the command itself.
mysqldump ... --result-file="file name" ...

linux expect command

I am using the linux 'expect' to automate passwords.
#!/usr/bin/expect
set password passwd
spawn scp * root#ip_address:.
expect "password:"
send "$password\r"
expect eof
output :
spawn scp * root#ip_address:.
root#ip_address's password: *: No such file or directory
Looks like the regular expression '*' is not recognized. I know of the ssh-key gen method to set up keys but 'expect' command is more suitable for my specific case.
* is not a valid regular expression, and in the context you're using it, it would be a wildcard. The spawn will interpret it literally and pass it as an argument to the program you're starting.
If you want the asterisk globbed, you'll have to get a shell to do it for you:
spawn sh -c "scp * root#foo"