How do you pass serveral passwords in SCP using expect? - passwords

My purpose is control transferring files between two remote machines. If I could use key-pair it would be much easier but I can't choose the options but passing passwords.
Environments : Local(Mac), Remote_source(Linux), Remote_target(Linux)
Here it is my expect.sh. When I run it, source#source's password: pops up, then target#target's password: and nothing else. No files transferred, no stdout, no error message, just disconnected.
#!/usr/bin/expect
set timeout -1
spawn scp -3 scp://remote_source_user#host:port/home/source/test.txt scp://remote_target_user#host:port/home/target/
expect "remote_source_user#host's password:"
send "SOURCE_PASSWORD\r"
expect "remote_target_user#host's password:"
send "TARGET_PASSWORD\r"
expect eof
When I change the sequence the password (meaning send target password first rather than sending source password first.) it occurs error, so I guess it is working but I have got no idea what is going on internally.
I have tried sshpass but it is not working with several passwords.

I debugged it with -v flag and found out that Connection works perfectly but the problem is the directory.
# in debugging mode
Sink: scp: home/username/test.txt: No such file or directory
It seems not recognizing /home/username/test.txt at the beginning.
so the code should be like below:
#!/usr/bin/expect
set timeout -1
spawn scp -3 scp://remote_source_user#host:port/~/test.txt scp://remote_target_user#host:port/~/
expect "remote_source_user#host's password:"
send "SOURCE_PASSWORD\r"
expect "remote_target_user#host's password:"
send "TARGET_PASSWORD\r"
expect eof
Do not explicitly write your home directory /home/username/ but use /~/.
# The Result
debug1: Sending command: scp -v -r -f ~/test.txt
Sending file modes: C0000 00 test.txt
Sink: C0000 00 test.txt

Related

Expect script not working and terminal closes immediately

I don't know what's wrong with the script. I set up a new profile on Iterm terminal to run the script, but it never works and closes immediately. Here's the script:
#!/usr/bin/expect -f
set timeout 120
set secret mysecret
set username asdf
set host {123.456.789.010}
set password password123
log_user 0
spawn oathtool --totp --base32 $secret
expect -re \\d+
sleep 400
set otp $expect_out(0,string)
spawn ssh -2 $username#$host
expect "*assword:*"
send "$password\n"
expect "Enter Google Authenticator code:"
send "$otp\n"
interact
First, test you ssh connection with:
ssh -v <auser>#<apassword>
That will validate the SSH session works.
Make sure to not use ssh -T ..., since you might need a terminal for expect commands to work.
Second, add at least an echo at the beginning of the script, to see if it is called:
puts "Script running\r"
Third, see if a bash script, with part of it using expect as in here, would work better in this case

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

Expect echo password in clear text

Automating psftp with bash/expect in cygwin.
I have a very minimal script file yftp.exp with code:
#!/usr/bin/expect -f
spawn psftp unixftpsrvr
expect "login as: "
send "myID\r"
expect "Password:"
send "Passw0rd\r"
expect "psftp>"
the output:
$ ./yftp.exp
spawn psftp unixftpsrvr
login as: myID
Using keyboard-interactive authentication.
Enter your UDS
Password: Passw0rd
Remote working directory is /home/myID
psftp>
The password is printed out as clear text!!!
if I run the command directly with psftp. here are the output:
$ psftp unixftpsrvr
login as: myID
Enter your UDS Password:
Remote working directory is /home/myID
psftp>
The password is not displayed at all.
This seems to be more an issue on the expect side.
I am not concerned the password in clear text in my expect script file, I am concerned the password in clear text in the output!
how can I supress the display of password in clear text?
The password may be sent too early before ECHO is turned off. So try adding sleep 1 after expect "Password:".
If that does not work then try like this:
expect "Password:"
log_user 0; # disable logging to stdout
send "password\r"
log_user 1

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.

Forwarding signal to remote child from local parent over ssh

I have a script which executes remote command and redirect output to local file.
Remote command just reads list of pcap files continuously and writes to stdout.
The final command is like this -
ssh root#host /sbin/path-to-utility | cat > local-file
The script which executes this remote command needs to have signal handler to save the state of overall transfer.
Also I want to send signal to remote command or process to stop reading pcap files, so that exit after finishing writing current file.
I tried -t option and signal handling works perfectly fine, but it adds some extra characters to the actual output written by remote command and disturbs my pcap data.
Either I need to handle signal without -t option over ssh or I need to find out why ssh -t is adding additional bytes to actual data.
Please help!
Thanks,
Sachin.
The -t option tells ssh to allocate a terminal. The extra characters are intended to be interpreted by your terminal.
Perhaps then you should tell ssh you are using a different terminal, one that will not generate any extra characters, but will still pass on signals. Does this work?
TERM=dumb ssh root#host /sbin/path-to-utility | cat > local-file
(I don't know what would be the best value to use for TERM.)