rancid暂时用北电的刀片交换机用alteon的alogin脚本测试,登录不了。h3c的脚本从google group上下载一份下来先。出处:https://sites.google.com/site/jrbinks/code/rancid/h3ch3crancid点击(此处)折叠或打开#! /usr/bin/perl5#### $Id: $#### @PACKAGE@ @VERSION@## Copyright (c) 1997-2009 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### h3crancid## h3clogin/h3crancid covers the following product ranges:## * 3Com SuperStack 4 (post-joint venture with Huawei)# * H3C# * HP Networking ('A' & some 'E' portfolio, post 2010 3Com acquitision)## They may also work with some Huawei equipment.## https://sites.google.com/site/jrbinks/code/rancid/h3c### Usage: h3crancid [-dV] [-l] [-f filename | hostname]## Notable changes from standard *rancid programs:## * abstracted to path to the 'tail' utility# * altered "cisco_cmds" to be "device_cmds"# * define and use $logincmd## TODO:## It may be useful to pull common subroutines like the sorting ones into# a library for use by all the *rancid programs.############################################################################## END-USER TWEAKS# The login program to use. If no path is given, $PATH is searched:#my $logincmd = "h3clogin99";my $logincmd = "h3clogin";#my $logincmd = "/usr/local/libexec/h3clogin";## Enable display of the FIB:my $display_fib = 1;## Enable display of the routing table:# (no-op)#my $display_iproutes = 1;# END OF END-USER TWEAKS#############################################################################use Getopt::Std;getopts('dflV');if ($opt_V) {    print "@PACKAGE@ @VERSION@\n";    exit(0);}$log = $opt_l;$debug = $opt_d;$file = $opt_f;$host = $ARGV[0];$clean_run = 0;$found_end = 0;#$timeo = 90;            # login command timeout in seconds$timeo = 20;            # login command timeout in secondsmy $TAIL = "/usr/bin/tail";my(@commandtable, %commands, @commands);# command listsmy($aclsort) = ("ipsort");        # ACL sorting modemy($filter_commstr);            # SNMP community string filteringmy($filter_pwds);            # password filtering mode# This routine is used to print out the router configurationsub ProcessHistory {    my($new_hist_tag,$new_command,$command_string,@string)=(@_);    if((($new_hist_tag ne $hist_tag) || ($new_command ne $command))       && defined %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 addressessub 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);}sub filter_lines {    my ($l) = (@_);# print STDERR " In filterlines: $l\n" if ($debug);    # Filter out some ANSI crud as a result of us not being able to turn    # off per-session terminal paging:    # h3c:    #s/^\033\[42D +\033\[42D(.+)$/$1/;    # hwlogin+mods:    #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;    # Probably not needed:    $l =~ s/\s*---- More ----\s*//;# print STDERR "out: $l\n" if ($debug);    return $l;}sub DisplayFib {    ## We should probably guarantee that the FIB is sorted properly    print STDERR " In DisplayFib: $_" if ($debug);    return(1) if $display_fib == 0;    chomp;    # Display the command we're processing in the output:    s/^[\[]\a?\s?(.*)/\'$1\':/g;    ProcessHistory("COMMENTS","keysort","A0","! $_\n!\n");    while () {        tr/\015//d;        last if(/^$prompt/);        chomp;        # skip blank lines        return(1) if /^\s+\^$/;        $_ = filter_lines($_);        # make this a subroutine:        return(1) if /% Too many parameters found at '\^' position/;        return(1) if /% Unrecognized command found at '\^' position/;        return(1) if /% Wrong parameter found at '\^' position/;        return(1) if /% Wrong device .+/;        # Chop out some detail that changes over time:        s/(\s+)TimeStamp\s+/$1/;        s/(\s+)t\[\d+\]\s+/$1/;        ProcessHistory("COMMENTS","ipsort","A0","! $_\n");        #ProcessHistory("COMMENTS","keysort","A0","! $_\n");    }    ProcessHistory("COMMENTS","keysort","A0","! \n");    return(0);}# This routine processes general output of "display" commandssub CommentOutput {    print STDERR " In CommentOutput: $_" if ($debug);    chomp;    # Display the command we're processing in the output:    s/^[\[].*?[\]>]\a?\s?(.*)/\'$1\':/g;    ProcessHistory("","","","! $_\n!\n");    # eat the header line# $junk = ;    # now just copy it mostly verbatim to the history file    while () {        tr/\015//d;        # If we find the prompt, we're done        #last if(/^.*>/);        last if(/^$prompt/);        chomp;        # skip blank lines        return(1) if /^\s+\^$/;        $_ = filter_lines($_);    # Filter out some ANSI crud as a result of us not being able to turn    # off per-session terminal paging:    # h3c:    #s/^\033\[42D +\033\[42D(.+)$/$1/;    # hwlogin+mods:        #s/\033\133\064\062\104\s*\033\133\064\062\104//g;# s/\033\133\064\062\104\s+\033\133\064\062\104//g;# s/\033\133\061\066\104\s+\033\133\061\066\104//g;    #s/\033\133\064\062\104//g;    # Probably not needed:# s/\s*---- More ----\s*//;        # make this a subroutine:        # Some commands are not supported on some models or versions        # of code. These lines simply remove the associated error        # messages:        return(1) if /% Too many parameters found at '\^' position/;        return(1) if /% Unrecognized command found at '\^' position/;        return(1) if /% Wrong parameter found at '\^' position/;        return(1) if /% Wrong device .+/;        # Parts of the output of some commands changes over time, but we don't        # want these changes to trigger a rancid notification, so we        # filter them out:        # This is part of one line, just cut it out:        s/\s+Current AccessNum:.+$//;        if (/^(PSE Total Power Consumption|PSE Available Power|PSE Peak Value|PSE Average Value).+$/) {            next;        }        s/(.*)uptime.*days*.*hours*.*minutes*(.*)/$1 $2/;        ProcessHistory("","","","! $_\n");    }    ProcessHistory("","","","! \n");    return(0);}## This routine processes a "display current"sub DisplayCurrent {    print STDERR " In DisplayCurrent: $_" if ($debug);    while () {    tr/\015//d;    last if(/^$prompt/);        $_ = filter_lines($_);    # Filter out some ANSI crud as a result of us not being able to turn    # off per-session terminal paging:    # h3c:    #s/^\033\[42D +\033\[42D(.+)$/$1/;    # hwlogin+mods:    #s/\033\133\064\062\104\s*\033\133\064\062\104//g;# s/\033\133\064\062\104\s+\033\133\064\062\104//g;# s/\033\133\061\066\104\s+\033\133\061\066\104//g;# s/\033\133\064\062\104//g;    # Probably not needed:# s/\s*---- More ----\s*//;    # Filter out some sensitive data:    if (/^( ?snmp-agent community (read|write) )(\S+)/ &&        $filter_commstr == 0) {        ProcessHistory("","","","!$1$'");        next;    }    ProcessHistory("","","","$_");    # end of config        if (/^return/) {        $found_end = 1;        return(0);    }    }    return(0);}# dummy functionsub DoNothing {print STDOUT;}# Main## Not all commands are supported on all models and code versions## Not all of these should necessarily be included@commandtable = (    {'display version'            => 'CommentOutput'},    {'display boot-loader'        => 'CommentOutput'},    {'dir /all unit1>flash:/'        => 'CommentOutput'},    {'dir /all unit2>flash:/'        => 'CommentOutput'},    {'dir /all unit3>flash:/'        => 'CommentOutput'},    {'dir /all unit4>flash:/'        => 'CommentOutput'},    {'dir /all unit5>flash:/'        => 'CommentOutput'},    {'dir /all unit6>flash:/'        => 'CommentOutput'},    {'dir /all unit7>flash:/'        => 'CommentOutput'},    {'dir /all unit8>flash:/'        => 'CommentOutput'},    {'display device'            => 'CommentOutput'},    {'display device manuinfo'        => 'CommentOutput'},    {'display irf'            => 'CommentOutput'},    {'display xrn-fabric'        => 'CommentOutput'},    {'display ftm topology-database'    => 'CommentOutput'},    {'display fan'            => 'CommentOutput'},    {'display power'            => 'CommentOutput'},    {'display poe powersupply'        => 'CommentOutput'},    {'display poe temperature-protection'    => 'CommentOutput'},    {'display cluster'            => 'CommentOutput'},    {'display domain'            => 'CommentOutput'},    {'display local-user'        => 'CommentOutput'},    {'display password-control'        => 'CommentOutput'},    {'display password-control super'    => 'CommentOutput'},    {'display ssh server status'    => 'CommentOutput'},    {'display fib'            => 'DisplayFib'},    {'display vlan all'            => 'CommentOutput'},    {'display ip routing-table'        => 'CommentOutput'},    {'display lacp sys'            => 'CommentOutput'},    {'display link-aggregation summary'    => 'CommentOutput'},    {'display link-aggregation verbose'    => 'CommentOutput'},    {'display mirror all'        => 'CommentOutput'},    {'display current-configuration'    => 'DisplayCurrent'},);# 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);$device_cmds=join(";",@commands);$cmds_regexp=join("|",@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 debuggingif ($debug) { $| = 1; }if ($file) {    print STDERR "opening file $host\n" if ($debug);    print STDOUT "opening file $host\n" if ($log);    open(INPUT,"} else {    print STDERR "executing $logincmd -t $timeo -c\"$device_cmds\" $host\n" if ($debug);    print STDOUT "executing $logincmd -t $timeo -c\"$device_cmds\" $host\n" if ($log);    if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {#    system "$logincmd -noenable -t $timeo -c \"$device_cmds\" $host $host.raw 2>&1" || die "$logincmd failed for $host: $!\n";# system "$logincmd -t $timeo -c \"$device_cmds\" $host $host.raw 2>&1" || die "$logincmd failed for $host: $!\n";    system "$logincmd -t $timeo -c \"$device_cmds\" $host $host.raw 2>&1" || die "$logincmd failed for $host: $!\n";    open(INPUT, "    } else {#    open(INPUT,"$logincmd -noenable -t $timeo -c \"$device_cmds\" $host    open(INPUT,"$logincmd -t $timeo -c \"$device_cmds\" $host    }}# determine ACL sorting modeif ($ENV{"ACLSORT"} =~ /no/i) {    $aclsort = "";}# determine community string filtering modeif (defined($ENV{"NOCOMMSTR"}) &&    ($ENV{"NOCOMMSTR"} =~ /yes/i || $ENV{"NOCOMMSTR"} =~ /^$/)) {    $filter_commstr = 1;} else {    $filter_commstr = 0;}# determine password filtering modeif ($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: h3c\n!\n");#ProcessHistory("COMMENTS","keysort","B0","!\n");#ProcessHistory("COMMENTS","keysort","D0","!\n");#ProcessHistory("COMMENTS","keysort","F0","!\n");#ProcessHistory("COMMENTS","keysort","G0","!\n");TOP: while() {    tr/\015//d;# h3c:# Look for the command at the end of the output# if (/\#exit$/) {# if (/\#quit$/) {# h3c:     if (/[\]>]\a?\s*quit/) {# if (/^[\[]\a?\s?quit/) {      $clean_run=1;      last;    }    if (/^Error:/) {    print STDOUT ("$host $logincmd error: $_");    print STDERR ("$host $logincmd error: $_") if ($debug);    $clean_run=0;    last;    }# while (/#\s*($cmds_regexp)\s*$/) {# h3c:    while (/[\]>]\a?\s*($cmds_regexp)\s*$/) {# while (/^[\[]\a?\s*($cmds_regexp)\s*$/) {    $cmd = $1;    if (!defined($prompt)) {    # h3c:    # Extract the prompt: look for something not [ or    # of the line, until either ] or > is reached:        #$prompt = ($_ =~ /^([^#]+#)/)[0];        #$prompt =~ s/([][}{)(\\])/\\$1/g;        #$prompt = ($_ =~ /^([^\]>]+[\]>]\007?)/)[0];        $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}};    delete($commands{$cmd});    if ($rval == -1) {        $clean_run = 0;        last TOP;    }    }}print STDOUT "Done $logincmd: $_\n" if ($log);# Flush HistoryProcessHistory("","","","");# Cleanupclose(INPUT);close(OUTPUT);if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {    unlink("$host.raw") if (! $debug);}printf(STDOUT "$host: clean_run=$clean_run found_end=$found_end\n") if ($debug);# check for completenessif (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(',h3clogin点击(此处)折叠或打开#! /usr/local/bin/expect --#### $Id: $#### @PACKAGE@ @VERSION@## Copyright (c) 1997-2009 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.## h3clogin - H3C login## h3clogin covers the following product ranges:## * 3Com SuperStack 4 (post-joint venture with Huawei)# * H3C# * HP Networking ('A' & some 'E' portfolio, post 2010 3Com acquitision)## It may also work with some Huawei equipment.## Set to 1 to enable some debugging, or pass "-d" on command lineexp_internal 0# Usage lineset 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 fileset password_file $env(HOME)/.cloginrc# Default is to login to the routerset do_command 0set do_script 0# The default is to automatically enableset 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 1set do_enapasswd 1set do_saveconfig 0# Sometimes routers take awhile to answer (the default is 10 sec)set timeoutdflt 45#set send_human {.1 .3 .7 .05 2}# H3C: some models don't like "3des"; specify "aes128-cbc" in .cloginrcset default_cyphertype "3des"# H3C: command to elevate priviges (aka "enable") is differentset enacmd "super"# H3C: command to exit from deviceset exitcmd "quit"# 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 linefor {set i 0} {$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 "@PACKAGE@ @VERSION@\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 $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 caresproc 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-pieproc 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 scriptproc 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 successfullyproc login { router user userpswd passwd enapasswd cmethod cyphertype identfile } {    global 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 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 match "ssh*" $prog] {     # ssh to the router & try to login with or without an identfile.     regexp {ssh(:([^[:space:]]+))*} $prog command suffix port     set cmd [join [lindex $sshcmd 0] " "]     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: $sshcmd 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;     }     set commands [split $command \;]     set num_commands [llength $commands]     set rshfail 0     for {set i 0} {$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 {     puts "\nError: unknown connection method: $prog"     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"; wait; return 1     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 "Offending key for .* \(yes\/no\)\?" {     send "no\r"     send_user "\nError: host key mismatch for $router. Update the SSH known_hosts file accordingly.\n"     catch {close}; catch {wait};     return 1    }    -re "(denied|Sorry)"    {                 send_user "\nError: Check your passwd for $router\n"                 catch {close}; catch {wait}; return 1                }    "Login failed"        {                 send_user "\nError: Check your passwd for $router\n"                 catch {close}; catch {wait}; return 1                }    -re "% (Bad passwords|Authentication failed)"    {                 send_user "\nError: Check your passwd for $router\n"                 catch {close}; catch {wait}; return 1                }    "Press any key to continue." {                 # send_user "Pressing the ANY key\n"                 send "\r"                 exp_continue                }    -re "Enter Selection: " {                 # Catalyst 1900s have some lame menu. Enter                 # K to reach a command-line.                 send "K\r"                 exp_continue;                }    -re "Last login:"    {                 exp_continue;                }    -re "@\[^\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                }     }    }    set in_proc 0    return 0}# Enableproc do_enable { enauser enapasswd } {    global prompt in_proc    global prompt u_prompt e_prompt    global enacmd    set in_proc 1    send -h "$enacmd\r"    expect {    -re "$u_prompt"    { send -h -- "$enauser\r"; exp_continue}    -re "$e_prompt"    { send -h -- "$enapasswd\r"; exp_continue}    -re ">"        { set prompt ">" }    "% Password is not set." {             send_user "\nError: No 'super' password set for device\n"             return 1            }    "% Authenticate failed." {             send_user "\nError: Check your enable password for 'super'\n"             return 1            }#    "#"        { 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 do_saveconfig in_proc platform    global exitcmd    set in_proc 1    # clogin has this beast:    #regsub -all {^(.{1,11}).*([#>])$} $prompt {\1([^#>\r\n]+)?[#>](\\([^)\\r\\n]+\\))?} reprompt    # escape any parens in the prompt, such as "(enable)"    regsub -all {[][)(]} $prompt {\\&} reprompt    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    set commands [split $command \;]    set num_commands [llength $commands]    # The pager can not be turned off on some 3Com/H3C, so we have to look    # for the "More" prompt.    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 "^ ---- More ----.*\[^\n\r]*"    {                         # H3C pager prompt                         sleep 0.1                         send " "                         exp_continue }     }    }    log_user 1    send -h "$exitcmd\r"    # H3C: the exit command leaves the switch completely; it does not    # prompt to save if the config has been modified    expect {#    -re "^\[^\n\r *]*$reprompt"        {#                         # H3C products#                         # return to non-enabled mode#                         # on exit in enabled mode.#                         send -h "$exitcmd\r"#                         exp_continue;#                        }# TODO: we will need to do this too:#    "Do you wish to save your configuration changes" {#                         send -h "n\r"#                         exp_continue#                        }    -re "\[\n\r]+"                { exp_continue }# hwlogin+mod:    -re "\[^\n\r *]Note:"            { return 0 }    timeout                    { catch {close}; catch {wait};                         return 0                        }    eof                    { return 0 }    }    set in_proc 0}## For each router... (this is main loop)#source_password_file $password_fileset in_proc 0set exitval 0set prompt_match ""set enable 0foreach 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 "(>|#| \\(enable\\))"    set prompt ">\a?"    # look for noenable option in .cloginrc    if { [find noenable $router] == "1" } {    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] ""]    } 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 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] ""]    }    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 "$default_cyphertype" }    }    # Figure out connection method    set cmethod [find method $router]    if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} }    # Figure out the SSH executable name    set sshcmd [find sshcmd $router]    if { "$sshcmd" == "" } { set sshcmd {ssh} }    # Login to the router    if {[login $router $ruser $userpswd $passwd $enapasswd $cmethod $cyphertype $identfile]} {    incr exitval    # if login failed or rsh was unsuccessful, move on to the next device    continue    }    # Figure out the prompt.# H3C: this is what we used to have, now should be obsolete:# # 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## hwlogin:#    #set prompt "(#| \\(enable\\))"#    set prompt ">\a?"# } else {#    set ae [find autoenable $router]#    if { "$ae" == "1" } {#     set autoenable 1#     set enable 0## hwlogin:#     set prompt ">\a?"#    } else {#     set autoenable 0#     set enable $avenable#     set prompt ">\a?"#    }# }## # look for noenable option in .cloginrc# if { [find noenable $router] == "1" } {#    set enable 0# }## clogin has:## # look for noenable option in .cloginrc## if | [find noenable $router] != "" | {##    set enable 0## }    # !! H3C does not appear to have a different prompt between lower    # privilege and higher privilege users, so the following test is    # not applicable# if { [regexp -- "(#| \\(enable\\))" $prompt_match junk] == 1 } {#    set enable 0# } else {    if { $avenable == 0 } {     set enable 0    } else {     set ne [find noenable $router]     set ae [find autoenable $router]     if { "$ne" == "1" || "$ae" == "1" || $avautoenable } {        set enable 0     } else {        set enable 1     }    }# }    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"    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#                 regsub -all "\[\]\[\(\)]" $junk {\\&} 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;                }    }    # H3C: Disable log junk being sent to terminal: must be done before    # $enacmd is run. It would be nice for this to be setable in .cloginrc    send -h "undo terminal monitor\r"    expect -re $prompt {}    # Turn session paging off    # Comware 5 only.    # Comware 3 models have a screen-length command that only works on    # a vty basis    # clogin does this only within the do_script clause below, but I can't    # see why you wouldn
12-23 23:53