shell scripting "expect"ing various responses from ssh - linux

So I have a shell script which sshs into a machine, then using expect passes a password via expect and then runs a matlab script. The problem is I would like to do this for a whole range of machines on the network and if it's one that's I've not connected before asking me for a password it tells me that it can't authenticate the machine as asks me if I want to connect and awaits a yes\no response.
I want my shell script to be able to handle situations where it just asks for the password and where it also manages to deal with the yes\no. I don't know how to go about doing this with "expect" as when it doesn't receive what it expects it just hangs.
Also for some reason my additional code to handle the yes no response doesn't work when testing it with machines I know I haven't logged in with. This is format with which they reply.
"The authenticity of host 'seven (128.40.41.89)' can't be established.
RSA key fingerprint is d6:9d:d0:61:5f:bb:36:9a:74:2c:f6:b9:a7:79:03:98.
Are you sure you want to continue connecting (yes/no)?"
And this is my code which for some reason doesn't work with my addition, but works fine with just the "assword:" bit which I found on stack exchange. I can see the terminal and it asks the yes\no question, but then my script doesn't respond. I'm guessing I'm somehow using the expect wrong, but I have no idea how.
#!/bin/sh
ssh seven
expect "(yes\no)? "
send "yes\r"
expect "assword:"
send "my password goes here\r"
matlab -nodisplay -nojvm -nosplash -nodesktop -r \
"try, run('\path\matlab_script.m'), catch me, fprintf('%s / %s \n',me.identifier,me.message), end, exit"

One possible workaround is running ssh with StrictHostKeyChecking set to no:
ssh seven -o StrictHostKeyChecking=no
This will autimatically add unknown host keys to the list of known hosts.

Related

From Windows, use Expect and plink to execute standard commands on remote Linux machine

I want to connect to a distant Linux machine trough ssh (with primary key and passphrase) and execute commands on that remote machine. The goal is to make some recurrent tasks faster.
I use plink (putty link) to connect with SSH and TCL (with Expect installed) to send commands to my linux server.
But nothing works! When I execute the following script, nothing happens. Not an error, not a line, nothing. Just the word "begin" until the timeout expires.
But if I write "plink sessionName" in the console directly I have the response of the linux server, I can enter my passphrase and control the remote machine.
package require Expect
exp_send "begin\n"
exp_spawn plink sessionName
exp_send "end\n"
expect "Using username \root\".\nPassphrase for key \"imported-openssh-key\": "
Thank you in advance for helping me :)

Telnet to login with username and password to mail Server

