Index: head/net-mgmt/rancid3/Makefile =================================================================== --- head/net-mgmt/rancid3/Makefile (revision 430722) +++ head/net-mgmt/rancid3/Makefile (revision 430723) @@ -1,114 +1,116 @@ # Created by: Janos.Mohacsi@bsd.hu # $FreeBSD$ PORTNAME= rancid PORTVERSION= 3.6.1 -PORTREVISION= 0 +PORTREVISION= 1 CATEGORIES= net-mgmt MASTER_SITES= ftp://ftp.shrubbery.net/pub/rancid/ PKGNAMESUFFIX= 3 MAINTAINER= feld@FreeBSD.org COMMENT= Really Awesome New Cisco confIg Differ LIB_DEPENDS= libexpect.so:lang/expect RUN_DEPENDS= p5-LockFile-Simple>=0:devel/p5-LockFile-Simple USES= gmake perl5 shebangfix perl_OLD_CMD= @PERLV_PATH@ SHEBANG_FILES= bin/* USERS= rancid GROUPS= rancid SUB_FILES= pkg-message 200.rancid GNU_CONFIGURE= yes CONFIGURE_ARGS= --localstatedir=${LOCALBASE}/var/${PORTNAME}/ \ --bindir=${LOCALBASE}/libexec/${PORTNAME}/ \ --sysconfdir=${LOCALBASE}/etc/${PORTNAME}/ OLDCONFIG_FILE1= bin/env OLDCONFIG_FILE2= util/lg/lg.conf -NEWERCONFIG_FILES1= etc/rancid.conf -NEWERCONFIG_FILES2= etc/lg.conf +NEWERCONFIG_FILE1= etc/rancid.conf +NEWERCONFIG_FILE2= etc/lg.conf NEWCONFIG_FILES= rancid.conf lg.conf OPTIONS_DEFINE= COMWARE SVN OPTIONS_DEFAULT= COMWARE_DESC= Add experimental support for Comware devices SVN_DESC= Use Subversion instead of CVS .include .if ${PORT_OPTIONS:MCOMWARE} PLIST_SUB+= COMWARE="" .else PLIST_SUB+= COMWARE="@comment " .endif .if ${PORT_OPTIONS:MSVN} CONFIGURE_ARGS+= --with-svn BUILD_DEPENDS+= svn:devel/subversion .else CONFIGURE_ARGS+= --without-svn .if ${OPSYS} == FreeBSD && ${OSVERSION} >= 1000000 RUN_DEPENDS+= cvs>0:devel/cvs .endif .endif pre-everything:: @ ${ECHO} "Make sure your rancid repository is quiet before upgrading; disable rancid cron jobs" post-patch: .if ${PORT_OPTIONS:MCOMWARE} ${CAT} ${FILESDIR}/comware_types.conf >> ${WRKSRC}/etc/rancid.types.base + ${SED} -e 's/@VERSION@/${PORTVERSION}/g' ${FILESDIR}/cmwlogin.in > ${WRKDIR}/cmwlogin + ${SED} -e 's/@VERSION@/${PORTVERSION}/g' ${FILESDIR}/cmw.pm.in > ${WRKDIR}/cmw.pm .endif ${REINPLACE_CMD} "s|par.1|rancid-par.1|" ${WRKSRC}/man/Makefile.in ${MV} ${WRKSRC}/man/par.1 ${WRKSRC}/man/rancid-par.1 post-install: ${MKDIR} ${STAGEDIR}${LOCALBASE}/etc/periodic/hourly ${INSTALL_SCRIPT} ${WRKDIR}/200.rancid ${STAGEDIR}${LOCALBASE}/etc/periodic/hourly ${LN} -s ${LOCALBASE}/libexec/${PORTNAME}/rancid-cvs ${STAGEDIR}${LOCALBASE}/bin ${LN} -s ${LOCALBASE}/libexec/${PORTNAME}/rancid-run ${STAGEDIR}${LOCALBASE}/bin .if ${PORT_OPTIONS:MCOMWARE} - ${INSTALL_DATA} ${FILESDIR}/cmw.pm ${STAGEDIR}/${LOCALBASE}/lib/rancid - ${INSTALL_SCRIPT} ${FILESDIR}/cmwlogin ${STAGEDIR}/${LOCALBASE}/libexec/rancid + ${INSTALL_DATA} ${WRKDIR}/cmw.pm ${STAGEDIR}/${LOCALBASE}/lib/rancid + ${INSTALL_SCRIPT} ${WRKDIR}/cmwlogin ${STAGEDIR}/${LOCALBASE}/libexec/rancid .endif .for file in ${NEWCONFIG_FILES} @ if [ -f ${LOCALBASE}/etc/${PORTNAME}/${file} ] ; then \ ${ECHO} "WARNING: *** new ${file} file is installed as ${LOCALBASE}/rancid/${file}.sample"; \ ${ECHO} " : *** review ${file}.sample for new/deprecated switches or install in place ${file}"; \ fi .endfor @ if [ -f ${LOCALBASE}/rancid/${NEWERCONFIG_FILE1} ] ; then \ ${ECHO} "WARNING: *** ${LOCALBASE}/rancid/${NEWERCONFIG_FILE1} has been replaced with "; \ ${ECHO} " : *** ${LOCALBASE}/etc/${PORTNAME}/rancid.conf. Merge from sample and old file "; \ fi @ if [ -f ${LOCALBASE}/rancid/${NEWERCONFIG_FILE2} ] ; then \ ${ECHO} "WARNING: *** ${LOCALBASE}/rancid/${NEWERCONFIG_FILE2} has been replaced with "; \ ${ECHO} " : *** ${LOCALBASE}/etc/${PORTNAME}/lg.conf. Merge from sample and old file "; \ fi @ if [ -f ${LOCALBASE}/rancid/${NEWERCONFIG_FILE1} -o \ -f ${LOCALBASE}/rancid/${NEWERCONFIG_FILE2} ] ; then \ ${ECHO} "WARNING: *** New CVS Repository will be stored ${LOCALBASE}/var/${PORTNAME}/ "; \ ${ECHO} " : *** Copy the repository if you want to keep the history "; \ fi @ if [ -f ${LOCALBASE}/rancid/${OLDCONFIG_FILE1} ] ; then \ ${ECHO} "WARNING: *** ${LOCALBASE}/rancid/${OLDCONFIG_FILE1} has been replaced with "; \ ${ECHO} " : *** ${LOCALBASE}/etc/${PORTNAME}/rancid.conf. Merge from sample and old file "; \ fi @ if [ -f ${LOCALBASE}/rancid/${OLDCONFIG_FILE2} ] ; then \ ${ECHO} "WARNING: *** ${LOCALBASE}/rancid/${OLDCONFIG_FILE2} has been replaced with "; \ ${ECHO} " : *** ${LOCALBASE}/etc/${PORTNAME}/lg.conf. Merge from sample and old file "; \ fi @ if [ -f ${LOCALBASE}/rancid/${OLDCONFIG_FILE1} -o \ -f ${LOCALBASE}/rancid/${OLDCONFIG_FILE2} ] ; then \ ${ECHO} "WARNING: *** New CVS Repository will be stored ${LOCALBASE}/rancid/var "; \ ${ECHO} " : *** Copy the repository if you want to keep the history "; \ fi .include Index: head/net-mgmt/rancid3/files/cmwlogin =================================================================== --- head/net-mgmt/rancid3/files/cmwlogin (revision 430722) +++ head/net-mgmt/rancid3/files/cmwlogin (nonexistent) @@ -1,1043 +0,0 @@ -#! /usr/local/bin/expect -- -## -## $Id: cmwlogin 3022 2015-01-13 20:00:00Z heas $ -## -## rancid 3.1.99 -## Copyright (c) 1997-2015 by Terrapin Communications, Inc. -## All rights reserved. -## -## This code is derived from software contributed to and maintained by -## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan, -## Pete Whiting, Austin Schutz, and Andrew Fort. -## -## Redistribution and use in source and binary forms, with or without -## modification, are permitted provided that the following conditions -## are met: -## 1. Redistributions of source code must retain the above copyright -## notice, this list of conditions and the following disclaimer. -## 2. Redistributions in binary form must reproduce the above copyright -## notice, this list of conditions and the following disclaimer in the -## documentation and/or other materials provided with the distribution. -## 3. All advertising materials mentioning features or use of this software -## must display the following acknowledgement: -## This product includes software developed by Terrapin Communications, -## Inc. and its contributors for RANCID. -## 4. Neither the name of Terrapin Communications, Inc. nor the names of its -## contributors may be used to endorse or promote products derived from -## this software without specific prior written permission. -## 5. It is requested that non-binding fixes and modifications be contributed -## back to Terrapin Communications, Inc. -## -## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS -## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS -## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -## POSSIBILITY OF SUCH DAMAGE. -# -# The expect login scripts were based on Erik Sherk's gwtn, by permission. -# -# cwlogin - Comware login -# -# Most options are intuitive for logging into a Comware device. -# The default is to enable (thus -noenable). Some folks have -# setup tacacs to have a user login at priv-lvl = 3 (enabled) -# so the -autoenable flag was added for this case (don't go through -# the process of enabling and the prompt will be the "#" prompt. -# The default username password is the same as the vty password. -# - -# Usage line -set usage "Usage: $argv0 \[-dSV\] \[-autoenable\] \[-noenable\] \[-c command\] \ -\[-Evar=x\] \[-e enable-password\] \[-f cloginrc-file\] \[-p user-password\] \ -\[-r passphrase\] \[-s script-file\] \[-t timeout\] \[-u username\] \ -\[-v vty-password\] \[-w enable-username\] \[-x command-file\] \[-P platform\] \ -\[-y ssh_cypher_type\] router \[router...\]\n" - -# env(CLOGIN) may contain: -# x == do not set xterm banner or name - -# Password file -set password_file $env(HOME)/.cloginrc -# Default is to login to the router -set do_command 0 -set do_script 0 -# The default is to automatically enable -set avenable 1 -# The default is that you login non-enabled (tacacs can have you login already -# enabled) -set avautoenable 0 -# 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 -# Save config, if prompted -set do_saveconfig 0 -# Sometimes routers take awhile to answer (the default is 10 sec) -set timeoutdflt 45 -# Some CLIs having problems if we write too fast (Extreme, PIX, Cat) -set send_human {.2 .1 .4 .2 1} - -# 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) -} - -# Process the command line -for {set i 0} {$i < $argc} {incr i} { - set arg [lindex $argv $i] - - switch -glob -- $arg { - # Expect debug mode - -d* { - exp_internal 1 - # Username - } -u* { - if {! [regexp .\[uU\](.+) $arg ignore user]} { - incr i - set username [lindex $argv $i] - } - # VTY Password - } -p* { - if {! [regexp .\[pP\](.+) $arg ignore userpasswd]} { - incr i - set userpasswd [lindex $argv $i] - } - set do_passwd 0 - # ssh passphrase - } -r* { - if {! [regexp .\[rR\](.+) $arg ignore passphrase]} { - incr i - set vapassphrase [lindex $argv $i] - } - # VTY Password - } -v* { - if {! [regexp .\[vV\](.+) $arg ignore passwd]} { - incr i - set passwd [lindex $argv $i] - } - set do_passwd 0 - # Version string - } -V* { - send_user "rancid 3.1.99\n" - exit 0 - # Enable Username - } -w* { - if {! [regexp .\[wW\](.+) $arg ignore enauser]} { - incr i - set enausername [lindex $argv $i] - } - # Environment variable to pass to -s scripts - } -E* { - if {[regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} { - set E$varname $varvalue - } else { - send_user "\nError: invalid format for -E in $arg\n" - exit 1 - } - # Enable Password - } -e* { - if {! [regexp .\[e\](.+) $arg ignore enapasswd]} { - incr i - set enapasswd [lindex $argv $i] - } - set do_enapasswd 0 - # Platform - } -P* { - if {! [regexp .\[P\](.+) $arg ignore platform]} { - incr i - set plat [lindex $argv $P] - } - # Command to run. - } -c* { - if {! [regexp .\[cC\](.+) $arg ignore command]} { - incr i - set command [lindex $argv $i] - } - set do_command 1 - # Expect script to run. - } -s* { - if {! [regexp .\[sS\](.+) $arg ignore sfile]} { - incr i - set sfile [lindex $argv $i] - } - if { ! [file readable $sfile] } { - send_user "\nError: Can't read $sfile\n" - exit 1 - } - set do_script 1 - # save config on exit - } -S* { - set do_saveconfig 1 - # 'ssh -c' cypher type - } -y* { - if {! [regexp .\[eE\](.+) $arg ignore cypher]} { - incr i - set cypher [lindex $argv $i] - } - # alternate cloginrc file - } -f* { - if {! [regexp .\[fF\](.+) $arg ignore password_file]} { - incr i - set password_file [lindex $argv $i] - } - # Timeout - } -t* { - if {! [regexp .\[tT\](.+) $arg ignore timeout]} { - incr i - set timeoutdflt [lindex $argv $i] - } - # Command file - } -x* { - if {! [regexp .\[xX\](.+) $arg ignore cmd_file]} { - incr i - set cmd_file [lindex $argv $i] - } - if [catch {set cmd_fd [open $cmd_file r]} reason] { - send_user "\nError: $reason\n" - exit 1 - } - 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 avenable 0 - # Does tacacs automatically enable us? - } -autoenable { - set avautoenable 1 - set avenable 0 - } -* { - send_user "\nError: Unknown argument! $arg\n" - send_user $usage - exit 1 - } default { - break - } - } -} -# Process routers...no routers listed is an error. -if { $i == $argc } { - send_user "\nError: $usage" -} - -# Only be quiet if we are running a script (it can log its output -# on its own) -if { $do_script } { - log_user 0 -} else { - log_user 1 -} - -# -# Done configuration/variable setting. Now run with it... -# - -# Sets Xterm title if interactive...if its an xterm and the user cares -proc label { host } { - global env - # if CLOGIN has an 'x' in it, don't set the xterm name/banner - if [info exists env(CLOGIN)] { - if {[string first "x" $env(CLOGIN)] != -1} { return } - } - # take host from ENV(TERM) - if [info exists env(TERM)] { - 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 * hanky-pie -proc add {var args} { global int_$var ; lappend int_$var $args} -proc include {args} { - global env - regsub -all "(^{|}$)" $args {} args - if { [regexp "^/" $args ignore] == 0 } { - set args $env(HOME)/$args - } - source_password_file $args -} - -proc find {var router} { - upvar int_$var list - if { [info exists list] } { - foreach line $list { - if { [string match -nocase [lindex $line 0] $router] } { - return [lrange $line 1 end] - } - } - } - return {} -} - -# 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 -proc source_password_file { password_file } { - global env - if { ! [file exists $password_file] } { - send_user "\nError: password file ($password_file) does not exist\n" - exit 1 - } - file stat $password_file fileinfo - if { [expr ($fileinfo(mode) & 007)] != 0000 } { - send_user "\nError: $password_file must not be world readable/writable\n" - exit 1 - } - if [catch {source $password_file} reason] { - send_user "\nError: $reason\n" - exit 1 - } -} - -# 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 identfile } { - global command spawn_id in_proc do_command do_script platform passphrase - global prompt prompt_match u_prompt p_prompt e_prompt sshcmd - set in_proc 1 - set uprompt_seen 0 - - # 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 methcmd suffix port - if {"$port" == ""} { - set retval [catch {spawn telnet $router} reason] - } else { - set retval [catch {spawn telnet $router $port} reason] - } - if { $retval } { - send_user "\nError: telnet failed: $reason\n" - return 1 - } - } elseif [string match "ssh*" $prog] { - # ssh to the router & try to login with or without an identfile. - regexp {ssh(:([^[:space:]]+))*} $prog methcmd suffix port - set cmd $sshcmd - if {"$port" != ""} { - set cmd "$cmd -p $port" - } - if {"$identfile" != ""} { - set cmd "$cmd -i $identfile" - } - set retval [catch {eval spawn [split "$cmd -c $cyphertype -x -l $user $router" { }]} reason] - if { $retval } { - send_user "\nError: $cmd failed: $reason\n" - return 1 - } - } elseif ![string compare $prog "rsh"] { - 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; - } - - # handle escaped ;s in commands, and ;; and ^; - regsub -all {([^\\]);;} $command "\\1;\u002;" esccommand - regsub {^;} $esccommand "\u002;" command - set sep "\\1\u001" - regsub -all {([^\\])\;} $command "$sep" esccommand - set sep "\u001" - set commands [split $esccommand $sep] - 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}; catch {wait}; - send_user "\nError: Connection\ - Refused ($prog): $router\n" - set rshfail 1 - } - -re "(Connection closed by|Connection to \[^\n\r]+ closed)" { - catch {close}; catch {wait}; - send_user "\nError: Connection\ - closed ($prog): $router\n" - set rshfail 1 - } - "Host is unreachable" { catch {close}; catch {wait}; - send_user "\nError: Host Unreachable:\ - $router\n" - set rshfail 1 - } - "No address associated with" { - catch {close}; catch {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}; catch {wait}; - send_user "\nError: TIMEOUT reached\n" - set rshfail 1 - } - eof { catch {close}; catch {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 { - send_user "\nError: unknown connection method: $prog\n" - return 1 - } - sleep 0.3 - - # This helps cleanup each expect clause. - expect_after { - timeout { - send_user "\nError: TIMEOUT reached\n" - catch {close}; catch {wait}; - if { $in_proc} { - return 1 - } else { - continue - } - } eof { - send_user "\nError: EOF received\n" - catch {close}; catch {wait}; - if { $in_proc} { - return 1 - } else { - continue - } - } - } - - # Here we get a little tricky. There are several possibilities: - # the router can ask for a username and passwd and then - # talk to the TACACS server to authenticate you, or if the - # 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 { - -re "^<-+ More -+>\[^\n\r]*" { - # ASA will use the pager for long banners - send " "; - exp_continue - } - -re "(Connection refused|Secure connection \[^\n\r]+ refused)" { - catch {close}; catch {wait}; - if !$progs { - send_user "\nError: Connection Refused ($prog): $router\n" - return 1 - } - } - -re "(Connection closed by|Connection to \[^\n\r]+ closed)" { - catch {close}; catch {wait}; - if !$progs { - send_user "\nError: Connection closed ($prog): $router\n" - return 1 - } - } - eof { send_user "\nError: Couldn't login: $router\n"; wait; return 1 } - -nocase "unknown host\r" { - send_user "\nError: Unknown host $router\n"; - catch {close}; catch {wait}; - return 1 - } - "Host is unreachable" { - send_user "\nError: Host Unreachable: $router\n"; - catch {close}; catch {wait}; - return 1 - } - "No address associated with name" { - send_user "\nError: Unknown host $router\n"; - catch {close}; catch {wait}; - return 1 - } - -re "(Host key not found |The authenticity of host .* be established).* \\(yes/no\\)\\?" { - send "yes\r" - send_user "\nHost $router added to the list of known hosts.\n" - exp_continue - } - -re "HOST IDENTIFICATION HAS CHANGED.* \\(yes/no\\)\\?" { - send "no\r" - send_user "\nError: The host key for $router has changed. Update the SSH known_hosts file accordingly.\n" - catch {close}; catch {wait}; - return 1 - } - -re "HOST IDENTIFICATION HAS CHANGED\[^\n\r]+" { - send_user "\nError: The host key for $router has changed. Update the SSH known_hosts file accordingly.\n" - return 1 - } - -re "Offending key for .* \\(yes/no\\)\\?" { - send "no\r" - send_user "\nError: host key mismatch for $router. Update the SSH known_hosts file accordingly.\n" - catch {close}; catch {wait}; - return 1 - } - -re "(denied|Sorry)" { - send_user "\nError: Check your passwd for $router\n" - catch {close}; catch {wait}; return 1 - } - "Login failed" { - send_user "\nError: Check your passwd for $router\n" - catch {close}; catch {wait}; return 1 - } - -re "% (Bad passwords|Authentication failed)" { - send_user "\nError: Check your passwd for $router\n" - catch {close}; catch {wait}; return 1 - } - "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 - } - -re "Last login:" { - exp_continue - } - -re "Press the key \[^\r\n]+\[\r\n]+" { - exp_continue - } - -re "@\[^\r\n]+ $p_prompt" { - # ssh pwd prompt - sleep 1 - send -- "$userpswd\r" - exp_continue - } - -re "Enter passphrase.*: " { - # sleep briefly to allow time for stty -echo - sleep .3 - send -- "$passphrase\r" - exp_continue - } - -re "$u_prompt" { - send -- "$user\r" - set uprompt_seen 1 - exp_continue - } - -re "$p_prompt" { - sleep 1 - if {$uprompt_seen == 1} { - send -- "$userpswd\r" - } else { - send -- "$passwd\r" - } - exp_continue - } - -re "$prompt" { - set prompt_match $expect_out(0,string); - break; - } - "Login invalid" { - send_user "\nError: Invalid login: $router\n"; - catch {close}; catch {wait}; return 1 - } - -re "\[^\r\n]*\[\r\n]+" { exp_continue; } - } - } - - set in_proc 0 - return 0 -} - -# Enable -proc do_enable { enauser enapasswd } { - global do_saveconfig in_proc - global prompt u_prompt e_prompt enacmd - set in_proc 1 - - send "$enacmd\r" - expect { - -re "$u_prompt" { send -- "$enauser\r"; exp_continue} - -re "$e_prompt" { send -- "$enapasswd\r"; exp_continue} - ">" { set prompt ">" } - "#" { set prompt "#" } - "(enable)" { set prompt "> \\(enable\\) " } - "% Invalid input" { - send_user "\nError: Unrecognized command, check your enable command\n"; - return 1 - } - -re "(denied|Sorry|Incorrect)" { - # % Access denied - from local auth and poss. others - send_user "\nError: Check your Enable passwd\n"; - return 1 - } - "% Error in authentication" { - send_user "\nError: Check your Enable passwd\n" - return 1 - } - "% Bad passwords" { - send_user "\nError: Check your Enable passwd\n" - return 1 - } - "% Password is not set." { # Comware - send_user "\nError: No '$enacmd' password set for devide\n" - return 1 - } - "% Authenticate failed." { # Comware - send_user "\nError: Check your enable password for '$enacmd'\n - return 1 - } - } - # We set the prompt variable (above) so script files don't need - # to know what it is. - set in_proc 0 - return 0 -} - -# Run commands given on the command line. -proc run_commands { prompt command } { - global do_saveconfig in_proc platform exitcmd - set in_proc 1 - - # If the prompt is (enable), then we are on a switch and the - # command is "set length 0"; otherwise its "terminal length 0". - # skip if its an extreme (since the pager can not be disabled on a - # per-vty basis). - if { [string compare "extreme" "$platform"] } { - # match cisco config mode prompts too, such as router(config-if)#, - # but catalyst does not change in this fashion. - regsub -all {^(.{1,11}).*([#>])$} $prompt {\1([^#>\r\n]+)?[#>](\\([^)\\r\\n]+\\))?} reprompt - } else { - set reprompt $prompt - } - - # this is the only way i see to get rid of more prompts in o/p..grrrrr - log_user 0 - - # handle escaped ;s in commands, and ;; and ^; - regsub -all {([^\\]);;} $command "\\1;\u002;" esccommand - regsub {^;} $esccommand "\u002;" command - set sep "\\1\u001" - regsub -all {([^\\]);} $command "$sep" esccommand - set sep "\u001" - set commands [split $esccommand $sep] - set num_commands [llength $commands] - # the pager can not be turned off on the PIX, so we have to look - # for the "More" prompt. the extreme is equally obnoxious in pre-12.3 XOS, - # with a global switch in the config. - for {set i 0} {$i < $num_commands} { incr i} { - if { [lindex $commands $i] == "\u002" } { - send -- "\r" - } else { - send -- "[subst -nocommands [lindex $commands $i]]\r" - } - expect { - -re "\b+" { exp_continue } - -re "^\[^\n\r *]*$reprompt" { send_user -- "$expect_out(buffer)" - } - -re "^\[^\n\r]*$reprompt." { send_user -- "$expect_out(buffer)" - exp_continue - } - -re "^--More--\[\r\n]+" { # specific match c1900 pager - send " " - exp_continue - } - -re "\[^\r\n]*\[\n\r]+" { send_user -- "$expect_out(buffer)" - exp_continue - } - -re "\[^\r\n]*Press to cont\[^\r\n]*" { - send " " - # bloody ^[[2K after " " - expect { - -re "^\[^\r\n]*\r" {} - } - exp_continue - } - -re "^ *--More--\[^\n\r]*" { - send " " - exp_continue } - -re "^<-+ More -+>\[^\n\r]*" { - send_user -- "$expect_out(buffer)" - send " " - exp_continue } - -re "^ {0,2}-+ More .*-+.*\[^\n\r]*" { - # Comware 3/5 pager prompt - sleep 0.1 - send " " - exp_continue } - -re "^---- More ----\[^\n\r]*" { - # Comware 7 pager prompt - sleep 0.1 - send " " - exp_continue } - } - } - log_user 1 - - if { [string compare "extreme" "$platform"] } { - send -h "exit\r" - } else { - 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 -h "$exitcmd\r" - exp_continue; - } - "The system has unsaved changes" { # Force10 SFTOS - if {$do_saveconfig} { - catch {send "y\r"} - } else { - catch {send "n\r"} - } - exp_continue - } - "Would you like to save them now" { # Force10 - if {$do_saveconfig} { - catch {send "y\r"} - } else { - catch {send "n\r"} - } - exp_continue - } - -re "(Profile|Configuration) changes have occurred.*" { - # Cisco CSS - if {$do_saveconfig} { - catch {send "y\r"} - } else { - catch {send "n\r"} - } - exp_continue - } - "Do you wish to save your configuration changes" { - if {$do_saveconfig} { - catch {send "y\r"} - } else { - catch {send "n\r"} - } - exp_continue - } - -re "\[\n\r]+" { exp_continue } - -re "\[^\n\r *]Note:" { return 0 } - timeout { catch {close}; catch {wait}; - return 0 - } - eof { return 0 } - } - set in_proc 0 -} - -# -# For each router... (this is main loop) -# -source_password_file $password_file -set in_proc 0 -set exitval 0 -set prompt_match "" -foreach router [lrange $argv $i end] { - set router [string tolower $router] - # attempt at platform switching. - set platform "" - send_user -- "$router\n" - - # Figure out the platform - if {[info exists plat]} { - # command line platform - set platform $plat - } else { - set plat [find platform $router] - if { "$plat" == "" } { set platform "" } - } - - # Based on the platform, set some other defaults - # These can get overridden by other explicit settings - # Note that MA5600 wants enacmd "enable" - # Note that later versions of Coomware want cyphertype "aes128-cbc" - if { [string compare "cmw" "$platform"] } { - set enacmd "super" - set exitcmd "quit" - set cyphertype "3des" - } else { - set exitcmd "exit" - } - - # device timeout - set timeout [find timeout $router] - if { [llength $timeout] == 0 } { - set timeout $timeoutdflt - } - - # Default prompt. - set prompt [join [find prompt $router] ""] - if { [llength $prompt] == 0 } { - set prompt "(>\a?|#| \\(enable\\))" - } - - # look for autoenable option in .cloginrc & cmd-line - set ae [find autoenable $router] - if { "$ae" == "1" || $avautoenable } { - set autoenable 1 - } else { - set autoenable 0 - } - # look for enable options in .cloginrc & cmd-line - if { $avenable == 0 } { - set enable 0 - } else { - set ne [find noenable $router] - if { "$ne" == "1" || "$autoenable" == "1" } { - set enable 0 - } else { - set enable 1 - } - } - - # Figure out passwords - 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" - continue - } - if { $enable && $do_enapasswd && $autoenable == 0 && [llength $pswd] < 2 } { - 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 - if {[info exists username]} { - # command line username - set ruser $username - } else { - set ruser [join [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 [join [find userpassword $router] ""] - if { "$userpswd" == "" } { set userpswd $passwd } - } - - # 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 $ruser } - } - - # Figure out enable command - set enacmd [join [find enablecmd $router] ""] - if { "$enacmd" == "" } { set enacmd "enable" } - - # Figure out prompts - set u_prompt [find userprompt $router] - if { "$u_prompt" == "" } { - set u_prompt "(\[Uu]sername|Login|login|user name|User|User name):" - } else { - set u_prompt [join [lindex $u_prompt 0] ""] - } - set p_prompt [find passprompt $router] - if { "$p_prompt" == "" } { - set p_prompt "(\[Pp]assword|passwd|Enter password for \[^ :]+):" - } else { - set p_prompt [join [lindex $p_prompt 0] ""] - } - set e_prompt [find enableprompt $router] - if { "$e_prompt" == "" } { - set e_prompt "\[Pp]assword:" - } else { - set e_prompt [join [lindex $e_prompt 0] ""] - } - - # Figure out identity file to use - set identfile [join [lindex [find identity $router] 0] ""] - - # Figure out passphrase to use - if {[info exists avpassphrase]} { - set passphrase $avpassphrase - } else { - set passphrase [join [lindex [find passphrase $router] 0] ""] - } - if { ! [string length "$passphrase"]} { - set passphrase $passwd - } - - # Figure out cypher type - if {[info exists cypher]} { - # command line cypher type - set cyphertype $cypher - } else { - set cyphertype [find cyphertype $router] - if { "$cyphertype" == "" } { set cyphertype "3des" } - } - - # Figure out connection method - set cmethod [find method $router] - if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} } - - # Figure out the SSH executable name - set sshcmd [join [lindex [find sshcmd $router] 0] ""] - if { "$sshcmd" == "" } { set sshcmd {ssh} } - - - # Login to the router - if {[login $router $ruser $userpswd $passwd $enapasswd $cmethod $cyphertype $identfile]} { - incr exitval - # if login failed or rsh was unsuccessful, move on to the next device - continue - } - # Figure out the prompt. - if { [regexp -- "(#| \\(enable\\))" $prompt_match junk] == 1 } { - set enable 0 - } - - # Disable smart and interactive before send other commands - # (MA5600 and similar only?) - # Also disable log junk being sent to terminal - if { [string compare "cmw" "$platform"] } { - send -h "undo smart\r" - expect -re $prompt {} - send -h "undo interactive\r" - expect -re $prompt {} - send -h "undo terminal monitor\r" - expect -re $prompt {} - } - - if { $enable } { - if {[do_enable $enauser $enapasswd]} { - if { $do_command || $do_script } { - incr exitval - catch {close}; catch {wait}; - continue - } - } - } - # we are logged in, now figure out the full prompt - send "\r" - regsub -all {^(\^*)(.*)} $prompt {\2} reprompt - expect { - -re "\[\r\n]+" { exp_continue; } - -re "^(.+\[:.])1 ($reprompt)" { # 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) - regsub -all "^\\\* " $expect_out(1,string) {} junk - regsub -all "\[\]\[\(\)]" $junk {\\&} junk; - set prompt ".? ?$junk\[0-9]+ $expect_out(2,string)"; - set platform "extreme" - } - -re "^.+$reprompt" { set junk $expect_out(0,string); - regsub -all "\[\]\[\(\)+]" $junk {\\&} prompt; - } - } - if { $do_command || $do_script } { - if { [string compare "extreme" "$platform"] } { - # If the prompt is (enable), then we are on a switch and the - # command is "set length 0"; otherwise its "terminal length 0". - if [regexp -- ".*> .*enable" "$prompt"] { - send "set length 0\r" - expect -re $prompt {} - send "set width 132\r" - expect -re $prompt {} - send "set logging session disable\r" - } else { - send "terminal length 0\r" - expect -re $prompt {} - send "terminal width 132\r" - } - expect -re $prompt {} - } elseif { [string compare "cmw" "$platform"] } { - # Turn session paging off - # Comware 5/7 only. - # Comware 3 models have a screen-length command that only works on - # a vty basis - send -h "screen-length disable\r" - expect -re $prompt {} - } else { - send "disable clipaging\r" - expect -re $prompt {} - } - } - if { $do_command } { - if {[run_commands $prompt $command]} { - incr exitval - continue - } - } elseif { $do_script } { - source $sfile - catch {close}; - } else { - label $router - log_user 1 - interact - } - - # End of for each router - catch {wait}; - sleep 0.3 -} -exit $exitval Property changes on: head/net-mgmt/rancid3/files/cmwlogin ___________________________________________________________________ Deleted: fbsd:nokeywords ## -1 +0,0 ## -yes \ No newline at end of property Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/net-mgmt/rancid3/files/cmw.pm =================================================================== --- head/net-mgmt/rancid3/files/cmw.pm (revision 430722) +++ head/net-mgmt/rancid3/files/cmw.pm (nonexistent) @@ -1,525 +0,0 @@ -package cmw; -## -## $Id: cmw.pm.in 3000 2015-01-06 18:47:49Z heas $ -## -## rancid 3.1.99 -## Copyright (c) 1997-2015 by Terrapin Communications, Inc. -## All rights reserved. -## -## This code is derived from software contributed to and maintained by -## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan, -## Pete Whiting, Austin Schutz, and Andrew Fort. -## -## Redistribution and use in source and binary forms, with or without -## modification, are permitted provided that the following conditions -## are met: -## 1. Redistributions of source code must retain the above copyright -## notice, this list of conditions and the following disclaimer. -## 2. Redistributions in binary form must reproduce the above copyright -## notice, this list of conditions and the following disclaimer in the -## documentation and/or other materials provided with the distribution. -## 3. All advertising materials mentioning features or use of this software -## must display the following acknowledgement: -## This product includes software developed by Terrapin Communications, -## Inc. and its contributors for RANCID. -## 4. Neither the name of Terrapin Communications, Inc. nor the names of its -## contributors may be used to endorse or promote products derived from -## this software without specific prior written permission. -## 5. It is requested that non-binding fixes and modifications be contributed -## back to Terrapin Communications, Inc. -## -## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS -## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS -## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -## POSSIBILITY OF SUCH DAMAGE. -# -# RANCID - Really Awesome New Cisco confIg Differ -# -# cmw.pm - Comware (Huawei/H3C/3com/HP) rancid procedures -# -# https://sites.google.com/site/jrbinks/code/rancid/cmwrancid - -use 5.010; -use strict 'vars'; -use warnings; -no warnings 'uninitialized'; -require(Exporter); -our @ISA = qw(Exporter); - -use rancid 3.1.99; - -our $login; - -@ISA = qw(Exporter rancid main); -#XXX @Exporter::EXPORT = qw($VERSION @commandtable %commands @commands); - -# XXX -#our @EXPORT = qw(iproutesort iprouteval); - -# load-time initialization -sub import { - 0; -} - -# post-open(collection file) initialization -sub init { - $login = "cmwlogin"; - # add content lines and separators - ProcessHistory("","","","!RANCID-CONTENT-TYPE: $devtype\n!\n"); - - 0; -} - -# main loop of input of device output -sub inloop { - my($INPUT, $OUTPUT) = @_; - my($cmd, $rval); - -TOP: while(<$INPUT>) { - tr/\015//d; - if (/[\]>#]\a?\s*quit/) { - #if (/[>#]\s?exit$/) { - $clean_run = 1; - last; - } - if (/^Error:/) { - print STDOUT ("$host $login error: $_"); - print STDERR ("$host $login error: $_") if ($debug); - $clean_run = 0; - last; - } - while (/[\]>#]\a?\s*($cmds_regexp)\s*$/) { - $cmd = $1; - - if (!defined($prompt)) { - # Extract the prompt: look for something not [ or < at the start - # of the line, until either ] or > or # is reached: - $prompt = ($_ =~ /^([^\]>#]+[\]>]\a?)/)[0]; - $prompt =~ s/([][}{)(\\])/\\$1/g; - print STDERR ("PROMPT MATCH: $prompt\n") if ($debug); - } - print STDERR ("HIT COMMAND:$_") if ($debug); - if (! defined($commands{$cmd})) { - print STDERR "$host: found unexpected command - \"$cmd\"\n"; - $clean_run = 0; - last TOP; - } - $rval = &{$commands{$cmd}}($INPUT, $OUTPUT, $cmd); - delete($commands{$cmd}); - if ($rval == -1) { - $clean_run = 0; - last TOP; - } - } - } -} - -# dummy function -sub DoNothing {print STDOUT;} - -# This is a sort routine that will sort on the -# ip route when the ip route is anywhere in -# the strings. -sub iproutesort { - my(%lines) = @_; - my($i) = 0; - my(@sorted_lines); - foreach my $iproute (sort sortbyiproute keys %lines) { - $sorted_lines[$i] = $lines{$iproute}; - $i++; - } - @sorted_lines; -} - -## XXX Re-evaluate based on new routines, and consider IPv6: -# These two routines will sort based upon IP route -sub iprouteval { - my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)/(\d+)$#); - $a[4] + ($a[3] + 256 * ($a[2] + 256 * ($a[1] + 256 * $a[0]))); -} - -sub sortbyiproute { - &iprouteval($a) <=> &iprouteval($b); -} - -# Clean up lines on input, particularly ANSI characters as a result -# of us not being able to turn off per-session terminal paging -sub filter_lines { - my ($l) = (@_); - - #s/^\033\[42D +\033\[42D(.+)$/$1/; - #s/\033\133\064\062\104\s*\033\133\064\062\104//g; - $l =~ s/\033\133\064\062\104\s+\033\133\064\062\104//g; - $l =~ s/\033\133\061\066\104\s+\033\133\061\066\104//g; - $l =~ s/\033\133\064\062\104//g; - $l =~ s/\033\133\061\062\104//g; - $l =~ s/.*\[37D(.*)/$1/g; # MA5600 - # Probably not needed: - $l =~ s/\s*---- More ----\s*//; - $l =~ s/^ //; # Comware7 - $l =~ s/Synchronization is finished.//g; - return $l; -} - -# Some commands are not supported on some models or versions -# of code. -# Remove the associated error messages, and rancid will ensure that -# these are not treated as "missed" commands -sub command_not_valid { - my ($l) = (@_); - - if ( $l =~ - /% Too many parameters found at '\^' position/ || - /% Unrecognized command found at '\^' position/ || - /% Incomplete command found at '\^' position./ || - /(% )?Wrong parameter found at '\^' position/ || - /% Wrong device .+/ - ) { - return(1); - } else { - return(0); - } -} - -# Some commands are not authorized under the current -# user's permissions -sub command_not_auth { - my ($l) = (@_); - - if ( $l =~ - /Permission denied\./ - ) { - return(1); - } else { - return(0); - } -} - -# Some output lines are always skipped -sub skip_pattern { - my ($l) = (@_); - - if ( $l =~ - /^\s+\^$/ || - /^$/ - ) { - return(1); - } else { - return(0); - } -} - -sub DisplayFib { - - my($INPUT, $OUTPUT, $cmd) = @_; - my($dest, $nexthop, $flag, $outint, $label); - print STDERR " In DisplayFib: $_" if ($debug); - - chomp; - - # Display the command we're processing in the output: - ProcessHistory("FIB","","","!\n! '$cmd':\n!\n"); - - while (<$INPUT>) { - tr/\015//d; - last if(/^\s*$prompt/); - chomp; - $_ = filter_lines($_); - - return(1) if command_not_valid($_); - return(-1) if command_not_auth($_); - next if skip_pattern($_); - - next if /^Destination count: \d+ FIB entry count: \d+/; - - # Chop out some detail that changes over time (Comware 3): - s/(\s+)TimeStamp\s+/$1/; # TimeStamp column heading - - ProcessHistory("FIB","","","! $_\n"); - - if ( m,Destination/Mask, ) { - while (<$INPUT>) { - tr/\015//d; - last if(/^\s*$prompt/); - chomp; - $_ = filter_lines($_); - - # Chop out some detail that changes over time (Comware 3): - s/(\s+)t\[\d+\]\s+/$1/; # TimeStamp data - - # "display fib" on comware7 shows host entries for things - # learned via arp too. For a distribution router, that's all - # the devices on subnets routed by it! - # If we filter out all "UH" entries that are NOT InLoop, we - # get acceptable output. - # - # So we want to keep: - # - # 0.0.0.0/32 127.0.0.1 UH InLoop0 Null - # - # but reject: - # - # 130.159.44.161/32 130.159.44.161 UH Vlan44 Null - # - # However I've a feeling that this is a problematic - # solution, and some object to the notion that rancid - # should be representing such potentially dynamic data in - # the first place, which is why we created the - # $display_fib flag for rancid 2, and in rancid 3 one - # can modify the command table in rancid.types.conf - - ($dest, $nexthop, $flag, $outint, $label) = split; - next if ( $flag eq 'UH' && $outint !~ /InLoop/ ); - #ProcessHistory("FIB", "cmw::iproutesort", "$dest", "! $_\n"); - ProcessHistory("FIB", "ipsort", "$dest", "! $_\n"); - } - - ProcessHistory("FIB", "", "", "!\n"); - - # return here to ensure that we don't keep swallowing the - # next command's output by returning to the surrounding - # while loop - return(0); - } - } - return(0); -} - -sub DisplayIPRoutes { - my($INPUT, $OUTPUT, $cmd) = @_; - my($key,$line,$spaces); - print STDERR " In DisplayIPRoutes: $_" if ($debug); - - chomp; - - # Display the command we're processing in the output: - ProcessHistory("IPR","","","!\n! '$cmd':\n!\n"); - - while (<$INPUT>) { - tr/\015//d; - last if(/^\s*$prompt/); - chomp; - - $_ = filter_lines($_); - return(1) if command_not_valid($_); - return(-1) if command_not_auth($_); - next if skip_pattern($_); - - ProcessHistory("IPR","","","! $_\n"); - - if ( m,Destination/Mask, ) { - my $lastkey = ""; - my $lastspaces = ""; - while (<$INPUT>) { - tr/\015//d; - last if(/^\s*$prompt/); - chomp; - $_ = filter_lines($_); - - # If the key is blank, indicating multiple nexthops for - # a particular route, then we use the previous one - if ( m/^\s+(.+)/ ) { - $key = $lastkey; - $line = $key . $lastspaces . $1; - #ProcessHistory("IPR", "cmw::iproutesort", "$key", "! $line\n"); - ProcessHistory("IPR", "ipsort", "$key", "! $line\n"); - } - if ( m/^(\S+)(\s+).+/ ) { - $key = $1; - $line = $_; - $spaces = $2; - #ProcessHistory("IPR", "cmw::iproutesort", "$key", "! $line\n"); - ProcessHistory("IPR", "ipsort", "$key", "! $line\n"); - - # Remember these, we may need them on the next pass - $lastkey = $key; - $lastspaces = $spaces; - } - } - - ProcessHistory("IPR", "", "", "!\n"); - - # return here to ensure that we don't keep swallowing the - # next command's output by returning to the surrounding - # while loop - return(0); - } - } - return(0); -} - -## This routine processes general output of "display" commands -sub CommentOutput { - my($INPUT, $OUTPUT, $cmd) = @_; - print STDERR " In CommentOutput: $_" if ($debug); - - chomp; - - # Display the command we're processing in the output: - ProcessHistory("COMMENTS", "", "", "!\n! '$cmd':\n!\n"); - - while (<$INPUT>) { - tr/\015//d; - - # If we find the prompt, we're done - # Ordinarily this matches from the start of the line, however - # we've seen circumstances at least in Comware7 where the - # prompt is preceded by whitespace, like so: - # ^M^M ^Mdisplay boot-loader^M - last if(/^\s*$prompt/); - chomp; - - # filter out some junk - $_ = filter_lines($_); - return(1) if command_not_valid($_); - return(-1) if command_not_auth($_); - next if skip_pattern($_); - - # Now we skip or modify some lines from various commands to - # remove irrelevant content, or to avoid insignificant diffs - - # 'display local-user': - s/\s+Current AccessNum:.+$//; - - # 'display version': - next if (/^(Uptime is \d|.+ [Uu]ptime is \d).+$/); - # No longer necessary since skipping the whole Uptime line: - # Mangle these lines: - #s/(.*)[Uu]ptime.*.weeks.*.days*.*hours*.*minutes*(.*)/$1 $2/; - #s/(.*)[Uu]ptime.*days*.*hours*.*minutes*(.*)/$1 $2/; - - # MSRs display a 'last reboot' time, but sometimes the seconds - # vary by one or two (presumably internal rounding), so simply make - # the last digit a fixed '0'. It would probably be safer to make - # the last two digits a fixed '00'. - # (Thx Alexander Belokopytov) - s/(^Last reboot.+)\d$/${1}0/; - - # 'dir ' commands - if ( $cmd =~ /^dir / ) { - # First field is just an index number, chop it out - s/^\s+\d+\s+(.+)/ $1/; - # Remove filenames that are updated frequently - next if ( - /logfile\.log$/ || - /lauth\.dat$/ || - /ifindex\.dat$/ || - /startup\.mdb$/ || - /private-data\.txt$/ || - /.+ KB total \(.+ KB free/ || - /.+ KB total \(.+ KB free/ || - /\.trash/ - ); - } - - # 'display ospf brief'/'display ospf' - if ( $cmd =~ 'display ospf( brief)?' ) { - #next if (/^(Ospf is not enabled yet|Info: OSPF routing process is not enabled|The feature OSPF has not been enabled.).+$/); - next if (/^\s+SPF (Computation|Scheduled|calculation) Count:.+$/i); - } - - if ( $cmd eq 'display power' ) { - next if (/^(\s+Input Power).+$/); - } - - if ( $cmd eq 'display poe powersupply' ) { - next if (/^(PSE Total Power Consumption|PSE Available Power|PSE Peak Value|PSE Average Value).+$/); - } - - if ( $cmd eq 'display ntp-service status' ) { - next unless m/(Clock status|Clock stratum|Reference clock ID)/i; - } - - if ( $cmd eq 'display transceiver interface' ) { - s/^(\S+ transceiver information:).+$/$1/; # filter random garbage - s/^Error: The transceiver is absent.$/ No transceiver present./; - s/^Error: The combo port is inactive.$/ Inactive combo port./; - } - - # Add the processed lines to the output buffer: - ProcessHistory("COMMENTS","","","! $_\n"); - } - - # Add a blank comment line to the output buffer - ProcessHistory("COMMENTS", "", "", "!\n"); - return(0); -} - -## This routine processes a "display current" -sub DisplayCurrent { - my($INPUT, $OUTPUT, $cmd) = @_; - print STDERR " In DisplayCurrent: $_" if ($debug); - - - while (<$INPUT>) { - tr/\015//d; - last if(/^\s*$prompt/); - chomp; - - $_ = filter_lines($_); - return(1) if command_not_valid($_); - return(-1) if command_not_auth($_); - next if skip_pattern($_); - - return(0) if ($found_end); - - # Filter out some sensitive data: - if ( $filter_commstr && - /^ ?(snmp-agent (target-host.+securityname|usm-user|community (read|write)) )(\S+)/ - ) { - ProcessHistory("","","","! $1$'\n"); - next; - } - if ( $filter_pwds >= 1 && - /^ ?(password (?:simple|cipher|hash) )(\S+)/ || - /^ ?(super password( role level-\d)( level \d)? (cipher|simple|hash) )(\S+)/ || - /^ ?(set authentication password (cipher|simple|hash) )(\S+)/ || - /^ ?(key (?:authentication|accounting) )(\S+)/ - ) { - ProcessHistory("","","","! $1$'\n"); - next; - } - - # filter ssh public keys of devices connected to from this device - if (/^ ?(public-key-code begin)/ && - $filter_pwds >= 2) { - ProcessHistory("","","","!$1\n"); - ProcessHistory("","","","! \n"); - while (<$INPUT>) { - tr/\015//d; - next if /^$/; - next if /^\s+[[:xdigit:]]$/; - if (/(^ public-key-code end)/) { - ProcessHistory("","","","!$1\n"); - last; - } - } - next; - } - - # Filter mac addresses dynamically added to config - next if (/^ ?mac-address security.+$/); - - ProcessHistory("", "", "", "$_\n"); - - # end of config - if (/^return/) { - $found_end = 1; - return(0); - } - } - return(0); -} - -1; - -__END__ - - Property changes on: head/net-mgmt/rancid3/files/cmw.pm ___________________________________________________________________ Deleted: fbsd:nokeywords ## -1 +0,0 ## -yes \ No newline at end of property Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/net-mgmt/rancid3/files/cmw.pm.in =================================================================== --- head/net-mgmt/rancid3/files/cmw.pm.in (nonexistent) +++ head/net-mgmt/rancid3/files/cmw.pm.in (revision 430723) @@ -0,0 +1,525 @@ +package cmw; +## +## $Id: cmw.pm.in 3000 2015-01-06 18:47:49Z heas $ +## +## rancid 3.1.99 +## Copyright (c) 1997-2015 by Terrapin Communications, Inc. +## All rights reserved. +## +## This code is derived from software contributed to and maintained by +## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan, +## Pete Whiting, Austin Schutz, and Andrew Fort. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions +## are met: +## 1. Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## 2. Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in the +## documentation and/or other materials provided with the distribution. +## 3. All advertising materials mentioning features or use of this software +## must display the following acknowledgement: +## This product includes software developed by Terrapin Communications, +## Inc. and its contributors for RANCID. +## 4. Neither the name of Terrapin Communications, Inc. nor the names of its +## contributors may be used to endorse or promote products derived from +## this software without specific prior written permission. +## 5. It is requested that non-binding fixes and modifications be contributed +## back to Terrapin Communications, Inc. +## +## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS +## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS +## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +## POSSIBILITY OF SUCH DAMAGE. +# +# RANCID - Really Awesome New Cisco confIg Differ +# +# cmw.pm - Comware (Huawei/H3C/3com/HP) rancid procedures +# +# https://sites.google.com/site/jrbinks/code/rancid/cmwrancid + +use 5.010; +use strict 'vars'; +use warnings; +no warnings 'uninitialized'; +require(Exporter); +our @ISA = qw(Exporter); + +use rancid 3.1.99; + +our $login; + +@ISA = qw(Exporter rancid main); +#XXX @Exporter::EXPORT = qw($VERSION @commandtable %commands @commands); + +# XXX +#our @EXPORT = qw(iproutesort iprouteval); + +# load-time initialization +sub import { + 0; +} + +# post-open(collection file) initialization +sub init { + $login = "cmwlogin"; + # add content lines and separators + ProcessHistory("","","","!RANCID-CONTENT-TYPE: $devtype\n!\n"); + + 0; +} + +# main loop of input of device output +sub inloop { + my($INPUT, $OUTPUT) = @_; + my($cmd, $rval); + +TOP: while(<$INPUT>) { + tr/\015//d; + if (/[\]>#]\a?\s*quit/) { + #if (/[>#]\s?exit$/) { + $clean_run = 1; + last; + } + if (/^Error:/) { + print STDOUT ("$host $login error: $_"); + print STDERR ("$host $login error: $_") if ($debug); + $clean_run = 0; + last; + } + while (/[\]>#]\a?\s*($cmds_regexp)\s*$/) { + $cmd = $1; + + if (!defined($prompt)) { + # Extract the prompt: look for something not [ or < at the start + # of the line, until either ] or > or # is reached: + $prompt = ($_ =~ /^([^\]>#]+[\]>]\a?)/)[0]; + $prompt =~ s/([][}{)(\\])/\\$1/g; + print STDERR ("PROMPT MATCH: $prompt\n") if ($debug); + } + print STDERR ("HIT COMMAND:$_") if ($debug); + if (! defined($commands{$cmd})) { + print STDERR "$host: found unexpected command - \"$cmd\"\n"; + $clean_run = 0; + last TOP; + } + $rval = &{$commands{$cmd}}($INPUT, $OUTPUT, $cmd); + delete($commands{$cmd}); + if ($rval == -1) { + $clean_run = 0; + last TOP; + } + } + } +} + +# dummy function +sub DoNothing {print STDOUT;} + +# This is a sort routine that will sort on the +# ip route when the ip route is anywhere in +# the strings. +sub iproutesort { + my(%lines) = @_; + my($i) = 0; + my(@sorted_lines); + foreach my $iproute (sort sortbyiproute keys %lines) { + $sorted_lines[$i] = $lines{$iproute}; + $i++; + } + @sorted_lines; +} + +## XXX Re-evaluate based on new routines, and consider IPv6: +# These two routines will sort based upon IP route +sub iprouteval { + my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)/(\d+)$#); + $a[4] + ($a[3] + 256 * ($a[2] + 256 * ($a[1] + 256 * $a[0]))); +} + +sub sortbyiproute { + &iprouteval($a) <=> &iprouteval($b); +} + +# Clean up lines on input, particularly ANSI characters as a result +# of us not being able to turn off per-session terminal paging +sub filter_lines { + my ($l) = (@_); + + #s/^\033\[42D +\033\[42D(.+)$/$1/; + #s/\033\133\064\062\104\s*\033\133\064\062\104//g; + $l =~ s/\033\133\064\062\104\s+\033\133\064\062\104//g; + $l =~ s/\033\133\061\066\104\s+\033\133\061\066\104//g; + $l =~ s/\033\133\064\062\104//g; + $l =~ s/\033\133\061\062\104//g; + $l =~ s/.*\[37D(.*)/$1/g; # MA5600 + # Probably not needed: + $l =~ s/\s*---- More ----\s*//; + $l =~ s/^ //; # Comware7 + $l =~ s/Synchronization is finished.//g; + return $l; +} + +# Some commands are not supported on some models or versions +# of code. +# Remove the associated error messages, and rancid will ensure that +# these are not treated as "missed" commands +sub command_not_valid { + my ($l) = (@_); + + if ( $l =~ + /% Too many parameters found at '\^' position/ || + /% Unrecognized command found at '\^' position/ || + /% Incomplete command found at '\^' position./ || + /(% )?Wrong parameter found at '\^' position/ || + /% Wrong device .+/ + ) { + return(1); + } else { + return(0); + } +} + +# Some commands are not authorized under the current +# user's permissions +sub command_not_auth { + my ($l) = (@_); + + if ( $l =~ + /Permission denied\./ + ) { + return(1); + } else { + return(0); + } +} + +# Some output lines are always skipped +sub skip_pattern { + my ($l) = (@_); + + if ( $l =~ + /^\s+\^$/ || + /^$/ + ) { + return(1); + } else { + return(0); + } +} + +sub DisplayFib { + + my($INPUT, $OUTPUT, $cmd) = @_; + my($dest, $nexthop, $flag, $outint, $label); + print STDERR " In DisplayFib: $_" if ($debug); + + chomp; + + # Display the command we're processing in the output: + ProcessHistory("FIB","","","!\n! '$cmd':\n!\n"); + + while (<$INPUT>) { + tr/\015//d; + last if(/^\s*$prompt/); + chomp; + $_ = filter_lines($_); + + return(1) if command_not_valid($_); + return(-1) if command_not_auth($_); + next if skip_pattern($_); + + next if /^Destination count: \d+ FIB entry count: \d+/; + + # Chop out some detail that changes over time (Comware 3): + s/(\s+)TimeStamp\s+/$1/; # TimeStamp column heading + + ProcessHistory("FIB","","","! $_\n"); + + if ( m,Destination/Mask, ) { + while (<$INPUT>) { + tr/\015//d; + last if(/^\s*$prompt/); + chomp; + $_ = filter_lines($_); + + # Chop out some detail that changes over time (Comware 3): + s/(\s+)t\[\d+\]\s+/$1/; # TimeStamp data + + # "display fib" on comware7 shows host entries for things + # learned via arp too. For a distribution router, that's all + # the devices on subnets routed by it! + # If we filter out all "UH" entries that are NOT InLoop, we + # get acceptable output. + # + # So we want to keep: + # + # 0.0.0.0/32 127.0.0.1 UH InLoop0 Null + # + # but reject: + # + # 130.159.44.161/32 130.159.44.161 UH Vlan44 Null + # + # However I've a feeling that this is a problematic + # solution, and some object to the notion that rancid + # should be representing such potentially dynamic data in + # the first place, which is why we created the + # $display_fib flag for rancid 2, and in rancid 3 one + # can modify the command table in rancid.types.conf + + ($dest, $nexthop, $flag, $outint, $label) = split; + next if ( $flag eq 'UH' && $outint !~ /InLoop/ ); + #ProcessHistory("FIB", "cmw::iproutesort", "$dest", "! $_\n"); + ProcessHistory("FIB", "ipsort", "$dest", "! $_\n"); + } + + ProcessHistory("FIB", "", "", "!\n"); + + # return here to ensure that we don't keep swallowing the + # next command's output by returning to the surrounding + # while loop + return(0); + } + } + return(0); +} + +sub DisplayIPRoutes { + my($INPUT, $OUTPUT, $cmd) = @_; + my($key,$line,$spaces); + print STDERR " In DisplayIPRoutes: $_" if ($debug); + + chomp; + + # Display the command we're processing in the output: + ProcessHistory("IPR","","","!\n! '$cmd':\n!\n"); + + while (<$INPUT>) { + tr/\015//d; + last if(/^\s*$prompt/); + chomp; + + $_ = filter_lines($_); + return(1) if command_not_valid($_); + return(-1) if command_not_auth($_); + next if skip_pattern($_); + + ProcessHistory("IPR","","","! $_\n"); + + if ( m,Destination/Mask, ) { + my $lastkey = ""; + my $lastspaces = ""; + while (<$INPUT>) { + tr/\015//d; + last if(/^\s*$prompt/); + chomp; + $_ = filter_lines($_); + + # If the key is blank, indicating multiple nexthops for + # a particular route, then we use the previous one + if ( m/^\s+(.+)/ ) { + $key = $lastkey; + $line = $key . $lastspaces . $1; + #ProcessHistory("IPR", "cmw::iproutesort", "$key", "! $line\n"); + ProcessHistory("IPR", "ipsort", "$key", "! $line\n"); + } + if ( m/^(\S+)(\s+).+/ ) { + $key = $1; + $line = $_; + $spaces = $2; + #ProcessHistory("IPR", "cmw::iproutesort", "$key", "! $line\n"); + ProcessHistory("IPR", "ipsort", "$key", "! $line\n"); + + # Remember these, we may need them on the next pass + $lastkey = $key; + $lastspaces = $spaces; + } + } + + ProcessHistory("IPR", "", "", "!\n"); + + # return here to ensure that we don't keep swallowing the + # next command's output by returning to the surrounding + # while loop + return(0); + } + } + return(0); +} + +## This routine processes general output of "display" commands +sub CommentOutput { + my($INPUT, $OUTPUT, $cmd) = @_; + print STDERR " In CommentOutput: $_" if ($debug); + + chomp; + + # Display the command we're processing in the output: + ProcessHistory("COMMENTS", "", "", "!\n! '$cmd':\n!\n"); + + while (<$INPUT>) { + tr/\015//d; + + # If we find the prompt, we're done + # Ordinarily this matches from the start of the line, however + # we've seen circumstances at least in Comware7 where the + # prompt is preceded by whitespace, like so: + # ^M^M ^Mdisplay boot-loader^M + last if(/^\s*$prompt/); + chomp; + + # filter out some junk + $_ = filter_lines($_); + return(1) if command_not_valid($_); + return(-1) if command_not_auth($_); + next if skip_pattern($_); + + # Now we skip or modify some lines from various commands to + # remove irrelevant content, or to avoid insignificant diffs + + # 'display local-user': + s/\s+Current AccessNum:.+$//; + + # 'display version': + next if (/^(Uptime is \d|.+ [Uu]ptime is \d).+$/); + # No longer necessary since skipping the whole Uptime line: + # Mangle these lines: + #s/(.*)[Uu]ptime.*.weeks.*.days*.*hours*.*minutes*(.*)/$1 $2/; + #s/(.*)[Uu]ptime.*days*.*hours*.*minutes*(.*)/$1 $2/; + + # MSRs display a 'last reboot' time, but sometimes the seconds + # vary by one or two (presumably internal rounding), so simply make + # the last digit a fixed '0'. It would probably be safer to make + # the last two digits a fixed '00'. + # (Thx Alexander Belokopytov) + s/(^Last reboot.+)\d$/${1}0/; + + # 'dir ' commands + if ( $cmd =~ /^dir / ) { + # First field is just an index number, chop it out + s/^\s+\d+\s+(.+)/ $1/; + # Remove filenames that are updated frequently + next if ( + /logfile\.log$/ || + /lauth\.dat$/ || + /ifindex\.dat$/ || + /startup\.mdb$/ || + /private-data\.txt$/ || + /.+ KB total \(.+ KB free/ || + /.+ KB total \(.+ KB free/ || + /\.trash/ + ); + } + + # 'display ospf brief'/'display ospf' + if ( $cmd =~ 'display ospf( brief)?' ) { + #next if (/^(Ospf is not enabled yet|Info: OSPF routing process is not enabled|The feature OSPF has not been enabled.).+$/); + next if (/^\s+SPF (Computation|Scheduled|calculation) Count:.+$/i); + } + + if ( $cmd eq 'display power' ) { + next if (/^(\s+Input Power).+$/); + } + + if ( $cmd eq 'display poe powersupply' ) { + next if (/^(PSE Total Power Consumption|PSE Available Power|PSE Peak Value|PSE Average Value).+$/); + } + + if ( $cmd eq 'display ntp-service status' ) { + next unless m/(Clock status|Clock stratum|Reference clock ID)/i; + } + + if ( $cmd eq 'display transceiver interface' ) { + s/^(\S+ transceiver information:).+$/$1/; # filter random garbage + s/^Error: The transceiver is absent.$/ No transceiver present./; + s/^Error: The combo port is inactive.$/ Inactive combo port./; + } + + # Add the processed lines to the output buffer: + ProcessHistory("COMMENTS","","","! $_\n"); + } + + # Add a blank comment line to the output buffer + ProcessHistory("COMMENTS", "", "", "!\n"); + return(0); +} + +## This routine processes a "display current" +sub DisplayCurrent { + my($INPUT, $OUTPUT, $cmd) = @_; + print STDERR " In DisplayCurrent: $_" if ($debug); + + + while (<$INPUT>) { + tr/\015//d; + last if(/^\s*$prompt/); + chomp; + + $_ = filter_lines($_); + return(1) if command_not_valid($_); + return(-1) if command_not_auth($_); + next if skip_pattern($_); + + return(0) if ($found_end); + + # Filter out some sensitive data: + if ( $filter_commstr && + /^ ?(snmp-agent (target-host.+securityname|usm-user|community (read|write)) )(\S+)/ + ) { + ProcessHistory("","","","! $1$'\n"); + next; + } + if ( $filter_pwds >= 1 && + /^ ?(password (?:simple|cipher|hash) )(\S+)/ || + /^ ?(super password( role level-\d)( level \d)? (cipher|simple|hash) )(\S+)/ || + /^ ?(set authentication password (cipher|simple|hash) )(\S+)/ || + /^ ?(key (?:authentication|accounting) )(\S+)/ + ) { + ProcessHistory("","","","! $1$'\n"); + next; + } + + # filter ssh public keys of devices connected to from this device + if (/^ ?(public-key-code begin)/ && + $filter_pwds >= 2) { + ProcessHistory("","","","!$1\n"); + ProcessHistory("","","","! \n"); + while (<$INPUT>) { + tr/\015//d; + next if /^$/; + next if /^\s+[[:xdigit:]]$/; + if (/(^ public-key-code end)/) { + ProcessHistory("","","","!$1\n"); + last; + } + } + next; + } + + # Filter mac addresses dynamically added to config + next if (/^ ?mac-address security.+$/); + + ProcessHistory("", "", "", "$_\n"); + + # end of config + if (/^return/) { + $found_end = 1; + return(0); + } + } + return(0); +} + +1; + +__END__ + + Property changes on: head/net-mgmt/rancid3/files/cmw.pm.in ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/net-mgmt/rancid3/files/cmwlogin.in =================================================================== --- head/net-mgmt/rancid3/files/cmwlogin.in (nonexistent) +++ head/net-mgmt/rancid3/files/cmwlogin.in (revision 430723) @@ -0,0 +1,1043 @@ +#! /usr/local/bin/expect -- +## +## $Id: cmwlogin 3022 2015-01-13 20:00:00Z heas $ +## +## rancid 3.1.99 +## Copyright (c) 1997-2015 by Terrapin Communications, Inc. +## All rights reserved. +## +## This code is derived from software contributed to and maintained by +## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan, +## Pete Whiting, Austin Schutz, and Andrew Fort. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions +## are met: +## 1. Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## 2. Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in the +## documentation and/or other materials provided with the distribution. +## 3. All advertising materials mentioning features or use of this software +## must display the following acknowledgement: +## This product includes software developed by Terrapin Communications, +## Inc. and its contributors for RANCID. +## 4. Neither the name of Terrapin Communications, Inc. nor the names of its +## contributors may be used to endorse or promote products derived from +## this software without specific prior written permission. +## 5. It is requested that non-binding fixes and modifications be contributed +## back to Terrapin Communications, Inc. +## +## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS +## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS +## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +## POSSIBILITY OF SUCH DAMAGE. +# +# The expect login scripts were based on Erik Sherk's gwtn, by permission. +# +# cwlogin - Comware login +# +# Most options are intuitive for logging into a Comware device. +# The default is to enable (thus -noenable). Some folks have +# setup tacacs to have a user login at priv-lvl = 3 (enabled) +# so the -autoenable flag was added for this case (don't go through +# the process of enabling and the prompt will be the "#" prompt. +# The default username password is the same as the vty password. +# + +# Usage line +set usage "Usage: $argv0 \[-dSV\] \[-autoenable\] \[-noenable\] \[-c command\] \ +\[-Evar=x\] \[-e enable-password\] \[-f cloginrc-file\] \[-p user-password\] \ +\[-r passphrase\] \[-s script-file\] \[-t timeout\] \[-u username\] \ +\[-v vty-password\] \[-w enable-username\] \[-x command-file\] \[-P platform\] \ +\[-y ssh_cypher_type\] router \[router...\]\n" + +# env(CLOGIN) may contain: +# x == do not set xterm banner or name + +# Password file +set password_file $env(HOME)/.cloginrc +# Default is to login to the router +set do_command 0 +set do_script 0 +# The default is to automatically enable +set avenable 1 +# The default is that you login non-enabled (tacacs can have you login already +# enabled) +set avautoenable 0 +# 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 +# Save config, if prompted +set do_saveconfig 0 +# Sometimes routers take awhile to answer (the default is 10 sec) +set timeoutdflt 45 +# Some CLIs having problems if we write too fast (Extreme, PIX, Cat) +set send_human {.2 .1 .4 .2 1} + +# 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) +} + +# Process the command line +for {set i 0} {$i < $argc} {incr i} { + set arg [lindex $argv $i] + + switch -glob -- $arg { + # Expect debug mode + -d* { + exp_internal 1 + # Username + } -u* { + if {! [regexp .\[uU\](.+) $arg ignore user]} { + incr i + set username [lindex $argv $i] + } + # VTY Password + } -p* { + if {! [regexp .\[pP\](.+) $arg ignore userpasswd]} { + incr i + set userpasswd [lindex $argv $i] + } + set do_passwd 0 + # ssh passphrase + } -r* { + if {! [regexp .\[rR\](.+) $arg ignore passphrase]} { + incr i + set vapassphrase [lindex $argv $i] + } + # VTY Password + } -v* { + if {! [regexp .\[vV\](.+) $arg ignore passwd]} { + incr i + set passwd [lindex $argv $i] + } + set do_passwd 0 + # Version string + } -V* { + send_user "rancid 3.1.99\n" + exit 0 + # Enable Username + } -w* { + if {! [regexp .\[wW\](.+) $arg ignore enauser]} { + incr i + set enausername [lindex $argv $i] + } + # Environment variable to pass to -s scripts + } -E* { + if {[regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} { + set E$varname $varvalue + } else { + send_user "\nError: invalid format for -E in $arg\n" + exit 1 + } + # Enable Password + } -e* { + if {! [regexp .\[e\](.+) $arg ignore enapasswd]} { + incr i + set enapasswd [lindex $argv $i] + } + set do_enapasswd 0 + # Platform + } -P* { + if {! [regexp .\[P\](.+) $arg ignore platform]} { + incr i + set plat [lindex $argv $P] + } + # Command to run. + } -c* { + if {! [regexp .\[cC\](.+) $arg ignore command]} { + incr i + set command [lindex $argv $i] + } + set do_command 1 + # Expect script to run. + } -s* { + if {! [regexp .\[sS\](.+) $arg ignore sfile]} { + incr i + set sfile [lindex $argv $i] + } + if { ! [file readable $sfile] } { + send_user "\nError: Can't read $sfile\n" + exit 1 + } + set do_script 1 + # save config on exit + } -S* { + set do_saveconfig 1 + # 'ssh -c' cypher type + } -y* { + if {! [regexp .\[eE\](.+) $arg ignore cypher]} { + incr i + set cypher [lindex $argv $i] + } + # alternate cloginrc file + } -f* { + if {! [regexp .\[fF\](.+) $arg ignore password_file]} { + incr i + set password_file [lindex $argv $i] + } + # Timeout + } -t* { + if {! [regexp .\[tT\](.+) $arg ignore timeout]} { + incr i + set timeoutdflt [lindex $argv $i] + } + # Command file + } -x* { + if {! [regexp .\[xX\](.+) $arg ignore cmd_file]} { + incr i + set cmd_file [lindex $argv $i] + } + if [catch {set cmd_fd [open $cmd_file r]} reason] { + send_user "\nError: $reason\n" + exit 1 + } + 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 avenable 0 + # Does tacacs automatically enable us? + } -autoenable { + set avautoenable 1 + set avenable 0 + } -* { + send_user "\nError: Unknown argument! $arg\n" + send_user $usage + exit 1 + } default { + break + } + } +} +# Process routers...no routers listed is an error. +if { $i == $argc } { + send_user "\nError: $usage" +} + +# Only be quiet if we are running a script (it can log its output +# on its own) +if { $do_script } { + log_user 0 +} else { + log_user 1 +} + +# +# Done configuration/variable setting. Now run with it... +# + +# Sets Xterm title if interactive...if its an xterm and the user cares +proc label { host } { + global env + # if CLOGIN has an 'x' in it, don't set the xterm name/banner + if [info exists env(CLOGIN)] { + if {[string first "x" $env(CLOGIN)] != -1} { return } + } + # take host from ENV(TERM) + if [info exists env(TERM)] { + 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 * hanky-pie +proc add {var args} { global int_$var ; lappend int_$var $args} +proc include {args} { + global env + regsub -all "(^{|}$)" $args {} args + if { [regexp "^/" $args ignore] == 0 } { + set args $env(HOME)/$args + } + source_password_file $args +} + +proc find {var router} { + upvar int_$var list + if { [info exists list] } { + foreach line $list { + if { [string match -nocase [lindex $line 0] $router] } { + return [lrange $line 1 end] + } + } + } + return {} +} + +# 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 +proc source_password_file { password_file } { + global env + if { ! [file exists $password_file] } { + send_user "\nError: password file ($password_file) does not exist\n" + exit 1 + } + file stat $password_file fileinfo + if { [expr ($fileinfo(mode) & 007)] != 0000 } { + send_user "\nError: $password_file must not be world readable/writable\n" + exit 1 + } + if [catch {source $password_file} reason] { + send_user "\nError: $reason\n" + exit 1 + } +} + +# 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 identfile } { + global command spawn_id in_proc do_command do_script platform passphrase + global prompt prompt_match u_prompt p_prompt e_prompt sshcmd + set in_proc 1 + set uprompt_seen 0 + + # 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 methcmd suffix port + if {"$port" == ""} { + set retval [catch {spawn telnet $router} reason] + } else { + set retval [catch {spawn telnet $router $port} reason] + } + if { $retval } { + send_user "\nError: telnet failed: $reason\n" + return 1 + } + } elseif [string match "ssh*" $prog] { + # ssh to the router & try to login with or without an identfile. + regexp {ssh(:([^[:space:]]+))*} $prog methcmd suffix port + set cmd $sshcmd + if {"$port" != ""} { + set cmd "$cmd -p $port" + } + if {"$identfile" != ""} { + set cmd "$cmd -i $identfile" + } + set retval [catch {eval spawn [split "$cmd -c $cyphertype -x -l $user $router" { }]} reason] + if { $retval } { + send_user "\nError: $cmd failed: $reason\n" + return 1 + } + } elseif ![string compare $prog "rsh"] { + 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; + } + + # handle escaped ;s in commands, and ;; and ^; + regsub -all {([^\\]);;} $command "\\1;\u002;" esccommand + regsub {^;} $esccommand "\u002;" command + set sep "\\1\u001" + regsub -all {([^\\])\;} $command "$sep" esccommand + set sep "\u001" + set commands [split $esccommand $sep] + 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}; catch {wait}; + send_user "\nError: Connection\ + Refused ($prog): $router\n" + set rshfail 1 + } + -re "(Connection closed by|Connection to \[^\n\r]+ closed)" { + catch {close}; catch {wait}; + send_user "\nError: Connection\ + closed ($prog): $router\n" + set rshfail 1 + } + "Host is unreachable" { catch {close}; catch {wait}; + send_user "\nError: Host Unreachable:\ + $router\n" + set rshfail 1 + } + "No address associated with" { + catch {close}; catch {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}; catch {wait}; + send_user "\nError: TIMEOUT reached\n" + set rshfail 1 + } + eof { catch {close}; catch {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 { + send_user "\nError: unknown connection method: $prog\n" + return 1 + } + sleep 0.3 + + # This helps cleanup each expect clause. + expect_after { + timeout { + send_user "\nError: TIMEOUT reached\n" + catch {close}; catch {wait}; + if { $in_proc} { + return 1 + } else { + continue + } + } eof { + send_user "\nError: EOF received\n" + catch {close}; catch {wait}; + if { $in_proc} { + return 1 + } else { + continue + } + } + } + + # Here we get a little tricky. There are several possibilities: + # the router can ask for a username and passwd and then + # talk to the TACACS server to authenticate you, or if the + # 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 { + -re "^<-+ More -+>\[^\n\r]*" { + # ASA will use the pager for long banners + send " "; + exp_continue + } + -re "(Connection refused|Secure connection \[^\n\r]+ refused)" { + catch {close}; catch {wait}; + if !$progs { + send_user "\nError: Connection Refused ($prog): $router\n" + return 1 + } + } + -re "(Connection closed by|Connection to \[^\n\r]+ closed)" { + catch {close}; catch {wait}; + if !$progs { + send_user "\nError: Connection closed ($prog): $router\n" + return 1 + } + } + eof { send_user "\nError: Couldn't login: $router\n"; wait; return 1 } + -nocase "unknown host\r" { + send_user "\nError: Unknown host $router\n"; + catch {close}; catch {wait}; + return 1 + } + "Host is unreachable" { + send_user "\nError: Host Unreachable: $router\n"; + catch {close}; catch {wait}; + return 1 + } + "No address associated with name" { + send_user "\nError: Unknown host $router\n"; + catch {close}; catch {wait}; + return 1 + } + -re "(Host key not found |The authenticity of host .* be established).* \\(yes/no\\)\\?" { + send "yes\r" + send_user "\nHost $router added to the list of known hosts.\n" + exp_continue + } + -re "HOST IDENTIFICATION HAS CHANGED.* \\(yes/no\\)\\?" { + send "no\r" + send_user "\nError: The host key for $router has changed. Update the SSH known_hosts file accordingly.\n" + catch {close}; catch {wait}; + return 1 + } + -re "HOST IDENTIFICATION HAS CHANGED\[^\n\r]+" { + send_user "\nError: The host key for $router has changed. Update the SSH known_hosts file accordingly.\n" + return 1 + } + -re "Offending key for .* \\(yes/no\\)\\?" { + send "no\r" + send_user "\nError: host key mismatch for $router. Update the SSH known_hosts file accordingly.\n" + catch {close}; catch {wait}; + return 1 + } + -re "(denied|Sorry)" { + send_user "\nError: Check your passwd for $router\n" + catch {close}; catch {wait}; return 1 + } + "Login failed" { + send_user "\nError: Check your passwd for $router\n" + catch {close}; catch {wait}; return 1 + } + -re "% (Bad passwords|Authentication failed)" { + send_user "\nError: Check your passwd for $router\n" + catch {close}; catch {wait}; return 1 + } + "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 + } + -re "Last login:" { + exp_continue + } + -re "Press the key \[^\r\n]+\[\r\n]+" { + exp_continue + } + -re "@\[^\r\n]+ $p_prompt" { + # ssh pwd prompt + sleep 1 + send -- "$userpswd\r" + exp_continue + } + -re "Enter passphrase.*: " { + # sleep briefly to allow time for stty -echo + sleep .3 + send -- "$passphrase\r" + exp_continue + } + -re "$u_prompt" { + send -- "$user\r" + set uprompt_seen 1 + exp_continue + } + -re "$p_prompt" { + sleep 1 + if {$uprompt_seen == 1} { + send -- "$userpswd\r" + } else { + send -- "$passwd\r" + } + exp_continue + } + -re "$prompt" { + set prompt_match $expect_out(0,string); + break; + } + "Login invalid" { + send_user "\nError: Invalid login: $router\n"; + catch {close}; catch {wait}; return 1 + } + -re "\[^\r\n]*\[\r\n]+" { exp_continue; } + } + } + + set in_proc 0 + return 0 +} + +# Enable +proc do_enable { enauser enapasswd } { + global do_saveconfig in_proc + global prompt u_prompt e_prompt enacmd + set in_proc 1 + + send "$enacmd\r" + expect { + -re "$u_prompt" { send -- "$enauser\r"; exp_continue} + -re "$e_prompt" { send -- "$enapasswd\r"; exp_continue} + ">" { set prompt ">" } + "#" { set prompt "#" } + "(enable)" { set prompt "> \\(enable\\) " } + "% Invalid input" { + send_user "\nError: Unrecognized command, check your enable command\n"; + return 1 + } + -re "(denied|Sorry|Incorrect)" { + # % Access denied - from local auth and poss. others + send_user "\nError: Check your Enable passwd\n"; + return 1 + } + "% Error in authentication" { + send_user "\nError: Check your Enable passwd\n" + return 1 + } + "% Bad passwords" { + send_user "\nError: Check your Enable passwd\n" + return 1 + } + "% Password is not set." { # Comware + send_user "\nError: No '$enacmd' password set for devide\n" + return 1 + } + "% Authenticate failed." { # Comware + send_user "\nError: Check your enable password for '$enacmd'\n + return 1 + } + } + # We set the prompt variable (above) so script files don't need + # to know what it is. + set in_proc 0 + return 0 +} + +# Run commands given on the command line. +proc run_commands { prompt command } { + global do_saveconfig in_proc platform exitcmd + set in_proc 1 + + # If the prompt is (enable), then we are on a switch and the + # command is "set length 0"; otherwise its "terminal length 0". + # skip if its an extreme (since the pager can not be disabled on a + # per-vty basis). + if { [string compare "extreme" "$platform"] } { + # match cisco config mode prompts too, such as router(config-if)#, + # but catalyst does not change in this fashion. + regsub -all {^(.{1,11}).*([#>])$} $prompt {\1([^#>\r\n]+)?[#>](\\([^)\\r\\n]+\\))?} reprompt + } else { + set reprompt $prompt + } + + # this is the only way i see to get rid of more prompts in o/p..grrrrr + log_user 0 + + # handle escaped ;s in commands, and ;; and ^; + regsub -all {([^\\]);;} $command "\\1;\u002;" esccommand + regsub {^;} $esccommand "\u002;" command + set sep "\\1\u001" + regsub -all {([^\\]);} $command "$sep" esccommand + set sep "\u001" + set commands [split $esccommand $sep] + set num_commands [llength $commands] + # the pager can not be turned off on the PIX, so we have to look + # for the "More" prompt. the extreme is equally obnoxious in pre-12.3 XOS, + # with a global switch in the config. + for {set i 0} {$i < $num_commands} { incr i} { + if { [lindex $commands $i] == "\u002" } { + send -- "\r" + } else { + send -- "[subst -nocommands [lindex $commands $i]]\r" + } + expect { + -re "\b+" { exp_continue } + -re "^\[^\n\r *]*$reprompt" { send_user -- "$expect_out(buffer)" + } + -re "^\[^\n\r]*$reprompt." { send_user -- "$expect_out(buffer)" + exp_continue + } + -re "^--More--\[\r\n]+" { # specific match c1900 pager + send " " + exp_continue + } + -re "\[^\r\n]*\[\n\r]+" { send_user -- "$expect_out(buffer)" + exp_continue + } + -re "\[^\r\n]*Press to cont\[^\r\n]*" { + send " " + # bloody ^[[2K after " " + expect { + -re "^\[^\r\n]*\r" {} + } + exp_continue + } + -re "^ *--More--\[^\n\r]*" { + send " " + exp_continue } + -re "^<-+ More -+>\[^\n\r]*" { + send_user -- "$expect_out(buffer)" + send " " + exp_continue } + -re "^ {0,2}-+ More .*-+.*\[^\n\r]*" { + # Comware 3/5 pager prompt + sleep 0.1 + send " " + exp_continue } + -re "^---- More ----\[^\n\r]*" { + # Comware 7 pager prompt + sleep 0.1 + send " " + exp_continue } + } + } + log_user 1 + + if { [string compare "extreme" "$platform"] } { + send -h "exit\r" + } else { + 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 -h "$exitcmd\r" + exp_continue; + } + "The system has unsaved changes" { # Force10 SFTOS + if {$do_saveconfig} { + catch {send "y\r"} + } else { + catch {send "n\r"} + } + exp_continue + } + "Would you like to save them now" { # Force10 + if {$do_saveconfig} { + catch {send "y\r"} + } else { + catch {send "n\r"} + } + exp_continue + } + -re "(Profile|Configuration) changes have occurred.*" { + # Cisco CSS + if {$do_saveconfig} { + catch {send "y\r"} + } else { + catch {send "n\r"} + } + exp_continue + } + "Do you wish to save your configuration changes" { + if {$do_saveconfig} { + catch {send "y\r"} + } else { + catch {send "n\r"} + } + exp_continue + } + -re "\[\n\r]+" { exp_continue } + -re "\[^\n\r *]Note:" { return 0 } + timeout { catch {close}; catch {wait}; + return 0 + } + eof { return 0 } + } + set in_proc 0 +} + +# +# For each router... (this is main loop) +# +source_password_file $password_file +set in_proc 0 +set exitval 0 +set prompt_match "" +foreach router [lrange $argv $i end] { + set router [string tolower $router] + # attempt at platform switching. + set platform "" + send_user -- "$router\n" + + # Figure out the platform + if {[info exists plat]} { + # command line platform + set platform $plat + } else { + set plat [find platform $router] + if { "$plat" == "" } { set platform "" } + } + + # Based on the platform, set some other defaults + # These can get overridden by other explicit settings + # Note that MA5600 wants enacmd "enable" + # Note that later versions of Coomware want cyphertype "aes128-cbc" + if { [string compare "cmw" "$platform"] } { + set enacmd "super" + set exitcmd "quit" + set cyphertype "3des" + } else { + set exitcmd "exit" + } + + # device timeout + set timeout [find timeout $router] + if { [llength $timeout] == 0 } { + set timeout $timeoutdflt + } + + # Default prompt. + set prompt [join [find prompt $router] ""] + if { [llength $prompt] == 0 } { + set prompt "(>\a?|#| \\(enable\\))" + } + + # look for autoenable option in .cloginrc & cmd-line + set ae [find autoenable $router] + if { "$ae" == "1" || $avautoenable } { + set autoenable 1 + } else { + set autoenable 0 + } + # look for enable options in .cloginrc & cmd-line + if { $avenable == 0 } { + set enable 0 + } else { + set ne [find noenable $router] + if { "$ne" == "1" || "$autoenable" == "1" } { + set enable 0 + } else { + set enable 1 + } + } + + # Figure out passwords + 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" + continue + } + if { $enable && $do_enapasswd && $autoenable == 0 && [llength $pswd] < 2 } { + 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 + if {[info exists username]} { + # command line username + set ruser $username + } else { + set ruser [join [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 [join [find userpassword $router] ""] + if { "$userpswd" == "" } { set userpswd $passwd } + } + + # 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 $ruser } + } + + # Figure out enable command + set enacmd [join [find enablecmd $router] ""] + if { "$enacmd" == "" } { set enacmd "enable" } + + # Figure out prompts + set u_prompt [find userprompt $router] + if { "$u_prompt" == "" } { + set u_prompt "(\[Uu]sername|Login|login|user name|User|User name):" + } else { + set u_prompt [join [lindex $u_prompt 0] ""] + } + set p_prompt [find passprompt $router] + if { "$p_prompt" == "" } { + set p_prompt "(\[Pp]assword|passwd|Enter password for \[^ :]+):" + } else { + set p_prompt [join [lindex $p_prompt 0] ""] + } + set e_prompt [find enableprompt $router] + if { "$e_prompt" == "" } { + set e_prompt "\[Pp]assword:" + } else { + set e_prompt [join [lindex $e_prompt 0] ""] + } + + # Figure out identity file to use + set identfile [join [lindex [find identity $router] 0] ""] + + # Figure out passphrase to use + if {[info exists avpassphrase]} { + set passphrase $avpassphrase + } else { + set passphrase [join [lindex [find passphrase $router] 0] ""] + } + if { ! [string length "$passphrase"]} { + set passphrase $passwd + } + + # Figure out cypher type + if {[info exists cypher]} { + # command line cypher type + set cyphertype $cypher + } else { + set cyphertype [find cyphertype $router] + if { "$cyphertype" == "" } { set cyphertype "3des" } + } + + # Figure out connection method + set cmethod [find method $router] + if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} } + + # Figure out the SSH executable name + set sshcmd [join [lindex [find sshcmd $router] 0] ""] + if { "$sshcmd" == "" } { set sshcmd {ssh} } + + + # Login to the router + if {[login $router $ruser $userpswd $passwd $enapasswd $cmethod $cyphertype $identfile]} { + incr exitval + # if login failed or rsh was unsuccessful, move on to the next device + continue + } + # Figure out the prompt. + if { [regexp -- "(#| \\(enable\\))" $prompt_match junk] == 1 } { + set enable 0 + } + + # Disable smart and interactive before send other commands + # (MA5600 and similar only?) + # Also disable log junk being sent to terminal + if { [string compare "cmw" "$platform"] } { + send -h "undo smart\r" + expect -re $prompt {} + send -h "undo interactive\r" + expect -re $prompt {} + send -h "undo terminal monitor\r" + expect -re $prompt {} + } + + if { $enable } { + if {[do_enable $enauser $enapasswd]} { + if { $do_command || $do_script } { + incr exitval + catch {close}; catch {wait}; + continue + } + } + } + # we are logged in, now figure out the full prompt + send "\r" + regsub -all {^(\^*)(.*)} $prompt {\2} reprompt + expect { + -re "\[\r\n]+" { exp_continue; } + -re "^(.+\[:.])1 ($reprompt)" { # 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) + regsub -all "^\\\* " $expect_out(1,string) {} junk + regsub -all "\[\]\[\(\)]" $junk {\\&} junk; + set prompt ".? ?$junk\[0-9]+ $expect_out(2,string)"; + set platform "extreme" + } + -re "^.+$reprompt" { set junk $expect_out(0,string); + regsub -all "\[\]\[\(\)+]" $junk {\\&} prompt; + } + } + if { $do_command || $do_script } { + if { [string compare "extreme" "$platform"] } { + # If the prompt is (enable), then we are on a switch and the + # command is "set length 0"; otherwise its "terminal length 0". + if [regexp -- ".*> .*enable" "$prompt"] { + send "set length 0\r" + expect -re $prompt {} + send "set width 132\r" + expect -re $prompt {} + send "set logging session disable\r" + } else { + send "terminal length 0\r" + expect -re $prompt {} + send "terminal width 132\r" + } + expect -re $prompt {} + } elseif { [string compare "cmw" "$platform"] } { + # Turn session paging off + # Comware 5/7 only. + # Comware 3 models have a screen-length command that only works on + # a vty basis + send -h "screen-length disable\r" + expect -re $prompt {} + } else { + send "disable clipaging\r" + expect -re $prompt {} + } + } + if { $do_command } { + if {[run_commands $prompt $command]} { + incr exitval + continue + } + } elseif { $do_script } { + source $sfile + catch {close}; + } else { + label $router + log_user 1 + interact + } + + # End of for each router + catch {wait}; + sleep 0.3 +} +exit $exitval Property changes on: head/net-mgmt/rancid3/files/cmwlogin.in ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property