diff options
Diffstat (limited to 'bin/clogin')
-rwxr-xr-x | bin/clogin | 181 |
1 files changed, 109 insertions, 72 deletions
@@ -7,7 +7,7 @@ ## This software may be freely copied, modified and redistributed without ## fee for non-commerical purposes provided that this copyright notice is ## preserved intact on all copies and modified copies. -## +## ## There is no warranty or other guarantee of fitness of this software. ## It is provided solely "as is". The author(s) disclaim(s) all ## responsibility and liability with respect to this software's usage @@ -29,8 +29,8 @@ # Usage line set usage "Usage: $argv0 \[-u user\] \[-p user-password\] \[-v vty-password\] \ \[-w enable-username\] \[-e enable-password\] \[-noenable\] \ -\[-f cloginrc-file\] \[-c command\] \[-s script-file\] \[-autoenable\] \ -\[-t timeout\] router \[router...\]\n" +\[-f cloginrc-file\] \[-y ssh_cypher_type\] \[-c command\] \[-s script-file\] \ +\[-x command-file\] \[-autoenable\] \[-t timeout\] router \[router...\]\n" # env(CLOGIN) may contain: # x == do not set xterm banner or name @@ -53,8 +53,8 @@ set do_enapasswd 1 if {[ info exists env(CISCO_USER) ] } { set default_user $env(CISCO_USER) } else { - # This uses "id" which I think is portable. At least it has existed - # (without options) on all machines/OSes I've been on recently - + # This uses "id" which I think is portable. At least it has existed + # (without options) on all machines/OSes I've been on recently - # unlike whoami or id -nu. regexp {\(([^)]*)} [exec id] junk default_user } @@ -125,6 +125,13 @@ for {set i 0} {$i < $argc} {incr i} { exit 1 } set do_script 1 + # cypher type + } -y* - + -Y* { + if {! [ regexp .\[eE\](.+) $arg ignore cypher]} { + incr i + set cypher [ lindex $argv $i ] + } # alternate cloginrc file } -f* - -F* { @@ -136,17 +143,17 @@ for {set i 0} {$i < $argc} {incr i} { -T* { incr i set timeout [ lindex $argv $i ] - } -x* - - -X { - if {! [ regexp .\[xX\](.+) $arg ignore cmd_file]} { - incr i - set cmd_file [ lindex $argv $i ] - } - set cmd_fd [open $cmd_file r] - set cmd_text [read $cmd_fd] - close $cmd_fd - set command [join [split $cmd_text \n] \;] - set do_command 1 + } -x* - + -X { + if {! [ regexp .\[xX\](.+) $arg ignore cmd_file]} { + incr i + set cmd_file [ lindex $argv $i ] + } + set cmd_fd [open $cmd_file r] + set cmd_text [read $cmd_fd] + close $cmd_fd + set command [join [split $cmd_text \n] \;] + set do_command 1 # Do we enable? } -noenable { set enable 0 @@ -192,20 +199,20 @@ proc label { host } { if [regexp \^(xterm|vs) $env(TERM) ignore ] { send_user "\033]1;[lindex [split $host "."] 0]\a" send_user "\033]2;$host\a" - } + } } } # This is a helper function to make the password file easier to # maintain. Using this the password file has the form: -# add password sl* pete cow -# add password at* steve +# add password sl* pete cow +# add password at* steve # add password * hanky-pie -proc add {var args} { global $var ;lappend $var $args} +proc add {var args} { global $var ;lappend $var $args} proc find {var router} { - source_password_file - upvar $var list - if { [info exists list] } { + source_password_file + upvar $var list + if { [info exists list] } { foreach line $list { if { [string match [lindex $line 0] $router ] } { return [lrange $line 1 end] @@ -219,11 +226,11 @@ proc find {var router} { # it is sourced, the user better know what to put in there, as it # could install more than just password info... I will assume however, # that a "bad guy" could just as easy put such code in the clogin -# script, so I will leave .cloginrc as just an extention of that script +# script, so I will leave .cloginrc as just an extention of that script proc source_password_file { } { global env password_file read_password_file if { [info exists read_password_file] } { return } - if { [info exists password_file] == 0 } { + if { [info exists password_file] == 0 } { set password_file $env(HOME)/.cloginrc } set read_password_file 1 @@ -236,9 +243,10 @@ proc source_password_file { } { } # Log into the router. -proc login { router user userpswd passwd enapasswd prompt } { +proc login { router user userpswd passwd enapasswd prompt cyphertype } { global spawn_id in_proc do_command do_script set in_proc 1 + set tryssh 1 # Telnet to the router & try to login. if [ catch {spawn telnet $router} reason ] { @@ -253,19 +261,19 @@ proc login { router user userpswd passwd enapasswd prompt } { send_user "\nError: TIMEOUT reached\n" close; wait if { $in_proc} { - return 1 + return 1 } else { - continue + continue } - } eof { + } eof { send_user "\nError: EOF received\n" close; wait if { $in_proc} { - return 1 + return 1 } else { - continue + continue } - } + } } # Here we get a little tricky. There are several possibilities: @@ -274,12 +282,24 @@ proc login { router user userpswd passwd enapasswd prompt } { # TACACS server is not working, then it will use the enable # passwd. Or, the router might not have TACACS turned on, # then it will just send the passwd. + # if telnet fails with connection refused, try ssh expect { - eof { send_user "Error: Couldn't login\n"; wait; return 1 } - "Connection refused" { - expect eof - send_user "Error: Connection Refused\n"; wait; return 1 - } "Unknown host\r\n" { + "Connection refused" { + close; wait + if { $tryssh } { + if [ catch {spawn ssh -c $cyphertype -x -l $user $router} reason ] { + send_user "Error: failed to ssh: $reason\n" + exit 1 + } + set tryssh 0 + sleep 0.3 + exp_continue + } else { + expect eof + send_user "Error: Connection Refused\n"; wait; return 1 + } + } eof { send_user "Error: Couldn't login\n"; wait; return 1 + } "Unknown host\r\n" { expect eof send_user "Error: Unknown host\n"; wait; return 1 } "Host is unreachable" { @@ -289,32 +309,40 @@ proc login { router user userpswd passwd enapasswd prompt } { expect eof send_user "Error: Unknown host\n"; wait; return 1 } + -re "Host key not found .* \(yes\/no\)\?" { + send "yes\r" + send_user "Host $router added to the list of known hosts.\n" + exp_continue } + -re "HOST IDENTIFICATION HAS CHANGED.* \(yes\/no\)\?" { + send "no\r" + send_user "Error: The host key for $router has changed. update the known_hosts file accordingly.\n" + return 1 } -re "(Username|login):" { send "$user\r" - expect { - eof { send_user "Error: Couldn't login\n"; wait; return 1 } + expect { + eof { send_user "Error: Couldn't login\n"; wait; return 1 } -re "\[Pp]assword:" { send "$userpswd\r" } "$prompt" { set in_proc 0; return 0 } } exp_continue } - "Password:" { send "$passwd\r" - expect { - eof { send_user "Error: Couldn't login\n"; wait; return 1 } + "\[Pp]assword:" { send "$passwd\r" + expect { + eof { send_user "Error: Couldn't login\n"; wait; return 1 } "Password:" { send "$enapasswd\r" } - "$prompt" { set in_proc 0; return 0 } + "$prompt" { set in_proc 0; return 0 } } exp_continue } - "$prompt" { } - denied { send_user "Error: Check your passwd for $router\n" - if { $do_command || $do_script } { + "$prompt" { } + denied { send_user "Error: Check your passwd for $router\n" + if { $do_command || $do_script } { send "quit" wait return 1 } else { return 1 } - } + } "% Bad passwords" {send_user "Error: Check your passwd for $router\n"; return 1 } } set in_proc 0 @@ -358,17 +386,17 @@ proc run_commands { prompt command } { for {set i 0} {$i < $num_commands} { incr i} { send "[subst [lindex $commands $i]]\r" expect { - -re "^\[^\n\r]*$prompt." { exp_continue } + -re "^\[^\n\r]*$prompt." { exp_continue } -re "^\[^\n\r *]*$prompt" {} - "\n" { exp_continue } - } + -re "\[\n\r]" { exp_continue } + } } } else { send "[subst $command]\r" expect { -re "^\[^\n\r]*$prompt." { exp_continue } -re "^\[^\n\r *]*$prompt" {} - "\n" { exp_continue } + -re "\[\n\r]" { exp_continue } } } send "exit\r" @@ -410,49 +438,58 @@ foreach router [lrange $argv $i end] { if { $do_passwd || $do_enapasswd } { set pswd [find password $router] if { [llength $pswd] == 0 } { - send_user "Error - no password for $router in $password_file.\n" - continue - } - if { $do_enapasswd && !$autoenable && [llength $pswd] < 2 } { + send_user "Error - no password for $router in $password_file.\n" + continue + } + if { $do_enapasswd && $autoenable == 0 && [llength $pswd] < 2 } { send_user "Error - no enable password for $router in $password_file.\n" - continue + continue } - set passwd [lindex $pswd 0] - set enapasswd [lindex $pswd 1] + set passwd [lindex $pswd 0] + set enapasswd [lindex $pswd 1] } # Figure out username - if {[info exists username]} { + if {[info exists username]} { # command line username set ruser $username } else { - set ruser [find user $router] + set ruser [find user $router] if { "$ruser" == "" } { set ruser $default_user } - } + } # Figure out username's password (if different from the vty password) if {[info exists userpasswd]} { # command line username set userpswd $userpasswd } else { - set userpswd [find userpassword $router] - if { "$userpswd" == "" } { set userpswd $passwd } - } - + set userpswd [find userpassword $router] + if { "$userpswd" == "" } { set userpswd $passwd } + } + # Figure out enable username - if {[info exists enausername]} { + if {[info exists enausername]} { # command line enausername set enauser $enausername } else { - set enauser [find enauser $router] - if { "$enauser" == "" } { set enauser $ruser } - } + set enauser [find enauser $router] + if { "$enauser" == "" } { set enauser $ruser } + } + + # Figure out cypher tpye + if {[info exists cypher]} { + # command line cypher type + set cyphertype $cypher + } else { + set cyphertype [find cyphertype $router] + if { "$cyphertype" == "" } { set cyphertype "3des" } + } # Login to the router - if {[login $router $ruser $userpswd $passwd $enapasswd $prompt]} { + if {[login $router $ruser $userpswd $passwd $enapasswd $prompt $cyphertype]} { continue } - if { $enable } { + if { $enable } { if {[do_enable $enauser $enapasswd]} { if { $do_command || $do_script } { close; wait @@ -471,7 +508,7 @@ foreach router [lrange $argv $i end] { source $sfile close } else { - label $router + label $router log_user 1 interact } |