View | Details | Raw Unified | Return to bug 209361
Collapse All | Expand All

(-)Makefile (-1 / +7 lines)
Lines 3-9 Link Here
3
3
4
PORTNAME=	rancid
4
PORTNAME=	rancid
5
PORTVERSION=	3.4.1
5
PORTVERSION=	3.4.1
6
PORTREVISION=	1
6
PORTREVISION=	2
7
CATEGORIES=	net-mgmt
7
CATEGORIES=	net-mgmt
8
MASTER_SITES=	ftp://ftp.shrubbery.net/pub/rancid/
8
MASTER_SITES=	ftp://ftp.shrubbery.net/pub/rancid/
9
PKGNAMESUFFIX=	3
9
PKGNAMESUFFIX=	3
Lines 59-66 Link Here
59
post-patch:
59
post-patch:
60
	${REINPLACE_CMD} "s|par.1|rancid-par.1|" ${WRKSRC}/man/Makefile.in
60
	${REINPLACE_CMD} "s|par.1|rancid-par.1|" ${WRKSRC}/man/Makefile.in
61
	${MV} ${WRKSRC}/man/par.1 ${WRKSRC}/man/rancid-par.1
61
	${MV} ${WRKSRC}/man/par.1 ${WRKSRC}/man/rancid-par.1
62
	${CAT} ${FILESDIR}/comware7_types.conf >> ${WRKSRC}/etc/rancid.types.base
62
63
63
post-install:
64
post-install:
65
# Comware7 support
66
# https://sites.google.com/site/jrbinks/code/rancid/cmwrancid
67
	${INSTALL_DATA} ${FILESDIR}/cmw.pm ${STAGEDIR}/${PREFIX}/lib/rancid
68
	${INSTALL_SCRIPT} ${FILESDIR}/cmwlogin ${STAGEDIR}/${PREFIX}/libexec/rancid
69
	
64
	${LN} -s ${PREFIX}/libexec/${PORTNAME}/rancid-cvs ${STAGEDIR}${PREFIX}/bin
70
	${LN} -s ${PREFIX}/libexec/${PORTNAME}/rancid-cvs ${STAGEDIR}${PREFIX}/bin
65
	${LN} -s ${PREFIX}/libexec/${PORTNAME}/rancid-run ${STAGEDIR}${PREFIX}/bin
71
	${LN} -s ${PREFIX}/libexec/${PORTNAME}/rancid-run ${STAGEDIR}${PREFIX}/bin
