Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ## 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.
- ##
- ## It is the request of the authors, but not a condition of license, that
- ## parties packaging or redistributing RANCID NOT distribute altered versions
- ## of the etc/rancid.types.base file nor alter how this file is processed nor
- ## when in relation to etc/rancid.types.conf. The goal of this is to help
- ## suppress our support costs. If it becomes a problem, this could become a
- ## condition of license.
- #
- # The expect login scripts were based on Erik Sherk's gwtn, by permission.
- #
- # The original looking glass software was written by Ed Kern, provided by
- # permission and modified beyond recognition.
- #
- # RANCID - Really Awesome New Cisco confIg Differ
- #
- # plogin - poly-login; use router.db files and rancid.{base,types}.conf
- # configurations to determine which login script to execute.
- #
- use 5.0010;
- use strict 'vars';
- use warnings;
- no warnings 'uninitialized';
- use Exporter;
- use Getopt::Long;
- # use Getopt::Long qw(:config no_ignore_case bundling);
- Getopt::Long::Configure ("bundling", "no_ignore_case");
- our($opt_d, $opt_S, $opt_V, $opt_autoenable, $opt_noenable, $opt_c, @opt_E, $opt_e,
- $opt_f, $opt_h, $opt_p, $opt_r, $opt_s, $opt_t, $opt_u, $opt_v, $opt_w,
- $opt_x, $opt_y, $opt_z);
- GetOptions('d' => \$opt_d, 'S' => \$opt_S, 'V' => \$opt_V,
- 'autoenable' => \$opt_autoenable, 'noenable' => \$opt_noenable,
- 'c=s' => \$opt_c, "E=s@" => \@opt_E, 'e=s' => \$opt_e, 'f=s' => \$opt_f,
- 'h=s' => \$opt_h,'p=s' => \$opt_p, 'r=s' => \$opt_r, 's=s' => \$opt_s,
- 't=s' => \$opt_t, 'u=s' => \$opt_u, 'v=s' => \$opt_v, 'w=s' => \$opt_w,
- 'x=s' => \$opt_x, 'y=s' => \$opt_y, 'z=s' => \$opt_z);
- my($BASEDIR, $LIST_OF_GROUPS, $cmd, $i, $j, @routers);
- BEGIN {
- push(@INC, "/usr/local/rancid/lib/rancid");
- }
- use rancid;
- our @ISA = qw(Exporter rancid);
- sub usage()
- {
- print STDERR "plogin [-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] [-y ssh_cypher_type] [-z device_type] router [router...]\n";
- exit 64;
- }
- # make OUTPUT unbuffered if debugging
- if ($opt_d) { $| = 1; }
- if ($opt_h) {
- usage();
- }
- # option handling initialization
- if ($opt_V) {
- print "plogin: rancid 3.4.1\n";
- # do not exit; exec the script with -V and it will exit
- }
- $cmd .= " -d" if ($opt_d);
- $cmd .= " -S" if ($opt_S);
- $cmd .= " -V" if ($opt_V);
- $cmd .= " -autoenable" if ($opt_autoenable);
- $cmd .= " -noenable" if ($opt_noenable);
- $cmd .= " -c '$opt_c'" if (length($opt_c));
- foreach $i (@opt_E) {
- $cmd .= " -E$i";
- }
- $cmd .= " -e '$opt_e'" if (length($opt_e));
- $cmd .= " -f '$opt_f'" if (length($opt_f));
- $cmd .= " -p '$opt_p'" if (length($opt_p));
- $cmd .= " -r '$opt_r'" if (length($opt_r));
- $cmd .= " -s '$opt_s'" if (length($opt_s));
- $cmd .= " -t $opt_s" if (length($opt_t));
- $cmd .= " -u '$opt_u'" if (length($opt_u));
- $cmd .= " -v '$opt_v'" if (length($opt_v));
- $cmd .= " -w '$opt_w'" if (length($opt_w));
- $cmd .= " -x '$opt_x'" if (length($opt_x));
- $cmd .= " -y '$opt_y'" if (length($opt_y));
- $devtype = $opt_z;
- foreach $i (@ARGV) {
- $cmd .= " $i";
- push(@routers, $i);
- }
- # what is the device type, supplied or looked-up
- if ($opt_z) {
- $devtype = $opt_z;
- } else {
- # Look in router.dbs for device type.
- # read rancid.conf for BASEDIR and LIST_OF_GROUPS?
- my($ENVFILE) = "/usr/local/rancid/etc/rancid.conf";
- open(INPUT, "< $ENVFILE") || die "Could not open $ENVFILE: $!";
- close(INPUT);
- open(INPUT,
- "sh -c \'. $ENVFILE; echo \"BASEDIR=\$BASEDIR\"; echo \"LIST_OF_GROUPS=\$LIST_OF_GROUPS\"\' |") ||
- die "Could not open $ENVFILE: $!";
- while (<INPUT>) {
- chomp;
- s/#.$//;
- s/^\s+//;
- my($varname, $value) = split('=');
- if ($varname eq "BASEDIR") {
- $BASEDIR = $value;
- }
- if ($varname eq "LIST_OF_GROUPS") {
- $LIST_OF_GROUPS = $value;
- $LIST_OF_GROUPS =~ s/^\s+//;
- $LIST_OF_GROUPS =~ s/\s+$//;
- }
- }
- close(INPUT);
- # read each router.db for the routername and thus the devtype
- foreach $i (split(/\s+/, $LIST_OF_GROUPS)) {
- if (!open(INPUT, "< $BASEDIR/$i/router.db")) {
- warn "Could not open $BASEDIR/$i/router.db: $!";
- next;
- }
- while (<INPUT>) {
- chomp;
- s/#.$//;
- s/^\s+//;
- my($router, $type, $state) = split('\;');
- foreach $j (@routers) {
- if ($router eq $j) {
- $devtype = $type;
- close(INPUT);
- goto FOUND;
- }
- }
- }
- close(INPUT);
- }
- }
- FOUND:
- if (length($devtype) < 1) {
- die "Couldn't find device type by hostname in router.dbs\n";
- }
- # load device type spec, build @commandtable and load modules
- if (loadtype($devtype)) {
- die "Couldn't load device type spec for $rancid::devtype\n";
- }
- if (! defined($lscript)) {
- die "login script not defined for device type $rancid::devtype\n";
- }
- exec($lscript . " $cmd") ||
- printf(STDERR "exec($script) failed router manufacturer $devtype: $!\n");
- exit(-1);
- #! /usr/bin/perl
- ##
- ## $Id: prancid.in 2279 2011-01-31 22:41:00Z heas $
- ##
- ## rancid 2.3.8
- ## Copyright (c) 1997-2008 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.
- #
- # This version of rancid tries to deal with Prockets.
- #
- # RANCID - Really Awesome New Cisco confIg Differ
- #
- # usage: rancid [-dV] [-l] [-f filename | hostname]
- #
- use Getopt::Std;
- getopts('dflV');
- if ($opt_V) {
- print "rancid 2.3.8\n";
- exit(0);
- }
- $log = $opt_l;
- $debug = $opt_d;
- $file = $opt_f;
- $host = $ARGV[0];
- $clean_run = 0;
- $found_end = 0;
- $timeo = 90; # clogin timeout in seconds
- my(@commandtable, %commands, @commands);# command lists
- my($aclsort) = ("ipsort"); # ACL sorting mode
- my($filter_commstr); # SNMP community string filtering
- my($filter_pwds); # password filtering mode
- my($platform); # platform/cpu type
- # This routine is used to print out the router configuration
- sub ProcessHistory {
- my($new_hist_tag,$new_command,$command_string,@string) = (@_);
- if ((($new_hist_tag ne $hist_tag) || ($new_command ne $command))
- && scalar(%history)) {
- print eval "$command \%history";
- undef %history;
- }
- if (($new_hist_tag) && ($new_command) && ($command_string)) {
- if ($history{$command_string}) {
- $history{$command_string} = "$history{$command_string}@string";
- } else {
- $history{$command_string} = "@string";
- }
- } elsif (($new_hist_tag) && ($new_command)) {
- $history{++$#history} = "@string";
- } else {
- print "@string";
- }
- $hist_tag = $new_hist_tag;
- $command = $new_command;
- 1;
- }
- sub numerically { $a <=> $b; }
- # This is a sort routine that will sort numerically on the
- # keys of a hash as if it were a normal array.
- sub keynsort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $key (sort numerically keys(%lines)) {
- $sorted_lines[$i] = $lines{$key};
- $i++;
- }
- @sorted_lines;
- }
- # This is a sort routine that will sort on the
- # keys of a hash as if it were a normal array.
- sub keysort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $key (sort keys(%lines)) {
- $sorted_lines[$i] = $lines{$key};
- $i++;
- }
- @sorted_lines;
- }
- # This is a sort routine that will sort on the
- # values of a hash as if it were a normal array.
- sub valsort{
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $key (sort values %lines) {
- $sorted_lines[$i] = $key;
- $i++;
- }
- @sorted_lines;
- }
- # This is a numerical sort routine (ascending).
- sub numsort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $num (sort {$a <=> $b} keys %lines) {
- $sorted_lines[$i] = $lines{$num};
- $i++;
- }
- @sorted_lines;
- }
- # This is a sort routine that will sort on the
- # ip address when the ip address is anywhere in
- # the strings.
- sub ipsort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $addr (sort sortbyipaddr keys %lines) {
- $sorted_lines[$i] = $lines{$addr};
- $i++;
- }
- @sorted_lines;
- }
- # These two routines will sort based upon IP addresses
- sub ipaddrval {
- my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#);
- $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0]));
- }
- sub sortbyipaddr {
- &ipaddrval($a) <=> &ipaddrval($b);
- }
- # This routine parses "show version"
- sub ShowVersion {
- print STDERR " In ShowVersion: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- last if(/^$prompt/);
- next if(/^(\s*|\s*$cmd\s*)$/);
- return(-1) if (/command authorization failed/i);
- if (/(lynxos|kernel) Version: .* (\S+)/i) {
- $platform = $2;
- }
- /Procket/ && ProcessHistory("COMMENTS","keysort","B0", "! $_") && next;
- /System Uptime:/ && next;
- /Protocol Uptime:/ && next;
- ProcessHistory("COMMENTS","keysort","B0", "!$_") && next;
- }
- return(0);
- }
- # This routine parses "show package"
- sub ShowPackage {
- print STDERR " In ShowPackage: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- last if(/^$prompt/);
- next if(/^(\s*|\s*$cmd\s*)$/);
- return(-1) if (/command authorization failed/i);
- ProcessHistory("COMMENTS","keysort","C0", "! $_") && next;
- }
- return(0);
- }
- # This routine parses "show hardware"
- sub ShowHardware {
- print STDERR " In ShowHardware: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- last if(/^$prompt/);
- next if(/^(\s*|\s*$cmd\s*)$/);
- # skip show hardware on titanium
- return(0) if ($platform =~ /i386/i);
- return(-1) if (/command authorization failed/i);
- return(-1) if (/cli: couldn.t communicate with/);
- ProcessHistory("COMMENTS","keysort","D0", "! $_") && next;
- }
- return(0);
- }
- # This routine parses "show inventory"
- sub ShowInventory {
- print STDERR " In ShowInventory: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- last if(/^$prompt/);
- next if(/^(\s*|\s*$cmd\s*)$/);
- return(0) if (/^\s+\^/);
- return(-1) if (/command authorization failed/i);
- /Procket/ && ProcessHistory("COMMENTS","keysort","E0", "! $_") && next;
- /System Uptime:/ && next;
- /Protocol Uptime:/ && next;
- ProcessHistory("COMMENTS","keysort","E0", "!$_") && next;
- }
- return(0);
- }
- # This routine processes a "write term"
- sub WriteTerm {
- print STDERR " In WriteTerm: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- last if(/^$prompt/);
- return(-1) if (/command authorization failed/i);
- /Non-Volatile memory is in use/ && return(-1); # NvRAM is locked
- # skip the crap
- if (/^(##+$|(Building|Current) configuration)/i) {
- while (<INPUT>) {
- next if (/^Current configuration\s*:/i);
- next if (/^([%!].*|\s*)$/);
- last;
- }
- tr/\015//d;
- }
- # some versions have other crap mixed in with the bits in the
- # block above
- /^! Last Changed:/ && next;
- # Dog gone Cool matches to process the rest of the config
- # /^tftp-server flash / && next; # kill any tftp remains
- # /^ntp clock-period / && next; # kill ntp clock-period
- # /^ length / && next; # kill length on serial lines
- # /^ width / && next; # kill width on serial lines
- # /^ clockrate / && next; # kill clockrate on serial interfaces
- if (/^(enable secret( level \d)?) / && $filter_pwds >= 2) {
- ProcessHistory("ENABLE","","","!$1 <removed>\n");
- next;
- }
- if (/^username (\S+)(\s.*)? password ((\d) \S+|\S+)/) {
- if ($filter_pwds == 2) {
- ProcessHistory("USER","keysort","$1","!username $1$2 password <removed>\n");
- } elsif ($filter_pwds == 1 && $4 ne "5"){
- ProcessHistory("USER","keysort","$1","!username $1$2 password <removed>\n");
- } else {
- ProcessHistory("USER","keysort","$1","$_");
- }
- next;
- }
- # prune passwords {bgp, ...}
- if (/^(\s*)password / && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1password <removed>\n");
- next;
- }
- # prune authentication keys {vrrp vrid N, router isis...}
- if (/^(\s*authentication \S+ key) / && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1 <removed>\n");
- next;
- }
- if (/^(\s*authentication-key) \d \S+( .*)/ && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1 <removed>$2\n");
- next;
- }
- # if (/^\s*neighbor (\S*) password / && $filter_pwds >= 1) {
- # ProcessHistory("","","","! neighbor $1 password <removed>\n");
- # next;
- # }
- # if (/^(ppp .* password) 7 .*/ && $filter_pwds >= 1) {
- # ProcessHistory("","","","!$1 <removed>\n"); next;
- # }
- # if (/^(ip ftp password) / && $filter_pwds >= 1) {
- # ProcessHistory("","","","!$1 <removed>\n"); next;
- # }
- # prune ospf keys
- if (/^( ip ospf authentication-key) / && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1 <removed>\n"); next;
- }
- # this is reversable, despite 'md5' in the cmd
- if (/^( ip ospf message-digest-key \d+ md5) / && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1 <removed>\n"); next;
- }
- # this is reversable, despite 'md5' in the cmd
- if (/^(\s*message-digest-key \d+ md5) / && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1 <removed>\n"); next;
- }
- # if (/^((crypto )?isakmp key) \S+ / && $filter_pwds >= 1) {
- # ProcessHistory("","","","!$1 <removed> $'"); next;
- # }
- # sort ip explicit-paths.
- if (/^ip explicit-path name (\S+)/) {
- my($key) = $1;
- my($expath) = $_;
- while (<INPUT>) {
- tr/\015//d;
- last if (/^$prompt/);
- last if (/^$prompt/ || ! /^(ip explicit-path name |[ !])/);
- if (/^ip explicit-path name (\S+)/) {
- ProcessHistory("EXPATH","keysort","$key","$expath");
- $key = $1;
- $expath = $_;
- } else {
- $expath .= $_;
- }
- }
- ProcessHistory("EXPATH","keysort","$key","$expath");
- }
- # sort route-maps
- if (/^route-map (\S+)/) {
- my($key) = $1;
- my($routemap) = $_;
- while (<INPUT>) {
- tr/\015//d;
- last if (/^$prompt/ || ! /^(route-map |[ !])/);
- if (/^route-map (\S+)/) {
- ProcessHistory("ROUTEMAP","keysort","$key","$routemap");
- $key = $1;
- $routemap = $_;
- } else {
- $routemap .= $_;
- }
- }
- ProcessHistory("ROUTEMAP","keysort","$key","$routemap");
- }
- # filter out any RCS/CVS tags to avoid confusing local CVS storage
- s/\$(Revision|Id):/ $1:/;
- # # order access-lists
- # /^access-list\s+(\d\d?)\s+(\S+)\s+(\S+)/ &&
- # ProcessHistory("ACL $1 $2","$aclsort","$3","$_") && next;
- # # order extended access-lists
- # /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+host\s+(\S+)/ &&
- # ProcessHistory("EACL $1 $2","$aclsort","$3","$_") && next;
- # /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+(\d\S+)/ &&
- # ProcessHistory("EACL $1 $2","$aclsort","$3","$_") && next;
- # /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+any/ &&
- # ProcessHistory("EACL $1 $2","$aclsort","0.0.0.0","$_") && next;
- # # order arp lists
- # /^arp\s+(\d+\.\d+\.\d+\.\d+)\s+/ &&
- # ProcessHistory("ARP","$aclsort","$1","$_") && next;
- # /^ip prefix-list\s+(\S+)\s+seq\s+(\d+)\s+(permit|deny)\s+(\d\S+)(\/.*)$/ &&
- # ProcessHistory("PACL $1 $3","$aclsort","$4","ip prefix-list $1 $3 $4$5\n")
- # && next;
- # order logging statements
- /^logging (\d+\.\d+\.\d+\.\d+)/ &&
- ProcessHistory("LOGGING","ipsort","$1","$_") && next;
- # order/prune snmp-server host statements
- # we only prune lines of the form
- # snmp-server host a.b.c.d <community>
- if (/^snmp-server host (\d+\.\d+\.\d+\.\d+) /) {
- if ($filter_commstr) {
- my($ip) = $1;
- my($line) = "snmp-server host $ip";
- my(@tokens) = split(' ', $');
- my($token);
- while ($token = shift(@tokens)) {
- if ($token eq 'version') {
- $line .= " " . join(' ', ($token, shift(@tokens)));
- } elsif ($token =~ /^(informs?|traps?|(no)?auth)$/) {
- $line .= " " . $token;
- } else {
- $line = "!$line " . join(' ', ("<removed>", join(' ',@tokens)));
- last;
- }
- }
- ProcessHistory("SNMPSERVERHOST","ipsort","$ip","$line\n");
- } else {
- ProcessHistory("SNMPSERVERHOST","ipsort","$1","$_");
- }
- next;
- }
- if (/^(snmp-server community) (\S+)/) {
- if ($filter_commstr) {
- ProcessHistory("SNMPSERVERCOMM","keysort","$_","!$1 <removed>$'") && next;
- } else {
- ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && next;
- }
- }
- # prune tacacs/radius server keys
- if (/^(tacacs-server|radius-server) key / && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1 key <removed>\n"); next;
- }
- if (/^(tacacs-server host \S+( .*)? key) (\d )?\S+/
- && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1 <removed>\n"); next;
- }
- # order clns host statements
- # /^clns host \S+ (\S+)/ &&
- # ProcessHistory("CLNS","keysort","$1","$_") && next;
- # prune vrrp password
- if (/^( ip vrrp authentication .* key) / && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1 <removed>\n"); next;
- }
- # prune isis password
- if (/^( isis authentication-key) \d \S+/ && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1 <removed>$'"); next;
- }
- # prune msdp password
- if (/^(ip msdp password \S+) / && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1 <removed>\n"); next;
- }
- # delete ntp auth password - this md5 is a reversable too
- if (/^(ntp authentication-key \d+ md5) / && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1 <removed>\n"); next;
- }
- # order ntp peers/servers
- if (/^ntp (server|peer) (\d+)\.(\d+)\.(\d+)\.(\d+)/) {
- $sortkey = sprintf("$1 %03d%03d%03d%03d",$2,$3,$4,$5);
- ProcessHistory("NTP","keysort",$sortkey,"$_");
- next;
- }
- # # order ip host line statements
- # /^ip host line(\d+)/ &&
- # ProcessHistory("IPHOST","numsort","$1","$_") && next;
- # # order ip nat source static statements
- # /^ip nat (\S+) source static (\S+)/ &&
- # ProcessHistory("IP NAT $1","ipsort","$2","$_") && next;
- # # order atm map-list statements
- # /^\s+ip\s+(\d+\.\d+\.\d+\.\d+)\s+atm-vc/ &&
- # ProcessHistory("ATM map-list","ipsort","$1","$_") && next;
- # # order ip rcmd lines
- # /^ip rcmd/ && ProcessHistory("RCMD","keysort","$_","$_") && next;
- # catch anything that wasnt matched above.
- ProcessHistory("","","","$_");
- # end of config.
- if (/^end$/) {
- $found_end = 1;
- return(1);
- }
- }
- return(0);
- }
- # dummy function
- sub DoNothing {print STDOUT;}
- # Main
- @commandtable = (
- {'show version all' => 'ShowVersion'},
- {'show package' => 'ShowPackage'},
- {'show hardware' => 'ShowHardware'},
- {'show inventory' => 'ShowInventory'},
- {'write term' => 'WriteTerm'}
- );
- # Use an array to preserve the order of the commands and a hash for mapping
- # commands to the subroutine and track commands that have been completed.
- @commands = map(keys(%$_), @commandtable);
- %commands = map(%$_, @commandtable);
- $cisco_cmds=join(";",@commands);
- $cmds_regexp = join("|", map quotemeta($_), @commands);
- if (length($host) == 0) {
- if ($file) {
- print(STDERR "Too few arguments: file name required\n");
- exit(1);
- } else {
- print(STDERR "Too few arguments: host name required\n");
- exit(1);
- }
- }
- open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n";
- select(OUTPUT);
- # make OUTPUT unbuffered if debugging
- if ($debug) { $| = 1; }
- if ($file) {
- print STDERR "opening file $host\n" if ($debug);
- print STDOUT "opening file $host\n" if ($log);
- open(INPUT,"<$host") || die "open failed for $host: $!\n";
- } else {
- print STDERR "executing clogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($debug);
- print STDOUT "executing clogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($log);
- if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
- system "clogin -t $timeo -c \"$cisco_cmds\" $host </dev/null > $host.raw 2>&1" || die "clogin failed for $host: $!\n";
- open(INPUT, "< $host.raw") || die "clogin failed for $host: $!\n";
- } else {
- open(INPUT,"clogin -t $timeo -c \"$cisco_cmds\" $host </dev/null |") || die "clogin failed for $host: $!\n";
- }
- }
- # determine ACL sorting mode
- if ($ENV{"ACLSORT"} =~ /no/i) {
- $aclsort = "";
- }
- # determine community string filtering mode
- if (defined($ENV{"NOCOMMSTR"}) &&
- ($ENV{"NOCOMMSTR"} =~ /yes/i || $ENV{"NOCOMMSTR"} =~ /^$/)) {
- $filter_commstr = 1;
- } else {
- $filter_commstr = 0;
- }
- # determine password filtering mode
- if ($ENV{"FILTER_PWDS"} =~ /no/i) {
- $filter_pwds = 0;
- } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) {
- $filter_pwds = 2;
- } else {
- $filter_pwds = 1;
- }
- ProcessHistory("","","","!RANCID-CONTENT-TYPE: procket\n!\n");
- ProcessHistory("COMMENTS","keysort","B0","!\n"); # show version
- ProcessHistory("COMMENTS","keysort","C0","!\n"); # show package
- ProcessHistory("COMMENTS","keysort","D0","!\n"); # show hardware
- ProcessHistory("COMMENTS","keysort","E0","!\n"); # show inventory
- ProcessHistory("COMMENTS","keysort","Z0","!\n");
- TOP: while(<INPUT>) {
- tr/\015//d;
- if (/\#\s?exit$/) {
- $clean_run=1;
- last;
- }
- if (/^Error:/) {
- print STDOUT ("$host clogin error: $_");
- print STDERR ("$host clogin error: $_") if ($debug);
- $clean_run=0;
- last;
- }
- while (/#\s*($cmds_regexp)\s*$/) {
- $cmd = $1;
- if (!defined($prompt)) {$prompt = ($_ =~ /^([^#]+#)/)[0]; }
- 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}};
- delete($commands{$cmd});
- if ($rval == -1) {
- $clean_run = 0;
- last TOP;
- }
- }
- }
- print STDOUT "Done $logincmd: $_\n" if ($log);
- # Flush History
- ProcessHistory("","","","");
- # Cleanup
- close(INPUT);
- close(OUTPUT);
- if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
- unlink("$host.raw") if (! $debug);
- }
- # check for completeness
- if (scalar(%commands) || !$clean_run || !$found_end) {
- if (scalar(%commands)) {
- printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands)));
- printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug);
- }
- if (!$clean_run || !$found_end) {
- print STDOUT "$host: End of run not found\n";
- print STDERR "$host: End of run not found\n" if ($debug);
- system("/usr/bin/tail -1 $host.new");
- }
- unlink "$host.new" if (! $debug);
- }
- #! /usr/bin/perl
- ##
- ## $Id: rancid.in 3123 2015-05-28 22:39:32Z heas $
- ##
- ## rancid 3.4.1
- ## Copyright (c) 1997-2016 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
- #
- # rancid - generalized rancid module; command schedule is derived from the
- # rancid.types.{base,conf} configurations.
- #
- # usage: rancid [-dhltCV] -t device_type [-f filename | hostname]
- #
- use 5.010;
- use strict 'vars';
- use warnings;
- no warnings 'uninitialized';
- use Exporter;
- use Getopt::Std;
- our($opt_d, $opt_f, $opt_h, $opt_l, $opt_t, $opt_C, $opt_V);
- getopts('dfhlt:CV');
- BEGIN {
- push(@INC, "/usr/local/rancid/lib/rancid");
- }
- use rancid;
- our @ISA = qw(Exporter rancid);
- sub usage()
- {
- print STDERR "rancid [-dhltCV] -t device_type [-f filename | hostname]\n";
- exit 64;
- }
- if ($opt_h) {
- usage();
- }
- # basic initialization
- rancidinit();
- # load device type spec, build @commandtable and load modules
- if (loadtype($devtype)) {
- die "Couldn't load device type spec for $rancid::devtype\n";
- }
- if (! defined($lscript)) {
- die "login script not defined for device type $rancid::devtype\n";
- }
- # open the temporary file for the digested output
- open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n";
- select(OUTPUT);
- if (length($#modules)) {
- my($module);
- foreach $module (@modules) {
- (my $file = $module) =~ s/::/\//g;
- my($err) = 0;
- # call module->init(); we expect 0 as success, as god intended it
- eval "\$err = ". $module ."::init();";
- if ($@) {
- printf(STDERR "loadtype: initializing $module failed: %s\n", $@);
- exit 1;
- } elsif ($err) {
- printf(STDERR "loadtype: %s::init() returned failure\n", $module);
- exit 1;
- }
- }
- }
- # open the input, a pre-collected file or start a login for a login stream or
- # temporary file
- if ($file) {
- print STDERR "opening file $host\n" if ($debug);
- print STDOUT "opening file $host\n" if ($log);
- open(INPUT,"<$host") || die "open failed for $host: $!\n";
- } else {
- print STDERR "executing $lscript -t $timeo -c\"$commandstr\" $host\n" if ($debug);
- print STDOUT "executing $lscript -t $timeo -c\"$commandstr\" $host\n" if ($log);
- if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
- system "$lscript -t $timeo -c \"$commandstr\" $host </dev/null > $host.raw 2>&1" || die "clogin failed for $host: $!\n";
- open(INPUT, "< $host.raw") || die "clogin failed for $host: $!\n";
- } else {
- open(INPUT,"$lscript -t $timeo -c \"$commandstr\" $host </dev/null |") || die "clogin failed for $host: $!\n";
- }
- }
- # loop over the input using the provided input/main loop
- if (!defined($inloop) || length($inloop) < 1) {
- die "inloop is not configured for device type $devtype";
- }
- eval($inloop ."(*INPUT, *OUTPUT);") && die "${inloop} failed: $@\n";
- print STDOUT "Done $lscript: $_\n" if ($log);
- # Flush History
- ProcessHistory("","","","");
- # Cleanup
- close(INPUT);
- close(OUTPUT);
- if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
- unlink("$host.raw") if (! $debug);
- }
- # check for completeness
- if (scalar(%commands) || !$clean_run || !$found_end) {
- if (scalar(keys %commands) eq $commandcnt) {
- printf(STDERR "$host: missed cmd(s): all commands\n");
- } elsif (scalar(%commands)) {
- printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands)));
- printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug);
- }
- if (!$clean_run || !$found_end) {
- print STDOUT "$host: End of run not found\n";
- print STDERR "$host: End of run not found\n" if ($debug);
- system("/usr/bin/tail -1 $host.new");
- }
- unlink "$host.new" if (! $debug);
- }
- #! /bin/sh
- ##
- ## $Id: rancid-cvs.in 3055 2015-03-12 18:24:07Z heas $
- ##
- ## rancid 3.4.1
- ## Copyright (c) 1997-2016 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.
- #
- # Create all of the misc files & dirs needed for each group and import them
- # into CVS or Subversion.
- #
- # rancid-cvs
- #
- # Read in the environment
- ENVFILE="/usr/local/rancid/etc/rancid.conf"
- # print a usage message to stderr
- pr_usage() {
- echo "usage: $0 [-V] [-f config_file] [group [group ...]]" >&2;
- }
- # command-line options
- # -V print version string
- if [ $# -ge 1 ] ; then
- while [ 1 ] ; do
- case $1 in
- -V)
- echo "rancid 3.4.1"
- exit 0
- ;;
- -f)
- shift
- # next arg is the alternate config file name
- ENVFILE="$1"
- if [ -z $ENVFILE ]; then
- pr_usage
- exit 1
- fi
- shift
- ;;
- -*)
- echo "unknown option: $1" >&2
- pr_usage
- exit 1
- ;;
- *)
- break;
- ;;
- esac
- done
- fi
- . $ENVFILE
- # Base dir
- if [ ! -d $BASEDIR ]; then
- mkdir -p $BASEDIR ||
- (echo "Could not create local state directory: $BASEDIR"; exit 1)
- fi
- cd $BASEDIR
- # RCS system
- RCSSYS=${RCSSYS:=cvs};
- if [ $RCSSYS != "cvs" -a $RCSSYS != "svn" -a $RCSSYS != "git" ] ; then
- echo "$RCSSYS is not a valid value for RCSSYS. See rancid.conf(5)." >&2
- exit 1
- fi
- # Top level RCS stuff
- case $RCSSYS in
- cvs )
- if [ ! -d $CVSROOT ]; then
- cvs -d $CVSROOT init
- fi
- ;;
- svn )
- if echo "$CVSROOT" | grep -q "://"; then
- # do nothing because CVSROOT is some sort of a URL
- # also assume the repository has already been provisioned
- :
- else
- if ! svn ls "file://$CVSROOT" >/dev/null 2>&1; then
- svnadmin create $CVSROOT --fs-type fsfs
- fi
- CVSROOT="file://$CVSROOT"
- fi
- ;;
- git)
- if echo "$CVSROOT" | grep -q "://"; then
- # do nothing because CVSROOT is some sort of a URL
- # also assume the repository has already been provisioned
- :
- else
- if [ ! -d $CVSROOT ]; then
- mkdir $CVSROOT
- fi
- fi
- ;;
- esac
- # Log dir
- if [ ! -d logs ]; then
- mkdir logs
- fi
- # Which groups to do
- if [ $# -ge 1 ] ; then
- LIST_OF_GROUPS="$*"; export LIST_OF_GROUPS
- elif [ "$LIST_OF_GROUPS" = "" ] ; then
- echo "LIST_OF_GROUPS is empty in $ENVFILE"
- exit 1
- fi
- for GROUP in `echo $LIST_OF_GROUPS` ;
- do
- DIR=$BASEDIR/$GROUP
- # Directory for the group and the configs
- if [ ! -d $DIR ]; then
- mkdir -p $DIR
- cd $DIR
- case $RCSSYS in
- cvs )
- cvs import -m "$GROUP" $GROUP new rancid
- cd $BASEDIR
- cvs checkout $GROUP
- ;;
- svn )
- svn import -m "$GROUP" . $CVSROOT/$GROUP
- cd $BASEDIR
- svn checkout $CVSROOT/$GROUP $GROUP
- cd $DIR
- svn update
- ;;
- git )
- git init --bare $CVSROOT/$GROUP
- git clone $CVSROOT/$GROUP .
- git config --global user.name RANCiD
- git config --global user.email $USER$MAILDOMAIN
- git config --global push.default current
- ;;
- esac
- fi
- cd $DIR
- if [ ! -d configs ]; then
- rm -f configs
- mkdir configs
- if [ $RCSSYS = "git" ]; then
- cat > configs/.gitignore <<EOF
- .old
- *.new
- *.raw
- EOF
- fi
- $RCSSYS add configs
- $RCSSYS commit -m 'new' configs
- if [ $RCSSYS = "git" ]; then
- git push
- fi
- fi
- # config and status files
- if [ ! -f routers.all ]; then
- touch routers.all
- fi
- if [ ! -f routers.down ]; then
- touch routers.down
- fi
- if [ ! -f routers.up ]; then
- touch routers.up
- fi
- if [ ! -f router.db ]; then
- touch router.db
- $RCSSYS add router.db
- $RCSSYS commit -m 'new' router.db
- if [ $RCSSYS = "git" ]; then
- git push
- fi
- fi
- done
- #! /usr/bin/perl
- ##
- ## $Id: rancid-fe.in 3018 2015-01-11 05:51:49Z heas $
- ##
- ## rancid 3.4.1
- ## Copyright (c) 1997-2016 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-FE - front-end to rancid/jrancid/etc. for use with par.
- #
- # usage: rancid-fe <router>;<vendor>
- #
- require 5;
- my($script);
- my($router, $devtype) = split('\;', $ARGV[0]);
- $devtype =~ tr/[A-Z]/[a-z]/;
- if (! length($devtype)) {
- printf(STDERR "unknown router manufacturer for $router: $devtype\n");
- exit(-1);
- }
- # XXX use rancid::loadtype() to parse these files.
- foreach $file ("/usr/local/rancid/etc/rancid.types.base",
- "/usr/local/rancid/etc/rancid.types.conf") {
- open(INPUT, "< $file") || die "Could not open $file: $!";
- while (<INPUT>) {
- chomp;
- my($type, $directive, $value) = split('\;');
- $type =~ tr/[A-Z]/[a-z]/;
- $directive =~ tr/[A-Z]/[a-z]/;
- if ($type eq $devtype && $directive eq "script") {
- $script = $value;
- close(INPUT);
- goto FOUND;
- }
- }
- close(INPUT);
- }
- FOUND:
- if (! defined($script)) {
- printf(STDERR "unknown router manufacturer for $router: $devtype\n");
- exit(-1);
- } else {
- exec($script . " $router");
- }
- printf(STDERR "exec($script) failed router manufacturer $devtype: $!\n");
- exit(-1);
- #! /bin/sh
- ##
- ## $Id: rancid-run.in 3232 2016-01-21 17:46:40Z heas $
- ##
- ## rancid 3.4.1
- ## Copyright (c) 1997-2016 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.
- #
- # Run rancid for each of the rancid groups defined by $LIST_OF_GROUPS in
- # /usr/local/rancid/etc/rancid.conf or those specified on the command-line.
- #
- # Default ENVFILE, overrideable with -f flag.
- ENVFILE="/usr/local/rancid/etc/rancid.conf"
- TMPDIR=${TMPDIR:=/tmp}; export TMPDIR
- # control_rancid argv
- CR_ARGV=""; export CR_ARGV
- # print a usage message to stderr
- pr_usage() {
- echo "usage: $0 [-V] [-f config_file] [-r device_name] [-m mail rcpt] [group [group ...]]" >&2;
- }
- # command-line options
- # -V
- # -f <config file name>
- # -m <mailto address>
- # -r <device name>
- if [ $# -ge 1 ] ; then
- while [ 1 ] ; do
- case $1 in
- -V)
- echo "rancid 3.4.1"
- exit 0
- ;;
- -f)
- shift
- # next arg is the alternate config file name
- ENVFILE="$1"
- if [ -z $ENVFILE ]; then
- pr_usage
- exit 1
- fi
- CR_ARGV="$CR_ARGV -f $1"; export CR_ARGV
- shift
- ;;
- -m)
- shift
- # next arg is the mailto name
- CR_ARGV="$CR_ARGV -m $1"; export CR_ARGV
- shift
- ;;
- -r)
- shift
- # next arg is the device name
- CR_ARGV="$CR_ARGV -r $1"; export CR_ARGV
- shift
- ;;
- --)
- shift; break;
- ;;
- -h)
- pr_usage
- exit
- ;;
- -*)
- echo "unknown option: $1" >&2
- pr_usage
- exit 1
- ;;
- *)
- break;
- ;;
- esac
- done
- fi
- . $ENVFILE
- # SENDMAIL location
- SENDMAIL=${SENDMAIL:=sendmail};
- if [ $# -ge 1 ] ; then
- LIST_OF_GROUPS="$*"; export LIST_OF_GROUPS
- elif [ "$LIST_OF_GROUPS" = "" ] ; then
- echo "LIST_OF_GROUPS is empty in $ENVFILE"
- exit 1
- fi
- if [ ! -d $LOGDIR ] ; then
- mkdir $LOGDIR || (echo "Could not create log directory: $LOGDIR"; exit 1)
- fi
- for GROUP in $LIST_OF_GROUPS
- do
- LOCKFILE=$TMPDIR/.$GROUP.run.lock
- (
- echo starting: `date`
- echo
- if [ -f $LOCKFILE ]
- then
- echo hourly config diffs failed: $LOCKFILE exists
- ls -l $LOCKFILE
- # Send email if the lock file is old.
- if [ "X$LOCKTIME" = "X" ] ; then
- LOCKTIME=4
- fi
- GRPOLDFILE=`mktemp -q $TMPDIR/.$GROUP.XXXXXX`
- if [ $? -ne 0 ] ; then
- echo "Could not create temporary file for error email" >&2
- exit 1
- fi
- perl -e "\$t = (stat(\"$LOCKFILE\"))[9]; print \"OLD\\n\" if (time() - \$t >= $LOCKTIME*60*60);" > $GRPOLDFILE
- if [ -s $TMPDIR/.$GROUP.old ]
- then
- (
- echo "To: rancid-admin-${GROUP}${MAILDOMAIN}"
- echo "Subject: rancid hung - $GROUP"
- echo "Precedence: bulk"
- echo "Auto-submitted: auto-generated"
- echo "X-Auto-Response-Suppress: All"
- echo ""
- cat <<END
- rancid $GROUP hung on `hostname`? Old lockfile still exists:
- `ls -l $LOCKFILE`
- END
- ) | $SENDMAIL -t $MAILOPTS
- fi
- rm -f $GRPOLDFILE
- exit 1
- else
- trap 'rm -fr $LOCKFILE;exit 1' 1 2 3 6 10 15
- perl -e 'use POSIX;sysopen(FH, $ARGV[1], O_RDWR|O_CREAT|O_EXCL, 0660) or exit 1;print FH "$ARGV[0]\n";' -- $$ $LOCKFILE
- if [ $? -eq 0 ] ; then
- control_rancid $CR_ARGV $GROUP
- trap '' 1 2 3 6 10 15
- rm -f $LOCKFILE
- fi
- trap '' 1 2 3 6 10 15
- fi
- echo
- echo ending: `date`
- ) >$LOGDIR/$GROUP.`date +%Y%m%d.%H%M%S` 2>&1
- done
- #! /usr/bin/expect --
- ##
- ## $Id: rblogin.in 3201 2015-11-05 00:48:01Z heas $
- ##
- ## rancid 3.4.1
- ## Copyright (c) 1997-2016 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.
- ##
- ## It is the request of the authors, but not a condition of license, that
- ## parties packaging or redistributing RANCID NOT distribute altered versions
- ## of the etc/rancid.types.base file nor alter how this file is processed nor
- ## when in relation to etc/rancid.types.conf. The goal of this is to help
- ## suppress our support costs. If it becomes a problem, this could become a
- ## condition of license.
- #
- # The expect login scripts were based on Erik Sherk's gwtn, by permission.
- #
- # The original looking glass software was written by Ed Kern, provided by
- # permission and modified beyond recognition.
- #
- # rblogin - Riverbed Steelhead login; this is starting from clogin r3115, with
- # a few changes for UI bugs.
- #
- # Most options are intuitive for logging into a Cisco router.
- # The default is to enable (thus -noenable). Some folks have
- # setup tacacs to have a user login at priv-lvl = 15 (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.
- #
- # 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}
- # env(CLOGIN) may contain:
- # x == do not set xterm banner or name
- # 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)
- }
- # Usage line
- set usage "Usage: $argv0 \[-dhSV\] \[-m|M\] \[-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\] \
- \[-y ssh_cypher_type\] router \[router...\]\n"
- # 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
- # cloginrc debugging knob
- set do_cloginrcdbg 0
- # intialize cloginrc parsing stacks
- set int_file {}
- set int_lineno {}
- # 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
- # Help
- } -h* {
- send_user "$usage"
- exit 0
- # Command to run.
- } -c* {
- if {! [regexp .\[cC\](.+) $arg ignore command]} {
- incr i
- set command [lindex $argv $i]
- }
- set do_command 1
- # 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
- }
- # alternate cloginrc file
- } -f* {
- if {! [regexp .\[fF\](.+) $arg ignore password_file]} {
- incr i
- set password_file [lindex $argv $i]
- }
- # VTY Password
- } -p* {
- if {! [regexp .\[pP\](.+) $arg ignore userpasswd]} {
- incr i
- set userpasswd [lindex $argv $i]
- }
- set do_passwd 0
- # cloginrc debugging knobs
- } -m* {
- set do_cloginrcdbg 1
- } -M* {
- set do_cloginrcdbg 2
- # ssh passphrase
- } -r* {
- if {! [regexp .\[rR\](.+) $arg ignore passphrase]} {
- incr i
- set avpassphrase [lindex $argv $i]
- }
- # 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* {
- # may not be supported by the script and may not be applicable to
- # the platform
- set do_saveconfig 1
- # Timeout
- } -t* {
- if {! [regexp .\[tT\](.+) $arg ignore timeout]} {
- incr i
- set timeoutdflt [lindex $argv $i]
- }
- # Username
- } -u* {
- if {! [regexp .\[uU\](.+) $arg ignore user]} {
- incr i
- set username [lindex $argv $i]
- }
- # VTY Password
- } -v* {
- # some scripts ignore -v, like jlogin
- if {! [regexp .\[vV\](.+) $arg ignore passwd]} {
- incr i
- set passwd [lindex $argv $i]
- }
- set do_passwd 0
- # Version string
- } -V* {
- send_user "rancid 3.4.1\n"
- exit 0
- # Enable Username
- } -w* {
- if {! [regexp .\[wW\](.+) $arg ignore enauser]} {
- incr i
- set enausername [lindex $argv $i]
- }
- # Enable Password
- } -e* {
- if {! [regexp .\[e\](.+) $arg ignore enapasswd]} {
- incr i
- set enapasswd [lindex $argv $i]
- }
- set do_enapasswd 0
- # 'ssh -c' cypher type
- } -y* {
- if {! [regexp .\[eE\](.+) $arg ignore cypher]} {
- incr i
- set cypher [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_file int_lineno int_$var
- set file [lindex $int_file 0]
- set lineno [lindex $int_lineno 0]
- lappend int_$var "$var:$file:$lineno: $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} {
- global do_cloginrcdbg
- upvar int_$var list
- if { [info exists list] } {
- foreach line $list {
- if { [string match -nocase [lindex $line 1] $router] } {
- if { $do_cloginrcdbg > 0 } {
- send_error -- [join [list [lindex $line 0] [lrange $line 1 end] "\r\n"]]
- }
- if { $do_cloginrcdbg == 2 } {
- # save return value
- if {! [info exists result]} {
- set result [lrange $line 2 end]
- }
- } else {
- return [lrange $line 2 end]
- }
- }
- }
- }
- if { $do_cloginrcdbg == 2 } {
- if {[info exists result]} {
- return $result
- }
- }
- 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 { file } {
- global env int_file int_lineno
- if { ! [file exists $file] } {
- send_user "\nError: password file ($file) does not exist\n"
- exit 1
- }
- file stat $file fileinfo
- if { [expr ($fileinfo(mode) & 007)] != 0000 } {
- send_user "\nError: $file must not be world readable/writable\n"
- exit 1
- }
- if [catch {set fd [open $file "r"]} reason] {
- send_user "\nError: $reason\n"
- exit 1
- }
- set int_file [linsert $int_file 0 $file]
- set int_lineno [linsert $int_lineno 0 0]
- while { [gets $fd line] >= 0 } {
- set tmp [lindex $int_lineno 0]; incr tmp
- lset int_lineno 0 $tmp
- eval $line
- }
- set int_file [lrange $int_file 1 end]
- set int_lineno [lrange $int_lineno 1 end]
- close $fd
- }
- # 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
- }
- -nocase -re "^warning: remote host denied authentication agent forwarding." {
- exp_continue;
- }
- -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 <tab> 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 "#" }
- "(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
- }
- }
- # 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
- set in_proc 1
- 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 -lineanchor -- {^(.{1,11}).*([#>])$} $prompt {\1} reprompt
- regsub -all -- {[\\]$} $reprompt {} reprompt
- append reprompt {([^#>\r\n]+)?[#>](\\([^)\\r\\n]+\\))?}
- } 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 "^<<Service needs \[^>]+>>" {
- # for whatever reason, the riverbed prints
- # this warning in show peers o/p, but doesnt
- # follow it with a CR, so the following
- # prompt is not at the BOL, confusing the
- # parsing script. so, filter it. XXX
- 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 <SPACE> 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 }
- }
- }
- 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 "exit\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 }
- timeout { catch {close}; catch {wait};
- return 1
- }
- 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"
- # 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 "(>|#| \\(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):"
- } 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} }
- # if [-mM], skip do not login
- if { $do_cloginrcdbg > 0 } { continue; }
- # 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
- }
- 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 {}
- # XXX This causes the riverbed to reprint the prompt after the
- # existing prompt, which confuses the expect script.
- # send "set width 132\r"
- # expect -re $prompt {}
- send "set logging session disable\r"
- } else {
- send "terminal length 0\r"
- # XXX This causes the riverbed to reprint the prompt after the
- # existing prompt, which confuses the expect script.
- # expect -re $prompt {}
- # send "terminal width 132\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
- #! /usr/bin/expect --
- ##
- ## $Id: rivlogin.in 3102 2015-04-23 17:18:18Z heas $
- ##
- ## rancid 3.4.1
- ## Copyright (c) 1997-2016 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.
- ##
- ## It is the request of the authors, but not a condition of license, that
- ## parties packaging or redistributing RANCID NOT distribute altered versions
- ## of the etc/rancid.types.base file nor alter how this file is processed nor
- ## when in relation to etc/rancid.types.conf. The goal of this is to help
- ## suppress our support costs. If it becomes a problem, this could become a
- ## condition of license.
- #
- # The expect login scripts were based on Erik Sherk's gwtn, by permission.
- #
- # The original looking glass software was written by Ed Kern, provided by
- # permission and modified beyond recognition.
- #
- # rivlogin - Riverstone (and Enterasys SSR) login
- #
- # Based upon rscmd (see nmops.org)
- # rscmd - Riverstone Networks Automated login
- # by Mike MacFaden, Kiran Addepalli
- # Riverstone Networks, 2000
- #
- # Returned to the RANCID crowd by andrew fort
- # Usage line
- set usage "Error: Usage: $argv0 \[-dV\] \[-noenable\] \
- \[-f cloginrc-file\] \[-c command\] \[-Evar=x\] \[-s script-file\] \
- \[-x command-file\] \[-t timeout\] \[-o output-file\] \
- router \[router...\]\n"
- # program diagnostics
- set verbose 0
- set success 1
- set config 0
- # in seconds to wait for data back from device
- set timeoutdflt 10
- # Some CLIs having problems if we write too fast (Extreme, PIX, Cat)
- set send_human {.2 .1 .4 .2 1}
- set tempfile "/tmp/rivlogin.[exec date]"
- # cli command prompt
- set my_prompt ">"
- set enable_prompt "\#"
- set default_user ""
- set output_file ""
- set conf_prompt "*\(config\)# "
- set logging 0
- set config_mode 0
- # Save config, if prompted
- set do_saveconfig 0
- # Password file for routers to access
- set password_file $env(HOME)/.cloginrc
- # If no -c or -s specified, just automate router login ala rsh
- set do_command 0
- set do_script 0
- set log_user 0
- # The default CLI mode to login to is "enable" mode
- set avenable 1
- # The default is to look in the password file to find the passwords. This
- # tracks if we receive them on the command line.
- set do_passwd 1
- set do_enapasswd 1
- #
- set send_human {.4 .4 .7 .3 5}
- # Find the user in the ENV, or use the unix userid.
- if {[ info exists env(CISCO_USER) ]} {
- set default_user $env(CISCO_USER)
- } elseif {[ info exists env(USER) ]} {
- set default_user $env(USER)
- } elseif {[ info exists env(LOGNAME) ]} {
- set default_user $env(LOGNAME)
- } else {
- # This uses "id" which I think is portable. At least it has existed
- # (without options) on all machines/OSes I've been on recently -
- # unlike whoami or id -nu.
- if [ catch {exec id} reason ] {
- send_error "\nError: could not exec id: $reason\n"
- exit 1
- }
- regexp {\(([^)]*)} "$reason" junk default_user
- }
- if {[ info exists env(CLOGINRC) ]} {
- set password_file $env(CLOGINRC)
- }
- # Procedures Section
- #
- # 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 }
- }
- 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.
- # NOTES: Using this the password file has the form:
- # add password sl* pete cow
- # add password at* steve
- # add password * hanky-pie
- proc add { var args } {
- global $var
- lappend $var $args
- }
- # Loads the password file. Note that as this file is tcl, and that
- # it is sourced, the user better know what to put in there, as it
- # could install more than just password info... I will assume however,
- # that a "bad guy" could just as easy put such code in the clogin
- # script, so I will leave .cloginrc as just an extention of that script
- proc source_password_file { } {
- global env password_file read_password_file
- if { [info exists read_password_file] } {
- return 1
- }
- if { [info exists password_file] == 0 } {
- set password_file $env(HOME)/.cloginrc
- }
- set read_password_file 1
- file stat $password_file fileinfo
- if { [expr ($fileinfo(mode) & 007)] != 0000 } {
- puts "ERROR: $password_file must not be group or world readable and writable\n"
- return 1
- }
- source $password_file
- }
- # pre: var is x, router is y
- # post: return routerr entry from database else null string
- proc find { var router } {
- if {[ source_password_file ] == 0 } {
- return {}
- }
- upvar $var list
- if { [info exists list] } {
- foreach line $list {
- if { [string match -nocase [lindex $line 0] $router ] } {
- return [lrange $line 1 end]
- }
- }
- }
- return {}
- }
- # pre: login completed ok
- # post: terminate login session by closing tcp connection
- proc auto_exit { } {
- global telnet_id
- if { $verbose == 1 } {
- puts "DEBUG: auto_exit closing connection to pid $telnet_id\n"
- }
- close -i telnet_id
- }
- # perform login basic to a router
- # pre: args are valid, router is reachable via network
- # post: return 0 on successful login, else 1
- #
- # NOTE: a number of globals are setup: my_prompt, telnet_id are key
- # and paging of cli output is disabled
- proc login { router user userpswd passwd enapasswd } {
- global login_array
- global telnet_id
- global expect_out
- global spawn_id
- global verbose
- global config verbose my_prompt
- if { $verbose == 1 } {
- puts "DEBUG: login router = $router"
- puts "DEBUG: login username = $user"
- puts "DEBUG: login userpasswd = $userpswd"
- puts "DEBUG: login passwd = $passwd"
- puts "DEBUG: login enapasswd = $enapasswd"
- }
- spawn -noecho telnet $router
- set telnet_id $spawn_id
- if { $telnet_id == 0 } {
- puts "ERROR: login: spawn telnet session failed.\n"
- return 1
- }
- # wait for initial 'Press RETURN to...' response
- sleep 0.3
- expect "*"
- send "\r"
- # If password fails 3 times then expect again
- set pass_attempt 0
- expect {
- -re ".*> " { }
- "Password:" {
- incr pass_attempt
- send -- "$passwd\r"
- exp_continue
- }
- "Username: " {
- set pattempt 0
- send -- "$user\r"
- expect {
- "Password: " {
- incr pattempt
- if {$pattempt == 1} {
- send -- "$userpswd\r";
- } else {
- send -- "$enapasswd\r";
- }
- exp_continue
- }
- -re ".*> " { exp_continue;}
- }
- }
- "%TELNETD-W-BADPASSWD" {
- puts "ERROR: bad userid or password to telnet."
- return 1
- }
- "%CONS-W-AUTH_PASSWD" {
- exp_continue
- }
- "% Authentication failed." {
- puts "ERROR: bad userid or password to telnet."
- return 1
- }
- "Authentication Failed:" {
- puts "ERROR: bad userid or password to radius/tacacs+"
- return 1
- }
- "Connection closed *" {
- if {$pass_attempt == 3} {
- puts "ERROR: Maximum attempts for password reached. Check password. Exiting.";
- puts $expect_out(0,string);
- return 1
- }
- }
- timeout {
- puts "ERROR: Timeout on login. Exiting.";
- return 1
- }
- eof {
- puts "ERROR: device closed telnet connection during login"
- return 1
- }
- }
- # save my_prompt for later use
- send "\r"
- expect -re ".*> "
- set abc "$expect_out(buffer)"
- set my_prompt "[lindex $abc 0]"
- regexp {(.*[^>])} $my_prompt my
- return 0;
- }
- # pre: login completed ok
- # post: turn off paging of commands
- proc disable_cli_paging { } {
- global my_prompt
- send "cli set terminal rows 0\r"
- expect {
- "$my_prompt" {return 0 }
- }
- return 1
- }
- # pre: login returned 0, prompt at top level
- # post: turn off command completion return 0
- # on error, return 1
- proc disable_cmd_autocomplete { } {
- global my_prompt
- send "cli set command completion off\r"
- expect {
- $my_prompt { }
- timeout {
- puts "ERROR:disable_cmd_autocomplete(TIMEOUT)";
- return 0;
- }
- }
- return 0
- }
- # pre: login returned 0, do_enable returned 0, cli is in enable or config mode
- # post: issues logout cli to device, returns 0
- proc logout { prompt } {
- global config_mode enable_prompt
- # in case of not being at root cmd...
- # verify top level prompt state, move to it if necessary
- if { $config_mode == 1 } {
- send "exit\r"
- expect {
- "Do you want*" {
- send "no\r"
- }
- "$enable_prompt" { }
- timeout { puts "ERROR: logout: timeout from config mode\n" }
- eof { puts "ERROR: device dropped connection\n" }
- }
- set config_mode 0
- }
- send "logout\r"
- expect {
- "Are you sure*" {
- send "yes\r"
- return 0
- }
- }
- }
- # pre: current mode allows transition to enable mode
- # post: enable mode entered, my_prompt updated, return 0 else 1
- proc do_enable { enauser enapasswd userpswd } {
- global expect_out verbose
- global my_prompt enable_prompt
- set enable_prompt [ string trimright $my_prompt ">" ]
- set enable_prompt $enable_prompt\#
- set uses_username 0;
- if { $verbose == 1 } {
- puts "DEBUG: do_enable: my_prompt = $my_prompt ena_prompt = $enable_prompt"
- }
- send "enable\r"
- expect {
- Username: {
- set uses_username 1;
- send -- "$enauser\r";
- exp_continue
- }
- Password: {
- if {$uses_username == 1} {
- send -- "$userpswd\r";
- } else {
- send -- "$enapasswd\r";
- }
- exp_continue
- }
- "$my_prompt" {
- puts "ERROR: do_enable failed to gain enable mode."
- return 1
- }
- "CONS-W-AUTH_PASSWD" { send -- "$enapasswd\r"; }
- "$enable_prompt " { }
- "%SYS-W-NOPASSWD*" { }
- "Authentication Failed: Access Denied" {
- puts "ERROR: Bad user or password for enable mode."
- return 1
- }
- }
- set my_prompt $enable_prompt
- return 0
- }
- # pre: current mode allows transition to enable mode
- # post: enable mode entered, my_prompt updated, return 0 else 1
- proc do_configure { } {
- global expect_out verbose config_mode
- global my_prompt
- set config_prompt [ string trimright $my_prompt "\#" ]
- set config_prompt $config_prompt\(config\)\#
- if { $verbose == 1 } {
- puts "DEBUG: do_config: my_prompt = $my_prompt cfg_prompt = $config_prompt"
- }
- send "configure\r"
- expect {
- "$config_prompt " { }
- "$my_prompt" { }
- eof { return 1}
- timeout { return 1}
- }
- set config_mode 1
- set my_prompt $config_prompt
- return 0
- }
- # track sent/received from device to output_file
- # pre: outut_file is valid filename w/write access
- # post: logfile open, global var logging == 1, return 0 , else 1
- proc start_logfile { output_file } {
- global logging
- if { [ string length $output_file ] != 0 } {
- set rc [ catch { log_file -noappend $output_file } errMsg ]
- if { $rc != 0 } {
- puts "ERROR: open file $output_file for write access failed. $errMsg\n"
- return 1
- }
- set logging 1
- }
- return 0
- }
- proc run_commands { prompt cmdstring } {
- global sendstring
- # 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 $cmdstring]
- for {set i 0} {$i < $num_commands} { incr i} {
- regsub -- {[ ]*([^\.]*)} [subst -nocommands [lindex $commands $i]] {\1} sendstring
- if {[ run_single_command $prompt $sendstring ] == 1} {
- puts "ERROR: command '$sendstring' not processed by device. Check previous error messages."
- return 1
- }
- }
- return 0
- }
- # Run commands given on the command line
- # pre: prompt is current system cli prompt, cmdstring is command to execute
- # post: return 0 on success else 1
- # NOTE: output from router ends up in output_file if specified
- # expect internal input buffer is reset to "" after each command
- proc run_single_command { prompt cmdstring } {
- global verbose
- set rc 0
- set seen_prompt 0
- set seen_timeout 0
- set need_ays 0
- set delay 0
- if {$verbose == 1} {
- puts "DEBUG: run_commands: prompt=$prompt \"$cmdstring\" "
- }
- # ays == "are you sure" - must send back yes
- if { [string compare $cmdstring "save startup" ] == 0 } {
- set need_ays 1
- set delay 1
- if {$verbose == 1} {
- puts "DEBUG: save startup cmd seen, set need_ays = 1"
- }
- }
- # TODO: add case for copy command to startup, also prompts for ok
- # TODO: if we see config command: system set name note it
- # if we see a save active, then update system prompts as well
- send "$cmdstring\r"
- if { $delay == 1} {
- sleep 1
- }
- expect {
- "%CLI-E-IVCMD*" {
- puts "ERROR: run_commands(command rejected by device)\n"
- set rc 1
- }
- "%CLI-E-FACUNKNWN*" {
- puts "ERROR: run_commands(command rejected by device)\n"
- set rc 1
- }
- "%SYS-I-ADDFAILED*" {
- puts "ERROR: run_commands(command rejected by device)\n"
- set rc 1
- }
- "%TFTP-E-REMOTE,*" {
- puts "ERROR: run_commands(command rejected by device)\n"
- set rc 1
- }
- "%SYS-E-PRIMARY_NO_SUCH_IMAGE*" {
- puts "ERROR: run_commands(command rejected by device)\n"
- set rc 1
- }
- "want to overwrite " {
- send "yes\r"
- if {$verbose == 1} {
- puts "DEBUG: got overwrite question, set need_ays to 0"
- }
- set need_ays 0
- }
- "%CONFIG-E-DUPLICATE,*" { }
- "$prompt" {
- if { $seen_prompt == 0 } {
- set seen_prompt 1
- }
- if {$verbose == 1} {
- puts "DEBUG: saw double prompt, exiting expect loop\n"
- }
- if { $need_ays == 1 } {
- exp_continue
- }
- }
- -re ".* More: m,<space> --- Quit: q --- One line: <return> ---" {
- send "q"
- exp_continue
- }
- timeout {
- if {$verbose == 1} {
- puts "DEBUG: timeout occured for the $seen_time time\n"
- }
- if { $seen_timeout == 0 } {
- set seen_timeout 1
- send "\r\r"
- exp_continue
- }
- puts "ERROR:run_commands(TIMEOUT)"
- set rc 1
- }
- eof {
- puts "ERROR:run_commands(connection closed by device)\n"
- set rc 1
- }
- "\n" { exp_continue }
- }
- # clear input buffer of any remaining data
- expect "*"
- return $rc
- }
- # pre: RSTONE_USER env var is set
- # post: update global "default_user" to this string
- proc init_userid { } {
- global default_user
- if {[ info exists env(RSTONE_USER) ] } {
- set default_user $env(RSTONE_USER)
- } else {
- # This uses "id" which I think is portable. At least it has existed
- # (without options) on all machines/OSes I've been on recently -
- # unlike whoami or id -nu.
- regexp {\(([^)]*)} [exec id] junk default_user
- }
- }
- proc source_script_file { filename } {
- global my_prompt
- expect -re "$my_prompt" {}
- source $filename
- }
- # pre: login completed ok, filename contains set of cli commands one per line
- # post: each command is extracted from filename and sent to device
- # return 0 on success, return 1 on error
- # NOTE: for scripts that begin with "configure", change the mode to configure
- # before executing the following commands
- proc process_script_file { filename } {
- global my_prompt verbose
- set rc 0
- set ifile ""
- set rc [ catch { set ifile [ open $filename r] } errMsg ]
- if { $rc != 0 } {
- puts "ERROR: process_script_file: open script file $filename for read access failed. $errMsg\n"
- return 1
- }
- set line_cnt 0
- while { [eof $ifile] != 1 } {
- set bytes [ gets $ifile cmd ]
- incr line_cnt
- if { $bytes < 0 } {
- break
- } elseif { $bytes == 0 } {
- continue
- }
- if { $verbose == 1 } {
- puts "DEBUG: line:$line_cnt cmd = $cmd\n"
- }
- # skip comments in script files
- if { [regexp "^\#" $cmd] != 1 } {
- # puts "$cmd rc = [string compare $cmd "configure" ]\n"
- if { [string compare $cmd "configure" ] == 0 } {
- do_configure
- } else {
- if {[ run_commands $my_prompt $cmd ] == 1} {
- puts "ERROR: line $line_cnt in $filename not processed by device. Check previous error msgs."
- set rc 1
- break
- }
- }
- }
- }
- close $ifile
- return $rc
- }
- # pre: filename is valid file
- # post: remove extended ascii sequences and other cruft
- # and prepend a header: rscmd: ip-addr : date
- # TODO: should watch all file commands more closely
- proc strip_log { filename router } {
- global tempfile
- set rc [ catch { set ifile [ open $filename r] } errMsg ]
- if { $rc != 0 } {
- puts "ERROR: strip_log: open script file $filename for read access failed. $errMsg\n"
- return 1
- }
- set rc [ catch { set ofile [ open $tempfile w] } errMsg ]
- if { $rc != 0 } {
- puts "ERROR: strip_log: open temp file $tempfile for write access failed. $errMsg\n"
- return 1
- }
- set nl 0
- puts $ofile "rscmd: $router : [exec date]"
- while { [eof $ifile] != 1 } {
- set bytes [ gets $ifile cmd ]
- if { $bytes <= 0 } {
- break
- }
- incr nl
- if { $nl <= 2 } {
- continue
- }
- regsub -all -- "\r" $cmd "" newcmd
- puts $ofile $newcmd
- }
- close $ifile
- close $ofile
- set rc 0
- file copy -force $tempfile $filename
- file delete $tempfile
- return $rc
- }
- #
- # main section
- #
- if { $verbose == 1 } {
- puts "\n\nrscmd: Version 1.1 started on [exec date]"
- puts "[exec uname -a]"
- puts "Expect Version: [exp_version]\n"
- }
- # send input like in a fast and consistent human style
- set send_human {.1 .3 1 .05 2}
- # initialize default_user variable
- init_userid
- # Parse Command Line
- for {set idx 0} {$idx < $argc} {incr idx} {
- set arg [lindex $argv $idx]
- switch -glob -- $arg {
- -c* {
- if {! [ regexp .\[cC\](.+) $arg ignore command]} {
- incr idx
- set command [ lindex $argv $idx ]
- }
- set do_command 1
- # Expect debug mode
- } -d* {
- exp_internal 1
- # Environment variable to pass to -s scripts
- } -E*
- {
- if {[ regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} {
- set E$varname $varvalue
- } else {
- send_user "Error: invalid format for -E in $arg\n"
- exit 1
- }
- # Expect script to run
- } -s* {
- if {! [ regexp .\[sS\](.+) $arg ignore sfile]} {
- incr idx
- set sfile [ lindex $argv $idx ]
- }
- if { ! [ file exists $sfile ] } {
- puts "ERROR: invalid argument script file \"$sfile\" does not exist.\n"
- exit 1
- }
- if { ! [ file readable $sfile ] } {
- puts "ERROR: invalid argument script file \"$sfile\" permissions disallow read access.\n"
- exit 1
- }
- set do_script 1
- # save config on exit
- } -S* {
- set do_saveconfig 1
- # Version string
- } -V* {
- send_user "rancid 3.4.1\n"
- exit 0
- # Command file
- } -x* {
- if {! [ regexp .\[xX\](.+) $arg ignore cmd_file]} {
- incr idx
- set cmd_file [ lindex $argv $idx ]
- }
- 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
- } -f* {
- if {! [ regexp .\[fF\](.+) $arg ignore password_file]} {
- incr idx
- set password_file [ lindex $argv $idx ]
- }
- } -o* {
- if {! [ regexp .\[fF\](.+) $arg ignore password_file]} {
- incr idx
- set output_file [ lindex $argv $idx ]
- if { $verbose == 1 } {
- puts "DEBUG: output file: $output_file"
- }
- }
- # Timeout
- } -t* {
- incr idx
- set timeoutdflt [ lindex $argv $idx ]
- # Do we enable?
- } -noenable {
- set avenable 0
- } -* {
- send_user "Error: Unkown argument! $arg\n"
- send_user $usage
- exit 1
- } default {
- break
- }
- }
- }
- # Verify at least one router is specified
- #
- if { $idx == $argc } {
- puts "\n$usage"
- exit 1
- }
- # main loop
- set exitval 0
- foreach router [lrange $argv $idx end] {
- set router [string tolower $router]
- send_user -- "$router\n"
- # device timeout
- set timeout [find timeout $router]
- if { [llength $timeout] == 0 } {
- set timeout $timeoutdflt
- }
- # Figure out passwords
- if {$verbose == 1} {
- puts "DEBUG: do_passwd = $do_passwd\n"
- puts "DEBUG: do_enablepasswd = $do_enapasswd\n"
- }
- # look for noenable option in .cloginrc
- if { [find noenable $router] == "1" } {
- set enable 0
- } else {
- set enable $avenable
- }
- if { $do_passwd || $do_enapasswd } {
- set pswd [find password $router]
- if { [llength $pswd] == 0 } {
- puts "ERROR: - no password for $router in $password_file.\n"
- exit 1
- }
- if { $do_enapasswd && [llength $pswd] < 2 } {
- puts "ERROR: no enable password found for $router in $password_file."
- exit 1
- }
- set passwd [join [lindex $pswd 0] ""]
- set enapasswd [join [lindex $pswd 1] ""]
- } else {
- set passwd $userpasswd
- set enapasswd $enapasswd
- }
- # Figure out user to login with if necessary
- if {[info exists username]} {
- # command line username
- set user $username
- } else {
- set user [join [find user $router] ""]
- if { "$user" == "" } { set user $default_user }
- }
- # Figure out username's password
- if {[info exists userpasswd]} {
- # command line username
- set userpswd $userpasswd
- } else {
- set userpswd [join [find userpassword $router] ""]
- if { "$userpswd" == "" } { set userpswd $passwd }
- }
- # Figure out enable username
- if {[info exists enausername]} {
- # command line enausername
- set enauser $enausername
- } else {
- set enauser [join [find enauser $router] ""]
- if { "$enauser" == "" } { set enauser $user }
- }
- # Login to the router, set my_prompt to router's cmd prompt
- if {[login $router $user $userpswd $passwd $enapasswd ]} {
- incr exitval
- if { $verbose == 1 } {
- puts "DEBUG: login to $router failed\n"
- }
- exit 1
- }
- if {$verbose == 1 } {
- puts "DEBUG: login completed ok\n"
- }
- if { $enable == 1 } {
- if { [do_enable $enauser $enapasswd $userpswd] == 1} {
- incr exitval
- if { $verbose == 1 } {
- puts "DEBUG: switch to enable mode on $router failed\n"
- }
- exit 1
- }
- }
- # run in one of three modes
- if { $do_command } {
- disable_cmd_autocomplete
- disable_cli_paging
- if { [start_logfile $output_file] != 0 } {
- exit 1
- }
- if {[ run_commands $my_prompt $command ]} {
- incr exitval
- log_file
- exit 1
- } else {
- logout $my_prompt
- }
- } elseif { $do_script } {
- disable_cmd_autocomplete
- disable_cli_paging
- if {[ start_logfile $output_file] != 0 } {
- exit 1
- }
- # if { [process_script_file $sfile] == 1}{
- # puts "DEBUG: logfile $output_file closed on error\n"
- # logout $my_prompt
- # exit 1
- # }
- source_script_file $sfile
- logout $my_prompt
- } else {
- label $router
- log_user 1
- if {[ start_logfile $output_file] != 0 } {
- exit 1
- }
- interact
- log_file
- }
- if { $verbose == 1 } {
- puts "DEBUG: exiting normally.\n"
- }
- if { $logging == 1} {
- log_file
- strip_log $output_file $router
- }
- # End of for each router
- catch {wait};
- sleep 0.3
- }
- exit $exitval
- #! /usr/bin/perl
- ##
- ## $Id: rivrancid.in 3018 2015-01-11 05:51:49Z heas $
- ##
- ## rancid 3.4.1
- ## Copyright (c) 1997-2016 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.
- #
- # Amazingly hacked version of Hank's rancid - this one tries to
- # deal with Cabletron, Riverstone and Enterasys routers/switches
- #
- # 10/23/2002 -- Initial changes for Riverstone/Cabletron support
- # Jim Meehan -- jmeehan@vpizza.org
- #
- # RANCID - Really Awesome New Cisco confIg Differ
- #
- # usage: rivrancid [-dltCV] [-f filename | hostname]
- #
- use Getopt::Std;
- getopts('dflt:CV');
- if ($opt_V) {
- print "rancid 3.4.1\n";
- exit(0);
- }
- $log = $opt_l;
- $debug = $opt_d;
- $file = $opt_f;
- $host = $ARGV[0];
- $clean_run = 0;
- $found_end = 0;
- $timeo = 90; # rivlogin timeout in seconds
- my(@commandtable, %commands, @commands);# command lists
- my($aclsort) = ("ipsort"); # ACL sorting mode
- my($filter_commstr); # SNMP community string filtering
- my($filter_pwds); # password filtering mode
- # This routine is used to print out the router configuration
- sub ProcessHistory {
- my($new_hist_tag,$new_command,$command_string,@string) = (@_);
- if ((($new_hist_tag ne $hist_tag) || ($new_command ne $command))
- && scalar(%history)) {
- print eval "$command \%history";
- undef %history;
- }
- if (($new_hist_tag) && ($new_command) && ($command_string)) {
- if ($history{$command_string}) {
- $history{$command_string} = "$history{$command_string}@string";
- } else {
- $history{$command_string} = "@string";
- }
- } elsif (($new_hist_tag) && ($new_command)) {
- $history{++$#history} = "@string";
- } else {
- print "@string";
- }
- $hist_tag = $new_hist_tag;
- $command = $new_command;
- 1;
- }
- sub numerically { $a <=> $b; }
- # This is a sort routine that will sort numerically on the
- # keys of a hash as if it were a normal array.
- sub keynsort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $key (sort numerically keys(%lines)) {
- $sorted_lines[$i] = $lines{$key};
- $i++;
- }
- @sorted_lines;
- }
- # This is a sort routine that will sort on the
- # keys of a hash as if it were a normal array.
- sub keysort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $key (sort keys(%lines)) {
- $sorted_lines[$i] = $lines{$key};
- $i++;
- }
- @sorted_lines;
- }
- # This is a sort routine that will sort on the
- # values of a hash as if it were a normal array.
- sub valsort{
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $key (sort values %lines) {
- $sorted_lines[$i] = $key;
- $i++;
- }
- @sorted_lines;
- }
- # This is a numerical sort routine (ascending).
- sub numsort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $num (sort {$a <=> $b} keys %lines) {
- $sorted_lines[$i] = $lines{$num};
- $i++;
- }
- @sorted_lines;
- }
- # This is a sort routine that will sort on the
- # ip address when the ip address is anywhere in
- # the strings.
- sub ipsort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $addr (sort sortbyipaddr keys %lines) {
- $sorted_lines[$i] = $lines{$addr};
- $i++;
- }
- @sorted_lines;
- }
- # These two routines will sort based upon IP addresses
- sub ipaddrval {
- my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#);
- $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0]));
- }
- sub sortbyipaddr {
- &ipaddrval($a) <=> &ipaddrval($b);
- }
- # This routine parses "system show version"
- sub ShowVersion {
- my($slot);
- print STDERR " In ShowVersion: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- next if /^\s*$/;
- last if(/^$prompt/);
- ProcessHistory("VERSION","","","!SW: $_");
- }
- ProcessHistory("VERSION","","","!\n");
- return(0);
- }
- # This routine parses "system show hardware"
- sub ShowHardware {
- print STDERR " In ShowHardware: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- last if (/^$prompt/);
- ProcessHistory("HARDWARE","","","!HW: $_");
- }
- ProcessHistory("","","","!\n");
- return(0);
- }
- # This routine parses "system show uptime"
- sub ShowUptime {
- print STDERR " In ShowUptime: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- last if(/^$prompt/);
- next if /^\s*$/;
- next if /System up/;
- ProcessHistory("UPTIME","","","!UPTIME: $_");
- }
- ProcessHistory("","","","!\n");
- return;
- }
- # This routine processes a "system show active"
- sub ShowActive {
- print STDERR " In ShowActive: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- # Remove leading whitespace and/or line numbers
- s/^\s*(\d+\D: )*//;
- # Riverstone/Cabletron doesn't have an "end" line, so
- # we need to set $clean_run here
- if (/^$prompt/) {
- $clean_run = 1;
- last;
- }
- next if (/Running system configuration/);
- # filter out any RCS/CVS tags to avoid confusing local CVS storage
- s/\$(Revision|Id):/ $1:/;
- if (/^(.*hashed-password \S+)/ && $filter_pwds == 2) {
- ProcessHistory("","","","! $1 <removed>\n");
- next;
- }
- if (/^(snmp set community )\S+/ && $filter_commstr) {
- ProcessHistory("","","","! $1<removed>$'");
- next;
- }
- ProcessHistory("","","","$_");
- }
- return;
- }
- # Main
- @commandtable = (
- {'system show uptime' => 'ShowUptime'},
- {'system show version' => 'ShowVersion'},
- {'system show hardware' => 'ShowHardware'},
- {'system show active-config' => 'ShowActive'}
- );
- # Use an array to preserve the order of the commands and a hash for mapping
- # commands to the subroutine and track commands that have been completed.
- @commands = map(keys(%$_), @commandtable);
- %commands = map(%$_, @commandtable);
- $commandcnt = scalar(keys %commands);
- $commandstr=join(";",@commands);
- $cmds_regexp = join("|", map quotemeta($_), @commands);
- if (length($host) == 0) {
- if ($file) {
- print(STDERR "Too few arguments: file name required\n");
- exit(1);
- } else {
- print(STDERR "Too few arguments: host name required\n");
- exit(1);
- }
- }
- if ($opt_C) {
- print "rivlogin -t $timeo -c\'$commandstr\' $host\n";
- exit(0);
- }
- open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n";
- select(OUTPUT);
- # make OUTPUT unbuffered if debugging
- if ($debug) { $| = 1; }
- if ($file) {
- print STDERR "opening file $host\n" if ($debug);
- print STDOUT "opening file $host\n" if ($log);
- open(INPUT,"<$host") || die "open failed for $host: $!\n";
- } else {
- print STDERR "executing rivlogin -t $timeo -c\"$commandstr\" $host\n" if ($debug);
- print STDOUT "executing rivlogin -t $timeo -c\"$commandstr\" $host\n" if ($log);
- if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
- system "rivlogin -t $timeo -c \"$commandstr\" $host </dev/null > $host.raw 2>&1" || die "rivlogin failed for $host: $!\n";
- open(INPUT, "< $host.raw") || die "rivlogin failed for $host: $!\n";
- } else {
- open(INPUT,"rivlogin -t $timeo -c \"$commandstr\" $host </dev/null |") || die "rivlogin failed for $host: $!\n";
- }
- }
- # determine ACL sorting mode
- if ($ENV{"ACLSORT"} =~ /no/i) {
- $aclsort = "";
- }
- # determine community string filtering mode
- if (defined($ENV{"NOCOMMSTR"}) &&
- ($ENV{"NOCOMMSTR"} =~ /yes/i || $ENV{"NOCOMMSTR"} =~ /^$/)) {
- $filter_commstr = 1;
- } else {
- $filter_commstr = 0;
- }
- # determine password filtering mode
- if ($ENV{"FILTER_PWDS"} =~ /no/i) {
- $filter_pwds = 0;
- } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) {
- $filter_pwds = 2;
- } else {
- $filter_pwds = 1;
- }
- ProcessHistory("","","","!RANCID-CONTENT-TYPE: riverstone\n!\n");
- TOP: while(<INPUT>) {
- tr/\015//d;
- last if ($clean_run);
- if (/^Error:/) {
- print STDOUT ("$host rivlogin error: $_");
- print STDERR ("$host rivlogin error: $_") if ($debug);
- $clean_run=0;
- last;
- }
- $kradcount++;
- while (/\033(\[\?25l)/) {
- s/\033\[\?25l//g;
- #print STDERR "krad $1\n";
- #print STDERR $_;
- #print STDERR $kradcount;
- next;
- }
- while (/#\s*($cmds_regexp)\s*$/) {
- $cmd = $1;
- if (!defined($prompt)) {
- $prompt = ($_ =~ /^([^#]+#)/)[0];
- $prompt =~ s/([}{)(\\])/\\$1/g;
- }
- 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;
- }
- }
- }
- print STDOUT "Done $logincmd: $_\n" if ($log);
- # Flush History
- ProcessHistory("","","","");
- # Cleanup
- close(INPUT);
- close(OUTPUT);
- if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
- unlink("$host.raw") if (! $debug);
- }
- # check for completeness
- if (scalar(%commands) || !$clean_run) {
- if (scalar(keys %commands) eq $commandcnt) {
- printf(STDERR "$host: missed cmd(s): all commands\n");
- } elsif (scalar(%commands)) {
- printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands)));
- printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug);
- }
- if (!$clean_run) {
- print STDOUT "$host: End of run not found\n";
- print STDERR "$host: End of run not found\n" if ($debug);
- system("/usr/bin/tail -1 $host.new");
- }
- unlink "$host.new" if (! $debug);
- }
- #! /usr/bin/perl
- ##
- ## $Id: rrancid.in 3018 2015-01-11 05:51:49Z heas $
- ##
- ## rancid 3.4.1
- ## Copyright (c) 1997-2016 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.
- #
- # hacked version of Hank's rancid - this one tries to deal with redbacks.
- #
- # RANCID - Really Awesome New Cisco confIg Differ
- #
- # usage: rrancid [-dltCV] [-f filename | hostname]
- #
- use Getopt::Std;
- getopts('dflt:CV');
- if ($opt_V) {
- print "rancid 3.4.1\n";
- exit(0);
- }
- $log = $opt_l;
- $debug = $opt_d;
- $file = $opt_f;
- $host = $ARGV[0];
- $clean_run = 0;
- $found_end = 0;
- $timeo = 90; # clogin timeout in seconds
- my(@commandtable, %commands, @commands);# command lists
- my($aclsort) = ("ipsort"); # ACL sorting mode
- my($filter_commstr); # SNMP community string filtering
- my($filter_pwds); # password filtering mode
- # This routine is used to print out the router configuration
- sub ProcessHistory {
- my($new_hist_tag,$new_command,$command_string,@string) = (@_);
- if ((($new_hist_tag ne $hist_tag) || ($new_command ne $command))
- && scalar(%history)) {
- print eval "$command \%history";
- undef %history;
- }
- if (($new_hist_tag) && ($new_command) && ($command_string)) {
- if ($history{$command_string}) {
- $history{$command_string} = "$history{$command_string}@string";
- } else {
- $history{$command_string} = "@string";
- }
- } elsif (($new_hist_tag) && ($new_command)) {
- $history{++$#history} = "@string";
- } else {
- print "@string";
- }
- $hist_tag = $new_hist_tag;
- $command = $new_command;
- 1;
- }
- sub numerically { $a <=> $b; }
- # This is a sort routine that will sort numerically on the
- # keys of a hash as if it were a normal array.
- sub keynsort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $key (sort numerically keys(%lines)) {
- $sorted_lines[$i] = $lines{$key};
- $i++;
- }
- @sorted_lines;
- }
- # This is a sort routine that will sort on the
- # keys of a hash as if it were a normal array.
- sub keysort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $key (sort keys(%lines)) {
- $sorted_lines[$i] = $lines{$key};
- $i++;
- }
- @sorted_lines;
- }
- # This is a sort routine that will sort on the
- # values of a hash as if it were a normal array.
- sub valsort{
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $key (sort values %lines) {
- $sorted_lines[$i] = $key;
- $i++;
- }
- @sorted_lines;
- }
- # This is a numerical sort routine (ascending).
- sub numsort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $num (sort {$a <=> $b} keys %lines) {
- $sorted_lines[$i] = $lines{$num};
- $i++;
- }
- @sorted_lines;
- }
- # This is a sort routine that will sort on the
- # ip address when the ip address is anywhere in
- # the strings.
- sub ipsort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $addr (sort sortbyipaddr keys %lines) {
- $sorted_lines[$i] = $lines{$addr};
- $i++;
- }
- @sorted_lines;
- }
- # These two routines will sort based upon IP addresses
- sub ipaddrval {
- my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#);
- $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0]));
- }
- sub sortbyipaddr {
- &ipaddrval($a) <=> &ipaddrval($b);
- }
- # This routine parses "show version"
- sub ShowVersion {
- print STDERR " In ShowVersion: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- last if(/^$prompt/);
- /(Copyright|uptime|restarted|^\s*$)/ && next;
- /(Up Time|Boot Time)/ && next;
- ProcessHistory("COMMENTS","keysort","A1","!Image: $_");
- }
- return;
- }
- # This routine parses "dir /<fsys>"
- sub DirFlash {
- print STDERR " In DirFlash: $_" if ($debug);
- my($dev) = (/\/(.*)$/);
- while (<INPUT>) {
- tr/\015//d;
- last if(/^$prompt/);
- /^\s*$/ && next;
- /(Can\'t open|No such device)/ && return;
- /is not a valid path on a local file system/ && return;
- ProcessHistory("FLASH","keysort",$dev,"!Flash: $dev: $_");
- }
- ProcessHistory("FLASH","keysort",$dev,"!\n");
- return;
- }
- # This routine parses "show hardware"
- sub ShowHardware {
- print STDERR " In ShowHardware: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- last if(/^$prompt/);
- s/\s*$/\n/;
- /Can not retrieve information/ && return;
- /^Temperature:/ && next;
- /^Voltage/ && next;
- /^$/ && next;
- #ProcessHistory("","","","!Chassis: $_") && next;
- ProcessHistory("COMMENTS","keysort","B1","!Chassis: $_");
- }
- ProcessHistory("COMMENTS","keysort","B1","!\n");
- return;
- }
- # This routine parses "show chassis"
- sub ShowChassis {
- print STDERR " In ShowChassis: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- last if(/^$prompt/);
- last if(/^invalid input at/i);
- next if(/^(\s*|\s*$cmd\s*|\s+\^)$/);
- ProcessHistory("COMMENTS","keysort","C1","!Chassis: $_");
- }
- ProcessHistory("COMMENTS","keysort","C1","!\n");
- return;
- }
- # This routine parses "show slot table"
- sub ShowSlotTable {
- print STDERR " In ShowSlotTable: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- last if(/^$prompt/);
- /(Slot Table|^$)/ && next;
- /^\s+\^/ && next;
- /Invalid input at/ && return;
- s/^\s*//;
- ProcessHistory("COMMENTS","keysort","D1","!Slot Table: $_");
- }
- ProcessHistory("COMMENTS","keysort","D1","!\n");
- return;
- }
- # This routine processes a "write term"
- sub WriteTerm {
- print STDERR " In WriteTerm: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- last if(/^$prompt/);
- next if(/^\s*$/);
- # /Non-Volatile memory is in use/ && return(-1); # NvRAM is locked
- # Dog gone Cool matches to process the rest of the config
- /^! last updated: .*$/ && next; # kill last updated line
- /^Building configuration/ && next; # kill Building config line
- /^Current configuration/ && next; # kill Current config line
- /^! Configuration last changed by user / && next;
- /^ length / && next; # kill length on serial lines
- /^ width / && next; # kill width on serial lines
- # filter out any RCS/CVS tags to avoid confusing local CVS storage
- s/\$(Revision|Id):/ $1:/;
- # order access-lists
- /^access-list\s+(\d\d?)\s+(\S+)\s+(\S+)/ &&
- ProcessHistory("ACL $1 $2","$aclsort","$3","$_") && next;
- # prune snmp community statements
- if (/^snmp (group|community) (\S+)/) {
- if ($filter_commstr) {
- ProcessHistory("SNMPSERVERCOMM","keysort","$_","!snmp $1 <removed>$'") && next;
- } else {
- ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && next;
- }
- }
- ProcessHistory("","","","$_");
- # end of config
- if (/^end$/) {
- $found_end = 1;
- last;
- }
- }
- return;
- }
- # Main subroutine that splits up the work
- # All Subs return the name of the next function to use.
- # If the sub returns a new funtion name, that name will be used
- # else the main loop keeps using the current function
- sub FlailHelplessly {
- print STDERR "Flailing: $_" if ($debug);
- print STDOUT "Flailing: $_" if ($log);
- /#(show version)$/ && delete($commands{$1}) && return("ShowVersion");
- /#(show hardware)$/ && delete($commands{$1}) && return("ShowHardware");
- /#(show chassis)$/ && delete($commands{$1}) && return("ShowChassis");
- /#(show slot table)$/ && delete($commands{$1}) && return("ShowSlotTable");
- /#(show config)$/ && delete($commands{$1}) && return("WriteTerm");
- return "FlailHelplessly";
- }
- # Main
- @commandtable = (
- {'show version' => 'ShowVersion'},
- {'dir /flash' => 'DirFlash'},
- {'dir /pcmcia0' => 'DirFlash'},
- {'dir /pcmcia1' => 'DirFlash'},
- {'show hardware' => 'ShowHardware'},
- {'show chassis' => 'ShowChassis'},
- {'show slot table' => 'ShowSlotTable'},
- {'show config' => 'WriteTerm'}
- );
- # Use an array to preserve the order of the commands and a hash for mapping
- # commands to the subroutine and track commands that have been completed.
- @commands = map(keys(%$_), @commandtable);
- %commands = map(%$_, @commandtable);
- $commandcnt = scalar(keys %commands);
- $redback_cmds=join(";",@commands);
- $cmds_regexp = join("|", map quotemeta($_), @commands);
- if (length($host) == 0) {
- if ($file) {
- print(STDERR "Too few arguments: file name required\n");
- exit(1);
- } else {
- print(STDERR "Too few arguments: host name required\n");
- exit(1);
- }
- }
- if ($opt_C) {
- print "clogin -t $timeo -c\'$commandstr\' $host\n";
- exit(0);
- }
- open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n";
- select(OUTPUT);
- # make OUTPUT unbuffered
- if ($debug) { $| = 1; }
- if ($file) {
- print STDERR "opening file $host\n" if ($debug);
- print STDOUT "opening file $host\n" if ($log);
- open(INPUT,"<$host") || die "open failed for $host: $!\n";
- } else {
- print STDERR "executing clogin -t $timeo -c\"$redback_cmds\" $host\n" if ($debug);
- print STDOUT "executing clogin -t $timeo -c\"$redback_cmds\" $host\n" if ($log);
- if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
- system "clogin -t $timeo -c \"$redback_cmds\" $host </dev/null > $host.raw" || die "clogin failed for $host: $!\n";
- open(INPUT, "< $host.raw") || die "clogin failed for $host: $!\n";
- } else {
- open(INPUT,"clogin -t $timeo -c \"$redback_cmds\" $host </dev/null |") || die "clogin failed for $host: $!\n";
- }
- }
- # determine ACL sorting mode
- if ($ENV{"ACLSORT"} =~ /no/i) {
- $aclsort = "";
- }
- # determine community string filtering mode
- if (defined($ENV{"NOCOMMSTR"}) &&
- ($ENV{"NOCOMMSTR"} =~ /yes/i || $ENV{"NOCOMMSTR"} =~ /^$/)) {
- $filter_commstr = 1;
- } else {
- $filter_commstr = 0;
- }
- # determine password filtering mode
- if ($ENV{"FILTER_PWDS"} =~ /no/i) {
- $filter_pwds = 0;
- } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) {
- $filter_pwds = 2;
- } else {
- $filter_pwds = 1;
- }
- ProcessHistory("","","","!RANCID-CONTENT-TYPE: redback\n!\n");
- ProcessHistory("COMMENTS","keysort","B0","!\n");
- ProcessHistory("COMMENTS","keysort","C0","!\n");
- ProcessHistory("COMMENTS","keysort","E0","!\n");
- while(<INPUT>) {
- tr/\015//d;
- if (/\#exit$/) {
- $clean_run=1;
- last;
- }
- if (/^Error:/) {
- print STDOUT ("$host clogin error: $_");
- print STDERR ("$host clogin error: $_") if ($debug);
- $clean_run=0;
- last;
- }
- while (/#\s*($cmds_regexp)\s*$/) {
- $cmd = $1;
- if (!defined($prompt)) {
- $prompt = ($_ =~ /^([^#]*#)/)[0];
- $prompt =~ s/([][}{)(\\])/\\$1/g; # quote the damn []'s
- 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;
- }
- $rval = &{$commands{$cmd}}(*INPUT, *OUTPUT, $cmd);
- delete($commands{$cmd});
- if ($rval == -1) {
- $clean_run = 0;
- last;
- }
- }
- }
- print STDOUT "Done $logincmd: $_\n" if ($log);
- # Flush History
- ProcessHistory("","","","");
- # Cleanup
- close(INPUT);
- close(OUTPUT);
- if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
- unlink("$host.raw") if (! $debug);
- }
- # check for completeness
- if (scalar(%commands) || !$clean_run || !$found_end) {
- if (scalar(keys %commands) eq $commandcnt) {
- printf(STDERR "$host: missed cmd(s): all commands\n");
- } elsif (scalar(%commands)) {
- printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands)));
- printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug);
- }
- if (!$clean_run || !$found_end) {
- print STDOUT "$host: End of run not found\n";
- print STDERR "$host: End of run not found\n" if ($debug);
- system("/usr/bin/tail -1 $host.new");
- }
- unlink "$host.new" if (! $debug);
- }
- #! /usr/bin/perl
- ##
- ## $Id: rtftpcopy.in 3187 2015-10-19 23:08:51Z heas $
- ##
- ## rancid 3.4.1
- ## Copyright (c) 1997-2016 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.
- #
- # copy configs from tftpboot within rancid; assumes CWD=<group>/configs and
- # that /bin/domainname is the same domainname as the routers, which is
- # replaced with "-confg" to form the filename expected in /tftpboot.
- #
- # usage: rtftpcopy [-dltCV] [-f filename | hostname]
- #
- use Getopt::Std;
- getopts('dflt:CV');
- if ($opt_V) {
- print "rancid 3.4.1\n";
- exit(0);
- }
- $log = $opt_l;
- $debug = $opt_d;
- $file = $opt_f;
- $host = $ARGV[0];
- $domain = system("/bin/domainname");
- $domain =~ s/[.]/\\./g;
- if ($file) {
- $srcfile = $host;
- $host =~ s/^.*\///;
- } else {
- $srcfile = $host;
- $srcfile =~ s/$domain$/-confg/;
- }
- if (length($host) == 0) {
- if ($file) {
- print(STDERR "Too few arguments: file name required\n");
- exit(1);
- } else {
- print(STDERR "Too few arguments: host name required\n");
- exit(1);
- }
- }
- if ($opt_C) {
- if ($file) {
- print "cp $srcfile $host.new\n";
- } else {
- print "cp /tftpboot/$srcfile $host.new\n";
- }
- exit(0);
- }
- if ($file) {
- print STDERR "copying file $host\n" if ($debug);
- print STDOUT "copying file $host\n" if ($log);
- system("/bin/cp $srcfile $host.new");
- } else {
- print STDERR "copying file $host\n" if ($debug);
- print STDOUT "copying file $host\n" if ($log);
- system("/bin/cp /tftpboot/$srcfile $host.new") == 0;
- }
- if (!$?) {
- print STDERR "copy failed: $!\n";
- }
- print STDOUT "Done cp: $_\n" if ($log);
- # check for completeness
- if (scalar(%commands) || !$clean_run || !$found_end) {
- if (scalar(keys %commands) eq $commandcnt) {
- printf(STDERR "$host: missed cmd(s): all commands\n");
- } elsif (scalar(%commands)) {
- printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands)));
- printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug);
- }
- if (!$clean_run || !$found_end) {
- print STDOUT "$host: End of run not found\n";
- print STDERR "$host: End of run not found\n" if ($debug);
- system("/usr/bin/tail -1 $host.new");
- }
- unlink "$host.new" if (! $debug);
- }
- #! /usr/bin/perl
- ##
- ## $Id: srancid.in 3229 2016-01-19 22:51:52Z heas $
- ##
- ## rancid 3.4.1
- ## Copyright (c) 1997-2016 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.
- #
- # Pretty huge hack to take care of Dell (aka. SMC) Switch configs; started by
- # d_pfleger@juniper.net
- #
- # RANCID - Really Awesome New Cisco confIg Differ
- #
- # usage: srancid [-dltCV] [-f filename | hostname]
- #
- # Code tested and working fine on these models:
- #
- # DELL PowerConnect M8024 / M8024-k
- # DELL PowerConnect M6348
- # DELL PowerConnect N2048, N4032F and N4064.
- # DELL PowerConnect 62xx
- # DELL 34xx (partially; configuration is incomplete)
- #
- use Getopt::Std;
- getopts('dflt:CV');
- if ($opt_V) {
- print "rancid 3.4.1\n";
- exit(0);
- }
- $log = $opt_l;
- $debug = $opt_d;
- $file = $opt_f;
- $host = $ARGV[0];
- $found_end = 0;
- $timeo = 90; # hlogin timeout in seconds
- my(@commandtable, %commands, @commands);# command lists
- my($aclsort) = ("ipsort"); # ACL sorting mode
- my($filter_commstr); # SNMP community string filtering
- my($filter_pwds); # password filtering mode
- # This routine is used to print out the router configuration
- sub ProcessHistory {
- my($new_hist_tag,$new_command,$command_string,@string) = (@_);
- if ((($new_hist_tag ne $hist_tag) || ($new_command ne $command))
- && scalar(%history)) {
- print eval "$command \%history";
- undef %history;
- }
- if (($new_hist_tag) && ($new_command) && ($command_string)) {
- if ($history{$command_string}) {
- $history{$command_string} = "$history{$command_string}@string";
- } else {
- $history{$command_string} = "@string";
- }
- } elsif (($new_hist_tag) && ($new_command)) {
- $history{++$#history} = "@string";
- } else {
- print "@string";
- }
- $hist_tag = $new_hist_tag;
- $command = $new_command;
- 1;
- }
- sub numerically { $a <=> $b; }
- # This is a sort routine that will sort numerically on the
- # keys of a hash as if it were a normal array.
- sub keynsort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $key (sort numerically keys(%lines)) {
- $sorted_lines[$i] = $lines{$key};
- $i++;
- }
- @sorted_lines;
- }
- # This is a sort routine that will sort on the
- # keys of a hash as if it were a normal array.
- sub keysort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $key (sort keys(%lines)) {
- $sorted_lines[$i] = $lines{$key};
- $i++;
- }
- @sorted_lines;
- }
- # This is a sort routine that will sort on the
- # values of a hash as if it were a normal array.
- sub valsort{
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $key (sort values %lines) {
- $sorted_lines[$i] = $key;
- $i++;
- }
- @sorted_lines;
- }
- # This is a numerical sort routine (ascending).
- sub numsort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $num (sort {$a <=> $b} keys %lines) {
- $sorted_lines[$i] = $lines{$num};
- $i++;
- }
- @sorted_lines;
- }
- # This is a sort routine that will sort on the
- # ip address when the ip address is anywhere in
- # the strings.
- sub ipsort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $addr (sort sortbyipaddr keys %lines) {
- $sorted_lines[$i] = $lines{$addr};
- $i++;
- }
- @sorted_lines;
- }
- # These two routines will sort based upon IP addresses
- sub ipaddrval {
- my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#);
- $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0]));
- }
- sub sortbyipaddr {
- &ipaddrval($a) <=> &ipaddrval($b);
- }
- # This routine parses "dir"
- sub Dir {
- print STDERR " In Dir: $_" if ($debug);
- $_ =~ s/^[^#]*//;
- ProcessHistory("COMMENTS","keysort","D1","!\n! $_");
- while (<INPUT>) {
- s/^\s+\015//g;
- tr/\015//d;
- next if /^\s*$/;
- last if(/$prompt/);
- # pager remnants like: ^H^H^H ^H^H^H content
- s/[\b]+\s*[\b]*//g;
- ProcessHistory("COMMENTS","keysort","D1","! $_");
- }
- ProcessHistory("COMMENTS","keysort","D1","!\n");
- return(0);
- }
- sub ShowVer {
- print STDERR " In ShowVer: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- next if /^\s*$/;
- last if(/$prompt/);
- # pager remnants like: ^H^H^H ^H^H^H content
- s/[\b]+\s*[\b]*//g;
- # Remove Uptime
- / up time/i && next;
- ProcessHistory("COMMENTS","keysort","B1","! $_");
- }
- return(0);
- }
- sub ShowSys {
- print STDERR " In ShowSys: $_" if ($debug);
- $_ =~ s/^[^#]*//;
- ProcessHistory("COMMENTS","keysort","C1","!\n! $_");
- while (<INPUT>) {
- s/^\s+\015//g;
- tr/\015//d;
- next if /^\s*$/;
- last if(/$prompt/);
- # pager remnants like: ^H^H^H ^H^H^H content
- s/[\b]+\s*[\b]*//g;
- # Remove Uptime
- / up time/i && next;
- # filter temperature sensor info for Dell 6428 stacks
- # /Temperature Sensors:/
- if (/Temperature \(Celsius\)/) {
- ProcessHistory("COMMENTS","keysort","C1","! $_");
- ProcessHistory("COMMENTS","keysort","C1","! Unit\tStatus\n");
- ProcessHistory("COMMENTS","keysort","C1","! ----\t------\n");
- while (<INPUT>) {
- s/^\s+\015//g;
- tr/\015//d;
- /(\d+)\s+\d+\s+(.*)$/ &&
- ProcessHistory("COMMENTS","keysort","C1","! $1\t$2\n");
- /^\s*$/ && last;
- }
- } elsif (/Temperature/) {
- # Filter temperature sensor info for Dell M6348 and M8024 blade
- # switches.
- #
- # M6348 and M8024 sample lines:
- # Unit Description Temperature Status
- # (Celsius)
- # ---- ----------- ----------- ------
- # 1 System 39 Good
- # 2 System 39 Good
- ProcessHistory("COMMENTS","keysort","C1",
- "! Unit\tDescription\tStatus\n");
- ProcessHistory("COMMENTS","keysort","C1",
- "! ----\t-----------\t------\n");
- while (<INPUT>) {
- /\(celsius\)/i && next;
- s/^\s+\015//g;
- tr/\015//d;
- /(\d+)\s+(\w+)\s+\d+\s+(.*)$/ &&
- ProcessHistory("COMMENTS","keysort","C1","! $1\t$2\t\t$3\n");
- /^\s*$/ && last;
- }
- }
- /system description: (.*)/i &&
- ProcessHistory("COMMENTS","keysort","A1", "!Chassis type: $1\n") &&
- next;
- ProcessHistory("COMMENTS","keysort","C1","! $_");
- }
- return(0);
- }
- sub ShowVlan {
- print STDERR " In ShowVlan: $_" if ($debug);
- $_ =~ s/^[^#]*//;
- ProcessHistory("COMMENTS","keysort","D1","!\n! $_");
- while (<INPUT>) {
- s/^\s+\015//g;
- tr/\015//d;
- next if /^\s*$/;
- last if(/$prompt/);
- # pager remnants like: ^H^H^H ^H^H^H content
- s/[\b]+\s*[\b]*//g;
- # Remove Uptime
- / up time/i && next;
- ProcessHistory("COMMENTS","keysort","D1","! $_");
- }
- return(0);
- }
- # This routine processes a "write term" (aka show running-configuration)
- sub WriteTerm {
- my($comment) = (0);
- print STDERR " In ShowRun: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- next if /^\s*$/;
- last if(/$prompt/);
- # pager remnants like: ^H^H^H ^H^H^H content
- s/[\b]+\s*[\b]*//g;
- # skip consecutive comment lines
- if (/^!/) {
- next if ($comment);
- ProcessHistory("","","",$_);
- $comment++;
- next;
- }
- $comment = 0;
- /^building running-config/ && next;
- /^------+/ && ProcessHistory("","","","!$_") && next;
- /^router configuration/i && ProcessHistory("","","","!$_") && next;
- /^oob host config/i && ProcessHistory("","","","!$_") && next;
- /^empty configuration/i && ProcessHistory("","","","!$_") && next;
- if (/^password (\S+) encrypted/ && $filter_pwds > 1) {
- ProcessHistory("","","","!password <removed> encrypted\n");
- next;
- }
- if (/^password (\S+)$/ && $filter_pwds >= 1) {
- ProcessHistory("","","","!password <removed>\n");
- next;
- }
- if (/^(enable password level \d+) (\S+) encrypted/ && $filter_pwds > 1){
- ProcessHistory("","","","!$1 <removed> encrypted\n");
- next;
- }
- if (/^(enable password level \d+) (\S+)$/ && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1 <removed> $'\n");
- next;
- }
- # order/prune snmp-server host statements
- # we only prune lines of the form
- # snmp-server host a.b.c.d <community>
- if (/^(snmp-server host) (\d+\.\d+\.\d+\.\d+) (\S+)/) {
- if ($filter_commstr) {
- ProcessHistory("SNMPSERVERHOST","ipsort",
- "$2","!$1 $2 <removed>$'");
- } else {
- ProcessHistory("SNMPSERVERHOST","ipsort","$2","$_");
- }
- next;
- }
- if (/^(snmp-server community) (\S+)/) {
- if ($filter_commstr) {
- ProcessHistory("SNMPSERVERCOMM","keysort",
- "$_","!$1 <removed>$'") && next;
- } else {
- ProcessHistory("SNMPSERVERCOMM","keysort","$2","$_") && next;
- }
- }
- # prune tacacs/radius server keys
- if (/^(tacacs-server|radius-server) key \w+/ && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1 <removed>$'"); next;
- }
- ProcessHistory("","","","$_");
- }
- $found_end = 1;
- return(1);
- }
- # Main
- @commandtable = (
- {'show system' => 'ShowSys'},
- {'show version' => 'ShowVer'},
- {'dir' => 'Dir'},
- {'show vlan' => 'ShowVlan'},
- {'show running-config' => 'WriteTerm'}
- );
- # Use an array to preserve the order of the commands and a hash for mapping
- # commands to the subroutine and track commands that have been completed.
- @commands = map(keys(%$_), @commandtable);
- %commands = map(%$_, @commandtable);
- $commandcnt = scalar(keys %commands);
- $commandstr=join(";",@commands);
- $cmds_regexp = join("|", map quotemeta($_), @commands);
- if (length($host) == 0) {
- if ($file) {
- print(STDERR "Too few arguments: file name required\n");
- exit(1);
- } else {
- print(STDERR "Too few arguments: host name required\n");
- exit(1);
- }
- }
- if ($opt_C) {
- print "hlogin -t $timeo -c\'$commandstr\' $host\n";
- exit(0);
- }
- open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n";
- select(OUTPUT);
- # make OUTPUT unbuffered if debugging
- if ($debug) { $| = 1; }
- if ($file) {
- print STDERR "opening file $host\n" if ($debug);
- print STDOUT "opening file $host\n" if ($log);
- open(INPUT,"<$host") || die "open failed for $host: $!\n"; } else {
- print STDERR "executing hlogin -t $timeo -c\"$commandstr\" $host\n" if ($debug);
- print STDOUT "executing hlogin -t $timeo -c\"$commandstr\" $host\n" if ($log);
- if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
- system "hlogin -t $timeo -c \"$commandstr\" $host </dev/null > $host.raw 2>&1" || die "hlogin failed for $host: $!\n";
- open(INPUT, "< $host.raw") || die "hlogin failed for $host: $!\n";
- } else {
- open(INPUT,"hlogin -t $timeo -c \"$commandstr\" $host </dev/null |") || die "hlogin failed for $host: $!\n";
- }
- }
- # determine ACL sorting mode
- if ($ENV{"ACLSORT"} =~ /no/i) {
- $aclsort = "";
- }
- # determine community string filtering mode
- if (defined($ENV{"NOCOMMSTR"}) &&
- ($ENV{"NOCOMMSTR"} =~ /yes/i || $ENV{"NOCOMMSTR"} =~ /^$/)) {
- $filter_commstr = 1;
- } else {
- $filter_commstr = 0;
- }
- # determine password filtering mode
- if ($ENV{"FILTER_PWDS"} =~ /no/i) {
- $filter_pwds = 0;
- } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) {
- $filter_pwds = 2;
- } else {
- $filter_pwds = 1;
- }
- ProcessHistory("","","","!RANCID-CONTENT-TYPE: smc\n!\n");
- ProcessHistory("COMMENTS","keysort","A0","!\n");
- ProcessHistory("COMMENTS","keysort","B0","!\n");
- ProcessHistory("COMMENTS","keysort","C0","!\n");
- ProcessHistory("COMMENTS","keysort","D0","!\n");
- TOP: while(<INPUT>) {
- tr/\015//d;
- if (/^Error:/) {
- print STDOUT ("$host hlogin error: $_");
- print STDERR ("$host hlogin error: $_") if ($debug);
- last;
- }
- while (/#\s*($cmds_regexp)\s*$/) {
- $cmd = $1;
- if (!defined($prompt)) {
- $prompt = ($_ =~ /^([^#]+#)/)[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";
- last TOP;
- }
- $rval = &{$commands{$cmd}}(*INPUT, *OUTPUT, $cmd);
- delete($commands{$cmd});
- if ($rval == -1) {
- last TOP;
- }
- }
- }
- print STDOUT "Done $logincmd: $_\n" if ($log);
- # Flush History
- ProcessHistory("","","","");
- # Cleanup
- close(INPUT);
- close(OUTPUT);
- if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
- unlink("$host.raw") if (! $debug);
- }
- # check for completeness
- if (scalar(%commands) || !$found_end) {
- if (scalar(keys %commands) eq $commandcnt) {
- printf(STDERR "$host: missed cmd(s): all commands\n");
- } elsif (scalar(%commands)) {
- printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands)));
- printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug);
- }
- if (!$found_end) {
- print STDOUT "$found_end: found end\n";
- print STDOUT "$host: End of run not found\n";
- print STDERR "$host: End of run not found\n" if ($debug);
- system("/usr/bin/tail -1 $host.new");
- }
- unlink "$host.new" if (! $debug);
- }
- #! /usr/bin/expect --
- ##
- ## $Id: tlogin.in 3201 2015-11-05 00:48:01Z heas $
- ##
- ## rancid 3.4.1
- ## Copyright (c) 1997-2016 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.
- ##
- ## It is the request of the authors, but not a condition of license, that
- ## parties packaging or redistributing RANCID NOT distribute altered versions
- ## of the etc/rancid.types.base file nor alter how this file is processed nor
- ## when in relation to etc/rancid.types.conf. The goal of this is to help
- ## suppress our support costs. If it becomes a problem, this could become a
- ## condition of license.
- #
- # The expect login scripts were based on Erik Sherk's gwtn, by permission.
- #
- # The original looking glass software was written by Ed Kern, provided by
- # permission and modified beyond recognition.
- #
- # The login expect scripts were based on Erik Sherk's gwtn, by permission.
- #
- # tlogin - Netopis login
- #
- # Modified by Ed Ravin for Netopia.
- # Usage line
- set usage "Usage: $argv0 \[-dSV\] \[-autoenable\] \[-noenable\] \[-c command\] \
- \[-Evar=x\] \[-e enable-password\] \[-f cloginrc-file\] \[-p user-password\] \
- \[-s script-file\] \[-t timeout\] \[-u username\] \
- \[-V\] \[-v vty-password\] \[-w enable-username\] \[-x command-file\] \
- \[-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
- # 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}
- # attempt at platform switching.
- set platform ""
- # 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
- }
- # Process the command line
- for {set i 0} {$i < $argc} {incr i} {
- set arg [lindex $argv $i]
- switch -glob -- $arg {
- } -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* {
- # ignore -r
- # VTY Password
- } -v* {
- if {! [regexp .\[vV\](.+) $arg ignore passwd]} {
- incr i
- set passwd [lindex $argv $i]
- }
- set do_passwd 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
- # 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
- # Version string
- } -V* {
- send_user "rancid 3.4.1\n"
- exit 0
- # 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.
- proc login { router user userpswd passwd enapasswd cmethod cyphertype } {
- global spawn_id in_proc do_command do_script platform
- global prompt u_prompt p_prompt e_prompt sshcmd usercmd usercmd_chat
- global otpinuse
- 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] {
- if [string match "telnet*" $prog] {
- regexp {telnet(:([^[:space:]]+))*} $prog command 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"
- exit 1
- }
- } elseif [string match "ssh*" $prog] {
- regexp {ssh(:([^[:space:]]+))*} $prog command suffix port
- set cmd $sshcmd
- if {"$port" != ""} {
- set cmd "$cmd -p $port"
- }
- set retval [catch {eval spawn [split "$cmd -c $cyphertype -x -l $user $router" { }]} reason]
- if { $retval } {
- send_user "\nError: $cmd failed: $reason\n"
- exit 1
- }
- } elseif [string match "usercmd" $prog] { # user supplies connect cmd
- set retval [catch {eval spawn $usercmd} reason]
- if { $retval } {
- send_user "\nError: '$usercmd' failed: $reason\n"
- exit 1
- }
- if { [llength $usercmd_chat] > 0 } {
- #send_user "\nExecuting usercmd_chat: $usercmd_chat\n"
- sleep 0.3
- foreach {i j} $usercmd_chat {
- expect {
- -re $i { eval send -- "\"$j\""}
- timeout { send "\r"; send_user "\nTimeout in usercmd_chat waiting for -re $i: punting with CR\n"; break }
- }
- }
- }
- } elseif ![string compare $prog "rsh"] {
- if [catch {spawn rsh -l $user $router} reason] {
- send_user "\nError: rsh failed: $reason\n"
- exit 1
- }
- } else {
- puts "\nError: unknown connection method: $prog"
- return 1
- }
- incr progs -1
- sleep 0.3
- # This helps cleanup each expect clause.
- expect_after {
- timeout {
- send_user "\nError: TIMEOUT reached\n"
- catch {close}; wait
- if { $in_proc} {
- return 1
- } else {
- continue
- }
- } eof {
- send_user "\nError: EOF received\n"
- catch {close}; 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 "(Connection refused|Secure connection \[^\n\r]+ refused)" {
- catch {close}; wait
- if !$progs {
- send_user "\nError: Connection Refused ($prog): $router\n"
- return 1
- }
- }
- -re "(Connection closed by|Connection to \[^\n\r]+ closed)" {
- catch {close}; 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" {
- catch {close};
- send_user "\nError: Unknown host $router\n"; wait; return 1
- }
- "Host is unreachable" {
- catch {close};
- send_user "\nError: Host Unreachable: $router\n"; wait; return 1
- }
- "No address associated with name" {
- catch {close};
- send_user "\nError: Unknown host $router\n"; 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"
- 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"
- return 1 }
- -nocase -re "^warning: remote host denied authentication agent forwarding." {
- exp_continue;
- }
- -re "(denied|Sorry)" {
- send_user "\nError: Check your passwd for $router\n"
- catch {close}; wait; return 1
- }
- "Login failed" {
- send_user "\nError: Check your passwd for $router\n"
- return 1
- }
- -re "% (Bad passwords|Authentication failed)" {
- send_user "\nError: Check your passwd for $router\n"
- 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 "Netopia.*always start from this main screen" {
- # send control-N to escape from the Playskool menu
- send -- "\x0e"
- set platform "netopia"
- set prompt "#"
- set autoenable 1
- return 0
- }
- -re "@\[^\r\n]+ $p_prompt" {
- # ssh pwd prompt
- sleep 1
- send -- "$userpswd\r"
- exp_continue
- }
- -re "$u_prompt" {
- send -- "$user\r"
- set uprompt_seen 1
- exp_continue
- }
- -re "(s/key|otp-\[0-9a-zA-Z]+) +\[0-9]+ +\[-0-9a-zA-Z]+\[ \r\n]" {
- if { !$otpinuse} {
- exp_continue
- }
- set challenge $expect_out(0,string)
- regsub {[ \r\n]$} $challenge {} challenge
- if [catch {exec otphelper $router "$challenge"} userpswd] {
- send_error "\nError: login: 'otphelper $router $challenge' failed.\nRun otphelper standalone to diagnose further.\n"
- exit 1
- }
- exp_continue
- }
- -re "$p_prompt" {
- sleep 1
- if {$uprompt_seen == 1} {
- send -- "$userpswd\r"
- } else {
- send -- "$passwd\r"
- }
- exp_continue
- }
- -re "$prompt" { break; }
- "Login invalid" {
- send_user "\nError: Invalid login: $router\n";
- catch {close}; wait; return 1
- }
- }
- }
- set in_proc 0
- return 0
- }
- # Enable
- proc do_enable { enauser enapasswd } {
- global prompt in_proc
- global u_prompt e_prompt
- global router otpinuse
- set in_proc 1
- send "enable\r"
- expect {
- -re "(s/key|otp-\[0-9a-zA-Z]+) +\[0-9]+ +\[-0-9a-zA-Z]+\[ \r\n]" {
- if { !$otpinuse} {
- exp_continue
- }
- set challenge $expect_out(0,string)
- regsub {[ \r\n]$} $challenge {} challenge
- if [catch {exec otphelper $router "$challenge"} enapasswd] {
- send_error "\nError: enable: 'otphelper $router $challenge' failed.\nRun otphelper standalone to diagnose further.\n"
- exit 1
- }
- exp_continue
- }
- -re "$u_prompt" { send -- "$enauser\r"; exp_continue}
- -re "$e_prompt" { send -- "$enapasswd\r"; exp_continue}
- "#" { set prompt "#" }
- "(enable)" { set prompt "> (enable) " }
- -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
- }
- }
- # 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 in_proc platform
- set in_proc 1
- # If the prompt is (enable), then we are on a switch and the
- # command is "set length 0"; otherwise its "term length 0".
- # skip if its an extreme (since the pager can not be disabled on a
- # per-vty basis).
- if { [string compare "extreme" "$platform"] } {
- if [regexp -- ".*> .*enable" "$prompt"] {
- send "set length 0\r"
- # This is ugly, but reduces code duplication, allowing the
- # subsequent expects to handle everything as normal.
- set command "set logging session disable;$command"
- } elseif { ![string compare "netopia" "$platform"] } {
- # kludge - should instead skip re-sensing prompt if platform netopia
- set prompt "#"
- } else {
- send "term length 0\r"
- }
- # match cisco config mode prompts too, such as router(config-if)#
- regsub -all {^(.{1,14}).*([#>])$} $prompt {\1} reprompt
- # escape any parens in the prompt, such as "(enable)"
- regsub -all {[)(]} $reprompt {\\&} reprompt
- append reprompt {([^#>\r\n]+)?[#>](\\([^)\\r\\n]+\\))?}
- expect {
- -re $reprompt {}
- -re "\[\n\r]+" { exp_continue }
- }
- } else {
- regsub -all "\[)(]" $prompt {\\&} reprompt
- }
- # 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, with a
- # global switch in the config.
- for {set i 0} {$i < $num_commands} { incr i} {
- 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 "\[\n\r]+" { send_user -- "$expect_out(buffer)"
- exp_continue }
- -re "\[^\r\n]*Press <SPACE> 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 }
- }
- }
- log_user 1
- if { [string compare "extreme" "$platform"] } {
- send "exit\r"
- } else {
- send "quit\r"
- }
- expect {
- -re "^\[^\n\r *]*$reprompt" {
- # the Cisco CE and Jnx ERX
- # return to non-enabled mode
- # on exit in enabled mode.
- send "exit\r"
- exp_continue;
- }
- "Do you wish to save your configuration changes" {
- send "n\r"
- exp_continue
- }
- -re "\[\n\r]+" { exp_continue }
- timeout { close; 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
- foreach router [lrange $argv $i end] {
- set router [string tolower $router]
- send_user "$router\n"
- # device timeout
- set timeout [find timeout $router]
- if { [llength $timeout] == 0 } {
- set timeout $timeoutdflt
- }
- # Figure out prompt.
- # Since autoenable is off by default, if we have it defined, it
- # was done on the command line. If it is not specifically set on the
- # command line, check the password file.
- if $avautoenable {
- set autoenable 1
- set enable 0
- set prompt "(#| \\(enable\\))"
- } else {
- set ae [find autoenable $router]
- if { "$ae" == "1" } {
- set autoenable 1
- set enable 0
- set prompt "(#| \\(enable\\))"
- } else {
- set autoenable 0
- set enable $avenable
- set prompt ">"
- }
- }
- # look for noenable option in .cloginrc
- if { [find noenable $router] == "1" } {
- set enable 0
- }
- # is OTP in use? If so, bypass password checks
- set otpinuse 0
- if { [find otp_secret $router] != "" } {
- set otpinuse 1
- }
- # Figure out passwords
- if { $do_passwd || $do_enapasswd } {
- set pswd [find password $router]
- if { [llength $pswd] == 0 && !$otpinuse} {
- send_user "\nError: no password for $router in $password_file.\n"
- continue
- }
- if { $enable && $do_enapasswd && $autoenable == 0 && [llength $pswd] < 2 && !$otpinuse } {
- 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] ""]
- }
- # 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 prompts
- set u_prompt [find userprompt $router]
- if { "$u_prompt" == "" } {
- set u_prompt "(Username|Login|login|user name|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):"
- } 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 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} }
- # If user provides a router-specific connection method, use it
- set usercmd [find usercmd $router]
- set usercmd_chat [find usercmd_chat $router]
- # Login to the router
- if {[login $router $ruser $userpswd $passwd $enapasswd $cmethod $cyphertype]} {
- continue
- }
- if { $enable } {
- if {[do_enable $enauser $enapasswd]} {
- if { $do_command || $do_script } {
- close; wait
- continue
- }
- }
- }
- # we are logged in, now figure out the full prompt
- send "\r"
- expect {
- -re "\[\r\n]+" { exp_continue; }
- -re "^(.+:)1 $prompt" { # stoopid extreme cmd-line numbers and
- # prompt based on state of config changes,
- # which may have an * at the beginning.
- set junk $expect_out(1,string)
- regsub -all "^\\\* " $expect_out(1,string) {} junk
- set prompt ".? ?$junk\[0-9]+ $expect_out(2,string)";
- set platform "extreme"
- }
- -re "^.+$prompt" { set junk $expect_out(0,string);
- regsub -all "\[\]\[]" $junk {\\&} prompt;
- }
- -re "^.+> \\\(enable\\\)" {
- set junk $expect_out(0,string);
- regsub -all "\[\]\[]" $junk {\\&} prompt;
- }
- }
- if { $do_command } {
- if {[run_commands $prompt $command]} {
- continue
- }
- } elseif { $do_script } {
- # If the prompt is (enable), then we are on a switch and the
- # command is "set length 0"; otherwise its "term length 0".
- if [regexp -- ".*> .*enable" "$prompt"] {
- send "set length 0\r"
- send "set logging session disable\r"
- } elseif { ![string compare "netopia" "$platform"] } {
- # do nothing
- } else {
- send "term length 0\r"
- }
- expect -re $prompt {}
- source $sfile
- close
- } else {
- label $router
- log_user 1
- interact
- }
- # End of for each router
- wait
- sleep 0.3
- }
- exit 0
- #! /usr/bin/expect --
- ##
- ## $Id: tntlogin.in 2376 2012-01-31 22:42:14Z heas $
- ##
- ## rancid 2.3.8
- ## Copyright (c) 1997-2011 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.
- #
- # Modified by P B Matthews.
- # Usage line
- set usage "Usage: $argv0 \[-dSV\] \[-c command\] \[-Evar=x\] \
- \[-f cloginrc-file\] \[-s script-file\] \[-t timeout\] \[-u username\] \
- \[-v vty-password\] \[-x command-file\] \[-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 0
- # The default is that you login non-enabled (tacacs can have you login already
- # enabled)
- set avautoenable 1
- # The default is to look in the password file to find the passwords. This
- # tracks if we receive them on the command line.
- set do_passwd 1
- # Save config, if prompted
- set do_saveconfig 0
- # Sometimes routers take awhile to answer (the default is 10 sec)
- set timeoutdflt 45
- # 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
- } -v* {
- if {! [ regexp .\[vV\](.+) $arg ignore passwd]} {
- incr i
- set passwd [ lindex $argv $i ]
- }
- set do_passwd 0
- # ssh passphrase
- } -r* {
- # ignore -r
- # Version string
- } -V* {
- send_user "rancid 2.3.8\n"
- exit 0
- # Enable Username
- } -w* {
- # ignore -w
- # Environment variable to pass to -s scripts
- } -E* {
- if {[ regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} {
- incr i
- set E$varname $varvalue
- } else {
- send_user "\nError: invalid format for -E in $arg\n"
- exit 1
- }
- # Enable Password
- } -e* {
- # ignore -e
- # 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 {
- # ignore -noenable
- # Does tacacs automatically enable us?
- } -autoenable {
- # ignore -autoenable
- } -* {
- 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 [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
- proc login { router user userpswd passwd prompt cmethod cyphertype } {
- global spawn_id in_proc do_command do_script
- global u_prompt p_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 command 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 compare $prog "ssh"] {
- regexp {ssh(:([^[:space:]]+))*} $prog methcmd suffix port
- set cmd $sshcmd
- if {"$port" != ""} {
- set cmd "$cmd -p $port"
- }
- 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"] {
- send_error "\nError: unsupported method: rsh\n"
- if { $progs == 0 } {
- return 1
- }
- continue;
- } 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
- }
- }
- }
- expect {
- "Connection refused" {
- catch {close}; catch {wait};
- sleep 0.3
- expect eof
- send_user "\nError: Connection Refused\n"; wait; return 1
- }
- eof { send_user "\nError: Couldn't login\n"; wait; return 1
- } "Unknown host\r\n" {
- expect eof
- send_user "\nError: Unknown host\n"; wait; return 1
- } "Host is unreachable" {
- expect eof
- send_user "\nError: Host Unreachable!\n"; wait; return 1
- } "No address associated with name" {
- expect eof
- send_user "\nError: Unknown host\n"; 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"
- 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"
- return 1
- }
- -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 "^Confirm seeing above note" {
- send "y\r"
- exp_continue
- }
- "Password incorrect" { send_user "\nError: Check your password for $router\n";
- catch {close}; catch {wait}; return 1 }
- -re "$prompt" { break; }
- denied { send_user "\nError: Check your passwd for $router\n"
- catch {close}; catch {wait}; return 1
- }
- "\r\n" { exp_continue; }
- }
- }
- set in_proc 0
- return 0
- }
- # Run commands given on the command line.
- proc run_commands { prompt command } {
- global in_proc
- set in_proc 1
- send "lines 0\r"
- expect -re $prompt {}
- regsub -all "\[)(]" $prompt {\\&} reprompt
- set commands [split $command \;]
- set num_commands [llength $commands]
- for {set i 0} {$i < $num_commands} { incr i} {
- send -- "[subst -nocommands [lindex $commands $i]]\r"
- expect {
- -re "^\[^\n\r]*$reprompt" {}
- -re "^\[^\n\r ]*>>.*$reprompt" { exp_continue }
- -re "\[\n\r]+" { exp_continue }
- }
- }
- send "quit\r"
- # expect {
- # -re "^WARNING: the current user has insufficient rights to view password fields. A configuration saved under this circumstance should not be used to restore profiles containing passwords. Save anyway? [y/n]"
- # {
- # send "y\r"
- exp_continue
- }
- "\n" { exp_continue }
- "\[^\n\r *]*Session terminated" { 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
- foreach router [lrange $argv $i end] {
- set router [string tolower $router]
- send_user "$router\n"
- # device timeout
- set timeout [find timeout $router]
- if { [llength $timeout] == 0 } {
- set timeout $timeoutdflt
- }
- # Figure out prompt.
- set prompt "admin>"
- # TNT only "enables" based on the password used at login time
- set autoenable 1
- set enable 0
- # Figure out passwords
- if { $do_passwd } {
- set pswd [find password $router]
- if { [llength $pswd] == 0 } {
- send_user "\nError - no password for $router in $password_file.\n"
- continue
- }
- set passwd [join [lindex $pswd 0] ""]
- }
- # 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 prompts
- set u_prompt [find userprompt $router]
- if { "$u_prompt" == "" } {
- set u_prompt "(User|Username|login| Login):"
- } else {
- set u_prompt [join [lindex $u_prompt 0] ""]
- }
- set p_prompt [find passprompt $router]
- if { "$p_prompt" == "" } {
- set p_prompt "\[Pp]assword:"
- } else {
- set p_prompt [join [lindex $p_prompt 0] ""]
- }
- # 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 $prompt $cmethod $cyphertype]} {
- incr exitval
- continue
- }
- if { $do_command } {
- if {[run_commands $prompt $command]} {
- incr exitval
- continue
- }
- } elseif { $do_script } {
- expect -re $prompt {}
- source $sfile
- send "y\r"
- catch {close};
- } else {
- label $router
- log_user 1
- interact
- }
- # End of for each router
- catch {wait};
- sleep 0.3
- }
- exit $exitval
- #! /usr/bin/perl
- ##
- ## $Id: tntrancid.in 2279 2011-01-31 22:41:00Z heas $
- ##
- ## rancid 2.3.8
- ## Copyright (c) 1997-2008 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.
- #
- # Modified by Paul B Matthews & Richard Vander Reyden.
- # I'm suprised it still works....
- #
- # RANCID - Really Awesome New Cisco confIg Differ
- #
- # usage: tntrancid [-dV] [-l] [-f filename | hostname]
- #
- use Getopt::Std;
- getopts('dflV');
- if ($opt_V) {
- print "rancid 2.3.8\n";
- exit(0);
- }
- $log = $opt_l;
- $debug = $opt_d;
- $file = $opt_f;
- $host = $ARGV[0];
- $clean_run = 0;
- $found_end = 0;
- $timeo = 90; # tntlogin timeout in seconds
- $prompt = "admin> ";
- $always_y = "y"; # cause its a pain.
- my(@commandtable, %commands, @commands);# command lists
- my($aclsort) = ("ipsort"); # ACL sorting mode
- my($filter_commstr); # SNMP community string filtering
- my($filter_pwds); # password filtering mode
- # This routine is used to print out the router configuration
- sub ProcessHistory {
- my($new_hist_tag,$new_command,$command_string,@string) = (@_);
- if ((($new_hist_tag ne $hist_tag) || ($new_command ne $command))
- && scalar(%history)) {
- print eval "$command \%history";
- undef %history;
- }
- if (($new_hist_tag) && ($new_command) && ($command_string)) {
- if ($history{$command_string}) {
- $history{$command_string} = "$history{$command_string}@string";
- } else {
- $history{$command_string} = "@string";
- }
- } elsif (($new_hist_tag) && ($new_command)) {
- $history{++$#history} = "@string";
- } else {
- print "@string";
- }
- $hist_tag = $new_hist_tag;
- $command = $new_command;
- 1;
- }
- sub numerically { $a <=> $b; }
- # This is a sort routine that will sort numerically on the
- # keys of a hash as if it were a normal array.
- sub keynsort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $key (sort numerically keys(%lines)) {
- $sorted_lines[$i] = $lines{$key};
- $i++;
- }
- @sorted_lines;
- }
- # This is a sort routine that will sort on the
- # keys of a hash as if it were a normal array.
- sub keysort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $key (sort keys(%lines)) {
- $sorted_lines[$i] = $lines{$key};
- $i++;
- }
- @sorted_lines;
- }
- # This is a sort routine that will sort on the
- # values of a hash as if it were a normal array.
- sub valsort{
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $key (sort values %lines) {
- $sorted_lines[$i] = $key;
- $i++;
- }
- @sorted_lines;
- }
- # This is a numerical sort routine (ascending).
- sub numsort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $num (sort {$a <=> $b} keys %lines) {
- $sorted_lines[$i] = $lines{$num};
- $i++;
- }
- @sorted_lines;
- }
- # This is a sort routine that will sort on the
- # ip address when the ip address is anywhere in
- # the strings.
- sub ipsort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $addr (sort sortbyipaddr keys %lines) {
- $sorted_lines[$i] = $lines{$addr};
- $i++;
- }
- @sorted_lines;
- }
- # These two routines will sort based upon IP addresses
- sub ipaddrval {
- my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#);
- $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0]));
- }
- sub sortbyipaddr {
- &ipaddrval($a) <=> &ipaddrval($b);
- }
- # This routine processes a "save con"
- sub SaveConf {
- print STDERR " In SaveConf: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- last if(/^$prompt/);
- # Leave software revision, but strip out saved date,
- # which causes rancid to think it changes each poll
- if (/^; saved from /) {
- ProcessHistory("","","","$_");
- next;
- }
- /^; saved / && next;
- # catch anything that wasnt match above.
- ProcessHistory("","","","$_");
- # end of config
- if (/; profiles saved$/) {
- printf STDERR " End SaveConf: $_" if ($debug);
- $found_end = 1;
- print STDOUT "$found_end = found_end within test\n";
- return(1);
- }
- # XXX what is the purpose of this?
- $found_end = 1;
- #### print STDOUT "$found_end = found_end at test\n";
- }
- $found_end = 1;
- return(0);
- }
- $found_end = 1;
- print STDOUT "$found_end = found_end at end test\n";
- # dummy function
- sub DoNothing {print STDOUT;}
- # Main
- @commandtable = (
- {'save con' => 'SaveConf'}
- );
- # Use an array to preserve the order of the commands and a hash for mapping
- # commands to the subroutine and track commands that have been completed.
- @commands = map(keys(%$_), @commandtable);
- %commands = map(%$_, @commandtable);
- $tnt_cmds=join(";",@commands);
- $cmds_regexp = join("|", map quotemeta($_), @commands);
- if (length($host) == 0) {
- if ($file) {
- print(STDERR "Too few arguments: file name required\n");
- exit(1);
- } else {
- print(STDERR "Too few arguments: host name required\n");
- exit(1);
- }
- }
- open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n";
- select(OUTPUT);
- # make OUTPUT unbuffered if debugging
- if ($debug) { $| = 1; }
- if ($file) {
- print STDERR "opening file $host\n" if ($debug);
- print STDOUT "opening file $host\n" if ($log);
- open(INPUT,"<$host") || die "open failed for $host: $!\n";
- } else {
- print STDERR "executing tntlogin -t $timeo -c\"$tnt_cmds\" $host\n" if ($debug);
- print STDOUT "executing tntlogin -t $timeo -c\"$tnt_cmds\" $host\n" if ($log);
- if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
- system "tntlogin -t $timeo -c \"$tnt_cmds\" $host </dev/null > $host.raw 2>&1" || die "tntlogin failed for $host: $!\n";
- open(INPUT, "< $host.raw") || die "tntlogin failed for $host: $!\n";
- } else {
- open(INPUT,"tntlogin -t $timeo -c \"$tnt_cmds\" $host </dev/null |") || die "tntlogin failed for $host: $!\n";
- }
- }
- # determine ACL sorting mode
- if ($ENV{"ACLSORT"} =~ /no/i) {
- $aclsort = "";
- }
- # determine community string filtering mode
- if (defined($ENV{"NOCOMMSTR"}) &&
- ($ENV{"NOCOMMSTR"} =~ /yes/i || $ENV{"NOCOMMSTR"} =~ /^$/)) {
- $filter_commstr = 1;
- } else {
- $filter_commstr = 0;
- }
- # determine password filtering mode
- if ($ENV{"FILTER_PWDS"} =~ /no/i) {
- $filter_pwds = 0;
- } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) {
- $filter_pwds = 2;
- } else {
- $filter_pwds = 1;
- }
- ProcessHistory("","","","#RANCID-CONTENT-TYPE: tnt\n#\n");
- ProcessHistory("COMMENTS","keysort","X0",";\n");
- TOP: while(<INPUT>) {
- tr/\015//d;
- if (/^Error:/) {
- print STDOUT ("$host tntlogin error: $_");
- print STDERR ("$host tntlogin error: $_") if ($debug);
- $clean_run=0;
- last;
- }
- while (/$prompt\s*($cmds_regexp)\s*$/) {
- $cmd = $1;
- if (!defined($prompt)) {
- $prompt = ($_ =~ /^([^#]+#)/)[0];
- $prompt =~ s/([][}{)(\\])/\\$1/g;
- $prompt =~ s/:(\d+ ?)#/:\\d+ ?#/;
- 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}};
- delete($commands{$cmd});
- if ($rval == -1) {
- printf STDERR "rval = -1\n" if ($debug);
- $clean_run = 0;
- last TOP;
- }
- }
- }
- print STDOUT "Done $logincmd: $_\n" if ($log);
- # Flush History
- ProcessHistory("","","","");
- # Cleanup
- $clean_run = 1;
- print STDOUT "$clean_run - clean\n";
- close(INPUT);
- close(OUTPUT);
- if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
- unlink("$host.raw") if (! $debug);
- }
- # check for completeness
- if (scalar(%commands) || !$clean_run || !$found_end) {
- if (scalar(%commands)) {
- printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands)));
- printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug);
- }
- if (!$clean_run || !$found_end) {
- print STDOUT "$host: End of run not found\n";
- print STDERR "$host: End of run not found\n" if ($debug);
- system("/usr/bin/tail -1 $host.new");
- }
- unlink "$host.new" if (! $debug);
- }
- #! /usr/bin/perl
- ##
- ## $Id: trancid.in 2880 2014-09-29 18:23:24Z heas $
- ##
- ## rancid 3.4.1
- ## Copyright (c) 1997-2016 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
- #
- # usage: trancid [-dltCV] [-f filename | hostname]
- #
- # Modified by Ed Ravin for Netopia.
- use Getopt::Std;
- getopts('dflt:CV');
- if ($opt_V) {
- print "rancid 3.4.1\n";
- exit(0);
- }
- $log = $opt_l;
- $debug = $opt_d;
- $file = $opt_f;
- $host = $ARGV[0];
- $clean_run = 0;
- $found_end = 0;
- $found_version = 0;
- $found_env = 0;
- $found_diag = 0;
- $timeo = 90; # clogin timeout in seconds
- my(%filter_pwds); # password filtering mode
- # This routine is used to print out the router configuration
- sub ProcessHistory {
- my($new_hist_tag,$new_command,$command_string,@string)=(@_);
- if((($new_hist_tag ne $hist_tag) || ($new_command ne $command))
- && scalar(%history)) {
- print eval "$command \%history";
- undef %history;
- }
- if (($new_hist_tag) && ($new_command) && ($command_string)) {
- if ($history{$command_string}) {
- $history{$command_string} = "$history{$command_string}@string";
- } else {
- $history{$command_string} = "@string";
- }
- } elsif (($new_hist_tag) && ($new_command)) {
- $history{++$#history} = "@string";
- } else {
- print "@string";
- }
- $hist_tag = $new_hist_tag;
- $command = $new_command;
- 1;
- }
- sub numerically { $a <=> $b; }
- # This is a sort routing that will sort numerically on the
- # keys of a hash as if it were a normal array.
- sub keynsort {
- local(%lines)=@_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $key (sort numerically keys(%lines)) {
- $sorted_lines[$i] = $lines{$key};
- $i++;
- }
- @sorted_lines;
- }
- # This is a sort routing that will sort on the
- # keys of a hash as if it were a normal array.
- sub keysort {
- local(%lines)=@_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $key (sort keys(%lines)) {
- $sorted_lines[$i] = $lines{$key};
- $i++;
- }
- @sorted_lines;
- }
- # This is a sort routing that will sort on the
- # values of a hash as if it were a normal array.
- sub valsort{
- local(%lines)=@_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $key (sort values %lines) {
- $sorted_lines[$i] = $key;
- $i++;
- }
- @sorted_lines;
- }
- # This is a numerical sort routing (ascending).
- sub numsort {
- local(%lines)=@_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $num (sort {$a <=> $b} keys %lines) {
- $sorted_lines[$i] = $lines{$num};
- $i++;
- }
- @sorted_lines;
- }
- # This is a sort routine that will sort on the
- # ip address when the ip address is anywhere in
- # the strings.
- sub ipsort {
- local(%lines)=@_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $addr (sort sortbyipaddr keys %lines) {
- $sorted_lines[$i] = $lines{$addr};
- $i++;
- }
- @sorted_lines;
- }
- # These two routines will sort based upon IP addresses
- sub ipaddrval {
- my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#);
- $a[3]+256*($a[2]+256*($a[1]+256*$a[0]));
- }
- sub sortbyipaddr {
- &ipaddrval($a) <=> &ipaddrval($b);
- }
- # This routine parses "show version"
- sub ShowVersion {
- print STDERR " In ShowVersion: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- if (/^$prompt/) { $found_version=1; last};
- next if(/^(\s*|\s*$cmd\s*)$/);
- return(1) if /(Invalid input detected|Type help or )/;
- return(-1) if (/command authorization failed/i);
- return(0) if ($found_version); # Only do this routine once
- # no pagers in Netopia-land, but shouldn't hurt
- s/^<-+ More -+>\s*//;
- ### sample output:
- ### #show version
- ### cli version: 01.00d00
- ### firmware version: 05.03.09f06
- ### hardware version: 01.00f00
- ### mib version: 01.00f00
- ### html version: 01.01d07
- ProcessHistory("COMMENTS","keysort","A1","# $_");
- }
- return(0);
- }
- sub ShowConfig {
- print STDERR " In ShowConfig: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- if (/^$prompt/) { $found_end=1; $clean_run=1; return 0};
- next if(/^(\s*|\s*$cmd\s*)$/);
- return(1) if /(Invalid input detected|Type help or )/;
- return(-1) if (/command authorization failed/i);
- # no pagers in Netopia-land, but shouldn't hurt
- s/^<-+ More -+>\s*//;
- # no post-processing needed - just file it
- ProcessHistory("","","","$_");
- }
- }
- # Main
- @commandtable=(
- {'show version' => "ShowVersion"},
- {'show config' => "ShowConfig"},
- );
- # Use array to preserve order of commands, and hash for mapping to subroutine
- my (%commands, @commands);
- foreach (@commandtable) {
- push @commands, (keys(%{$_}))[0];
- $commands{$commands[$#commands]}= (values(%{$_}))[0];
- };
- $commandstr=join(";",@commands);
- $cmds_regexp = join("|", map quotemeta($_), @commands);
- $commandcnt = scalar(keys %commands);
- if (length($host) == 0) {
- if ($file) {
- print(STDERR "Too few arguments: file name required\n");
- exit(1);
- } else {
- print(STDERR "Too few arguments: host name required\n");
- exit(1);
- }
- }
- if ($opt_C) {
- print "tlogin -t $timeo -c\'$commandstr\' $host\n";
- exit(0);
- }
- open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n";
- select(OUTPUT);
- # make OUTPUT unbuffered if debugging
- if ($debug) { $| = 1; }
- if ($file) {
- print STDERR "opening file $host\n" if ($debug);
- print STDOUT "opening file $host\n" if ($log);
- open(INPUT,"<$host") || die "open failed for $host: $!\n";
- } else {
- print STDERR "executing tlogin -t $timeo -c\"$commandstr\" $host\n" if ($debug);
- print STDOUT "executing tlogin -t $timeo -c\"$commandstr\" $host\n" if ($log);
- if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
- system "tlogin -t $timeo -c \"$commandstr\" $host </dev/null > $host.raw 2>&1" || die "tlogin failed for $host: $!\n";
- open(INPUT, "< $host.raw") || die "tlogin failed for $host: $!\n";
- } else {
- open(INPUT,"tlogin -t $timeo -c \"$commandstr\" $host </dev/null |") || die "tlogin failed for $host: $!\n";
- }
- }
- # determine password filtering mode
- if ($ENV{"FILTER_PWDS"} =~ /no/i) {
- $filter_pwds = 0;
- } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) {
- $filter_pwds = 2;
- } else {
- $filter_pwds = 1;
- }
- ProcessHistory("","","","#RANCID-CONTENT-TYPE: netopia\n#\n");
- ProcessHistory("COMMENTS","keysort","B0","#\n");
- ProcessHistory("COMMENTS","keysort","D0","#\n");
- ProcessHistory("COMMENTS","keysort","F0","#\n");
- ProcessHistory("COMMENTS","keysort","G0","#\n");
- TOP: while(<INPUT>) {
- tr/\015//d;
- if (/[>#]\s?exit$/) {
- $clean_run=1;
- last;
- }
- if (/^Error:/) {
- print STDOUT ("$host tlogin error: $_");
- print STDERR ("$host tlogin error: $_") if ($debug);
- $clean_run=0;
- last;
- }
- while (/#\s*($cmds_regexp)\s*$/) {
- $cmd = $1;
- if (!defined($prompt)) {
- $prompt = "#"; # crude but effective
- $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;
- }
- }
- }
- print STDOUT "Done $logincmd: $_\n" if ($log);
- # Flush History
- ProcessHistory("","","","");
- # Cleanup
- close(INPUT);
- close(OUTPUT);
- if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
- unlink("$host.raw") if (! $debug);
- }
- # check for completeness
- if (scalar(%commands) || !$clean_run || !$found_end) {
- if (scalar(keys %commands) eq $commandcnt) {
- printf(STDERR "$host: missed cmd(s): all commands\n");
- } elsif (scalar(%commands)) {
- printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands)));
- printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug);
- }
- if (!$clean_run || !$found_end) {
- print STDOUT "$host: End of run not found\n";
- print STDERR "$host: End of run not found\n" if ($debug);
- system("/usr/bin/tail -1 $host.new");
- }
- unlink "$host.new" if (! $debug);
- }
- #! /usr/bin/expect --
- ##
- ## $Id: wlogin.in 3201 2015-11-05 00:48:01Z heas $
- ##
- ## rancid 3.4.1
- ## Copyright (c) 1997-2016 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.
- ##
- ## It is the request of the authors, but not a condition of license, that
- ## parties packaging or redistributing RANCID NOT distribute altered versions
- ## of the etc/rancid.types.base file nor alter how this file is processed nor
- ## when in relation to etc/rancid.types.conf. The goal of this is to help
- ## suppress our support costs. If it becomes a problem, this could become a
- ## condition of license.
- #
- # The expect login scripts were based on Erik Sherk's gwtn, by permission.
- #
- # The original looking glass software was written by Ed Kern, provided by
- # permission and modified beyond recognition.
- #
- # wlogin - Cisco Wireless Lan Controller login
- #
- # Modified from clogin for use with WLCs 4/17/2008 - Josh Yost
- #
- # Most options are intuitive for logging into a Cisco router.
- # The default is to enable (thus -noenable). Some folks have
- # setup tacacs to have a user login at priv-lvl = 15 (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\] \
- \[-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
- # Sometimes routers take awhile to answer (the default is 10 sec)
- set timeoutdflt 10
- # 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
- }
- # Sometimes routers take awhile to answer (the default is 10 sec)
- set timeout 45
- # Process the command line
- for {set i 0} {$i < $argc} {incr i} {
- set arg [lindex $argv $i]
- switch -glob -- $arg {
- # Command to run.
- -c* {
- if {! [ regexp .\[cC\](.+) $arg ignore command]} {
- incr i
- set command [ lindex $argv $i ]
- }
- set do_command 1
- # Expect debug mode
- } -d* {
- exp_internal 1
- # 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
- }
- # alternate cloginrc file
- } -f* {
- if {! [ regexp .\[fF\](.+) $arg ignore password_file]} {
- incr i
- set password_file [ lindex $argv $i ]
- }
- # VTY Password
- } -p* -
- -P* {
- if {! [ regexp .\[pP\](.+) $arg ignore userpasswd]} {
- incr i
- set userpasswd [ lindex $argv $i ]
- }
- set do_passwd 0
- # Enable Password
- } -e*
- {
- if {! [ regexp .\[e\](.+) $arg ignore enapasswd]} {
- incr i
- set enapasswd [ lindex $argv $i ]
- }
- set do_enapasswd 0
- # 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
- # Timeout
- } -t* {
- if {! [ regexp .\[tT\](.+) $arg ignore timeout]} {
- incr i
- set timeout [ 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.4.1\n"
- exit 0
- # Enable Username
- } -w* -
- -W* {
- if {! [ regexp .\[wW\](.+) $arg ignore enauser]} {
- incr i
- set enausername [ lindex $argv $i ]
- }
- # Username
- } -u* {
- if {! [ regexp .\[uU\](.+) $arg ignore user]} {
- incr i
- set username [ 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
- # 'ssh -c' cypher type
- } -y* {
- if {! [ regexp .\[eE\](.+) $arg ignore cypher]} {
- incr i
- set cypher [ lindex $argv $i ]
- }
- # 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 } {
- global spawn_id in_proc do_command do_script platform
- global prompt 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
- regexp {ssh(:([^[:space:]]+))*} $prog methcmd suffix port
- set cmd $sshcmd
- if {"$port" != ""} {
- set cmd "$cmd -p $port"
- }
- 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"] {
- global command
- if { ! $do_command } {
- if { [llength $cmethod] == 1 } {
- send_user "\nError: rsh is an invalid method for -x and "
- send_user "interactive logins\n"
- }
- if { $progs == 0 } {
- return 1
- }
- continue;
- }
- # 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}; wait;
- send_user "\nError: Connection\
- Refused ($prog): $router\n"
- set rshfail 1
- }
- -re "(Connection closed by|Connection to \[^\n\r]+ closed)" {
- catch {close}; wait;
- send_user "\nError: Connection\
- closed ($prog): $router\n"
- set rshfail 1
- }
- "Host is unreachable" { catch {close}; wait;
- send_user "\nError: Host Unreachable:\
- $router\n"
- set rshfail 1
- }
- "No address associated with" {
- catch {close}; wait;
- send_user "\nError: Unknown host\
- $router\n"
- set rshfail 1
- }
- -re "\b+" { exp_continue }
- -re "\[\n\r]+" { send_user -- "$expect_out(buffer)"
- exp_continue
- }
- timeout { catch {close}; wait
- send_user "\nError: TIMEOUT reached\n"
- set rshfail 1
- }
- eof { catch {close}; wait }
- }
- log_user 1
- }
- if { $rshfail } {
- if { !$progs } {
- return 1
- } else {
- continue
- }
- }
- # fake the end of the session for rancid.
- send_user "$router# logout\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}; wait
- if { $in_proc} {
- return 1
- } else {
- continue
- }
- } eof {
- send_user "\nError: EOF received\n"
- catch {close}; 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 "(Connection refused|Secure connection \[^\n\r]+ refused)" {
- catch {close}; wait
- if !$progs {
- send_user "\nError: Connection Refused ($prog): $router\n"
- return 1
- }
- }
- -re "(Connection closed by|Connection to \[^\n\r]+ closed)" {
- catch {close}; 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" {
- catch {close};
- send_user "\nError: Unknown host $router\n"; wait; return 1
- }
- "Host is unreachable" {
- catch {close};
- send_user "\nError: Host Unreachable: $router\n"; wait; return 1
- }
- "No address associated with name" {
- catch {close};
- send_user "\nError: Unknown host $router\n"; 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"
- 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"
- return 1 }
- -nocase -re "^warning: remote host denied authentication agent forwarding." {
- exp_continue;
- }
- -re "(denied|Sorry)" {
- send_user "\nError: Check your passwd for $router\n"
- catch {close}; wait; return 1
- }
- "Login failed" {
- send_user "\nError: Check your passwd for $router\n"
- return 1
- }
- -re "% (Bad passwords|Authentication failed)" {
- send_user "\nError: Check your passwd for $router\n"
- 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 "@\[^\r\n]+ $p_prompt" {
- # ssh pwd prompt
- sleep 1
- send "$userpswd\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" { break; }
- "Login invalid" {
- send_user "\nError: Invalid login: $router\n";
- catch {close}; wait; return 1
- }
- }
- }
- set in_proc 0
- return 0
- }
- # Enable
- proc do_enable { enauser enapasswd } {
- global prompt in_proc
- global u_prompt e_prompt
- set in_proc 1
- send "enable\r"
- expect {
- -re "$u_prompt" { send "$enauser\r"; exp_continue}
- -re "$e_prompt" { send "$enapasswd\r"; exp_continue}
- "#" { set prompt "#" }
- "(enable)" { set prompt "> (enable) " }
- -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
- }
- }
- # 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 in_proc platform
- set in_proc 1
- # If the prompt is (enable), then we are on a switch and the
- # command is "set length 0"; otherwise its "term length 0".
- # skip if its an extreme (since the pager can not be disabled on a
- # per-vty basis).
- if { [ string compare "extreme" "$platform" ] } {
- if [ regexp -- ".*> .*enable" "$prompt" ] {
- send "set length 0\r"
- # This is ugly, but reduces code duplication, allowing the
- # subsequent expects to handle everything as normal.
- set command "set logging session disable;$command"
- } else {
- send "term length 0\r"
- }
- # 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} reprompt
- # escape any parens in the prompt, such as "(enable)"
- regsub -all {[)(]} $reprompt {\\&} reprompt
- append reprompt {([^#>\r\n]+)?[#>](\\([^)\\r\\n]+\\))?}
- expect {
- -re $reprompt {}
- -re "\[\n\r]+" { exp_continue }
- }
- } else {
- regsub -all "\[)(]" $prompt {\\&} reprompt
- }
- # 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, with a
- # global switch in the config.
- for {set i 0} {$i < $num_commands} { incr i} {
- 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 "\[\n\r]+" { send_user -- "$expect_out(buffer)"
- exp_continue }
- -re "\[^\r\n]*Press <SPACE> to cont\[^\r\n]*" {
- send " "
- # bloody ^[[2K after " "
- expect {
- -re "^\[^\r\n]*\r" {}
- }
- exp_continue
- }
- -re "^Press Enter to continue\.\.\.\[^\n\r]*" {
- send "\r"
- exp_continue }
- -re "^Press Enter to continue or \[^\n\r]* abort" {
- send "\r"
- exp_continue }
- -re "^--More or \[^\n\r]* abort" {
- send " "
- exp_continue }
- -re "^ *--More--\[^\n\r]*" {
- send " "
- exp_continue }
- -re "^<-+ More -+>\[^\n\r]*" {
- send_user -- "$expect_out(buffer)"
- send " "
- exp_continue }
- }
- }
- log_user 1
- # Send an Unconditional CTRL Z to exit out of any context the WLC prompt
- # may be in
- send "\032"
- expect {
- -re "(.+)>" { # the Cisco CE and Jnx ERX
- # return to non-enabled mode
- # on exit in enabled mode.
- send "logout\r"
- exp_continue;
- }
- -re "Would you like to save them .+" {
- send "n\r"
- exp_continue
- }
- -re "\[\n\r]+" { exp_continue }
- timeout { 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
- foreach router [lrange $argv $i end] {
- set router [string tolower $router]
- # attempt at platform switching.
- set platform ""
- send_user -- "$router\n"
- # device timeout
- set timeout [find timeout $router]
- if { [llength $timeout] == 0 } {
- set timeout $timeoutdflt
- }
- # Figure out the prompt.
- # autoenable is off by default. If we have it defined, it was done
- # on the command line. If it is not specifically set on the command
- # line, check the password file.
- if $avautoenable {
- set autoenable 1
- set enable 0
- set prompt "(#| \\(enable\\))"
- } else {
- set ae [find autoenable $router]
- if { "$ae" == "1" } {
- set autoenable 1
- set enable 0
- set prompt "(#| \\(enable\\)|>)"
- } else {
- set autoenable 0
- set enable $avenable
- set prompt ">"
- }
- }
- # look for noenable option in .cloginrc
- if { [find noenable $router] != "" } {
- set enable 0
- }
- # 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] ""]
- }
- # 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 prompts
- set u_prompt [find userprompt $router]
- if { "$u_prompt" == "" } {
- set u_prompt "(Username|Login|login|user name|User):"
- } else {
- set u_prompt [join [lindex $u_prompt 0] ""]
- }
- set p_prompt [find passprompt $router]
- if { "$p_prompt" == "" } {
- set p_prompt "(\[Pp]assword|passwd):"
- } 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 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]} {
- # if login failed or rsh was successful, move on to the next device
- continue
- }
- if { $enable } {
- if {[do_enable $enauser $enapasswd]} {
- if { $do_command || $do_script } {
- close; wait
- continue
- }
- }
- }
- # we are logged in, now figure out the full prompt
- send "\r"
- expect {
- -re "\[\r\n]+" { exp_continue; }
- -re "^(.+\[:.])1 $prompt" { # stoopid extreme cmd-line numbers and
- # prompt based on state of config changes,
- # which may have an * at the beginning.
- set junk $expect_out(1,string)
- regsub -all "^\\\* " $expect_out(1,string) {} junk
- set prompt ".? ?$junk\[0-9]+ $expect_out(2,string)";
- set platform "extreme"
- }
- -re "^.+$prompt" { set junk $expect_out(0,string);
- regsub -all "\[\]\[]" $junk {\\&} prompt;
- }
- -re "^.+> \\\(enable\\\)" {
- set junk $expect_out(0,string);
- regsub -all "\[\]\[]" $junk {\\&} prompt;
- }
- -re "\(Cisco Controller\) \>" {
- set junk $expect_out(0,string);
- regsub -all "\[\]\[]" $junk {\\&} prompt;
- }
- }
- if { $do_command } {
- if {[run_commands $prompt $command]} {
- continue
- }
- } elseif { $do_script } {
- # If the prompt is (enable), then we are on a switch and the
- # command is "set length 0"; otherwise its "term length 0".
- if [ regexp -- ".*> .*enable" "$prompt" ] {
- send "set length 0\r"
- send "set logging session disable\r"
- } else {
- send "term length 0\r"
- }
- expect -re $prompt {}
- source $sfile
- close
- } else {
- label $router
- log_user 1
- interact
- }
- # End of for each router
- wait
- sleep 0.3
- }
- exit 0
- #! /usr/bin/expect --
- ##
- ## $Id: xilogin.in 2255 2010-10-06 20:31:24Z heas $
- ##
- ## rancid 3.4.1
- ## Copyright (c) 1997-2016 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.
- ##
- ## It is the request of the authors, but not a condition of license, that
- ## parties packaging or redistributing RANCID NOT distribute altered versions
- ## of the etc/rancid.types.base file nor alter how this file is processed nor
- ## when in relation to etc/rancid.types.conf. The goal of this is to help
- ## suppress our support costs. If it becomes a problem, this could become a
- ## condition of license.
- #
- # The expect login scripts were based on Erik Sherk's gwtn, by permission.
- #
- # The original looking glass software was written by Ed Kern, provided by
- # permission and modified beyond recognition.
- #
- # xilogin - Xirrus login
- #
- # Most options are intuitive for logging into a Xirrus array.
- # The default is to not enable.
- #
- # 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\] \
- \[-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.4.1\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
- # 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 xilogin
- # 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 passphrase
- global prompt u_prompt p_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 "(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
- }
- -nocase -re "^warning: remote host denied authentication agent forwarding." {
- exp_continue;
- }
- -nocase -re "^warning:" { exp_continue }
- -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 "@\[^\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" { break; }
- "Login invalid" {
- send_user "\nError: Invalid login: $router\n";
- catch {close}; catch {wait}; return 1
- }
- }
- }
- set in_proc 0
- return 0
- }
- # New subroutine to provide "login" command capabilities, using the enable user and enable password
- # Login
- proc do_login { enauser enapasswd } {
- global prompt in_proc
- global u_prompt
- set in_proc 1
- send "login\r"
- expect {
- -re "$u_prompt" { send "$enauser\r"; exp_continue}
- "#" { set prompt "#" }
- "(login)" { set prompt "> (login) " }
- -re "(denied|Sorry|Incorrect)" {
- # % Access denied - from local auth and poss. others
- send_user "\nError: Check your Login passwd\n";
- return 1
- }
- "% Error in authentication" {
- send_user "\nError: Check your Login passwd\n"
- return 1
- }
- "% Bad passwords" {
- send_user "\nError: Check your Login passwd\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
- set in_proc 1
- # Disable paging
- send "more off \r"
- # escape any parens in the prompt, such as "(enable)"
- regsub -all {[)(]} $prompt {\\&} reprompt
- expect {
- -re $reprompt {}
- -re "\[\n\r]+" { exp_continue }
- }
- # Disable command auto-completion
- send "auto-complete off \r"
- expect {
- -re $reprompt {}
- -re "\[\n\r]+" { exp_continue }
- }
- # 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, with a
- # global switch in the config.
- for {set i 0} {$i < $num_commands} { incr i} {
- 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]+" { # match Xirrus pager
- send " "
- exp_continue
- }
- -re "\[\n\r]+" { send_user -- "$expect_out(buffer)"
- exp_continue
- }
- }
- }
- log_user 1
- send -h "quit\r"
- expect {
- "Do you want to save changes to flash" { # Xirrus
- if {$do_saveconfig} {
- catch {send "y\r"}
- } else {
- catch {send "n\r"}
- }
- exp_continue
- }
- -re "\[\n\r]+" { exp_continue }
- 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
- foreach router [lrange $argv $i end] {
- set router [string tolower $router]
- send_user -- "$router\n"
- # device timeout
- set timeout [find timeout $router]
- if { [llength $timeout] == 0 } {
- set timeout $timeoutdflt
- }
- # Default prompt.
- set prompt "(>|#)"
- # 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
- }
- 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 prompts
- set u_prompt [find userprompt $router]
- if { "$u_prompt" == "" } {
- set u_prompt "(Username|Login|login|user name|User):"
- } 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] ""]
- }
- # 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
- }
- # we are logged in, now figure out the full prompt
- send "\r"
- expect {
- -re "\[\r\n]+" { exp_continue; }
- -re "^.+$prompt" { set junk $expect_out(0,string);
- regsub -all "\[\]\[\(\)]" $junk {\\&} 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
- #! /usr/bin/perl
- ##
- ## $Id: xirancid.in 2246 2010-09-08 01:36:07Z heas $
- ##
- ## rancid 3.4.1
- ## Copyright (c) 1997-2016 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.
- #
- # hacked version of Hank's rancid - this one tries to deal with Xirrus arrays.
- #
- # RANXID - Really Awesome New Xirrus confIg Differ
- #
- # usage: xirancid [-dltCV] [-f filename | hostname]
- #
- use Getopt::Std;
- getopts('dflt:CV');
- if ($opt_V) {
- print "rancid 3.4.1\n";
- exit(0);
- }
- $log = $opt_l;
- $debug = $opt_d;
- $file = $opt_f;
- $host = $ARGV[0];
- $clean_run = 0;
- $timeo = 90; # xilogin timeout in seconds
- my(@commandtable, %commands, @commands);# command lists
- # This routine is used to print out the router configuration
- sub ProcessHistory {
- my($new_hist_tag,$new_command,$command_string,@string) = (@_);
- if ((($new_hist_tag ne $hist_tag) || ($new_command ne $command))
- && scalar(%history)) {
- print eval "$command \%history";
- undef %history;
- }
- if (($new_hist_tag) && ($new_command) && ($command_string)) {
- if ($history{$command_string}) {
- $history{$command_string} = "$history{$command_string}@string";
- } else {
- $history{$command_string} = "@string";
- }
- } elsif (($new_hist_tag) && ($new_command)) {
- $history{++$#history} = "@string";
- } else {
- print "@string";
- }
- $hist_tag = $new_hist_tag;
- $command = $new_command;
- 1;
- }
- # This routine parses "show config"
- sub ShowConfig {
- print STDERR " In ShowConfig: $_\n" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- last if (/^$prompt/);
- next if (/^(\s*|\s*$cmd\s*)$/);
- ProcessHistory("","","","$_");
- }
- return(0);
- }
- # Main
- @commandtable = (
- {'show boot-env' => "ShowConfig"},
- {'show running-config inc-defaults' => "ShowConfig"}
- );
- # Use an array to preserve the order of the commands and a hash for mapping
- # commands to the subroutine and track commands that have been completed.
- @commands = map(keys(%$_), @commandtable);
- %commands = map(%$_, @commandtable);
- $commandcnt = scalar(keys %commands);
- $xirrus_cmds=join(";",@commands);
- $cmds_regexp = join("|", map quotemeta($_), @commands);
- if (length($host) == 0) {
- if ($file) {
- print(STDERR "Too few arguments: file name required\n");
- exit(1);
- } else {
- print(STDERR "Too few arguments: host name required\n");
- exit(1);
- }
- }
- if ($opt_C) {
- print "xilogin -t $timeo -c\'$xirrus_cmds\' $host\n";
- exit(0);
- }
- open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n";
- select(OUTPUT);
- # make OUTPUT unbuffered if debugging
- if ($debug) { $| = 1; }
- if ($file) {
- print STDERR "opening file $host\n" if ($debug);
- print STDOUT "opening file $host\n" if ($log);
- open(INPUT,"<$host") || die "open failed for $host: $!\n";
- } else {
- print STDERR "executing xilogin -t $timeo -c\"$xirrus_cmds\" $host\n" if ($debug);
- print STDOUT "executing xilogin -t $timeo -c\"$xirrus_cmds\" $host\n" if ($log);
- if (defined($ENV{NOPIPE})) {
- system "xilogin -t $timeo -c \"$xirrus_cmds\" $host </dev/null > $host.raw 2>&1" || die "xilogin failed for $host: $!\n";
- open(INPUT, "< $host.raw") || die "xilogin failed for $host: $!\n";
- } else {
- open(INPUT,"xilogin -t $timeo -c \"$xirrus_cmds\" $host </dev/null |") || die "xilogin failed for $host: $!\n";
- }
- }
- ProcessHistory("","","","!RANCID-CONTENT-TYPE: xirrus\n!\n");
- TOP: while(<INPUT>) {
- tr/\015//d;
- if (/^end/) {
- $clean_run=1;
- last;
- }
- if (/^Error:/) {
- print STDOUT ("$host xilogin error: $_");
- print STDERR ("$host xilogin error: $_") if ($debug);
- $clean_run=0;
- last;
- }
- while (/[>#]\s*($cmds_regexp)\s*$/) {
- $cmd = $1;
- if (!defined($prompt)) {
- $prompt = ($_ =~ /^([^:]+:)/)[0];
- }
- 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;
- }
- }
- }
- print STDOUT "Done $logincmd: $_\n" if ($log);
- # Flush History
- ProcessHistory("","","","");
- # Cleanup
- close(INPUT);
- close(OUTPUT);
- if (defined($ENV{NOPIPE})) {
- unlink("$host.raw") if (! $debug);
- }
- # check for completeness
- if (scalar(%commands) || !$clean_run ) {
- if (scalar(keys %commands) eq $commandcnt) {
- printf(STDERR "$host: missed cmd(s): all commands\n");
- } elsif (scalar(%commands)) {
- printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands)));
- printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug);
- }
- if (!$clean_run ) {
- print STDOUT "$host: End of run not found\n";
- print STDERR "$host: End of run not found\n" if ($debug);
- system("/usr/bin/tail -1 $host.new");
- }
- unlink "$host.new" if (! $debug);
- }
- #! /usr/bin/perl
- ##
- ## $Id: xrancid.in 3018 2015-01-11 05:51:49Z heas $
- ##
- ## rancid 3.4.1
- ## Copyright (c) 1997-2016 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
- #
- # usage: xrancid [-dltCV] [-f filename | hostname]
- #
- use Getopt::Std;
- getopts('dflt:CV');
- if ($opt_V) {
- print "rancid 3.4.1\n";
- exit(0);
- }
- $log = $opt_l;
- $debug = $opt_d;
- $file = $opt_f;
- $host = $ARGV[0];
- $clean_run = 0;
- $found_end = 0;
- $timeo = 90; # clogin timeout in seconds
- my(@commandtable, %commands, @commands);# command lists
- my($aclsort) = ("ipsort"); # ACL sorting mode
- my($filter_commstr); # SNMP community string filtering
- my($filter_pwds); # password filtering mode
- # This routine is used to print out the router configuration
- sub ProcessHistory {
- my($new_hist_tag,$new_command,$command_string,@string) = (@_);
- if ((($new_hist_tag ne $hist_tag) || ($new_command ne $command))
- && scalar(%history)) {
- print eval "$command \%history";
- undef %history;
- }
- if (($new_hist_tag) && ($new_command) && ($command_string)) {
- if ($history{$command_string}) {
- $history{$command_string} = "$history{$command_string}@string";
- } else {
- $history{$command_string} = "@string";
- }
- } elsif (($new_hist_tag) && ($new_command)) {
- $history{++$#history} = "@string";
- } else {
- print "@string";
- }
- $hist_tag = $new_hist_tag;
- $command = $new_command;
- 1;
- }
- sub numerically { $a <=> $b; }
- # This is a sort routine that will sort numerically on the
- # keys of a hash as if it were a normal array.
- sub keynsort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $key (sort numerically keys(%lines)) {
- $sorted_lines[$i] = $lines{$key};
- $i++;
- }
- @sorted_lines;
- }
- # This is a sort routine that will sort on the
- # keys of a hash as if it were a normal array.
- sub keysort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $key (sort keys(%lines)) {
- $sorted_lines[$i] = $lines{$key};
- $i++;
- }
- @sorted_lines;
- }
- # This is a sort routine that will sort on the
- # values of a hash as if it were a normal array.
- sub valsort{
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $key (sort values %lines) {
- $sorted_lines[$i] = $key;
- $i++;
- }
- @sorted_lines;
- }
- # This is a numerical sort routine (ascending).
- sub numsort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $num (sort {$a <=> $b} keys %lines) {
- $sorted_lines[$i] = $lines{$num};
- $i++;
- }
- @sorted_lines;
- }
- # This is a sort routine that will sort on the
- # ip address when the ip address is anywhere in
- # the strings.
- sub ipsort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $addr (sort sortbyipaddr keys %lines) {
- $sorted_lines[$i] = $lines{$addr};
- $i++;
- }
- @sorted_lines;
- }
- # These two routines will sort based upon IP addresses
- sub ipaddrval {
- my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#);
- $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0]));
- }
- sub sortbyipaddr {
- &ipaddrval($a) <=> &ipaddrval($b);
- }
- # This routine parses "show version"
- sub ShowVersion {
- print STDERR " In ShowVersion: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- last if(/^$prompt/);
- next if(/^(\s*|\s*$cmd\s*)$/);
- /^\S+ Serial Number:/i &&
- ProcessHistory("COMMENTS","keysort","B0","#$_") && next;
- /^(\S+) Power Supply ([^:]+):\s+(.*)/i &&
- ProcessHistory("COMMENTS","keysort","C0","#Power: $1 $2 $3\n")
- && next;
- /^image\s*:\s*(.*)\s+by\s+/i &&
- ProcessHistory("COMMENTS","keysort","D0","#Image: $1\n")
- && next;
- /^bootrom\s+:\s+(.*)/i &&
- ProcessHistory("COMMENTS","keysort","D1","#\n#Bootrom: $1\n")
- && next;
- #heas: need to collect this from show vers for ShowSlot where rev #s are excluded
- #SLOT 1 : 702005-06 0025S-00877 CPLD Rev <FF>
- #SLOT 2 : 702005-06 0021S-00131 CPLD Rev 02
- #SLOT 3 : 702009-06 0024S-00170 CPLD Rev <FF>
- #SLOT 4 : 702009-06 0024S-00319 CPLD Rev <FF>
- }
- return(0);
- }
- # This routine parses "show memory"
- sub ShowMemory {
- print STDERR " In ShowMemory: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- last if(/^$prompt/);
- next if(/^(\s*|\s*$cmd\s*)$/);
- /^Total DRAM (Size|\(KB\)): (.*)/ &&
- ProcessHistory("COMMENTS","keysort","B1","#\n#Memory: $2\n")
- }
- return(0);
- }
- # This routine parses "show diag"
- sub ShowDiag {
- print STDERR " In ShowDiag: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- last if (/^$prompt/);
- last if (/^Syntax error at token/);
- next if (/^(\s*|\s*$cmd\s*)$/);
- /platform\s+:\s+(.*)$/i &&
- ProcessHistory("COMMENTS","keysort","A0","#Chassis type: $1\n") &&
- next;
- /(\S+) part no\s+:\s+(.*)$/i &&
- ProcessHistory("COMMENTS","keysort","E0","#$1 PN: $2\n") &&
- next;
- /(\S+ \S+) no\s+:\s+(.*)$/i &&
- ProcessHistory("COMMENTS","keysort","E0","#$1 PN: $2\n") &&
- next;
- /(mac address)\s+:\s+(.*)$/i &&
- ProcessHistory("COMMENTS","keysort","B0","#$1: $2\n") &&
- next;
- }
- return(0);
- }
- # This routine parses "show slot"
- sub ShowSlot {
- print STDERR " In ShowSlot: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- last if (/^$prompt/);
- next if (/^(\s*|\s*$cmd\s*)$/);
- if (/^Slot\s+(\d+)\s+/i) {
- my($slot) = $1;
- my($hwtype, $conftype, $sn, $state);
- ProcessHistory("COMMENTS","keysort","F$slot","#\n");
- while (<INPUT>) {
- tr/\015//d;
- last if (/^$prompt/ || /^\s*$/);
- if (/State:\s+(.*)$/i) { $state = $1; }
- if (/serial number:\s+(.*)$/i) { $sn = $1; }
- if (/hw module type:\s+(.*)$/i) { $hwtype = $1; }
- if (/configured type:\s+(.*)$/i) { $conftype = $1; }
- }
- ProcessHistory("COMMENTS","keysort","F$slot","#Slot $slot: type "
- . "$hwtype,"
- . " $conftype\n#Slot $slot: serial $sn\n#Slot $slot: state "
- . " $state\n");
- return if (/^$prompt/);
- next;
- }
- }
- return(0);
- }
- # This routine parses "show switch"
- sub ShowSwitch {
- print STDERR " In ShowSwitch: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- last if(/^$prompt/);
- next if(/^(\s*|\s*$cmd\s*)$/);
- /^\s*$/i && next;
- /^(primary|secondary) configuration:/i && next;
- /^(boot |next reboot)/i && next;
- /^(auto |qos mode|sys\S*:|temperature|time)/i && next;
- /^power supply: (.*)/i &&
- ProcessHistory("COMMENTS","keysort","C0","#$1") && next;
- /^license/i && ProcessHistory("COMMENTS","keysort","D0","#Image: $_")
- && next;
- s/^software image (\S+):/Image: $1:/i &&
- ProcessHistory("COMMENTS","keysort","D0","#$_") && next;
- /^\S+ software version:/i &&
- ProcessHistory("COMMENTS","keysort","D0","#Image: $_") && next;
- /^(\S+ )?software/i &&
- ProcessHistory("COMMENTS","keysort","D0","# $_") && next;
- /System MAC:\s+(.*)$/ &&
- ProcessHistory("COMMENTS","keysort","B0","#MAC: $1\n") &&
- next;
- /System Type:\s+(.*)$/ &&
- ProcessHistory("COMMENTS","keysort","A0","#Chassis type: $1\n")
- && next;
- /^(Image Selected):\s+(\S+)/ &&
- ProcessHistory("COMMENTS","keysort","A0","#$1: $2\n") && next;
- /^(Image Booted):\s+(\S+)/ &&
- ProcessHistory("COMMENTS","keysort","A0","#$1: $2\n") && next;
- /^(Primary (\S+ )?ver):\s+(\S+)/i &&
- ProcessHistory("COMMENTS","keysort","A0","#$1: $3\n") && next;
- /^(Secondary (\S+ )?ver):\s+(\S+)/i &&
- ProcessHistory("COMMENTS","keysort","A0","#$1: $3\n") && next;
- /^(Config Selected):\s+(\S+)/ &&
- ProcessHistory("COMMENTS","keysort","A0","#$1: $2\n") && next;
- /^(Config Booted):\s+(\S+)/ &&
- ProcessHistory("COMMENTS","keysort","A0","#$1: $2\n") && next;
- }
- return(0);
- }
- # This routine processes a "show configuration {detail}"
- sub WriteTerm {
- my($lines) = 0;
- print STDERR " In WriteTerm: $_" if ($debug);
- my($comment) = 1; # strip extra comments, esp to preserve chassis type
- while (<INPUT>) {
- tr/\015//d;
- last if(/^$prompt/);
- next if(/^\s*$/);
- return(0) if (/^syntax error at token /i);
- return(0) if (/^%% Invalid input detected at /i);
- return(0) if (/^%% Ambiguous command:/i);
- # the pager can not be disabled per-session on the PIX
- s/^<-+ More -+>\s*//;
- return(0) if ($found_end);
- s/^\s*$/#/;
- next if (/full detail configuration/i);
- # filter extra comments and lead comments in config so we can preserve
- # the chassis type at the top of muched o/p before the process history
- # key changes.
- if (/^#\s*$/) {
- if ($comment) {
- next;
- } else {
- $comment++;
- }
- } else {
- $comment = 0;
- }
- $lines++;
- # Dog gone Cool matches to process the rest of the config
- # some chassis report their chassis type in show diag...oh, but
- # others do not. grab it here, if available. so, nothing else
- # can change the keysort key until this is grabbed. sigh.
- /# (\S+) configuration generated/i &&
- ProcessHistory("COMMENTS","keysort","A0","#Chassis type: $1\n") &&
- ($comment = 0) && next;
- /configuration generated/i && next;
- /# system name/i && next;
- /# software version/i && next;
- if (/((create|configure) account \S+ \S+) / && $filter_pwds >= 2) {
- ProcessHistory("COMMENTS","keysort","H0","# $1 <key removed>\n");
- next;
- }
- if (/configure ssh2 key/ && $filter_pwds >= 1) {
- ProcessHistory("COMMENTS","keysort","H0","# $_# <key removed>\n");
- while (<INPUT>) {
- if (/^(#|enable|conf|disable|unconf)/) {
- tr/\015//d;
- last;
- }
- }
- }
- # filter out any RCS/CVS tags to avoid confusing local CVS storage
- s/\$(Revision|Id):/ $1:/;
- if (/^((config|configure) bgp (neighbor|peer-group) \S+ password encrypted)/i && $filter_pwds >= 1) {
- ProcessHistory("COMMENTS","keysort","H0","# $1 <removed>\n");
- next;
- }
- # order logging statements
- /^configure syslog add logging (\d+\.\d+\.\d+\.\d+)/ &&
- ProcessHistory("LOGGING","ipsort","$1","$_") && next;
- # order/prune snmp-server host statements
- # we only prune lines of the form
- # configure snmp add trapreceiver a.b.c.d <community>
- if (/^(configure snmp add trapreceiver )(\d+\.\d+\.\d+\.\d+) (community) \S+/) {
- if ($filter_commstr) {
- ProcessHistory("SNMPSVRHOST","ipsort","$2","# $1$2 $3 <removed> $'\n");
- } else {
- ProcessHistory("SNMPSVRHOST","ipsort","$2","$_\n");
- }
- next;
- }
- if (/^(configure snmp community (readonly|readwrite)( encrypted)?) (\S+)/) {
- if ($filter_commstr) {
- ProcessHistory("SNMPSVRCOMM","keysort","$_","#$1 <removed>$'");
- next;
- } else {
- ProcessHistory("SNMPSVRCOMM","keysort","$_","$_") && next;
- }
- }
- # order/prune tacacs/radius server statements
- if (/^(configure radius (primary|secondary) (tacacs-server|radius-server) shared-secret encrypted)/ && $filter_pwds >= 1) {
- ProcessHistory("COMMENTS","keysort","H0","# $1 <removed>\n");
- next;
- }
- # catch anything that wasnt match above.
- ProcessHistory("COMMENTS","keysort","H0","$_");
- # end of config
- if (/^# End of configuration file/i) {
- printf STDERR " End WriteTerm: $_" if ($debug);
- $found_end = 1;
- return(0);
- }
- }
- printf STDERR " End WriteTerm: $_" if ($debug);
- if ($lines < 3) {
- printf(STDERR "ERROR: $host configuration appears to be truncated.\n");
- $found_end = 0;
- return(-1);
- }
- $found_end = 1;
- return(0);
- }
- # Main
- @commandtable = (
- {'show version' => 'ShowVersion'},
- {'show memory' => 'ShowMemory'},
- {'show diag' => 'ShowDiag'},
- {'show switch' => 'ShowSwitch'},
- {'show slot' => 'ShowSlot'},
- {'show configuration detail' => 'WriteTerm'},
- {'show configuration' => 'WriteTerm'},
- );
- # Use an array to preserve the order of the commands and a hash for mapping
- # commands to the subroutine and track commands that have been completed.
- @commands = map(keys(%$_), @commandtable);
- %commands = map(%$_, @commandtable);
- $commandcnt = scalar(keys %commands);
- $commandstr = join(";",@commands);
- $cmds_regexp = join("|", map quotemeta($_), @commands);
- if (length($host) == 0) {
- if ($file) {
- print(STDERR "Too few arguments: file name required\n");
- exit(1);
- } else {
- print(STDERR "Too few arguments: host name required\n");
- exit(1);
- }
- }
- if ($opt_C) {
- print "clogin -t $timeo -c\'$commandstr\' $host\n";
- exit(0);
- }
- open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n";
- select(OUTPUT);
- # make OUTPUT unbuffered if debugging
- if ($debug) { $| = 1; }
- if ($file) {
- print STDERR "opening file $host\n" if ($debug);
- print STDOUT "opening file $host\n" if ($log);
- open(INPUT,"<$host") || die "open failed for $host: $!\n";
- } else {
- print STDERR "executing clogin -t $timeo -c \"$commandstr\" $host\n" if ($debug);
- print STDOUT "executing clogin -t $timeo -c \"$commandstr\" $host\n" if ($log);
- if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
- system "clogin -t $timeo -c \"$commandstr\" $host </dev/null > $host.raw 2>&1" || die "clogin failed for $host: $!\n";
- open(INPUT, "< $host.raw") || die "clogin failed for $host: $!\n";
- } else {
- open(INPUT,"clogin -t $timeo -c \"$commandstr\" $host </dev/null |") || die "clogin failed for $host: $!\n";
- }
- }
- # determine ACL sorting mode
- if ($ENV{"ACLSORT"} =~ /no/i) {
- $aclsort = "";
- }
- # determine community string filtering mode
- if (defined($ENV{"NOCOMMSTR"}) &&
- ($ENV{"NOCOMMSTR"} =~ /yes/i || $ENV{"NOCOMMSTR"} =~ /^$/)) {
- $filter_commstr = 1;
- } else {
- $filter_commstr = 0;
- }
- # determine password filtering mode
- if ($ENV{"FILTER_PWDS"} =~ /no/i) {
- $filter_pwds = 0;
- } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) {
- $filter_pwds = 2;
- } else {
- $filter_pwds = 1;
- }
- ProcessHistory("","","","#RANCID-CONTENT-TYPE: extreme\n#\n");
- ProcessHistory("COMMENTS","keysort","B0","#\n"); # chassis info
- ProcessHistory("COMMENTS","keysort","C0","#\n"); # power supply info
- ProcessHistory("COMMENTS","keysort","D0","#\n"); # image name
- ProcessHistory("COMMENTS","keysort","E0","#\n"); # h/w info
- ProcessHistory("COMMENTS","keysort","F0","#\n"); # slot info
- ProcessHistory("COMMENTS","keysort","H0","#\n"); # config
- ProcessHistory("COMMENTS","keysort","X0","#\n");
- TOP: while(<INPUT>) {
- tr/\015//d;
- # note: this match sucks rocks, but currently the extreme bits are
- # unreliable about echoing the 'exit\n' command. this match might really
- # be a bad idea, but instead rely upon WriteTerm's found_end?
- if (/($prompt\s?(quit|exit)|Connection( to \S+)? closed)/ && $found_end) {
- $clean_run = 1;
- last;
- }
- if (/^Error:/) {
- print STDOUT ("$host clogin error: $_");
- print STDERR ("$host clogin error: $_") if ($debug);
- $clean_run = 0;
- last;
- }
- while (/$prompt\s*($cmds_regexp)\s*$/) {
- $cmd = $1;
- if (!defined($prompt)) {
- $prompt = ($_ =~ /^([^#]+#)/)[0];
- $prompt =~ s/([][}{)(\\])/\\$1/g;
- $prompt =~ s/[:.](\d+ ?)#/[:.]\\d+ ?#/;
- $prompt =~ s/\*/\\\*/;
- 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) {
- printf STDERR "rval = -1\n" if ($debug);
- $clean_run = 0;
- last TOP;
- }
- }
- }
- print STDOUT "Done $logincmd: $_\n" if ($log);
- # Flush History
- ProcessHistory("","","","");
- # Cleanup
- close(INPUT);
- close(OUTPUT);
- if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
- unlink("$host.raw") if (! $debug);
- }
- # check for completeness
- if (scalar(%commands) || !$clean_run || !$found_end) {
- if (scalar(keys %commands) eq $commandcnt) {
- printf(STDERR "$host: missed cmd(s): all commands\n");
- } elsif (scalar(%commands)) {
- printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands)));
- printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug);
- }
- if (!$clean_run || !$found_end) {
- print STDOUT "$host: End of run not found\n";
- print STDERR "$host: End of run not found\n" if ($debug);
- system("/usr/bin/tail -1 $host.new");
- }
- unlink "$host.new" if (! $debug);
- }
- #! /usr/bin/perl
- ##
- ## $Id: xrrancid.in 2369 2012-01-30 21:06:03Z heas $
- ##
- ## rancid 2.3.8
- ## Copyright (c) 1997-2010 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
- #
- # usage: rancid [-dV] [-l] [-f filename | hostname]
- #
- use Getopt::Std;
- getopts('dflV');
- if ($opt_V) {
- print "rancid 2.3.8\n";
- exit(0);
- }
- $log = $opt_l;
- $debug = $opt_d;
- $file = $opt_f;
- $host = $ARGV[0];
- $proc = "";
- $clean_run = 0;
- $found_end = 0;
- $found_version = 0;
- $found_env = 0;
- $found_diag = 0;
- $timeo = 90; # clogin timeout in seconds
- my(@commandtable, %commands, @commands);# command lists
- my($aclsort) = ("ipsort"); # ACL sorting mode
- my($config_register); # configuration register value
- my($filter_commstr); # SNMP community string filtering
- my($filter_pwds); # password filtering mode
- # This routine is used to print out the router configuration
- sub ProcessHistory {
- my($new_hist_tag,$new_command,$command_string,@string) = (@_);
- if ((($new_hist_tag ne $hist_tag) || ($new_command ne $command))
- && scalar(%history)) {
- print eval "$command \%history";
- undef %history;
- }
- if (($new_hist_tag) && ($new_command) && ($command_string)) {
- if ($history{$command_string}) {
- $history{$command_string} = "$history{$command_string}@string";
- } else {
- $history{$command_string} = "@string";
- }
- } elsif (($new_hist_tag) && ($new_command)) {
- $history{++$#history} = "@string";
- } else {
- print "@string";
- }
- $hist_tag = $new_hist_tag;
- $command = $new_command;
- 1;
- }
- sub numerically { $a <=> $b; }
- # This is a sort routine that will sort numerically on the
- # keys of a hash as if it were a normal array.
- sub keynsort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $key (sort numerically keys(%lines)) {
- $sorted_lines[$i] = $lines{$key};
- $i++;
- }
- @sorted_lines;
- }
- # This is a sort routine that will sort on the
- # keys of a hash as if it were a normal array.
- sub keysort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $key (sort keys(%lines)) {
- $sorted_lines[$i] = $lines{$key};
- $i++;
- }
- @sorted_lines;
- }
- # This is a sort routine that will sort on the
- # values of a hash as if it were a normal array.
- sub valsort{
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $key (sort values %lines) {
- $sorted_lines[$i] = $key;
- $i++;
- }
- @sorted_lines;
- }
- # This is a numerical sort routine (ascending).
- sub numsort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $num (sort {$a <=> $b} keys %lines) {
- $sorted_lines[$i] = $lines{$num};
- $i++;
- }
- @sorted_lines;
- }
- # This is a sort routine that will sort on the
- # ip address when the ip address is anywhere in
- # the strings.
- sub ipsort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $addr (sort sortbyipaddr keys %lines) {
- $sorted_lines[$i] = $lines{$addr};
- $i++;
- }
- @sorted_lines;
- }
- # These two routines will sort based upon IP addresses
- sub ipaddrval {
- my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#);
- $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0]));
- }
- sub sortbyipaddr {
- &ipaddrval($a) <=> &ipaddrval($b);
- }
- # This routine parses "admin show version"
- sub ShowVersion {
- print STDERR " In ShowVersion: $_" if ($debug);
- my($slaveslot);
- while (<INPUT>) {
- tr/\015//d;
- if (/^$prompt/) { $found_version = 1; last};
- next if (/^(\s*|\s*$cmd\s*)$/);
- return(1) if (/Line has invalid autocommand /);
- return(1) if (/(Invalid (input|command) detected|Type help or )/i);
- return(0) if ($found_version); # Only do this routine once
- return(-1) if (/command authorization failed/i);
- if (/^Slave in slot (\d+) is running/) {
- $slave = " Slave:";
- $slaveslot = ", slot $1";
- next;
- }
- /^(Cisco )?IOS .* Software,? \(([A-Za-z0-9_-]*)\), .*Version\s+(.*)$/ &&
- ProcessHistory("COMMENTS","keysort","F1",
- "!Image:$slave Software: $2, $3\n") && next;
- /^([A-Za-z-0-9_]*) Synced to mainline version: (.*)$/ &&
- ProcessHistory("COMMENTS","keysort","F2",
- "!Image:$slave $1 Synced to mainline version: $2\n") && next;
- /^Compiled (.*)$/ &&
- ProcessHistory("COMMENTS","keysort","F3",
- "!Image:$slave Compiled: $1\n") && next;
- /^ROM: (IOS \S+ )?(System )?Bootstrap.*(Version.*)$/ &&
- ProcessHistory("COMMENTS","keysort","G1",
- "!ROM Bootstrap: $3\n") && next;
- if (/^Hardware:\s+(.*), (.* RAM), CPU (.*)$/) {
- ProcessHistory("COMMENTS","keysort","A1",
- "!Chassis type: $1 - a PIX\n");
- ProcessHistory("COMMENTS","keysort","A2",
- "!CPU: $3\n");
- ProcessHistory("COMMENTS","keysort","B1", "!Memory: $2\n");
- }
- /^Serial Number:\s+(.*)$/ &&
- ProcessHistory("COMMENTS","keysort","C1", "!$_") && next;
- # More PIX stuff
- /^Encryption hardware device\s+:\s+(.*)/ &&
- ProcessHistory("COMMENTS","keysort","A3", "!Encryption: $1\n") &&
- next;
- /^running activation key\s*:\s+(.*)/i &&
- ProcessHistory("COMMENTS","keysort","D2", "!Key: $1\n") &&
- next;
- # Flash on the PIX or FWSM (FireWall Switch Module)
- /^Flash(\s+\S+)+ \@ 0x\S+,\s+(\S+)/ &&
- ProcessHistory("COMMENTS","keysort","B2", "!Memory: Flash $2\n") &&
- next;
- # CatOS 3500xl stuff
- /^System serial number(:\s+.*)$/ &&
- ProcessHistory("COMMENTS","keysort","C1", "!Serial Number$1\n") &&
- next;
- /^Model / &&
- ProcessHistory("COMMENTS","keysort","C2", "!$_") && next;
- /^Motherboard / &&
- ProcessHistory("COMMENTS","keysort","C3", "!$_") && next;
- /^Power supply / &&
- ProcessHistory("COMMENTS","keysort","C4", "!$_") && next;
- /^Activation Key:\s+(.*)$/ &&
- ProcessHistory("COMMENTS","keysort","C2", "!$_") && next;
- /^ROM: \d+ Bootstrap .*(Version.*)$/ &&
- ProcessHistory("COMMENTS","keysort","G2",
- "!ROM Image: Bootstrap $1\n!\n") && next;
- /^ROM: .*(Version.*)$/ &&
- ProcessHistory("COMMENTS","keysort","G3","!ROM Image: $1\n") && next;
- /^BOOTFLASH: .*(Version.*)$/ &&
- ProcessHistory("COMMENTS","keysort","G4","!BOOTFLASH: $1\n") && next;
- /^BOOTLDR: .*(Version.*)$/ &&
- ProcessHistory("COMMENTS","keysort","G4","!BOOTLDR: $1\n") && next;
- /^System image file is "([^\"]*)", booted via (\S*)/ &&
- # removed the booted source due to
- # CSCdk28131: cycling info in 'sh ver'
- # ProcessHistory("COMMENTS","keysort","F4","!Image: booted via $2, $1\n") &&
- ProcessHistory("COMMENTS","keysort","F4","!Image: booted $1\n") &&
- next;
- /^System image file is "([^\"]*)"$/ &&
- ProcessHistory("COMMENTS","keysort","F5","!Image: $1\n") && next;
- if (/(\S+(?:\sseries)?)\s+(?:\((\S+)\)\s+processor|\(revision[^)]+\)).*\s+with (\S+k) bytes/i) {
- $proc = $1;
- my($cpu) = $2;
- my($mem) = $3;
- my($device) = "router";
- # the next line ought to be the more specific cpu info, grab it.
- # yet, some boards/IOS vers have a processor ID line between these
- # two. grrr. make sure we dont grab the "software" junk that
- # follows these lines by looking for "CPU at " or the 2600s
- # "processor: " unique string. there are undoubtedly many other
- # incantations. for a slave, we dont get this info, its just a
- # blank line.
- $_ = <INPUT>;
- if (/processor board id/i) {
- my($sn);
- if (/processor board id (\S+)/i) {
- $sn = $1;
- $sn =~ s/,$//;
- ProcessHistory("COMMENTS","keysort","D9",
- "!Processor ID: $sn\n");
- }
- $_ = <INPUT>;
- }
- $_ = "" if (! /(cpu at |processor: |$cpu processor,)/i);
- tr/\015//d;
- s/implementation/impl/i;
- if ($_ !~ /^\s*$/) {
- chomp;
- s/^/, /;
- }
- if ($proc eq "CSC") {
- $type = "AGS";
- } elsif ($proc eq "CSC4") {
- $type = "AGS+";
- } elsif ($proc =~ /1900/) {
- $type = "1900";
- $device = "switch";
- } elsif ($proc =~ /^(AS)?25[12][12]/) {
- $type = "2500";
- } elsif ($proc =~ /261[01]/ || $proc =~ /262[01]/ ) {
- $type = "2600";
- } elsif ($proc =~ /WS-C29/) {
- $type = "2900XL";
- $device = "switch";
- } elsif ($proc =~ /WS-C355/) {
- $type = "3550";
- $device = "switch";
- } elsif ($proc =~ /WS-C35/) {
- $type = "3500XL";
- $device = "switch";
- } elsif ($proc =~ /^36[0246][0-9]/) {
- $type = "3600";
- } elsif ($proc =~ /^37/) {
- $type = "3700";
- } elsif ($proc =~ /^38/) {
- $type = "3800";
- } elsif ($proc =~ /WS-C45/) {
- $type = "4500";
- $device = "switch";
- } elsif ( $proc =~ /^AS5300/) {
- $type = "AS5300";
- } elsif ( $proc =~ /^AS5350/) {
- $type = "AS5350";
- } elsif ( $proc =~ /^AS5400/) {
- $type = "AS5400";
- } elsif ($proc =~ /6000/) {
- $type = "6000";
- $device = "switch";
- } elsif ($proc eq "WK-C65") {
- $type = "6500";
- } elsif ($proc eq "RP") {
- $type = "7000";
- } elsif ($proc eq "RP1") {
- $type = "7000";
- } elsif ($proc =~ /720[246]/) {
- $type = "7200";
- } elsif ( $proc =~ /^73/) {
- $type = "7300";
- } elsif ($proc eq "RSP7000") {
- $type = "7500";
- } elsif ($proc =~ /RSP\d/) {
- $type = "7500";
- } elsif ($proc =~ /OSR-76/) {
- $type = "7600";
- } elsif ($proc =~ /CISCO76/) {
- $type = "7600";
- } elsif ($proc =~ /1200[48]\/(GRP|PRP)/ || $proc =~ /1201[26]\/(GRP|PRP)/) {
- $type = "12000";
- } elsif ($proc =~ /1201[26]-8R\/(GRP|PRP)/) {
- $type = "12000";
- } elsif ($proc =~ /1240[48]\/(GRP|PRP)/ || $proc =~ /1241[06]\/(GRP|PRP)/) {
- $type = "12400";
- } else {
- $type = $proc;
- }
- print STDERR "TYPE = $type\n" if ($debug);
- ProcessHistory("COMMENTS","keysort","A1",
- "!Chassis type:$slave $proc - a $type $device\n");
- ProcessHistory("COMMENTS","keysort","B1",
- "!Memory:$slave main $mem\n");
- if (defined($cpu)) {
- ProcessHistory("COMMENTS","keysort","A3",
- "!CPU:$slave $cpu$_$slaveslot\n");
- }
- next;
- }
- if (/(\S+) Silicon\s*Switch Processor/) {
- if (!defined($C0)) {
- $C0 = 1; ProcessHistory("COMMENTS","keysort","C0","!\n");
- }
- ProcessHistory("COMMENTS","keysort","C2","!SSP: $1\n");
- $ssp = 1;
- $sspmem = $1;
- next;
- }
- /^(\d+[kK]) bytes of multibus/ &&
- ProcessHistory("COMMENTS","keysort","B2",
- "!Memory: multibus $1\n") && next;
- /^(\d+[kK]) bytes of (non-volatile|NVRAM)/ &&
- ProcessHistory("COMMENTS","keysort","B3",
- "!Memory: nvram $1\n") && next;
- /^(\d+[kK]) bytes of flash memory/ &&
- ProcessHistory("COMMENTS","keysort","B5","!Memory: flash $1\n") &&
- next;
- /^(\d+[kK]) bytes of .*flash partition/ &&
- ProcessHistory("COMMENTS","keysort","B6",
- "!Memory: flash partition $1\n") && next;
- /^(\d+[kK]) bytes of Flash internal/ &&
- ProcessHistory("COMMENTS","keysort","B4",
- "!Memory: bootflash $1\n") && next;
- if (/^(\d+[kK]) bytes of (Flash|ATA)?.*PCMCIA .*(slot|disk) ?(\d)/i) {
- ProcessHistory("COMMENTS","keysort","B7",
- "!Memory: pcmcia $2 $3$4 $1\n");
- next;
- }
- if (/^(\d+[kK]) bytes of (slot|disk)(\d)/i) {
- ProcessHistory("COMMENTS","keysort","B7",
- "!Memory: pcmcia $2$3 $1\n");
- next;
- }
- if (/^WARNING/) {
- if (!defined($I0)) {
- $I0 = 1;
- ProcessHistory("COMMENTS","keysort","I0","!\n");
- }
- ProcessHistory("COMMENTS","keysort","I1","! $_");
- }
- if (/^Configuration register is (.*)$/) {
- $config_register = $1;
- next;
- }
- if (/^Configuration register on node \S+ is (.*)$/) {
- $config_register = $1 if (length($config_register) < 1);
- next;
- }
- }
- return(0);
- }
- # This routine parses "admin show diag".
- # This will create arrays for hw info.
- sub AdminShowDiag {
- print STDERR " In ShowDiag: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- if (/^$prompt/) { $found_diag = 1; last};
- next if (/^(\s*|\s*$cmd\s*)$/);
- return(1) if (/Line has invalid autocommand /);
- return(1) if (/(Invalid (input|command) detected|Type help or )/i);
- return(-1) if (/command authorization failed/i);
- /^$/ && next;
- s/^NODE //;
- # wtf are these?
- next if (/(New Deviation|UDI_VID|Board State)/);
- # skip insertion time
- next if (/insertion time/i);
- # skip board h/w revision junk
- next if (/^(\s{2}board |\s{3,})/i);
- ProcessHistory("SLOT","","","!$_");
- }
- ProcessHistory("SLOT","","","!\n");
- return(0);
- }
- # This routine parses "admin show running".
- # This will create arrays for hw info.
- sub AdminShowRunning {
- print STDERR " In ShowRunning: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- if (/^$prompt/) { $found_diag = 1; last};
- next if (/^(\s*|\s*$cmd\s*)$/);
- return(1) if (/Line has invalid autocommand /);
- return(1) if (/(Invalid (input|command) detected|Type help or )/i);
- return(-1) if (/command authorization failed/i);
- /^$/ && next;
- /^building configuration/i && next;
- if (/^(\s*secret) / && $filter_pwds >= 2) {
- ProcessHistory("SLOT","","","!$1 <removed>\n");
- next;
- }
- /^end$/ && last;
- ProcessHistory("SLOT","","","!$_");
- }
- ProcessHistory("SLOT","","","!\n");
- return(0);
- }
- # This routine parses "admin show redundancy"
- sub ShowRedundancy {
- print STDERR " In ShowRedundancy: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- last if (/^$prompt/);
- next if (/^(\s*|\s*$cmd\s*)$/);
- return(1) if (/Line has invalid autocommand /);
- return(1) if (/(Invalid (input|command) detected|Type help or )/i);
- if (/^Version information for secondary in slot (\d+):/) {
- $slave = " Slave:";
- $slaveslot = ", slot $1";
- next;
- }
- /^IOS .* Software \(([A-Za-z0-9_-]*)\), .*Version\s+(.*)$/ &&
- ProcessHistory("COMMENTS","keysort","F1",
- "!Image:$slave Software: $1, $2\n") && next;
- /^Compiled (.*)$/ &&
- ProcessHistory("COMMENTS","keysort","F3",
- "!Image:$slave Compiled: $1\n") && next;
- }
- return(0);
- }
- # This routine parses "show install active"
- sub ShowInstallActive {
- print STDERR " In ShowInstallActive: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- last if (/^$prompt/);
- next if (/^(\s*|\s*$cmd\s*)$/);
- return(1) if (/^\s*\^\s*$/);
- return(1) if (/Line has invalid autocommand /);
- return(1) if (/(Invalid (input|command) detected|Type help or )/i);
- return(-1) if (/command authorization failed/i);
- ProcessHistory("COMMENTS","keysort","F5","!Image: $_") && next;
- }
- return(0);
- }
- # This routine parses "admin show env all"
- sub ShowEnv {
- # Skip if this is not a 7500, 7200, or 7000.
- print STDERR " In ShowEnv: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- if (/^$prompt/) { $found_env = 1; last};
- next if (/^(\s*|\s*$cmd\s*)$/);
- #return(1) if ($type !~ /^7/);
- return(1) if (/Line has invalid autocommand /);
- return(1) if (/(Invalid (input|command) detected|Type help or )/i);
- return(0) if ($found_env); # Only do this routine once
- return(-1) if (/command authorization failed/i);
- if (!defined($E0)) {
- $E0 = 1;
- ProcessHistory("COMMENTS","keysort","E0","!\n");
- }
- if (/^Arbiter type (\d), backplane type (\S+)/) {
- if (!defined($C0)) {
- $C0 = 1; ProcessHistory("COMMENTS","keysort","C0","!\n");
- }
- ProcessHistory("COMMENTS","keysort","C1",
- "!Enviromental Arbiter Type: $1\n");
- ProcessHistory("COMMENTS","keysort","A2",
- "!Chassis type: $2 backplane\n");
- next;
- }
- /^Power Supply Information$/ && next;
- /^\s*Power Module\s+Voltage\s+Current$/ && next;
- /^\s*(Power [^:\n]+)$/ &&
- ProcessHistory("COMMENTS","keysort","E1","!Power: $1\n") && next;
- /^\s*(Lower Power .*)/i &&
- ProcessHistory("COMMENTS","keysort","E2","!Power: $1\n") && next;
- /^\s*(redundant .*)/i &&
- ProcessHistory("COMMENTS","keysort","E2","!Power: $1\n") && next;
- /^\s*(RPS is .*)/i &&
- ProcessHistory("COMMENTS","keysort","E2","!Power: $1\n") && next;
- }
- ProcessHistory("COMMENTS","","","!\n");
- return(0);
- }
- # This routine parses "dir /all ((disk|slot)N|bootflash|nvram):"
- sub DirSlotN {
- print STDERR " In DirSlotN: $_" if ($debug);
- my($dev) = (/\s([^\s]+):/);
- while (<INPUT>) {
- tr/\015//d;
- last if (/^$prompt/);
- next if (/^(\s*|\s*$cmd\s*)$/);
- return(1) if /^\s*\^\s*$/;
- return(1) if (/Line has invalid autocommand /);
- return(1) if (/(Invalid (input|command) detected|Type help or )/i);
- return(1) if (/(No such device|Error Sending Request)/i);
- return(1) if (/\%Error: No such file or directory/);
- return(1) if (/No space information available/);
- # Corrupt flash
- /\%Error calling getdents / &&
- ProcessHistory("FLASH","","","!Flash: $dev: $_") && next;
- return(-1) if (/\%Error calling/);
- return(-1) if (/(: device being squeezed|ATA_Status time out)/i); # busy
- return(-1) if (/\%Error opening \S+:\S+ \(Device or resource busy\)/i);
- return(-1) if (/command authorization failed/i);
- return(1) if (/(Open device \S+ failed|Error opening \S+:)/);
- # filter frequently changing files from IOX bootflash
- if ($dev =~ /bootflash/) {
- next if (/temp_cont\s*$/);
- next if (/uptime_cont\s*$/);
- }
- # Filter dhcp database
- if (/dhcp_[^. ]*\.txt/) {
- next;
- }
- # Filter debugging file dlbg.txt & dlbg.txt-1 only on ASR9k w/ XR
- if ($proc =~ /ASR9K/ && /dlbg\.txt/) {
- next;
- }
- if (/.*\((\d+) bytes free\)/) {
- my($tmp) = $1;
- if ($tmp >= (1024 * 1024 * 1024)) {
- $tmp = int($tmp / (1024 * 1024 * 1024));
- s/$1 bytes free/$tmp GB free/;
- } else {
- $tmp = int($tmp / (1024 * 1024));
- s/$1 bytes free/$tmp MB free/;
- }
- }
- ProcessHistory("FLASH","","","!Flash: $dev: $_");
- }
- ProcessHistory("","","","!\n");
- return(0);
- }
- # This routine parses "admin show variables boot"
- sub ShowBootVar {
- print STDERR " In ShowBootVar: $_" if ($debug);
- while (<INPUT>) {
- # delete non-ascii chars, except new line
- tr/ -~\n//cd;
- last if (/^$prompt/);
- next if (/\s*$cmd\s*$/);
- return(1) if (/^\s*\^\s*$/);
- return(1) if (/Line has invalid autocommand /);
- return(1) if (/(Invalid (input|command) detected|Type help or )/i);
- return(1) if (/Ambiguous command/i);
- return(1) if (/(Open device \S+ failed|Error opening \S+:)/);
- return(-1) if (/command authorization failed/i);
- # skip blank lines
- next if (/^\s*$/);
- ProcessHistory("COMMENTS", "keysort", "C30", "! $_");
- }
- ProcessHistory("COMMENTS", "keysort", "C39", "!\n");
- return(0);
- }
- # This routine parses "show controllers"
- sub ShowContAll {
- # Skip if this is a 70[01]0, 7500, or 12000.
- print STDERR " In ShowContAll: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- last if (/^$prompt/);
- next if (/^(\s*|\s*$cmd\s*)$/);
- return(1) if (/(Invalid (input|command) detected|Type help or )/i);
- # return(1) if ($type =~ /^(12[40]|7[05])/);
- return(-1) if (/command authorization failed/i);
- if (/^Interface ([^ \n(]*)/) { $INT = "$1, "; next; }
- /^(BRI unit \d)/ &&
- ProcessHistory("INT","","","!Interface: $1\n") && next;
- /^LANCE unit \d, NIM/ &&
- ProcessHistory("INT","","","!Interface: $_") && next;
- /^(LANCE unit \d)/ &&
- ProcessHistory("INT","","","!Interface: $1\n") && next;
- /(Media Type is \S+),/ &&
- ProcessHistory("INT","","","!\t$1\n");
- if (/(M\dT[^ :]*:) show controller:$/) {
- my($ctlr) = $1;
- $_ = <INPUT>; tr/\015//d; s/ subunit \d,//;
- ProcessHistory("INT","","","!Interface: $ctlr $_");
- }
- if (/^(\S+) : show controller:$/) {
- my($ctlr) = $1;
- $_ = <INPUT>; tr/\015//d; s/ subunit \d,//;
- ProcessHistory("INT","","","!Interface: $ctlr: $_");
- }
- /^(HD unit \d), idb/ &&
- ProcessHistory("INT","","","!Interface: $1\n") && next;
- /^HD unit \d, NIM/ &&
- ProcessHistory("INT","","","!Interface: $_") && next;
- /^buffer size \d+ HD unit \d, (.*)/ &&
- ProcessHistory("INT","","","!\t$1\n") && next;
- /^AM79970 / && ProcessHistory("INT","","","!Interface: $_") && next;
- /^buffer size \d+ (Universal Serial: .*)/ &&
- ProcessHistory("INT","","","!\t$1\n") && next;
- /^Hardware is (.*)/ &&
- ProcessHistory("INT","","","!Interface: $INT$1\n") && next;
- /^(QUICC Serial unit \d),/ &&
- ProcessHistory("INT","","","!$1\n") && next;
- /^QUICC Ethernet .*/ &&
- ProcessHistory("INT","","","!$_") && next;
- /^DTE .*\.$/ &&
- ProcessHistory("INT","","","!\t$_") && next;
- /^(cable type :.*),/ &&
- ProcessHistory("INT","","","!\t$1\n") && next;
- /^(.* cable.*), received clockrate \d+$/ &&
- ProcessHistory("INT","","","!\t$1\n") && next;
- /^.* cable.*$/ &&
- ProcessHistory("INT","","","!\t$_") && next;
- }
- return(0);
- }
- # This routine parses "show debug"
- sub ShowDebug {
- print STDERR " In ShowDebug: $_" if ($debug);
- my($lines) = 0;
- while (<INPUT>) {
- tr/\015//d;
- last if (/^$prompt/);
- next if (/^(\s*|\s*$cmd\s*)$/);
- return(1) if (/Line has invalid autocommand /);
- return(1) if (/(Invalid (input|command) detected|Type help or )/i);
- return(-1) if (/command authorization failed/i);
- /^No matching debug flags set$/ && next;
- /^No debug flags set$/ && next;
- ProcessHistory("COMMENTS","keysort","J1","!DEBUG: $_");
- $lines++;
- }
- if ($lines) {
- ProcessHistory("COMMENTS","keysort","J0","!\n");
- }
- return(0);
- }
- # This routine parses "admin show install summary"
- sub ShowInstallSummary {
- print STDERR " In ShowInstallSummary: $_" if ($debug);
- while (<INPUT>) {
- # delete non-ascii chars, except new line
- tr/ -~\n//cd;
- last if (/^$prompt/);
- next if (/\s*$cmd\s*$/);
- return(1) if (/^\s*\^\s*$/);
- return(1) if (/Line has invalid autocommand /);
- return(1) if (/(Invalid (input|command) detected|Type help or )/i);
- return(1) if (/Ambiguous command/i);
- return(1) if (/(Open device \S+ failed|Error opening \S+:)/);
- return(-1) if (/command authorization failed/i);
- # skip blank lines
- next if (/^\s*$/);
- ProcessHistory("COMMENTS", "keysort", "C15", "! $_");
- }
- ProcessHistory("COMMENTS", "keysort", "C10", "!\n");
- ProcessHistory("COMMENTS", "keysort", "C19", "!\n");
- return(0);
- }
- # This routine parses "show inventory".
- sub ShowInventory {
- print STDERR " In ShowInventory: $_" if ($debug);
- while (<INPUT>) {
- # delete non-ascii chars, except new line
- tr/ -~\n//cd;
- return if (/^\s*\^$/);
- last if (/^$prompt/);
- next if (/^(\s*|\s*$cmd\s*)$/);
- return(1) if (/Line has invalid autocommand /);
- return(1) if (/(Invalid (input|command) detected|Type help or )/i);
- return(-1) if (/command authorization failed/i);
- # remove spaces after quotes
- s/\"\s+/\"/g;
- if (/^(NAME: "[^"]*",) (DESCR: "[^"]+")/) {
- ProcessHistory("INVENTORY","","", sprintf("!%-30s %s\n", $1, $2));
- next;
- }
- # split PID/VID/SN line
- if (/^PID: (\S*)\s*, VID: (\S*)\s*, SN: (\S*)\s*$/) {
- my($pid,$vid,$sn) = ($1, $2, $3);
- my($entries) = "";
- # filter <empty>, "0x" and "N/A" lines
- if ($pid !~ /^(|0x|N\/A)$/) {
- $entries .= "!PID: $pid\n";
- }
- if ($vid !~ /^(|0x|N\/A)$/) {
- $entries .= "!VID: $vid\n";
- }
- if ($sn !~ /^(|0x|N\/A)$/) {
- $entries .= "!SN: $sn\n";
- }
- ProcessHistory("INVENTORY","","", "$entries");
- next;
- }
- ProcessHistory("INVENTORY","","","!$_");
- }
- ProcessHistory("INVENTORY","","","!\n");
- return(0);
- }
- # This routine parses "admin show license"
- sub ShowLicense {
- print STDERR " In ShowLicense: $_" if ($debug);
- while (<INPUT>) {
- # delete non-ascii chars, except new line
- tr/ -~\n//cd;
- last if (/^$prompt/);
- next if (/\s*$cmd\s*$/);
- return(1) if (/^\s*\^\s*$/);
- return(1) if (/Line has invalid autocommand /);
- return(1) if (/(Invalid (input|command) detected|Type help or )/i);
- return(1) if (/Ambiguous command/i);
- return(1) if (/(Open device \S+ failed|Error opening \S+:)/);
- return(-1) if (/command authorization failed/i);
- # skip blank lines
- next if (/^\s*$/);
- ProcessHistory("COMMENTS", "keysort", "C20", "! $_");
- }
- ProcessHistory("COMMENTS", "keysort", "C29", "!\n");
- return(0);
- }
- # This routine parses "show rpl maximum"
- sub ShowRPL {
- print STDERR " In ShowRPL: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- last if (/^$prompt/);
- next if (/^(\s*|\s*$cmd\s*)$/);
- return(1) if /^\s*\^\s*$/;
- return(1) if (/Line has invalid autocommand /);
- return(1) if (/(Invalid (input|command) detected|Type help or )/i);
- return(1) if (/Ambiguous command/i);
- return(-1) if (/command authorization failed/i);
- ProcessHistory("COMMENTS","keysort","RPLMAX","! $_");
- }
- ProcessHistory("COMMENTS","keysort","RPLMAX","!\n");
- return(0);
- }
- # This routine parses "show vlan"
- sub ShowVLAN {
- print STDERR " In ShowVLAN: $_" if ($debug);
- ($_ = <INPUT>, return(1)) if (!$DO_SHOW_VLAN);
- while (<INPUT>) {
- tr/\015//d;
- last if (/^$prompt/);
- next if (/^(\s*|\s*$cmd\s*)$/);
- return(1) if /^\s*\^\s*$/;
- return(1) if (/Line has invalid autocommand /);
- return(1) if (/(Invalid (input|command) detected|Type help or )/i);
- return(1) if (/Ambiguous command/i);
- return(-1) if (/command authorization failed/i);
- ProcessHistory("COMMENTS","keysort","IO","!VLAN: $_");
- }
- ProcessHistory("COMMENTS","keysort","IO","!\n");
- return(0);
- }
- # This routine processes a "write term"
- sub WriteTerm {
- print STDERR " In WriteTerm: $_" if ($debug);
- my($lineauto,$comment,$linecnt) = (0,0,0);
- while (<INPUT>) {
- tr/\015//d;
- last if (/^$prompt/);
- return(1) if (!$linecnt && /^\s+\^\s*$/);
- return(1) if (/Line has invalid autocommand /);
- return(1) if (/(Invalid (input|command) detected|Type help or )/i);
- return(1) if (/\%Error: No such file or directory/);
- return(0) if ($found_end); # Only do this routine once
- return(-1) if (/command authorization failed/i);
- return(-1) if (/% ?configuration buffer full/i);
- /^! no configuration change since last restart/i && next;
- # skip emtpy lines at the beginning
- if (!$linecnt && /^\s*$/) {
- next;
- }
- if (!$linecnt && defined($config_register)) {
- ProcessHistory("","","", "!\nconfig-register $config_register\n");
- }
- /Non-Volatile memory is in use/ && return(-1); # NvRAM is locked
- /% Configuration buffer full, / && return(-1); # buffer is in use
- $linecnt++;
- $lineauto = 0 if (/^[^ ]/);
- # skip the crap
- if (/^(##+|(building|current) configuration)/i) {
- while (<INPUT>) {
- next if (/^Current configuration\s*:/i);
- next if (/^:/);
- next if (/^([%!].*|\s*)$/);
- next if (/^ip add.*ipv4:/); # band-aid for 3620 12.0S
- last;
- }
- tr/\015//d;
- }
- # some versions have other crap mixed in with the bits in the
- # block above
- /^! (Last configuration|NVRAM config last)/ && next;
- # and for the ASA
- /^: (Written by \S+ at|Saved)/ && next;
- # skip consecutive comment lines to avoid oscillating extra comment
- # line on some access servers. grrr.
- if (/^!\s*$/) {
- next if ($comment);
- ProcessHistory("","","",$_);
- $comment++;
- next;
- }
- $comment = 0;
- # Dog gone Cool matches to process the rest of the config
- /^tftp-server flash / && next; # kill any tftp remains
- /^ntp clock-period / && next; # kill ntp clock-period
- /^ length / && next; # kill length on serial lines
- /^ width / && next; # kill width on serial lines
- $lineauto = 1 if /^ modem auto/;
- /^ speed / && $lineauto && next; # kill speed on serial lines
- /^ clockrate / && next; # kill clockrate on serial interfaces
- if (/^(enable )?(password|passwd)( level \d+)? / && $filter_pwds >= 1) {
- ProcessHistory("ENABLE","","","!$1$2$3 <removed>\n");
- next;
- }
- if (/^(enable secret) / && $filter_pwds >= 2) {
- ProcessHistory("ENABLE","","","!$1 <removed>\n");
- next;
- }
- if (/^username (\S+)(\s.*)? secret /) {
- if ($filter_pwds >= 2) {
- ProcessHistory("USER","keysort","$1",
- "!username $1$2 secret <removed>\n");
- } else {
- ProcessHistory("USER","keysort","$1","$_");
- }
- next;
- }
- if (/^username (\S+)(\s.*)? password ((\d) \S+|\S+)/) {
- if ($filter_pwds >= 2) {
- ProcessHistory("USER","keysort","$1",
- "!username $1$2 password <removed>\n");
- } elsif ($filter_pwds >= 1 && $4 ne "5"){
- ProcessHistory("USER","keysort","$1",
- "!username $1$2 password <removed>\n");
- } else {
- ProcessHistory("USER","keysort","$1","$_");
- }
- next;
- }
- if (/^( set session-key (in|out)bound ah \d+ )/ && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1<removed>\n");
- next;
- }
- if (/^( set session-key (in|out)bound esp \d+ (authenticator|cypher) )/
- && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1<removed>\n");
- next;
- }
- if (/^(\s*)password / && $filter_pwds >= 1) {
- ProcessHistory("LINE-PASS","","","!$1password <removed>\n");
- next;
- }
- if (/^(\s*)secret / && $filter_pwds >= 2) {
- ProcessHistory("LINE-PASS","","","!$1secret <removed>\n");
- next;
- }
- if (/^\s*neighbor (\S*) password / && $filter_pwds >= 1) {
- ProcessHistory("","","","! neighbor $1 password <removed>\n");
- next;
- }
- if (/^(ppp .* password) 7 .*/ && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1 <removed>\n"); next;
- }
- if (/^(ip ftp password) / && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1 <removed>\n"); next;
- }
- if (/^( ip ospf authentication-key) / && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1 <removed>\n"); next;
- }
- # isis passwords appear to be completely plain-text
- if (/^\s+isis password (\S+)( .*)?/ && $filter_pwds >= 1) {
- ProcessHistory("","","","!isis password <removed>$2\n"); next;
- }
- if (/^\s+(domain-password|area-password) (\S+)( .*)?/
- && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1 <removed>$3\n"); next;
- }
- # this is reversable, despite 'md5' in the cmd
- if (/^( ip ospf message-digest-key \d+ md5) / && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1 <removed>\n"); next;
- }
- # this is also reversable, despite 'md5 encrypted' in the cmd
- if (/^( message-digest-key \d+ md5 (7|encrypted)) /
- && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1 <removed>\n"); next;
- }
- if (/^((crypto )?isakmp key) \S+ / && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1 <removed> $'"); next;
- }
- # filter HSRP passwords
- if (/^(\s+standby \d+ authentication) / && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1 <removed>\n"); next;
- }
- # this appears in "measurement/sla" images
- if (/^(\s+key-string \d?)/ && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1 <removed>\n"); next;
- }
- if (/^( l2tp tunnel \S+ password)/ && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1 <removed>\n"); next;
- }
- # i am told these are plain-text on the PIX
- if (/^(vpdn username (\S+) password)/) {
- if ($filter_pwds >= 1) {
- ProcessHistory("USER","keysort","$2","!$1 <removed>\n");
- } else {
- ProcessHistory("USER","keysort","$2","$_");
- }
- next;
- }
- # ASA/PIX keys in more system:running-config
- if (/^( pre-shared-key | key |failover key ).*/ && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1 <removed> $'"); next;
- }
- if (/(\s+ldap-login-password )\S+(.*)/ && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1 <removed> $'"); next;
- }
- #
- if (/^( cable shared-secret )/ && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1 <removed>\n");
- next;
- }
- /fair-queue individual-limit/ && next;
- # sort ip explicit-paths.
- if (/^ip explicit-path name (\S+)/) {
- my($key) = $1;
- my($expath) = $_;
- while (<INPUT>) {
- tr/\015//d;
- last if (/^$prompt/);
- last if (! /^(ip explicit-path name |[ !])/);
- if (/^ip explicit-path name (\S+)/) {
- ProcessHistory("EXPATH","keysort","$key","$expath");
- $key = $1;
- $expath = $_;
- } else {
- $expath .= $_;
- }
- }
- ProcessHistory("EXPATH","keysort","$key","$expath");
- }
- # sort route-maps
- if (/^route-map (\S+)/) {
- my($key) = $1;
- my($routemap) = $_;
- while (<INPUT>) {
- tr/\015//d;
- last if (/^$prompt/ || ! /^(route-map |[ !])/);
- if (/^route-map (\S+)/) {
- ProcessHistory("ROUTEMAP","keysort","$key","$routemap");
- $key = $1;
- $routemap = $_;
- } else {
- $routemap .= $_;
- }
- }
- ProcessHistory("ROUTEMAP","keysort","$key","$routemap");
- }
- # filter out any RCS/CVS tags to avoid confusing local CVS storage
- s/\$(Revision|Id):/ $1:/;
- # order access-lists
- /^access-list\s+(\d\d?)\s+(\S+)\s+(\S+)/ &&
- ProcessHistory("ACL $1 $2","$aclsort","$3","$_") && next;
- # order extended access-lists
- /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+host\s+(\S+)/ &&
- ProcessHistory("EACL $1 $2","$aclsort","$3","$_") && next;
- /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+(\d\S+)/ &&
- ProcessHistory("EACL $1 $2","$aclsort","$3","$_") && next;
- /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+any/ &&
- ProcessHistory("EACL $1 $2","$aclsort","0.0.0.0","$_") && next;
- # sort ipv{4,6} access-lists
- if (/^ipv(4|6) access-list (\S+)\s*$/) {
- my($nlri, $key) = ($1, $2);
- my($seq, $cmd);
- ProcessHistory("ACL $nlri $key","","","$_");
- while (<INPUT>) {
- tr/\015//d;
- last if (/^$prompt/ || /^\S/);
- ($seq, $cmd, $misc, $ip) = ($_ =~ /^\s+(\d+) (\w+) (.*\s)(\w+)/);
- if ($cmd =~ /(permit|deny)/) {
- ProcessHistory("ACL $nlri $key $cmd","$aclsort","$ip",
- " $cmd $misc$ip\n");
- } else {
- ProcessHistory("ACL $nlri $key","",""," $cmd $misc$ip\n");
- }
- }
- }
- # order arp lists
- /^arp\s+(\d+\.\d+\.\d+\.\d+)\s+/ &&
- ProcessHistory("ARP","$aclsort","$1","$_") && next;
- /^ip prefix-list\s+(\S+)\s+seq\s+(\d+)\s+(permit|deny)\s+(\d\S+)(\/.*)$/ &&
- ProcessHistory("PACL $1 $3","$aclsort","$4","ip prefix-list $1 $3 $4$5\n")
- && next;
- # order logging statements
- /^logging (\d+\.\d+\.\d+\.\d+)/ &&
- ProcessHistory("LOGGING","ipsort","$1","$_") && next;
- # order/prune snmp-server host statements
- # we only prune lines of the form
- # snmp-server host a.b.c.d <community>
- if (/^snmp-server host (\d+\.\d+\.\d+\.\d+) /) {
- if ($filter_commstr) {
- my($ip) = $1;
- my($line) = "snmp-server host $ip";
- my(@tokens) = split(' ', $');
- my($token);
- while ($token = shift(@tokens)) {
- if ($token eq 'version') {
- $line .= " " . join(' ', ($token, shift(@tokens)));
- if ($token eq '3') {
- $line .= " " . join(' ', ($token, shift(@tokens)));
- }
- } elsif ($token eq 'vrf') {
- $line .= " " . join(' ', ($token, shift(@tokens)));
- } elsif ($token =~ /^(informs?|traps?|(no)?auth)$/) {
- $line .= " " . $token;
- } else {
- $line = "!$line " . join(' ', ("<removed>",
- join(' ',@tokens)));
- last;
- }
- }
- ProcessHistory("SNMPSERVERHOST","ipsort","$ip","$line\n");
- } else {
- ProcessHistory("SNMPSERVERHOST","ipsort","$1","$_");
- }
- next;
- }
- if (/^(snmp-server community) (\S+)/) {
- if ($filter_commstr) {
- ProcessHistory("SNMPSERVERCOMM","keysort","$_",
- "!$1 <removed>$'") && next;
- } else {
- ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && next;
- }
- }
- # prune tacacs/radius server keys
- if (/^((tacacs|radius)-server\s(\w*[-\s(\s\S+])*\s?key) (\d )?\w+/
- && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1 <removed>$'"); next;
- }
- # order clns host statements
- /^clns host \S+ (\S+)/ &&
- ProcessHistory("CLNS","keysort","$1","$_") && next;
- # order alias statements
- /^alias / && ProcessHistory("ALIAS","keysort","$_","$_") && next;
- # delete ntp auth password - this md5 is a reversable too
- if (/^(ntp authentication-key \d+ md5) / && $filter_pwds >= 1) {
- ProcessHistory("","","","!$1 <removed>\n"); next;
- }
- # order ntp peers/servers
- if (/^ntp (server|peer) (\d+)\.(\d+)\.(\d+)\.(\d+)/) {
- $sortkey = sprintf("$1 %03d%03d%03d%03d",$2,$3,$4,$5);
- ProcessHistory("NTP","keysort",$sortkey,"$_");
- next;
- }
- # order ip host statements
- /^ip host (\S+) / &&
- ProcessHistory("IPHOST","keysort","$1","$_") && next;
- # order ip nat source static statements
- /^ip nat (\S+) source static (\S+)/ &&
- ProcessHistory("IP NAT $1","ipsort","$2","$_") && next;
- # order atm map-list statements
- /^\s+ip\s+(\d+\.\d+\.\d+\.\d+)\s+atm-vc/ &&
- ProcessHistory("ATM map-list","ipsort","$1","$_") && next;
- # order ip rcmd lines
- /^ip rcmd/ && ProcessHistory("RCMD","keysort","$_","$_") && next;
- # system controller
- /^syscon address (\S*) (\S*)/ &&
- ProcessHistory("","","","!syscon address $1 <removed>\n") &&
- next;
- if (/^syscon password (\S*)/ && $filter_pwds >= 1) {
- ProcessHistory("","","","!syscon password <removed>\n");
- next;
- }
- /^ *Cryptochecksum:/ && next;
- # catch anything that wasnt matched above.
- ProcessHistory("","","","$_");
- # end of config.
- if (/^end$/) {
- $found_end = 1;
- return(0);
- }
- }
- return(0);
- }
- # This routine processes a "write term"
- sub FilterAll {
- print STDERR " In FilterAll: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- last if (/^$prompt/);
- return(1) if (/Line has invalid autocommand /);
- return(1) if (/(Invalid (input|command) detected|Type help or )/i);
- return(1) if (/\%Error: No such file or directory/);
- return(-1) if (/command authorization failed/i);
- return(-1) if (/% ?configuration buffer full/i);
- }
- }
- # dummy function
- sub DoNothing {print STDOUT;}
- # Main
- @commandtable = (
- # Disable timestamps in output
- {'terminal no-timestamp' => 'FilterAll' }, # XR 3.6 style
- {'terminal exec prompt no-timestamp' => 'FilterAll' }, # XR 3.8 style
- {'admin show version' => 'ShowVersion'},
- # XR IMAGE commands
- {'admin show install summary' => 'ShowInstallSummary'},
- {'admin show license' => 'ShowLicense'},
- {'admin show variables boot' => 'ShowBootVar'},
- {'show redundancy secondary' => 'ShowRedundancy'},
- {'show install active' => 'ShowInstallActive'},
- {'admin show env all' => 'ShowEnv'},
- {'dir /all nvram:' => 'DirSlotN'},
- {'dir /all bootflash:' => 'DirSlotN'},
- {'dir /all compactflash:' => 'DirSlotN'},
- {'dir /all compactflasha:' => 'DirSlotN'},
- {'dir /all slot0:' => 'DirSlotN'},
- {'dir /all disk0:' => 'DirSlotN'},
- {'dir /all disk0a:' => 'DirSlotN'},
- {'dir /all slot1:' => 'DirSlotN'},
- {'dir /all disk1:' => 'DirSlotN'},
- {'dir /all disk1a:' => 'DirSlotN'},
- {'dir /all slot2:' => 'DirSlotN'},
- {'dir /all disk2:' => 'DirSlotN'},
- {'dir /all harddisk:' => 'DirSlotN'},
- {'dir /all harddiska:' => 'DirSlotN'},
- {'dir /all harddiskb:' => 'DirSlotN'},
- {'dir /all slavenvram:' => 'DirSlotN'},
- {'dir /all slavebootflash:' => 'DirSlotN'},
- {'dir /all slaveslot0:' => 'DirSlotN'},
- {'dir /all slavedisk0:' => 'DirSlotN'},
- {'dir /all slaveslot1:' => 'DirSlotN'},
- {'dir /all slavedisk1:' => 'DirSlotN'},
- {'dir /all slaveslot2:' => 'DirSlotN'},
- {'dir /all slavedisk2:' => 'DirSlotN'},
- {'dir /all sec-nvram:' => 'DirSlotN'},
- {'dir /all sec-bootflash:' => 'DirSlotN'},
- {'dir /all sec-slot0:' => 'DirSlotN'},
- {'dir /all sec-disk0:' => 'DirSlotN'},
- {'dir /all sec-slot1:' => 'DirSlotN'},
- {'dir /all sec-disk1:' => 'DirSlotN'},
- {'dir /all sec-slot2:' => 'DirSlotN'},
- {'dir /all sec-disk2:' => 'DirSlotN'},
- {'show controllers' => 'ShowContAll'},
- {'admin show running' => 'AdminShowRunning'},
- {'admin show diag' => 'AdminShowDiag'},
- {'admin show inventory raw' => 'ShowInventory'},
- {'show vlan' => 'ShowVLAN'},
- {'show debug' => 'ShowDebug'},
- {'show rpl maximum' => 'ShowRPL'},
- {'show running-config' => 'WriteTerm'},
- );
- # Use an array to preserve the order of the commands and a hash for mapping
- # commands to the subroutine and track commands that have been completed.
- @commands = map(keys(%$_), @commandtable);
- %commands = map(%$_, @commandtable);
- $cisco_cmds = join(";",@commands);
- $cmds_regexp = join("|", map quotemeta($_), @commands);
- if (length($host) == 0) {
- if ($file) {
- print(STDERR "Too few arguments: file name required\n");
- exit(1);
- } else {
- print(STDERR "Too few arguments: host name required\n");
- exit(1);
- }
- }
- open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n";
- select(OUTPUT);
- # make OUTPUT unbuffered if debugging
- if ($debug) { $| = 1; }
- if ($file) {
- print STDERR "opening file $host\n" if ($debug);
- print STDOUT "opening file $host\n" if ($log);
- open(INPUT,"<$host") || die "open failed for $host: $!\n";
- } else {
- print STDERR "executing clogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($debug);
- print STDOUT "executing clogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($log);
- if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
- system "clogin -t $timeo -c \"$cisco_cmds\" $host </dev/null > $host.raw 2>&1" || die "clogin failed for $host: $!\n";
- open(INPUT, "< $host.raw") || die "clogin failed for $host: $!\n";
- } else {
- open(INPUT,"clogin -t $timeo -c \"$cisco_cmds\" $host </dev/null |") || die "clogin failed for $host: $!\n";
- }
- }
- # determine ACL sorting mode
- if ($ENV{"ACLSORT"} =~ /no/i) {
- $aclsort = "";
- }
- # determine community string filtering mode
- if (defined($ENV{"NOCOMMSTR"}) &&
- ($ENV{"NOCOMMSTR"} =~ /yes/i || $ENV{"NOCOMMSTR"} =~ /^$/)) {
- $filter_commstr = 1;
- } else {
- $filter_commstr = 0;
- }
- # determine password filtering mode
- if ($ENV{"FILTER_PWDS"} =~ /no/i) {
- $filter_pwds = 0;
- } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) {
- $filter_pwds = 2;
- } else {
- $filter_pwds = 1;
- }
- ProcessHistory("","","","!RANCID-CONTENT-TYPE: cisco-xr\n!\n");
- ProcessHistory("COMMENTS","keysort","B0","!\n");
- ProcessHistory("COMMENTS","keysort","D0","!\n");
- ProcessHistory("COMMENTS","keysort","F0","!\n");
- ProcessHistory("COMMENTS","keysort","G0","!\n");
- TOP: while(<INPUT>) {
- tr/\015//d;
- if (/[>#]\s?exit$/) {
- $clean_run = 1;
- last;
- }
- if (/^Error:/) {
- print STDOUT ("$host clogin error: $_");
- print STDERR ("$host clogin error: $_") if ($debug);
- $clean_run = 0;
- last;
- }
- while (/#\s*($cmds_regexp)\s*$/) {
- $cmd = $1;
- if (!defined($prompt)) {
- $prompt = ($_ =~ /^([^#]+#)/)[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}};
- delete($commands{$cmd});
- if ($rval == -1) {
- $clean_run = 0;
- last TOP;
- }
- }
- }
- print STDOUT "Done $logincmd: $_\n" if ($log);
- # Flush History
- ProcessHistory("","","","");
- # Cleanup
- close(INPUT);
- close(OUTPUT);
- if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
- unlink("$host.raw") if (! $debug);
- }
- # check for completeness
- if (scalar(%commands) || !$clean_run || !$found_end) {
- if (scalar(%commands)) {
- printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands)));
- printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug);
- }
- if (!$clean_run || !$found_end) {
- print STDOUT "$host: End of run not found\n";
- print STDERR "$host: End of run not found\n" if ($debug);
- system("/usr/bin/tail -1 $host.new");
- }
- unlink "$host.new" if (! $debug);
- }
- #! /usr/bin/perl
- ##
- ## $Id: zrancid.in 3135 2015-07-02 18:59:15Z heas $
- ##
- ## rancid 3.4.1
- ## Copyright (c) 1997-2016 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.
- #
- # This version of rancid tries to deal with zebra s/w.
- #
- # RANCID - Really Awesome New Cisco confIg Differ
- #
- # usage: zrancid [-dltCV] [-f filename | hostname]
- #
- use Getopt::Std;
- getopts('dflt:CV');
- if ($opt_V) {
- print "rancid 3.4.1\n";
- exit(0);
- }
- $log = $opt_l;
- $debug = $opt_d;
- $file = $opt_f;
- $host = $ARGV[0];
- $clean_run = 0;
- $found_end = 0;
- $timeo = 90; # clogin timeout in seconds
- my(@commandtable, %commands, @commands);# command lists
- my($aclsort) = ("ipsort"); # ACL sorting mode
- my($filter_commstr); # SNMP community string filtering
- my($filter_pwds); # password filtering mode
- # force a terminal type so as not to confuse Linux
- $ENV{'TERM'} = "ansi";
- # This routine is used to print out the router configuration
- sub ProcessHistory {
- my($new_hist_tag,$new_command,$command_string,@string) = (@_);
- if ((($new_hist_tag ne $hist_tag) || ($new_command ne $command))
- && scalar(%history)) {
- print eval "$command \%history";
- undef %history;
- }
- if (($new_hist_tag) && ($new_command) && ($command_string)) {
- if ($history{$command_string}) {
- $history{$command_string} = "$history{$command_string}@string";
- } else {
- $history{$command_string} = "@string";
- }
- } elsif (($new_hist_tag) && ($new_command)) {
- $history{++$#history} = "@string";
- } else {
- print "@string";
- }
- $hist_tag = $new_hist_tag;
- $command = $new_command;
- 1;
- }
- sub numerically { $a <=> $b; }
- # This is a sort routine that will sort numerically on the
- # keys of a hash as if it were a normal array.
- sub keynsort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $key (sort numerically keys(%lines)) {
- $sorted_lines[$i] = $lines{$key};
- $i++;
- }
- @sorted_lines;
- }
- # This is a sort routine that will sort on the
- # keys of a hash as if it were a normal array.
- sub keysort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $key (sort keys(%lines)) {
- $sorted_lines[$i] = $lines{$key};
- $i++;
- }
- @sorted_lines;
- }
- # This is a sort routine that will sort on the
- # values of a hash as if it were a normal array.
- sub valsort{
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $key (sort values %lines) {
- $sorted_lines[$i] = $key;
- $i++;
- }
- @sorted_lines;
- }
- # This is a numerical sort routine (ascending).
- sub numsort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $num (sort {$a <=> $b} keys %lines) {
- $sorted_lines[$i] = $lines{$num};
- $i++;
- }
- @sorted_lines;
- }
- # This is a sort routine that will sort on the
- # ip address when the ip address is anywhere in
- # the strings.
- sub ipsort {
- local(%lines) = @_;
- local($i) = 0;
- local(@sorted_lines);
- foreach $addr (sort sortbyipaddr keys %lines) {
- $sorted_lines[$i] = $lines{$addr};
- $i++;
- }
- @sorted_lines;
- }
- # These two routines will sort based upon IP addresses
- sub ipaddrval {
- my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#);
- $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0]));
- }
- sub sortbyipaddr {
- &ipaddrval($a) <=> &ipaddrval($b);
- }
- # This routine parses "show version"
- sub ShowVersion {
- print STDERR " In ShowVersion: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- last if(/^$prompt/);
- next if(/^(\s*|\s*$cmd\s*)$/);
- return(-1) if (/command authorization failed/i);
- ProcessHistory("COMMENTS","keysort","B0", "!$_") && next;
- }
- return(0);
- }
- # This routine processes a "write term"
- sub WriteTerm {
- print STDERR " In WriteTerm: $_" if ($debug);
- while (<INPUT>) {
- tr/\015//d;
- last if(/^$prompt/);
- return(-1) if (/command authorization failed/i);
- /Non-Volatile memory is in use/ && return(-1); # NvRAM is locked
- # skip the crap
- if (/^(##+$|(Building|Current) configuration)/i) {
- while (<INPUT>) {
- next if (/^Current configuration\s*:/i);
- next if (/^([%!].*|\s*)$/);
- last;
- }
- tr/\015//d;
- }
- # some versions have other crap mixed in with the bits in the
- # block above
- /^! Last Changed:/ && next;
- # Dog gone Cool matches to process the rest of the config
- # /^tftp-server flash / && next; # kill any tftp remains
- # /^ntp clock-period / && next; # kill ntp clock-period
- # /^ length / && next; # kill length on serial lines
- # /^ width / && next; # kill width on serial lines
- # /^ clockrate / && next; # kill clockrate on serial interfaces
- if (/^((enable )?password( \d)?) / && $filter_pwds >= 1) {
- ProcessHistory("ENABLE","","","!$1 <removed>\n");
- next;
- }
- if (/^username (\S+)(\s.*)? password ((\d) \S+|\S+)/) {
- if ($filter_pwds == 2) {
- ProcessHistory("USER","keysort","$1","!username $1$2 password <removed>\n");
- } elsif ($filter_pwds == 1 && $4 ne "5"){
- ProcessHistory("USER","keysort","$1","!username $1$2 password <removed>\n");
- } else {
- ProcessHistory("USER","keysort","$1","$_");
- }
- next;
- }
- # prune passwords {bgp, ...}
- if (/^\s*neighbor (\S*) password / && $filter_pwds >= 1) {
- ProcessHistory("","","","! neighbor $1 password <removed>\n");
- next;
- }
- # sort route-maps
- if (/^route-map (\S+)/) {
- my($key) = $1;
- my($routemap) = $_;
- while (<INPUT>) {
- tr/\015//d;
- last if (/^$prompt/ || ! /^(route-map |[ !])/);
- if (/^route-map (\S+)/) {
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement