Respond y(es) to psftp host key prompt - ssh

I am creating a script file programmatically and call psftp.exe as follows:
psftp user#hostname.com -pw password -b psftpscript.txt
but it prompts for user input
The server's host key is not cached in the registry. You have no
guarantee that the server is the computer you think it is. The
server's rsa2 key fingerprint is: [ssh-rsa 1024 somekey]
If you trust this
host, enter "y" to add the key to PuTTY's cache and carry on
connecting. If you want to carry on connecting just once, without
adding the key to the cache, enter "n". If you do not trust this host,
press Return to abandon the connection. Store key in cache? (y/n)
I need it to be completely prompt free, automatic.
I tried -batch parameter but it just abandons the connection

I had the same problem with running a unattended script in Windows Server 2008's 'sandbox' like environment. I ended up running the following which enters the y at the prompt for you:
echo y | psftp user#hostname.com -l username -pw password -b psftpscript.txt
Hope this helps!
Note: I only had to run the echo y once and removing it for the 2nd run didn't ask for the key to be cached anymore.

When you run it the first time, it will show you your key for the server.
Copy the key and then on your command line, specify your host key like this:
psftp example.com -hostkey 06:15:d4:3b:e4:e8:23:c0:d6:6d:45:47:7e:bd:8d:74 -l yourusername -pw yourpassword -batch

You can create a file as input containing just a y and carriage return then run
psftp user#hostname.com -pw password -b psftpscript.txt < filename.txt
Thanks to James from http://www.sqlservercentral.com/Forums/Topic281954-9-1.aspx for such a simple solution

This doesn't answer your question directly, but provides a possible workaround:
Launch a command prompt as the user who will be running your script and manually accept the certificate. Then upon future connections, you won't have the issue.
Given your need, beyond what has been stated, this may or may not work. I came to this question with the same problem and ended up resolving it using the approach I've just described.

In .Net, I found that the above method didn't work quite as expected. The trick was to use .Net's built-in input redirection - and not the < operator. Here's what the code looks like now:
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.EnableRaisingEvents = false;
proc.StartInfo.FileName = "c:\\psftp.exe";
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardInput = true;
proc.StartInfo.Arguments = strIP + " -v -l " + strUsername + " -pw " + strPassword + " -b " + strBatchFilename;
proc.Start();
StreamWriter myStreamWriter = proc.StandardInput;
myStreamWriter.WriteLine("Y\n"); //override the public key question <---
myStreamWriter.Close();
proc.WaitForExit();
proc.Close();

I had the problem where I didn't have the permission to delete \ rename file over the remote server and the files contains time stamp.
So I needed to download files by name.
The psftp can't accept params (or any way I was aware of) and I couldn't dynamically change the file names according to the current date.
So, from the batch file which I'm calling the psftp commands I created the commands dynamically and with the file with the relevant time stamp.
I could copy only the today files which is better the then copy everything each time.
cd "C:\Files"
echo cd outbound > C:\SFTP\temp.txt
echo mget file_%date:~10,4%%date:~4,2%%date:~7,2%*.csv >> C:\SFTP\temp.txt
echo quit >> C:\SFTP\temp.txt
echo close >> C:\SFTP\temp.txt
C:\SFTP\psftp user#ftp.address.com -b C:\SFTP\temp.txt
close
exit
The "echo cd outbound > C:\SFTP\temp.txt" cleaned the old file and start writing the content of the new file.
The "echo mget file_%date:~10,4%%date:~4,2%%date:~7,2%.csv >> C:\SFTP\temp.txt" resulted in creating the the command: "mget file_20151008.csv " which downloads all files which starts with "file_20151008..." the next 2 rows just ended the action and the line "C:\SFTP\psftp user#ftp.address.com -b C:\SFTP\temp.txt" execute it.
as results temp.txt looks like this:
cd outbound
mget file_20151008*.csv
quit
close

I ended up adding the key to cache by entering 'y' to the prompt. I had to do it only once, and after that no more prompts, it works good.

I think it should also be noted that if you are intending to use psftp in an unattended manner that you MUST include the -batch option. This will ensure that psftp does not provide any interactive prompts.
In the event user input would be required, psftp would abort. (e.g. ask user to cache host key, ask for password, etc.)
This will ensure that your process doesn't 'hang' and allow your automation to alert someone that there is an issue.

