expect command ssh sudo error
Hello. First time posting. I have written an expect command to ssh and sudo to a server and run a command.
I must write this code to allow for any variances or errors from the user (Ex, no ssh keys, no passwordless sudo, no sudo privileges, account locked out, wrong username, wrong password, invalid hostname, host not reachable, etc.). Basically, I must allow for anything that can go wrong - within reason. The code is working fine with valid and invalid input except for when I setup the user to have password-less sudo "NOPASSWD" in /etc/sudoers. Then I get garbage output which is not what I'm expecting. I have included "send_user" statement for debugging purposes and they will not be included in the final version. Here are the variables I use in my script which are prompted for prior to executing expect. hn="testserver1" sshUser="testuser1" sshPassword="testpassword1" expect –c “ set timeout 2 log_user 0 stty -echo spawn -noecho ssh -q -o NumberOfPasswordPrompts=1 StrictHostKeyChecking=no -o ConnectTimeout=3 \”${hn}\” -l \”${sshUser}\” -t \“/usr/bin/sudo -k ; /usr/bin/sudo ls -ld /root/Desktop 2>/dev/null\” 2>/dev/null # Expect ssh password prompt. expect { -nocase password: { send_user \”ssh password was triggered\” send \”${sshPassword}\” } timeout { send_user \“ssh timout was triggered\” } eof { send_user \“ssh eof was triggered\” } } # Expect sudo password prompt. expect { sudo { send_user \“sudo password was triggered\” send \”${sshpassword}\” } @ { # This never gets executed. Here just in case I ever see the command prompt. # For testing purposes only. send_user \”sudo command prompt found\” } timeout { send_user \“sudo timeout was triggered\” } eof { send_user \“sudo eof was triggered\” } } stty echo interact;” 2>/dev/null # Here is the output I receive with "testuser1 ALL=(ALL) ALL" in /etc/sudoers. [testuser1@testserver1 ~]$ ./expect_script ssh password was triggeredsudo password was triggered drwxr-xr-x 2 root root 4096 Mar 29 10:07 /root/Desktop # Here is the output I receive with "testuser1 ALL=(ALL) NOPASSWD: ALL" in /etc/sudoers. [testuser1@testserver1 ~]$ ./expect_script ssh password was triggeredsudo eof was triggered[testuser1@testserver1 ~]$ Since sudo is not prompting for a password eof is found and the script exits. That is fine but I would expect to see the same output as above. # Here is the same code with error redirection (2>/dev/null), "log_user 0", and "stty -echo" removed. # "testuser1 ALL=(ALL) ALL" in /etc/sudoers [testuser1@testserver1 ~]$ ./expect_script testuser1@testserver1's password: ssh password was triggered [sudo] password for testuser1: sudo password was triggered drwxr-xr-x 2 root root 4096 Mar 29 10:07 /root/Desktop # Here is the same code with error redirection (2>/dev/null), "log_user 0", and "stty -echo" removed. # "testuser1 ALL=(ALL) NOPASSWD: ALL" in /etc/sudoers [testuser1@testserver1 ~]$ ./expect_script testuser1@testserver1's password: ssh password was triggered drwxr-xr-x 2 root root 4096 Mar 29 10:07 /root/Desktop sudo eof was triggeredspawn_id: spawn id exp4 not open while executing "interact" As you can see I receive the output but other errors as well. I cannot simply grep for what I want because any command can be substitued for "ls -ld /root/Desktop". I won't know what to look for. I was reading about the expect buffer but not sure if that is my answer. Any help is appreciated. |
i am very new to the expect/autoexpect (have never liked it for p/w as it puts the p/w in plane text) but from what i have been reading the -c " you have for the expect is incomplete you have either no closing " or you have no command. also please use code/code flags this makes life much simpler when reading code. so example:
for the opening code... [ code ] without the spaces and [ / code ] without the spaces to end: Code:
# echo "Hello world." Code:
The -c flag prefaces a command to be executed before any in the script. Code:
expect –c “ from an other forum i just found, this might help Quote:
Quote:
|
Since you expect a password prompt and the erroneous entry is the one in which you do not require passwords, I'd expect it to be because no password prompt is shown. Ref: http://stackoverflow.com/questions/1...-exp4-not-open
Small tip: add the extra verbose flag to your shebang to debug scripts (at the top): Code:
#!/bin/bash -xv |
Thanks for the tips guys. I think my problem is the linear fashion of my expect statements. After nesting the expect statements and removing the sudo command from the initial ssh session I am getting better results. Basically, I check if ssh failed or not and if successful then I send the sudo command. This way I can control the errors much better. I will post my results probably in a few days if anyone is interested. Thanks for all your help.
|
glad to help, yes i would be interested in your final script.
|
Final script
I was finally able to get a good working version of my script. A little background - I created a script to get the firmware from a server. I setup the script to walk through an IBM Blade Center and grab the hostnames in the description fields so it can ssh to the server and get the firmware levels. I have included some test cases (embedded after expect command) in case anyone else is trying to do this too. I have included the whole bash function I use in my script. In the function, I only care to retrieve the correct result, if it fails I just want it to return nothing. For anyone copying this you can add send_user commands to get output for the errors if you desire.
## Retrieve Chassis Blade Firmware. get_chassis_blade_fw() { export hn_blade=$(snmpwalk -r 10 -Ov -Oq -v $secVersion -u $secName -l $secLevel -a $authProtocol -A $authPassword -x $privProtocol -X $privPassword $hn 1.3.6.1.4.1.2.3.51.2.2.21.5.1.1.5.$1 2>/dev/null | sed 's/"//g') local chassis_blade_fw="" local answer=() export sshUser export sshPassword export prompt="${sshUser}@${hn_blade}" export cmd="/usr/sbin/lsfw ${chassis_blade_options} 2>/dev/null" # Check for conditions. [[ "${hn_blade}" = '(No name)' ]] && chassis_blade_fw="EMPTY" [[ "${hn_blade:0:5}" = "Error" ]] && chassis_blade_fw="N/F" [[ "${hn_blade:0:7}" = "timeout" ]] && chassis_blade_fw="N/F" [[ "${hn_blade:0:8}" = "snmpwalk" ]] && chassis_blade_fw="N/F" [[ "${hn_blade:0:14}" = 'No Such Object' ]] && chassis_blade_fw="N/F" [[ "${hn_blade:0:16}" = 'No Such Instance' ]] && chassis_blade_fw="N/F" [[ -z "${hn_blade}" ]] && chassis_blade_fw="N/F" if [[ "${chassis_blade_fw}" != "EMPTY" && "${chassis_blade_fw}" != "N/F" ]] ; then #### Test cases # Wrong ssh password/username: Returns null. # Invalid username: Returns null. # Host invalid/not reachable: Returns null. # Account locked out: Returns null. # Account requires password change: Returns null. # "Your LDAP password will expire in ? days" message: Failed testing. Don't plan to fix. # Last login message: Filtered by expect. # "There were ? failed login attempts since the last successful login" message: Filtered by expect. # Login banner: Filtered by expect. # ssh_key_exchange failure message:+ (fixed with ssh -q) Returns null. # ssh keys are setup: (fixed with PubkeyAuthentication=no) Works as expected # Wrong sudo password: (N/A since same as ssh pwd and ssh will fail) N/A # No sudo privileges: Returns null # sudo with NOPASSWD: Works as expected # Invalid command: Requires 2>/dev/null in $cmd and returns null #### #### Caveats # Must use short hostname is AMM blade description field. #### chassis_blade_fw=$(/usr/bin/expect -c ' set sshUser $env(sshUser) set sshPassword $env(sshPassword) set hn $env(hn_blade) set prompt $env(prompt) set cmd $env(cmd) #exp_internal 1 set timeout 2 set send_human {.1 .3 1 .05 2} match_max 100000 log_user 0 stty -echo spawn -noecho ssh -q -o PubkeyAuthentication=no -o NumberOfPasswordPrompts=1 -o StrictHostKeyChecking=no -o ConnectTimeout=3 $hn -l $sshUser -t expect { default { exit 1 } -nocase password: { send "$sshPassword\r" } } expect { default { exit 1 } -re ${prompt} { send "/usr/bin/sudo $cmd\r" expect full_buffer { exp_continue } ; # Force all output before continuing. } -re (expired|change) { exit 1 } } expect { default { exit 1 } # Sudo requires password. "password for $sshUser: " { send "$sshPassword\r" expect -indices -re $prompt set sudo_out [string range $expect_out(buffer) 0 [expr $expect_out(0,start) -1]] ; # Retrive only expected output. # Trim garbage output. set sudo_out [string trimleft "$sudo_out" " \r\n"] set sudo_out [string trimright "$sudo_out" "\r\n\u001b\]0\;${prompt}:~\u0007\["] send_user [string trimright "$sudo_out" "\r\n\u001b\]0\;"] exit } # Sudo does not require a password (from sudo grace period or NOPASSWD). -re ".*${cmd}(.*)${prompt}" { set sudo_out $expect_out(1,string) # Trim garbage output. set sudo_out [string trimleft "$sudo_out" " \r\n"] set sudo_out [string trimright "$sudo_out" "\r\n\u001b\]0\;${prompt}:~\u0007\["] send_user [string trimright "$sudo_out" "\r\n\u001b\]0\;"] exit } } stty echo interact;' 2>/dev/null) fi # Check for conditions. [[ -z "${chassis_blade_fw}" ]] && chassis_blade_fw="${hn_blade} (N/R)" # Return results. echo "${chassis_blade_fw}" } # END get_chassis_blade_fw() You may notice most of the test cases were satisfied by ssh options. One problem with this script I need your help on is how do I wait for all the output after sending a command before it starts matching the expect statements? When I send the sudo command it starts matching right away that is why I have the full_buffer line so it will not match and if the sudo command requires a password it will see the prompt. Without full_buffer it will never match the sudo prompt. Thanks. |
Can someone tell me how to keep the formatting in the code? It looks horrible after I hit send.
|
use [ code ] and [ / code ] without the spaces and that will do the trick.
|
All times are GMT -5. The time now is 04:09 AM. |