I am having some issues trying to connect through telnet to a mail server.The main problem that I am having is that I need to create a script that logs me to the destination and I can't find a way to echo the password.
What I tried:
telnet host -l username ; echo 'password'
And still it asks for my password.Is there any way to fix this or I am doing something wrong?
First of all, you can use eval:
eval "{ echo user_name; sleep 1; echo pass; sleep 1; echo '?'; sleep 5; }" | telnet host_address
Make sure to replace user_name, pass, ? which is the command you want to run and host_address where your telnet host is listening; for me it is a local IP.
It’s surprisingly easy to script a set of command and pipe them into the telnet application. All you need to do is something like this:
(echo commandname;echo anothercommand) | telnet host_address
The only problem is the nagging login that you have to get through… it doesn’t show up right away. So if you pipe in an “echo admin” and then “echo password,” it will happen too quickly and won’t be sent to the server. The solution? Use the sleep command!
Adding in a couple of sleep 3 commands, to wait three seconds, solves the problem. First we’ll echo the username and password, and then we’ll echo the reboot command, and each time we’ll wait three seconds between. The final command will reboot the server immediately:
(sleep 3;echo admin;sleep 3;echo mypassword;sleep 3;echo system reboot;sleep 3;) | telnet host_address
You can put this into a shell script and run it whenever you want. Or you can add it to your cron like this (on OS X or Linux):
crontab -e
Add this line somewhere:
1 7 * * * (sleep 3;echo admin;sleep 3;echo mypassword;sleep 3;echo system reboot;sleep 3;) | telnet host_address
This will reboot your router at 7:01 AM each morning.
AFAIK, you won't be able to automate telnet that way. But it is still possible - even if it is a very bad idea (I'll elaborate on that later).
First why does your try fail :
you launched a telnet command reading from stdin (I suppose terminal) and writing to stdout and stderr (I suppose also a terminal)
if your telnet is reasonably recent, it tries to protect your authentication and asks your password from /dev/tty (for security reasons)
when that command has ended you write password on your own terminal
What should you do instead :
launch telnet with automatic authentication disable (on mine it is telnet -X SRA)
feed its input with the commands you want to pass
wait some delay before entering input, at least for login and password, because if you don't telnet clear input before reading and discards your inputs
Here is an example that allowed me to telnet to my own machine :
sh << EOF | telnet -X SRA localhost
sleep 2
echo my_user_name
sleep 1
echo my_password
# sleep 1 # looks like it can be removed
echo echo foo and bar
sleep 1
EOF
It correctly logs me into my box, executes echo foo and bar (essential command :-) ) and disconnects
Now why you should never do that :
you write a password in clear text in a script file which is poor security practice
you use telnet to do batch processing when it is not intended to be used that way : the script may not be portable to another telnet version
If you really want to pass command in a batch way to a remote server, you should instead try to use ssh which :
has options to process authentication securely (no password in script, nothing in clear text)
is intended to be used in batch mode as well as interactively
If you cannot use ssh (some sysadmin do not like to have uncontrolled input ssh connections) you could also try to use rsh. It is older, far less secure, but at least was designed for batch usage.
Thanks to Harvix answer, I got knew that there is also expect alternative native for shell, called sexpect. Get it from here. Then create this script (I call it telnetpass):
#!/bin/bash
# This script is used for automatically pass authentication by username and password in telnet prompt
# Its goal is similar as sshpass, but for telnet, so I call it telnetpass
. ~/.private/cisco_pw # should contain PASSWORD variable
export SEXPECT_SOCKFILE=/tmp/sexpect-telnetpass-$$.sock
sexpect spawn telnet $1
sexpect expect -cstring 'Username:'
sexpect send -enter $USER
sexpect expect -cstring 'Password:'
sexpect send -enter $PASSWORD
sexpect interact
Then you can run: telnetpass Host125 and got pass the authentication automatically
Trying 198.51.100.78 ...
Connected to Host125.
Escape character is '^]'.
User Access Verification
Username: ashark
Password:
host-125>
I like this solution more than using sleep commands as suggested in another answers, because sleep solutions sometimes fail.
Have you tried using the expect command ?? You will have to create a script where you identify the 'expected' response from the server e.g. 'Password:' and then supply the password in the script. The following will explain: https://en.wikipedia.org/wiki/Expect - A good example is also shown here: http://en.kioskea.net/faq/4736-shell-script-for-telnet-and-run-commands
Try eval:
eval "{ echo;
sleep 3;
echo $user;
sleep 1;
echo $pass;
sleep 1;
echo '?';
sleep 1; }" | telnet your_host
In this example, my remote command is '?' (help).
The sleeps (maybe not all of them nor these times; trial-error...) are needed to avoid telnet misses some inputs.
The user and password are passed as variables ($user and $pass). Take into account security recommendations to store the password if you are scripting.

ssh without key and collect the output using bash script

I want to create a bash script that will login to all the linux servers in my network using ssh and collect the output of 'uptime' command to a local file. There is no keypair installed between these local server and the remote servers. So I need to give the password (username and password is same for all the remote servers) in the script itself. I know this is not a secure way to do it, but it is just for learning purpose. I see 'expect' command can be used for the ssh login with password but confused how to use it together with the 'uptime' command that provide the server status. So my requirement is
1. I have local server test1 which contains a text file 'server_status.txt'
2. I need a script in test1 that will try to login to all the remote servers (say 192.168.0.1 to 192.168.0.50) using the same username and password. It will execute the command 'uptime' once logged in to the remote servers and store the output to the local file 'server_status.txt'
REVOKE: paste your public key into the server's /path2userthatshouldlogon/.ssh/authorized_keys and run the your commands remotely using ssh user#host commandtoexecute
due to connection wanted to be established without key.
UPDATE: have a look at sshpass if you really want to need passwords, which is NOT RECOMMENDED
Note: Doing this is poor practice. If you are testing around with this then you are learning a bad habit. Don't do this in production on servers you care about.
You'll want to execute the expect call as a $? and be sure to store the $USER and $SERVER variables or just replace them:
uptime=$(expect -c 'spawn ssh $USER#$SERVER send "uptime"; exit;')
echo $uptime