I think there is a problem with your command line.
Usage: psftp [options] [user#]host
Try:
psftp -pw password -b psftpscript.txt user#hostname.com

None of the above suggestions worked for me, but I did figure out something that DID work for me.
I made 2 entries in my batch file for it to work.
The first entry causes a connection to cache in the registry.
The second entry will connect automatically because now the hostkey is cached in the registry.
echo y | psftp.exe username#hostname.com -pw password
psftp.exe username#hostname.com -pw password -v -be -batch -b psftp_upload_command.bat

Related

Robot Framework - SSH library - Editing a file on remote server

I am writing a test case in Robot Framework where in, I have to either copy the file from the local machine (windows) to the remote server (linux) or create a new one at the location.
I have used multiple sudo su - command to switch users to root user to reach the desired host. As a result of this, I am not able to use Put File Keyword from SSH Library to upload the file. I have reached at the desired folder location by executing the commands with Write keyword.
Since there is no option left (thats what i realize with my limited knowledge on Robot Framework), i started creating a new file with vi <filename> command. I have also reached the INSERT mode of the file, BUT i am not able to edit text into the file.
Can someone please suggest me how can i either
Copy the file from local windows machine to remote linux server AFTER multiple SU commands (Switch User)
Create a new text file and enter the content.
Please See : the new file which is being created / copied is a certificate file. Hence i do not wish to write the entire content of the certificate in my test suite file
The entire test case looks something like this
First Jump1
Log Starting the connection to AWS VM
# Connection to VM with Public Key
Connection To VM ${hostname} ${username}
Send Command sudo su -
Send Command su - <ServiceUser1>
# Reached the Detination server
Send Command whoami
Send Command ss -tln | grep 127.0.0.1:40
# Connecting to Particular ZIP
Send Command sudo -u <ServiceUser2> /usr/bin/ssh <ServiceUser2>#localhost -p <port>
Send Command sudo su -
# Check Auth Certificate
Send Command mosquitto_pub -h ${mq_host} -p ${mq_port} -u ${mq_username} -P ${mq_password}
In the step Check Auth Certificate, the certificate is checked to be present or not, if present -> delete the current certificate and create the new one (either create a new file or upload from local) and if it not there create a new certificate
though it might not be ideal, but was able to achieve what i wanted to do with
echo "content" > newFilename
echo "update content" >> newFileName

How to check SSH credentials are working or not

I have a large number of devices around 300
I have different creds to them
SSH CREDS, API CREDS
So as I cannot manually SSH to all those devices and check the creds are working or not
I am thinking of writing a script and pass the device IP's to the script and which gives me as yes as a result if the SSH creds are working and NO if not working.
I am new to all this stuff! details will be appreciated!
I will run this script on a server from where I can ssh to all the devices.
Your question isn't clear as to what sort of credentials you use for connecting to each host: do all hosts have the same connection method, for instance?
Let's assume that you use ssh's authorised keys method to log in to each host (i.e. you have a public key on each host within the ~/.ssh/authorized_keys file). You can run ssh with a do nothing command against each host and look at the exit code to see if the connection was successful.
HOST=1.2.3.4
ssh -i /path/to/my/private.key user#${HOST} true > /dev/null 2>&1
if [ $? -ne 0]; then echo "Error, could not connect to ${HOST}"; fi
Now it's just a case of wrapping this in some form of loop where you cycle through each host (and choose the right key for each host, perhaps you could name each private key after the name or IP address of the target host). The script will go out all those hosts for which a connection was not possible. Note that this script assumes that true is available on the target host, otherwise you could use ls or similar. We pipe all output to /dev/null/ as we're only interested in the ability to connect.
EDIT IN RESPONSE TO OP CLARIFICATION:
I'd strongly recommend not using username/password for login, as the username and password will likely be held in your script somewhere, or even in your shell history, if you run the command from the command line. If you must do this, then you could use expect or sshpass, as detailed here: https://srvfail.com/how-to-provide-ssh-password-inside-a-script-or-oneliner/
The ssh command shown does not spawn a shell, it literally logs in to the remote server, executes the command true (or ls, etc), then exits. You can use the return code ($? in bash) to check whether the command executed correctly. My example shows it printing out an error message for non-zero return codes, but to print out YES on successful connection, you could do this:
if [ $? -eq 0]; then echo "${HOST}: YES"; fi

How to do remote ssh non-interactively

I am trying to connect to a remote host from my local host through the below command.But there was a setting in the remote host that soon after we login it will prompt to enter a badge ID,password and reason for logging in, because it was coded like that in profile file on remote-host How can I overcome those steps and login directly non-interactively, without disturbing the code in profile.
jsmith#local-host$ ssh -t -t generic_userID#remote-host
Enter your badgeID, < exit > to abort:
Enter your password for <badgeID> :
Enter a one line justification for your interactive login to generic_userID
Small amendment: to overcome remote server expect approach is required, but in case local script connects to bunch of remote servers, which configuration may be broken, just use SSH options:
ssh -f -q -o BatchMode=yes -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null USER#TARGETSYSTEM
This will omit ask for password in case there is no ssh_key setup, exit silently and continue with script/other hosts.
Puts ssh to background with -f, which is required when calling ssh command from sh (batch) file to remove local console redirect to remote input (implies -n).
Look into setting up a wrapper script around expect. This should do exactly what you're looking for.
Here are a few examples you can work from.
I have upvoted Marvin Pinto's answer because there is every reason to script this, in case there are other features in the profile that you need, such as Message of the Day motd.
However, there is a quick and dirty alternative if you don't want to make a script and you don't want other features from the profile. Depending on your preferred shell on the remote host, you can insist that the shell bypasses the profile files. For example, if bash is available on the remote host, you can invoke it with:
ssh -t -t generic_userID#remote-host bash --noprofile
I tested the above on the macOS 10.13 version of OpenSSH. Normally the command at the end of the ssh invocation is run non-interactively, but the -t flag allows bash to start an interactive shell.
Details are in the Start-up files section of the Bash Reference Manual.

how to ssh / su - by passing the password initially itself?

Anyone knows how to ssh / su - by passing the password initially itself?
Like:
ssh username#hostname -p [password]
pbrun su - unix_owner -p [password]
How can I achieve this?
It shouldn't popup for password or any RSA authentication like yes/no.
I think you will probably need a sudoers file to get stuff done in a su like manner without being prompted for a password.
I have never used ssh without a password prompt, but found this which suggests it can be done...
passing a password in clear text is not intended by ssh.
Try to learn about ssh key authentication (google would help), you won't need to type your password anymore.
ok, more detailed, try this:
on the remote machine
> mkdir -p ~/.ssh #if neccessary
> touch ~/.ssh/authorized_keys2
> chmod go-rwx $HOME/.ssh/authorized_keys2
on your local machine:
> ssh-keygen # if neccessary
> cat ~/.ssh/id_rsa.pub | ssh root#remotehost "cat >> .ssh/authorized_keys2 && chmod 0600 ~/.ssh/authorized_keys2"
A better approach would be using ssh keys, like other answers recommend, but if you really need it, you can use expect for that.
Just create a expect.file like this one:
#!/usr/bin/env expect
set username youruser
set pass yourpassword
set host yourhost
spawn ssh ${username}#${host}
expect -re "password:"
send "${pass}\r"
expect -re "$"
interact
and execute it:
expect expect.file
Can't do it. You're invoking the passwd program on the remote machine. If it had a way to change a password without prompting for the old one, ANYONE could change your password if they got onto your console. You'd still need to pass the password in over the ssh link
As for SSH, you could use RSA keys, and those won't prompt you for passwords.
As for SU, it would have to be hardcoded or you would have to create your own application to serve as a wrapper of sorts.
I don't think you can pass in password directly to the ssh command (It will be stored in your history otherwise). Why don't you use keys to skip the authentication prompt.

How to make ssh receive the password from stdin

How can you make SSH read the password from stdin, which it doesn't do by default?
based on this post you can do:
Create a command which open a ssh session using SSH_ASKPASS (seek SSH_ASKPASS on man ssh)
$ cat > ssh_session <<EOF
export SSH_ASKPASS="/path/to/script_returning_pass"
setsid ssh "your_user"#"your_host"
EOF
NOTE: To avoid ssh to try to ask on tty we use setsid
Create a script which returns your password (note echo "echo)
$ echo "echo your_ssh_password" > /path/to/script_returning_pass
Make them executable
$ chmod +x ssh_session
$ chmod +x /path/to/script_returning_pass
try it
$ ./ssh_session
Keep in mind that ssh stands for secure shell, and if you store your user, host and password in plain text files you are misleading the tool an creating a possible security gap
You can use sshpass which is for example in the offical debian repositories. Example:
$ apt-get install sshpass
$ sshpass -p 'password' ssh username#server
You can't with most SSH clients. You can work around it with by using SSH API's, like Paramiko for Python. Be careful not to overrule all security policies.
Distilling this answer leaves a simple and generic script:
#!/bin/bash
[[ $1 =~ password: ]] && cat || SSH_ASKPASS="$0" DISPLAY=nothing:0 exec setsid "$#"
Save it as pass, do a chmod +x pass and then use it like this:
$ echo mypass | pass ssh user#host ...
If its first argument contains password: then it passes its input to its output (cat) otherwise it launches whatver was presented after setting itself as the SSH_ASKPASS program.
When ssh encounters both SSH_ASKPASS AND DISPLAY set, it will launch the program referred to by SSH_ASKPASS, passing it the prompt user#host's password:
An old post reviving...
I found this one while looking for a solution to the exact same problem, I found something and I hope someone will one day find it useful:
Install ssh-askpass program (apt-get, yum ...)
Set the SSH_ASKPASS variable (export SSH_ASKPASS=/usr/bin/ssh-askpass)
From a terminal open a new ssh connection without an undefined TERMINAL variable (setsid ssh user#host)
This looks simple enough to be secure but did not check yet (just using in a local secure context).
Here we are.
FreeBSD mailing list recommends the expect library.
If you need a programmatic ssh login, you really ought to be using public key logins, however -- obviously there are a lot fewer security holes this way as compared to using an external library to pass a password through stdin.
a better sshpass alternative is :
https://github.com/clarkwang/passh
I got problems with sshpass, if ssh server is not added to my known_hosts sshpass will not show me any message, passh do not have this problem.
I'm not sure the reason you need this functionality but it seems you can get this behavior with ssh-keygen.
It allows you to login to a server without using a password by having a private RSA key on your computer and a public RSA key on the server.
http://www.linuxproblem.org/art_9.html