bash script which can ssh to a remote machine and execute commands, throws error when password is incorrect - bash

I'm trying a bash script where i'm taking an argument of a file which has the IP address. I'm using sshpass, but with this i'm not able to know if ssh login was successful or not. Is there a way to check this ?
Please suggest if not sshpass, do i need to use any other cmd, to do remote login and execute cmds ?
Here is the snippet of the code :
#!/bin/bash
filename="$1"
while read -r line; do
sshpass -p 'test' ssh -o StrictHostKeyChecking=no test#$line 'df -h'
done < "$filename"
Have tried the suggested way to check $? value (if its incorrect password, $? value will be 5, however with valid or invalid password, shell script is not echoing 'wrong password', its always echoing "Can ssh to box- Password is correct" as per the following code :
#!/bin/bash
filename="$1"
while read -r line; do
sshpass -p 'test' ssh -o StrictHostKeyChecking=no test#$line 'df -h'
if [ $? -eq 5]
then
echo "Wrong password"
else
echo "Can ssh to box- Password is correct"
fi
done < "$filename"
My Requirement is to ssh to the remote box and execute commands. And in case, ssh fails i.e password is invalid, it need to print that password is invalid.

Use return value from sshpass.
According to man sshpass:
RETURN VALUES
As with any other program, sshpass returns 0 on success. In case of failure, the following return codes are used:
5 Invalid/incorrect password
After running sshpass, in bash return value from command is stored in $? variable.
Proof:
devilan#localhost:~ $ sshpass -p 'test' ssh smurf#localhost
devilan#localhost:~ $ echo $?
5
Sugested usage:
sshpass -p 'test' ssh smurf#localhost
if [ $? -eq 5 ]
then
echo "Wrong password"
else
echo "Something else"
fi

Space was missing after 5, and thus if condition wasn't getting evaluated successfully.
Here is the modified code which works :
filename="$1"
while read -r line; do
sshpass -p 'test' ssh -o StrictHostKeyChecking=no test#$line 'df -h'
if [ $? -eq 5 ]
then
echo "Wrong password"
else
echo "Can ssh to box- Password is correct"
fi
done < "$filename"

Related

While loop in bash script execute only once [duplicate]

This question already has answers here:
bash cycle breaks when calling ssh command in the loop
(2 answers)
Closed 3 months ago.
I have a given shell script:
#!/bin/bash
USERNAME=xenobot
SSH_KEY_LOCATION="~/.ssh/id_rsa"
FILE="server.info"
while read -r server_ip package_type; do
if [[ $package_type == "deb" ]]; then
echo "For $server_ip package type is $package_type"
DPKG_FILE_PATH=$(ls ./src/dpkg/dpkg-*)
DPKG_FILE=$(basename $DPKG_FILE_PATH)
echo "$DPKG_FILE located at $DPKG_FILE_PATH will be transfered via SSH to server"
scp ./src/dpkg/${DPKG_FILE} $USERNAME#$server_ip:/tmp
ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -l ${USERNAME} ${server_ip} "cd /tmp; sudo dpkg -i *.deb"
elif [[ $package_type == "rpm" ]]; then
echo "For $server_ip package type is $package_type"
RPM_FILE_PATH=$(ls ./src/rpm/rpm-*)
RPM_FILE=$(basename $RPM_FILE_PATH)
echo "$RPM_FILE located at $RPM_FILE_PATH will be transfered via SSH to server"
scp -o 'StrictHostKeyChecking no' ./src/rpm/${RPM_FILE} $USERNAME#$server_ip:/tmp
echo "$RPM_FILE has been successfuly transfered to server!"
ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -l ${USERNAME} ${server_ip} "cd /tmp; sudo rpm -ivh --force $RPM_FILE"
fi
done <"$FILE"
And I have following file server.info, from which previous shell script reads:
213.136.80.123 rpm 213.136.91.102 rpm
The problem with it, as it is execute only once from first line, and just stops there without executing the second line
I have tried just to print output from this server.info using the same while read -r and it seems that outputs just fine like this
#!/bin/bash
USERNAME=xenobot
SSH_KEY_LOCATION="~/.ssh/id_rsa"
FILE="server.info"
while read -r server_ip package_type; do
if [[ $package_type == "deb" ]]; then
echo "For $server_ip package type is $package_type"
elif [[ $package_type == "rpm" ]]; then
echo "For $server_ip package type is $package_type"
fi
done <"$FILE"
Output:
213.136.80.123 rpm 213.136.91.102 rpm
So it seems like it outputs two separate lines, however I do not know why it runs script only once in bigger example
Try using a different file descriptor for your list other than 0, 1, or 2 (in this case it's set to 3).
while read -r server_ip package_type <&3; do
...
done 3<"$FILE"
If that works, then what's going on here is that ssh -- being an interactive program -- is sucking up your STDIN input.

How to wait until ssh is available?

I'm trying to code a script which will wait for a server to be up and check if ssh is running.
#!/bin/bash
until [ $(ssh -o BatchMode=yes -o ConnectTimeout=5 root#HOST echo ok 2>&1) = "ok" ]; do
echo "Trying again..."
done
echo "SSH is running"
I have this error if server is power off :
test3: ligne 3 : [: Too many arguments
Trying again...
^C
If server is running it output :
ok
The trivial fix is to put double quotes around the string which might come up empty.
until [ "$(ssh ...)" = "ok" ]; do ...
The Bash-only test [[ is more tolerant, so you could use [[ ... ]] instead of [ ... ] and not have to add quotes.
... but a better solution is to look for the exit status from ssh:
until ssh ...; do ...
If you want the operation to be silent, add a redirection.
until ssh user#hostname true >/dev/null 2>&1; do ...
with whatever additional options you want, of course. You might need to add one or more ssh -t options if it complains about not being connected to a TTY, for example.
Your ssh command is expanding to nothing, or to multiple words; you should quote it (and run Shellcheck on your script):
until [ "$(ssh ... )" = ok ]; do

How to check connection to a list of servers in bash?

Im trying to check connections for a list of servers. I want to loop through the list, check if a connection works and if yes, do some stuff, if not, echo out a problem message.
My problem is:
the script stops at the first node without echoing the $?.
So, whats wrong with my for-loop?
These vars are included from a config file:
$nodes is a list of server IPs like 1.1.1.1,2.2.2.2,10.10.10.10
$user is one string
for node in $(echo $nodes | sed "s/,/ /g")
do
echo "Checking Node: $node"
ssh -q -o ConnectTimeout=3 $user#$node echo ok
echo $?
if [[ $? != 0 ]]
then
echo "Problem in logging into $node"
else
# do some stuff here
fi
done
EDIT #1:
for node in $(echo $nodes | sed "s/,/ /g")
do
echo "Checking Node: $node"
ssh -q -t -o ConnectTimeout=3 $user#$node "echo ok"
retcode=$?
echo $retcode
if [[ "$retcode" -ne 0 ]]
then
echo "Problem in logging into $node"
else
echo "OK"
fi
done
It is because ssh first asks you to validate The authority of the host and If you accept the authority it will ask for password. That is why your command does not return to shell and waits for input.
If your intention is just validating ssh connection, then you may consider to use
telnet <your_host> <port> < /dev/null
But if your intend is to run some commands you need a trust relationship between hosts. In that case you can use:
Execute this commands:
ssh-keygen -t rsa
then
ssh-copy-id -i root#ip_address
Now you can connect with
ssh <user>#<host>
Furher information
You can add -tto make virtual terminal and add quotes on command:
ssh -q -t -o ConnectTimeout=3 ${user}#${node} "echo ok"
Also use -ne instead of != which is for compare strings
if [[ "$?" -ne 0 ]]
Also echo $? mess the return code. You should use something like:
ssh -q -t -o ConnectTimeout=3 ${user}#${node} "echo ok"
retcode=$?
echo $retcode
if [[ "$retcode" -ne 0 ]]
You can rewrite ssh command like this to avoid problems with ssh host keys
ssh -q -t -o StrictHostKeyChecking=no -o ConnectTimeout=3 ${user}#${node} "echo ok"

SSH hot to check remote directory exist

Idea is to check remote folder. Is it exist or no?
I try this
ssh -p 22 -tt user#server.com 'bash -d /home/test22
and it works fine
/home/test22: /home/test22: is a directory
Connection to server.com closed.
But when I try to use it with "IF" - it is wrong...always said "That directory exists"
#!/bin/bash
if [ "ssh -p 22 -tt user#server.com 'bash -d /home/test22'" ]; then
echo "That directory exists"
else
echo "That directory doesn't exists"
fi
Can you show correct example?
Thank you!
The command to use is not bash but test or its alias [:
if ssh -p 22 -tt user#server.com 'test -d /home/test22'; then
echo "That directory exists"
else
echo "That directory doesn't exists"
fi
The other important thing is that [] is not part of the if syntax. if is always followed by a command and if evaluates its exit status. So no need to surround your ssh command with [].
-d dir are actually the arguments of command test or [.
test -d dir
[ -d dir ]
are identical, the latter form requires a closing ] argument.

Checking SSH failure in a script

Hi what is the best way to check to see if SSH fails for whatever reason?
Can I use a IF statement ( if it fails then do something)
I'm using the ssh command in a loop and passing my hosts names form a flat file.
so I do something like:
for i in `cat /tmp/hosts` ; do ssh $i 'hostname;sudo ethtool eth1'; done
I get sometime this error or I just cannot connect
ssh: host1 Temporary failure in name resolution
I want to skip the hosts that I cannot connect to is SSH fails. What is the best way to do this? Is there a runtime error I can trap to bypass the hosts that I cannot ssh into for whatever reason, perhaps ssh is not allowed or I do not have the right password ?
Thanking you in advance
Cheers
To check if there was a problem connecting and/or running the remote command:
if ! ssh host command
then
echo "SSH connection or remote command failed"
fi
To check if there was a problem connecting, regardless of success of the remote command (unless it happens to return status 255, which is rare):
if ssh host command; [ $? -eq 255 ]
then
echo "SSH connection failed"
fi
Applied to your example, this would be:
for i in `cat /tmp/hosts` ;
do
if ! ssh $i 'hostname;sudo ethtool eth1';
then
echo "Connection or remote command on $i failed";
fi
done
You can check the return value that ssh gives you as originally shown here:
How to create a bash script to check the SSH connection?
$ ssh -q user#downhost exit
$ echo $?
255
$ ssh -q user#uphost exit
$ echo $?
0
EDIT - I cheated and used nc
Something like this:
#!/bin/bash
ssh_port_is_open() { nc -z ${1:?hostname} 22 > /dev/null; }
for host in `cat /tmp/hosts` ; do
if ssh_port_is_open $host; then
ssh -o "BatchMode=yes" $i 'hostname; sudo ethtool eth1';
else
echo " $i Down"
fi
done

Resources