Cannot use expect in Bash script

In my bash script file, I try to use expect to provide password for ssh command but it doesn't work. Here is my script:
#!/bin/bash
/usr/bin/expect << EOD
spawn ssh root#192.168.1.201
expect "root#192.168.1.201's password:"
send "mypassword\r"
interact
expect eof
EOD
And the output after I execute the script:
[oracle#BTMVNSRV191 Desktop]$ ./login.sh
spawn ssh root#192.168.1.201
root#192.168.1.201's password: [oracle#BTMVNSRV191 Desktop]$
Could someone let me know, how to use expect in my script without changing #!/bin/bash to #!/usr/bin/expect?
The following works as a single line of bash script in OS X Terminal. It was only intended for use on a firewall protected LAN. Further details at my original post.
expect -c 'spawn ssh -o StrictHostKeyChecking=no remote-user#remote-IP;
expect assword; send remote-password\r; expect remote-user$;
send "sudo shutdown -h +1\r"; expect assword; send remote-password\r; interact'
ssh (and any other password reading tool) reads its password not from its standard input. It uses some tricky ioctl()-s on its terminal device. This is because you can't give them your password in a pipe.
It is not really a big problem, because widely used cleartext passwords caused more harm as if sometimes we need to find some alternative, password-less solution.
In cases of the ssh, there is a very simple thing for that. Google for ssh-keygen. I suggest to use that, configure a passwordless ssh and everything will be fine.

expect script + expect miss the send string + delay issue

I write the active.ksh script (based on expect) in order to login automatically to some Solaris machine and execute the hostname command (login to virtual IP in order to verify which hostname is the active machine - I have two cluster solaris machines )
The problem is with expect; expect sends the password string (pass123) and it misses the Password question, and it still waits for the password.
So actually the password (pass123) was entered after password question. On most cases the expect script works fine but sometimes it missed the password.
EXAMPLE OF THE PROBLEM
./active.ksh
spawn ssh 10.10.18.61
sh: /usr/local/bin/stty: not found
This computer system, including all related equipment, networks and network devices (specifically including Internet access),is provided only for authorized uss
Password: * my remark - pass123 string was missed the Password Question pass123
Password:
THE SCRIPT
more active.ksh
#!/bin/ksh
VIP_ADDRESS=10.10.18.61
expect_for_verify_which_active_machine=`cat << EOF
set timeout -1
spawn ssh $VIP_ADDRESS
expect {
")?" { send "yes\r" ; exp_continue }
Password: {send "pass123\r"}
}
expect > {send "hostname\r"}
expect > {send exit\r}
expect eof
EOF`
expect -c "$expect_for_verify_which_active_machine"
EXAMPLE OF RIGHT RESULTS
./active.ksh
[Friday, February 24, 2012 2:32:06 PM IST] INFO Verify which is active SMU machine
spawn ssh 10.10.18.61
sh: /usr/local/bin/stty: not found
This computer system, including all related equipment, networks and network devices (specifically including Internet access),is provided only for authorized uss
yes
Password:
Last login: Fri Feb 24 14:32:06 2012 from smu1a
This computer system, including all related equipment, networks and network devices (specifically including Internet access),is provided only for authorized uss
solaris1:/ ROOT > hostname
solaris1
solaris1:/ ROOT > exit
logout
Connection to 10.10.18.61 closed.
Maybe it will be easier to script this process using empty. It's a small utility similar to expect but more convenient in some cases. You can use it to just "type text into an application", and you can ignore the application's prompts (though you don't have to). Logging to a remote machine and executing hostname could look like this:
./empty -f -L templog ssh 10.10.18.61 hostname
echo YOUR_SECRET_PASSWORD | ./empty -s -c
cat templog
The first one starts your command in the background. The other one sends it data (your password) from stdin. The whole session (including passwords!) is logged to file templog where you will find also the result of hostname. There are also mechanisms for finer-grained control, but they may be a bit harder to set up.
As some people already pointed out, ssh keys are the way to go, this is just an ugly and unsafe workaround (it's risky due to shell history being preserved, users being able to see your password in ps results, and in my example the password is additionally saved in the templog file etc).

Resources