66
.for file in ${NEWCONFIG_FILES}
72
.for file in ${NEWCONFIG_FILES}
(-)files/cmw.pm (+522 lines)
Line 0 Link Here
1
package cmw;
2
##
3
## $Id: cmw.pm.in 3000 2015-01-06 18:47:49Z heas $
4
##
5
## rancid 3.1.99
6
## Copyright (c) 1997-2015 by Terrapin Communications, Inc.
7
## All rights reserved.
8
##
9
## This code is derived from software contributed to and maintained by
10
## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan,
11
## Pete Whiting, Austin Schutz, and Andrew Fort.
12
##
13
## Redistribution and use in source and binary forms, with or without
14
## modification, are permitted provided that the following conditions
15
## are met:
16
## 1. Redistributions of source code must retain the above copyright
17
##    notice, this list of conditions and the following disclaimer.
18
## 2. Redistributions in binary form must reproduce the above copyright
19
##    notice, this list of conditions and the following disclaimer in the
20
##    documentation and/or other materials provided with the distribution.
21
## 3. All advertising materials mentioning features or use of this software
22
##    must display the following acknowledgement:
23
##        This product includes software developed by Terrapin Communications,
24
##        Inc. and its contributors for RANCID.
25
## 4. Neither the name of Terrapin Communications, Inc. nor the names of its
26
##    contributors may be used to endorse or promote products derived from
27
##    this software without specific prior written permission.
28
## 5. It is requested that non-binding fixes and modifications be contributed
29
##    back to Terrapin Communications, Inc.
30
##
31
## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS
32
## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
33
## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
34
## PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
35
## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
36
## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37
## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38
## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
39
## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40
## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41
## POSSIBILITY OF SUCH DAMAGE.
42
#
43
#  RANCID - Really Awesome New Cisco confIg Differ
44
#
45
#  cmw.pm - Comware (Huawei/H3C/3com/HP) rancid procedures
46
#
47
# https://sites.google.com/site/jrbinks/code/rancid/cmwrancid
48
49
use 5.010;
50
use strict 'vars';
51
use warnings;
52
no warnings 'uninitialized';
53
require(Exporter);
54
our @ISA = qw(Exporter);
55
56
use rancid;
57
58
our $login;
59
60
@ISA = qw(Exporter rancid main);
61
#XXX @Exporter::EXPORT = qw($VERSION @commandtable %commands @commands);
62
63
# XXX
64
#our @EXPORT = qw(iproutesort iprouteval);
65
66
# load-time initialization
67
sub import {
68
    0;
69
}
70
71
# post-open(collection file) initialization
72
sub init {
73
    $login = "cmwlogin";
74
    # add content lines and separators
75
    ProcessHistory("","","","!RANCID-CONTENT-TYPE: $devtype\n!\n");
76
77
    0;
78
}
79
80
# main loop of input of device output
81
sub inloop {
82
    my($INPUT, $OUTPUT) = @_;
83
    my($cmd, $rval);
84
85
TOP: while(<$INPUT>) {
86
	tr/\015//d;
87
        if (/[\]>#]\a?\s*quit/) {
88
	#if (/[>#]\s?exit$/) {
89
	    $clean_run = 1;
90
	    last;
91
	}
92
	if (/^Error:/) {
93
	    print STDOUT ("$host $login error: $_");
94
	    print STDERR ("$host $login error: $_") if ($debug);
95
	    $clean_run = 0;
96
	    last;
97
	}
98
        while (/[\]>#]\a?\s*($cmds_regexp)\s*$/) {
99
	    $cmd = $1;
100
101
	    if (!defined($prompt)) {
102
		# Extract the prompt: look for something not [ or < at the start
103
		# of the line, until either ] or > or # is reached:
104
		$prompt = ($_ =~ /^([^\]>#]+[\]>]\a?)/)[0]; 
105
		$prompt =~ s/([][}{)(\\])/\\$1/g;
106
		print STDERR ("PROMPT MATCH: $prompt\n") if ($debug);
107
	    }
108
	    print STDERR ("HIT COMMAND:$_") if ($debug);
109
	    if (! defined($commands{$cmd})) {
110
		print STDERR "$host: found unexpected command - \"$cmd\"\n";
111
		$clean_run = 0;
112
		last TOP;
113
	    }
114
	    $rval = &{$commands{$cmd}}($INPUT, $OUTPUT, $cmd);
115
	    delete($commands{$cmd});
116
	    if ($rval == -1) {
117
		$clean_run = 0;
118
		last TOP;
119
	    }
120
	}
121
    }
122
}
123
124
# dummy function
125
sub DoNothing {print STDOUT;}
126
127
# This is a sort routine that will sort on the
128
# ip route when the ip route is anywhere in
129
# the strings.
130
sub iproutesort {
131
    my(%lines) = @_;
132
    my($i) = 0;
133
    my(@sorted_lines);
134
    foreach my $iproute (sort sortbyiproute keys %lines) {
135
	$sorted_lines[$i] = $lines{$iproute};
136
	$i++;
137
    }
138
    @sorted_lines;
139
}
140
141
## XXX Re-evaluate based on new routines, and consider IPv6:
142
# These two routines will sort based upon IP route
143
sub iprouteval {
144
    my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)/(\d+)$#);
145
    $a[4] + ($a[3] + 256 * ($a[2] + 256 * ($a[1] + 256 * $a[0])));
146
}
147
148
sub sortbyiproute {
149
    &iprouteval($a) <=> &iprouteval($b);
150
}
151
152
# Clean up lines on input, particularly ANSI characters as a result
153
# of us not being able to turn off per-session terminal paging
154
sub filter_lines {
155
    my ($l) = (@_);
156
157
    #s/^\033\[42D +\033\[42D(.+)$/$1/;
158
    #s/\033\133\064\062\104\s*\033\133\064\062\104//g;
159
    $l =~ s/\033\133\064\062\104\s+\033\133\064\062\104//g;
160
    $l =~ s/\033\133\061\066\104\s+\033\133\061\066\104//g;
161
    $l =~ s/\033\133\064\062\104//g;
162
    $l =~ s/\033\133\061\062\104//g;
163
    $l =~ s/.*\[37D(.*)/$1/g;    # MA5600
164
    # Probably not needed:
165
    $l =~ s/\s*---- More ----\s*//;
166
    $l =~ s/^               //; # Comware7
167
    $l =~ s/Synchronization is finished.//g;
168
    return $l;
169
}
170
171
# Some commands are not supported on some models or versions
172
# of code.
173
# Remove the associated error messages, and rancid will ensure that
174
# these are not treated as "missed" commands
175
sub command_not_valid {
176
    my ($l) = (@_);
177
178
    if ( $l =~
179
	/% Too many parameters found at '\^' position/ ||
180
	/% Unrecognized command found at '\^' position/ ||
181
	/% Incomplete command found at '\^' position./ ||
182
	/(% )?Wrong parameter found at '\^' position/ ||
183
	/% Wrong device .+/
184
    ) {
185
	return(1);
186
    } else {
187
	return(0);
188
    }
189
}
190
191
# Some commands are not authorized under the current
192
# user's permissions
193
sub command_not_auth {
194
    my ($l) = (@_);
195
196
    if ( $l =~
197
	/Permission denied\./
198
    ) {
199
	return(1);
200
    } else {
201
	return(0);
202
    }
203
}
204
205
# Some output lines are always skipped
206
sub skip_pattern {
207
    my ($l) = (@_);
208
209
    if ( $l =~
210
	/^\s+\^$/ ||
211
        /^$/
212
    ) {
213
	return(1);
214
    } else {
215
	return(0);
216
    }
217
}
218
219
sub DisplayFib {
220
221
    my($INPUT, $OUTPUT, $cmd) = @_;
222
    my($dest, $nexthop, $flag, $outint, $label);
223
    print STDERR "    In DisplayFib: $_" if ($debug);
224
225
    chomp;
226
227
    # Display the command we're processing in the output:
228
    ProcessHistory("FIB","","","!\n! '$cmd':\n!\n");
229
230
    while (<$INPUT>) {
231
        tr/\015//d;
232
        last if(/^\s*$prompt/);
233
        chomp;
234
        $_ = filter_lines($_);
235
236
	return(1) if command_not_valid($_);
237
	return(-1) if command_not_auth($_);
238
	next if skip_pattern($_);
239
240
        next if /^Destination count: \d+ FIB entry count: \d+/;
241
242
        # Chop out some detail that changes over time (Comware 3):
243
        s/(\s+)TimeStamp\s+/$1/;        # TimeStamp column heading
244
245
        ProcessHistory("FIB","","","! $_\n");
246
247
        if ( m,Destination/Mask, ) {
248
            while (<$INPUT>) {
249
                tr/\015//d;
250
                last if(/^\s*$prompt/);
251
                chomp;
252
                $_ = filter_lines($_);
253
254
                # Chop out some detail that changes over time (Comware 3):
255
                s/(\s+)t\[\d+\]\s+/$1/;    # TimeStamp data
256
257
                # "display fib" on comware7 shows host entries for things
258
                # learned via arp too.  For a distribution router, that's all
259
                # the devices on subnets routed by it!
260
                # If we filter out all "UH" entries that are NOT InLoop, we
261
                # get acceptable output.
262
                #
263
                # So we want to keep:
264
                #
265
                # 0.0.0.0/32         127.0.0.1       UH  InLoop0 Null
266
                #
267
                # but reject:
268
                #
269
                # 130.159.44.161/32  130.159.44.161  UH  Vlan44  Null
270
                #
271
                # However I've a feeling that this is a problematic
272
                # solution, and some object to the notion that rancid
273
                # should be representing such potentially dynamic data in
274
                # the first place, which is why we created the
275
                # $display_fib flag for rancid 2, and in rancid 3 one
276
		# can modify the command table in rancid.types.conf
277
278
		($dest, $nexthop, $flag, $outint, $label) = split;
279
                next if ( $flag eq 'UH' && $outint !~ /InLoop/ );
280
                #ProcessHistory("FIB", "cmw::iproutesort", "$dest", "! $_\n");
281
                ProcessHistory("FIB", "ipsort", "$dest", "! $_\n");
282
            }
283
284
            ProcessHistory("FIB", "", "", "!\n");
285
286
            # return here to ensure that we don't keep swallowing the
287
            # next command's output by returning to the surrounding
288
            # while loop
289
            return(0);
290
        }
291
    }
292
    return(0);
293
}
294
295
sub DisplayIPRoutes {
296
    my($INPUT, $OUTPUT, $cmd) = @_;
297
    my($key,$line,$spaces);
298
    print STDERR "    In DisplayIPRoutes: $_" if ($debug);
299
300
    chomp;
301
302
    # Display the command we're processing in the output:
303
    ProcessHistory("IPR","","","!\n! '$cmd':\n!\n");
304
305
    while (<$INPUT>) {
306
        tr/\015//d;
307
        last if(/^\s*$prompt/);
308
        chomp;
309
310
        $_ = filter_lines($_);
311
	return(1) if command_not_valid($_);
312
	return(-1) if command_not_auth($_);
313
	next if skip_pattern($_);
314
315
        ProcessHistory("IPR","","","! $_\n");
316
317
        if ( m,Destination/Mask, ) {
318
            my $lastkey = "";
319
            my $lastspaces = "";
320
            while (<$INPUT>) {
321
                tr/\015//d;
322
                last if(/^\s*$prompt/);
323
                chomp;
324
                $_ = filter_lines($_);
325
326
                # If the key is blank, indicating multiple nexthops for
327
                # a particular route, then we use the previous one
328
                if ( m/^\s+(.+)/ ) {
329
                    $key = $lastkey;
330
                    $line = $key . $lastspaces . $1;
331
                    #ProcessHistory("IPR", "cmw::iproutesort", "$key", "! $line\n");
332
                    ProcessHistory("IPR", "ipsort", "$key", "! $line\n");
333
                }
334
                if ( m/^(\S+)(\s+).+/ ) {
335
                    $key = $1;
336
                    $line = $_;
337
                    $spaces = $2;
338
                    #ProcessHistory("IPR", "cmw::iproutesort", "$key", "! $line\n");
339
                    ProcessHistory("IPR", "ipsort", "$key", "! $line\n");
340
341
		    # Remember these, we may need them on the next pass
342
                    $lastkey = $key;
343
                    $lastspaces = $spaces;
344
                }
345
            }
346
347
            ProcessHistory("IPR", "", "", "!\n");
348
349
            # return here to ensure that we don't keep swallowing the
350
            # next command's output by returning to the surrounding
351
            # while loop
352
            return(0);
353
        }
354
    }
355
    return(0);
356
}
357
358
## This routine processes general output of "display" commands
359
sub CommentOutput {
360
    my($INPUT, $OUTPUT, $cmd) = @_;
361
    print STDERR "    In CommentOutput: $_" if ($debug);
362
363
    chomp;
364
365
    # Display the command we're processing in the output:
366
    ProcessHistory("COMMENTS", "", "", "!\n! '$cmd':\n!\n");
367
368
    while (<$INPUT>) {
369
        tr/\015//d;
370
371
        # If we find the prompt, we're done
372
        # Ordinarily this matches from the start of the line, however
373
        # we've seen circumstances at least in Comware7 where the
374
        # prompt is preceded by whitespace, like so:
375
        # ^M^M               ^M<router>display boot-loader^M
376
        last if(/^\s*$prompt/);
377
        chomp;
378
379
	# filter out some junk
380
        $_ = filter_lines($_);
381
	return(1) if command_not_valid($_);
382
	return(-1) if command_not_auth($_);
383
	next if skip_pattern($_);
384
385
	# Now we skip or modify some lines from various commands to
386
        # remove irrelevant content, or to avoid insignificant diffs
387
388
        # 'display local-user':
389
        s/\s+Current AccessNum:.+$//;
390
391
        # 'display version':
392
        next if (/^(Uptime is \d|.+ [Uu]ptime is \d).+$/);
393
        # No longer necessary since skipping the whole Uptime line:
394
        # Mangle these lines:
395
        #s/(.*)[Uu]ptime.*.weeks.*.days*.*hours*.*minutes*(.*)/$1 $2/;
396
        #s/(.*)[Uu]ptime.*days*.*hours*.*minutes*(.*)/$1 $2/;
397
398
        # MSRs display a 'last reboot' time, but sometimes the seconds
399
        # vary by one or two (presumably internal rounding), so simply make
400
        # the last digit a fixed '0'.  It would probably be safer to make
401
        # the last two digits a fixed '00'.
402
        # (Thx Alexander Belokopytov)
403
        s/(^Last reboot.+)\d$/${1}0/;
404
405
        # 'dir ' commands
406
        if ( $cmd =~ /^dir / ) {
407
            # First field is just an index number, chop it out
408
            s/^\s+\d+\s+(.+)/ $1/;
409
            # Remove filenames that are updated frequently
410
            next if (
411
                /logfile\.log$/ ||
412
                /lauth\.dat$/ ||
413
                /ifindex\.dat$/ ||
414
                /startup\.mdb$/ ||
415
                /private-data\.txt$/ ||
416
                /.+ KB total \(.+ KB free/ ||
417
                /.+ KB total \(.+ KB free/ ||
418
                /\.trash/
419
            );
420
        }
421
422
	# 'display ospf brief'/'display ospf'
423
        if ( $cmd =~ 'display ospf( brief)?' ) {
424
            #next if (/^(Ospf is not enabled yet|Info: OSPF routing process is not enabled|The feature OSPF has not been enabled.).+$/);
425
            next if (/^\s+SPF (Computation|Scheduled|calculation) Count:.+$/i);
426
        }
427
428
        if ( $cmd eq 'display power' ) {
429
            next if (/^(\s+Input Power).+$/);
430
        }
431
432
        if ( $cmd eq 'display poe powersupply' ) {
433
            next if (/^(PSE Total Power Consumption|PSE Available Power|PSE Peak Value|PSE Average Value).+$/);
434
        }
435
436
        if ( $cmd eq 'display ntp-service status' ) {
437
            next unless m/(Clock status|Clock stratum|Reference clock ID)/i;
438
        }
439
440
        if ( $cmd eq 'display transceiver interface' ) {
441
            s/^(\S+ transceiver information:).+$/$1/;   # filter random garbage
442
            s/^Error: The transceiver is absent.$/  No transceiver present./;
443
            s/^Error: The combo port is inactive.$/  Inactive combo port./;
444
        }
445
446
        # Add the processed lines to the output buffer:
447
        ProcessHistory("COMMENTS","","","! $_\n");
448
    }
449
450
    # Add a blank comment line to the output buffer
451
    ProcessHistory("COMMENTS", "", "", "!\n");
452
    return(0);
453
}
454
455
## This routine processes a "display current"
456
sub DisplayCurrent {
457
    my($INPUT, $OUTPUT, $cmd) = @_;
458
    print STDERR "    In DisplayCurrent: $_" if ($debug);
459
460
461
    while (<$INPUT>) {
462
        tr/\015//d;
463
        last if(/^\s*$prompt/);
464
        chomp;
465
466
        $_ = filter_lines($_);
467
	return(1) if command_not_valid($_);
468
	return(-1) if command_not_auth($_);
469
	next if skip_pattern($_);
470
471
        return(0) if ($found_end);
472
473
        # Filter out some sensitive data:
474
        if ( $filter_commstr &&
475
             /^ ?(snmp-agent (target-host.+securityname|usm-user|community (read|write)) )(\S+)/
476
           ) {
477
            ProcessHistory("","","","! $1<removed>$'\n");
478
            next;
479
        }
480
        if ( $filter_pwds >= 1 &&
481
            /^ ?(password (?:simple|cipher|hash) )(\S+)/ ||
482
            /^ ?(super password( role level-\d)( level \d)? (cipher|simple|hash) )(\S+)/ ||
483
            /^ ?(set authentication password (cipher|simple|hash) )(\S+)/ ||
484
            /^ ?(key (?:authentication|accounting) )(\S+)/ 
485
           ) {
486
            ProcessHistory("","","","! $1<removed>$'\n");
487
            next;
488
        }
489
490
        # filter ssh public keys of devices connected to from this device
491
        if (/^ ?(public-key-code begin)/ &&
492
                $filter_pwds >= 2) {
493
            ProcessHistory("","","","!$1\n");
494
            ProcessHistory("","","","! <removed>\n");
495
            while (<$INPUT>) {
496
                tr/\015//d;
497
                next if /^$/;
498
		next if /^\s+[[:xdigit:]]$/;
499
                if (/(^ public-key-code end)/) {
500
                    ProcessHistory("","","","!$1\n");
501
                    last;
502
                }
503
            }
504
        next;
505
        }
506
507
	# Filter mac addresses dynamically added to config
508
	next if (/^ ?mac-address security.+$/);
509
510
        ProcessHistory("", "", "", "$_\n");
511
512
        # end of config
513
        if (/^return/) {
514
            $found_end = 1;
515
            return(0);
516
        }
517
    }
518
    return(0);
519
}
520
521
1;
522
(-)files/cmwlogin (+1043 lines)
Line 0 Link Here
1
#! /usr/local/bin/expect --
2
##
3
## $Id: cmwlogin 3022 2015-01-13 20:00:00Z heas $
4
##
5
## rancid 3.4.1
6
## Copyright (c) 1997-2015 by Terrapin Communications, Inc.
7
## All rights reserved.
8
##
9
## This code is derived from software contributed to and maintained by
10
## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan,
11
## Pete Whiting, Austin Schutz, and Andrew Fort.
12
##
13
## Redistribution and use in source and binary forms, with or without
14
## modification, are permitted provided that the following conditions
15
## are met:
16
## 1. Redistributions of source code must retain the above copyright
17
##    notice, this list of conditions and the following disclaimer.
18
## 2. Redistributions in binary form must reproduce the above copyright
19
##    notice, this list of conditions and the following disclaimer in the
20
##    documentation and/or other materials provided with the distribution.
21
## 3. All advertising materials mentioning features or use of this software
22
##    must display the following acknowledgement:
23
##        This product includes software developed by Terrapin Communications,
24
##        Inc. and its contributors for RANCID.
25
## 4. Neither the name of Terrapin Communications, Inc. nor the names of its
26
##    contributors may be used to endorse or promote products derived from
27
##    this software without specific prior written permission.
28
## 5. It is requested that non-binding fixes and modifications be contributed
29
##    back to Terrapin Communications, Inc.
30
##
31
## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS
32
## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
33
## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
34
## PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
35
## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
36
## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37
## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38
## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
39
## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40
## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41
## POSSIBILITY OF SUCH DAMAGE.
42
#
43
#  The expect login scripts were based on Erik Sherk's gwtn, by permission.
44
#
45
# cwlogin - Comware login
46
#
47
# Most options are intuitive for logging into a Comware device.
48
# The default is to enable (thus -noenable).  Some folks have
49
# setup tacacs to have a user login at priv-lvl = 3 (enabled)
50
# so the -autoenable flag was added for this case (don't go through
51
# the process of enabling and the prompt will be the "#" prompt.
52
# The default username password is the same as the vty password.
53
#
54
55
# Usage line
56
set usage "Usage: $argv0 \[-dSV\] \[-autoenable\] \[-noenable\] \[-c command\] \
57
\[-Evar=x\] \[-e enable-password\] \[-f cloginrc-file\] \[-p user-password\] \
58
\[-r passphrase\] \[-s script-file\] \[-t timeout\] \[-u username\] \
59
\[-v vty-password\] \[-w enable-username\] \[-x command-file\] \[-P platform\] \
60
\[-y ssh_cypher_type\] router \[router...\]\n"
61
62
# env(CLOGIN) may contain:
63
#	x == do not set xterm banner or name
64
65
# Password file
66
set password_file $env(HOME)/.cloginrc
67
# Default is to login to the router
68
set do_command 0
69
set do_script 0
70
# The default is to automatically enable
71
set avenable 1
72
# The default is that you login non-enabled (tacacs can have you login already
73
# enabled)
74
set avautoenable 0
75
# The default is to look in the password file to find the passwords.  This
76
# tracks if we receive them on the command line.
77
set do_passwd 1
78
set do_enapasswd 1
79
# Save config, if prompted
80
set do_saveconfig 0
81
# Sometimes routers take awhile to answer (the default is 10 sec)
82
set timeoutdflt 45
83
# Some CLIs having problems if we write too fast (Extreme, PIX, Cat)
84
set send_human {.2 .1 .4 .2 1}
85
86
# Find the user in the ENV, or use the unix userid.
87
if {[info exists env(CISCO_USER)]} {
88
    set default_user $env(CISCO_USER)
89
} elseif {[info exists env(USER)]} {
90
    set default_user $env(USER)
91
} elseif {[info exists env(LOGNAME)]} {
92
    set default_user $env(LOGNAME)
93
} else {
94
    # This uses "id" which I think is portable.  At least it has existed
95
    # (without options) on all machines/OSes I've been on recently -
96
    # unlike whoami or id -nu.
97
    if [catch {exec id} reason] {
98
	send_error "\nError: could not exec id: $reason\n"
99
	exit 1
100
    }
101
    regexp {\(([^)]*)} "$reason" junk default_user
102
}
103
if {[info exists env(CLOGINRC)]} {
104
    set password_file $env(CLOGINRC)
105
}
106
107
# Process the command line
108
for {set i 0} {$i < $argc} {incr i} {
109
    set arg [lindex $argv $i]
110
111
    switch  -glob -- $arg {
112
	# Expect debug mode
113
	-d* {
114
	    exp_internal 1
115
	# Username
116
	} -u* {
117
	    if {! [regexp .\[uU\](.+) $arg ignore user]} {
118
		incr i
119
		set username [lindex $argv $i]
120
	    }
121
	# VTY Password
122
	} -p* {
123
	    if {! [regexp .\[pP\](.+) $arg ignore userpasswd]} {
124
		incr i
125
		set userpasswd [lindex $argv $i]
126
	    }
127
	    set do_passwd 0
128
	# ssh passphrase
129
	} -r* {
130
	    if {! [regexp .\[rR\](.+) $arg ignore passphrase]} {
131
		incr i
132
		set vapassphrase [lindex $argv $i]
133
	    }
134
	# VTY Password
135
	} -v* {
136
	    if {! [regexp .\[vV\](.+) $arg ignore passwd]} {
137
		incr i
138
		set passwd [lindex $argv $i]
139
	    }
140
	    set do_passwd 0
141
	# Version string
142
	} -V* {
143
	    send_user "rancid 3.4.1\n"
144
	    exit 0
145
	# Enable Username
146
	} -w* {
147
	    if {! [regexp .\[wW\](.+) $arg ignore enauser]} {
148
		incr i
149
		set enausername [lindex $argv $i]
150
	    }
151
	# Environment variable to pass to -s scripts
152
	} -E* {
153
	    if {[regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} {
154
		set E$varname $varvalue
155
	    } else {
156
		send_user "\nError: invalid format for -E in $arg\n"
157
		exit 1
158
	    }
159
	# Enable Password
160
	} -e* {
161
	    if {! [regexp .\[e\](.+) $arg ignore enapasswd]} {
162
		incr i
163
		set enapasswd [lindex $argv $i]
164
	    }
165
	    set do_enapasswd 0
166
	# Platform
167
	} -P* {
168
	    if {! [regexp .\[P\](.+) $arg ignore platform]} {
169
		incr i
170
		set plat [lindex $argv $P]
171
	    }
172
	# Command to run.
173
	} -c* {
174
	    if {! [regexp .\[cC\](.+) $arg ignore command]} {
175
		incr i
176
		set command [lindex $argv $i]
177
	    }
178
	    set do_command 1
179
	# Expect script to run.
180
	} -s* {
181
	    if {! [regexp .\[sS\](.+) $arg ignore sfile]} {
182
		incr i
183
		set sfile [lindex $argv $i]
184
	    }
185
	    if { ! [file readable $sfile] } {
186
		send_user "\nError: Can't read $sfile\n"
187
		exit 1
188
	    }
189
	    set do_script 1
190
	# save config on exit
191
	} -S* {
192
	    set do_saveconfig 1
193
	# 'ssh -c' cypher type
194
	} -y* {
195
	    if {! [regexp .\[eE\](.+) $arg ignore cypher]} {
196
		incr i
197
		set cypher [lindex $argv $i]
198
	    }
199
	# alternate cloginrc file
200
	} -f* {
201
	    if {! [regexp .\[fF\](.+) $arg ignore password_file]} {
202
		incr i
203
		set password_file [lindex $argv $i]
204
	    }
205
	# Timeout
206
	} -t* {
207
	    if {! [regexp .\[tT\](.+) $arg ignore timeout]} {
208
		incr i
209
	        set timeoutdflt [lindex $argv $i]
210
	    }
211
	# Command file
212
	} -x* {
213
	    if {! [regexp .\[xX\](.+) $arg ignore cmd_file]} {
214
		incr i
215
		set cmd_file [lindex $argv $i]
216
	    }
217
	    if [catch {set cmd_fd [open $cmd_file r]} reason] {
218
		send_user "\nError: $reason\n"
219
		exit 1
220
	    }
221
	    set cmd_text [read $cmd_fd]
222
	    close $cmd_fd
223
	    set command [join [split $cmd_text \n] \;]
224
	    set do_command 1
225
	# Do we enable?
226
	} -noenable {
227
	    set avenable 0
228
	# Does tacacs automatically enable us?
229
	} -autoenable {
230
	    set avautoenable 1
231
	    set avenable 0
232
	} -* {
233
	    send_user "\nError: Unknown argument! $arg\n"
234
	    send_user $usage
235
	    exit 1
236
	} default {
237
	    break
238
	}
239
    }
240
}
241
# Process routers...no routers listed is an error.
242
if { $i == $argc } {
243
    send_user "\nError: $usage"
244
}
245
246
# Only be quiet if we are running a script (it can log its output
247
# on its own)
248
if { $do_script } {
249
    log_user 0
250
} else {
251
    log_user 1
252
}
253
254
#
255
# Done configuration/variable setting.  Now run with it...
256
#
257
258
# Sets Xterm title if interactive...if its an xterm and the user cares
259
proc label { host } {
260
    global env
261
    # if CLOGIN has an 'x' in it, don't set the xterm name/banner
262
    if [info exists env(CLOGIN)] {
263
	if {[string first "x" $env(CLOGIN)] != -1} { return }
264
    }
265
    # take host from ENV(TERM)
266
    if [info exists env(TERM)] {
267
	if [regexp \^(xterm|vs) $env(TERM) ignore] {
268
	    send_user "\033]1;[lindex [split $host "."] 0]\a"
269
	    send_user "\033]2;$host\a"
270
	}
271
    }
272
}
273
274
# This is a helper function to make the password file easier to
275
# maintain.  Using this the password file has the form:
276
# add password sl*	pete cow
277
# add password at*	steve
278
# add password *	hanky-pie
279
proc add {var args} { global int_$var ; lappend int_$var $args}
280
proc include {args} {
281
    global env
282
    regsub -all "(^{|}$)" $args {} args
283
    if { [regexp "^/" $args ignore] == 0 } {
284
	set args $env(HOME)/$args
285
    }
286
    source_password_file $args
287
}
288
289
proc find {var router} {
290
    upvar int_$var list
291
    if { [info exists list] } {
292
	foreach line $list {
293
	    if { [string match -nocase [lindex $line 0] $router] } {
294
		return [lrange $line 1 end]
295
	    }
296
	}
297
    }
298
    return {}
299
}
300
301
# Loads the password file.  Note that as this file is tcl, and that
302
# it is sourced, the user better know what to put in there, as it
303
# could install more than just password info...  I will assume however,
304
# that a "bad guy" could just as easy put such code in the clogin
305
# script, so I will leave .cloginrc as just an extention of that script
306
proc source_password_file { password_file } {
307
    global env
308
    if { ! [file exists $password_file] } {
309
	send_user "\nError: password file ($password_file) does not exist\n"
310
	exit 1
311
    }
312
    file stat $password_file fileinfo
313
    if { [expr ($fileinfo(mode) & 007)] != 0000 } {
314
	send_user "\nError: $password_file must not be world readable/writable\n"
315
	exit 1
316
    }
317
    if [catch {source $password_file} reason] {
318
	send_user "\nError: $reason\n"
319
	exit 1
320
    }
321
}
322
323
# Log into the router.
324
# returns: 0 on success, 1 on failure, -1 if rsh was used successfully
325
proc login { router user userpswd passwd enapasswd cmethod cyphertype identfile } {
326
    global command spawn_id in_proc do_command do_script platform passphrase
327
    global prompt prompt_match u_prompt p_prompt e_prompt sshcmd
328
    set in_proc 1
329
    set uprompt_seen 0
330
331
    # try each of the connection methods in $cmethod until one is successful
332
    set progs [llength $cmethod]
333
    foreach prog [lrange $cmethod 0 end] {
334
	incr progs -1
335
	if [string match "telnet*" $prog] {
336
	    regexp {telnet(:([^[:space:]]+))*} $prog methcmd suffix port
337
	    if {"$port" == ""} {
338
		set retval [catch {spawn telnet $router} reason]
339
	    } else {
340
		set retval [catch {spawn telnet $router $port} reason]
341
	    }
342
	    if { $retval } {
343
		send_user "\nError: telnet failed: $reason\n"
344
		return 1
345
	    }
346
	} elseif [string match "ssh*" $prog] {
347
	    # ssh to the router & try to login with or without an identfile.
348
	    regexp {ssh(:([^[:space:]]+))*} $prog methcmd suffix port
349
	    set cmd $sshcmd
350
	    if {"$port" != ""} {
351
		set cmd "$cmd -p $port"
352
	    }
353
	    if {"$identfile" != ""} {
354
		set cmd "$cmd -i $identfile"
355
	    }
356
	    set retval [catch {eval spawn [split "$cmd -c $cyphertype -x -l $user $router" { }]} reason]
357
	    if { $retval } {
358
		send_user "\nError: $cmd failed: $reason\n"
359
		return 1
360
	    }
361
	} elseif ![string compare $prog "rsh"] {
362
	    if { ! $do_command } {
363
		if { [llength $cmethod] == 1 } {
364
		    send_user "\nError: rsh is an invalid method for -x and "
365
		    send_user "interactive logins\n"
366
		}
367
		if { $progs == 0 } {
368
		    return 1
369
		}
370
		continue;
371
	    }
372
373
	    # handle escaped ;s in commands, and ;; and ^;
374
	    regsub -all {([^\\]);;} $command "\\1;\u002;" esccommand
375
	    regsub {^;} $esccommand "\u002;" command
376
	    set sep "\\1\u001"
377
	    regsub -all {([^\\])\;} $command "$sep" esccommand
378
	    set sep "\u001"
379
	    set commands [split $esccommand $sep]
380
	    set num_commands [llength $commands]
381
	    set rshfail 0
382
	    for {set i 0} {$i < $num_commands && !$rshfail} { incr i} {
383
		log_user 0
384
		set retval [catch {spawn rsh $user@$router [lindex $commands $i] } reason]
385
		if { $retval } {
386
		    send_user "\nError: rsh failed: $reason\n"
387
		    log_user 1; return 1
388
		}
389
		send_user "$router# [lindex $commands $i]\n"
390
391
		# rcmd does not get a pager and no prompts, so we just have to
392
		# look for failures & lines.
393
		expect {
394
		  "Connection refused"	{ catch {close}; catch {wait};
395
					  send_user "\nError: Connection\
396
						    Refused ($prog): $router\n"
397
					  set rshfail 1
398
					}
399
		  -re "(Connection closed by|Connection to \[^\n\r]+ closed)" {
400
					  catch {close}; catch {wait};
401
					  send_user "\nError: Connection\
402
						    closed ($prog): $router\n"
403
					  set rshfail 1
404
					}
405
		  "Host is unreachable"	{ catch {close}; catch {wait};
406
					  send_user "\nError: Host Unreachable:\
407
						    $router\n"
408
					  set rshfail 1
409
					}
410
		  "No address associated with" {
411
					  catch {close}; catch {wait};
412
					  send_user "\nError: Unknown host\
413
						    $router\n"
414
					  set rshfail 1
415
					}
416
		  -re "\b+"		{ exp_continue }
417
		  -re "\[\n\r]+"	{ send_user -- "$expect_out(buffer)"
418
					  exp_continue
419
					}
420
		  timeout		{ catch {close}; catch {wait};
421
					  send_user "\nError: TIMEOUT reached\n"
422
					  set rshfail 1
423
					}
424
		  eof			{ catch {close}; catch {wait}; }
425
		}
426
		log_user 1
427
	    }
428
	    if { $rshfail } {
429
		if { !$progs } {
430
		    return 1
431
		} else {
432
		    continue
433
		}
434
	    }
435
	    # fake the end of the session for rancid.
436
	    send_user "$router# exit\n"
437
	    # return rsh "success"
438
	    return -1
439
	} else {
440
	    send_user "\nError: unknown connection method: $prog\n"
441
	    return 1
442
	}
443
	sleep 0.3
444
445
	# This helps cleanup each expect clause.
446
	expect_after {
447
	    timeout {
448
		send_user "\nError: TIMEOUT reached\n"
449
		catch {close}; catch {wait};
450
		if { $in_proc} {
451
		    return 1
452
		} else {
453
		    continue
454
		}
455
	    } eof {
456
		send_user "\nError: EOF received\n"
457
		catch {close}; catch {wait};
458
		if { $in_proc} {
459
		    return 1
460
		} else {
461
		    continue
462
		}
463
	    }
464
	}
465
466
    # Here we get a little tricky.  There are several possibilities:
467
    # the router can ask for a username and passwd and then
468
    # talk to the TACACS server to authenticate you, or if the
469
    # TACACS server is not working, then it will use the enable
470
    # passwd.  Or, the router might not have TACACS turned on,
471
    # then it will just send the passwd.
472
    # if telnet fails with connection refused, try ssh
473
    expect {
474
	-re "^<-+ More -+>\[^\n\r]*" {
475
	    # ASA will use the pager for long banners
476
	    send " ";
477
	    exp_continue
478
	}
479
	-re "(Connection refused|Secure connection \[^\n\r]+ refused)" {
480
	    catch {close}; catch {wait};
481
	    if !$progs {
482
		send_user "\nError: Connection Refused ($prog): $router\n"
483
		return 1
484
	    }
485
	}
486
	-re "(Connection closed by|Connection to \[^\n\r]+ closed)" {
487
	    catch {close}; catch {wait};
488
	    if !$progs {
489
		send_user "\nError: Connection closed ($prog): $router\n"
490
		return 1
491
	    }
492
	}
493
	eof { send_user "\nError: Couldn't login: $router\n"; wait; return 1 }
494
	-nocase "unknown host\r" {
495
	    send_user "\nError: Unknown host $router\n";
496
	    catch {close}; catch {wait};
497
	    return 1
498
	}
499
	"Host is unreachable" {
500
	    send_user "\nError: Host Unreachable: $router\n";
501
	    catch {close}; catch {wait};
502
	    return 1
503
	}
504
	"No address associated with name" {
505
	    send_user "\nError: Unknown host $router\n";
506
	    catch {close}; catch {wait};
507
	    return 1
508
	}
509
	-re "(Host key not found |The authenticity of host .* be established).* \\(yes/no\\)\\?" {
510
	    send "yes\r"
511
	    send_user "\nHost $router added to the list of known hosts.\n"
512
	    exp_continue
513
	}
514
	-re "HOST IDENTIFICATION HAS CHANGED.* \\(yes/no\\)\\?" {
515
	    send "no\r"
516
	    send_user "\nError: The host key for $router has changed.  Update the SSH known_hosts file accordingly.\n"
517
	    catch {close}; catch {wait};
518
	    return 1
519
	}
520
	-re "HOST IDENTIFICATION HAS CHANGED\[^\n\r]+" {
521
	    send_user "\nError: The host key for $router has changed.  Update the SSH known_hosts file accordingly.\n"
522
	    return 1
523
	}
524
	-re "Offending key for .* \\(yes/no\\)\\?" {
525
	    send "no\r"
526
	    send_user "\nError: host key mismatch for $router.  Update the SSH known_hosts file accordingly.\n"
527
	    catch {close}; catch {wait};
528
	    return 1
529
	}
530
	-re "(denied|Sorry)"	{
531
				  send_user "\nError: Check your passwd for $router\n"
532
				  catch {close}; catch {wait}; return 1
533
				}
534
	"Login failed"		{
535
				  send_user "\nError: Check your passwd for $router\n"
536
				  catch {close}; catch {wait}; return 1
537
				}
538
	-re "% (Bad passwords|Authentication failed)"	{
539
				  send_user "\nError: Check your passwd for $router\n"
540
				  catch {close}; catch {wait}; return 1
541
				}
542
	"Press any key to continue" {
543
				  # send_user "Pressing the ANY key\n"
544
				  send "\r"
545
				  exp_continue
546
				}
547
	-re "Enter Selection: " {
548
				  # Catalyst 1900s have some lame menu.  Enter
549
				  # K to reach a command-line.
550
				  send "K\r"
551
				  exp_continue
552
				}
553
	-re "Last login:"	{
554
				  exp_continue
555
				}
556
	-re "Press the <tab> key \[^\r\n]+\[\r\n]+"	{
557
				  exp_continue
558
				}
559
	-re "@\[^\r\n]+ $p_prompt"	{
560
				  # ssh pwd prompt
561
				  sleep 1
562
				  send -- "$userpswd\r"
563
				  exp_continue
564
				}
565
	-re "Enter passphrase.*: " {
566
				  # sleep briefly to allow time for stty -echo
567
				  sleep .3
568
				  send -- "$passphrase\r"
569
				  exp_continue
570
				}
571
	-re "$u_prompt"		{
572
				  send -- "$user\r"
573
				  set uprompt_seen 1
574
				  exp_continue
575
				}
576
	-re "$p_prompt"		{
577
				  sleep 1
578
				  if {$uprompt_seen == 1} {
579
					send -- "$userpswd\r"
580
				  } else {
581
					send -- "$passwd\r"
582
				  }
583
				  exp_continue
584
				}
585
	-re "$prompt"		{
586
				  set prompt_match $expect_out(0,string);
587
				  break;
588
				}
589
	"Login invalid"		{
590
				  send_user "\nError: Invalid login: $router\n";
591
				  catch {close}; catch {wait}; return 1
592
				}
593
	-re "\[^\r\n]*\[\r\n]+"	{ exp_continue; }
594
     }
595
    }
596
597
    set in_proc 0
598
    return 0
599
}
600
601
# Enable
602
proc do_enable { enauser enapasswd } {
603
    global do_saveconfig in_proc
604
    global prompt u_prompt e_prompt enacmd
605
    set in_proc 1
606
607
    send "$enacmd\r"
608
    expect {
609
	-re "$u_prompt"	{ send -- "$enauser\r"; exp_continue}
610
	-re "$e_prompt"	{ send -- "$enapasswd\r"; exp_continue}
611
	">"		{ set prompt ">" }
612
	"#"		{ set prompt "#" }
613
	"(enable)"	{ set prompt "> \\(enable\\) " }
614
	"% Invalid input" {
615
			  send_user "\nError: Unrecognized command, check your enable command\n";
616
			  return 1
617
			}
618
	-re "(denied|Sorry|Incorrect)"	{
619
			  # % Access denied - from local auth and poss. others
620
			  send_user "\nError: Check your Enable passwd\n";
621
			  return 1
622
			}
623
	"% Error in authentication" {
624
			  send_user "\nError: Check your Enable passwd\n"
625
			  return 1
626
			}
627
	"% Bad passwords" {
628
			  send_user "\nError: Check your Enable passwd\n"
629
			  return 1
630
			}
631
	"% Password is not set." { # Comware
632
			  send_user "\nError: No '$enacmd' password set for devide\n"
633
			  return 1
634
			}
635
	"% Authenticate failed." { # Comware
636
			  send_user "\nError: Check your enable password for '$enacmd'\n
637
			  return 1
638
			}
639
    }
640
    # We set the prompt variable (above) so script files don't need
641
    # to know what it is.
642
    set in_proc 0
643
    return 0
644
}
645
646
# Run commands given on the command line.
647
proc run_commands { prompt command } {
648
    global do_saveconfig in_proc platform exitcmd
649
    set in_proc 1
650
651
    # If the prompt is (enable), then we are on a switch and the
652
    # command is "set length 0"; otherwise its "terminal length 0".
653
    # skip if its an extreme (since the pager can not be disabled on a
654
    # per-vty basis).
655
    if { [string compare "extreme" "$platform"] } {
656
	# match cisco config mode prompts too, such as router(config-if)#,
657
	# but catalyst does not change in this fashion.
658
	regsub -all {^(.{1,11}).*([#>])$} $prompt {\1([^#>\r\n]+)?[#>](\\([^)\\r\\n]+\\))?} reprompt
659
    } else {
660
	set reprompt $prompt
661
    }
662
663
    # this is the only way i see to get rid of more prompts in o/p..grrrrr
664
    log_user 0
665
666
    # handle escaped ;s in commands, and ;; and ^;
667
    regsub -all {([^\\]);;} $command "\\1;\u002;" esccommand
668
    regsub {^;} $esccommand "\u002;" command
669
    set sep "\\1\u001"
670
    regsub -all {([^\\]);} $command "$sep" esccommand
671
    set sep "\u001"
672
    set commands [split $esccommand $sep]
673
    set num_commands [llength $commands]
674
    # the pager can not be turned off on the PIX, so we have to look
675
    # for the "More" prompt.  the extreme is equally obnoxious in pre-12.3 XOS,
676
    # with a global switch in the config.
677
    for {set i 0} {$i < $num_commands} { incr i} {
678
	if { [lindex $commands $i] == "\u002" } {
679
	    send -- "\r"
680
	} else {
681
	    send -- "[subst -nocommands [lindex $commands $i]]\r"
682
	}
683
	expect {
684
	    -re "\b+"				{ exp_continue }
685
	    -re "^\[^\n\r *]*$reprompt"		{ send_user -- "$expect_out(buffer)"
686
						}
687
	    -re "^\[^\n\r]*$reprompt."		{ send_user -- "$expect_out(buffer)"
688
						  exp_continue
689
						}
690
	    -re "^--More--\[\r\n]+"		{ # specific match c1900 pager
691
						  send " "
692
						  exp_continue
693
						}
694
	    -re "\[^\r\n]*\[\n\r]+"		{ send_user -- "$expect_out(buffer)"
695
						  exp_continue
696
						}
697
	    -re "\[^\r\n]*Press <SPACE> to cont\[^\r\n]*"	{
698
						  send " "
699
						  # bloody ^[[2K after " "
700
						  expect {
701
							-re "^\[^\r\n]*\r" {}
702
							}
703
						  exp_continue
704
						}
705
	    -re "^ *--More--\[^\n\r]*"		{
706
						  send " "
707
						  exp_continue }
708
	    -re "^<-+ More -+>\[^\n\r]*"	{
709
						  send_user -- "$expect_out(buffer)"
710
						  send " "
711
						  exp_continue }
712
	    -re "^ {0,2}-+ More .*-+.*\[^\n\r]*"	{
713
						  # Comware 3/5 pager prompt
714
						  sleep 0.1
715
						  send " "
716
						  exp_continue }
717
	    -re "^---- More ----\[^\n\r]*"  {
718
						  # Comware 7 pager prompt
719
						  sleep 0.1
720
						  send " "
721
						  exp_continue }
722
	}
723
    }
724
    log_user 1
725
726
    if { [string compare "extreme" "$platform"] } {
727
	send -h "exit\r"
728
    } else {
729
	send -h "quit\r"
730
    }
731
    expect {
732
	-re "^\[^\n\r *]*$reprompt"		{
733
						  # the Cisco CE and Jnx ERX
734
						  # return to non-enabled mode
735
						  # on exit in enabled mode.
736
						  send -h "$exitcmd\r"
737
						  exp_continue;
738
						}
739
	"The system has unsaved changes"	{ # Force10 SFTOS
740
						  if {$do_saveconfig} {
741
						    catch {send "y\r"}
742
						  } else {
743
						    catch {send "n\r"}
744
						  }
745
						  exp_continue
746
						}
747
	"Would you like to save them now"	{ # Force10
748
						  if {$do_saveconfig} {
749
						    catch {send "y\r"}
750
						  } else {
751
						    catch {send "n\r"}
752
						  }
753
						  exp_continue
754
						}
755
	-re "(Profile|Configuration) changes have occurred.*"	{
756
						  # Cisco CSS
757
						  if {$do_saveconfig} {
758
						    catch {send "y\r"}
759
						  } else {
760
						    catch {send "n\r"}
761
						  }
762
						  exp_continue
763
						}
764
	"Do you wish to save your configuration changes" {
765
						  if {$do_saveconfig} {
766
						    catch {send "y\r"}
767
						  } else {
768
						    catch {send "n\r"}
769
						  }
770
						  exp_continue
771
						}
772
	-re "\[\n\r]+"				{ exp_continue }
773
	-re "\[^\n\r *]Note:"			{ return 0 }
774
	timeout					{ catch {close}; catch {wait};
775
						  return 0
776
						}
777
	eof					{ return 0 }
778
    }
779
    set in_proc 0
780
}
781
782
#
783
# For each router... (this is main loop)
784
#
785
source_password_file $password_file
786
set in_proc 0
787
set exitval 0
788
set prompt_match ""
789
foreach router [lrange $argv $i end] {
790
    set router [string tolower $router]
791
    # attempt at platform switching.
792
    set platform ""
793
    send_user -- "$router\n"
794
795
    # Figure out the platform
796
    if {[info exists plat]} {
797
	# command line platform
798
	set platform $plat
799
    } else {
800
	set plat [find platform $router]
801
	if { "$plat" == "" } { set platform "" }
802
    }
803
804
    # Based on the platform, set some other defaults
805
    # These can get overridden by other explicit settings
806
    # Note that MA5600 wants enacmd "enable"
807
    # Note that later versions of Coomware want cyphertype "aes128-cbc"
808
    if { [string compare "cmw" "$platform"] } {
809
	set enacmd "super"
810
	set exitcmd "quit"
811
	set cyphertype "3des"
812
    } else {
813
	set exitcmd "exit"
814
    }
815
816
    # device timeout
817
    set timeout [find timeout $router]
818
    if { [llength $timeout] == 0 } {
819
	set timeout $timeoutdflt
820
    }
821
822
    # Default prompt.
823
    set prompt [join [find prompt $router] ""]
824
    if { [llength $prompt] == 0 } {
825
	set prompt "(>\a?|#| \\(enable\\))"
826
    }
827
828
    # look for autoenable option in .cloginrc & cmd-line
829
    set ae [find autoenable $router]
830
    if { "$ae" == "1" || $avautoenable } {
831
	set autoenable 1
832
    } else {
833
	set autoenable 0
834
    }
835
    # look for enable options in .cloginrc & cmd-line
836
    if { $avenable == 0 } {
837
	set enable 0
838
    } else {
839
	set ne [find noenable $router]
840
	if { "$ne" == "1" || "$autoenable" == "1" } {
841
	    set enable 0
842
	} else {
843
	    set enable 1
844
	}
845
    }
846
847
    # Figure out passwords
848
    if { $do_passwd || $do_enapasswd } {
849
      set pswd [find password $router]
850
      if { [llength $pswd] == 0 } {
851
	send_user -- "\nError: no password for $router in $password_file.\n"
852
	continue
853
      }
854
      if { $enable && $do_enapasswd && $autoenable == 0 && [llength $pswd] < 2 } {
855
	send_user -- "\nError: no enable password for $router in $password_file.\n"
856
	continue
857
      }
858
      set passwd [join [lindex $pswd 0] ""]
859
      set enapasswd [join [lindex $pswd 1] ""]
860
    } else {
861
	set passwd $userpasswd
862
	set enapasswd $enapasswd
863
    }
864
865
    # Figure out username
866
    if {[info exists username]} {
867
      # command line username
868
      set ruser $username
869
    } else {
870
      set ruser [join [find user $router] ""]
871
      if { "$ruser" == "" } { set ruser $default_user }
872
    }
873
874
    # Figure out username's password (if different from the vty password)
875
    if {[info exists userpasswd]} {
876
      # command line username
877
      set userpswd $userpasswd
878
    } else {
879
      set userpswd [join [find userpassword $router] ""]
880
      if { "$userpswd" == "" } { set userpswd $passwd }
881
    }
882
883
    # Figure out enable username
884
    if {[info exists enausername]} {
885
      # command line enausername
886
      set enauser $enausername
887
    } else {
888
      set enauser [join [find enauser $router] ""]
889
      if { "$enauser" == "" } { set enauser $ruser }
890
    }
891
892
    # Figure out enable command
893
    set enacmd [join [find enablecmd $router] ""]
894
    if { "$enacmd" == "" } { set enacmd "enable" }
895
896
    # Figure out prompts
897
    set u_prompt [find userprompt $router]
898
    if { "$u_prompt" == "" } {
899
	set u_prompt "(\[Uu]sername|Login|login|user name|User|User name):"
900
    } else {
901
	set u_prompt [join [lindex $u_prompt 0] ""]
902
    }
903
    set p_prompt [find passprompt $router]
904
    if { "$p_prompt" == "" } {
905
	set p_prompt "(\[Pp]assword|passwd|Enter password for \[^ :]+):"
906
    } else {
907
	set p_prompt [join [lindex $p_prompt 0] ""]
908
    }
909
    set e_prompt [find enableprompt $router]
910
    if { "$e_prompt" == "" } {
911
	set e_prompt "\[Pp]assword:"
912
    } else {
913
	set e_prompt [join [lindex $e_prompt 0] ""]
914
    }
915
916
    # Figure out identity file to use
917
    set identfile [join [lindex [find identity $router] 0] ""]
918
919
    # Figure out passphrase to use
920
    if {[info exists avpassphrase]} {
921
	set passphrase $avpassphrase
922
    } else {
923
	set passphrase [join [lindex [find passphrase $router] 0] ""]
924
    }
925
    if { ! [string length "$passphrase"]} {
926
	set passphrase $passwd
927
    }
928
929
    # Figure out cypher type
930
    if {[info exists cypher]} {
931
        # command line cypher type
932
        set cyphertype $cypher
933
    } else {
934
        set cyphertype [find cyphertype $router]
935
        if { "$cyphertype" == "" } { set cyphertype "3des" }
936
    }
937
938
    # Figure out connection method
939
    set cmethod [find method $router]
940
    if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} }
941
942
    # Figure out the SSH executable name
943
    set sshcmd [join [lindex [find sshcmd $router] 0] ""]
944
    if { "$sshcmd" == "" } { set sshcmd {ssh} }
945
946
947
    # Login to the router
948
    if {[login $router $ruser $userpswd $passwd $enapasswd $cmethod $cyphertype $identfile]} {
949
	incr exitval
950
	# if login failed or rsh was unsuccessful, move on to the next device
951
	continue
952
    }
953
    # Figure out the prompt.
954
    if { [regexp -- "(#| \\(enable\\))" $prompt_match junk] == 1 } {
955
	set enable 0
956
    }
957
958
    # Disable smart and interactive before send other commands
959
    # (MA5600 and similar only?)
960
    # Also disable log junk being sent to terminal
961
    if { [string compare "cmw" "$platform"] } {
962
	send -h "undo smart\r"
963
	expect -re $prompt  {}
964
	send -h "undo interactive\r"
965
	expect -re $prompt  {}
966
	send -h "undo terminal monitor\r"
967
	expect -re $prompt  {}
968
    }
969
970
    if { $enable } {
971
	if {[do_enable $enauser $enapasswd]} {
972
	    if { $do_command || $do_script } {
973
		incr exitval
974
		catch {close}; catch {wait};
975
		continue
976
	    }
977
	}
978
    }
979
    # we are logged in, now figure out the full prompt
980
    send "\r"
981
    regsub -all {^(\^*)(.*)} $prompt {\2} reprompt
982
    expect {
983
	-re "\[\r\n]+"		{ exp_continue; }
984
	-re "^(.+\[:.])1 ($reprompt)" { # stoopid extreme cmd-line numbers and
985
				  # prompt based on state of config changes,
986
				  # which may have an * at the beginning.
987
				  set junk $expect_out(1,string)
988
				  regsub -all "^\\\* " $expect_out(1,string) {} junk
989
				  regsub -all "\[\]\[\(\)]" $junk {\\&} junk;
990
				  set prompt ".? ?$junk\[0-9]+ $expect_out(2,string)";
991
				  set platform "extreme"
992
				}
993
	-re "^.+$reprompt"	{ set junk $expect_out(0,string);
994
				  regsub -all "\[\]\[\(\)+]" $junk {\\&} prompt;
995
				}
996
    }
997
    if { $do_command || $do_script } {
998
	if { [string compare "extreme" "$platform"] } {
999
	    # If the prompt is (enable), then we are on a switch and the
1000
	    # command is "set length 0"; otherwise its "terminal length 0".
1001
	    if [regexp -- ".*> .*enable" "$prompt"] {
1002
		send "set length 0\r"
1003
		expect -re $prompt  	{}
1004
		send "set width 132\r"
1005
		expect -re $prompt	{}
1006
		send "set logging session disable\r"
1007
	    } else {
1008
		send "terminal length 0\r"
1009
		expect -re $prompt  	{}
1010
		send "terminal width 132\r"
1011
	    }
1012
	    expect -re $prompt		{}
1013
	} elseif { [string compare "cmw" "$platform"] } {
1014
	    # Turn session paging off
1015
	    # Comware 5/7 only.
1016
	    # Comware 3 models have a screen-length command that only works on
1017
	    # a vty basis
1018
	    send -h "screen-length disable\r"
1019
	    expect -re $prompt		{}
1020
	} else {
1021
	    send "disable clipaging\r"
1022
	    expect -re $prompt		{}
1023
	}
1024
    }
1025
    if { $do_command } {
1026
	if {[run_commands $prompt $command]} {
1027
	    incr exitval
1028
	    continue
1029
	}
1030
    } elseif { $do_script } {
1031
	source $sfile
1032
	catch {close};
1033
    } else {
1034
	label $router
1035
	log_user 1
1036
	interact
1037
    }
1038
1039
    # End of for each router
1040
    catch {wait};
1041
    sleep 0.3
1042
}
1043
exit $exitval
(-)files/comware7_types.conf (+58 lines)
Line 0 Link Here
1
#
2
# Comware devices v3.11
3
# source: https://sites.google.com/site/jrbinks/code/rancid/cmwrancid
4
cmw;script;rancid -t cmw
5
cmw;login;cmwlogin
6
cmw;module;cmw
7
cmw;inloop;cmw::inloop
8
cmw;command;cmw::CommentOutput;display version
9
cmw;command;cmw::CommentOutput;display boot-loader
10
cmw;command;cmw::CommentOutput;display startup
11
cmw;command;cmw::CommentOutput;dir /all
12
cmw;command;cmw::CommentOutput;dir /all unit2>flash:/
13
cmw;command;cmw::CommentOutput;dir /all slot2#flash:/
14
cmw;command;cmw::CommentOutput;dir /all unit3>flash:/
15
cmw;command;cmw::CommentOutput;dir /all slot3#flash:/
16
cmw;command;cmw::CommentOutput;dir /all unit4>flash:/
17
cmw;command;cmw::CommentOutput;dir /all slot4#flash:/
18
cmw;command;cmw::CommentOutput;dir /all unit5>flash:/
19
cmw;command;cmw::CommentOutput;dir /all slot5#flash:/
20
cmw;command;cmw::CommentOutput;dir /all unit6>flash:/
21
cmw;command;cmw::CommentOutput;dir /all slot6#flash:/
22
cmw;command;cmw::CommentOutput;dir /all unit7>flash:/
23
cmw;command;cmw::CommentOutput;dir /all slot7#flash:/
24
cmw;command;cmw::CommentOutput;dir /all unit8>flash:/
25
cmw;command;cmw::CommentOutput;dir /all slot8#flash:/
26
# Commands relating to the hardware:
27
cmw;command;cmw::CommentOutput;display device
28
cmw;command;cmw::CommentOutput;display device manuinfo
29
cmw;command;cmw::CommentOutput;display fan
30
cmw;command;cmw::CommentOutput;display power
31
cmw;command;cmw::CommentOutput;display poe powersupply
32
cmw;command;cmw::CommentOutput;display poe temperature-protection
33
cmw;command;cmw::CommentOutput;display transceiver interface
34
# Commands relating to authentication:
35
cmw;command;cmw::CommentOutput;display cluster
36
cmw;command;cmw::CommentOutput;display domain
37
cmw;command;cmw::CommentOutput;display local-user
38
cmw;command;cmw::CommentOutput;display password-control
39
cmw;command;cmw::CommentOutput;display password-control super
40
cmw;command;cmw::CommentOutput;display ssh server status
41
# Commands relating to system state:
42
cmw;command;cmw::CommentOutput;display irf
43
cmw;command;cmw::CommentOutput;display xrn-fabric
44
cmw;command;cmw::CommentOutput;display ftm topology-database
45
cmw;command;cmw::DisplayFib;display fib
46
cmw;command;cmw::DisplayIPRoutes;display ip routing-table
47
cmw;command;cmw::CommentOutput;display ospf
48
cmw;command;cmw::CommentOutput;display ospf brief
49
cmw;command;cmw::CommentOutput;display vlan all
50
cmw;command;cmw::CommentOutput;display lacp sys
51
cmw;command;cmw::CommentOutput;display link-aggregation summary
52
cmw;command;cmw::CommentOutput;display link-aggregation verbose
53
cmw;command;cmw::CommentOutput;display loopback-detection
54
cmw;command;cmw::CommentOutput;display mirror all
55
cmw;command;cmw::CommentOutput;display ntp-service status
56
cmw;command;cmw::CommentOutput;display stp root
57
# And the system config itself:
58
cmw;command;cmw::DisplayCurrent;display current-configuration
(-)pkg-plist (+2 lines)
Lines 3-8 Link Here
3
lib/rancid/acos.pm
3
lib/rancid/acos.pm
4
lib/rancid/arbor.pm
4
lib/rancid/arbor.pm
5
lib/rancid/ciscowlc.pm
5
lib/rancid/ciscowlc.pm
6
lib/rancid/cmw.pm
6
lib/rancid/dell.pm
7
lib/rancid/dell.pm
7
lib/rancid/eos.pm
8
lib/rancid/eos.pm
8
lib/rancid/foundry.pm
9
lib/rancid/foundry.pm
Lines 27-32 Link Here
27
libexec/rancid/brancid
28
libexec/rancid/brancid
28
libexec/rancid/cat5rancid
29
libexec/rancid/cat5rancid
29
libexec/rancid/clogin
30
libexec/rancid/clogin
31
libexec/rancid/cmwlogin
30
libexec/rancid/complogin
32
libexec/rancid/complogin
31
libexec/rancid/control_rancid
33
libexec/rancid/control_rancid
32
libexec/rancid/cssrancid
34
libexec/rancid/cssrancid

Return to bug 209361