Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 17 Aug 2016 18:13:37 +0000 (UTC)
From:      Mark Felder <feld@FreeBSD.org>
To:        ports-committers@freebsd.org, svn-ports-all@freebsd.org, svn-ports-head@freebsd.org
Subject:   svn commit: r420361 - in head/net-mgmt/rancid3: . files
Message-ID:  <201608171813.u7HIDbqJ052473@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: feld
Date: Wed Aug 17 18:13:36 2016
New Revision: 420361
URL: https://svnweb.freebsd.org/changeset/ports/420361

Log:
  net-mgmt/rancid3: Add experimental support for Comware devices
  
  Comware support has been added via a port option. It is not enabled by
  default as upstream has not been able to validate the reliability of
  this enhancement.
  
  PR:		209361

Added:
  head/net-mgmt/rancid3/files/cmw.pm   (contents, props changed)
  head/net-mgmt/rancid3/files/cmwlogin   (contents, props changed)
  head/net-mgmt/rancid3/files/comware_types.conf   (contents, props changed)
Modified:
  head/net-mgmt/rancid3/Makefile
  head/net-mgmt/rancid3/pkg-plist

Modified: head/net-mgmt/rancid3/Makefile
==============================================================================
--- head/net-mgmt/rancid3/Makefile	Wed Aug 17 18:10:01 2016	(r420360)
+++ head/net-mgmt/rancid3/Makefile	Wed Aug 17 18:13:36 2016	(r420361)
@@ -34,15 +34,22 @@ NEWERCONFIG_FILES1=	etc/rancid.conf
 NEWERCONFIG_FILES2=	etc/lg.conf
 NEWCONFIG_FILES=	rancid.conf lg.conf
 
-OPTIONS_DEFINE=		SVN
+OPTIONS_DEFINE=		COMWARE SVN
 OPTIONS_DEFAULT=
 
+COMWARE_DESC=		Add experimental support for Comware devices
 SVN_DESC=		Use Subversion instead of CVS
 
 CONFLICTS=	rancid-[0-9]*
 
 .include <bsd.port.options.mk>
 
+.if ${PORT_OPTIONS:MCOMWARE}
+PLIST_SUB+=	COMWARE=""
+.else
+PLIST_SUB+=	COMWARE="@comment "
+.endif
+
 .if ${PORT_OPTIONS:MSVN}
 CONFIGURE_ARGS+=	--with-svn
 BUILD_DEPENDS+=		svn:devel/subversion
@@ -57,6 +64,9 @@ pre-everything::
 	@ ${ECHO} "Make sure your rancid repository is quiet before upgrading; disable rancid cron jobs"
 
 post-patch:
