expect command - Unix - linux

I am using 'expect' to automate ssh password authentication. When I run the script in SunOS, I find the spawned ssh process gets killed once the below script is completed. This is not the case in Linux. How do we avoid it? Should we ignore the SIGCHLD signal somehow?
Is there anyway to determine through this script if spawned process is successful and report error if any?
#!/usr/local/bin/expect -f
set password blah-blah
spawn ssh -NfL 8002:<test domain>:22 test#testdomain.com
expect "* password:*"
send -- "$password\r"
send -- "\r"
expect EOF
-Karthik

If you use ssh-keys, you won't need to code passwords in shell scripts.
You could even encrypt the key with a passphrase, and use ssh-agent to manage the key for you -- you unlock your key in the morning, start your tunnel, and then forget your key when you head to lunch, unlock your key in the afternoon, and forget it again when you go home at night. No on-disk magic gateway to remote machines.

Instead of putting the ssh command in the background you could put the expect script into the background:
#!/usr/local/bin/expect -f
if {[fork] != 0} exit
disconnect
set password blah-blah
spawn ssh -NL 8002:localhost:22 test#testdomain.com
expect {
EOF {exit 1}
"assword:" {}
}
send -- "$password\n"
send -- "\n"
expect EOF
wait
Works for me on Linux. At least for the setup phase, stopping it is more difficult. I had to kill -9 to stop the expect script. Which probably requires killing the ssh process as well.

Related

Connect via ssh and run a program after a switch user

I want to create inside a bash script a funcion that connects via ssh to another server (using rsa keys), do a switch user (inserting the password), start a program and then exit with the exit code of the program started.
Below a test I'm doing:
#! /usr/bin/expect
set timeout 120
spawn ssh user1#10.211.55.24
expect ".*user1"
sleep 3
send "whoami\r"
send "/bin/su hdfs\r"
expect "*?assword:"
send "hdfs\r"
expect "$"
send "whomai\r"
send "exit\r"
It works until the switch user, I can switch to the hdfs user but the following commands are not sent (whomai). The $ prompt is correct. Furthermore I'm not able to get the exit code of the command (in this example echo command).

shell scripting "expect"ing various responses from ssh

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.

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.

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.

How to automate telnet session using Expect?

I'm trying to write an expect script to automate telnet. This is what I have so far.
#!/usr/bin/expect
# Test expect script to telnet.
spawn telnet 10.62.136.252
expect "foobox login:"
send "foo1\r"
expect "Password:"
send "foo2\r"
send "echo HELLO WORLD\r"
# end of expect script.
Basically, what I want to do is telnet to the following IP address and then echo HELLO WORLD. However, it seems that the script fails after attempting to telnet...I'm not sure if it's able to accept login and password input, but it is not echoing HELLO WORLD. Instead, I just get this output:
cheungj#sfgpws30:~/justin> ./hpuxrama
spawn telnet 10.62.136.252
Trying 10.62.136.252...
Connected to 10.62.136.252.
Escape character is '^]'.
Welcome to openSUSE 11.1 - Kernel 2.6.27.7-9-pae (7).
foobox login: foo1
Password: foo2~/justin>
It's hard to tell, but from the output you're pasting it looks like:
Your script isn't waiting for login to complete before sending the next command.
Your script is exiting and closing the process before you can see any output.
There are no guarantees in life, but I'd try this as a first step:
#!/usr/bin/expect -f
spawn telnet 10.62.136.252
expect "foobox login:"
send "foo1\r"
expect "Password:"
send "foo2\r"
# Wait for a prompt. Adjust as needed to match the expected prompt.
expect "justin>"
send "echo HELLO WORLD\r"
# Wait 5 seconds before exiting script and closing all processes.
sleep 5
Alternatives
If you can't get your script to work by manually programming it, try the autoexpect script that comes with Expect. You can perform your commands manually, and autoexpect will generate an Expect typescript based on those commands, which you can then edit as needed.
It's a good way to find out what Expect actually sees, especially in cases where the problem is hard to pin down. It's saves me a lot of debugging time over the years, and is definitely worth a try if the solution above doesn't work for you.
You're sending the echo command without first expecting the prompt. Try:
# after sending the password
expect -re "> ?$"
send "echo HELLO WORLD\r"
expect eof
Have you seen this StackOverflow Question?
He seems to have got things working by using curly braces.
Here is a simplified version
#!/usr/bin/expect
# just do a chmod 755 one the script
# ./YOUR_SCRIPT_NAME.sh $YOUHOST $PORT
# if you get "Escape character is '^]'" as the output it means got connected otherwise it has failed
set ip [lindex $argv 0]
set port [lindex $argv 1]
set timeout 5
spawn telnet $ip $port
expect "'^]'."

Resources