I'm now learning Expect to try to automate a check on a remote system under Nagios Core, and while the script runs perfectly from the 'nagios' user account (which is what Nagios runs its commands under), the script errors under a Nagios run. In fact, the script run from the command line worked stright away without much drama - but now I've spent 3 days trying to figure out what's going wrong under Nagios.
I've determined that the CLI version sees the response from the send "aaa test-server... command, but the Nagios run doesn't and just times out. I've written things to the logfile to try to determine what I've done wrong, and I just can't see it. (I've disabled responses back to Nagios because that'll confuse it, but they're seen and used in the script.)
Sequence I'm trying to automate:
nagios:~# ssh accountname#192.168.1.20
accountname#192.168.1.20's password:
Last login: Wed Mar 27 03:43:03 2013 from 192.168.1.14
(Aruba3400) >en
Password:***********
(Aruba3400) #aaa test-server mschapv2 tester account1 password1
Authentication Successful
(Aruba3400) #exit
(Aruba3400) >exitConnection closed by foreign host.
Connection to 192.168.1.20 closed.
Script:
#!/usr/bin/expect
# turn on logging output
log_user 0
log_file /tmp/output.txt
# set Variables
set password SomeThingOrOther
set useracct accountname
set ipaddr 192.168.1.20
set timeout 9
match_max -d 10000
# now connect to remote UNIX box (ipaddr) with given script to execute
spawn -noecho /usr/bin/ssh $useracct#$ipaddr
# Look for password prompt
expect "assword:"
# Send password aka $password
send "$password\n"
# send blank line (\r) to make sure we're at the prompt
expect "Aruba3400"
send "\r"
#send_log "log: 1st password entered.\n"
# Look for password prompt again, send Enable req
expect "Aruba3400"
send "en\r"
expect "assword:"
send "$password\r"
expect "(Aruba3400) #"
# send blank line (\r) to make sure we're at the prompt
send "\r"
expect "#"
send_log "log: Sent auth command.\n"
send "aaa test-server mschapv2 tester account1 password1\r"
# at next line, nagios run times out; command line runs fine
expect -timeout 9 "Successful"
# printout some debugs to logs whether it works or times out
send_log "log 0: $expect_out(0,string)\n"
send_log "log x: $expect_out(buffer)\n"
#---stock exit here so I can see some output, fix it later----
set TIME [exec date +%H:%M:%S]
log_user 1
send_user "Time: $TIME\n"
send_log "-----------------------\n"
exit 0
Output of logs file:
-----------------------
log: Sent auth command.
log 0: Successful
log x: aaa test-server mschapv2 tester account1 password1
Authentication Successful <-- this is from the cli (works!)
Time: 16:00:02
-----------------------
log: Sent auth command.
log 0: #
log x:
(Aruba3400) # <-- this is under Nagios (timeout)
Time: 16:00:29
-----------------------
Can anyone provide me some clues as to what is going wrong here?
Thanks in advance!!
Related
I have a telnet expect script only used for check if the server is ok.
#!/usr/bin/expect
set IP 192.168.5.100
catch {spawn -noecho telnet $IP}
set timeout 3
expect {
timeout
{ send_user "Telnet timed out waiting for $IP\n" ; exit }
"onnection refused"
{ send_user "Connection was refused to $IP\n" ; exit }
"No route"
{ send_user "System $IP is unknown\n" ; exit}
"login:"
}
send_user "Success\n" ; exit
THis is working perfect and I call it from anothe bash script to store the message into a log file. The problem is that the output have too many information, e.g. in case the server is not reachable:
# ./checkconn.expect
Trying 192.168.5.101...
telnet: connect to address 192.168.5.101: No route to host
System 192.168.5.101 is unknown
In case the server is reachable:
Trying 192.168.5.100...
Connected to 192.168.5.100.
Escape character is '^]'.
--- Unauthorised access prohibited ---
This is a closed-access system. If you do not have permission
to access this system, then log off now. If you remain logged on
you consent to monitoring of your actions.
z1 login: Success
So I would like to store into log ONLY the message sent by expect script, like in the above example "System 192.168.5.101 is unknown"
How can I do this?
Thank you
Lucas
expect utility has proc named log_file to record the logs.
In man expect:
log_file [args] [[-a] file]
If a filename is provided, log_file will record a transcript of the session (beginning at that point) in the file. log_file will stop recording if no argument is given. Any previous log file is
closed.
Instead of a filename, a Tcl file identifier may be provided by using the -open or -leaveopen flags. This is similar to the spawn command. (See spawn for more info.)
The -a flag forces output to be logged that was suppressed by the log_user command.
By default, the log_file command appends to old files rather than truncating them, for the convenience of being able to turn logging off and on multiple times in one session. To truncate files,
use the -noappend flag.
The -info flag causes log_file to return a description of the most recent non-info arguments given.`
You can just use like this:
#!/usr/bin/expect
set IP 192.168.5.100
catch {spawn -noecho telnet $IP}
set timeout 3
log_file your_log_file.log
---
---
---
If your script is executed by entering
./yourscript
then you can use something like the following pipe:
./yourscript | sed -n '/^System.*is unknown$/p' > logfile
Here is my except script:
#!/usr/bin/expect
spawn openvpn --config peter.ovpn
expect -exact "Enter Private Key Password: "
send -- "mypassword\r"
I run it and see OpenVPN ask for my client password. But the script exits, apparently without ever sending the password. When I try with an incorrect password it is the same (no incorrect password message). It is also exactly the same result if I delete the send -- "mypassword\r" line from the end of the expect script.
It's my first expect script so probably my syntax is wrong. Or could it be that OpenVPN is kicking me off for using an expect script to connect?
Your syntax is fine. The problem is the script has no more commands to run after you send the password, so the expect script exits and that kills openvpn.
What do you need to do after you send the password?
If you just need to keep openvpn running, then do this:
#!/usr/bin/expect
spawn openvpn --config peter.ovpn
expect -exact "Enter Private Key Password: "
send -- "mypassword\r"
set timeout -1
expect eof
-1 means "infinite", and expect eof means you are waiting for the spawned process to exit before the expect script can exit.
I have a bunch of linux servers. What I am trying to do is making sure all the servers have the password I want by prompting all the logins change. I am trying to implement it by writing a short bash script which includes the expect command. I am running it over a file which contains the list of IPs.
My file ips.txt contains:
10.195.166.52
10.195.166.54
My "expect" script is:
#!/usr/bin/expect -f
log_file myfile.log ;# <<< === append output to a file
set timeout 180
set username pippo
set old_password 0ldp455w0rd
set new_password n3wp455w0rd
set filedes [open "ips.txt" r]
gets $filedes ip
while {$ip != -1} {
spawn ssh $username#$ip
expect "$username"
send "$old_password\r"
expect "(current)"
send "$old_password\r"
expect "New"
send "$new_password\r"
expect "Retype"
send "$new_password\r"
expect "$username"
send "exit\r"
#expect eof ;#wait for the connection to close
}
close $filedes
What I obtain is:
You are required to change your password immediately (root enforced)
Last login: Thu Jul 19 16:14:46 2018 from 10.222.233.139
WARNING: Your password has expired.
You must change your password now and login again!
Changing password for user pippo.
Changing password for pippo.
(current) UNIX password:
New password:
Retype new password:
passwd: all authentication tokens updated successfully.
Connection to 10.195.166.52 closed.
send: spawn id exp6 not open
while executing
"send "exit\r""
("while" body line 12)
invoked from within
"while {$ip != -1} {
spawn ssh $username#$ip
expect "$username"
send "$old_password\r"
expect "(current)"
send "$old_password\r"
expect "New"
send "$ne..."
(file "./passwd.xp" line 12)
So the script is not proceeding further than the first IP. What is happening ? I am trying variations of the expect commands without success.
Essentially I connect to remote host, authenticate, run command, logout. However logout command is being skipped.
/usr/bin/expect << EOD
spawn ssh $_host
expect "Password: ";
send "$_pass\r";
expect "$_host>";
send "sh arp | inc $_host2\r";
expect "$_host>";
send "logout\r";
EOD
echo "blah blah"
What i get is my expected output from arp command however, blah blah will be entered into the terminal of the remote host. It seems the logout command is being skipped, somewhat new to bash scripting but it seems that expect doesn't instantly see "$_host>" when executing and skips it? Appreciate any feedback.
Don't use expect here at all. Even if you must get the password from a variable, using sshpass for the purpose will avoid mixing two separate languages (bash and TCL).
SSHPASS="$_pass" sshpass -e "$_host" "sh arp | inc $_host2"
I believe the \r ( carrige return ) should be \n ( enter / new line ) ?
send "logout\r"; -> send "logout\n";
If that will help - I would replace it in the entire script ..
Suggesting:
/usr/bin/expect << EOD
match_max 1000000
spawn ssh $_host
expect "Password: ";
send "$_pass\n";
expect "$_host>";
send "sh arp | inc $_host2\n";
expect "$_host>";
send "logout\n";
EOD
echo "blah blah"
Using the following shell code for remote telnet request:
{
sleep 5
echo admin
sleep 3
echo pass
sleep 3
echo ls
sleep 5
echo exit
} | telnet 172.16.1.1
I want to check if telnet connection was successful or not. Trying to use $?:
echo $?
But it always returns "1", even if telnet connection was OK.
Telnet is exceptionally difficult to script in this way, there is a high degree of asynchronicity with the time it takes to establish a connection and for your intended actions to complete. expect was created for exactly this kind of purpose. You launch a program, like telnet, then declare a series of expectations - eg, when 'username: ' is emitted from the program, and an action to trigger (eg: typing in the username).
There are also libraries or wrappers for expect in many languages:
python expect
ruby expect
perl expect
Here is an example that drives telnet to make an HTTP HEAD request:
set timeout 20
spawn telnet localhost 80
expect "Connected to "
send "HEAD / HTTP/1.0\r\n\r\n"
expect "HTTP 200 OK"
Given all of this, I feel I must point out that telnet is considered insecure. Ssh is a much better choice and supports better choices for authentication (eg: public/private key auth), restrictions for commands that can be run (via .ssh/authorized_keys). With ssh, and ssh-keys set up, your script reduces to a single shell command:
ssh user#hostname ls
ssh has great support for safe, secure remote command execution.
If I'm remembering correctly, this expect script does what you're doing above.
#!/usr/bin/expect
spawn telnet 172.16.1.1
expect username:
send admin
expect password:
send pass
expect "\$ "
send ls
expect "\$ "
send exit
Here's a useful link for getting started: http://oreilly.com/catalog/expect/chapter/ch03.html