Wednesday, October 26, 2011

auto SSH using expect

Intro
Expect is a Unix automation and testing tool, written by Don Libes as an extension to the Tcl scripting language, for interactive applications such as telnet, ftp, passwd, fsck, rlogin, tip, ssh, and others. It uses Unix pseudo terminals to wrap up subprocesses transparently, allowing the automation of arbitrary applications that are accessed over a terminal. With Tk, interactive applications can be wrapped in X11 GUIs.

Expect serves as a "glue" to link existing utilities together. The general idea is to try to figure out how to make Expect utilize the system's existing tools rather than figure out how to solve a problem inside of Expect.
A key usage of Expect involves commercial software products. Many of these products provide some type of command-line interface, but these usually lack the power needed to write scripts. They were built to service the users administering the product, but the company often doesn't spend the resources to fully implement a robust scripting language. An Expect script can spawn a shell, look up environmental variables, perform some Unix commands to retrieve more information, and then enter into the product's command-line interface armed with the necessary information to achieve the user's goal. After looking up information inside the product's command-line interface, the script can make an intelligent decision about what action to take, if any.

Heres a working expect TCL script that can be invoke easily from the unix console, very useful when handling alot of multiple unix machine, save the script as ssh.exp.
#!/usr/bin/expect -f
# modified from dearvoid (MSN: dearvoid@263.net) enable-auto-ssh.exp script
set prefix "\033\[1;31m>>>\033\[0m"

proc usage {} {
regsub ".*/" $::argv0 "" name
send_user "Usage:\n"
send_user " $name \[user@]host password\n"
exit 1
}

proc check_id_files {} {
if {! [file exists $::id_file]} {
send_user "$::prefix id file not found, try creating ...\n"
if {[catch { spawn ssh-keygen -t rsa } error]} {
send_error "$::prefix $error\n"
exit 1
}
expect -nocase -re "\(.*\):"
send -- "\r"
expect -nocase -re "passphrase.*:"
send -- "\r"
expect -nocase -re "passphrase.*again:"
send -- "\r"
expect eof
send_user "$::prefix id file successfully created\n"
}
}

proc remove_known_hosts_entry {host} {
regsub ".*/" $::argv0 "" name
set tmp_file "/tmp/$name.tmp"
set known_hosts "$::env(HOME)/.ssh/known_hosts"
send_user "$::prefix trying to remove '$host' from ~/.ssh/known_hosts ... "
if {[catch {
set fd_known_hosts [open $known_hosts r]
set fdTmp [open $tmp_file w]
while 1 {
gets $fd_known_hosts line
if [eof $fd_known_hosts] {
break
}
if [regexp "(\[^, ]+,)*${host}(,\[^, ]+)* " $line] {
continue
}
puts $fdTmp $line
}
close $fd_known_hosts
close $fdTmp
file rename -force $tmp_file $known_hosts
send_user "OK\n"
} error]} {
send_user "failed\n"
send_user "$::prefix $error\n"
exit 1
}
}

set user@host [lindex $argv 0]
set passwd [lindex $argv 1]
set cmd ""
set src ""
set dst ""
set address_pos ""
if {[llength $argv] == 3} {
set cmd [lindex $argv 2]
}
if {[llength $argv] == 5} {
set src [lindex $argv 2]
set dst [lindex $argv 3]
set address_pos [lindex $argv 4]
}


set id_file "$env(HOME)/.ssh/id_rsa.pub"

set yes_no 0
set ok_string SUCCESS
set timeout 66
set done 0
while {!$done} {
spawn ssh ${user@host} echo $ok_string
expect {
-nocase -re "yes/no" {
set yes_no 1
send -- "yes\r"
set done 1
}
-nocase -re "password: " {
set done 1
}
$ok_string {
send_user "$prefix ok\n"
exit 0
}
"@@@@@@@@@@@@@@@@@@@@" {
expect eof
set indexOfAtSign [string first "@" ${user@host}]
incr indexOfAtSign
set hostname [string range ${user@host} $indexOfAtSign end]
remove_known_hosts_entry $hostname
}
eof {
send_error "$prefix failed\n"
exit 1
}
timeout {
send_error "$prefix timeout\n"
exit 16
}
}
}

if {$yes_no} {
expect {
$ok_string {
send_user "$prefix ok\n"
exit 0
}
-nocase -re "password: " {}
}
}
send -- "$passwd\r"
expect {
-nocase "try again" {
send_error "$prefix passwd error\n"

exit 11

}

-nocase "password:" {
send_error "$prefix passwd error\n"

exit 11



}

$ok_string {}
}
expect eof

sleep 1

set timeout 10806

if {[llength $argv] == 3} {
spawn ssh ${user@host} "$cmd"
}
if {[llength $argv] == 5} {
if { $address_pos == "RIGHT"} {
spawn /opt/dms/bin/scp_echo -r "$src" "${user@host}:$dst"
}
if { $address_pos == "LEFT" } {
spawn /opt/dms/bin/scp_echo -r "${user@host}:$src" "$dst"
}
}
expect -nocase -re "password:"
send -- "$passwd\r"

expect {
-nocase -re "--exit code=.*=" {
exit 0
}
timeout {
exit 16
}
}

## END


save the script as ssh.exp, and u can call it from unix console by using.
#ex, getting filelist from remote server : ssh.exp root@192.168.1.2 syafar123 "ls"
ssh.exp {user}@{ip_address} {passwd} "{standard unix command/remote script}"

3 Comment :

HGH Human Growth Hormone said...

Constantly i used to read smaller posts which as well clear their motive, and that is also happening with this paragraph which I am reading at this time.

Atlanta Contract Staffing said...

Nice post. I learn something new and challenging on websites I stumble upon every day.

Unknown said...

Hi. I really enjoyed my brief visit on your site and I’ll be sure to be back for more.
Can you please consider placing my website on your link list?

Please email me back.

Thanks!
Kevin
kevincollins1011 gmail.com