diff options
Diffstat (limited to 'bin/rivlogin.in')
-rw-r--r-- | bin/rivlogin.in | 433 |
1 files changed, 222 insertions, 211 deletions
diff --git a/bin/rivlogin.in b/bin/rivlogin.in index 12554d5..2d80217 100644 --- a/bin/rivlogin.in +++ b/bin/rivlogin.in @@ -1,8 +1,9 @@ #! @EXPECT_PATH@ -- ## -## $Id: rivlogin.in,v 1.15 2004/01/11 05:39:15 heas Exp $ +## $Id: rivlogin.in,v 1.26 2006/12/08 21:28:26 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 @@ -24,24 +25,28 @@ # rivlogin - Riverstone (and Enterasys SSR) login # # Based upon rscmd (see nmops.org) -# rscmd - Riverstone Networks Automated login -# by Mike MacFaden, Kiran Addepalli +# rscmd - Riverstone Networks Automated login +# by Mike MacFaden, Kiran Addepalli # Riverstone Networks, 2000 # # Returned to the RANCID crowd by andrew fort -# Global vars section +# Usage line +set usage "Error: Usage: $argv0 \[-noenable\] \ +\[-f cloginrc-file\] \[-c command\] \[-Evar=x\] \[-s script-file\] \ +\[-x command-file\] \[-t timeout\] \[-o output-file\] \ +router \[router...\]\n" # program diagnostics set verbose 0 set success 1 set config 0 - + # in seconds to wait for data back from device set timeout 10 set tempfile "/tmp/rivlogin.[exec date]" -# cli command prompt +# cli command prompt set my_prompt ">" set enable_prompt "\#" @@ -60,18 +65,35 @@ set do_script 0 set log_user 0 # The default CLI mode to login to is "enable" mode -set enable 1 +set avenable 1 # The default is to look in the password file to find the passwords. This # tracks if we receive them on the command line. set do_passwd 1 set do_enapasswd 1 - -# cmd usage -set usage "Error: Usage: $argv0 \[-noenable\] \ -\[-f cloginrc-file\] \[-c command\] \[-Evar=x\] \[-s script-file\] \ -\[-x command-file\] \[-t timeout\] \[-o output-file\] \ -router \[router...\]\n" +# +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) ]} { + set default_user $env(CISCO_USER) +} elseif {[ info exists env(USER) ]} { + set default_user $env(USER) +} elseif {[ info exists env(LOGNAME) ]} { + set default_user $env(LOGNAME) +} 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 - + # unlike whoami or id -nu. + if [ catch {exec id} reason ] { + send_error "\nError: could not exec id: $reason\n" + exit 1 + } + regexp {\(([^)]*)} "$reason" junk default_user +} +if {[ info exists env(CLOGINRC) ]} { + set password_file $env(CLOGINRC) +} # Procedures Section @@ -79,7 +101,6 @@ router \[router...\]\n" # # Sets Xterm title if interactive...if its an xterm and the user cares # - proc label { host } { global env @@ -97,35 +118,32 @@ proc label { host } { } } - # This is a helper function to make the password file easier to # maintain. # NOTES: Using this the password file has the form: # add password sl* pete cow # add password at* steve # add password * hanky-pie - -proc add { var args } { +proc add { var args } { global $var lappend $var $args -} +} # Loads the password file. Note that as this file is tcl, and that # 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] } { + if { [info exists read_password_file] } { return 1 } - if { [info exists password_file] == 0 } { + if { [info exists password_file] == 0 } { set password_file $env(HOME)/.cloginrc } @@ -142,15 +160,14 @@ proc source_password_file { } { # pre: var is x, router is y # post: return routerr entry from database else null string - proc find { var router } { if {[ source_password_file ] == 0 } { return {} } - upvar $var list - if { [info exists list] } { + upvar $var list + if { [info exists list] } { foreach line $list { if { [string match [lindex $line 0] $router ] } { return [lrange $line 1 end] @@ -160,13 +177,11 @@ proc find { var router } { return {} } - # pre: login completed ok # post: terminate login session by closing tcp connection - proc auto_exit { } { - global telnet_id + global telnet_id if { $verbose == 1 } { puts "DEBUG: auto_exit closing connection to pid $telnet_id\n" @@ -179,8 +194,7 @@ proc auto_exit { } { # post: return 0 on successful login, else 1 # # NOTE: a number of globals are setup: my_prompt, telnet_id are key -# and paging of cli output is disabled - +# and paging of cli output is disabled proc login { router user userpswd passwd enapasswd } { global login_array @@ -212,7 +226,7 @@ proc login { router user userpswd passwd enapasswd } { expect "*" send "\r" - # If password fails 3 times then expect again + # If password fails 3 times then expect again set pass_attempt 0 expect { @@ -220,7 +234,7 @@ proc login { router user userpswd passwd enapasswd } { -re ".*> " { } "Password:" { - incr pass_attempt + incr pass_attempt send "$passwd\r" exp_continue } @@ -232,13 +246,13 @@ proc login { router user userpswd passwd enapasswd } { send "$user\r" expect { - "Password: " { + "Password: " { incr pattempt if {$pattempt == 1} { - send "$userpswd\r"; - } else { - send "$enapasswd\r"; + send "$userpswd\r"; + } else { + send "$enapasswd\r"; } exp_continue } @@ -246,8 +260,8 @@ proc login { router user userpswd passwd enapasswd } { -re ".*> " { exp_continue;} } } - - "%TELNETD-W-BADPASSWD" { + + "%TELNETD-W-BADPASSWD" { puts "ERROR: bad userid or password to telnet." return 1 } @@ -266,7 +280,7 @@ proc login { router user userpswd passwd enapasswd } { return 1 } - "Connection closed *" { + "Connection closed *" { if {$pass_attempt == 3} { puts "ERROR: Maximum attempts for password reached. Check password. Exiting."; puts $expect_out(0,string); @@ -279,7 +293,7 @@ proc login { router user userpswd passwd enapasswd } { return 1 } - eof { + eof { puts "ERROR: device closed telnet connection during login" return 1 } @@ -298,7 +312,6 @@ proc login { router user userpswd passwd enapasswd } { # pre: login completed ok # post: turn off paging of commands - proc disable_cli_paging { } { global my_prompt @@ -313,7 +326,6 @@ proc disable_cli_paging { } { # pre: login returned 0, prompt at top level # post: turn off command completion return 0 # on error, return 1 - proc disable_cmd_autocomplete { } { global my_prompt @@ -322,9 +334,9 @@ proc disable_cmd_autocomplete { } { $my_prompt { } - timeout { + timeout { puts "ERROR:disable_cmd_autocomplete(TIMEOUT)"; - return 0; + return 0; } } @@ -333,8 +345,7 @@ proc disable_cmd_autocomplete { } { } # pre: login returned 0, do_enable returned 0, cli is in enable or config mode -# post: issues logout cli to device, returns 0 - +# post: issues logout cli to device, returns 0 proc logout { prompt } { global config_mode enable_prompt @@ -342,7 +353,7 @@ proc logout { prompt } { # verify top level prompt state, move to it if necessary if { $config_mode == 1 } { - + send "exit\r" expect { @@ -370,7 +381,6 @@ proc logout { prompt } { # pre: current mode allows transition to enable mode # post: enable mode entered, my_prompt updated, return 0 else 1 - proc do_enable { enauser enapasswd userpswd } { global expect_out verbose global my_prompt enable_prompt @@ -380,19 +390,32 @@ proc do_enable { enauser enapasswd userpswd } { if { $verbose == 1 } { puts "DEBUG: do_enable: my_prompt = $my_prompt ena_prompt = $enable_prompt" } - + + set uses_username 0; + send "enable\r" expect { - Username: { send "$enauser\r"; exp_continue } - Password: { send "$userpswd\r"; exp_continue } + Username: { + set uses_username 1; + send "$enauser\r"; + exp_continue + } + Password: { + if {$uses_username == 1} { + send "$userpswd\r"; + } else { + send "$enapasswd\r"; + } + exp_continue + } "$my_prompt" { puts "ERROR: do_enable failed to gain enable mode." return 1 } - "CONS-W-AUTH_PASSWD" { send "$enapasswd\r"; } + "CONS-W-AUTH_PASSWD" { send "$enapasswd\r"; } "$enable_prompt " { } "%SYS-W-NOPASSWD*" { } @@ -402,14 +425,13 @@ proc do_enable { enauser enapasswd userpswd } { return 1 } } - + set my_prompt $enable_prompt return 0 } # pre: current mode allows transition to enable mode # post: enable mode entered, my_prompt updated, return 0 else 1 - proc do_configure { } { global expect_out verbose config_mode global my_prompt @@ -419,7 +441,7 @@ proc do_configure { } { if { $verbose == 1 } { puts "DEBUG: do_config: my_prompt = $my_prompt cfg_prompt = $config_prompt" } - + send "configure\r" expect { "$config_prompt " { } @@ -438,15 +460,14 @@ proc do_configure { } { # track sent/received from device to output_file # pre: outut_file is valid filename w/write access # post: logfile open, global var logging == 1, return 0 , else 1 - proc start_logfile { output_file } { - global logging + global logging if { [ string length $output_file ] != 0 } { - set rc [ catch { + set rc [ catch { log_file -noappend $output_file } errMsg ] - + if { $rc != 0 } { puts "ERROR: open file $output_file for write access failed. $errMsg\n" return 1 @@ -458,7 +479,7 @@ proc start_logfile { output_file } { } proc run_commands { prompt cmdstring } { - global sendstring + global sendstring set commands [split $cmdstring \;] set num_commands [llength $cmdstring] @@ -474,13 +495,11 @@ proc run_commands { prompt cmdstring } { return 0 } - # Run commands given on the command line # pre: prompt is current system cli prompt, cmdstring is command to execute # post: return 0 on success else 1 # NOTE: output from router ends up in output_file if specified # expect internal input buffer is reset to "" after each command - proc run_single_command { prompt cmdstring } { global verbose set rc 0 @@ -498,7 +517,7 @@ proc run_single_command { prompt cmdstring } { set need_ays 1 set delay 1 if {$verbose == 1} { - puts "DEBUG: save startup cmd seen, set need_ays = 1" + puts "DEBUG: save startup cmd seen, set need_ays = 1" } } @@ -511,7 +530,7 @@ proc run_single_command { prompt cmdstring } { if { $delay == 1} { sleep 1 - } + } expect { @@ -542,7 +561,7 @@ proc run_single_command { prompt cmdstring } { "want to overwrite " { send "yes\r" if {$verbose == 1} { - puts "DEBUG: got overwrite question, set need_ays to 0" + puts "DEBUG: got overwrite question, set need_ays to 0" } set need_ays 0 } @@ -551,7 +570,7 @@ proc run_single_command { prompt cmdstring } { "%CONFIG-E-DUPLICATE,*" { } - "$prompt" { + "$prompt" { if { $seen_prompt == 0 } { set seen_prompt 1 } @@ -571,7 +590,7 @@ proc run_single_command { prompt cmdstring } { } - timeout { + timeout { if {$verbose == 1} { puts "DEBUG: timeout occured for the $seen_time time\n" } @@ -586,8 +605,8 @@ proc run_single_command { prompt cmdstring } { set rc 1 } - eof { - puts "ERROR:run_commands(connection closed by device)\n" + eof { + puts "ERROR:run_commands(connection closed by device)\n" set rc 1 } @@ -602,15 +621,14 @@ proc run_single_command { prompt cmdstring } { # pre: RSTONE_USER env var is set # post: update global "default_user" to this string - proc init_userid { } { global default_user if {[ info exists env(RSTONE_USER) ] } { set default_user $env(RSTONE_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 } @@ -631,14 +649,13 @@ proc source_script_file { filename } { # return 0 on success, return 1 on error # NOTE: for scripts that begin with "configure", change the mode to configure # before executing the following commands - proc process_script_file { filename } { global my_prompt verbose set rc 0 set ifile "" - set rc [ catch { + set rc [ catch { set ifile [ open $filename r] } errMsg ] @@ -650,16 +667,16 @@ proc process_script_file { filename } { set line_cnt 0 while { [eof $ifile] != 1 } { - + set bytes [ gets $ifile cmd ] incr line_cnt - if { $bytes < 0 } { - break + if { $bytes < 0 } { + break } elseif { $bytes == 0 } { continue } - + if { $verbose == 1 } { puts "DEBUG: line:$line_cnt cmd = $cmd\n" } @@ -693,12 +710,11 @@ proc process_script_file { filename } { # post: remove extended ascii sequences and other cruft # and prepend a header: rscmd: ip-addr : date # TODO: should watch all file commands more closely - proc strip_log { filename router } { global tempfile - set rc [ catch { + set rc [ catch { set ifile [ open $filename r] } errMsg ] @@ -706,7 +722,7 @@ proc strip_log { filename router } { puts "ERROR: strip_log: open script file $filename for read access failed. $errMsg\n" return 1 } - set rc [ catch { + set rc [ catch { set ofile [ open $tempfile w] } errMsg ] @@ -718,12 +734,11 @@ proc strip_log { filename router } { set nl 0 puts $ofile "rscmd: $router : [exec date]" - + while { [eof $ifile] != 1 } { - set bytes [ gets $ifile cmd ] - if { $bytes <= 0 } { - break + if { $bytes <= 0 } { + break } incr nl if { $nl <= 2 } { @@ -801,6 +816,10 @@ for {set idx 0} {$idx < $argc} {incr idx} { } set do_script 1 + # Version string + } -V* { + send_user "@PACKAGE@ @VERSION@\n" + exit 0 # Command file } -x* - -X { @@ -832,22 +851,21 @@ for {set idx 0} {$idx < $argc} {incr idx} { puts "DEBUG: output file: $output_file" } } - - } -t* - - -T* { - incr idx - set timeout [ lindex $argv $idx ] - - } -noenable { - set enable 0 - } -* { - puts "ERROR:unkown argument passed: $arg\n" - puts $usage + # Timeout + } -t* - + -T* { + incr idx + set timeout [ lindex $argv $idx ] + # Do we enable? + } -noenable { + set avenable 0 + } -* { + send_user "Error: Unkown argument! $arg\n" + send_user $usage exit 1 - - } default { + } default { break - } + } } } @@ -859,146 +877,139 @@ if { $idx == $argc } { } # main loop - foreach router [lrange $argv $idx end] { set router [string tolower $router] -# Figure out passwords -if {$verbose == 1} { - puts "DEBUG: do_passwd = $do_passwd\n" - puts "DEBUG: do_enablepasswd = $do_enapasswd\n" -} - -if { $do_passwd || $do_enapasswd } { - set pswd [find password $router] - if { [llength $pswd] == 0 } { - puts "ERROR: - no password for $router in $password_file.\n" - exit 1 - } - if { $do_enapasswd && [llength $pswd] < 2 } { - puts "ERROR: no enable password found for $router in $password_file." - exit 1 - } - - set passwd [join [lindex $pswd 0] ""] - set enapasswd [join [lindex $pswd 1] ""] -} - - -# Figure out user to login with if necessary - -if {[info exists username]} { - # command line username - set user $username -} else { - set user [join [find user $router] ""] - if { "$user" == "" } { set user $default_user } -} - -# Figure out username's password - -if {[info exists userpasswd]} { - # command line username - set userpswd $userpasswd -} else { - set userpswd [join [find userpassword $router] ""] - if { "$userpswd" == "" } { set userpswd $passwd } -} + # Figure out passwords + if {$verbose == 1} { + puts "DEBUG: do_passwd = $do_passwd\n" + puts "DEBUG: do_enablepasswd = $do_enapasswd\n" + } -# Figure out enable username + # look for noenable option in .cloginrc + if { [find noenable $router] != "" } { + set enable 0 + } else { + set enable $avenable + } -if {[info exists enausername]} { - # command line enausername - set enauser $enausername -} else { - set enauser [join [find enauser $router] ""] - if { "$enauser" == "" } { set enauser $user } -} + if { $do_passwd || $do_enapasswd } { + set pswd [find password $router] + if { [llength $pswd] == 0 } { + puts "ERROR: - no password for $router in $password_file.\n" + exit 1 + } + if { $do_enapasswd && [llength $pswd] < 2 } { + puts "ERROR: no enable password found for $router in $password_file." + exit 1 + } -# Login to the router, set my_prompt to router's cmd prompt + set passwd [join [lindex $pswd 0] ""] + set enapasswd [join [lindex $pswd 1] ""] + } else { + set passwd $userpasswd + set enapasswd $enapasswd + } -if {[login $router $user $userpswd $passwd $enapasswd ]} { - if { $verbose == 1 } { - puts "DEBUG: login to $router failed\n" + # Figure out user to login with if necessary + if {[info exists username]} { + # command line username + set user $username + } else { + set user [join [find user $router] ""] + if { "$user" == "" } { set user $default_user } } - exit 1 -} -if {$verbose == 1 } { - puts "DEBUG: login completed ok\n" -} + # Figure out username's password + if {[info exists userpasswd]} { + # command line username + set userpswd $userpasswd + } else { + set userpswd [join [find userpassword $router] ""] + if { "$userpswd" == "" } { set userpswd $passwd } + } -if { $enable == 1 } { + # Figure out enable username + if {[info exists enausername]} { + # command line enausername + set enauser $enausername + } else { + set enauser [join [find enauser $router] ""] + if { "$enauser" == "" } { set enauser $user } + } - if { [do_enable $enauser $enapasswd $userpswd] == 1} { + # Login to the router, set my_prompt to router's cmd prompt + if {[login $router $user $userpswd $passwd $enapasswd ]} { if { $verbose == 1 } { - puts "DEBUG: switch to enable mode on $router failed\n" + puts "DEBUG: login to $router failed\n" } exit 1 } -} - -# run in one of three modes - -if { $do_command } { - disable_cmd_autocomplete - disable_cli_paging - - if {[ start_logfile $output_file] != 0 } { - exit 1 + if {$verbose == 1 } { + puts "DEBUG: login completed ok\n" } - if {[ run_commands $my_prompt $command ]} { - - log_file - exit 1 + if { $enable == 1 } { + if { [do_enable $enauser $enapasswd $userpswd] == 1} { + if { $verbose == 1 } { + puts "DEBUG: switch to enable mode on $router failed\n" + } + exit 1 + } + } - } else { + # run in one of three modes + if { $do_command } { + disable_cmd_autocomplete + disable_cli_paging - logout $my_prompt + if { [start_logfile $output_file] != 0 } { + exit 1 + } - } - -} elseif { $do_script } { - - disable_cmd_autocomplete - disable_cli_paging - - if {[ start_logfile $output_file] != 0 } { - exit 1 - } + if {[ run_commands $my_prompt $command ]} { + log_file + exit 1 + } else { + logout $my_prompt + } + } elseif { $do_script } { + disable_cmd_autocomplete + disable_cli_paging - #if { [process_script_file $sfile] == 1} { -# puts "DEBUG: logfile $output_file closed on error\n" -# logout $my_prompt -# exit 1 -# } + if {[ start_logfile $output_file] != 0 } { + exit 1 + } - source_script_file $sfile +# if { [process_script_file $sfile] == 1} { +# puts "DEBUG: logfile $output_file closed on error\n" +# logout $my_prompt +# exit 1 +# } - logout $my_prompt + source_script_file $sfile -} else { - - label $router - log_user 1 + logout $my_prompt + } else { + label $router + log_user 1 - if {[ start_logfile $output_file] != 0 } { - exit 1 + if {[ start_logfile $output_file] != 0 } { + exit 1 + } + interact + log_file } - interact - log_file -} -if { $verbose == 1 } { - puts "DEBUG: exiting normally.\n" -} + if { $verbose == 1 } { + puts "DEBUG: exiting normally.\n" + } -if { $logging == 1} { - log_file - strip_log $output_file $router -} + if { $logging == 1} { + log_file + strip_log $output_file $router + } } # puts "\n" |