diff options
Diffstat (limited to 'bin/clogin.in')
-rw-r--r-- | bin/clogin.in | 208 |
1 files changed, 163 insertions, 45 deletions
diff --git a/bin/clogin.in b/bin/clogin.in index b05b56e..b7ac1a2 100644 --- a/bin/clogin.in +++ b/bin/clogin.in @@ -1,8 +1,9 @@ #! @EXPECT_PATH@ -- ## -## $Id: clogin.in,v 1.72 2004/01/11 05:39:15 heas Exp $ +## $Id: clogin.in,v 1.107 2006/12/08 21:28:25 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -47,7 +48,7 @@ set password_file $env(HOME)/.cloginrc set do_command 0 set do_script 0 # The default is to automatically enable -set enable 1 +set avenable 1 # The default is that you login non-enabled (tacacs can have you login already # enabled) set avautoenable 0 @@ -55,11 +56,11 @@ set avautoenable 0 # tracks if we receive them on the command line. set do_passwd 1 set do_enapasswd 1 -# attempt at platform switching. -set platform "" +# +set send_human {.4 .4 .7 .3 5} # Find the user in the ENV, or use the unix userid. -if {[ info exists env(CISCO_USER) ] } { +if {[ info exists env(CISCO_USER) ]} { set default_user $env(CISCO_USER) } elseif {[ info exists env(USER) ]} { set default_user $env(USER) @@ -75,6 +76,9 @@ if {[ info exists env(CISCO_USER) ] } { } regexp {\(([^)]*)} "$reason" junk default_user } +if {[ info exists env(CLOGINRC) ]} { + set password_file $env(CLOGINRC) +} # Sometimes routers take awhile to answer (the default is 10 sec) set timeout 45 @@ -100,13 +104,16 @@ for {set i 0} {$i < $argc} {incr i} { } set do_passwd 0 # VTY Password - } -v* - - -v* { + } -v* { if {! [ regexp .\[vV\](.+) $arg ignore passwd]} { incr i set passwd [ lindex $argv $i ] } set do_passwd 0 + # Version string + } -V* { + send_user "@PACKAGE@ @VERSION@\n" + exit 0 # Enable Username } -w* - -W* { @@ -189,11 +196,11 @@ for {set i 0} {$i < $argc} {incr i} { set do_command 1 # Do we enable? } -noenable { - set enable 0 + set avenable 0 # Does tacacs automatically enable us? } -autoenable { set avautoenable 1 - set enable 0 + set avenable 0 } -* { send_user "\nError: Unknown argument! $arg\n" send_user $usage @@ -286,6 +293,7 @@ proc source_password_file { password_file } { } # Log into the router. +# returns: 0 on success, 1 on failure, -1 if rsh was used successfully proc login { router user userpswd passwd enapasswd cmethod cyphertype } { global spawn_id in_proc do_command do_script platform global prompt u_prompt p_prompt e_prompt sshcmd usercmd usercmd_chat @@ -295,6 +303,7 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype } { # try each of the connection methods in $cmethod until one is successful set progs [llength $cmethod] foreach prog [lrange $cmethod 0 end] { + incr progs -1 if [string match "telnet*" $prog] { regexp {telnet(:([^[:space:]]+))*} $prog command suffix port if {"$port" == ""} { @@ -304,12 +313,19 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype } { } if { $retval } { send_user "\nError: telnet failed: $reason\n" - exit 1 + return 1 } - } elseif ![string compare $prog "ssh"] { - if [ catch {spawn $sshcmd -c $cyphertype -x -l $user $router} reason ] { + } elseif [string match "ssh*" $prog] { + regexp {ssh(:([^[:space:]]+))*} $prog command suffix port + if {"$port" == ""} { + set retval [ catch {spawn $sshcmd -c $cyphertype -x -l $user $router} reason ] + + } else { + set retval [ catch {spawn $sshcmd -c $cyphertype -x -l $user -p $port $router} reason ] + } + if { $retval } { send_user "\nError: $sshcmd failed: $reason\n" - exit 1 + return 1 } } elseif [string match "usercmd" $prog] { # user supplies connect cmd set retval [ catch {eval spawn $usercmd} reason ] @@ -328,15 +344,83 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype } { } } } elseif ![string compare $prog "rsh"] { - if [ catch {spawn rsh -l $user $router} reason ] { - send_user "\nError: rsh failed: $reason\n" - exit 1 + global command + + if { ! $do_command } { + if { [llength $cmethod] == 1 } { + send_user "\nError: rsh is an invalid method for -x and " + send_user "interactive logins\n" + } + if { $progs == 0 } { + return 1 + } + continue; + } + + set commands [split $command \;] + set num_commands [llength $commands] + set rshfail 0 + for {set i 0} {$i < $num_commands && !$rshfail} { incr i} { + log_user 0 + set retval [ catch {spawn rsh $user@$router [lindex $commands $i] } reason ] + if { $retval } { + send_user "\nError: rsh failed: $reason\n" + log_user 1; return 1 + } + send_user "$router# [lindex $commands $i]\n" + + # rcmd does not get a pager and no prompts, so we just have to + # look for failures & lines. + expect { + "Connection refused" { catch {close}; wait; + send_user "\nError: Connection\ + Refused ($prog): $router\n" + set rshfail 1 + } + -re "(Connection closed by|Connection to \[^\n\r]+ closed)" { + catch {close}; wait; + send_user "\nError: Connection\ + closed ($prog): $router\n" + set rshfail 1 + } + "Host is unreachable" { catch {close}; wait; + send_user "\nError: Host Unreachable:\ + $router\n" + set rshfail 1 + } + "No address associated with" { + catch {close}; wait; + send_user "\nError: Unknown host\ + $router\n" + set rshfail 1 + } + -re "\b+" { exp_continue } + -re "\[\n\r]+" { send_user -- "$expect_out(buffer)" + exp_continue + } + timeout { catch {close}; wait + send_user "\nError: TIMEOUT reached\n" + set rshfail 1 + } + eof { catch {close}; wait } + } + log_user 1 + } + if { $rshfail } { + if { !$progs } { + return 1 + } else { + continue + } } + # fake the end of the session for rancid. + send_user "$router# exit\n" + # return rsh "success" + return -1 } else { - puts "\nError: unknown connection method: $prog" + send_user "\nError: unknown connection method: $prog\n" return 1 } - incr progs -1 sleep 0.3 # This helps cleanup each expect clause. @@ -419,18 +503,26 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype } { send_user "\nError: Check your passwd for $router\n" return 1 } - -re "^Enter Selection: " { + "Press any key to continue." { + # send_user "Pressing the ANY key\n" + send "\r" + exp_continue + } + -re "Enter Selection: " { # Catalyst 1900s have some lame menu. Enter # K to reach a command-line. send "K\r" - exp_continue; + exp_continue + } + -re "Last login:" { + exp_continue } -re "@\[^\r\n]+ $p_prompt" { - # ssh pwd prompt - sleep 1 - send "$userpswd\r" - exp_continue - } + # ssh pwd prompt + sleep 1 + send "$userpswd\r" + exp_continue + } -re "$u_prompt" { send "$user\r" set uprompt_seen 1 @@ -469,8 +561,8 @@ proc do_enable { enauser enapasswd } { -re "$e_prompt" { send "$enapasswd\r"; exp_continue} "#" { set prompt "#" } "(enable)" { set prompt "> (enable) " } - "denied" { - # % Access denied - from local auth + -re "(denied|Sorry|Incorrect)" { + # % Access denied - from local auth and poss. others send_user "\nError: Check your Enable passwd\n"; return 1 } @@ -501,6 +593,9 @@ proc run_commands { prompt command } { if { [ string compare "extreme" "$platform" ] } { if [ regexp -- ".*> .*enable" "$prompt" ] { send "set length 0\r" + # This is ugly, but reduces code duplication, allowing the + # subsequent expects to handle everything as normal. + set command "set logging session disable;$command" } else { send "term length 0\r" } @@ -508,7 +603,7 @@ proc run_commands { prompt command } { regsub -all {[)(]} $prompt {\\&} reprompt # match cisco config mode prompts too, such as router(config-if)#, # but catalyst does not change in this fashion. - regsub -all {^(.{1,14}).*([#>])$} $reprompt {\1([^#>\r\n]+)?[#>](\\([^)\\r\\n]+\\))?} reprompt + regsub -all {^(.{1,11}).*([#>])$} $reprompt {\1([^#>\r\n]+)?[#>](\\([^)\\r\\n]+\\))?} reprompt expect { -re $reprompt {} -re "\[\n\r]+" { exp_continue } @@ -534,6 +629,9 @@ proc run_commands { prompt command } { } -re "^\[^\n\r]*$reprompt." { send_user -- "$expect_out(buffer)" exp_continue } + -re "^--More--\r\n" { # specific match c1900 pager + send " " + exp_continue } -re "\[\n\r]+" { send_user -- "$expect_out(buffer)" exp_continue } -re "\[^\r\n]*Press <SPACE> to cont\[^\r\n]*" { @@ -544,7 +642,7 @@ proc run_commands { prompt command } { } exp_continue } - -re "^ --More--\[^\n\r]*" { + -re "^ *--More--\[^\n\r]*" { send " " exp_continue } -re "^<-+ More -+>\[^\n\r]*" { @@ -564,6 +662,9 @@ proc run_commands { prompt command } { } -re "^\[^\n\r]*$reprompt." { send_user -- "$expect_out(buffer)" exp_continue } + -re "^--More--\r\n" { # specific match c1900 pager + send " " + exp_continue } -re "\[\n\r]+" { send_user -- "$expect_out(buffer)" exp_continue } -re "\[^\r\n]*Press <SPACE> to cont\[^\r\n]*" { @@ -574,7 +675,7 @@ proc run_commands { prompt command } { } exp_continue } - -re "^ --More--\[^\n\r]*" { + -re "^ *--More--\[^\n\r]*" { send " " exp_continue } -re "^<-+ More -+>\[^\n\r]*" { @@ -586,24 +687,34 @@ proc run_commands { prompt command } { log_user 1 if { [ string compare "extreme" "$platform" ] } { - send "exit\r" + send -h "exit\r" } else { - send "quit\r" + send -h "quit\r" } expect { -re "^\[^\n\r *]*$reprompt" { # the Cisco CE and Jnx ERX # return to non-enabled mode # on exit in enabled mode. - send "exit\r" + send -h "exit\r" exp_continue; } + "Would you like to save them now" { # Force10 + send "n\r" + exp_continue + } + "Configuration changes have occurred.*" { # Cisco CSS + send "n\r" + exp_continue + } "Do you wish to save your configuration changes" { send "n\r" exp_continue } -re "\[\n\r]+" { exp_continue } - timeout { close; return 0 } + timeout { catch {close}; wait + return 0 + } eof { return 0 } } set in_proc 0 @@ -616,12 +727,14 @@ source_password_file $password_file set in_proc 0 foreach router [lrange $argv $i end] { set router [string tolower $router] - send_user "$router\n" - - # Figure out prompt. - # Since autoenable is off by default, if we have it defined, it - # was done on the command line. If it is not specifically set on the - # command line, check the password file. + # attempt at platform switching. + set platform "" + send_user -- "$router\n" + + # Figure out the prompt. + # autoenable is off by default. If we have it defined, it was done + # on the command line. If it is not specifically set on the command + # line, check the password file. if $avautoenable { set autoenable 1 set enable 0 @@ -634,6 +747,7 @@ foreach router [lrange $argv $i end] { set prompt "(#| \\(enable\\))" } else { set autoenable 0 + set enable $avenable set prompt ">" } } @@ -647,15 +761,18 @@ foreach router [lrange $argv $i end] { if { $do_passwd || $do_enapasswd } { set pswd [find password $router] if { [llength $pswd] == 0 } { - send_user "\nError: no password for $router in $password_file.\n" + send_user -- "\nError: no password for $router in $password_file.\n" continue } if { $enable && $do_enapasswd && $autoenable == 0 && [llength $pswd] < 2 } { - send_user "\nError: no enable password for $router in $password_file.\n" + send_user -- "\nError: no enable password for $router in $password_file.\n" continue } set passwd [join [lindex $pswd 0] ""] set enapasswd [join [lindex $pswd 1] ""] + } else { + set passwd $userpasswd + set enapasswd $enapasswd } # Figure out username @@ -728,12 +845,13 @@ foreach router [lrange $argv $i end] { # Login to the router if {[login $router $ruser $userpswd $passwd $enapasswd $cmethod $cyphertype]} { + # if login failed or rsh was unsuccessful, move on to the next device continue } if { $enable } { if {[do_enable $enauser $enapasswd]} { if { $do_command || $do_script } { - close; wait + catch {close}; catch {wait} continue } } @@ -742,7 +860,7 @@ foreach router [lrange $argv $i end] { send "\r" expect { -re "\[\r\n]+" { exp_continue; } - -re "^(.+:)1 $prompt" { # stoopid extreme cmd-line numbers and + -re "^(.+\[:.])1 ($prompt)" { # stoopid extreme cmd-line numbers and # prompt based on state of config changes, # which may have an * at the beginning. set junk $expect_out(1,string) |