+.if ${PORT_OPTIONS:MCOMWARE}
+	${CAT} ${FILESDIR}/comware_types.conf >> ${WRKSRC}/etc/rancid.types.base
+.endif
 	${REINPLACE_CMD} "s|par.1|rancid-par.1|" ${WRKSRC}/man/Makefile.in
 	${MV} ${WRKSRC}/man/par.1 ${WRKSRC}/man/rancid-par.1
 	${REINPLACE_CMD} "s|3des|3des-cbc|g" ${WRKSRC}/bin/*.in ${WRKSRC}/cloginrc.sample \
@@ -65,6 +75,10 @@ post-patch:
 post-install:
 	${LN} -s ${PREFIX}/libexec/${PORTNAME}/rancid-cvs ${STAGEDIR}${PREFIX}/bin
 	${LN} -s ${PREFIX}/libexec/${PORTNAME}/rancid-run ${STAGEDIR}${PREFIX}/bin
+.if ${PORT_OPTIONS:MCOMWARE}
+	${INSTALL_DATA} ${FILESDIR}/cmw.pm ${STAGEDIR}/${PREFIX}/lib/rancid
+	${INSTALL_SCRIPT} ${FILESDIR}/cmwlogin ${STAGEDIR}/${PREFIX}/libexec/rancid
+.endif
 .for file in ${NEWCONFIG_FILES}
 	@ if [ -f ${PREFIX}/etc/${PORTNAME}/${file} ] ; then \
 	${ECHO} "WARNING: *** new ${file} file is installed as ${PREFIX}/rancid/${file}.sample"; \

Added: head/net-mgmt/rancid3/files/cmw.pm
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/net-mgmt/rancid3/files/cmw.pm	Wed Aug 17 18:13:36 2016	(r420361)
@@ -0,0 +1,525 @@
+package cmw;
+##
+## $Id: cmw.pm.in 3000 2015-01-06 18:47:49Z heas $
+##
+## rancid 3.1.99
+## Copyright (c) 1997-2015 by Terrapin Communications, Inc.
+## All rights reserved.
+##
+## This code is derived from software contributed to and maintained by
+## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan,
+## Pete Whiting, Austin Schutz, and Andrew Fort.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted provided that the following conditions
+## are met:
+## 1. Redistributions of source code must retain the above copyright
+##    notice, this list of conditions and the following disclaimer.
+## 2. Redistributions in binary form must reproduce the above copyright
+##    notice, this list of conditions and the following disclaimer in the
+##    documentation and/or other materials provided with the distribution.
+## 3. All advertising materials mentioning features or use of this software
+##    must display the following acknowledgement:
+##        This product includes software developed by Terrapin Communications,
+##        Inc. and its contributors for RANCID.
+## 4. Neither the name of Terrapin Communications, Inc. nor the names of its
+##    contributors may be used to endorse or promote products derived from
+##    this software without specific prior written permission.
+## 5. It is requested that non-binding fixes and modifications be contributed
+##    back to Terrapin Communications, Inc.
+##
+## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS
+## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+## PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
+## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+## POSSIBILITY OF SUCH DAMAGE.
+#
+#  RANCID - Really Awesome New Cisco confIg Differ
+#
+#  cmw.pm - Comware (Huawei/H3C/3com/HP) rancid procedures
+#
+# https://sites.google.com/site/jrbinks/code/rancid/cmwrancid
+
+use 5.010;
+use strict 'vars';
+use warnings;
+no warnings 'uninitialized';
+require(Exporter);
+our @ISA = qw(Exporter);
+
+use rancid 3.1.99;
+
+our $login;
+
+@ISA = qw(Exporter rancid main);
+#XXX @Exporter::EXPORT = qw($VERSION @commandtable %commands @commands);
+
+# XXX
+#our @EXPORT = qw(iproutesort iprouteval);
+
+# load-time initialization
+sub import {
+    0;
+}
+
+# post-open(collection file) initialization
+sub init {
+    $login = "cmwlogin";
+    # add content lines and separators
+    ProcessHistory("","","","!RANCID-CONTENT-TYPE: $devtype\n!\n");
+
+    0;
+}
+
+# main loop of input of device output
+sub inloop {
+    my($INPUT, $OUTPUT) = @_;
+    my($cmd, $rval);
+
+TOP: while(<$INPUT>) {
+	tr/\015//d;
+        if (/[\]>#]\a?\s*quit/) {
+	#if (/[>#]\s?exit$/) {
+	    $clean_run = 1;
+	    last;
+	}
+	if (/^Error:/) {
+	    print STDOUT ("$host $login error: $_");
+	    print STDERR ("$host $login error: $_") if ($debug);
+	    $clean_run = 0;
+	    last;
+	}
+        while (/[\]>#]\a?\s*($cmds_regexp)\s*$/) {
+	    $cmd = $1;
+
+	    if (!defined($prompt)) {
+		# Extract the prompt: look for something not [ or < at the start
+		# of the line, until either ] or > or # is reached:
+		$prompt = ($_ =~ /^([^\]>#]+[\]>]\a?)/)[0]; 
+		$prompt =~ s/([][}{)(\\])/\\$1/g;
+		print STDERR ("PROMPT MATCH: $prompt\n") if ($debug);
+	    }
+	    print STDERR ("HIT COMMAND:$_") if ($debug);
+	    if (! defined($commands{$cmd})) {
+		print STDERR "$host: found unexpected command - \"$cmd\"\n";
+		$clean_run = 0;
+		last TOP;
+	    }
+	    $rval = &{$commands{$cmd}}($INPUT, $OUTPUT, $cmd);
+	    delete($commands{$cmd});
+	    if ($rval == -1) {
+		$clean_run = 0;
+		last TOP;
+	    }
+	}
+    }
+}
+
+# dummy function
+sub DoNothing {print STDOUT;}
+
+# This is a sort routine that will sort on the
+# ip route when the ip route is anywhere in
+# the strings.
+sub iproutesort {
+    my(%lines) = @_;
+    my($i) = 0;
+    my(@sorted_lines);
+    foreach my $iproute (sort sortbyiproute keys %lines) {
+	$sorted_lines[$i] = $lines{$iproute};
+	$i++;
+    }
+    @sorted_lines;
+}
+
+## XXX Re-evaluate based on new routines, and consider IPv6:
+# These two routines will sort based upon IP route
+sub iprouteval {
+    my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)/(\d+)$#);
+    $a[4] + ($a[3] + 256 * ($a[2] + 256 * ($a[1] + 256 * $a[0])));
+}
+
+sub sortbyiproute {
+    &iprouteval($a) <=> &iprouteval($b);
+}
+
+# Clean up lines on input, particularly ANSI characters as a result
+# of us not being able to turn off per-session terminal paging
+sub filter_lines {
+    my ($l) = (@_);
+
+    #s/^\033\[42D +\033\[42D(.+)$/$1/;
+    #s/\033\133\064\062\104\s*\033\133\064\062\104//g;
+    $l =~ s/\033\133\064\062\104\s+\033\133\064\062\104//g;
+    $l =~ s/\033\133\061\066\104\s+\033\133\061\066\104//g;
+    $l =~ s/\033\133\064\062\104//g;
+    $l =~ s/\033\133\061\062\104//g;
+    $l =~ s/.*\[37D(.*)/$1/g;    # MA5600
+    # Probably not needed:
+    $l =~ s/\s*---- More ----\s*//;
+    $l =~ s/^               //; # Comware7
+    $l =~ s/Synchronization is finished.//g;
+    return $l;
+}
+
+# Some commands are not supported on some models or versions
+# of code.
+# Remove the associated error messages, and rancid will ensure that
+# these are not treated as "missed" commands
+sub command_not_valid {
+    my ($l) = (@_);
+
+    if ( $l =~
+	/% Too many parameters found at '\^' position/ ||
+	/% Unrecognized command found at '\^' position/ ||
+	/% Incomplete command found at '\^' position./ ||
+	/(% )?Wrong parameter found at '\^' position/ ||
+	/% Wrong device .+/
+    ) {
+	return(1);
+    } else {
+	return(0);
+    }
+}
+
+# Some commands are not authorized under the current
+# user's permissions
+sub command_not_auth {
+    my ($l) = (@_);
+
+    if ( $l =~
+	/Permission denied\./
+    ) {
+	return(1);
+    } else {
+	return(0);
+    }
+}
+
+# Some output lines are always skipped
+sub skip_pattern {
+    my ($l) = (@_);
+
+    if ( $l =~
+	/^\s+\^$/ ||
+        /^$/
+    ) {
+	return(1);
+    } else {
+	return(0);
+    }
+}
+
+sub DisplayFib {
+
+    my($INPUT, $OUTPUT, $cmd) = @_;
+    my($dest, $nexthop, $flag, $outint, $label);
+    print STDERR "    In DisplayFib: $_" if ($debug);
+
+    chomp;
+
+    # Display the command we're processing in the output:
+    ProcessHistory("FIB","","","!\n! '$cmd':\n!\n");
+
+    while (<$INPUT>) {
+        tr/\015//d;
+        last if(/^\s*$prompt/);
+        chomp;
+        $_ = filter_lines($_);
+
+	return(1) if command_not_valid($_);
+	return(-1) if command_not_auth($_);
+	next if skip_pattern($_);
+
+        next if /^Destination count: \d+ FIB entry count: \d+/;
+
+        # Chop out some detail that changes over time (Comware 3):
+        s/(\s+)TimeStamp\s+/$1/;        # TimeStamp column heading
+
+        ProcessHistory("FIB","","","! $_\n");
+
+        if ( m,Destination/Mask, ) {
+            while (<$INPUT>) {
+                tr/\015//d;
+                last if(/^\s*$prompt/);
+                chomp;
+                $_ = filter_lines($_);
+
+                # Chop out some detail that changes over time (Comware 3):
+                s/(\s+)t\[\d+\]\s+/$1/;    # TimeStamp data
+
+                # "display fib" on comware7 shows host entries for things
+                # learned via arp too.  For a distribution router, that's all
+                # the devices on subnets routed by it!
+                # If we filter out all "UH" entries that are NOT InLoop, we
+                # get acceptable output.
+                #
+                # So we want to keep:
+                #
+                # 0.0.0.0/32         127.0.0.1       UH  InLoop0 Null
+                #
+                # but reject:
+                #
+                # 130.159.44.161/32  130.159.44.161  UH  Vlan44  Null
+                #
+                # However I've a feeling that this is a problematic
+                # solution, and some object to the notion that rancid
+                # should be representing such potentially dynamic data in
+                # the first place, which is why we created the
+                # $display_fib flag for rancid 2, and in rancid 3 one
+		# can modify the command table in rancid.types.conf
+
+		($dest, $nexthop, $flag, $outint, $label) = split;
+                next if ( $flag eq 'UH' && $outint !~ /InLoop/ );
+                #ProcessHistory("FIB", "cmw::iproutesort", "$dest", "! $_\n");
+                ProcessHistory("FIB", "ipsort", "$dest", "! $_\n");
+            }
+
+            ProcessHistory("FIB", "", "", "!\n");
+
+            # return here to ensure that we don't keep swallowing the
+            # next command's output by returning to the surrounding
+            # while loop
+            return(0);
+        }
+    }
+    return(0);
+}
+
+sub DisplayIPRoutes {
+    my($INPUT, $OUTPUT, $cmd) = @_;
+    my($key,$line,$spaces);
+    print STDERR "    In DisplayIPRoutes: $_" if ($debug);
+
+    chomp;
+
+    # Display the command we're processing in the output:
+    ProcessHistory("IPR","","","!\n! '$cmd':\n!\n");
+
+    while (<$INPUT>) {
+        tr/\015//d;
+        last if(/^\s*$prompt/);
+        chomp;
+
+        $_ = filter_lines($_);
+	return(1) if command_not_valid($_);
+	return(-1) if command_not_auth($_);
+	next if skip_pattern($_);
+
+        ProcessHistory("IPR","","","! $_\n");
+
+        if ( m,Destination/Mask, ) {
+            my $lastkey = "";
+            my $lastspaces = "";
+            while (<$INPUT>) {
+                tr/\015//d;
+                last if(/^\s*$prompt/);
+                chomp;
+                $_ = filter_lines($_);
+
+                # If the key is blank, indicating multiple nexthops for
+                # a particular route, then we use the previous one
+                if ( m/^\s+(.+)/ ) {
+                    $key = $lastkey;
+                    $line = $key . $lastspaces . $1;
+                    #ProcessHistory("IPR", "cmw::iproutesort", "$key", "! $line\n");
+                    ProcessHistory("IPR", "ipsort", "$key", "! $line\n");
+                }
+                if ( m/^(\S+)(\s+).+/ ) {
+                    $key = $1;
+                    $line = $_;
+                    $spaces = $2;
+                    #ProcessHistory("IPR", "cmw::iproutesort", "$key", "! $line\n");
+                    ProcessHistory("IPR", "ipsort", "$key", "! $line\n");
+
+		    # Remember these, we may need them on the next pass
+                    $lastkey = $key;
+                    $lastspaces = $spaces;
+                }
+            }
+
+            ProcessHistory("IPR", "", "", "!\n");
+
+            # return here to ensure that we don't keep swallowing the
+            # next command's output by returning to the surrounding
+            # while loop
+            return(0);
+        }
+    }
+    return(0);
+}
+
+## This routine processes general output of "display" commands
+sub CommentOutput {
+    my($INPUT, $OUTPUT, $cmd) = @_;
+    print STDERR "    In CommentOutput: $_" if ($debug);
+
+    chomp;
+
+    # Display the command we're processing in the output:
+    ProcessHistory("COMMENTS", "", "", "!\n! '$cmd':\n!\n");
+
+    while (<$INPUT>) {
+        tr/\015//d;
+
+        # If we find the prompt, we're done
+        # Ordinarily this matches from the start of the line, however
+        # we've seen circumstances at least in Comware7 where the
+        # prompt is preceded by whitespace, like so:
+        # ^M^M               ^M<router>display boot-loader^M
+        last if(/^\s*$prompt/);
+        chomp;
+
+	# filter out some junk
+        $_ = filter_lines($_);
+	return(1) if command_not_valid($_);
+	return(-1) if command_not_auth($_);
+	next if skip_pattern($_);
+
+	# Now we skip or modify some lines from various commands to
+        # remove irrelevant content, or to avoid insignificant diffs
+
+        # 'display local-user':
+        s/\s+Current AccessNum:.+$//;
+
+        # 'display version':
+        next if (/^(Uptime is \d|.+ [Uu]ptime is \d).+$/);
+        # No longer necessary since skipping the whole Uptime line:
+        # Mangle these lines:
+        #s/(.*)[Uu]ptime.*.weeks.*.days*.*hours*.*minutes*(.*)/$1 $2/;
+        #s/(.*)[Uu]ptime.*days*.*hours*.*minutes*(.*)/$1 $2/;
+
+        # MSRs display a 'last reboot' time, but sometimes the seconds
+        # vary by one or two (presumably internal rounding), so simply make
+        # the last digit a fixed '0'.  It would probably be safer to make
+        # the last two digits a fixed '00'.
+        # (Thx Alexander Belokopytov)
+        s/(^Last reboot.+)\d$/${1}0/;
+
+        # 'dir ' commands
+        if ( $cmd =~ /^dir / ) {
+            # First field is just an index number, chop it out
+            s/^\s+\d+\s+(.+)/ $1/;
+            # Remove filenames that are updated frequently
+            next if (
+                /logfile\.log$/ ||
+                /lauth\.dat$/ ||
+                /ifindex\.dat$/ ||
+                /startup\.mdb$/ ||
+                /private-data\.txt$/ ||
+                /.+ KB total \(.+ KB free/ ||
+                /.+ KB total \(.+ KB free/ ||
+                /\.trash/
+            );
+        }
+
+	# 'display ospf brief'/'display ospf'
+        if ( $cmd =~ 'display ospf( brief)?' ) {
+            #next if (/^(Ospf is not enabled yet|Info: OSPF routing process is not enabled|The feature OSPF has not been enabled.).+$/);
+            next if (/^\s+SPF (Computation|Scheduled|calculation) Count:.+$/i);
+        }
+
+        if ( $cmd eq 'display power' ) {
+            next if (/^(\s+Input Power).+$/);
+        }
+
+        if ( $cmd eq 'display poe powersupply' ) {
+            next if (/^(PSE Total Power Consumption|PSE Available Power|PSE Peak Value|PSE Average Value).+$/);
+        }
+
+        if ( $cmd eq 'display ntp-service status' ) {
+            next unless m/(Clock status|Clock stratum|Reference clock ID)/i;
+        }
+
+        if ( $cmd eq 'display transceiver interface' ) {
+            s/^(\S+ transceiver information:).+$/$1/;   # filter random garbage
+            s/^Error: The transceiver is absent.$/  No transceiver present./;
+            s/^Error: The combo port is inactive.$/  Inactive combo port./;
+        }
+
+        # Add the processed lines to the output buffer:
+        ProcessHistory("COMMENTS","","","! $_\n");
+    }
+
+    # Add a blank comment line to the output buffer
+    ProcessHistory("COMMENTS", "", "", "!\n");
+    return(0);
+}
+
+## This routine processes a "display current"
+sub DisplayCurrent {
+    my($INPUT, $OUTPUT, $cmd) = @_;
+    print STDERR "    In DisplayCurrent: $_" if ($debug);
+
+
+    while (<$INPUT>) {
+        tr/\015//d;
+        last if(/^\s*$prompt/);
+        chomp;
+
+        $_ = filter_lines($_);
+	return(1) if command_not_valid($_);
+	return(-1) if command_not_auth($_);
+	next if skip_pattern($_);
+
+        return(0) if ($found_end);
+
+        # Filter out some sensitive data:
+        if ( $filter_commstr &&
+             /^ ?(snmp-agent (target-host.+securityname|usm-user|community (read|write)) )(\S+)/
+           ) {
+            ProcessHistory("","","","! $1<removed>$'\n");
+            next;
+        }
+        if ( $filter_pwds >= 1 &&
+            /^ ?(password (?:simple|cipher|hash) )(\S+)/ ||
+            /^ ?(super password( role level-\d)( level \d)? (cipher|simple|hash) )(\S+)/ ||
+            /^ ?(set authentication password (cipher|simple|hash) )(\S+)/ ||
+            /^ ?(key (?:authentication|accounting) )(\S+)/ 
+           ) {
+            ProcessHistory("","","","! $1<removed>$'\n");
+            next;
+        }
+
+        # filter ssh public keys of devices connected to from this device
+        if (/^ ?(public-key-code begin)/ &&
+                $filter_pwds >= 2) {
+            ProcessHistory("","","","!$1\n");
+            ProcessHistory("","","","! <removed>\n");
+            while (<$INPUT>) {
+                tr/\015//d;
+                next if /^$/;
+		next if /^\s+[[:xdigit:]]$/;
+                if (/(^ public-key-code end)/) {
+                    ProcessHistory("","","","!$1\n");
+                    last;
+                }
+            }
+        next;
+        }
+
+	# Filter mac addresses dynamically added to config
+	next if (/^ ?mac-address security.+$/);
+
+        ProcessHistory("", "", "", "$_\n");
+
+        # end of config
+        if (/^return/) {
+            $found_end = 1;
+            return(0);
+        }
+    }
+    return(0);
+}
+
+1;
+
+__END__
+
+

Added: head/net-mgmt/rancid3/files/cmwlogin
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/net-mgmt/rancid3/files/cmwlogin	Wed Aug 17 18:13:36 2016	(r420361)
@@ -0,0 +1,1043 @@
+#! /usr/local/bin/expect --
+##
+## $Id: cmwlogin 3022 2015-01-13 20:00:00Z heas $
+##
+## rancid 3.1.99
+## Copyright (c) 1997-2015 by Terrapin Communications, Inc.
+## All rights reserved.
+##
+## This code is derived from software contributed to and maintained by
+## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan,
+## Pete Whiting, Austin Schutz, and Andrew Fort.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted provided that the following conditions
+## are met:
+## 1. Redistributions of source code must retain the above copyright
+##    notice, this list of conditions and the following disclaimer.
+## 2. Redistributions in binary form must reproduce the above copyright
+##    notice, this list of conditions and the following disclaimer in the
+##    documentation and/or other materials provided with the distribution.
+## 3. All advertising materials mentioning features or use of this software
+##    must display the following acknowledgement:
+##        This product includes software developed by Terrapin Communications,
+##        Inc. and its contributors for RANCID.
+## 4. Neither the name of Terrapin Communications, Inc. nor the names of its
+##    contributors may be used to endorse or promote products derived from
+##    this software without specific prior written permission.
+## 5. It is requested that non-binding fixes and modifications be contributed
+##    back to Terrapin Communications, Inc.
+##
+## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS
+## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+## PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
+## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+## POSSIBILITY OF SUCH DAMAGE.
+#
+#  The expect login scripts were based on Erik Sherk's gwtn, by permission.
+#
+# cwlogin - Comware login
+#
+# Most options are intuitive for logging into a Comware device.
+# The default is to enable (thus -noenable).  Some folks have
+# setup tacacs to have a user login at priv-lvl = 3 (enabled)
+# so the -autoenable flag was added for this case (don't go through
+# the process of enabling and the prompt will be the "#" prompt.
+# The default username password is the same as the vty password.
+#
+
+# Usage line
+set usage "Usage: $argv0 \[-dSV\] \[-autoenable\] \[-noenable\] \[-c command\] \
+\[-Evar=x\] \[-e enable-password\] \[-f cloginrc-file\] \[-p user-password\] \
+\[-r passphrase\] \[-s script-file\] \[-t timeout\] \[-u username\] \
+\[-v vty-password\] \[-w enable-username\] \[-x command-file\] \[-P platform\] \
+\[-y ssh_cypher_type\] router \[router...\]\n"
+
+# env(CLOGIN) may contain:
+#	x == do not set xterm banner or name
+
+# Password file
+set password_file $env(HOME)/.cloginrc
+# Default is to login to the router
+set do_command 0
+set do_script 0
+# The default is to automatically enable
+set avenable 1
+# The default is that you login non-enabled (tacacs can have you login already
+# enabled)
+set avautoenable 0
+# The default is to look in the password file to find the passwords.  This
+# tracks if we receive them on the command line.
+set do_passwd 1
+set do_enapasswd 1
+# Save config, if prompted
+set do_saveconfig 0
+# Sometimes routers take awhile to answer (the default is 10 sec)
+set timeoutdflt 45
+# Some CLIs having problems if we write too fast (Extreme, PIX, Cat)
+set send_human {.2 .1 .4 .2 1}
+
+# Find the user in the ENV, or use the unix userid.
+if {[info exists env(CISCO_USER)]} {
+    set default_user $env(CISCO_USER)
+} elseif {[info exists env(USER)]} {
+    set default_user $env(USER)
+} elseif {[info exists env(LOGNAME)]} {
+    set default_user $env(LOGNAME)
+} else {
+    # This uses "id" which I think is portable.  At least it has existed
+    # (without options) on all machines/OSes I've been on recently -
+    # unlike whoami or id -nu.
+    if [catch {exec id} reason] {
+	send_error "\nError: could not exec id: $reason\n"
+	exit 1
+    }
+    regexp {\(([^)]*)} "$reason" junk default_user
+}
+if {[info exists env(CLOGINRC)]} {
+    set password_file $env(CLOGINRC)
+}
+
+# Process the command line
+for {set i 0} {$i < $argc} {incr i} {
+    set arg [lindex $argv $i]
+
+    switch  -glob -- $arg {
+	# Expect debug mode
+	-d* {
+	    exp_internal 1
+	# Username
+	} -u* {
+	    if {! [regexp .\[uU\](.+) $arg ignore user]} {
+		incr i
+		set username [lindex $argv $i]
+	    }
+	# VTY Password
+	} -p* {
+	    if {! [regexp .\[pP\](.+) $arg ignore userpasswd]} {
+		incr i
+		set userpasswd [lindex $argv $i]
+	    }
+	    set do_passwd 0
+	# ssh passphrase
+	} -r* {
+	    if {! [regexp .\[rR\](.+) $arg ignore passphrase]} {
+		incr i
+		set vapassphrase [lindex $argv $i]
+	    }
+	# VTY Password
+	} -v* {
+	    if {! [regexp .\[vV\](.+) $arg ignore passwd]} {
+		incr i
+		set passwd [lindex $argv $i]
+	    }
+	    set do_passwd 0
+	# Version string
+	} -V* {
+	    send_user "rancid 3.1.99\n"
+	    exit 0
+	# Enable Username
+	} -w* {
+	    if {! [regexp .\[wW\](.+) $arg ignore enauser]} {
+		incr i
+		set enausername [lindex $argv $i]
+	    }
+	# Environment variable to pass to -s scripts
+	} -E* {
+	    if {[regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} {
+		set E$varname $varvalue
+	    } else {
+		send_user "\nError: invalid format for -E in $arg\n"
+		exit 1
+	    }
+	# Enable Password
+	} -e* {
+	    if {! [regexp .\[e\](.+) $arg ignore enapasswd]} {
+		incr i
+		set enapasswd [lindex $argv $i]
+	    }
+	    set do_enapasswd 0
+	# Platform
+	} -P* {
+	    if {! [regexp .\[P\](.+) $arg ignore platform]} {
+		incr i
+		set plat [lindex $argv $P]
+	    }
+	# Command to run.
+	} -c* {
+	    if {! [regexp .\[cC\](.+) $arg ignore command]} {
+		incr i
+		set command [lindex $argv $i]
+	    }
+	    set do_command 1
+	# Expect script to run.
+	} -s* {
+	    if {! [regexp .\[sS\](.+) $arg ignore sfile]} {
+		incr i
+		set sfile [lindex $argv $i]
+	    }
+	    if { ! [file readable $sfile] } {
+		send_user "\nError: Can't read $sfile\n"
+		exit 1
+	    }
+	    set do_script 1
+	# save config on exit
+	} -S* {
+	    set do_saveconfig 1
+	# 'ssh -c' cypher type
+	} -y* {
+	    if {! [regexp .\[eE\](.+) $arg ignore cypher]} {
+		incr i
+		set cypher [lindex $argv $i]
+	    }
+	# alternate cloginrc file
+	} -f* {
+	    if {! [regexp .\[fF\](.+) $arg ignore password_file]} {
+		incr i
+		set password_file [lindex $argv $i]
+	    }
+	# Timeout
+	} -t* {
+	    if {! [regexp .\[tT\](.+) $arg ignore timeout]} {
+		incr i
+	        set timeoutdflt [lindex $argv $i]
+	    }
+	# Command file
+	} -x* {
+	    if {! [regexp .\[xX\](.+) $arg ignore cmd_file]} {
+		incr i
+		set cmd_file [lindex $argv $i]
+	    }
+	    if [catch {set cmd_fd [open $cmd_file r]} reason] {
+		send_user "\nError: $reason\n"
+		exit 1
+	    }
+	    set cmd_text [read $cmd_fd]
+	    close $cmd_fd
+	    set command [join [split $cmd_text \n] \;]
+	    set do_command 1
+	# Do we enable?
+	} -noenable {
+	    set avenable 0
+	# Does tacacs automatically enable us?
+	} -autoenable {
+	    set avautoenable 1
+	    set avenable 0
+	} -* {
+	    send_user "\nError: Unknown argument! $arg\n"
+	    send_user $usage
+	    exit 1
+	} default {
+	    break
+	}
+    }
+}
+# Process routers...no routers listed is an error.
+if { $i == $argc } {
+    send_user "\nError: $usage"
+}
+
+# Only be quiet if we are running a script (it can log its output
+# on its own)
+if { $do_script } {
+    log_user 0
+} else {
+    log_user 1
+}
+
+#
+# Done configuration/variable setting.  Now run with it...
+#
+
+# Sets Xterm title if interactive...if its an xterm and the user cares
+proc label { host } {
+    global env
+    # if CLOGIN has an 'x' in it, don't set the xterm name/banner
+    if [info exists env(CLOGIN)] {
+	if {[string first "x" $env(CLOGIN)] != -1} { return }
+    }
+    # take host from ENV(TERM)
+    if [info exists env(TERM)] {
+	if [regexp \^(xterm|vs) $env(TERM) ignore] {
+	    send_user "\033]1;[lindex [split $host "."] 0]\a"
+	    send_user "\033]2;$host\a"
+	}
+    }
+}
+
+# This is a helper function to make the password file easier to
+# maintain.  Using this the password file has the form:
+# add password sl*	pete cow
+# add password at*	steve
+# add password *	hanky-pie
+proc add {var args} { global int_$var ; lappend int_$var $args}
+proc include {args} {
+    global env
+    regsub -all "(^{|}$)" $args {} args
+    if { [regexp "^/" $args ignore] == 0 } {
+	set args $env(HOME)/$args
+    }
+    source_password_file $args
+}
+
+proc find {var router} {
+    upvar int_$var list
+    if { [info exists list] } {
+	foreach line $list {
+	    if { [string match -nocase [lindex $line 0] $router] } {
+		return [lrange $line 1 end]
+	    }
+	}
+    }
+    return {}
+}
+
+# Loads the password file.  Note that as this file is tcl, and that
+# it is sourced, the user better know what to put in there, as it
+# could install more than just password info...  I will assume however,
+# that a "bad guy" could just as easy put such code in the clogin
+# script, so I will leave .cloginrc as just an extention of that script
+proc source_password_file { password_file } {
+    global env
+    if { ! [file exists $password_file] } {
+	send_user "\nError: password file ($password_file) does not exist\n"
+	exit 1
+    }
+    file stat $password_file fileinfo
+    if { [expr ($fileinfo(mode) & 007)] != 0000 } {
+	send_user "\nError: $password_file must not be world readable/writable\n"
+	exit 1
+    }
+    if [catch {source $password_file} reason] {
+	send_user "\nError: $reason\n"
+	exit 1
+    }
+}
+
+# Log into the router.
+# returns: 0 on success, 1 on failure, -1 if rsh was used successfully
+proc login { router user userpswd passwd enapasswd cmethod cyphertype identfile } {
+    global command spawn_id in_proc do_command do_script platform passphrase
+    global prompt prompt_match u_prompt p_prompt e_prompt sshcmd
+    set in_proc 1
+    set uprompt_seen 0
+
+    # try each of the connection methods in $cmethod until one is successful
+    set progs [llength $cmethod]
+    foreach prog [lrange $cmethod 0 end] {
+	incr progs -1
+	if [string match "telnet*" $prog] {
+	    regexp {telnet(:([^[:space:]]+))*} $prog methcmd suffix port
+	    if {"$port" == ""} {
+		set retval [catch {spawn telnet $router} reason]
+	    } else {
+		set retval [catch {spawn telnet $router $port} reason]
+	    }
+	    if { $retval } {
+		send_user "\nError: telnet failed: $reason\n"
+		return 1
+	    }
+	} elseif [string match "ssh*" $prog] {
+	    # ssh to the router & try to login with or without an identfile.
+	    regexp {ssh(:([^[:space:]]+))*} $prog methcmd suffix port
+	    set cmd $sshcmd
+	    if {"$port" != ""} {
+		set cmd "$cmd -p $port"
+	    }
+	    if {"$identfile" != ""} {
+		set cmd "$cmd -i $identfile"
+	    }
+	    set retval [catch {eval spawn [split "$cmd -c $cyphertype -x -l $user $router" { }]} reason]
+	    if { $retval } {
+		send_user "\nError: $cmd failed: $reason\n"
+		return 1
+	    }
+	} elseif ![string compare $prog "rsh"] {
+	    if { ! $do_command } {
+		if { [llength $cmethod] == 1 } {
+		    send_user "\nError: rsh is an invalid method for -x and "
+		    send_user "interactive logins\n"
+		}
+		if { $progs == 0 } {
+		    return 1
+		}
+		continue;
+	    }
+
+	    # handle escaped ;s in commands, and ;; and ^;
+	    regsub -all {([^\\]);;} $command "\\1;\u002;" esccommand
+	    regsub {^;} $esccommand "\u002;" command
+	    set sep "\\1\u001"
+	    regsub -all {([^\\])\;} $command "$sep" esccommand
+	    set sep "\u001"
+	    set commands [split $esccommand $sep]
+	    set num_commands [llength $commands]
+	    set rshfail 0
+	    for {set i 0} {$i < $num_commands && !$rshfail} { incr i} {
+		log_user 0
+		set retval [catch {spawn rsh $user@$router [lindex $commands $i] } reason]
+		if { $retval } {
+		    send_user "\nError: rsh failed: $reason\n"
+		    log_user 1; return 1
+		}
+		send_user "$router# [lindex $commands $i]\n"
+
+		# rcmd does not get a pager and no prompts, so we just have to
+		# look for failures & lines.
+		expect {
+		  "Connection refused"	{ catch {close}; catch {wait};
+					  send_user "\nError: Connection\
+						    Refused ($prog): $router\n"
+					  set rshfail 1
+					}
+		  -re "(Connection closed by|Connection to \[^\n\r]+ closed)" {
+					  catch {close}; catch {wait};
+					  send_user "\nError: Connection\
+						    closed ($prog): $router\n"
+					  set rshfail 1
+					}
+		  "Host is unreachable"	{ catch {close}; catch {wait};
+					  send_user "\nError: Host Unreachable:\
+						    $router\n"
+					  set rshfail 1
+					}
+		  "No address associated with" {
+					  catch {close}; catch {wait};
+					  send_user "\nError: Unknown host\
+						    $router\n"
+					  set rshfail 1
+					}
+		  -re "\b+"		{ exp_continue }
+		  -re "\[\n\r]+"	{ send_user -- "$expect_out(buffer)"
+					  exp_continue
+					}
+		  timeout		{ catch {close}; catch {wait};
+					  send_user "\nError: TIMEOUT reached\n"
+					  set rshfail 1

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201608171813.u7HIDbqJ052473>