Advertisement
Guest User

Untitled

a guest
Nov 13th, 2017
1,364
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 338.23 KB | None | 0 0
  1. ## Pete Whiting, Austin Schutz, and Andrew Fort.
  2. ##
  3. ## Redistribution and use in source and binary forms, with or without
  4. ## modification, are permitted provided that the following conditions
  5. ## are met:
  6. ## 1. Redistributions of source code must retain the above copyright
  7. ## notice, this list of conditions and the following disclaimer.
  8. ## 2. Redistributions in binary form must reproduce the above copyright
  9. ## notice, this list of conditions and the following disclaimer in the
  10. ## documentation and/or other materials provided with the distribution.
  11. ## 3. All advertising materials mentioning features or use of this software
  12. ## must display the following acknowledgement:
  13. ## This product includes software developed by Terrapin Communications,
  14. ## Inc. and its contributors for RANCID.
  15. ## 4. Neither the name of Terrapin Communications, Inc. nor the names of its
  16. ## contributors may be used to endorse or promote products derived from
  17. ## this software without specific prior written permission.
  18. ## 5. It is requested that non-binding fixes and modifications be contributed
  19. ## back to Terrapin Communications, Inc.
  20. ##
  21. ## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS
  22. ## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  23. ## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  24. ## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
  25. ## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  26. ## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  27. ## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  28. ## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  29. ## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  30. ## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  31. ## POSSIBILITY OF SUCH DAMAGE.
  32. ##
  33. ## It is the request of the authors, but not a condition of license, that
  34. ## parties packaging or redistributing RANCID NOT distribute altered versions
  35. ## of the etc/rancid.types.base file nor alter how this file is processed nor
  36. ## when in relation to etc/rancid.types.conf. The goal of this is to help
  37. ## suppress our support costs. If it becomes a problem, this could become a
  38. ## condition of license.
  39. #
  40. # The expect login scripts were based on Erik Sherk's gwtn, by permission.
  41. #
  42. # The original looking glass software was written by Ed Kern, provided by
  43. # permission and modified beyond recognition.
  44. #
  45. # RANCID - Really Awesome New Cisco confIg Differ
  46. #
  47. # plogin - poly-login; use router.db files and rancid.{base,types}.conf
  48. # configurations to determine which login script to execute.
  49. #
  50. use 5.0010;
  51. use strict 'vars';
  52. use warnings;
  53. no warnings 'uninitialized';
  54. use Exporter;
  55. use Getopt::Long;
  56. # use Getopt::Long qw(:config no_ignore_case bundling);
  57. Getopt::Long::Configure ("bundling", "no_ignore_case");
  58. our($opt_d, $opt_S, $opt_V, $opt_autoenable, $opt_noenable, $opt_c, @opt_E, $opt_e,
  59. $opt_f, $opt_h, $opt_p, $opt_r, $opt_s, $opt_t, $opt_u, $opt_v, $opt_w,
  60. $opt_x, $opt_y, $opt_z);
  61. GetOptions('d' => \$opt_d, 'S' => \$opt_S, 'V' => \$opt_V,
  62. 'autoenable' => \$opt_autoenable, 'noenable' => \$opt_noenable,
  63. 'c=s' => \$opt_c, "E=s@" => \@opt_E, 'e=s' => \$opt_e, 'f=s' => \$opt_f,
  64. 'h=s' => \$opt_h,'p=s' => \$opt_p, 'r=s' => \$opt_r, 's=s' => \$opt_s,
  65. 't=s' => \$opt_t, 'u=s' => \$opt_u, 'v=s' => \$opt_v, 'w=s' => \$opt_w,
  66. 'x=s' => \$opt_x, 'y=s' => \$opt_y, 'z=s' => \$opt_z);
  67. my($BASEDIR, $LIST_OF_GROUPS, $cmd, $i, $j, @routers);
  68. BEGIN {
  69. push(@INC, "/usr/local/rancid/lib/rancid");
  70. }
  71. use rancid;
  72. our @ISA = qw(Exporter rancid);
  73.  
  74. sub usage()
  75. {
  76. print STDERR "plogin [-dSV] [-autoenable] [-noenable] [-c command] [-Evar=x] [-e enable-password] [-f cloginrc-file] [-p user-password] [-r passphrase] [-s script-file] [-t timeout] [-u username] [-v vty-password] [-w enable-username] [-x command-file] [-y ssh_cypher_type] [-z device_type] router [router...]\n";
  77. exit 64;
  78. }
  79.  
  80. # make OUTPUT unbuffered if debugging
  81. if ($opt_d) { $| = 1; }
  82.  
  83. if ($opt_h) {
  84. usage();
  85. }
  86.  
  87. # option handling initialization
  88. if ($opt_V) {
  89. print "plogin: rancid 3.4.1\n";
  90. # do not exit; exec the script with -V and it will exit
  91. }
  92. $cmd .= " -d" if ($opt_d);
  93. $cmd .= " -S" if ($opt_S);
  94. $cmd .= " -V" if ($opt_V);
  95. $cmd .= " -autoenable" if ($opt_autoenable);
  96. $cmd .= " -noenable" if ($opt_noenable);
  97. $cmd .= " -c '$opt_c'" if (length($opt_c));
  98. foreach $i (@opt_E) {
  99. $cmd .= " -E$i";
  100. }
  101. $cmd .= " -e '$opt_e'" if (length($opt_e));
  102. $cmd .= " -f '$opt_f'" if (length($opt_f));
  103. $cmd .= " -p '$opt_p'" if (length($opt_p));
  104. $cmd .= " -r '$opt_r'" if (length($opt_r));
  105. $cmd .= " -s '$opt_s'" if (length($opt_s));
  106. $cmd .= " -t $opt_s" if (length($opt_t));
  107. $cmd .= " -u '$opt_u'" if (length($opt_u));
  108. $cmd .= " -v '$opt_v'" if (length($opt_v));
  109. $cmd .= " -w '$opt_w'" if (length($opt_w));
  110. $cmd .= " -x '$opt_x'" if (length($opt_x));
  111. $cmd .= " -y '$opt_y'" if (length($opt_y));
  112. $devtype = $opt_z;
  113. foreach $i (@ARGV) {
  114. $cmd .= " $i";
  115. push(@routers, $i);
  116. }
  117.  
  118. # what is the device type, supplied or looked-up
  119. if ($opt_z) {
  120. $devtype = $opt_z;
  121. } else {
  122. # Look in router.dbs for device type.
  123. # read rancid.conf for BASEDIR and LIST_OF_GROUPS?
  124. my($ENVFILE) = "/usr/local/rancid/etc/rancid.conf";
  125. open(INPUT, "< $ENVFILE") || die "Could not open $ENVFILE: $!";
  126. close(INPUT);
  127. open(INPUT,
  128. "sh -c \'. $ENVFILE; echo \"BASEDIR=\$BASEDIR\"; echo \"LIST_OF_GROUPS=\$LIST_OF_GROUPS\"\' |") ||
  129. die "Could not open $ENVFILE: $!";
  130. while (<INPUT>) {
  131. chomp;
  132. s/#.$//;
  133. s/^\s+//;
  134. my($varname, $value) = split('=');
  135. if ($varname eq "BASEDIR") {
  136. $BASEDIR = $value;
  137. }
  138. if ($varname eq "LIST_OF_GROUPS") {
  139. $LIST_OF_GROUPS = $value;
  140. $LIST_OF_GROUPS =~ s/^\s+//;
  141. $LIST_OF_GROUPS =~ s/\s+$//;
  142. }
  143. }
  144. close(INPUT);
  145.  
  146. # read each router.db for the routername and thus the devtype
  147. foreach $i (split(/\s+/, $LIST_OF_GROUPS)) {
  148. if (!open(INPUT, "< $BASEDIR/$i/router.db")) {
  149. warn "Could not open $BASEDIR/$i/router.db: $!";
  150. next;
  151. }
  152. while (<INPUT>) {
  153. chomp;
  154. s/#.$//;
  155. s/^\s+//;
  156. my($router, $type, $state) = split('\;');
  157. foreach $j (@routers) {
  158. if ($router eq $j) {
  159. $devtype = $type;
  160. close(INPUT);
  161. goto FOUND;
  162. }
  163. }
  164. }
  165. close(INPUT);
  166. }
  167. }
  168.  
  169. FOUND:
  170. if (length($devtype) < 1) {
  171. die "Couldn't find device type by hostname in router.dbs\n";
  172. }
  173.  
  174. # load device type spec, build @commandtable and load modules
  175. if (loadtype($devtype)) {
  176. die "Couldn't load device type spec for $rancid::devtype\n";
  177. }
  178. if (! defined($lscript)) {
  179. die "login script not defined for device type $rancid::devtype\n";
  180. }
  181. exec($lscript . " $cmd") ||
  182. printf(STDERR "exec($script) failed router manufacturer $devtype: $!\n");
  183. exit(-1);
  184. #! /usr/bin/perl
  185. ##
  186. ## $Id: prancid.in 2279 2011-01-31 22:41:00Z heas $
  187. ##
  188. ## rancid 2.3.8
  189. ## Copyright (c) 1997-2008 by Terrapin Communications, Inc.
  190. ## All rights reserved.
  191. ##
  192. ## This code is derived from software contributed to and maintained by
  193. ## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan,
  194. ## Pete Whiting, Austin Schutz, and Andrew Fort.
  195. ##
  196. ## Redistribution and use in source and binary forms, with or without
  197. ## modification, are permitted provided that the following conditions
  198. ## are met:
  199. ## 1. Redistributions of source code must retain the above copyright
  200. ## notice, this list of conditions and the following disclaimer.
  201. ## 2. Redistributions in binary form must reproduce the above copyright
  202. ## notice, this list of conditions and the following disclaimer in the
  203. ## documentation and/or other materials provided with the distribution.
  204. ## 3. All advertising materials mentioning features or use of this software
  205. ## must display the following acknowledgement:
  206. ## This product includes software developed by Terrapin Communications,
  207. ## Inc. and its contributors for RANCID.
  208. ## 4. Neither the name of Terrapin Communications, Inc. nor the names of its
  209. ## contributors may be used to endorse or promote products derived from
  210. ## this software without specific prior written permission.
  211. ## 5. It is requested that non-binding fixes and modifications be contributed
  212. ## back to Terrapin Communications, Inc.
  213. ##
  214. ## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS
  215. ## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  216. ## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  217. ## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
  218. ## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  219. ## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  220. ## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  221. ## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  222. ## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  223. ## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  224. ## POSSIBILITY OF SUCH DAMAGE.
  225. #
  226. # This version of rancid tries to deal with Prockets.
  227. #
  228. # RANCID - Really Awesome New Cisco confIg Differ
  229. #
  230. # usage: rancid [-dV] [-l] [-f filename | hostname]
  231. #
  232. use Getopt::Std;
  233. getopts('dflV');
  234. if ($opt_V) {
  235. print "rancid 2.3.8\n";
  236. exit(0);
  237. }
  238. $log = $opt_l;
  239. $debug = $opt_d;
  240. $file = $opt_f;
  241. $host = $ARGV[0];
  242. $clean_run = 0;
  243. $found_end = 0;
  244. $timeo = 90; # clogin timeout in seconds
  245.  
  246. my(@commandtable, %commands, @commands);# command lists
  247. my($aclsort) = ("ipsort"); # ACL sorting mode
  248. my($filter_commstr); # SNMP community string filtering
  249. my($filter_pwds); # password filtering mode
  250. my($platform); # platform/cpu type
  251.  
  252. # This routine is used to print out the router configuration
  253. sub ProcessHistory {
  254. my($new_hist_tag,$new_command,$command_string,@string) = (@_);
  255. if ((($new_hist_tag ne $hist_tag) || ($new_command ne $command))
  256. && scalar(%history)) {
  257. print eval "$command \%history";
  258. undef %history;
  259. }
  260. if (($new_hist_tag) && ($new_command) && ($command_string)) {
  261. if ($history{$command_string}) {
  262. $history{$command_string} = "$history{$command_string}@string";
  263. } else {
  264. $history{$command_string} = "@string";
  265. }
  266. } elsif (($new_hist_tag) && ($new_command)) {
  267. $history{++$#history} = "@string";
  268. } else {
  269. print "@string";
  270. }
  271. $hist_tag = $new_hist_tag;
  272. $command = $new_command;
  273. 1;
  274. }
  275.  
  276. sub numerically { $a <=> $b; }
  277.  
  278. # This is a sort routine that will sort numerically on the
  279. # keys of a hash as if it were a normal array.
  280. sub keynsort {
  281. local(%lines) = @_;
  282. local($i) = 0;
  283. local(@sorted_lines);
  284. foreach $key (sort numerically keys(%lines)) {
  285. $sorted_lines[$i] = $lines{$key};
  286. $i++;
  287. }
  288. @sorted_lines;
  289. }
  290.  
  291. # This is a sort routine that will sort on the
  292. # keys of a hash as if it were a normal array.
  293. sub keysort {
  294. local(%lines) = @_;
  295. local($i) = 0;
  296. local(@sorted_lines);
  297. foreach $key (sort keys(%lines)) {
  298. $sorted_lines[$i] = $lines{$key};
  299. $i++;
  300. }
  301. @sorted_lines;
  302. }
  303.  
  304. # This is a sort routine that will sort on the
  305. # values of a hash as if it were a normal array.
  306. sub valsort{
  307. local(%lines) = @_;
  308. local($i) = 0;
  309. local(@sorted_lines);
  310. foreach $key (sort values %lines) {
  311. $sorted_lines[$i] = $key;
  312. $i++;
  313. }
  314. @sorted_lines;
  315. }
  316.  
  317. # This is a numerical sort routine (ascending).
  318. sub numsort {
  319. local(%lines) = @_;
  320. local($i) = 0;
  321. local(@sorted_lines);
  322. foreach $num (sort {$a <=> $b} keys %lines) {
  323. $sorted_lines[$i] = $lines{$num};
  324. $i++;
  325. }
  326. @sorted_lines;
  327. }
  328.  
  329. # This is a sort routine that will sort on the
  330. # ip address when the ip address is anywhere in
  331. # the strings.
  332. sub ipsort {
  333. local(%lines) = @_;
  334. local($i) = 0;
  335. local(@sorted_lines);
  336. foreach $addr (sort sortbyipaddr keys %lines) {
  337. $sorted_lines[$i] = $lines{$addr};
  338. $i++;
  339. }
  340. @sorted_lines;
  341. }
  342.  
  343. # These two routines will sort based upon IP addresses
  344. sub ipaddrval {
  345. my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#);
  346. $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0]));
  347. }
  348. sub sortbyipaddr {
  349. &ipaddrval($a) <=> &ipaddrval($b);
  350. }
  351.  
  352. # This routine parses "show version"
  353. sub ShowVersion {
  354. print STDERR " In ShowVersion: $_" if ($debug);
  355.  
  356. while (<INPUT>) {
  357. tr/\015//d;
  358. last if(/^$prompt/);
  359. next if(/^(\s*|\s*$cmd\s*)$/);
  360. return(-1) if (/command authorization failed/i);
  361.  
  362. if (/(lynxos|kernel) Version: .* (\S+)/i) {
  363. $platform = $2;
  364. }
  365. /Procket/ && ProcessHistory("COMMENTS","keysort","B0", "! $_") && next;
  366. /System Uptime:/ && next;
  367. /Protocol Uptime:/ && next;
  368. ProcessHistory("COMMENTS","keysort","B0", "!$_") && next;
  369.  
  370. }
  371. return(0);
  372. }
  373.  
  374. # This routine parses "show package"
  375. sub ShowPackage {
  376. print STDERR " In ShowPackage: $_" if ($debug);
  377.  
  378. while (<INPUT>) {
  379. tr/\015//d;
  380. last if(/^$prompt/);
  381. next if(/^(\s*|\s*$cmd\s*)$/);
  382. return(-1) if (/command authorization failed/i);
  383.  
  384. ProcessHistory("COMMENTS","keysort","C0", "! $_") && next;
  385.  
  386. }
  387. return(0);
  388. }
  389.  
  390. # This routine parses "show hardware"
  391. sub ShowHardware {
  392. print STDERR " In ShowHardware: $_" if ($debug);
  393.  
  394. while (<INPUT>) {
  395. tr/\015//d;
  396. last if(/^$prompt/);
  397. next if(/^(\s*|\s*$cmd\s*)$/);
  398. # skip show hardware on titanium
  399. return(0) if ($platform =~ /i386/i);
  400. return(-1) if (/command authorization failed/i);
  401. return(-1) if (/cli: couldn.t communicate with/);
  402.  
  403. ProcessHistory("COMMENTS","keysort","D0", "! $_") && next;
  404.  
  405. }
  406. return(0);
  407. }
  408.  
  409. # This routine parses "show inventory"
  410. sub ShowInventory {
  411. print STDERR " In ShowInventory: $_" if ($debug);
  412.  
  413. while (<INPUT>) {
  414. tr/\015//d;
  415. last if(/^$prompt/);
  416. next if(/^(\s*|\s*$cmd\s*)$/);
  417. return(0) if (/^\s+\^/);
  418. return(-1) if (/command authorization failed/i);
  419.  
  420. /Procket/ && ProcessHistory("COMMENTS","keysort","E0", "! $_") && next;
  421. /System Uptime:/ && next;
  422. /Protocol Uptime:/ && next;
  423. ProcessHistory("COMMENTS","keysort","E0", "!$_") && next;
  424.  
  425. }
  426. return(0);
  427. }
  428.  
  429. # This routine processes a "write term"
  430. sub WriteTerm {
  431. print STDERR " In WriteTerm: $_" if ($debug);
  432.  
  433. while (<INPUT>) {
  434. tr/\015//d;
  435. last if(/^$prompt/);
  436. return(-1) if (/command authorization failed/i);
  437.  
  438. /Non-Volatile memory is in use/ && return(-1); # NvRAM is locked
  439. # skip the crap
  440. if (/^(##+$|(Building|Current) configuration)/i) {
  441. while (<INPUT>) {
  442. next if (/^Current configuration\s*:/i);
  443. next if (/^([%!].*|\s*)$/);
  444. last;
  445. }
  446. tr/\015//d;
  447. }
  448. # some versions have other crap mixed in with the bits in the
  449. # block above
  450. /^! Last Changed:/ && next;
  451.  
  452. # Dog gone Cool matches to process the rest of the config
  453. # /^tftp-server flash / && next; # kill any tftp remains
  454. # /^ntp clock-period / && next; # kill ntp clock-period
  455. # /^ length / && next; # kill length on serial lines
  456. # /^ width / && next; # kill width on serial lines
  457. # /^ clockrate / && next; # kill clockrate on serial interfaces
  458.  
  459. if (/^(enable secret( level \d)?) / && $filter_pwds >= 2) {
  460. ProcessHistory("ENABLE","","","!$1 <removed>\n");
  461. next;
  462. }
  463. if (/^username (\S+)(\s.*)? password ((\d) \S+|\S+)/) {
  464. if ($filter_pwds == 2) {
  465. ProcessHistory("USER","keysort","$1","!username $1$2 password <removed>\n");
  466. } elsif ($filter_pwds == 1 && $4 ne "5"){
  467. ProcessHistory("USER","keysort","$1","!username $1$2 password <removed>\n");
  468. } else {
  469. ProcessHistory("USER","keysort","$1","$_");
  470. }
  471. next;
  472. }
  473.  
  474. # prune passwords {bgp, ...}
  475. if (/^(\s*)password / && $filter_pwds >= 1) {
  476. ProcessHistory("","","","!$1password <removed>\n");
  477. next;
  478. }
  479. # prune authentication keys {vrrp vrid N, router isis...}
  480. if (/^(\s*authentication \S+ key) / && $filter_pwds >= 1) {
  481. ProcessHistory("","","","!$1 <removed>\n");
  482. next;
  483. }
  484. if (/^(\s*authentication-key) \d \S+( .*)/ && $filter_pwds >= 1) {
  485. ProcessHistory("","","","!$1 <removed>$2\n");
  486. next;
  487. }
  488.  
  489. # if (/^\s*neighbor (\S*) password / && $filter_pwds >= 1) {
  490. # ProcessHistory("","","","! neighbor $1 password <removed>\n");
  491. # next;
  492. # }
  493. # if (/^(ppp .* password) 7 .*/ && $filter_pwds >= 1) {
  494. # ProcessHistory("","","","!$1 <removed>\n"); next;
  495. # }
  496. # if (/^(ip ftp password) / && $filter_pwds >= 1) {
  497. # ProcessHistory("","","","!$1 <removed>\n"); next;
  498. # }
  499.  
  500. # prune ospf keys
  501. if (/^( ip ospf authentication-key) / && $filter_pwds >= 1) {
  502. ProcessHistory("","","","!$1 <removed>\n"); next;
  503. }
  504. # this is reversable, despite 'md5' in the cmd
  505. if (/^( ip ospf message-digest-key \d+ md5) / && $filter_pwds >= 1) {
  506. ProcessHistory("","","","!$1 <removed>\n"); next;
  507. }
  508. # this is reversable, despite 'md5' in the cmd
  509. if (/^(\s*message-digest-key \d+ md5) / && $filter_pwds >= 1) {
  510. ProcessHistory("","","","!$1 <removed>\n"); next;
  511. }
  512.  
  513. # if (/^((crypto )?isakmp key) \S+ / && $filter_pwds >= 1) {
  514. # ProcessHistory("","","","!$1 <removed> $'"); next;
  515. # }
  516.  
  517. # sort ip explicit-paths.
  518. if (/^ip explicit-path name (\S+)/) {
  519. my($key) = $1;
  520. my($expath) = $_;
  521. while (<INPUT>) {
  522. tr/\015//d;
  523. last if (/^$prompt/);
  524. last if (/^$prompt/ || ! /^(ip explicit-path name |[ !])/);
  525. if (/^ip explicit-path name (\S+)/) {
  526. ProcessHistory("EXPATH","keysort","$key","$expath");
  527. $key = $1;
  528. $expath = $_;
  529. } else {
  530. $expath .= $_;
  531. }
  532. }
  533. ProcessHistory("EXPATH","keysort","$key","$expath");
  534. }
  535.  
  536. # sort route-maps
  537. if (/^route-map (\S+)/) {
  538. my($key) = $1;
  539. my($routemap) = $_;
  540. while (<INPUT>) {
  541. tr/\015//d;
  542. last if (/^$prompt/ || ! /^(route-map |[ !])/);
  543. if (/^route-map (\S+)/) {
  544. ProcessHistory("ROUTEMAP","keysort","$key","$routemap");
  545. $key = $1;
  546. $routemap = $_;
  547. } else {
  548. $routemap .= $_;
  549. }
  550. }
  551. ProcessHistory("ROUTEMAP","keysort","$key","$routemap");
  552. }
  553.  
  554. # filter out any RCS/CVS tags to avoid confusing local CVS storage
  555. s/\$(Revision|Id):/ $1:/;
  556.  
  557. # # order access-lists
  558. # /^access-list\s+(\d\d?)\s+(\S+)\s+(\S+)/ &&
  559. # ProcessHistory("ACL $1 $2","$aclsort","$3","$_") && next;
  560. # # order extended access-lists
  561. # /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+host\s+(\S+)/ &&
  562. # ProcessHistory("EACL $1 $2","$aclsort","$3","$_") && next;
  563. # /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+(\d\S+)/ &&
  564. # ProcessHistory("EACL $1 $2","$aclsort","$3","$_") && next;
  565. # /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+any/ &&
  566. # ProcessHistory("EACL $1 $2","$aclsort","0.0.0.0","$_") && next;
  567. # # order arp lists
  568. # /^arp\s+(\d+\.\d+\.\d+\.\d+)\s+/ &&
  569. # ProcessHistory("ARP","$aclsort","$1","$_") && next;
  570. # /^ip prefix-list\s+(\S+)\s+seq\s+(\d+)\s+(permit|deny)\s+(\d\S+)(\/.*)$/ &&
  571. # ProcessHistory("PACL $1 $3","$aclsort","$4","ip prefix-list $1 $3 $4$5\n")
  572. # && next;
  573.  
  574. # order logging statements
  575. /^logging (\d+\.\d+\.\d+\.\d+)/ &&
  576. ProcessHistory("LOGGING","ipsort","$1","$_") && next;
  577.  
  578. # order/prune snmp-server host statements
  579. # we only prune lines of the form
  580. # snmp-server host a.b.c.d <community>
  581. if (/^snmp-server host (\d+\.\d+\.\d+\.\d+) /) {
  582. if ($filter_commstr) {
  583. my($ip) = $1;
  584. my($line) = "snmp-server host $ip";
  585. my(@tokens) = split(' ', $');
  586. my($token);
  587. while ($token = shift(@tokens)) {
  588. if ($token eq 'version') {
  589. $line .= " " . join(' ', ($token, shift(@tokens)));
  590. } elsif ($token =~ /^(informs?|traps?|(no)?auth)$/) {
  591. $line .= " " . $token;
  592. } else {
  593. $line = "!$line " . join(' ', ("<removed>", join(' ',@tokens)));
  594. last;
  595. }
  596. }
  597. ProcessHistory("SNMPSERVERHOST","ipsort","$ip","$line\n");
  598. } else {
  599. ProcessHistory("SNMPSERVERHOST","ipsort","$1","$_");
  600. }
  601. next;
  602. }
  603. if (/^(snmp-server community) (\S+)/) {
  604. if ($filter_commstr) {
  605. ProcessHistory("SNMPSERVERCOMM","keysort","$_","!$1 <removed>$'") && next;
  606. } else {
  607. ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && next;
  608. }
  609. }
  610.  
  611. # prune tacacs/radius server keys
  612. if (/^(tacacs-server|radius-server) key / && $filter_pwds >= 1) {
  613. ProcessHistory("","","","!$1 key <removed>\n"); next;
  614. }
  615. if (/^(tacacs-server host \S+( .*)? key) (\d )?\S+/
  616. && $filter_pwds >= 1) {
  617. ProcessHistory("","","","!$1 <removed>\n"); next;
  618. }
  619.  
  620. # order clns host statements
  621. # /^clns host \S+ (\S+)/ &&
  622. # ProcessHistory("CLNS","keysort","$1","$_") && next;
  623.  
  624. # prune vrrp password
  625. if (/^( ip vrrp authentication .* key) / && $filter_pwds >= 1) {
  626. ProcessHistory("","","","!$1 <removed>\n"); next;
  627. }
  628. # prune isis password
  629. if (/^( isis authentication-key) \d \S+/ && $filter_pwds >= 1) {
  630. ProcessHistory("","","","!$1 <removed>$'"); next;
  631. }
  632. # prune msdp password
  633. if (/^(ip msdp password \S+) / && $filter_pwds >= 1) {
  634. ProcessHistory("","","","!$1 <removed>\n"); next;
  635. }
  636. # delete ntp auth password - this md5 is a reversable too
  637. if (/^(ntp authentication-key \d+ md5) / && $filter_pwds >= 1) {
  638. ProcessHistory("","","","!$1 <removed>\n"); next;
  639. }
  640. # order ntp peers/servers
  641. if (/^ntp (server|peer) (\d+)\.(\d+)\.(\d+)\.(\d+)/) {
  642. $sortkey = sprintf("$1 %03d%03d%03d%03d",$2,$3,$4,$5);
  643. ProcessHistory("NTP","keysort",$sortkey,"$_");
  644. next;
  645. }
  646.  
  647. # # order ip host line statements
  648. # /^ip host line(\d+)/ &&
  649. # ProcessHistory("IPHOST","numsort","$1","$_") && next;
  650. # # order ip nat source static statements
  651. # /^ip nat (\S+) source static (\S+)/ &&
  652. # ProcessHistory("IP NAT $1","ipsort","$2","$_") && next;
  653. # # order atm map-list statements
  654. # /^\s+ip\s+(\d+\.\d+\.\d+\.\d+)\s+atm-vc/ &&
  655. # ProcessHistory("ATM map-list","ipsort","$1","$_") && next;
  656. # # order ip rcmd lines
  657. # /^ip rcmd/ && ProcessHistory("RCMD","keysort","$_","$_") && next;
  658.  
  659. # catch anything that wasnt matched above.
  660. ProcessHistory("","","","$_");
  661. # end of config.
  662. if (/^end$/) {
  663. $found_end = 1;
  664. return(1);
  665. }
  666. }
  667. return(0);
  668. }
  669.  
  670. # dummy function
  671. sub DoNothing {print STDOUT;}
  672.  
  673. # Main
  674. @commandtable = (
  675. {'show version all' => 'ShowVersion'},
  676. {'show package' => 'ShowPackage'},
  677. {'show hardware' => 'ShowHardware'},
  678. {'show inventory' => 'ShowInventory'},
  679. {'write term' => 'WriteTerm'}
  680. );
  681. # Use an array to preserve the order of the commands and a hash for mapping
  682. # commands to the subroutine and track commands that have been completed.
  683. @commands = map(keys(%$_), @commandtable);
  684. %commands = map(%$_, @commandtable);
  685.  
  686. $cisco_cmds=join(";",@commands);
  687. $cmds_regexp = join("|", map quotemeta($_), @commands);
  688.  
  689. if (length($host) == 0) {
  690. if ($file) {
  691. print(STDERR "Too few arguments: file name required\n");
  692. exit(1);
  693. } else {
  694. print(STDERR "Too few arguments: host name required\n");
  695. exit(1);
  696. }
  697. }
  698. open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n";
  699. select(OUTPUT);
  700. # make OUTPUT unbuffered if debugging
  701. if ($debug) { $| = 1; }
  702.  
  703. if ($file) {
  704. print STDERR "opening file $host\n" if ($debug);
  705. print STDOUT "opening file $host\n" if ($log);
  706. open(INPUT,"<$host") || die "open failed for $host: $!\n";
  707. } else {
  708. print STDERR "executing clogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($debug);
  709. print STDOUT "executing clogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($log);
  710. if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
  711. system "clogin -t $timeo -c \"$cisco_cmds\" $host </dev/null > $host.raw 2>&1" || die "clogin failed for $host: $!\n";
  712. open(INPUT, "< $host.raw") || die "clogin failed for $host: $!\n";
  713. } else {
  714. open(INPUT,"clogin -t $timeo -c \"$cisco_cmds\" $host </dev/null |") || die "clogin failed for $host: $!\n";
  715. }
  716. }
  717.  
  718. # determine ACL sorting mode
  719. if ($ENV{"ACLSORT"} =~ /no/i) {
  720. $aclsort = "";
  721. }
  722. # determine community string filtering mode
  723. if (defined($ENV{"NOCOMMSTR"}) &&
  724. ($ENV{"NOCOMMSTR"} =~ /yes/i || $ENV{"NOCOMMSTR"} =~ /^$/)) {
  725. $filter_commstr = 1;
  726. } else {
  727. $filter_commstr = 0;
  728. }
  729. # determine password filtering mode
  730. if ($ENV{"FILTER_PWDS"} =~ /no/i) {
  731. $filter_pwds = 0;
  732. } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) {
  733. $filter_pwds = 2;
  734. } else {
  735. $filter_pwds = 1;
  736. }
  737.  
  738. ProcessHistory("","","","!RANCID-CONTENT-TYPE: procket\n!\n");
  739. ProcessHistory("COMMENTS","keysort","B0","!\n"); # show version
  740. ProcessHistory("COMMENTS","keysort","C0","!\n"); # show package
  741. ProcessHistory("COMMENTS","keysort","D0","!\n"); # show hardware
  742. ProcessHistory("COMMENTS","keysort","E0","!\n"); # show inventory
  743. ProcessHistory("COMMENTS","keysort","Z0","!\n");
  744. TOP: while(<INPUT>) {
  745. tr/\015//d;
  746. if (/\#\s?exit$/) {
  747. $clean_run=1;
  748. last;
  749. }
  750. if (/^Error:/) {
  751. print STDOUT ("$host clogin error: $_");
  752. print STDERR ("$host clogin error: $_") if ($debug);
  753. $clean_run=0;
  754. last;
  755. }
  756. while (/#\s*($cmds_regexp)\s*$/) {
  757. $cmd = $1;
  758. if (!defined($prompt)) {$prompt = ($_ =~ /^([^#]+#)/)[0]; }
  759. print STDERR ("HIT COMMAND:$_") if ($debug);
  760. if (! defined($commands{$cmd})) {
  761. print STDERR "$host: found unexpected command - \"$cmd\"\n";
  762. $clean_run = 0;
  763. last TOP;
  764. }
  765. $rval = &{$commands{$cmd}};
  766. delete($commands{$cmd});
  767. if ($rval == -1) {
  768. $clean_run = 0;
  769. last TOP;
  770. }
  771. }
  772. }
  773. print STDOUT "Done $logincmd: $_\n" if ($log);
  774. # Flush History
  775. ProcessHistory("","","","");
  776. # Cleanup
  777. close(INPUT);
  778. close(OUTPUT);
  779.  
  780. if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
  781. unlink("$host.raw") if (! $debug);
  782. }
  783.  
  784. # check for completeness
  785. if (scalar(%commands) || !$clean_run || !$found_end) {
  786. if (scalar(%commands)) {
  787. printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands)));
  788. printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug);
  789. }
  790. if (!$clean_run || !$found_end) {
  791. print STDOUT "$host: End of run not found\n";
  792. print STDERR "$host: End of run not found\n" if ($debug);
  793. system("/usr/bin/tail -1 $host.new");
  794. }
  795. unlink "$host.new" if (! $debug);
  796. }
  797. #! /usr/bin/perl
  798. ##
  799. ## $Id: rancid.in 3123 2015-05-28 22:39:32Z heas $
  800. ##
  801. ## rancid 3.4.1
  802. ## Copyright (c) 1997-2016 by Terrapin Communications, Inc.
  803. ## All rights reserved.
  804. ##
  805. ## This code is derived from software contributed to and maintained by
  806. ## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan,
  807. ## Pete Whiting, Austin Schutz, and Andrew Fort.
  808. ##
  809. ## Redistribution and use in source and binary forms, with or without
  810. ## modification, are permitted provided that the following conditions
  811. ## are met:
  812. ## 1. Redistributions of source code must retain the above copyright
  813. ## notice, this list of conditions and the following disclaimer.
  814. ## 2. Redistributions in binary form must reproduce the above copyright
  815. ## notice, this list of conditions and the following disclaimer in the
  816. ## documentation and/or other materials provided with the distribution.
  817. ## 3. All advertising materials mentioning features or use of this software
  818. ## must display the following acknowledgement:
  819. ## This product includes software developed by Terrapin Communications,
  820. ## Inc. and its contributors for RANCID.
  821. ## 4. Neither the name of Terrapin Communications, Inc. nor the names of its
  822. ## contributors may be used to endorse or promote products derived from
  823. ## this software without specific prior written permission.
  824. ## 5. It is requested that non-binding fixes and modifications be contributed
  825. ## back to Terrapin Communications, Inc.
  826. ##
  827. ## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS
  828. ## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  829. ## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  830. ## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
  831. ## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  832. ## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  833. ## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  834. ## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  835. ## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  836. ## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  837. ## POSSIBILITY OF SUCH DAMAGE.
  838. #
  839. # RANCID - Really Awesome New Cisco confIg Differ
  840. #
  841. # rancid - generalized rancid module; command schedule is derived from the
  842. # rancid.types.{base,conf} configurations.
  843. #
  844. # usage: rancid [-dhltCV] -t device_type [-f filename | hostname]
  845. #
  846. use 5.010;
  847. use strict 'vars';
  848. use warnings;
  849. no warnings 'uninitialized';
  850. use Exporter;
  851. use Getopt::Std;
  852. our($opt_d, $opt_f, $opt_h, $opt_l, $opt_t, $opt_C, $opt_V);
  853. getopts('dfhlt:CV');
  854. BEGIN {
  855. push(@INC, "/usr/local/rancid/lib/rancid");
  856. }
  857. use rancid;
  858. our @ISA = qw(Exporter rancid);
  859.  
  860. sub usage()
  861. {
  862. print STDERR "rancid [-dhltCV] -t device_type [-f filename | hostname]\n";
  863. exit 64;
  864. }
  865.  
  866. if ($opt_h) {
  867. usage();
  868. }
  869.  
  870. # basic initialization
  871. rancidinit();
  872.  
  873. # load device type spec, build @commandtable and load modules
  874. if (loadtype($devtype)) {
  875. die "Couldn't load device type spec for $rancid::devtype\n";
  876. }
  877. if (! defined($lscript)) {
  878. die "login script not defined for device type $rancid::devtype\n";
  879. }
  880.  
  881. # open the temporary file for the digested output
  882. open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n";
  883. select(OUTPUT);
  884. if (length($#modules)) {
  885. my($module);
  886.  
  887. foreach $module (@modules) {
  888. (my $file = $module) =~ s/::/\//g;
  889. my($err) = 0;
  890.  
  891. # call module->init(); we expect 0 as success, as god intended it
  892. eval "\$err = ". $module ."::init();";
  893. if ($@) {
  894. printf(STDERR "loadtype: initializing $module failed: %s\n", $@);
  895. exit 1;
  896. } elsif ($err) {
  897. printf(STDERR "loadtype: %s::init() returned failure\n", $module);
  898. exit 1;
  899. }
  900. }
  901. }
  902.  
  903. # open the input, a pre-collected file or start a login for a login stream or
  904. # temporary file
  905. if ($file) {
  906. print STDERR "opening file $host\n" if ($debug);
  907. print STDOUT "opening file $host\n" if ($log);
  908. open(INPUT,"<$host") || die "open failed for $host: $!\n";
  909. } else {
  910. print STDERR "executing $lscript -t $timeo -c\"$commandstr\" $host\n" if ($debug);
  911. print STDOUT "executing $lscript -t $timeo -c\"$commandstr\" $host\n" if ($log);
  912. if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
  913. system "$lscript -t $timeo -c \"$commandstr\" $host </dev/null > $host.raw 2>&1" || die "clogin failed for $host: $!\n";
  914. open(INPUT, "< $host.raw") || die "clogin failed for $host: $!\n";
  915. } else {
  916. open(INPUT,"$lscript -t $timeo -c \"$commandstr\" $host </dev/null |") || die "clogin failed for $host: $!\n";
  917. }
  918. }
  919.  
  920. # loop over the input using the provided input/main loop
  921. if (!defined($inloop) || length($inloop) < 1) {
  922. die "inloop is not configured for device type $devtype";
  923. }
  924. eval($inloop ."(*INPUT, *OUTPUT);") && die "${inloop} failed: $@\n";
  925.  
  926. print STDOUT "Done $lscript: $_\n" if ($log);
  927. # Flush History
  928. ProcessHistory("","","","");
  929. # Cleanup
  930. close(INPUT);
  931. close(OUTPUT);
  932.  
  933. if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
  934. unlink("$host.raw") if (! $debug);
  935. }
  936.  
  937. # check for completeness
  938. if (scalar(%commands) || !$clean_run || !$found_end) {
  939. if (scalar(keys %commands) eq $commandcnt) {
  940. printf(STDERR "$host: missed cmd(s): all commands\n");
  941. } elsif (scalar(%commands)) {
  942. printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands)));
  943. printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug);
  944. }
  945. if (!$clean_run || !$found_end) {
  946. print STDOUT "$host: End of run not found\n";
  947. print STDERR "$host: End of run not found\n" if ($debug);
  948. system("/usr/bin/tail -1 $host.new");
  949. }
  950. unlink "$host.new" if (! $debug);
  951. }
  952. #! /bin/sh
  953. ##
  954. ## $Id: rancid-cvs.in 3055 2015-03-12 18:24:07Z heas $
  955. ##
  956. ## rancid 3.4.1
  957. ## Copyright (c) 1997-2016 by Terrapin Communications, Inc.
  958. ## All rights reserved.
  959. ##
  960. ## This code is derived from software contributed to and maintained by
  961. ## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan,
  962. ## Pete Whiting, Austin Schutz, and Andrew Fort.
  963. ##
  964. ## Redistribution and use in source and binary forms, with or without
  965. ## modification, are permitted provided that the following conditions
  966. ## are met:
  967. ## 1. Redistributions of source code must retain the above copyright
  968. ## notice, this list of conditions and the following disclaimer.
  969. ## 2. Redistributions in binary form must reproduce the above copyright
  970. ## notice, this list of conditions and the following disclaimer in the
  971. ## documentation and/or other materials provided with the distribution.
  972. ## 3. All advertising materials mentioning features or use of this software
  973. ## must display the following acknowledgement:
  974. ## This product includes software developed by Terrapin Communications,
  975. ## Inc. and its contributors for RANCID.
  976. ## 4. Neither the name of Terrapin Communications, Inc. nor the names of its
  977. ## contributors may be used to endorse or promote products derived from
  978. ## this software without specific prior written permission.
  979. ## 5. It is requested that non-binding fixes and modifications be contributed
  980. ## back to Terrapin Communications, Inc.
  981. ##
  982. ## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS
  983. ## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  984. ## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  985. ## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
  986. ## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  987. ## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  988. ## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  989. ## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  990. ## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  991. ## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  992. ## POSSIBILITY OF SUCH DAMAGE.
  993. #
  994. # Create all of the misc files & dirs needed for each group and import them
  995. # into CVS or Subversion.
  996. #
  997. # rancid-cvs
  998. #
  999.  
  1000. # Read in the environment
  1001. ENVFILE="/usr/local/rancid/etc/rancid.conf"
  1002.  
  1003. # print a usage message to stderr
  1004. pr_usage() {
  1005. echo "usage: $0 [-V] [-f config_file] [group [group ...]]" >&2;
  1006. }
  1007.  
  1008. # command-line options
  1009. # -V print version string
  1010. if [ $# -ge 1 ] ; then
  1011. while [ 1 ] ; do
  1012. case $1 in
  1013. -V)
  1014. echo "rancid 3.4.1"
  1015. exit 0
  1016. ;;
  1017. -f)
  1018. shift
  1019. # next arg is the alternate config file name
  1020. ENVFILE="$1"
  1021. if [ -z $ENVFILE ]; then
  1022. pr_usage
  1023. exit 1
  1024. fi
  1025. shift
  1026. ;;
  1027. -*)
  1028. echo "unknown option: $1" >&2
  1029. pr_usage
  1030. exit 1
  1031. ;;
  1032. *)
  1033. break;
  1034. ;;
  1035. esac
  1036. done
  1037. fi
  1038.  
  1039. . $ENVFILE
  1040.  
  1041. # Base dir
  1042. if [ ! -d $BASEDIR ]; then
  1043. mkdir -p $BASEDIR ||
  1044. (echo "Could not create local state directory: $BASEDIR"; exit 1)
  1045. fi
  1046.  
  1047. cd $BASEDIR
  1048.  
  1049. # RCS system
  1050. RCSSYS=${RCSSYS:=cvs};
  1051. if [ $RCSSYS != "cvs" -a $RCSSYS != "svn" -a $RCSSYS != "git" ] ; then
  1052. echo "$RCSSYS is not a valid value for RCSSYS. See rancid.conf(5)." >&2
  1053. exit 1
  1054. fi
  1055.  
  1056. # Top level RCS stuff
  1057. case $RCSSYS in
  1058. cvs )
  1059. if [ ! -d $CVSROOT ]; then
  1060. cvs -d $CVSROOT init
  1061. fi
  1062. ;;
  1063. svn )
  1064. if echo "$CVSROOT" | grep -q "://"; then
  1065. # do nothing because CVSROOT is some sort of a URL
  1066. # also assume the repository has already been provisioned
  1067. :
  1068. else
  1069. if ! svn ls "file://$CVSROOT" >/dev/null 2>&1; then
  1070. svnadmin create $CVSROOT --fs-type fsfs
  1071. fi
  1072. CVSROOT="file://$CVSROOT"
  1073. fi
  1074. ;;
  1075. git)
  1076. if echo "$CVSROOT" | grep -q "://"; then
  1077. # do nothing because CVSROOT is some sort of a URL
  1078. # also assume the repository has already been provisioned
  1079. :
  1080. else
  1081. if [ ! -d $CVSROOT ]; then
  1082. mkdir $CVSROOT
  1083. fi
  1084. fi
  1085. ;;
  1086. esac
  1087.  
  1088. # Log dir
  1089. if [ ! -d logs ]; then
  1090. mkdir logs
  1091. fi
  1092.  
  1093. # Which groups to do
  1094. if [ $# -ge 1 ] ; then
  1095. LIST_OF_GROUPS="$*"; export LIST_OF_GROUPS
  1096. elif [ "$LIST_OF_GROUPS" = "" ] ; then
  1097. echo "LIST_OF_GROUPS is empty in $ENVFILE"
  1098. exit 1
  1099. fi
  1100.  
  1101. for GROUP in `echo $LIST_OF_GROUPS` ;
  1102. do
  1103. DIR=$BASEDIR/$GROUP
  1104.  
  1105. # Directory for the group and the configs
  1106. if [ ! -d $DIR ]; then
  1107. mkdir -p $DIR
  1108. cd $DIR
  1109. case $RCSSYS in
  1110. cvs )
  1111. cvs import -m "$GROUP" $GROUP new rancid
  1112. cd $BASEDIR
  1113. cvs checkout $GROUP
  1114. ;;
  1115. svn )
  1116. svn import -m "$GROUP" . $CVSROOT/$GROUP
  1117. cd $BASEDIR
  1118. svn checkout $CVSROOT/$GROUP $GROUP
  1119. cd $DIR
  1120. svn update
  1121. ;;
  1122. git )
  1123. git init --bare $CVSROOT/$GROUP
  1124. git clone $CVSROOT/$GROUP .
  1125. git config --global user.name RANCiD
  1126. git config --global user.email $USER$MAILDOMAIN
  1127. git config --global push.default current
  1128. ;;
  1129. esac
  1130. fi
  1131. cd $DIR
  1132. if [ ! -d configs ]; then
  1133. rm -f configs
  1134. mkdir configs
  1135. if [ $RCSSYS = "git" ]; then
  1136. cat > configs/.gitignore <<EOF
  1137. .old
  1138. *.new
  1139. *.raw
  1140. EOF
  1141. fi
  1142. $RCSSYS add configs
  1143. $RCSSYS commit -m 'new' configs
  1144. if [ $RCSSYS = "git" ]; then
  1145. git push
  1146. fi
  1147. fi
  1148.  
  1149. # config and status files
  1150. if [ ! -f routers.all ]; then
  1151. touch routers.all
  1152. fi
  1153. if [ ! -f routers.down ]; then
  1154. touch routers.down
  1155. fi
  1156. if [ ! -f routers.up ]; then
  1157. touch routers.up
  1158. fi
  1159. if [ ! -f router.db ]; then
  1160. touch router.db
  1161. $RCSSYS add router.db
  1162. $RCSSYS commit -m 'new' router.db
  1163. if [ $RCSSYS = "git" ]; then
  1164. git push
  1165. fi
  1166. fi
  1167. done
  1168. #! /usr/bin/perl
  1169. ##
  1170. ## $Id: rancid-fe.in 3018 2015-01-11 05:51:49Z heas $
  1171. ##
  1172. ## rancid 3.4.1
  1173. ## Copyright (c) 1997-2016 by Terrapin Communications, Inc.
  1174. ## All rights reserved.
  1175. ##
  1176. ## This code is derived from software contributed to and maintained by
  1177. ## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan,
  1178. ## Pete Whiting, Austin Schutz, and Andrew Fort.
  1179. ##
  1180. ## Redistribution and use in source and binary forms, with or without
  1181. ## modification, are permitted provided that the following conditions
  1182. ## are met:
  1183. ## 1. Redistributions of source code must retain the above copyright
  1184. ## notice, this list of conditions and the following disclaimer.
  1185. ## 2. Redistributions in binary form must reproduce the above copyright
  1186. ## notice, this list of conditions and the following disclaimer in the
  1187. ## documentation and/or other materials provided with the distribution.
  1188. ## 3. All advertising materials mentioning features or use of this software
  1189. ## must display the following acknowledgement:
  1190. ## This product includes software developed by Terrapin Communications,
  1191. ## Inc. and its contributors for RANCID.
  1192. ## 4. Neither the name of Terrapin Communications, Inc. nor the names of its
  1193. ## contributors may be used to endorse or promote products derived from
  1194. ## this software without specific prior written permission.
  1195. ## 5. It is requested that non-binding fixes and modifications be contributed
  1196. ## back to Terrapin Communications, Inc.
  1197. ##
  1198. ## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS
  1199. ## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  1200. ## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  1201. ## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
  1202. ## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  1203. ## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  1204. ## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  1205. ## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  1206. ## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  1207. ## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  1208. ## POSSIBILITY OF SUCH DAMAGE.
  1209. #
  1210. # rancid-FE - front-end to rancid/jrancid/etc. for use with par.
  1211. #
  1212. # usage: rancid-fe <router>;<vendor>
  1213. #
  1214.  
  1215. require 5;
  1216.  
  1217. my($script);
  1218. my($router, $devtype) = split('\;', $ARGV[0]);
  1219. $devtype =~ tr/[A-Z]/[a-z]/;
  1220. if (! length($devtype)) {
  1221. printf(STDERR "unknown router manufacturer for $router: $devtype\n");
  1222. exit(-1);
  1223. }
  1224.  
  1225. # XXX use rancid::loadtype() to parse these files.
  1226. foreach $file ("/usr/local/rancid/etc/rancid.types.base",
  1227. "/usr/local/rancid/etc/rancid.types.conf") {
  1228. open(INPUT, "< $file") || die "Could not open $file: $!";
  1229. while (<INPUT>) {
  1230. chomp;
  1231. my($type, $directive, $value) = split('\;');
  1232. $type =~ tr/[A-Z]/[a-z]/;
  1233. $directive =~ tr/[A-Z]/[a-z]/;
  1234. if ($type eq $devtype && $directive eq "script") {
  1235. $script = $value;
  1236. close(INPUT);
  1237. goto FOUND;
  1238. }
  1239. }
  1240. close(INPUT);
  1241. }
  1242.  
  1243. FOUND:
  1244. if (! defined($script)) {
  1245. printf(STDERR "unknown router manufacturer for $router: $devtype\n");
  1246. exit(-1);
  1247. } else {
  1248. exec($script . " $router");
  1249. }
  1250.  
  1251. printf(STDERR "exec($script) failed router manufacturer $devtype: $!\n");
  1252. exit(-1);
  1253. #! /bin/sh
  1254. ##
  1255. ## $Id: rancid-run.in 3232 2016-01-21 17:46:40Z heas $
  1256. ##
  1257. ## rancid 3.4.1
  1258. ## Copyright (c) 1997-2016 by Terrapin Communications, Inc.
  1259. ## All rights reserved.
  1260. ##
  1261. ## This code is derived from software contributed to and maintained by
  1262. ## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan,
  1263. ## Pete Whiting, Austin Schutz, and Andrew Fort.
  1264. ##
  1265. ## Redistribution and use in source and binary forms, with or without
  1266. ## modification, are permitted provided that the following conditions
  1267. ## are met:
  1268. ## 1. Redistributions of source code must retain the above copyright
  1269. ## notice, this list of conditions and the following disclaimer.
  1270. ## 2. Redistributions in binary form must reproduce the above copyright
  1271. ## notice, this list of conditions and the following disclaimer in the
  1272. ## documentation and/or other materials provided with the distribution.
  1273. ## 3. All advertising materials mentioning features or use of this software
  1274. ## must display the following acknowledgement:
  1275. ## This product includes software developed by Terrapin Communications,
  1276. ## Inc. and its contributors for RANCID.
  1277. ## 4. Neither the name of Terrapin Communications, Inc. nor the names of its
  1278. ## contributors may be used to endorse or promote products derived from
  1279. ## this software without specific prior written permission.
  1280. ## 5. It is requested that non-binding fixes and modifications be contributed
  1281. ## back to Terrapin Communications, Inc.
  1282. ##
  1283. ## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS
  1284. ## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  1285. ## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  1286. ## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
  1287. ## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  1288. ## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  1289. ## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  1290. ## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  1291. ## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  1292. ## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  1293. ## POSSIBILITY OF SUCH DAMAGE.
  1294. #
  1295. # Run rancid for each of the rancid groups defined by $LIST_OF_GROUPS in
  1296. # /usr/local/rancid/etc/rancid.conf or those specified on the command-line.
  1297. #
  1298.  
  1299. # Default ENVFILE, overrideable with -f flag.
  1300. ENVFILE="/usr/local/rancid/etc/rancid.conf"
  1301.  
  1302. TMPDIR=${TMPDIR:=/tmp}; export TMPDIR
  1303.  
  1304. # control_rancid argv
  1305. CR_ARGV=""; export CR_ARGV
  1306.  
  1307. # print a usage message to stderr
  1308. pr_usage() {
  1309. echo "usage: $0 [-V] [-f config_file] [-r device_name] [-m mail rcpt] [group [group ...]]" >&2;
  1310. }
  1311.  
  1312. # command-line options
  1313. # -V
  1314. # -f <config file name>
  1315. # -m <mailto address>
  1316. # -r <device name>
  1317. if [ $# -ge 1 ] ; then
  1318. while [ 1 ] ; do
  1319. case $1 in
  1320. -V)
  1321. echo "rancid 3.4.1"
  1322. exit 0
  1323. ;;
  1324. -f)
  1325. shift
  1326. # next arg is the alternate config file name
  1327. ENVFILE="$1"
  1328. if [ -z $ENVFILE ]; then
  1329. pr_usage
  1330. exit 1
  1331. fi
  1332. CR_ARGV="$CR_ARGV -f $1"; export CR_ARGV
  1333. shift
  1334. ;;
  1335. -m)
  1336. shift
  1337. # next arg is the mailto name
  1338. CR_ARGV="$CR_ARGV -m $1"; export CR_ARGV
  1339. shift
  1340. ;;
  1341. -r)
  1342. shift
  1343. # next arg is the device name
  1344. CR_ARGV="$CR_ARGV -r $1"; export CR_ARGV
  1345. shift
  1346. ;;
  1347. --)
  1348. shift; break;
  1349. ;;
  1350. -h)
  1351. pr_usage
  1352. exit
  1353. ;;
  1354. -*)
  1355. echo "unknown option: $1" >&2
  1356. pr_usage
  1357. exit 1
  1358. ;;
  1359. *)
  1360. break;
  1361. ;;
  1362. esac
  1363. done
  1364. fi
  1365.  
  1366. . $ENVFILE
  1367.  
  1368. # SENDMAIL location
  1369. SENDMAIL=${SENDMAIL:=sendmail};
  1370.  
  1371. if [ $# -ge 1 ] ; then
  1372. LIST_OF_GROUPS="$*"; export LIST_OF_GROUPS
  1373. elif [ "$LIST_OF_GROUPS" = "" ] ; then
  1374. echo "LIST_OF_GROUPS is empty in $ENVFILE"
  1375. exit 1
  1376. fi
  1377.  
  1378. if [ ! -d $LOGDIR ] ; then
  1379. mkdir $LOGDIR || (echo "Could not create log directory: $LOGDIR"; exit 1)
  1380. fi
  1381.  
  1382. for GROUP in $LIST_OF_GROUPS
  1383. do
  1384.  
  1385. LOCKFILE=$TMPDIR/.$GROUP.run.lock
  1386.  
  1387. (
  1388. echo starting: `date`
  1389. echo
  1390.  
  1391. if [ -f $LOCKFILE ]
  1392. then
  1393. echo hourly config diffs failed: $LOCKFILE exists
  1394. ls -l $LOCKFILE
  1395.  
  1396. # Send email if the lock file is old.
  1397. if [ "X$LOCKTIME" = "X" ] ; then
  1398. LOCKTIME=4
  1399. fi
  1400. GRPOLDFILE=`mktemp -q $TMPDIR/.$GROUP.XXXXXX`
  1401. if [ $? -ne 0 ] ; then
  1402. echo "Could not create temporary file for error email" >&2
  1403. exit 1
  1404. fi
  1405. perl -e "\$t = (stat(\"$LOCKFILE\"))[9]; print \"OLD\\n\" if (time() - \$t >= $LOCKTIME*60*60);" > $GRPOLDFILE
  1406. if [ -s $TMPDIR/.$GROUP.old ]
  1407. then
  1408. (
  1409. echo "To: rancid-admin-${GROUP}${MAILDOMAIN}"
  1410. echo "Subject: rancid hung - $GROUP"
  1411. echo "Precedence: bulk"
  1412. echo "Auto-submitted: auto-generated"
  1413. echo "X-Auto-Response-Suppress: All"
  1414. echo ""
  1415.  
  1416. cat <<END
  1417. rancid $GROUP hung on `hostname`? Old lockfile still exists:
  1418. `ls -l $LOCKFILE`
  1419. END
  1420. ) | $SENDMAIL -t $MAILOPTS
  1421. fi
  1422. rm -f $GRPOLDFILE
  1423. exit 1
  1424. else
  1425. trap 'rm -fr $LOCKFILE;exit 1' 1 2 3 6 10 15
  1426. perl -e 'use POSIX;sysopen(FH, $ARGV[1], O_RDWR|O_CREAT|O_EXCL, 0660) or exit 1;print FH "$ARGV[0]\n";' -- $$ $LOCKFILE
  1427. if [ $? -eq 0 ] ; then
  1428. control_rancid $CR_ARGV $GROUP
  1429. trap '' 1 2 3 6 10 15
  1430. rm -f $LOCKFILE
  1431. fi
  1432. trap '' 1 2 3 6 10 15
  1433. fi
  1434.  
  1435. echo
  1436. echo ending: `date`
  1437. ) >$LOGDIR/$GROUP.`date +%Y%m%d.%H%M%S` 2>&1
  1438. done
  1439. #! /usr/bin/expect --
  1440. ##
  1441. ## $Id: rblogin.in 3201 2015-11-05 00:48:01Z heas $
  1442. ##
  1443. ## rancid 3.4.1
  1444. ## Copyright (c) 1997-2016 by Terrapin Communications, Inc.
  1445. ## All rights reserved.
  1446. ##
  1447. ## This code is derived from software contributed to and maintained by
  1448. ## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan,
  1449. ## Pete Whiting, Austin Schutz, and Andrew Fort.
  1450. ##
  1451. ## Redistribution and use in source and binary forms, with or without
  1452. ## modification, are permitted provided that the following conditions
  1453. ## are met:
  1454. ## 1. Redistributions of source code must retain the above copyright
  1455. ## notice, this list of conditions and the following disclaimer.
  1456. ## 2. Redistributions in binary form must reproduce the above copyright
  1457. ## notice, this list of conditions and the following disclaimer in the
  1458. ## documentation and/or other materials provided with the distribution.
  1459. ## 3. All advertising materials mentioning features or use of this software
  1460. ## must display the following acknowledgement:
  1461. ## This product includes software developed by Terrapin Communications,
  1462. ## Inc. and its contributors for RANCID.
  1463. ## 4. Neither the name of Terrapin Communications, Inc. nor the names of its
  1464. ## contributors may be used to endorse or promote products derived from
  1465. ## this software without specific prior written permission.
  1466. ## 5. It is requested that non-binding fixes and modifications be contributed
  1467. ## back to Terrapin Communications, Inc.
  1468. ##
  1469. ## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS
  1470. ## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  1471. ## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  1472. ## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
  1473. ## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  1474. ## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  1475. ## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  1476. ## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  1477. ## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  1478. ## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  1479. ## POSSIBILITY OF SUCH DAMAGE.
  1480. ##
  1481. ## It is the request of the authors, but not a condition of license, that
  1482. ## parties packaging or redistributing RANCID NOT distribute altered versions
  1483. ## of the etc/rancid.types.base file nor alter how this file is processed nor
  1484. ## when in relation to etc/rancid.types.conf. The goal of this is to help
  1485. ## suppress our support costs. If it becomes a problem, this could become a
  1486. ## condition of license.
  1487. #
  1488. # The expect login scripts were based on Erik Sherk's gwtn, by permission.
  1489. #
  1490. # The original looking glass software was written by Ed Kern, provided by
  1491. # permission and modified beyond recognition.
  1492. #
  1493. # rblogin - Riverbed Steelhead login; this is starting from clogin r3115, with
  1494. # a few changes for UI bugs.
  1495. #
  1496. # Most options are intuitive for logging into a Cisco router.
  1497. # The default is to enable (thus -noenable). Some folks have
  1498. # setup tacacs to have a user login at priv-lvl = 15 (enabled)
  1499. # so the -autoenable flag was added for this case (don't go through
  1500. # the process of enabling and the prompt will be the "#" prompt.
  1501. # The default username password is the same as the vty password.
  1502. #
  1503.  
  1504. # Sometimes routers take awhile to answer (the default is 10 sec)
  1505. set timeoutdflt 45
  1506. # Some CLIs having problems if we write too fast (Extreme, PIX, Cat)
  1507. set send_human {.2 .1 .4 .2 1}
  1508.  
  1509. # env(CLOGIN) may contain:
  1510. # x == do not set xterm banner or name
  1511.  
  1512. # Find the user in the ENV, or use the unix userid.
  1513. if {[info exists env(CISCO_USER)]} {
  1514. set default_user $env(CISCO_USER)
  1515. } elseif {[info exists env(USER)]} {
  1516. set default_user $env(USER)
  1517. } elseif {[info exists env(LOGNAME)]} {
  1518. set default_user $env(LOGNAME)
  1519. } else {
  1520. # This uses "id" which I think is portable. At least it has existed
  1521. # (without options) on all machines/OSes I've been on recently -
  1522. # unlike whoami or id -nu.
  1523. if [catch {exec id} reason] {
  1524. send_error "\nError: could not exec id: $reason\n"
  1525. exit 1
  1526. }
  1527. regexp {\(([^)]*)} "$reason" junk default_user
  1528. }
  1529. if {[info exists env(CLOGINRC)]} {
  1530. set password_file $env(CLOGINRC)
  1531. }
  1532.  
  1533. # Usage line
  1534. set usage "Usage: $argv0 \[-dhSV\] \[-m|M\] \[-autoenable\] \[-noenable\] \
  1535. \[-c command\] \[-Evar=x\] \[-e enable-password\] \[-f cloginrc-file\] \
  1536. \[-p user-password\] \[-r passphrase\] \[-s script-file\] \[-t timeout\] \
  1537. \[-u username\] \[-v vty-password\] \[-w enable-username\] \[-x command-file\] \
  1538. \[-y ssh_cypher_type\] router \[router...\]\n"
  1539.  
  1540. # Password file
  1541. set password_file $env(HOME)/.cloginrc
  1542. # Default is to login to the router
  1543. set do_command 0
  1544. set do_script 0
  1545. # The default is to automatically enable
  1546. set avenable 1
  1547. # The default is that you login non-enabled (tacacs can have you login already
  1548. # enabled)
  1549. set avautoenable 0
  1550. # The default is to look in the password file to find the passwords. This
  1551. # tracks if we receive them on the command line.
  1552. set do_passwd 1
  1553. set do_enapasswd 1
  1554. # Save config, if prompted
  1555. set do_saveconfig 0
  1556. # cloginrc debugging knob
  1557. set do_cloginrcdbg 0
  1558. # intialize cloginrc parsing stacks
  1559. set int_file {}
  1560. set int_lineno {}
  1561.  
  1562. # Process the command line
  1563. for {set i 0} {$i < $argc} {incr i} {
  1564. set arg [lindex $argv $i]
  1565.  
  1566. switch -glob -- $arg {
  1567. # Expect debug mode
  1568. -d* {
  1569. exp_internal 1
  1570. # Help
  1571. } -h* {
  1572. send_user "$usage"
  1573. exit 0
  1574. # Command to run.
  1575. } -c* {
  1576. if {! [regexp .\[cC\](.+) $arg ignore command]} {
  1577. incr i
  1578. set command [lindex $argv $i]
  1579. }
  1580. set do_command 1
  1581. # Environment variable to pass to -s scripts
  1582. } -E* {
  1583. if {[regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} {
  1584. set E$varname $varvalue
  1585. } else {
  1586. send_user "\nError: invalid format for -E in $arg\n"
  1587. exit 1
  1588. }
  1589. # alternate cloginrc file
  1590. } -f* {
  1591. if {! [regexp .\[fF\](.+) $arg ignore password_file]} {
  1592. incr i
  1593. set password_file [lindex $argv $i]
  1594. }
  1595. # VTY Password
  1596. } -p* {
  1597. if {! [regexp .\[pP\](.+) $arg ignore userpasswd]} {
  1598. incr i
  1599. set userpasswd [lindex $argv $i]
  1600. }
  1601. set do_passwd 0
  1602. # cloginrc debugging knobs
  1603. } -m* {
  1604. set do_cloginrcdbg 1
  1605. } -M* {
  1606. set do_cloginrcdbg 2
  1607. # ssh passphrase
  1608. } -r* {
  1609. if {! [regexp .\[rR\](.+) $arg ignore passphrase]} {
  1610. incr i
  1611. set avpassphrase [lindex $argv $i]
  1612. }
  1613. # Expect script to run.
  1614. } -s* {
  1615. if {! [regexp .\[sS\](.+) $arg ignore sfile]} {
  1616. incr i
  1617. set sfile [lindex $argv $i]
  1618. }
  1619. if { ! [file readable $sfile] } {
  1620. send_user "\nError: Can't read $sfile\n"
  1621. exit 1
  1622. }
  1623. set do_script 1
  1624. # save config on exit
  1625. } -S* {
  1626. # may not be supported by the script and may not be applicable to
  1627. # the platform
  1628. set do_saveconfig 1
  1629. # Timeout
  1630. } -t* {
  1631. if {! [regexp .\[tT\](.+) $arg ignore timeout]} {
  1632. incr i
  1633. set timeoutdflt [lindex $argv $i]
  1634. }
  1635. # Username
  1636. } -u* {
  1637. if {! [regexp .\[uU\](.+) $arg ignore user]} {
  1638. incr i
  1639. set username [lindex $argv $i]
  1640. }
  1641. # VTY Password
  1642. } -v* {
  1643. # some scripts ignore -v, like jlogin
  1644. if {! [regexp .\[vV\](.+) $arg ignore passwd]} {
  1645. incr i
  1646. set passwd [lindex $argv $i]
  1647. }
  1648. set do_passwd 0
  1649. # Version string
  1650. } -V* {
  1651. send_user "rancid 3.4.1\n"
  1652. exit 0
  1653. # Enable Username
  1654. } -w* {
  1655. if {! [regexp .\[wW\](.+) $arg ignore enauser]} {
  1656. incr i
  1657. set enausername [lindex $argv $i]
  1658. }
  1659. # Enable Password
  1660. } -e* {
  1661. if {! [regexp .\[e\](.+) $arg ignore enapasswd]} {
  1662. incr i
  1663. set enapasswd [lindex $argv $i]
  1664. }
  1665. set do_enapasswd 0
  1666. # 'ssh -c' cypher type
  1667. } -y* {
  1668. if {! [regexp .\[eE\](.+) $arg ignore cypher]} {
  1669. incr i
  1670. set cypher [lindex $argv $i]
  1671. }
  1672. # Command file
  1673. } -x* {
  1674. if {! [regexp .\[xX\](.+) $arg ignore cmd_file]} {
  1675. incr i
  1676. set cmd_file [lindex $argv $i]
  1677. }
  1678. if [catch {set cmd_fd [open $cmd_file r]} reason] {
  1679. send_user "\nError: $reason\n"
  1680. exit 1
  1681. }
  1682. set cmd_text [read $cmd_fd]
  1683. close $cmd_fd
  1684. set command [join [split $cmd_text \n] \;]
  1685. set do_command 1
  1686. # Do we enable?
  1687. } -noenable {
  1688. set avenable 0
  1689. # Does tacacs automatically enable us?
  1690. } -autoenable {
  1691. set avautoenable 1
  1692. set avenable 0
  1693. } -* {
  1694. send_user "\nError: Unknown argument! $arg\n"
  1695. send_user $usage
  1696. exit 1
  1697. } default {
  1698. break
  1699. }
  1700. }
  1701. }
  1702. # Process routers...no routers listed is an error.
  1703. if { $i == $argc } {
  1704. send_user "\nError: $usage"
  1705. }
  1706.  
  1707. # Only be quiet if we are running a script (it can log its output
  1708. # on its own)
  1709. if { $do_script } {
  1710. log_user 0
  1711. } else {
  1712. log_user 1
  1713. }
  1714.  
  1715. #
  1716. # Done configuration/variable setting. Now run with it...
  1717. #
  1718.  
  1719. # Sets Xterm title if interactive...if its an xterm and the user cares
  1720. proc label { host } {
  1721. global env
  1722. # if CLOGIN has an 'x' in it, don't set the xterm name/banner
  1723. if [info exists env(CLOGIN)] {
  1724. if {[string first "x" $env(CLOGIN)] != -1} { return }
  1725. }
  1726. # take host from ENV(TERM)
  1727. if [info exists env(TERM)] {
  1728. if [regexp \^(xterm|vs) $env(TERM) ignore] {
  1729. send_user "\033]1;[lindex [split $host "."] 0]\a"
  1730. send_user "\033]2;$host\a"
  1731. }
  1732. }
  1733. }
  1734.  
  1735. # This is a helper function to make the password file easier to
  1736. # maintain. Using this the password file has the form:
  1737. # add password sl* pete cow
  1738. # add password at* steve
  1739. # add password * hanky-pie
  1740. proc add {var args} {
  1741. global int_file int_lineno int_$var
  1742. set file [lindex $int_file 0]
  1743. set lineno [lindex $int_lineno 0]
  1744. lappend int_$var "$var:$file:$lineno: $args"
  1745. }
  1746. proc include {args} {
  1747. global env
  1748. regsub -all "(^{|}$)" $args {} args
  1749. if { [regexp "^/" $args ignore] == 0 } {
  1750. set args $env(HOME)/$args
  1751. }
  1752. source_password_file $args
  1753. }
  1754.  
  1755. proc find {var router} {
  1756. global do_cloginrcdbg
  1757. upvar int_$var list
  1758. if { [info exists list] } {
  1759. foreach line $list {
  1760. if { [string match -nocase [lindex $line 1] $router] } {
  1761. if { $do_cloginrcdbg > 0 } {
  1762. send_error -- [join [list [lindex $line 0] [lrange $line 1 end] "\r\n"]]
  1763. }
  1764. if { $do_cloginrcdbg == 2 } {
  1765. # save return value
  1766. if {! [info exists result]} {
  1767. set result [lrange $line 2 end]
  1768. }
  1769. } else {
  1770. return [lrange $line 2 end]
  1771. }
  1772. }
  1773. }
  1774. }
  1775.  
  1776. if { $do_cloginrcdbg == 2 } {
  1777. if {[info exists result]} {
  1778. return $result
  1779. }
  1780. }
  1781. return {}
  1782. }
  1783.  
  1784. # Loads the password file. Note that as this file is tcl, and that
  1785. # it is sourced, the user better know what to put in there, as it
  1786. # could install more than just password info... I will assume however,
  1787. # that a "bad guy" could just as easy put such code in the clogin
  1788. # script, so I will leave .cloginrc as just an extention of that script
  1789. proc source_password_file { file } {
  1790. global env int_file int_lineno
  1791. if { ! [file exists $file] } {
  1792. send_user "\nError: password file ($file) does not exist\n"
  1793. exit 1
  1794. }
  1795. file stat $file fileinfo
  1796. if { [expr ($fileinfo(mode) & 007)] != 0000 } {
  1797. send_user "\nError: $file must not be world readable/writable\n"
  1798. exit 1
  1799. }
  1800. if [catch {set fd [open $file "r"]} reason] {
  1801. send_user "\nError: $reason\n"
  1802. exit 1
  1803. }
  1804. set int_file [linsert $int_file 0 $file]
  1805. set int_lineno [linsert $int_lineno 0 0]
  1806. while { [gets $fd line] >= 0 } {
  1807. set tmp [lindex $int_lineno 0]; incr tmp
  1808. lset int_lineno 0 $tmp
  1809. eval $line
  1810. }
  1811. set int_file [lrange $int_file 1 end]
  1812. set int_lineno [lrange $int_lineno 1 end]
  1813. close $fd
  1814. }
  1815.  
  1816. # Log into the router.
  1817. # returns: 0 on success, 1 on failure, -1 if rsh was used successfully
  1818. proc login { router user userpswd passwd enapasswd cmethod cyphertype identfile } {
  1819. global command spawn_id in_proc do_command do_script platform passphrase
  1820. global prompt prompt_match u_prompt p_prompt e_prompt sshcmd
  1821. set in_proc 1
  1822. set uprompt_seen 0
  1823.  
  1824. # try each of the connection methods in $cmethod until one is successful
  1825. set progs [llength $cmethod]
  1826. foreach prog [lrange $cmethod 0 end] {
  1827. incr progs -1
  1828. if [string match "telnet*" $prog] {
  1829. regexp {telnet(:([^[:space:]]+))*} $prog methcmd suffix port
  1830. if {"$port" == ""} {
  1831. set retval [catch {spawn telnet $router} reason]
  1832. } else {
  1833. set retval [catch {spawn telnet $router $port} reason]
  1834. }
  1835. if { $retval } {
  1836. send_user "\nError: telnet failed: $reason\n"
  1837. return 1
  1838. }
  1839. } elseif [string match "ssh*" $prog] {
  1840. # ssh to the router & try to login with or without an identfile.
  1841. regexp {ssh(:([^[:space:]]+))*} $prog methcmd suffix port
  1842. set cmd $sshcmd
  1843. if {"$port" != ""} {
  1844. set cmd "$cmd -p $port"
  1845. }
  1846. if {"$identfile" != ""} {
  1847. set cmd "$cmd -i $identfile"
  1848. }
  1849. set retval [catch {eval spawn [split "$cmd -c $cyphertype -x -l $user $router" { }]} reason]
  1850. if { $retval } {
  1851. send_user "\nError: $cmd failed: $reason\n"
  1852. return 1
  1853. }
  1854. } elseif ![string compare $prog "rsh"] {
  1855. if { ! $do_command } {
  1856. if { [llength $cmethod] == 1 } {
  1857. send_user "\nError: rsh is an invalid method for -x and "
  1858. send_user "interactive logins\n"
  1859. }
  1860. if { $progs == 0 } {
  1861. return 1
  1862. }
  1863. continue;
  1864. }
  1865.  
  1866. # handle escaped ;s in commands, and ;; and ^;
  1867. regsub -all {([^\\]);;} $command "\\1;\u002;" esccommand
  1868. regsub {^;} $esccommand "\u002;" command
  1869. set sep "\\1\u001"
  1870. regsub -all {([^\\])\;} $command "$sep" esccommand
  1871. set sep "\u001"
  1872. set commands [split $esccommand $sep]
  1873. set num_commands [llength $commands]
  1874. set rshfail 0
  1875. for {set i 0} {$i < $num_commands && !$rshfail} { incr i} {
  1876. log_user 0
  1877. set retval [catch {spawn rsh $user@$router [lindex $commands $i] } reason]
  1878. if { $retval } {
  1879. send_user "\nError: rsh failed: $reason\n"
  1880. log_user 1; return 1
  1881. }
  1882. send_user "$router# [lindex $commands $i]\n"
  1883.  
  1884. # rcmd does not get a pager and no prompts, so we just have to
  1885. # look for failures & lines.
  1886. expect {
  1887. "Connection refused" { catch {close}; catch {wait};
  1888. send_user "\nError: Connection\
  1889. Refused ($prog): $router\n"
  1890. set rshfail 1
  1891. }
  1892. -re "(Connection closed by|Connection to \[^\n\r]+ closed)" {
  1893. catch {close}; catch {wait};
  1894. send_user "\nError: Connection\
  1895. closed ($prog): $router\n"
  1896. set rshfail 1
  1897. }
  1898. "Host is unreachable" { catch {close}; catch {wait};
  1899. send_user "\nError: Host Unreachable:\
  1900. $router\n"
  1901. set rshfail 1
  1902. }
  1903. "No address associated with" {
  1904. catch {close}; catch {wait};
  1905. send_user "\nError: Unknown host\
  1906. $router\n"
  1907. set rshfail 1
  1908. }
  1909. -re "\b+" { exp_continue }
  1910. -re "\[\n\r]+" { send_user -- "$expect_out(buffer)"
  1911. exp_continue
  1912. }
  1913. timeout { catch {close}; catch {wait};
  1914. send_user "\nError: TIMEOUT reached\n"
  1915. set rshfail 1
  1916. }
  1917. eof { catch {close}; catch {wait}; }
  1918. }
  1919. log_user 1
  1920. }
  1921. if { $rshfail } {
  1922. if { !$progs } {
  1923. return 1
  1924. } else {
  1925. continue
  1926. }
  1927. }
  1928. # fake the end of the session for rancid.
  1929. send_user "$router# exit\n"
  1930. # return rsh "success"
  1931. return -1
  1932. } else {
  1933. send_user "\nError: unknown connection method: $prog\n"
  1934. return 1
  1935. }
  1936. sleep 0.3
  1937.  
  1938. # This helps cleanup each expect clause.
  1939. expect_after {
  1940. timeout {
  1941. send_user "\nError: TIMEOUT reached\n"
  1942. catch {close}; catch {wait};
  1943. if { $in_proc} {
  1944. return 1
  1945. } else {
  1946. continue
  1947. }
  1948. } eof {
  1949. send_user "\nError: EOF received\n"
  1950. catch {close}; catch {wait};
  1951. if { $in_proc} {
  1952. return 1
  1953. } else {
  1954. continue
  1955. }
  1956. }
  1957. }
  1958.  
  1959. # Here we get a little tricky. There are several possibilities:
  1960. # the router can ask for a username and passwd and then
  1961. # talk to the TACACS server to authenticate you, or if the
  1962. # TACACS server is not working, then it will use the enable
  1963. # passwd. Or, the router might not have TACACS turned on,
  1964. # then it will just send the passwd.
  1965. # if telnet fails with connection refused, try ssh
  1966. expect {
  1967. -re "^<-+ More -+>\[^\n\r]*" {
  1968. # ASA will use the pager for long banners
  1969. send " ";
  1970. exp_continue
  1971. }
  1972. -re "(Connection refused|Secure connection \[^\n\r]+ refused)" {
  1973. catch {close}; catch {wait};
  1974. if !$progs {
  1975. send_user "\nError: Connection Refused ($prog): $router\n"
  1976. return 1
  1977. }
  1978. }
  1979. -re "(Connection closed by|Connection to \[^\n\r]+ closed)" {
  1980. catch {close}; catch {wait};
  1981. if !$progs {
  1982. send_user "\nError: Connection closed ($prog): $router\n"
  1983. return 1
  1984. }
  1985. }
  1986. eof { send_user "\nError: Couldn't login: $router\n"; wait; return 1 }
  1987. -nocase "unknown host\r" {
  1988. send_user "\nError: Unknown host $router\n";
  1989. catch {close}; catch {wait};
  1990. return 1
  1991. }
  1992. "Host is unreachable" {
  1993. send_user "\nError: Host Unreachable: $router\n";
  1994. catch {close}; catch {wait};
  1995. return 1
  1996. }
  1997. "No address associated with name" {
  1998. send_user "\nError: Unknown host $router\n";
  1999. catch {close}; catch {wait};
  2000. return 1
  2001. }
  2002. -re "(Host key not found |The authenticity of host .* be established).* \\(yes/no\\)\\?" {
  2003. send "yes\r"
  2004. send_user "\nHost $router added to the list of known hosts.\n"
  2005. exp_continue
  2006. }
  2007. -re "HOST IDENTIFICATION HAS CHANGED.* \\(yes/no\\)\\?" {
  2008. send "no\r"
  2009. send_user "\nError: The host key for $router has changed. Update the SSH known_hosts file accordingly.\n"
  2010. catch {close}; catch {wait};
  2011. return 1
  2012. }
  2013. -re "HOST IDENTIFICATION HAS CHANGED\[^\n\r]+" {
  2014. send_user "\nError: The host key for $router has changed. Update the SSH known_hosts file accordingly.\n"
  2015. return 1
  2016. }
  2017. -re "Offending key for .* \\(yes/no\\)\\?" {
  2018. send "no\r"
  2019. send_user "\nError: host key mismatch for $router. Update the SSH known_hosts file accordingly.\n"
  2020. catch {close}; catch {wait};
  2021. return 1
  2022. }
  2023. -nocase -re "^warning: remote host denied authentication agent forwarding." {
  2024. exp_continue;
  2025. }
  2026. -re "(denied|Sorry)" {
  2027. send_user "\nError: Check your passwd for $router\n"
  2028. catch {close}; catch {wait}; return 1
  2029. }
  2030. "Login failed" {
  2031. send_user "\nError: Check your passwd for $router\n"
  2032. catch {close}; catch {wait}; return 1
  2033. }
  2034. -re "% (Bad passwords|Authentication failed)" {
  2035. send_user "\nError: Check your passwd for $router\n"
  2036. catch {close}; catch {wait}; return 1
  2037. }
  2038. "Press any key to continue" {
  2039. # send_user "Pressing the ANY key\n"
  2040. send "\r"
  2041. exp_continue
  2042. }
  2043. -re "Enter Selection: " {
  2044. # Catalyst 1900s have some lame menu. Enter
  2045. # K to reach a command-line.
  2046. send "K\r"
  2047. exp_continue
  2048. }
  2049. -re "Last login:" {
  2050. exp_continue
  2051. }
  2052. -re "Press the <tab> key \[^\r\n]+\[\r\n]+" {
  2053. exp_continue
  2054. }
  2055. -re "@\[^\r\n]+ $p_prompt" {
  2056. # ssh pwd prompt
  2057. sleep 1
  2058. send -- "$userpswd\r"
  2059. exp_continue
  2060. }
  2061. -re "Enter passphrase.*: " {
  2062. # sleep briefly to allow time for stty -echo
  2063. sleep .3
  2064. send -- "$passphrase\r"
  2065. exp_continue
  2066. }
  2067. -re "$u_prompt" {
  2068. send -- "$user\r"
  2069. set uprompt_seen 1
  2070. exp_continue
  2071. }
  2072. -re "$p_prompt" {
  2073. sleep 1
  2074. if {$uprompt_seen == 1} {
  2075. send -- "$userpswd\r"
  2076. } else {
  2077. send -- "$passwd\r"
  2078. }
  2079. exp_continue
  2080. }
  2081. -re "$prompt" {
  2082. set prompt_match $expect_out(0,string);
  2083. break;
  2084. }
  2085. "Login invalid" {
  2086. send_user "\nError: Invalid login: $router\n";
  2087. catch {close}; catch {wait}; return 1
  2088. }
  2089. -re "\[^\r\n]*\[\r\n]+" { exp_continue; }
  2090. }
  2091. }
  2092.  
  2093. set in_proc 0
  2094. return 0
  2095. }
  2096.  
  2097. # Enable
  2098. proc do_enable { enauser enapasswd } {
  2099. global do_saveconfig in_proc
  2100. global prompt u_prompt e_prompt enacmd
  2101. set in_proc 1
  2102.  
  2103. send "$enacmd\r"
  2104. expect {
  2105. -re "$u_prompt" { send -- "$enauser\r"; exp_continue}
  2106. -re "$e_prompt" { send -- "$enapasswd\r"; exp_continue}
  2107. "#" { set prompt "#" }
  2108. "(enable)" { set prompt "> \\(enable\\) " }
  2109. "% Invalid input" {
  2110. send_user "\nError: Unrecognized command, check your enable command\n";
  2111. return 1
  2112. }
  2113. -re "(denied|Sorry|Incorrect)" {
  2114. # % Access denied - from local auth and poss. others
  2115. send_user "\nError: Check your Enable passwd\n";
  2116. return 1
  2117. }
  2118. "% Error in authentication" {
  2119. send_user "\nError: Check your Enable passwd\n"
  2120. return 1
  2121. }
  2122. "% Bad passwords" {
  2123. send_user "\nError: Check your Enable passwd\n"
  2124. return 1
  2125. }
  2126. }
  2127. # We set the prompt variable (above) so script files don't need
  2128. # to know what it is.
  2129. set in_proc 0
  2130. return 0
  2131. }
  2132.  
  2133. # Run commands given on the command line.
  2134. proc run_commands { prompt command } {
  2135. global do_saveconfig in_proc platform
  2136. set in_proc 1
  2137.  
  2138. if { [string compare "extreme" "$platform"] } {
  2139. # match cisco config mode prompts too, such as router(config-if)#,
  2140. # but catalyst does not change in this fashion.
  2141. regsub -lineanchor -- {^(.{1,11}).*([#>])$} $prompt {\1} reprompt
  2142. regsub -all -- {[\\]$} $reprompt {} reprompt
  2143. append reprompt {([^#>\r\n]+)?[#>](\\([^)\\r\\n]+\\))?}
  2144. } else {
  2145. set reprompt $prompt
  2146. }
  2147.  
  2148. # this is the only way i see to get rid of more prompts in o/p..grrrrr
  2149. log_user 0
  2150.  
  2151. # handle escaped ;s in commands, and ;; and ^;
  2152. regsub -all {([^\\]);;} $command "\\1;\u002;" esccommand
  2153. regsub {^;} $esccommand "\u002;" command
  2154. set sep "\\1\u001"
  2155. regsub -all {([^\\]);} $command "$sep" esccommand
  2156. set sep "\u001"
  2157. set commands [split $esccommand $sep]
  2158. set num_commands [llength $commands]
  2159. # the pager can not be turned off on the PIX, so we have to look
  2160. # for the "More" prompt. the extreme is equally obnoxious in pre-12.3 XOS,
  2161. # with a global switch in the config.
  2162. for {set i 0} {$i < $num_commands} { incr i} {
  2163. if { [lindex $commands $i] == "\u002" } {
  2164. send -- "\r"
  2165. } else {
  2166. send -- "[subst -nocommands [lindex $commands $i]]\r"
  2167. }
  2168. expect {
  2169. -re "\b+" { exp_continue }
  2170. -re "^<<Service needs \[^>]+>>" {
  2171. # for whatever reason, the riverbed prints
  2172. # this warning in show peers o/p, but doesnt
  2173. # follow it with a CR, so the following
  2174. # prompt is not at the BOL, confusing the
  2175. # parsing script. so, filter it. XXX
  2176. exp_continue;
  2177. }
  2178. -re "^\[^\n\r *]*$reprompt" { send_user -- "$expect_out(buffer)"
  2179. }
  2180. -re "^\[^\n\r]*$reprompt." { send_user -- "$expect_out(buffer)"
  2181. exp_continue
  2182. }
  2183. -re "^--More--\[\r\n]+" { # specific match c1900 pager
  2184. send " "
  2185. exp_continue
  2186. }
  2187. -re "\[^\r\n]*\[\n\r]+" { send_user -- "$expect_out(buffer)"
  2188. exp_continue
  2189. }
  2190. -re "\[^\r\n]*Press <SPACE> to cont\[^\r\n]*" {
  2191. send " "
  2192. # bloody ^[[2K after " "
  2193. expect {
  2194. -re "^\[^\r\n]*\r" {}
  2195. }
  2196. exp_continue
  2197. }
  2198. -re "^ *--More--\[^\n\r]*" {
  2199. send " "
  2200. exp_continue }
  2201. -re "^<-+ More -+>\[^\n\r]*" {
  2202. send_user -- "$expect_out(buffer)"
  2203. send " "
  2204. exp_continue }
  2205. }
  2206. }
  2207. log_user 1
  2208.  
  2209. if { [string compare "extreme" "$platform"] } {
  2210. send -h "exit\r"
  2211. } else {
  2212. send -h "quit\r"
  2213. }
  2214. expect {
  2215. -re "^\[^\n\r *]*$reprompt" {
  2216. # the Cisco CE and Jnx ERX
  2217. # return to non-enabled mode
  2218. # on exit in enabled mode.
  2219. send -h "exit\r"
  2220. exp_continue;
  2221. }
  2222. "The system has unsaved changes" { # Force10 SFTOS
  2223. if {$do_saveconfig} {
  2224. catch {send "y\r"}
  2225. } else {
  2226. catch {send "n\r"}
  2227. }
  2228. exp_continue
  2229. }
  2230. "Would you like to save them now" { # Force10
  2231. if {$do_saveconfig} {
  2232. catch {send "y\r"}
  2233. } else {
  2234. catch {send "n\r"}
  2235. }
  2236. exp_continue
  2237. }
  2238. -re "(Profile|Configuration) changes have occurred.*" {
  2239. # Cisco CSS
  2240. if {$do_saveconfig} {
  2241. catch {send "y\r"}
  2242. } else {
  2243. catch {send "n\r"}
  2244. }
  2245. exp_continue
  2246. }
  2247. "Do you wish to save your configuration changes" {
  2248. if {$do_saveconfig} {
  2249. catch {send "y\r"}
  2250. } else {
  2251. catch {send "n\r"}
  2252. }
  2253. exp_continue
  2254. }
  2255. -re "\[\n\r]+" { exp_continue }
  2256. timeout { catch {close}; catch {wait};
  2257. return 1
  2258. }
  2259. eof { return 0 }
  2260. }
  2261. set in_proc 0
  2262. }
  2263.  
  2264. #
  2265. # For each router... (this is main loop)
  2266. #
  2267. source_password_file $password_file
  2268. set in_proc 0
  2269. set exitval 0
  2270. set prompt_match ""
  2271. foreach router [lrange $argv $i end] {
  2272. set router [string tolower $router]
  2273. # attempt at platform switching.
  2274. set platform ""
  2275. send_user -- "$router\n"
  2276.  
  2277. # device timeout
  2278. set timeout [find timeout $router]
  2279. if { [llength $timeout] == 0 } {
  2280. set timeout $timeoutdflt
  2281. }
  2282.  
  2283. # Default prompt.
  2284. set prompt [join [find prompt $router] ""]
  2285. if { [llength $prompt] == 0 } {
  2286. set prompt "(>|#| \\(enable\\))"
  2287. }
  2288.  
  2289. # look for autoenable option in .cloginrc & cmd-line
  2290. set ae [find autoenable $router]
  2291. if { "$ae" == "1" || $avautoenable } {
  2292. set autoenable 1
  2293. } else {
  2294. set autoenable 0
  2295. }
  2296. # look for enable options in .cloginrc & cmd-line
  2297. if { $avenable == 0 } {
  2298. set enable 0
  2299. } else {
  2300. set ne [find noenable $router]
  2301. if { "$ne" == "1" || "$autoenable" == "1" } {
  2302. set enable 0
  2303. } else {
  2304. set enable 1
  2305. }
  2306. }
  2307.  
  2308. # Figure out passwords
  2309. if { $do_passwd || $do_enapasswd } {
  2310. set pswd [find password $router]
  2311. if { [llength $pswd] == 0 } {
  2312. send_user -- "\nError: no password for $router in $password_file.\n"
  2313. continue
  2314. }
  2315. if { $enable && $do_enapasswd && $autoenable == 0 && [llength $pswd] < 2 } {
  2316. send_user -- "\nError: no enable password for $router in $password_file.\n"
  2317. continue
  2318. }
  2319. set passwd [join [lindex $pswd 0] ""]
  2320. set enapasswd [join [lindex $pswd 1] ""]
  2321. } else {
  2322. set passwd $userpasswd
  2323. set enapasswd $enapasswd
  2324. }
  2325.  
  2326. # Figure out username
  2327. if {[info exists username]} {
  2328. # command line username
  2329. set ruser $username
  2330. } else {
  2331. set ruser [join [find user $router] ""]
  2332. if { "$ruser" == "" } { set ruser $default_user }
  2333. }
  2334.  
  2335. # Figure out username's password (if different from the vty password)
  2336. if {[info exists userpasswd]} {
  2337. # command line username
  2338. set userpswd $userpasswd
  2339. } else {
  2340. set userpswd [join [find userpassword $router] ""]
  2341. if { "$userpswd" == "" } { set userpswd $passwd }
  2342. }
  2343.  
  2344. # Figure out enable username
  2345. if {[info exists enausername]} {
  2346. # command line enausername
  2347. set enauser $enausername
  2348. } else {
  2349. set enauser [join [find enauser $router] ""]
  2350. if { "$enauser" == "" } { set enauser $ruser }
  2351. }
  2352.  
  2353. # Figure out enable command
  2354. set enacmd [join [find enablecmd $router] ""]
  2355. if { "$enacmd" == "" } { set enacmd "enable" }
  2356.  
  2357. # Figure out prompts
  2358. set u_prompt [find userprompt $router]
  2359. if { "$u_prompt" == "" } {
  2360. set u_prompt "(\[Uu]sername|Login|login|user name|User):"
  2361. } else {
  2362. set u_prompt [join [lindex $u_prompt 0] ""]
  2363. }
  2364. set p_prompt [find passprompt $router]
  2365. if { "$p_prompt" == "" } {
  2366. set p_prompt "(\[Pp]assword|passwd|Enter password for \[^ :]+):"
  2367. } else {
  2368. set p_prompt [join [lindex $p_prompt 0] ""]
  2369. }
  2370. set e_prompt [find enableprompt $router]
  2371. if { "$e_prompt" == "" } {
  2372. set e_prompt "\[Pp]assword:"
  2373. } else {
  2374. set e_prompt [join [lindex $e_prompt 0] ""]
  2375. }
  2376.  
  2377. # Figure out identity file to use
  2378. set identfile [join [lindex [find identity $router] 0] ""]
  2379.  
  2380. # Figure out passphrase to use
  2381. if {[info exists avpassphrase]} {
  2382. set passphrase $avpassphrase
  2383. } else {
  2384. set passphrase [join [lindex [find passphrase $router] 0] ""]
  2385. }
  2386. if { ! [string length "$passphrase"]} {
  2387. set passphrase $passwd
  2388. }
  2389.  
  2390. # Figure out cypher type
  2391. if {[info exists cypher]} {
  2392. # command line cypher type
  2393. set cyphertype $cypher
  2394. } else {
  2395. set cyphertype [find cyphertype $router]
  2396. if { "$cyphertype" == "" } { set cyphertype "3des" }
  2397. }
  2398.  
  2399. # Figure out connection method
  2400. set cmethod [find method $router]
  2401. if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} }
  2402.  
  2403. # Figure out the SSH executable name
  2404. set sshcmd [join [lindex [find sshcmd $router] 0] ""]
  2405. if { "$sshcmd" == "" } { set sshcmd {ssh} }
  2406.  
  2407. # if [-mM], skip do not login
  2408. if { $do_cloginrcdbg > 0 } { continue; }
  2409.  
  2410. # Login to the router
  2411. if {[login $router $ruser $userpswd $passwd $enapasswd $cmethod $cyphertype $identfile]} {
  2412. incr exitval
  2413. # if login failed or rsh was unsuccessful, move on to the next device
  2414. continue
  2415. }
  2416. # Figure out the prompt.
  2417. if { [regexp -- "(#| \\(enable\\))" $prompt_match junk] == 1 } {
  2418. set enable 0
  2419. }
  2420. if { $enable } {
  2421. if {[do_enable $enauser $enapasswd]} {
  2422. if { $do_command || $do_script } {
  2423. incr exitval
  2424. catch {close}; catch {wait};
  2425. continue
  2426. }
  2427. }
  2428. }
  2429. # we are logged in, now figure out the full prompt
  2430. send "\r"
  2431. regsub -all {^(\^*)(.*)} $prompt {\2} reprompt
  2432. expect {
  2433. -re "\[\r\n]+" { exp_continue; }
  2434. -re "^(.+\[:.])1 ($reprompt)" { # stoopid extreme cmd-line numbers and
  2435. # prompt based on state of config changes,
  2436. # which may have an * at the beginning.
  2437. set junk $expect_out(1,string)
  2438. regsub -all "^\\\* " $expect_out(1,string) {} junk
  2439. regsub -all "\[\]\[\(\)]" $junk {\\&} junk;
  2440. set prompt ".? ?$junk\[0-9]+ $expect_out(2,string)";
  2441. set platform "extreme"
  2442. }
  2443. -re "^.+$reprompt" { set junk $expect_out(0,string);
  2444. regsub -all "\[\]\[\(\)+]" $junk {\\&} prompt;
  2445. }
  2446. }
  2447. if { $do_command || $do_script } {
  2448. if { [string compare "extreme" "$platform"] } {
  2449. # If the prompt is (enable), then we are on a switch and the
  2450. # command is "set length 0"; otherwise its "terminal length 0".
  2451. if [regexp -- ".*> .*enable" "$prompt"] {
  2452. send "set length 0\r"
  2453. expect -re $prompt {}
  2454. # XXX This causes the riverbed to reprint the prompt after the
  2455. # existing prompt, which confuses the expect script.
  2456. # send "set width 132\r"
  2457. # expect -re $prompt {}
  2458. send "set logging session disable\r"
  2459. } else {
  2460. send "terminal length 0\r"
  2461. # XXX This causes the riverbed to reprint the prompt after the
  2462. # existing prompt, which confuses the expect script.
  2463. # expect -re $prompt {}
  2464. # send "terminal width 132\r"
  2465. }
  2466. expect -re $prompt {}
  2467. } else {
  2468. send "disable clipaging\r"
  2469. expect -re $prompt {}
  2470. }
  2471. }
  2472. if { $do_command } {
  2473. if {[run_commands $prompt $command]} {
  2474. incr exitval
  2475. continue
  2476. }
  2477. } elseif { $do_script } {
  2478. source $sfile
  2479. catch {close};
  2480. } else {
  2481. label $router
  2482. log_user 1
  2483. interact
  2484. }
  2485.  
  2486. # End of for each router
  2487. catch {wait};
  2488. sleep 0.3
  2489. }
  2490. exit $exitval
  2491. #! /usr/bin/expect --
  2492. ##
  2493. ## $Id: rivlogin.in 3102 2015-04-23 17:18:18Z heas $
  2494. ##
  2495. ## rancid 3.4.1
  2496. ## Copyright (c) 1997-2016 by Terrapin Communications, Inc.
  2497. ## All rights reserved.
  2498. ##
  2499. ## This code is derived from software contributed to and maintained by
  2500. ## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan,
  2501. ## Pete Whiting, Austin Schutz, and Andrew Fort.
  2502. ##
  2503. ## Redistribution and use in source and binary forms, with or without
  2504. ## modification, are permitted provided that the following conditions
  2505. ## are met:
  2506. ## 1. Redistributions of source code must retain the above copyright
  2507. ## notice, this list of conditions and the following disclaimer.
  2508. ## 2. Redistributions in binary form must reproduce the above copyright
  2509. ## notice, this list of conditions and the following disclaimer in the
  2510. ## documentation and/or other materials provided with the distribution.
  2511. ## 3. All advertising materials mentioning features or use of this software
  2512. ## must display the following acknowledgement:
  2513. ## This product includes software developed by Terrapin Communications,
  2514. ## Inc. and its contributors for RANCID.
  2515. ## 4. Neither the name of Terrapin Communications, Inc. nor the names of its
  2516. ## contributors may be used to endorse or promote products derived from
  2517. ## this software without specific prior written permission.
  2518. ## 5. It is requested that non-binding fixes and modifications be contributed
  2519. ## back to Terrapin Communications, Inc.
  2520. ##
  2521. ## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS
  2522. ## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  2523. ## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  2524. ## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
  2525. ## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  2526. ## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  2527. ## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  2528. ## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  2529. ## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  2530. ## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  2531. ## POSSIBILITY OF SUCH DAMAGE.
  2532. ##
  2533. ## It is the request of the authors, but not a condition of license, that
  2534. ## parties packaging or redistributing RANCID NOT distribute altered versions
  2535. ## of the etc/rancid.types.base file nor alter how this file is processed nor
  2536. ## when in relation to etc/rancid.types.conf. The goal of this is to help
  2537. ## suppress our support costs. If it becomes a problem, this could become a
  2538. ## condition of license.
  2539. #
  2540. # The expect login scripts were based on Erik Sherk's gwtn, by permission.
  2541. #
  2542. # The original looking glass software was written by Ed Kern, provided by
  2543. # permission and modified beyond recognition.
  2544. #
  2545. # rivlogin - Riverstone (and Enterasys SSR) login
  2546. #
  2547. # Based upon rscmd (see nmops.org)
  2548. # rscmd - Riverstone Networks Automated login
  2549. # by Mike MacFaden, Kiran Addepalli
  2550. # Riverstone Networks, 2000
  2551. #
  2552. # Returned to the RANCID crowd by andrew fort
  2553.  
  2554. # Usage line
  2555. set usage "Error: Usage: $argv0 \[-dV\] \[-noenable\] \
  2556. \[-f cloginrc-file\] \[-c command\] \[-Evar=x\] \[-s script-file\] \
  2557. \[-x command-file\] \[-t timeout\] \[-o output-file\] \
  2558. router \[router...\]\n"
  2559.  
  2560. # program diagnostics
  2561. set verbose 0
  2562. set success 1
  2563. set config 0
  2564.  
  2565. # in seconds to wait for data back from device
  2566. set timeoutdflt 10
  2567. # Some CLIs having problems if we write too fast (Extreme, PIX, Cat)
  2568. set send_human {.2 .1 .4 .2 1}
  2569. set tempfile "/tmp/rivlogin.[exec date]"
  2570.  
  2571. # cli command prompt
  2572. set my_prompt ">"
  2573. set enable_prompt "\#"
  2574.  
  2575. set default_user ""
  2576. set output_file ""
  2577. set conf_prompt "*\(config\)# "
  2578. set logging 0
  2579. set config_mode 0
  2580. # Save config, if prompted
  2581. set do_saveconfig 0
  2582.  
  2583. # Password file for routers to access
  2584. set password_file $env(HOME)/.cloginrc
  2585.  
  2586. # If no -c or -s specified, just automate router login ala rsh
  2587. set do_command 0
  2588. set do_script 0
  2589. set log_user 0
  2590.  
  2591. # The default CLI mode to login to is "enable" mode
  2592. set avenable 1
  2593.  
  2594. # The default is to look in the password file to find the passwords. This
  2595. # tracks if we receive them on the command line.
  2596. set do_passwd 1
  2597. set do_enapasswd 1
  2598. #
  2599. set send_human {.4 .4 .7 .3 5}
  2600.  
  2601. # Find the user in the ENV, or use the unix userid.
  2602. if {[ info exists env(CISCO_USER) ]} {
  2603. set default_user $env(CISCO_USER)
  2604. } elseif {[ info exists env(USER) ]} {
  2605. set default_user $env(USER)
  2606. } elseif {[ info exists env(LOGNAME) ]} {
  2607. set default_user $env(LOGNAME)
  2608. } else {
  2609. # This uses "id" which I think is portable. At least it has existed
  2610. # (without options) on all machines/OSes I've been on recently -
  2611. # unlike whoami or id -nu.
  2612. if [ catch {exec id} reason ] {
  2613. send_error "\nError: could not exec id: $reason\n"
  2614. exit 1
  2615. }
  2616. regexp {\(([^)]*)} "$reason" junk default_user
  2617. }
  2618. if {[ info exists env(CLOGINRC) ]} {
  2619. set password_file $env(CLOGINRC)
  2620. }
  2621.  
  2622. # Procedures Section
  2623.  
  2624.  
  2625. #
  2626. # Sets Xterm title if interactive...if its an xterm and the user cares
  2627. #
  2628. proc label { host } {
  2629. global env
  2630.  
  2631. # if CLOGIN has an 'x' in it, don't set the xterm name/banner
  2632. if [info exists env(CLOGIN)] {
  2633. if {[string first "x" $env(CLOGIN)] != -1} { return }
  2634. }
  2635.  
  2636. if [info exists env(TERM)] {
  2637. if [regexp \^(xterm|vs) $env(TERM) ignore ] {
  2638. send_user "\033]1;[lindex [split $host "."] 0]\a"
  2639. send_user "\033]2;$host\a"
  2640. }
  2641. }
  2642. }
  2643.  
  2644. # This is a helper function to make the password file easier to
  2645. # maintain.
  2646. # NOTES: Using this the password file has the form:
  2647. # add password sl* pete cow
  2648. # add password at* steve
  2649. # add password * hanky-pie
  2650. proc add { var args } {
  2651.  
  2652. global $var
  2653. lappend $var $args
  2654. }
  2655.  
  2656. # Loads the password file. Note that as this file is tcl, and that
  2657. # it is sourced, the user better know what to put in there, as it
  2658. # could install more than just password info... I will assume however,
  2659. # that a "bad guy" could just as easy put such code in the clogin
  2660. # script, so I will leave .cloginrc as just an extention of that script
  2661. proc source_password_file { } {
  2662. global env password_file read_password_file
  2663.  
  2664. if { [info exists read_password_file] } {
  2665. return 1
  2666. }
  2667.  
  2668. if { [info exists password_file] == 0 } {
  2669. set password_file $env(HOME)/.cloginrc
  2670. }
  2671.  
  2672. set read_password_file 1
  2673. file stat $password_file fileinfo
  2674.  
  2675. if { [expr ($fileinfo(mode) & 007)] != 0000 } {
  2676. puts "ERROR: $password_file must not be group or world readable and writable\n"
  2677. return 1
  2678. }
  2679.  
  2680. source $password_file
  2681. }
  2682.  
  2683. # pre: var is x, router is y
  2684. # post: return routerr entry from database else null string
  2685. proc find { var router } {
  2686.  
  2687. if {[ source_password_file ] == 0 } {
  2688. return {}
  2689. }
  2690.  
  2691. upvar $var list
  2692. if { [info exists list] } {
  2693. foreach line $list {
  2694. if { [string match -nocase [lindex $line 0] $router ] } {
  2695. return [lrange $line 1 end]
  2696. }
  2697. }
  2698. }
  2699. return {}
  2700. }
  2701.  
  2702. # pre: login completed ok
  2703. # post: terminate login session by closing tcp connection
  2704. proc auto_exit { } {
  2705.  
  2706. global telnet_id
  2707.  
  2708. if { $verbose == 1 } {
  2709. puts "DEBUG: auto_exit closing connection to pid $telnet_id\n"
  2710. }
  2711. close -i telnet_id
  2712. }
  2713.  
  2714. # perform login basic to a router
  2715. # pre: args are valid, router is reachable via network
  2716. # post: return 0 on successful login, else 1
  2717. #
  2718. # NOTE: a number of globals are setup: my_prompt, telnet_id are key
  2719. # and paging of cli output is disabled
  2720. proc login { router user userpswd passwd enapasswd } {
  2721.  
  2722. global login_array
  2723. global telnet_id
  2724. global expect_out
  2725. global spawn_id
  2726. global verbose
  2727. global config verbose my_prompt
  2728.  
  2729. if { $verbose == 1 } {
  2730. puts "DEBUG: login router = $router"
  2731. puts "DEBUG: login username = $user"
  2732. puts "DEBUG: login userpasswd = $userpswd"
  2733. puts "DEBUG: login passwd = $passwd"
  2734. puts "DEBUG: login enapasswd = $enapasswd"
  2735. }
  2736.  
  2737. spawn -noecho telnet $router
  2738. set telnet_id $spawn_id
  2739.  
  2740. if { $telnet_id == 0 } {
  2741. puts "ERROR: login: spawn telnet session failed.\n"
  2742. return 1
  2743. }
  2744.  
  2745. # wait for initial 'Press RETURN to...' response
  2746. sleep 0.3
  2747.  
  2748. expect "*"
  2749. send "\r"
  2750.  
  2751. # If password fails 3 times then expect again
  2752. set pass_attempt 0
  2753.  
  2754. expect {
  2755. -re ".*> " { }
  2756. "Password:" {
  2757. incr pass_attempt
  2758. send -- "$passwd\r"
  2759. exp_continue
  2760. }
  2761. "Username: " {
  2762. set pattempt 0
  2763.  
  2764. send -- "$user\r"
  2765. expect {
  2766. "Password: " {
  2767. incr pattempt
  2768. if {$pattempt == 1} {
  2769. send -- "$userpswd\r";
  2770. } else {
  2771. send -- "$enapasswd\r";
  2772. }
  2773. exp_continue
  2774. }
  2775. -re ".*> " { exp_continue;}
  2776. }
  2777. }
  2778. "%TELNETD-W-BADPASSWD" {
  2779. puts "ERROR: bad userid or password to telnet."
  2780. return 1
  2781. }
  2782. "%CONS-W-AUTH_PASSWD" {
  2783. exp_continue
  2784. }
  2785. "% Authentication failed." {
  2786. puts "ERROR: bad userid or password to telnet."
  2787. return 1
  2788. }
  2789. "Authentication Failed:" {
  2790. puts "ERROR: bad userid or password to radius/tacacs+"
  2791. return 1
  2792. }
  2793. "Connection closed *" {
  2794. if {$pass_attempt == 3} {
  2795. puts "ERROR: Maximum attempts for password reached. Check password. Exiting.";
  2796. puts $expect_out(0,string);
  2797. return 1
  2798. }
  2799. }
  2800. timeout {
  2801. puts "ERROR: Timeout on login. Exiting.";
  2802. return 1
  2803. }
  2804. eof {
  2805. puts "ERROR: device closed telnet connection during login"
  2806. return 1
  2807. }
  2808. }
  2809.  
  2810. # save my_prompt for later use
  2811. send "\r"
  2812. expect -re ".*> "
  2813. set abc "$expect_out(buffer)"
  2814. set my_prompt "[lindex $abc 0]"
  2815. regexp {(.*[^>])} $my_prompt my
  2816.  
  2817. return 0;
  2818. }
  2819.  
  2820.  
  2821. # pre: login completed ok
  2822. # post: turn off paging of commands
  2823. proc disable_cli_paging { } {
  2824. global my_prompt
  2825.  
  2826. send "cli set terminal rows 0\r"
  2827.  
  2828. expect {
  2829. "$my_prompt" {return 0 }
  2830. }
  2831. return 1
  2832. }
  2833.  
  2834. # pre: login returned 0, prompt at top level
  2835. # post: turn off command completion return 0
  2836. # on error, return 1
  2837. proc disable_cmd_autocomplete { } {
  2838. global my_prompt
  2839.  
  2840. send "cli set command completion off\r"
  2841. expect {
  2842. $my_prompt { }
  2843.  
  2844. timeout {
  2845. puts "ERROR:disable_cmd_autocomplete(TIMEOUT)";
  2846. return 0;
  2847. }
  2848. }
  2849.  
  2850. return 0
  2851. }
  2852.  
  2853. # pre: login returned 0, do_enable returned 0, cli is in enable or config mode
  2854. # post: issues logout cli to device, returns 0
  2855. proc logout { prompt } {
  2856. global config_mode enable_prompt
  2857.  
  2858. # in case of not being at root cmd...
  2859. # verify top level prompt state, move to it if necessary
  2860. if { $config_mode == 1 } {
  2861. send "exit\r"
  2862.  
  2863. expect {
  2864. "Do you want*" {
  2865. send "no\r"
  2866. }
  2867. "$enable_prompt" { }
  2868. timeout { puts "ERROR: logout: timeout from config mode\n" }
  2869. eof { puts "ERROR: device dropped connection\n" }
  2870. }
  2871. set config_mode 0
  2872. }
  2873.  
  2874. send "logout\r"
  2875. expect {
  2876. "Are you sure*" {
  2877. send "yes\r"
  2878. return 0
  2879. }
  2880. }
  2881. }
  2882.  
  2883. # pre: current mode allows transition to enable mode
  2884. # post: enable mode entered, my_prompt updated, return 0 else 1
  2885. proc do_enable { enauser enapasswd userpswd } {
  2886. global expect_out verbose
  2887. global my_prompt enable_prompt
  2888. set enable_prompt [ string trimright $my_prompt ">" ]
  2889. set enable_prompt $enable_prompt\#
  2890. set uses_username 0;
  2891.  
  2892. if { $verbose == 1 } {
  2893. puts "DEBUG: do_enable: my_prompt = $my_prompt ena_prompt = $enable_prompt"
  2894. }
  2895.  
  2896. send "enable\r"
  2897.  
  2898. expect {
  2899. Username: {
  2900. set uses_username 1;
  2901. send -- "$enauser\r";
  2902. exp_continue
  2903. }
  2904. Password: {
  2905. if {$uses_username == 1} {
  2906. send -- "$userpswd\r";
  2907. } else {
  2908. send -- "$enapasswd\r";
  2909. }
  2910. exp_continue
  2911. }
  2912. "$my_prompt" {
  2913. puts "ERROR: do_enable failed to gain enable mode."
  2914. return 1
  2915. }
  2916. "CONS-W-AUTH_PASSWD" { send -- "$enapasswd\r"; }
  2917. "$enable_prompt " { }
  2918. "%SYS-W-NOPASSWD*" { }
  2919. "Authentication Failed: Access Denied" {
  2920. puts "ERROR: Bad user or password for enable mode."
  2921. return 1
  2922. }
  2923. }
  2924.  
  2925. set my_prompt $enable_prompt
  2926. return 0
  2927. }
  2928.  
  2929. # pre: current mode allows transition to enable mode
  2930. # post: enable mode entered, my_prompt updated, return 0 else 1
  2931. proc do_configure { } {
  2932. global expect_out verbose config_mode
  2933. global my_prompt
  2934. set config_prompt [ string trimright $my_prompt "\#" ]
  2935. set config_prompt $config_prompt\(config\)\#
  2936.  
  2937. if { $verbose == 1 } {
  2938. puts "DEBUG: do_config: my_prompt = $my_prompt cfg_prompt = $config_prompt"
  2939. }
  2940.  
  2941. send "configure\r"
  2942. expect {
  2943. "$config_prompt " { }
  2944. "$my_prompt" { }
  2945. eof { return 1}
  2946. timeout { return 1}
  2947. }
  2948.  
  2949. set config_mode 1
  2950. set my_prompt $config_prompt
  2951. return 0
  2952. }
  2953.  
  2954. # track sent/received from device to output_file
  2955. # pre: outut_file is valid filename w/write access
  2956. # post: logfile open, global var logging == 1, return 0 , else 1
  2957. proc start_logfile { output_file } {
  2958. global logging
  2959.  
  2960. if { [ string length $output_file ] != 0 } {
  2961. set rc [ catch { log_file -noappend $output_file } errMsg ]
  2962.  
  2963. if { $rc != 0 } {
  2964. puts "ERROR: open file $output_file for write access failed. $errMsg\n"
  2965. return 1
  2966. }
  2967. set logging 1
  2968. }
  2969.  
  2970. return 0
  2971. }
  2972.  
  2973. proc run_commands { prompt cmdstring } {
  2974. global sendstring
  2975.  
  2976. # handle escaped ;s in commands, and ;; and ^;
  2977. regsub -all {([^\\]);;} $command "\\1;\u002;" esccommand
  2978. regsub {^;} $esccommand "\u002;" command
  2979. set sep "\\1\u001"
  2980. regsub -all {([^\\])\;} $command "$sep" esccommand
  2981. set sep "\u001"
  2982. set commands [split $esccommand $sep]
  2983. set num_commands [llength $cmdstring]
  2984.  
  2985. for {set i 0} {$i < $num_commands} { incr i} {
  2986. regsub -- {[ ]*([^\.]*)} [subst -nocommands [lindex $commands $i]] {\1} sendstring
  2987.  
  2988. if {[ run_single_command $prompt $sendstring ] == 1} {
  2989. puts "ERROR: command '$sendstring' not processed by device. Check previous error messages."
  2990. return 1
  2991. }
  2992. }
  2993. return 0
  2994. }
  2995.  
  2996. # Run commands given on the command line
  2997. # pre: prompt is current system cli prompt, cmdstring is command to execute
  2998. # post: return 0 on success else 1
  2999. # NOTE: output from router ends up in output_file if specified
  3000. # expect internal input buffer is reset to "" after each command
  3001. proc run_single_command { prompt cmdstring } {
  3002. global verbose
  3003. set rc 0
  3004. set seen_prompt 0
  3005. set seen_timeout 0
  3006. set need_ays 0
  3007. set delay 0
  3008.  
  3009. if {$verbose == 1} {
  3010. puts "DEBUG: run_commands: prompt=$prompt \"$cmdstring\" "
  3011. }
  3012.  
  3013. # ays == "are you sure" - must send back yes
  3014. if { [string compare $cmdstring "save startup" ] == 0 } {
  3015. set need_ays 1
  3016. set delay 1
  3017. if {$verbose == 1} {
  3018. puts "DEBUG: save startup cmd seen, set need_ays = 1"
  3019. }
  3020. }
  3021.  
  3022. # TODO: add case for copy command to startup, also prompts for ok
  3023.  
  3024. # TODO: if we see config command: system set name note it
  3025. # if we see a save active, then update system prompts as well
  3026.  
  3027. send "$cmdstring\r"
  3028.  
  3029. if { $delay == 1} {
  3030. sleep 1
  3031. }
  3032.  
  3033. expect {
  3034. "%CLI-E-IVCMD*" {
  3035. puts "ERROR: run_commands(command rejected by device)\n"
  3036. set rc 1
  3037. }
  3038. "%CLI-E-FACUNKNWN*" {
  3039. puts "ERROR: run_commands(command rejected by device)\n"
  3040. set rc 1
  3041. }
  3042. "%SYS-I-ADDFAILED*" {
  3043. puts "ERROR: run_commands(command rejected by device)\n"
  3044. set rc 1
  3045. }
  3046. "%TFTP-E-REMOTE,*" {
  3047. puts "ERROR: run_commands(command rejected by device)\n"
  3048. set rc 1
  3049. }
  3050. "%SYS-E-PRIMARY_NO_SUCH_IMAGE*" {
  3051. puts "ERROR: run_commands(command rejected by device)\n"
  3052. set rc 1
  3053. }
  3054. "want to overwrite " {
  3055. send "yes\r"
  3056. if {$verbose == 1} {
  3057. puts "DEBUG: got overwrite question, set need_ays to 0"
  3058. }
  3059. set need_ays 0
  3060. }
  3061. "%CONFIG-E-DUPLICATE,*" { }
  3062. "$prompt" {
  3063. if { $seen_prompt == 0 } {
  3064. set seen_prompt 1
  3065. }
  3066.  
  3067. if {$verbose == 1} {
  3068. puts "DEBUG: saw double prompt, exiting expect loop\n"
  3069. }
  3070.  
  3071. if { $need_ays == 1 } {
  3072. exp_continue
  3073. }
  3074. }
  3075. -re ".* More: m,<space> --- Quit: q --- One line: <return> ---" {
  3076. send "q"
  3077. exp_continue
  3078. }
  3079. timeout {
  3080. if {$verbose == 1} {
  3081. puts "DEBUG: timeout occured for the $seen_time time\n"
  3082. }
  3083.  
  3084. if { $seen_timeout == 0 } {
  3085. set seen_timeout 1
  3086. send "\r\r"
  3087. exp_continue
  3088. }
  3089.  
  3090. puts "ERROR:run_commands(TIMEOUT)"
  3091. set rc 1
  3092. }
  3093. eof {
  3094. puts "ERROR:run_commands(connection closed by device)\n"
  3095. set rc 1
  3096. }
  3097. "\n" { exp_continue }
  3098. }
  3099.  
  3100. # clear input buffer of any remaining data
  3101. expect "*"
  3102. return $rc
  3103. }
  3104.  
  3105.  
  3106. # pre: RSTONE_USER env var is set
  3107. # post: update global "default_user" to this string
  3108. proc init_userid { } {
  3109. global default_user
  3110.  
  3111. if {[ info exists env(RSTONE_USER) ] } {
  3112. set default_user $env(RSTONE_USER)
  3113. } else {
  3114. # This uses "id" which I think is portable. At least it has existed
  3115. # (without options) on all machines/OSes I've been on recently -
  3116. # unlike whoami or id -nu.
  3117. regexp {\(([^)]*)} [exec id] junk default_user
  3118. }
  3119. }
  3120.  
  3121. proc source_script_file { filename } {
  3122. global my_prompt
  3123.  
  3124. expect -re "$my_prompt" {}
  3125.  
  3126. source $filename
  3127. }
  3128.  
  3129. # pre: login completed ok, filename contains set of cli commands one per line
  3130. # post: each command is extracted from filename and sent to device
  3131. # return 0 on success, return 1 on error
  3132. # NOTE: for scripts that begin with "configure", change the mode to configure
  3133. # before executing the following commands
  3134. proc process_script_file { filename } {
  3135. global my_prompt verbose
  3136. set rc 0
  3137. set ifile ""
  3138.  
  3139. set rc [ catch { set ifile [ open $filename r] } errMsg ]
  3140.  
  3141. if { $rc != 0 } {
  3142. puts "ERROR: process_script_file: open script file $filename for read access failed. $errMsg\n"
  3143. return 1
  3144. }
  3145.  
  3146. set line_cnt 0
  3147.  
  3148. while { [eof $ifile] != 1 } {
  3149.  
  3150. set bytes [ gets $ifile cmd ]
  3151. incr line_cnt
  3152.  
  3153. if { $bytes < 0 } {
  3154. break
  3155. } elseif { $bytes == 0 } {
  3156. continue
  3157. }
  3158.  
  3159. if { $verbose == 1 } {
  3160. puts "DEBUG: line:$line_cnt cmd = $cmd\n"
  3161. }
  3162.  
  3163. # skip comments in script files
  3164. if { [regexp "^\#" $cmd] != 1 } {
  3165.  
  3166. # puts "$cmd rc = [string compare $cmd "configure" ]\n"
  3167.  
  3168. if { [string compare $cmd "configure" ] == 0 } {
  3169.  
  3170. do_configure
  3171.  
  3172. } else {
  3173. if {[ run_commands $my_prompt $cmd ] == 1} {
  3174. puts "ERROR: line $line_cnt in $filename not processed by device. Check previous error msgs."
  3175. set rc 1
  3176. break
  3177. }
  3178. }
  3179. }
  3180. }
  3181.  
  3182. close $ifile
  3183. return $rc
  3184. }
  3185.  
  3186. # pre: filename is valid file
  3187. # post: remove extended ascii sequences and other cruft
  3188. # and prepend a header: rscmd: ip-addr : date
  3189. # TODO: should watch all file commands more closely
  3190. proc strip_log { filename router } {
  3191. global tempfile
  3192.  
  3193. set rc [ catch { set ifile [ open $filename r] } errMsg ]
  3194.  
  3195. if { $rc != 0 } {
  3196. puts "ERROR: strip_log: open script file $filename for read access failed. $errMsg\n"
  3197. return 1
  3198. }
  3199. set rc [ catch { set ofile [ open $tempfile w] } errMsg ]
  3200.  
  3201. if { $rc != 0 } {
  3202. puts "ERROR: strip_log: open temp file $tempfile for write access failed. $errMsg\n"
  3203. return 1
  3204. }
  3205.  
  3206. set nl 0
  3207.  
  3208. puts $ofile "rscmd: $router : [exec date]"
  3209.  
  3210. while { [eof $ifile] != 1 } {
  3211. set bytes [ gets $ifile cmd ]
  3212. if { $bytes <= 0 } {
  3213. break
  3214. }
  3215. incr nl
  3216. if { $nl <= 2 } {
  3217. continue
  3218. }
  3219.  
  3220. regsub -all -- "\r" $cmd "" newcmd
  3221. puts $ofile $newcmd
  3222. }
  3223.  
  3224. close $ifile
  3225. close $ofile
  3226. set rc 0
  3227. file copy -force $tempfile $filename
  3228. file delete $tempfile
  3229. return $rc
  3230. }
  3231.  
  3232. #
  3233. # main section
  3234. #
  3235. if { $verbose == 1 } {
  3236. puts "\n\nrscmd: Version 1.1 started on [exec date]"
  3237. puts "[exec uname -a]"
  3238. puts "Expect Version: [exp_version]\n"
  3239. }
  3240.  
  3241. # send input like in a fast and consistent human style
  3242. set send_human {.1 .3 1 .05 2}
  3243.  
  3244. # initialize default_user variable
  3245. init_userid
  3246.  
  3247. # Parse Command Line
  3248. for {set idx 0} {$idx < $argc} {incr idx} {
  3249. set arg [lindex $argv $idx]
  3250.  
  3251. switch -glob -- $arg {
  3252. -c* {
  3253. if {! [ regexp .\[cC\](.+) $arg ignore command]} {
  3254. incr idx
  3255. set command [ lindex $argv $idx ]
  3256. }
  3257. set do_command 1
  3258. # Expect debug mode
  3259. } -d* {
  3260. exp_internal 1
  3261. # Environment variable to pass to -s scripts
  3262. } -E*
  3263. {
  3264. if {[ regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} {
  3265. set E$varname $varvalue
  3266. } else {
  3267. send_user "Error: invalid format for -E in $arg\n"
  3268. exit 1
  3269. }
  3270. # Expect script to run
  3271. } -s* {
  3272. if {! [ regexp .\[sS\](.+) $arg ignore sfile]} {
  3273. incr idx
  3274. set sfile [ lindex $argv $idx ]
  3275. }
  3276.  
  3277. if { ! [ file exists $sfile ] } {
  3278. puts "ERROR: invalid argument script file \"$sfile\" does not exist.\n"
  3279. exit 1
  3280. }
  3281. if { ! [ file readable $sfile ] } {
  3282. puts "ERROR: invalid argument script file \"$sfile\" permissions disallow read access.\n"
  3283. exit 1
  3284. }
  3285.  
  3286. set do_script 1
  3287. # save config on exit
  3288. } -S* {
  3289. set do_saveconfig 1
  3290. # Version string
  3291. } -V* {
  3292. send_user "rancid 3.4.1\n"
  3293. exit 0
  3294. # Command file
  3295. } -x* {
  3296. if {! [ regexp .\[xX\](.+) $arg ignore cmd_file]} {
  3297. incr idx
  3298. set cmd_file [ lindex $argv $idx ]
  3299. }
  3300. if [ catch {set cmd_fd [open $cmd_file r]} reason ] {
  3301. send_user "\nError: $reason\n"
  3302. exit 1
  3303. }
  3304. set cmd_text [read $cmd_fd]
  3305. close $cmd_fd
  3306. set command [join [split $cmd_text \n] \;]
  3307. set do_command 1
  3308. } -f* {
  3309. if {! [ regexp .\[fF\](.+) $arg ignore password_file]} {
  3310. incr idx
  3311. set password_file [ lindex $argv $idx ]
  3312. }
  3313. } -o* {
  3314. if {! [ regexp .\[fF\](.+) $arg ignore password_file]} {
  3315. incr idx
  3316. set output_file [ lindex $argv $idx ]
  3317. if { $verbose == 1 } {
  3318. puts "DEBUG: output file: $output_file"
  3319. }
  3320. }
  3321. # Timeout
  3322. } -t* {
  3323. incr idx
  3324. set timeoutdflt [ lindex $argv $idx ]
  3325. # Do we enable?
  3326. } -noenable {
  3327. set avenable 0
  3328. } -* {
  3329. send_user "Error: Unkown argument! $arg\n"
  3330. send_user $usage
  3331. exit 1
  3332. } default {
  3333. break
  3334. }
  3335. }
  3336. }
  3337.  
  3338. # Verify at least one router is specified
  3339. #
  3340. if { $idx == $argc } {
  3341. puts "\n$usage"
  3342. exit 1
  3343. }
  3344.  
  3345. # main loop
  3346. set exitval 0
  3347. foreach router [lrange $argv $idx end] {
  3348. set router [string tolower $router]
  3349. send_user -- "$router\n"
  3350.  
  3351. # device timeout
  3352. set timeout [find timeout $router]
  3353. if { [llength $timeout] == 0 } {
  3354. set timeout $timeoutdflt
  3355. }
  3356.  
  3357. # Figure out passwords
  3358. if {$verbose == 1} {
  3359. puts "DEBUG: do_passwd = $do_passwd\n"
  3360. puts "DEBUG: do_enablepasswd = $do_enapasswd\n"
  3361. }
  3362.  
  3363. # look for noenable option in .cloginrc
  3364. if { [find noenable $router] == "1" } {
  3365. set enable 0
  3366. } else {
  3367. set enable $avenable
  3368. }
  3369.  
  3370. if { $do_passwd || $do_enapasswd } {
  3371. set pswd [find password $router]
  3372. if { [llength $pswd] == 0 } {
  3373. puts "ERROR: - no password for $router in $password_file.\n"
  3374. exit 1
  3375. }
  3376. if { $do_enapasswd && [llength $pswd] < 2 } {
  3377. puts "ERROR: no enable password found for $router in $password_file."
  3378. exit 1
  3379. }
  3380.  
  3381. set passwd [join [lindex $pswd 0] ""]
  3382. set enapasswd [join [lindex $pswd 1] ""]
  3383. } else {
  3384. set passwd $userpasswd
  3385. set enapasswd $enapasswd
  3386. }
  3387.  
  3388. # Figure out user to login with if necessary
  3389. if {[info exists username]} {
  3390. # command line username
  3391. set user $username
  3392. } else {
  3393. set user [join [find user $router] ""]
  3394. if { "$user" == "" } { set user $default_user }
  3395. }
  3396.  
  3397. # Figure out username's password
  3398. if {[info exists userpasswd]} {
  3399. # command line username
  3400. set userpswd $userpasswd
  3401. } else {
  3402. set userpswd [join [find userpassword $router] ""]
  3403. if { "$userpswd" == "" } { set userpswd $passwd }
  3404. }
  3405.  
  3406. # Figure out enable username
  3407. if {[info exists enausername]} {
  3408. # command line enausername
  3409. set enauser $enausername
  3410. } else {
  3411. set enauser [join [find enauser $router] ""]
  3412. if { "$enauser" == "" } { set enauser $user }
  3413. }
  3414.  
  3415. # Login to the router, set my_prompt to router's cmd prompt
  3416. if {[login $router $user $userpswd $passwd $enapasswd ]} {
  3417. incr exitval
  3418. if { $verbose == 1 } {
  3419. puts "DEBUG: login to $router failed\n"
  3420. }
  3421. exit 1
  3422. }
  3423.  
  3424. if {$verbose == 1 } {
  3425. puts "DEBUG: login completed ok\n"
  3426. }
  3427.  
  3428. if { $enable == 1 } {
  3429. if { [do_enable $enauser $enapasswd $userpswd] == 1} {
  3430. incr exitval
  3431. if { $verbose == 1 } {
  3432. puts "DEBUG: switch to enable mode on $router failed\n"
  3433. }
  3434. exit 1
  3435. }
  3436. }
  3437.  
  3438. # run in one of three modes
  3439. if { $do_command } {
  3440. disable_cmd_autocomplete
  3441. disable_cli_paging
  3442.  
  3443. if { [start_logfile $output_file] != 0 } {
  3444. exit 1
  3445. }
  3446.  
  3447. if {[ run_commands $my_prompt $command ]} {
  3448. incr exitval
  3449. log_file
  3450. exit 1
  3451. } else {
  3452. logout $my_prompt
  3453. }
  3454. } elseif { $do_script } {
  3455. disable_cmd_autocomplete
  3456. disable_cli_paging
  3457.  
  3458. if {[ start_logfile $output_file] != 0 } {
  3459. exit 1
  3460. }
  3461.  
  3462. # if { [process_script_file $sfile] == 1}{
  3463. # puts "DEBUG: logfile $output_file closed on error\n"
  3464. # logout $my_prompt
  3465. # exit 1
  3466. # }
  3467.  
  3468. source_script_file $sfile
  3469.  
  3470. logout $my_prompt
  3471. } else {
  3472. label $router
  3473. log_user 1
  3474.  
  3475. if {[ start_logfile $output_file] != 0 } {
  3476. exit 1
  3477. }
  3478. interact
  3479. log_file
  3480. }
  3481.  
  3482. if { $verbose == 1 } {
  3483. puts "DEBUG: exiting normally.\n"
  3484. }
  3485.  
  3486. if { $logging == 1} {
  3487. log_file
  3488. strip_log $output_file $router
  3489. }
  3490.  
  3491. # End of for each router
  3492. catch {wait};
  3493. sleep 0.3
  3494. }
  3495. exit $exitval
  3496. #! /usr/bin/perl
  3497. ##
  3498. ## $Id: rivrancid.in 3018 2015-01-11 05:51:49Z heas $
  3499. ##
  3500. ## rancid 3.4.1
  3501. ## Copyright (c) 1997-2016 by Terrapin Communications, Inc.
  3502. ## All rights reserved.
  3503. ##
  3504. ## This code is derived from software contributed to and maintained by
  3505. ## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan,
  3506. ## Pete Whiting, Austin Schutz, and Andrew Fort.
  3507. ##
  3508. ## Redistribution and use in source and binary forms, with or without
  3509. ## modification, are permitted provided that the following conditions
  3510. ## are met:
  3511. ## 1. Redistributions of source code must retain the above copyright
  3512. ## notice, this list of conditions and the following disclaimer.
  3513. ## 2. Redistributions in binary form must reproduce the above copyright
  3514. ## notice, this list of conditions and the following disclaimer in the
  3515. ## documentation and/or other materials provided with the distribution.
  3516. ## 3. All advertising materials mentioning features or use of this software
  3517. ## must display the following acknowledgement:
  3518. ## This product includes software developed by Terrapin Communications,
  3519. ## Inc. and its contributors for RANCID.
  3520. ## 4. Neither the name of Terrapin Communications, Inc. nor the names of its
  3521. ## contributors may be used to endorse or promote products derived from
  3522. ## this software without specific prior written permission.
  3523. ## 5. It is requested that non-binding fixes and modifications be contributed
  3524. ## back to Terrapin Communications, Inc.
  3525. ##
  3526. ## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS
  3527. ## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  3528. ## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  3529. ## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
  3530. ## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  3531. ## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  3532. ## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  3533. ## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  3534. ## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  3535. ## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  3536. ## POSSIBILITY OF SUCH DAMAGE.
  3537. #
  3538. # Amazingly hacked version of Hank's rancid - this one tries to
  3539. # deal with Cabletron, Riverstone and Enterasys routers/switches
  3540. #
  3541. # 10/23/2002 -- Initial changes for Riverstone/Cabletron support
  3542. # Jim Meehan -- jmeehan@vpizza.org
  3543. #
  3544. # RANCID - Really Awesome New Cisco confIg Differ
  3545. #
  3546. # usage: rivrancid [-dltCV] [-f filename | hostname]
  3547. #
  3548. use Getopt::Std;
  3549. getopts('dflt:CV');
  3550. if ($opt_V) {
  3551. print "rancid 3.4.1\n";
  3552. exit(0);
  3553. }
  3554. $log = $opt_l;
  3555. $debug = $opt_d;
  3556. $file = $opt_f;
  3557. $host = $ARGV[0];
  3558. $clean_run = 0;
  3559. $found_end = 0;
  3560. $timeo = 90; # rivlogin timeout in seconds
  3561.  
  3562. my(@commandtable, %commands, @commands);# command lists
  3563. my($aclsort) = ("ipsort"); # ACL sorting mode
  3564. my($filter_commstr); # SNMP community string filtering
  3565. my($filter_pwds); # password filtering mode
  3566.  
  3567. # This routine is used to print out the router configuration
  3568. sub ProcessHistory {
  3569. my($new_hist_tag,$new_command,$command_string,@string) = (@_);
  3570. if ((($new_hist_tag ne $hist_tag) || ($new_command ne $command))
  3571. && scalar(%history)) {
  3572. print eval "$command \%history";
  3573. undef %history;
  3574. }
  3575. if (($new_hist_tag) && ($new_command) && ($command_string)) {
  3576. if ($history{$command_string}) {
  3577. $history{$command_string} = "$history{$command_string}@string";
  3578. } else {
  3579. $history{$command_string} = "@string";
  3580. }
  3581. } elsif (($new_hist_tag) && ($new_command)) {
  3582. $history{++$#history} = "@string";
  3583. } else {
  3584. print "@string";
  3585. }
  3586. $hist_tag = $new_hist_tag;
  3587. $command = $new_command;
  3588. 1;
  3589. }
  3590.  
  3591. sub numerically { $a <=> $b; }
  3592.  
  3593. # This is a sort routine that will sort numerically on the
  3594. # keys of a hash as if it were a normal array.
  3595. sub keynsort {
  3596. local(%lines) = @_;
  3597. local($i) = 0;
  3598. local(@sorted_lines);
  3599. foreach $key (sort numerically keys(%lines)) {
  3600. $sorted_lines[$i] = $lines{$key};
  3601. $i++;
  3602. }
  3603. @sorted_lines;
  3604. }
  3605.  
  3606. # This is a sort routine that will sort on the
  3607. # keys of a hash as if it were a normal array.
  3608. sub keysort {
  3609. local(%lines) = @_;
  3610. local($i) = 0;
  3611. local(@sorted_lines);
  3612. foreach $key (sort keys(%lines)) {
  3613. $sorted_lines[$i] = $lines{$key};
  3614. $i++;
  3615. }
  3616. @sorted_lines;
  3617. }
  3618.  
  3619. # This is a sort routine that will sort on the
  3620. # values of a hash as if it were a normal array.
  3621. sub valsort{
  3622. local(%lines) = @_;
  3623. local($i) = 0;
  3624. local(@sorted_lines);
  3625. foreach $key (sort values %lines) {
  3626. $sorted_lines[$i] = $key;
  3627. $i++;
  3628. }
  3629. @sorted_lines;
  3630. }
  3631.  
  3632. # This is a numerical sort routine (ascending).
  3633. sub numsort {
  3634. local(%lines) = @_;
  3635. local($i) = 0;
  3636. local(@sorted_lines);
  3637. foreach $num (sort {$a <=> $b} keys %lines) {
  3638. $sorted_lines[$i] = $lines{$num};
  3639. $i++;
  3640. }
  3641. @sorted_lines;
  3642. }
  3643.  
  3644. # This is a sort routine that will sort on the
  3645. # ip address when the ip address is anywhere in
  3646. # the strings.
  3647. sub ipsort {
  3648. local(%lines) = @_;
  3649. local($i) = 0;
  3650. local(@sorted_lines);
  3651. foreach $addr (sort sortbyipaddr keys %lines) {
  3652. $sorted_lines[$i] = $lines{$addr};
  3653. $i++;
  3654. }
  3655. @sorted_lines;
  3656. }
  3657.  
  3658. # These two routines will sort based upon IP addresses
  3659. sub ipaddrval {
  3660. my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#);
  3661. $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0]));
  3662. }
  3663. sub sortbyipaddr {
  3664. &ipaddrval($a) <=> &ipaddrval($b);
  3665. }
  3666.  
  3667. # This routine parses "system show version"
  3668. sub ShowVersion {
  3669. my($slot);
  3670.  
  3671. print STDERR " In ShowVersion: $_" if ($debug);
  3672.  
  3673. while (<INPUT>) {
  3674. tr/\015//d;
  3675. next if /^\s*$/;
  3676. last if(/^$prompt/);
  3677.  
  3678. ProcessHistory("VERSION","","","!SW: $_");
  3679. }
  3680. ProcessHistory("VERSION","","","!\n");
  3681. return(0);
  3682. }
  3683.  
  3684. # This routine parses "system show hardware"
  3685. sub ShowHardware {
  3686. print STDERR " In ShowHardware: $_" if ($debug);
  3687.  
  3688. while (<INPUT>) {
  3689. tr/\015//d;
  3690. last if (/^$prompt/);
  3691. ProcessHistory("HARDWARE","","","!HW: $_");
  3692. }
  3693. ProcessHistory("","","","!\n");
  3694. return(0);
  3695. }
  3696.  
  3697. # This routine parses "system show uptime"
  3698. sub ShowUptime {
  3699. print STDERR " In ShowUptime: $_" if ($debug);
  3700.  
  3701. while (<INPUT>) {
  3702. tr/\015//d;
  3703. last if(/^$prompt/);
  3704. next if /^\s*$/;
  3705. next if /System up/;
  3706. ProcessHistory("UPTIME","","","!UPTIME: $_");
  3707. }
  3708. ProcessHistory("","","","!\n");
  3709. return;
  3710. }
  3711.  
  3712. # This routine processes a "system show active"
  3713. sub ShowActive {
  3714. print STDERR " In ShowActive: $_" if ($debug);
  3715.  
  3716. while (<INPUT>) {
  3717. tr/\015//d;
  3718.  
  3719. # Remove leading whitespace and/or line numbers
  3720. s/^\s*(\d+\D: )*//;
  3721.  
  3722. # Riverstone/Cabletron doesn't have an "end" line, so
  3723. # we need to set $clean_run here
  3724. if (/^$prompt/) {
  3725. $clean_run = 1;
  3726. last;
  3727. }
  3728.  
  3729. next if (/Running system configuration/);
  3730.  
  3731. # filter out any RCS/CVS tags to avoid confusing local CVS storage
  3732. s/\$(Revision|Id):/ $1:/;
  3733.  
  3734. if (/^(.*hashed-password \S+)/ && $filter_pwds == 2) {
  3735. ProcessHistory("","","","! $1 <removed>\n");
  3736. next;
  3737. }
  3738.  
  3739. if (/^(snmp set community )\S+/ && $filter_commstr) {
  3740. ProcessHistory("","","","! $1<removed>$'");
  3741. next;
  3742. }
  3743.  
  3744. ProcessHistory("","","","$_");
  3745. }
  3746. return;
  3747. }
  3748.  
  3749. # Main
  3750. @commandtable = (
  3751. {'system show uptime' => 'ShowUptime'},
  3752. {'system show version' => 'ShowVersion'},
  3753. {'system show hardware' => 'ShowHardware'},
  3754. {'system show active-config' => 'ShowActive'}
  3755. );
  3756. # Use an array to preserve the order of the commands and a hash for mapping
  3757. # commands to the subroutine and track commands that have been completed.
  3758. @commands = map(keys(%$_), @commandtable);
  3759. %commands = map(%$_, @commandtable);
  3760. $commandcnt = scalar(keys %commands);
  3761.  
  3762. $commandstr=join(";",@commands);
  3763. $cmds_regexp = join("|", map quotemeta($_), @commands);
  3764.  
  3765. if (length($host) == 0) {
  3766. if ($file) {
  3767. print(STDERR "Too few arguments: file name required\n");
  3768. exit(1);
  3769. } else {
  3770. print(STDERR "Too few arguments: host name required\n");
  3771. exit(1);
  3772. }
  3773. }
  3774. if ($opt_C) {
  3775. print "rivlogin -t $timeo -c\'$commandstr\' $host\n";
  3776. exit(0);
  3777. }
  3778. open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n";
  3779. select(OUTPUT);
  3780. # make OUTPUT unbuffered if debugging
  3781. if ($debug) { $| = 1; }
  3782.  
  3783. if ($file) {
  3784. print STDERR "opening file $host\n" if ($debug);
  3785. print STDOUT "opening file $host\n" if ($log);
  3786. open(INPUT,"<$host") || die "open failed for $host: $!\n";
  3787. } else {
  3788. print STDERR "executing rivlogin -t $timeo -c\"$commandstr\" $host\n" if ($debug);
  3789. print STDOUT "executing rivlogin -t $timeo -c\"$commandstr\" $host\n" if ($log);
  3790. if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
  3791. system "rivlogin -t $timeo -c \"$commandstr\" $host </dev/null > $host.raw 2>&1" || die "rivlogin failed for $host: $!\n";
  3792. open(INPUT, "< $host.raw") || die "rivlogin failed for $host: $!\n";
  3793. } else {
  3794. open(INPUT,"rivlogin -t $timeo -c \"$commandstr\" $host </dev/null |") || die "rivlogin failed for $host: $!\n";
  3795. }
  3796. }
  3797.  
  3798. # determine ACL sorting mode
  3799. if ($ENV{"ACLSORT"} =~ /no/i) {
  3800. $aclsort = "";
  3801. }
  3802. # determine community string filtering mode
  3803. if (defined($ENV{"NOCOMMSTR"}) &&
  3804. ($ENV{"NOCOMMSTR"} =~ /yes/i || $ENV{"NOCOMMSTR"} =~ /^$/)) {
  3805. $filter_commstr = 1;
  3806. } else {
  3807. $filter_commstr = 0;
  3808. }
  3809. # determine password filtering mode
  3810. if ($ENV{"FILTER_PWDS"} =~ /no/i) {
  3811. $filter_pwds = 0;
  3812. } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) {
  3813. $filter_pwds = 2;
  3814. } else {
  3815. $filter_pwds = 1;
  3816. }
  3817.  
  3818. ProcessHistory("","","","!RANCID-CONTENT-TYPE: riverstone\n!\n");
  3819. TOP: while(<INPUT>) {
  3820. tr/\015//d;
  3821. last if ($clean_run);
  3822. if (/^Error:/) {
  3823. print STDOUT ("$host rivlogin error: $_");
  3824. print STDERR ("$host rivlogin error: $_") if ($debug);
  3825. $clean_run=0;
  3826. last;
  3827. }
  3828.  
  3829. $kradcount++;
  3830.  
  3831. while (/\033(\[\?25l)/) {
  3832. s/\033\[\?25l//g;
  3833. #print STDERR "krad $1\n";
  3834. #print STDERR $_;
  3835. #print STDERR $kradcount;
  3836. next;
  3837. }
  3838.  
  3839.  
  3840. while (/#\s*($cmds_regexp)\s*$/) {
  3841. $cmd = $1;
  3842. if (!defined($prompt)) {
  3843. $prompt = ($_ =~ /^([^#]+#)/)[0];
  3844. $prompt =~ s/([}{)(\\])/\\$1/g;
  3845. }
  3846. print STDERR ("HIT COMMAND:$_") if ($debug);
  3847. if (! defined($commands{$cmd})) {
  3848. print STDERR "$host: found unexpected command - \"$cmd\"\n";
  3849. $clean_run = 0;
  3850. last TOP;
  3851. }
  3852. $rval = &{$commands{$cmd}}(*INPUT, *OUTPUT, $cmd);
  3853. delete($commands{$cmd});
  3854. if ($rval == -1) {
  3855. $clean_run = 0;
  3856. last TOP;
  3857. }
  3858. }
  3859. }
  3860. print STDOUT "Done $logincmd: $_\n" if ($log);
  3861. # Flush History
  3862. ProcessHistory("","","","");
  3863. # Cleanup
  3864. close(INPUT);
  3865. close(OUTPUT);
  3866.  
  3867. if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
  3868. unlink("$host.raw") if (! $debug);
  3869. }
  3870.  
  3871. # check for completeness
  3872. if (scalar(%commands) || !$clean_run) {
  3873. if (scalar(keys %commands) eq $commandcnt) {
  3874. printf(STDERR "$host: missed cmd(s): all commands\n");
  3875. } elsif (scalar(%commands)) {
  3876. printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands)));
  3877. printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug);
  3878. }
  3879. if (!$clean_run) {
  3880. print STDOUT "$host: End of run not found\n";
  3881. print STDERR "$host: End of run not found\n" if ($debug);
  3882. system("/usr/bin/tail -1 $host.new");
  3883. }
  3884. unlink "$host.new" if (! $debug);
  3885. }
  3886. #! /usr/bin/perl
  3887. ##
  3888. ## $Id: rrancid.in 3018 2015-01-11 05:51:49Z heas $
  3889. ##
  3890. ## rancid 3.4.1
  3891. ## Copyright (c) 1997-2016 by Terrapin Communications, Inc.
  3892. ## All rights reserved.
  3893. ##
  3894. ## This code is derived from software contributed to and maintained by
  3895. ## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan,
  3896. ## Pete Whiting, Austin Schutz, and Andrew Fort.
  3897. ##
  3898. ## Redistribution and use in source and binary forms, with or without
  3899. ## modification, are permitted provided that the following conditions
  3900. ## are met:
  3901. ## 1. Redistributions of source code must retain the above copyright
  3902. ## notice, this list of conditions and the following disclaimer.
  3903. ## 2. Redistributions in binary form must reproduce the above copyright
  3904. ## notice, this list of conditions and the following disclaimer in the
  3905. ## documentation and/or other materials provided with the distribution.
  3906. ## 3. All advertising materials mentioning features or use of this software
  3907. ## must display the following acknowledgement:
  3908. ## This product includes software developed by Terrapin Communications,
  3909. ## Inc. and its contributors for RANCID.
  3910. ## 4. Neither the name of Terrapin Communications, Inc. nor the names of its
  3911. ## contributors may be used to endorse or promote products derived from
  3912. ## this software without specific prior written permission.
  3913. ## 5. It is requested that non-binding fixes and modifications be contributed
  3914. ## back to Terrapin Communications, Inc.
  3915. ##
  3916. ## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS
  3917. ## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  3918. ## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  3919. ## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
  3920. ## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  3921. ## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  3922. ## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  3923. ## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  3924. ## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  3925. ## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  3926. ## POSSIBILITY OF SUCH DAMAGE.
  3927. #
  3928. # hacked version of Hank's rancid - this one tries to deal with redbacks.
  3929. #
  3930. # RANCID - Really Awesome New Cisco confIg Differ
  3931. #
  3932. # usage: rrancid [-dltCV] [-f filename | hostname]
  3933. #
  3934. use Getopt::Std;
  3935. getopts('dflt:CV');
  3936. if ($opt_V) {
  3937. print "rancid 3.4.1\n";
  3938. exit(0);
  3939. }
  3940. $log = $opt_l;
  3941. $debug = $opt_d;
  3942. $file = $opt_f;
  3943. $host = $ARGV[0];
  3944. $clean_run = 0;
  3945. $found_end = 0;
  3946. $timeo = 90; # clogin timeout in seconds
  3947.  
  3948. my(@commandtable, %commands, @commands);# command lists
  3949. my($aclsort) = ("ipsort"); # ACL sorting mode
  3950. my($filter_commstr); # SNMP community string filtering
  3951. my($filter_pwds); # password filtering mode
  3952.  
  3953. # This routine is used to print out the router configuration
  3954. sub ProcessHistory {
  3955. my($new_hist_tag,$new_command,$command_string,@string) = (@_);
  3956. if ((($new_hist_tag ne $hist_tag) || ($new_command ne $command))
  3957. && scalar(%history)) {
  3958. print eval "$command \%history";
  3959. undef %history;
  3960. }
  3961. if (($new_hist_tag) && ($new_command) && ($command_string)) {
  3962. if ($history{$command_string}) {
  3963. $history{$command_string} = "$history{$command_string}@string";
  3964. } else {
  3965. $history{$command_string} = "@string";
  3966. }
  3967. } elsif (($new_hist_tag) && ($new_command)) {
  3968. $history{++$#history} = "@string";
  3969. } else {
  3970. print "@string";
  3971. }
  3972. $hist_tag = $new_hist_tag;
  3973. $command = $new_command;
  3974. 1;
  3975. }
  3976.  
  3977. sub numerically { $a <=> $b; }
  3978.  
  3979. # This is a sort routine that will sort numerically on the
  3980. # keys of a hash as if it were a normal array.
  3981. sub keynsort {
  3982. local(%lines) = @_;
  3983. local($i) = 0;
  3984. local(@sorted_lines);
  3985. foreach $key (sort numerically keys(%lines)) {
  3986. $sorted_lines[$i] = $lines{$key};
  3987. $i++;
  3988. }
  3989. @sorted_lines;
  3990. }
  3991.  
  3992. # This is a sort routine that will sort on the
  3993. # keys of a hash as if it were a normal array.
  3994. sub keysort {
  3995. local(%lines) = @_;
  3996. local($i) = 0;
  3997. local(@sorted_lines);
  3998. foreach $key (sort keys(%lines)) {
  3999. $sorted_lines[$i] = $lines{$key};
  4000. $i++;
  4001. }
  4002. @sorted_lines;
  4003. }
  4004.  
  4005. # This is a sort routine that will sort on the
  4006. # values of a hash as if it were a normal array.
  4007. sub valsort{
  4008. local(%lines) = @_;
  4009. local($i) = 0;
  4010. local(@sorted_lines);
  4011. foreach $key (sort values %lines) {
  4012. $sorted_lines[$i] = $key;
  4013. $i++;
  4014. }
  4015. @sorted_lines;
  4016. }
  4017.  
  4018. # This is a numerical sort routine (ascending).
  4019. sub numsort {
  4020. local(%lines) = @_;
  4021. local($i) = 0;
  4022. local(@sorted_lines);
  4023. foreach $num (sort {$a <=> $b} keys %lines) {
  4024. $sorted_lines[$i] = $lines{$num};
  4025. $i++;
  4026. }
  4027. @sorted_lines;
  4028. }
  4029.  
  4030. # This is a sort routine that will sort on the
  4031. # ip address when the ip address is anywhere in
  4032. # the strings.
  4033. sub ipsort {
  4034. local(%lines) = @_;
  4035. local($i) = 0;
  4036. local(@sorted_lines);
  4037. foreach $addr (sort sortbyipaddr keys %lines) {
  4038. $sorted_lines[$i] = $lines{$addr};
  4039. $i++;
  4040. }
  4041. @sorted_lines;
  4042. }
  4043.  
  4044. # These two routines will sort based upon IP addresses
  4045. sub ipaddrval {
  4046. my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#);
  4047. $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0]));
  4048. }
  4049. sub sortbyipaddr {
  4050. &ipaddrval($a) <=> &ipaddrval($b);
  4051. }
  4052.  
  4053. # This routine parses "show version"
  4054. sub ShowVersion {
  4055. print STDERR " In ShowVersion: $_" if ($debug);
  4056.  
  4057. while (<INPUT>) {
  4058. tr/\015//d;
  4059. last if(/^$prompt/);
  4060.  
  4061. /(Copyright|uptime|restarted|^\s*$)/ && next;
  4062. /(Up Time|Boot Time)/ && next;
  4063. ProcessHistory("COMMENTS","keysort","A1","!Image: $_");
  4064. }
  4065. return;
  4066. }
  4067.  
  4068. # This routine parses "dir /<fsys>"
  4069. sub DirFlash {
  4070. print STDERR " In DirFlash: $_" if ($debug);
  4071.  
  4072. my($dev) = (/\/(.*)$/);
  4073. while (<INPUT>) {
  4074. tr/\015//d;
  4075. last if(/^$prompt/);
  4076. /^\s*$/ && next;
  4077.  
  4078. /(Can\'t open|No such device)/ && return;
  4079. /is not a valid path on a local file system/ && return;
  4080. ProcessHistory("FLASH","keysort",$dev,"!Flash: $dev: $_");
  4081. }
  4082. ProcessHistory("FLASH","keysort",$dev,"!\n");
  4083. return;
  4084. }
  4085.  
  4086. # This routine parses "show hardware"
  4087. sub ShowHardware {
  4088. print STDERR " In ShowHardware: $_" if ($debug);
  4089.  
  4090. while (<INPUT>) {
  4091. tr/\015//d;
  4092. last if(/^$prompt/);
  4093. s/\s*$/\n/;
  4094.  
  4095. /Can not retrieve information/ && return;
  4096. /^Temperature:/ && next;
  4097. /^Voltage/ && next;
  4098. /^$/ && next;
  4099. #ProcessHistory("","","","!Chassis: $_") && next;
  4100. ProcessHistory("COMMENTS","keysort","B1","!Chassis: $_");
  4101. }
  4102. ProcessHistory("COMMENTS","keysort","B1","!\n");
  4103. return;
  4104. }
  4105.  
  4106. # This routine parses "show chassis"
  4107. sub ShowChassis {
  4108. print STDERR " In ShowChassis: $_" if ($debug);
  4109.  
  4110. while (<INPUT>) {
  4111. tr/\015//d;
  4112. last if(/^$prompt/);
  4113. last if(/^invalid input at/i);
  4114. next if(/^(\s*|\s*$cmd\s*|\s+\^)$/);
  4115.  
  4116. ProcessHistory("COMMENTS","keysort","C1","!Chassis: $_");
  4117. }
  4118. ProcessHistory("COMMENTS","keysort","C1","!\n");
  4119. return;
  4120. }
  4121.  
  4122. # This routine parses "show slot table"
  4123. sub ShowSlotTable {
  4124. print STDERR " In ShowSlotTable: $_" if ($debug);
  4125.  
  4126. while (<INPUT>) {
  4127. tr/\015//d;
  4128. last if(/^$prompt/);
  4129.  
  4130. /(Slot Table|^$)/ && next;
  4131. /^\s+\^/ && next;
  4132. /Invalid input at/ && return;
  4133. s/^\s*//;
  4134. ProcessHistory("COMMENTS","keysort","D1","!Slot Table: $_");
  4135. }
  4136. ProcessHistory("COMMENTS","keysort","D1","!\n");
  4137. return;
  4138. }
  4139.  
  4140. # This routine processes a "write term"
  4141. sub WriteTerm {
  4142. print STDERR " In WriteTerm: $_" if ($debug);
  4143.  
  4144. while (<INPUT>) {
  4145. tr/\015//d;
  4146. last if(/^$prompt/);
  4147. next if(/^\s*$/);
  4148.  
  4149. # /Non-Volatile memory is in use/ && return(-1); # NvRAM is locked
  4150. # Dog gone Cool matches to process the rest of the config
  4151. /^! last updated: .*$/ && next; # kill last updated line
  4152. /^Building configuration/ && next; # kill Building config line
  4153. /^Current configuration/ && next; # kill Current config line
  4154. /^! Configuration last changed by user / && next;
  4155. /^ length / && next; # kill length on serial lines
  4156. /^ width / && next; # kill width on serial lines
  4157. # filter out any RCS/CVS tags to avoid confusing local CVS storage
  4158. s/\$(Revision|Id):/ $1:/;
  4159. # order access-lists
  4160. /^access-list\s+(\d\d?)\s+(\S+)\s+(\S+)/ &&
  4161. ProcessHistory("ACL $1 $2","$aclsort","$3","$_") && next;
  4162. # prune snmp community statements
  4163. if (/^snmp (group|community) (\S+)/) {
  4164. if ($filter_commstr) {
  4165. ProcessHistory("SNMPSERVERCOMM","keysort","$_","!snmp $1 <removed>$'") && next;
  4166. } else {
  4167. ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && next;
  4168. }
  4169. }
  4170. ProcessHistory("","","","$_");
  4171. # end of config
  4172. if (/^end$/) {
  4173. $found_end = 1;
  4174. last;
  4175. }
  4176. }
  4177. return;
  4178. }
  4179.  
  4180. # Main subroutine that splits up the work
  4181. # All Subs return the name of the next function to use.
  4182. # If the sub returns a new funtion name, that name will be used
  4183. # else the main loop keeps using the current function
  4184. sub FlailHelplessly {
  4185. print STDERR "Flailing: $_" if ($debug);
  4186. print STDOUT "Flailing: $_" if ($log);
  4187. /#(show version)$/ && delete($commands{$1}) && return("ShowVersion");
  4188. /#(show hardware)$/ && delete($commands{$1}) && return("ShowHardware");
  4189. /#(show chassis)$/ && delete($commands{$1}) && return("ShowChassis");
  4190. /#(show slot table)$/ && delete($commands{$1}) && return("ShowSlotTable");
  4191. /#(show config)$/ && delete($commands{$1}) && return("WriteTerm");
  4192. return "FlailHelplessly";
  4193. }
  4194.  
  4195. # Main
  4196. @commandtable = (
  4197. {'show version' => 'ShowVersion'},
  4198. {'dir /flash' => 'DirFlash'},
  4199. {'dir /pcmcia0' => 'DirFlash'},
  4200. {'dir /pcmcia1' => 'DirFlash'},
  4201. {'show hardware' => 'ShowHardware'},
  4202. {'show chassis' => 'ShowChassis'},
  4203. {'show slot table' => 'ShowSlotTable'},
  4204. {'show config' => 'WriteTerm'}
  4205. );
  4206. # Use an array to preserve the order of the commands and a hash for mapping
  4207. # commands to the subroutine and track commands that have been completed.
  4208. @commands = map(keys(%$_), @commandtable);
  4209. %commands = map(%$_, @commandtable);
  4210. $commandcnt = scalar(keys %commands);
  4211.  
  4212. $redback_cmds=join(";",@commands);
  4213. $cmds_regexp = join("|", map quotemeta($_), @commands);
  4214.  
  4215. if (length($host) == 0) {
  4216. if ($file) {
  4217. print(STDERR "Too few arguments: file name required\n");
  4218. exit(1);
  4219. } else {
  4220. print(STDERR "Too few arguments: host name required\n");
  4221. exit(1);
  4222. }
  4223. }
  4224. if ($opt_C) {
  4225. print "clogin -t $timeo -c\'$commandstr\' $host\n";
  4226. exit(0);
  4227. }
  4228. open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n";
  4229. select(OUTPUT);
  4230. # make OUTPUT unbuffered
  4231. if ($debug) { $| = 1; }
  4232.  
  4233. if ($file) {
  4234. print STDERR "opening file $host\n" if ($debug);
  4235. print STDOUT "opening file $host\n" if ($log);
  4236. open(INPUT,"<$host") || die "open failed for $host: $!\n";
  4237. } else {
  4238. print STDERR "executing clogin -t $timeo -c\"$redback_cmds\" $host\n" if ($debug);
  4239. print STDOUT "executing clogin -t $timeo -c\"$redback_cmds\" $host\n" if ($log);
  4240.  
  4241. if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
  4242. system "clogin -t $timeo -c \"$redback_cmds\" $host </dev/null > $host.raw" || die "clogin failed for $host: $!\n";
  4243. open(INPUT, "< $host.raw") || die "clogin failed for $host: $!\n";
  4244. } else {
  4245. open(INPUT,"clogin -t $timeo -c \"$redback_cmds\" $host </dev/null |") || die "clogin failed for $host: $!\n";
  4246. }
  4247. }
  4248.  
  4249. # determine ACL sorting mode
  4250. if ($ENV{"ACLSORT"} =~ /no/i) {
  4251. $aclsort = "";
  4252. }
  4253. # determine community string filtering mode
  4254. if (defined($ENV{"NOCOMMSTR"}) &&
  4255. ($ENV{"NOCOMMSTR"} =~ /yes/i || $ENV{"NOCOMMSTR"} =~ /^$/)) {
  4256. $filter_commstr = 1;
  4257. } else {
  4258. $filter_commstr = 0;
  4259. }
  4260. # determine password filtering mode
  4261. if ($ENV{"FILTER_PWDS"} =~ /no/i) {
  4262. $filter_pwds = 0;
  4263. } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) {
  4264. $filter_pwds = 2;
  4265. } else {
  4266. $filter_pwds = 1;
  4267. }
  4268.  
  4269. ProcessHistory("","","","!RANCID-CONTENT-TYPE: redback\n!\n");
  4270. ProcessHistory("COMMENTS","keysort","B0","!\n");
  4271. ProcessHistory("COMMENTS","keysort","C0","!\n");
  4272. ProcessHistory("COMMENTS","keysort","E0","!\n");
  4273. while(<INPUT>) {
  4274. tr/\015//d;
  4275. if (/\#exit$/) {
  4276. $clean_run=1;
  4277. last;
  4278. }
  4279. if (/^Error:/) {
  4280. print STDOUT ("$host clogin error: $_");
  4281. print STDERR ("$host clogin error: $_") if ($debug);
  4282. $clean_run=0;
  4283. last;
  4284. }
  4285. while (/#\s*($cmds_regexp)\s*$/) {
  4286. $cmd = $1;
  4287. if (!defined($prompt)) {
  4288. $prompt = ($_ =~ /^([^#]*#)/)[0];
  4289. $prompt =~ s/([][}{)(\\])/\\$1/g; # quote the damn []'s
  4290. print STDERR ("PROMPT MATCH: $prompt\n") if ($debug);
  4291. }
  4292. print STDERR ("HIT COMMAND:$_") if ($debug);
  4293. if (! defined($commands{$cmd})) {
  4294. print STDERR "$host: found unexpected command - \"$cmd\"\n";
  4295. $clean_run = 0;
  4296. last;
  4297. }
  4298. $rval = &{$commands{$cmd}}(*INPUT, *OUTPUT, $cmd);
  4299. delete($commands{$cmd});
  4300. if ($rval == -1) {
  4301. $clean_run = 0;
  4302. last;
  4303. }
  4304. }
  4305. }
  4306. print STDOUT "Done $logincmd: $_\n" if ($log);
  4307. # Flush History
  4308. ProcessHistory("","","","");
  4309. # Cleanup
  4310. close(INPUT);
  4311. close(OUTPUT);
  4312.  
  4313. if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
  4314. unlink("$host.raw") if (! $debug);
  4315. }
  4316.  
  4317. # check for completeness
  4318. if (scalar(%commands) || !$clean_run || !$found_end) {
  4319. if (scalar(keys %commands) eq $commandcnt) {
  4320. printf(STDERR "$host: missed cmd(s): all commands\n");
  4321. } elsif (scalar(%commands)) {
  4322. printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands)));
  4323. printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug);
  4324. }
  4325. if (!$clean_run || !$found_end) {
  4326. print STDOUT "$host: End of run not found\n";
  4327. print STDERR "$host: End of run not found\n" if ($debug);
  4328. system("/usr/bin/tail -1 $host.new");
  4329. }
  4330. unlink "$host.new" if (! $debug);
  4331. }
  4332. #! /usr/bin/perl
  4333. ##
  4334. ## $Id: rtftpcopy.in 3187 2015-10-19 23:08:51Z heas $
  4335. ##
  4336. ## rancid 3.4.1
  4337. ## Copyright (c) 1997-2016 by Terrapin Communications, Inc.
  4338. ## All rights reserved.
  4339. ##
  4340. ## This code is derived from software contributed to and maintained by
  4341. ## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan,
  4342. ## Pete Whiting, Austin Schutz, and Andrew Fort.
  4343. ##
  4344. ## Redistribution and use in source and binary forms, with or without
  4345. ## modification, are permitted provided that the following conditions
  4346. ## are met:
  4347. ## 1. Redistributions of source code must retain the above copyright
  4348. ## notice, this list of conditions and the following disclaimer.
  4349. ## 2. Redistributions in binary form must reproduce the above copyright
  4350. ## notice, this list of conditions and the following disclaimer in the
  4351. ## documentation and/or other materials provided with the distribution.
  4352. ## 3. All advertising materials mentioning features or use of this software
  4353. ## must display the following acknowledgement:
  4354. ## This product includes software developed by Terrapin Communications,
  4355. ## Inc. and its contributors for RANCID.
  4356. ## 4. Neither the name of Terrapin Communications, Inc. nor the names of its
  4357. ## contributors may be used to endorse or promote products derived from
  4358. ## this software without specific prior written permission.
  4359. ## 5. It is requested that non-binding fixes and modifications be contributed
  4360. ## back to Terrapin Communications, Inc.
  4361. ##
  4362. ## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS
  4363. ## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  4364. ## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  4365. ## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
  4366. ## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  4367. ## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  4368. ## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  4369. ## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  4370. ## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  4371. ## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  4372. ## POSSIBILITY OF SUCH DAMAGE.
  4373. #
  4374. # copy configs from tftpboot within rancid; assumes CWD=<group>/configs and
  4375. # that /bin/domainname is the same domainname as the routers, which is
  4376. # replaced with "-confg" to form the filename expected in /tftpboot.
  4377. #
  4378. # usage: rtftpcopy [-dltCV] [-f filename | hostname]
  4379. #
  4380. use Getopt::Std;
  4381. getopts('dflt:CV');
  4382. if ($opt_V) {
  4383. print "rancid 3.4.1\n";
  4384. exit(0);
  4385. }
  4386. $log = $opt_l;
  4387. $debug = $opt_d;
  4388. $file = $opt_f;
  4389. $host = $ARGV[0];
  4390. $domain = system("/bin/domainname");
  4391. $domain =~ s/[.]/\\./g;
  4392. if ($file) {
  4393. $srcfile = $host;
  4394. $host =~ s/^.*\///;
  4395. } else {
  4396. $srcfile = $host;
  4397. $srcfile =~ s/$domain$/-confg/;
  4398. }
  4399.  
  4400. if (length($host) == 0) {
  4401. if ($file) {
  4402. print(STDERR "Too few arguments: file name required\n");
  4403. exit(1);
  4404. } else {
  4405. print(STDERR "Too few arguments: host name required\n");
  4406. exit(1);
  4407. }
  4408. }
  4409. if ($opt_C) {
  4410. if ($file) {
  4411. print "cp $srcfile $host.new\n";
  4412. } else {
  4413. print "cp /tftpboot/$srcfile $host.new\n";
  4414. }
  4415. exit(0);
  4416. }
  4417.  
  4418. if ($file) {
  4419. print STDERR "copying file $host\n" if ($debug);
  4420. print STDOUT "copying file $host\n" if ($log);
  4421. system("/bin/cp $srcfile $host.new");
  4422. } else {
  4423. print STDERR "copying file $host\n" if ($debug);
  4424. print STDOUT "copying file $host\n" if ($log);
  4425. system("/bin/cp /tftpboot/$srcfile $host.new") == 0;
  4426. }
  4427. if (!$?) {
  4428. print STDERR "copy failed: $!\n";
  4429. }
  4430. print STDOUT "Done cp: $_\n" if ($log);
  4431.  
  4432. # check for completeness
  4433. if (scalar(%commands) || !$clean_run || !$found_end) {
  4434. if (scalar(keys %commands) eq $commandcnt) {
  4435. printf(STDERR "$host: missed cmd(s): all commands\n");
  4436. } elsif (scalar(%commands)) {
  4437. printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands)));
  4438. printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug);
  4439. }
  4440. if (!$clean_run || !$found_end) {
  4441. print STDOUT "$host: End of run not found\n";
  4442. print STDERR "$host: End of run not found\n" if ($debug);
  4443. system("/usr/bin/tail -1 $host.new");
  4444. }
  4445. unlink "$host.new" if (! $debug);
  4446. }
  4447. #! /usr/bin/perl
  4448. ##
  4449. ## $Id: srancid.in 3229 2016-01-19 22:51:52Z heas $
  4450. ##
  4451. ## rancid 3.4.1
  4452. ## Copyright (c) 1997-2016 by Terrapin Communications, Inc.
  4453. ## All rights reserved.
  4454. ##
  4455. ## This code is derived from software contributed to and maintained by
  4456. ## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan,
  4457. ## Pete Whiting, Austin Schutz, and Andrew Fort.
  4458. ##
  4459. ## Redistribution and use in source and binary forms, with or without
  4460. ## modification, are permitted provided that the following conditions
  4461. ## are met:
  4462. ## 1. Redistributions of source code must retain the above copyright
  4463. ## notice, this list of conditions and the following disclaimer.
  4464. ## 2. Redistributions in binary form must reproduce the above copyright
  4465. ## notice, this list of conditions and the following disclaimer in the
  4466. ## documentation and/or other materials provided with the distribution.
  4467. ## 3. All advertising materials mentioning features or use of this software
  4468. ## must display the following acknowledgement:
  4469. ## This product includes software developed by Terrapin Communications,
  4470. ## Inc. and its contributors for RANCID.
  4471. ## 4. Neither the name of Terrapin Communications, Inc. nor the names of its
  4472. ## contributors may be used to endorse or promote products derived from
  4473. ## this software without specific prior written permission.
  4474. ## 5. It is requested that non-binding fixes and modifications be contributed
  4475. ## back to Terrapin Communications, Inc.
  4476. ##
  4477. ## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS
  4478. ## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  4479. ## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  4480. ## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
  4481. ## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  4482. ## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  4483. ## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  4484. ## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  4485. ## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  4486. ## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  4487. ## POSSIBILITY OF SUCH DAMAGE.
  4488. #
  4489. # Pretty huge hack to take care of Dell (aka. SMC) Switch configs; started by
  4490. # d_pfleger@juniper.net
  4491. #
  4492. # RANCID - Really Awesome New Cisco confIg Differ
  4493. #
  4494. # usage: srancid [-dltCV] [-f filename | hostname]
  4495. #
  4496. # Code tested and working fine on these models:
  4497. #
  4498. # DELL PowerConnect M8024 / M8024-k
  4499. # DELL PowerConnect M6348
  4500. # DELL PowerConnect N2048, N4032F and N4064.
  4501. # DELL PowerConnect 62xx
  4502. # DELL 34xx (partially; configuration is incomplete)
  4503. #
  4504. use Getopt::Std;
  4505. getopts('dflt:CV');
  4506. if ($opt_V) {
  4507. print "rancid 3.4.1\n";
  4508. exit(0);
  4509. }
  4510. $log = $opt_l;
  4511. $debug = $opt_d;
  4512. $file = $opt_f;
  4513. $host = $ARGV[0];
  4514. $found_end = 0;
  4515. $timeo = 90; # hlogin timeout in seconds
  4516.  
  4517. my(@commandtable, %commands, @commands);# command lists
  4518. my($aclsort) = ("ipsort"); # ACL sorting mode
  4519. my($filter_commstr); # SNMP community string filtering
  4520. my($filter_pwds); # password filtering mode
  4521.  
  4522. # This routine is used to print out the router configuration
  4523. sub ProcessHistory {
  4524. my($new_hist_tag,$new_command,$command_string,@string) = (@_);
  4525. if ((($new_hist_tag ne $hist_tag) || ($new_command ne $command))
  4526. && scalar(%history)) {
  4527. print eval "$command \%history";
  4528. undef %history;
  4529. }
  4530. if (($new_hist_tag) && ($new_command) && ($command_string)) {
  4531. if ($history{$command_string}) {
  4532. $history{$command_string} = "$history{$command_string}@string";
  4533. } else {
  4534. $history{$command_string} = "@string";
  4535. }
  4536. } elsif (($new_hist_tag) && ($new_command)) {
  4537. $history{++$#history} = "@string";
  4538. } else {
  4539. print "@string";
  4540. }
  4541. $hist_tag = $new_hist_tag;
  4542. $command = $new_command;
  4543. 1;
  4544. }
  4545.  
  4546. sub numerically { $a <=> $b; }
  4547.  
  4548. # This is a sort routine that will sort numerically on the
  4549. # keys of a hash as if it were a normal array.
  4550. sub keynsort {
  4551. local(%lines) = @_;
  4552. local($i) = 0;
  4553. local(@sorted_lines);
  4554. foreach $key (sort numerically keys(%lines)) {
  4555. $sorted_lines[$i] = $lines{$key};
  4556. $i++;
  4557. }
  4558. @sorted_lines;
  4559. }
  4560.  
  4561. # This is a sort routine that will sort on the
  4562. # keys of a hash as if it were a normal array.
  4563. sub keysort {
  4564. local(%lines) = @_;
  4565. local($i) = 0;
  4566. local(@sorted_lines);
  4567. foreach $key (sort keys(%lines)) {
  4568. $sorted_lines[$i] = $lines{$key};
  4569. $i++;
  4570. }
  4571. @sorted_lines;
  4572. }
  4573.  
  4574. # This is a sort routine that will sort on the
  4575. # values of a hash as if it were a normal array.
  4576. sub valsort{
  4577. local(%lines) = @_;
  4578. local($i) = 0;
  4579. local(@sorted_lines);
  4580. foreach $key (sort values %lines) {
  4581. $sorted_lines[$i] = $key;
  4582. $i++;
  4583. }
  4584. @sorted_lines;
  4585. }
  4586.  
  4587. # This is a numerical sort routine (ascending).
  4588. sub numsort {
  4589. local(%lines) = @_;
  4590. local($i) = 0;
  4591. local(@sorted_lines);
  4592. foreach $num (sort {$a <=> $b} keys %lines) {
  4593. $sorted_lines[$i] = $lines{$num};
  4594. $i++;
  4595. }
  4596. @sorted_lines;
  4597. }
  4598.  
  4599. # This is a sort routine that will sort on the
  4600. # ip address when the ip address is anywhere in
  4601. # the strings.
  4602. sub ipsort {
  4603. local(%lines) = @_;
  4604. local($i) = 0;
  4605. local(@sorted_lines);
  4606. foreach $addr (sort sortbyipaddr keys %lines) {
  4607. $sorted_lines[$i] = $lines{$addr};
  4608. $i++;
  4609. }
  4610. @sorted_lines;
  4611. }
  4612.  
  4613. # These two routines will sort based upon IP addresses
  4614. sub ipaddrval {
  4615. my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#);
  4616. $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0]));
  4617. }
  4618. sub sortbyipaddr {
  4619. &ipaddrval($a) <=> &ipaddrval($b);
  4620. }
  4621.  
  4622. # This routine parses "dir"
  4623. sub Dir {
  4624. print STDERR " In Dir: $_" if ($debug);
  4625. $_ =~ s/^[^#]*//;
  4626. ProcessHistory("COMMENTS","keysort","D1","!\n! $_");
  4627.  
  4628. while (<INPUT>) {
  4629. s/^\s+\015//g;
  4630. tr/\015//d;
  4631. next if /^\s*$/;
  4632. last if(/$prompt/);
  4633. # pager remnants like: ^H^H^H ^H^H^H content
  4634. s/[\b]+\s*[\b]*//g;
  4635.  
  4636. ProcessHistory("COMMENTS","keysort","D1","! $_");
  4637. }
  4638. ProcessHistory("COMMENTS","keysort","D1","!\n");
  4639. return(0);
  4640. }
  4641.  
  4642. sub ShowVer {
  4643. print STDERR " In ShowVer: $_" if ($debug);
  4644.  
  4645. while (<INPUT>) {
  4646. tr/\015//d;
  4647. next if /^\s*$/;
  4648. last if(/$prompt/);
  4649. # pager remnants like: ^H^H^H ^H^H^H content
  4650. s/[\b]+\s*[\b]*//g;
  4651.  
  4652. # Remove Uptime
  4653. / up time/i && next;
  4654.  
  4655. ProcessHistory("COMMENTS","keysort","B1","! $_");
  4656. }
  4657. return(0);
  4658. }
  4659.  
  4660. sub ShowSys {
  4661. print STDERR " In ShowSys: $_" if ($debug);
  4662. $_ =~ s/^[^#]*//;
  4663. ProcessHistory("COMMENTS","keysort","C1","!\n! $_");
  4664.  
  4665. while (<INPUT>) {
  4666. s/^\s+\015//g;
  4667. tr/\015//d;
  4668. next if /^\s*$/;
  4669. last if(/$prompt/);
  4670. # pager remnants like: ^H^H^H ^H^H^H content
  4671. s/[\b]+\s*[\b]*//g;
  4672.  
  4673. # Remove Uptime
  4674. / up time/i && next;
  4675.  
  4676. # filter temperature sensor info for Dell 6428 stacks
  4677. # /Temperature Sensors:/
  4678. if (/Temperature \(Celsius\)/) {
  4679. ProcessHistory("COMMENTS","keysort","C1","! $_");
  4680. ProcessHistory("COMMENTS","keysort","C1","! Unit\tStatus\n");
  4681. ProcessHistory("COMMENTS","keysort","C1","! ----\t------\n");
  4682. while (<INPUT>) {
  4683. s/^\s+\015//g;
  4684. tr/\015//d;
  4685. /(\d+)\s+\d+\s+(.*)$/ &&
  4686. ProcessHistory("COMMENTS","keysort","C1","! $1\t$2\n");
  4687. /^\s*$/ && last;
  4688. }
  4689. } elsif (/Temperature/) {
  4690. # Filter temperature sensor info for Dell M6348 and M8024 blade
  4691. # switches.
  4692. #
  4693. # M6348 and M8024 sample lines:
  4694. # Unit Description Temperature Status
  4695. # (Celsius)
  4696. # ---- ----------- ----------- ------
  4697. # 1 System 39 Good
  4698. # 2 System 39 Good
  4699. ProcessHistory("COMMENTS","keysort","C1",
  4700. "! Unit\tDescription\tStatus\n");
  4701. ProcessHistory("COMMENTS","keysort","C1",
  4702. "! ----\t-----------\t------\n");
  4703. while (<INPUT>) {
  4704. /\(celsius\)/i && next;
  4705. s/^\s+\015//g;
  4706. tr/\015//d;
  4707. /(\d+)\s+(\w+)\s+\d+\s+(.*)$/ &&
  4708. ProcessHistory("COMMENTS","keysort","C1","! $1\t$2\t\t$3\n");
  4709. /^\s*$/ && last;
  4710. }
  4711. }
  4712.  
  4713. /system description: (.*)/i &&
  4714. ProcessHistory("COMMENTS","keysort","A1", "!Chassis type: $1\n") &&
  4715. next;
  4716.  
  4717. ProcessHistory("COMMENTS","keysort","C1","! $_");
  4718. }
  4719. return(0);
  4720. }
  4721.  
  4722. sub ShowVlan {
  4723. print STDERR " In ShowVlan: $_" if ($debug);
  4724. $_ =~ s/^[^#]*//;
  4725. ProcessHistory("COMMENTS","keysort","D1","!\n! $_");
  4726.  
  4727. while (<INPUT>) {
  4728. s/^\s+\015//g;
  4729. tr/\015//d;
  4730. next if /^\s*$/;
  4731. last if(/$prompt/);
  4732. # pager remnants like: ^H^H^H ^H^H^H content
  4733. s/[\b]+\s*[\b]*//g;
  4734.  
  4735. # Remove Uptime
  4736. / up time/i && next;
  4737. ProcessHistory("COMMENTS","keysort","D1","! $_");
  4738. }
  4739. return(0);
  4740. }
  4741.  
  4742. # This routine processes a "write term" (aka show running-configuration)
  4743. sub WriteTerm {
  4744. my($comment) = (0);
  4745. print STDERR " In ShowRun: $_" if ($debug);
  4746.  
  4747. while (<INPUT>) {
  4748. tr/\015//d;
  4749. next if /^\s*$/;
  4750. last if(/$prompt/);
  4751. # pager remnants like: ^H^H^H ^H^H^H content
  4752. s/[\b]+\s*[\b]*//g;
  4753.  
  4754. # skip consecutive comment lines
  4755. if (/^!/) {
  4756. next if ($comment);
  4757. ProcessHistory("","","",$_);
  4758. $comment++;
  4759. next;
  4760. }
  4761. $comment = 0;
  4762.  
  4763. /^building running-config/ && next;
  4764. /^------+/ && ProcessHistory("","","","!$_") && next;
  4765. /^router configuration/i && ProcessHistory("","","","!$_") && next;
  4766. /^oob host config/i && ProcessHistory("","","","!$_") && next;
  4767. /^empty configuration/i && ProcessHistory("","","","!$_") && next;
  4768.  
  4769. if (/^password (\S+) encrypted/ && $filter_pwds > 1) {
  4770. ProcessHistory("","","","!password <removed> encrypted\n");
  4771. next;
  4772. }
  4773. if (/^password (\S+)$/ && $filter_pwds >= 1) {
  4774. ProcessHistory("","","","!password <removed>\n");
  4775. next;
  4776. }
  4777.  
  4778. if (/^(enable password level \d+) (\S+) encrypted/ && $filter_pwds > 1){
  4779. ProcessHistory("","","","!$1 <removed> encrypted\n");
  4780. next;
  4781. }
  4782. if (/^(enable password level \d+) (\S+)$/ && $filter_pwds >= 1) {
  4783. ProcessHistory("","","","!$1 <removed> $'\n");
  4784. next;
  4785. }
  4786.  
  4787. # order/prune snmp-server host statements
  4788. # we only prune lines of the form
  4789. # snmp-server host a.b.c.d <community>
  4790. if (/^(snmp-server host) (\d+\.\d+\.\d+\.\d+) (\S+)/) {
  4791. if ($filter_commstr) {
  4792. ProcessHistory("SNMPSERVERHOST","ipsort",
  4793. "$2","!$1 $2 <removed>$'");
  4794. } else {
  4795. ProcessHistory("SNMPSERVERHOST","ipsort","$2","$_");
  4796. }
  4797. next;
  4798. }
  4799. if (/^(snmp-server community) (\S+)/) {
  4800. if ($filter_commstr) {
  4801. ProcessHistory("SNMPSERVERCOMM","keysort",
  4802. "$_","!$1 <removed>$'") && next;
  4803. } else {
  4804. ProcessHistory("SNMPSERVERCOMM","keysort","$2","$_") && next;
  4805. }
  4806. }
  4807.  
  4808. # prune tacacs/radius server keys
  4809. if (/^(tacacs-server|radius-server) key \w+/ && $filter_pwds >= 1) {
  4810. ProcessHistory("","","","!$1 <removed>$'"); next;
  4811. }
  4812.  
  4813. ProcessHistory("","","","$_");
  4814. }
  4815. $found_end = 1;
  4816. return(1);
  4817. }
  4818.  
  4819. # Main
  4820. @commandtable = (
  4821. {'show system' => 'ShowSys'},
  4822. {'show version' => 'ShowVer'},
  4823. {'dir' => 'Dir'},
  4824. {'show vlan' => 'ShowVlan'},
  4825. {'show running-config' => 'WriteTerm'}
  4826. );
  4827. # Use an array to preserve the order of the commands and a hash for mapping
  4828. # commands to the subroutine and track commands that have been completed.
  4829. @commands = map(keys(%$_), @commandtable);
  4830. %commands = map(%$_, @commandtable);
  4831. $commandcnt = scalar(keys %commands);
  4832.  
  4833. $commandstr=join(";",@commands);
  4834. $cmds_regexp = join("|", map quotemeta($_), @commands);
  4835.  
  4836. if (length($host) == 0) {
  4837. if ($file) {
  4838. print(STDERR "Too few arguments: file name required\n");
  4839. exit(1);
  4840. } else {
  4841. print(STDERR "Too few arguments: host name required\n");
  4842. exit(1);
  4843. }
  4844. }
  4845. if ($opt_C) {
  4846. print "hlogin -t $timeo -c\'$commandstr\' $host\n";
  4847. exit(0);
  4848. }
  4849. open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n";
  4850. select(OUTPUT);
  4851. # make OUTPUT unbuffered if debugging
  4852. if ($debug) { $| = 1; }
  4853.  
  4854. if ($file) {
  4855. print STDERR "opening file $host\n" if ($debug);
  4856. print STDOUT "opening file $host\n" if ($log);
  4857. open(INPUT,"<$host") || die "open failed for $host: $!\n"; } else {
  4858. print STDERR "executing hlogin -t $timeo -c\"$commandstr\" $host\n" if ($debug);
  4859. print STDOUT "executing hlogin -t $timeo -c\"$commandstr\" $host\n" if ($log);
  4860. if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
  4861. system "hlogin -t $timeo -c \"$commandstr\" $host </dev/null > $host.raw 2>&1" || die "hlogin failed for $host: $!\n";
  4862. open(INPUT, "< $host.raw") || die "hlogin failed for $host: $!\n";
  4863. } else {
  4864. open(INPUT,"hlogin -t $timeo -c \"$commandstr\" $host </dev/null |") || die "hlogin failed for $host: $!\n";
  4865. }
  4866. }
  4867.  
  4868. # determine ACL sorting mode
  4869. if ($ENV{"ACLSORT"} =~ /no/i) {
  4870. $aclsort = "";
  4871. }
  4872. # determine community string filtering mode
  4873. if (defined($ENV{"NOCOMMSTR"}) &&
  4874. ($ENV{"NOCOMMSTR"} =~ /yes/i || $ENV{"NOCOMMSTR"} =~ /^$/)) {
  4875. $filter_commstr = 1;
  4876. } else {
  4877. $filter_commstr = 0;
  4878. }
  4879. # determine password filtering mode
  4880. if ($ENV{"FILTER_PWDS"} =~ /no/i) {
  4881. $filter_pwds = 0;
  4882. } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) {
  4883. $filter_pwds = 2;
  4884. } else {
  4885. $filter_pwds = 1;
  4886. }
  4887.  
  4888. ProcessHistory("","","","!RANCID-CONTENT-TYPE: smc\n!\n");
  4889. ProcessHistory("COMMENTS","keysort","A0","!\n");
  4890. ProcessHistory("COMMENTS","keysort","B0","!\n");
  4891. ProcessHistory("COMMENTS","keysort","C0","!\n");
  4892. ProcessHistory("COMMENTS","keysort","D0","!\n");
  4893. TOP: while(<INPUT>) {
  4894. tr/\015//d;
  4895. if (/^Error:/) {
  4896. print STDOUT ("$host hlogin error: $_");
  4897. print STDERR ("$host hlogin error: $_") if ($debug);
  4898. last;
  4899. }
  4900. while (/#\s*($cmds_regexp)\s*$/) {
  4901. $cmd = $1;
  4902. if (!defined($prompt)) {
  4903. $prompt = ($_ =~ /^([^#]+#)/)[0];
  4904. $prompt =~ s/([][}{)(\\])/\\$1/g;
  4905. print STDERR ("PROMPT MATCH: $prompt\n") if ($debug);
  4906. }
  4907. print STDERR ("HIT COMMAND:$_") if ($debug);
  4908. if (!defined($commands{$cmd})) {
  4909. print STDERR "$host: found unexpected command - \"$cmd\"\n";
  4910. last TOP;
  4911. }
  4912. $rval = &{$commands{$cmd}}(*INPUT, *OUTPUT, $cmd);
  4913. delete($commands{$cmd});
  4914. if ($rval == -1) {
  4915. last TOP;
  4916. }
  4917. }
  4918. }
  4919. print STDOUT "Done $logincmd: $_\n" if ($log);
  4920. # Flush History
  4921. ProcessHistory("","","","");
  4922. # Cleanup
  4923. close(INPUT);
  4924. close(OUTPUT);
  4925.  
  4926. if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
  4927. unlink("$host.raw") if (! $debug);
  4928. }
  4929.  
  4930. # check for completeness
  4931. if (scalar(%commands) || !$found_end) {
  4932. if (scalar(keys %commands) eq $commandcnt) {
  4933. printf(STDERR "$host: missed cmd(s): all commands\n");
  4934. } elsif (scalar(%commands)) {
  4935. printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands)));
  4936. printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug);
  4937. }
  4938. if (!$found_end) {
  4939. print STDOUT "$found_end: found end\n";
  4940. print STDOUT "$host: End of run not found\n";
  4941. print STDERR "$host: End of run not found\n" if ($debug);
  4942. system("/usr/bin/tail -1 $host.new");
  4943. }
  4944. unlink "$host.new" if (! $debug);
  4945. }
  4946. #! /usr/bin/expect --
  4947. ##
  4948. ## $Id: tlogin.in 3201 2015-11-05 00:48:01Z heas $
  4949. ##
  4950. ## rancid 3.4.1
  4951. ## Copyright (c) 1997-2016 by Terrapin Communications, Inc.
  4952. ## All rights reserved.
  4953. ##
  4954. ## This code is derived from software contributed to and maintained by
  4955. ## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan,
  4956. ## Pete Whiting, Austin Schutz, and Andrew Fort.
  4957. ##
  4958. ## Redistribution and use in source and binary forms, with or without
  4959. ## modification, are permitted provided that the following conditions
  4960. ## are met:
  4961. ## 1. Redistributions of source code must retain the above copyright
  4962. ## notice, this list of conditions and the following disclaimer.
  4963. ## 2. Redistributions in binary form must reproduce the above copyright
  4964. ## notice, this list of conditions and the following disclaimer in the
  4965. ## documentation and/or other materials provided with the distribution.
  4966. ## 3. All advertising materials mentioning features or use of this software
  4967. ## must display the following acknowledgement:
  4968. ## This product includes software developed by Terrapin Communications,
  4969. ## Inc. and its contributors for RANCID.
  4970. ## 4. Neither the name of Terrapin Communications, Inc. nor the names of its
  4971. ## contributors may be used to endorse or promote products derived from
  4972. ## this software without specific prior written permission.
  4973. ## 5. It is requested that non-binding fixes and modifications be contributed
  4974. ## back to Terrapin Communications, Inc.
  4975. ##
  4976. ## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS
  4977. ## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  4978. ## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  4979. ## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
  4980. ## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  4981. ## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  4982. ## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  4983. ## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  4984. ## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  4985. ## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  4986. ## POSSIBILITY OF SUCH DAMAGE.
  4987. ##
  4988. ## It is the request of the authors, but not a condition of license, that
  4989. ## parties packaging or redistributing RANCID NOT distribute altered versions
  4990. ## of the etc/rancid.types.base file nor alter how this file is processed nor
  4991. ## when in relation to etc/rancid.types.conf. The goal of this is to help
  4992. ## suppress our support costs. If it becomes a problem, this could become a
  4993. ## condition of license.
  4994. #
  4995. # The expect login scripts were based on Erik Sherk's gwtn, by permission.
  4996. #
  4997. # The original looking glass software was written by Ed Kern, provided by
  4998. # permission and modified beyond recognition.
  4999. #
  5000. # The login expect scripts were based on Erik Sherk's gwtn, by permission.
  5001. #
  5002. # tlogin - Netopis login
  5003. #
  5004. # Modified by Ed Ravin for Netopia.
  5005.  
  5006. # Usage line
  5007. set usage "Usage: $argv0 \[-dSV\] \[-autoenable\] \[-noenable\] \[-c command\] \
  5008. \[-Evar=x\] \[-e enable-password\] \[-f cloginrc-file\] \[-p user-password\] \
  5009. \[-s script-file\] \[-t timeout\] \[-u username\] \
  5010. \[-V\] \[-v vty-password\] \[-w enable-username\] \[-x command-file\] \
  5011. \[-y ssh_cypher_type\] router \[router...\]\n"
  5012.  
  5013. # env(CLOGIN) may contain:
  5014. # x == do not set xterm banner or name
  5015.  
  5016. # Password file
  5017. set password_file $env(HOME)/.cloginrc
  5018. # Default is to login to the router
  5019. set do_command 0
  5020. set do_script 0
  5021. # The default is to automatically enable
  5022. set avenable 1
  5023. # The default is that you login non-enabled (tacacs can have you login already
  5024. # enabled)
  5025. set avautoenable 0
  5026. # The default is to look in the password file to find the passwords. This
  5027. # tracks if we receive them on the command line.
  5028. set do_passwd 1
  5029. set do_enapasswd 1
  5030. # Sometimes routers take awhile to answer (the default is 10 sec)
  5031. set timeoutdflt 45
  5032. # Some CLIs having problems if we write too fast (Extreme, PIX, Cat)
  5033. set send_human {.2 .1 .4 .2 1}
  5034. # attempt at platform switching.
  5035. set platform ""
  5036.  
  5037. # Find the user in the ENV, or use the unix userid.
  5038. if {[info exists env(CISCO_USER)] } {
  5039. set default_user $env(CISCO_USER)
  5040. } elseif {[info exists env(USER)]} {
  5041. set default_user $env(USER)
  5042. } elseif {[info exists env(LOGNAME)]} {
  5043. set default_user $env(LOGNAME)
  5044. } else {
  5045. # This uses "id" which I think is portable. At least it has existed
  5046. # (without options) on all machines/OSes I've been on recently -
  5047. # unlike whoami or id -nu.
  5048. if [catch {exec id} reason] {
  5049. send_error "\nError: could not exec id: $reason\n"
  5050. exit 1
  5051. }
  5052. regexp {\(([^)]*)} "$reason" junk default_user
  5053. }
  5054.  
  5055. # Process the command line
  5056. for {set i 0} {$i < $argc} {incr i} {
  5057. set arg [lindex $argv $i]
  5058.  
  5059. switch -glob -- $arg {
  5060. } -d {
  5061. exp_internal 1
  5062. # Username
  5063. } -u* {
  5064. if {! [regexp .\[uU\](.+) $arg ignore user]} {
  5065. incr i
  5066. set username [lindex $argv $i]
  5067. }
  5068. # VTY Password
  5069. } -p* {
  5070. if {! [regexp .\[pP\](.+) $arg ignore userpasswd]} {
  5071. incr i
  5072. set userpasswd [lindex $argv $i]
  5073. }
  5074. set do_passwd 0
  5075. # ssh passphrase
  5076. } -r* {
  5077. # ignore -r
  5078. # VTY Password
  5079. } -v* {
  5080. if {! [regexp .\[vV\](.+) $arg ignore passwd]} {
  5081. incr i
  5082. set passwd [lindex $argv $i]
  5083. }
  5084. set do_passwd 0
  5085. # Enable Username
  5086. } -w* {
  5087. if {! [regexp .\[wW\](.+) $arg ignore enauser]} {
  5088. incr i
  5089. set enausername [lindex $argv $i]
  5090. }
  5091. # Environment variable to pass to -s scripts
  5092. } -E* {
  5093. if {[regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} {
  5094. set E$varname $varvalue
  5095. } else {
  5096. send_user "\nError: invalid format for -E in $arg\n"
  5097. exit 1
  5098. }
  5099. # Enable Password
  5100. } -e* {
  5101. if {! [regexp .\[e\](.+) $arg ignore enapasswd]} {
  5102. incr i
  5103. set enapasswd [lindex $argv $i]
  5104. }
  5105. set do_enapasswd 0
  5106. # Command to run.
  5107. } -c* {
  5108. if {! [regexp .\[cC\](.+) $arg ignore command]} {
  5109. incr i
  5110. set command [lindex $argv $i]
  5111. }
  5112. set do_command 1
  5113. # Expect script to run.
  5114. } -s* {
  5115. if {! [regexp .\[sS\](.+) $arg ignore sfile]} {
  5116. incr i
  5117. set sfile [lindex $argv $i]
  5118. }
  5119. if { ! [file readable $sfile] } {
  5120. send_user "\nError: Can't read $sfile\n"
  5121. exit 1
  5122. }
  5123. set do_script 1
  5124. # save config on exit
  5125. } -S* {
  5126. set do_saveconfig 1
  5127. # 'ssh -c' cypher type
  5128. } -y* {
  5129. if {! [regexp .\[eE\](.+) $arg ignore cypher]} {
  5130. incr i
  5131. set cypher [lindex $argv $i]
  5132. }
  5133. # alternate cloginrc file
  5134. } -f* {
  5135. if {! [regexp .\[fF\](.+) $arg ignore password_file]} {
  5136. incr i
  5137. set password_file [lindex $argv $i]
  5138. }
  5139. # Timeout
  5140. } -t* {
  5141. if {! [regexp .\[tT\](.+) $arg ignore timeout]} {
  5142. incr i
  5143. set timeoutdflt [lindex $argv $i]
  5144. }
  5145. # Command file
  5146. } -x* {
  5147. if {! [regexp .\[xX\](.+) $arg ignore cmd_file]} {
  5148. incr i
  5149. set cmd_file [lindex $argv $i]
  5150. }
  5151. if [catch {set cmd_fd [open $cmd_file r]} reason] {
  5152. send_user "\nError: $reason\n"
  5153. exit 1
  5154. }
  5155. set cmd_text [read $cmd_fd]
  5156. close $cmd_fd
  5157. set command [join [split $cmd_text \n] \;]
  5158. set do_command 1
  5159. # Version string
  5160. } -V* {
  5161. send_user "rancid 3.4.1\n"
  5162. exit 0
  5163. # Do we enable?
  5164. } -noenable {
  5165. set avenable 0
  5166. # Does tacacs automatically enable us?
  5167. } -autoenable {
  5168. set avautoenable 1
  5169. set avenable 0
  5170. } -* {
  5171. send_user "\nError: Unknown argument! $arg\n"
  5172. send_user $usage
  5173. exit 1
  5174. } default {
  5175. break
  5176. }
  5177. }
  5178. }
  5179. # Process routers...no routers listed is an error.
  5180. if { $i == $argc } {
  5181. send_user "\nError: $usage"
  5182. }
  5183.  
  5184. # Only be quiet if we are running a script (it can log its output
  5185. # on its own)
  5186. if { $do_script } {
  5187. log_user 0
  5188. } else {
  5189. log_user 1
  5190. }
  5191.  
  5192. #
  5193. # Done configuration/variable setting. Now run with it...
  5194. #
  5195.  
  5196. # Sets Xterm title if interactive...if its an xterm and the user cares
  5197. proc label { host } {
  5198. global env
  5199. # if CLOGIN has an 'x' in it, don't set the xterm name/banner
  5200. if [info exists env(CLOGIN)] {
  5201. if {[string first "x" $env(CLOGIN)] != -1} { return }
  5202. }
  5203. # take host from ENV(TERM)
  5204. if [info exists env(TERM)] {
  5205. if [regexp \^(xterm|vs) $env(TERM) ignore] {
  5206. send_user "\033]1;[lindex [split $host "."] 0]\a"
  5207. send_user "\033]2;$host\a"
  5208. }
  5209. }
  5210. }
  5211.  
  5212. # This is a helper function to make the password file easier to
  5213. # maintain. Using this the password file has the form:
  5214. # add password sl* pete cow
  5215. # add password at* steve
  5216. # add password * hanky-pie
  5217. proc add {var args} { global int_$var ; lappend int_$var $args}
  5218. proc include {args} {
  5219. global env
  5220. regsub -all "(^{|}$)" $args {} args
  5221. if { [regexp "^/" $args ignore] == 0 } {
  5222. set args $env(HOME)/$args
  5223. }
  5224. source_password_file $args
  5225. }
  5226.  
  5227. proc find {var router} {
  5228. upvar int_$var list
  5229. if { [info exists list] } {
  5230. foreach line $list {
  5231. if { [string match -nocase [lindex $line 0] $router] } {
  5232. return [lrange $line 1 end]
  5233. }
  5234. }
  5235. }
  5236. return {}
  5237. }
  5238.  
  5239. # Loads the password file. Note that as this file is tcl, and that
  5240. # it is sourced, the user better know what to put in there, as it
  5241. # could install more than just password info... I will assume however,
  5242. # that a "bad guy" could just as easy put such code in the clogin
  5243. # script, so I will leave .cloginrc as just an extention of that script
  5244. proc source_password_file { password_file } {
  5245. global env
  5246. if { ! [file exists $password_file] } {
  5247. send_user "\nError: password file ($password_file) does not exist\n"
  5248. exit 1
  5249. }
  5250. file stat $password_file fileinfo
  5251. if { [expr ($fileinfo(mode) & 007)] != 0000 } {
  5252. send_user "\nError: $password_file must not be world readable/writable\n"
  5253. exit 1
  5254. }
  5255. if [catch {source $password_file} reason] {
  5256. send_user "\nError: $reason\n"
  5257. exit 1
  5258. }
  5259. }
  5260.  
  5261. # Log into the router.
  5262. proc login { router user userpswd passwd enapasswd cmethod cyphertype } {
  5263. global spawn_id in_proc do_command do_script platform
  5264. global prompt u_prompt p_prompt e_prompt sshcmd usercmd usercmd_chat
  5265. global otpinuse
  5266. set in_proc 1
  5267. set uprompt_seen 0
  5268.  
  5269. # try each of the connection methods in $cmethod until one is successful
  5270. set progs [llength $cmethod]
  5271. foreach prog [lrange $cmethod 0 end] {
  5272. if [string match "telnet*" $prog] {
  5273. regexp {telnet(:([^[:space:]]+))*} $prog command suffix port
  5274. if {"$port" == ""} {
  5275. set retval [catch {spawn telnet $router} reason]
  5276. } else {
  5277. set retval [catch {spawn telnet $router $port} reason]
  5278. }
  5279. if { $retval } {
  5280. send_user "\nError: telnet failed: $reason\n"
  5281. exit 1
  5282. }
  5283. } elseif [string match "ssh*" $prog] {
  5284. regexp {ssh(:([^[:space:]]+))*} $prog command suffix port
  5285. set cmd $sshcmd
  5286. if {"$port" != ""} {
  5287. set cmd "$cmd -p $port"
  5288. }
  5289. set retval [catch {eval spawn [split "$cmd -c $cyphertype -x -l $user $router" { }]} reason]
  5290. if { $retval } {
  5291. send_user "\nError: $cmd failed: $reason\n"
  5292. exit 1
  5293. }
  5294. } elseif [string match "usercmd" $prog] { # user supplies connect cmd
  5295. set retval [catch {eval spawn $usercmd} reason]
  5296. if { $retval } {
  5297. send_user "\nError: '$usercmd' failed: $reason\n"
  5298. exit 1
  5299. }
  5300. if { [llength $usercmd_chat] > 0 } {
  5301. #send_user "\nExecuting usercmd_chat: $usercmd_chat\n"
  5302. sleep 0.3
  5303. foreach {i j} $usercmd_chat {
  5304. expect {
  5305. -re $i { eval send -- "\"$j\""}
  5306. timeout { send "\r"; send_user "\nTimeout in usercmd_chat waiting for -re $i: punting with CR\n"; break }
  5307. }
  5308. }
  5309. }
  5310. } elseif ![string compare $prog "rsh"] {
  5311. if [catch {spawn rsh -l $user $router} reason] {
  5312. send_user "\nError: rsh failed: $reason\n"
  5313. exit 1
  5314. }
  5315. } else {
  5316. puts "\nError: unknown connection method: $prog"
  5317. return 1
  5318. }
  5319. incr progs -1
  5320. sleep 0.3
  5321.  
  5322. # This helps cleanup each expect clause.
  5323. expect_after {
  5324. timeout {
  5325. send_user "\nError: TIMEOUT reached\n"
  5326. catch {close}; wait
  5327. if { $in_proc} {
  5328. return 1
  5329. } else {
  5330. continue
  5331. }
  5332. } eof {
  5333. send_user "\nError: EOF received\n"
  5334. catch {close}; wait
  5335. if { $in_proc} {
  5336. return 1
  5337. } else {
  5338. continue
  5339. }
  5340. }
  5341. }
  5342.  
  5343. # Here we get a little tricky. There are several possibilities:
  5344. # the router can ask for a username and passwd and then
  5345. # talk to the TACACS server to authenticate you, or if the
  5346. # TACACS server is not working, then it will use the enable
  5347. # passwd. Or, the router might not have TACACS turned on,
  5348. # then it will just send the passwd.
  5349. # if telnet fails with connection refused, try ssh
  5350. expect {
  5351. -re "(Connection refused|Secure connection \[^\n\r]+ refused)" {
  5352. catch {close}; wait
  5353. if !$progs {
  5354. send_user "\nError: Connection Refused ($prog): $router\n"
  5355. return 1
  5356. }
  5357. }
  5358. -re "(Connection closed by|Connection to \[^\n\r]+ closed)" {
  5359. catch {close}; wait
  5360. if !$progs {
  5361. send_user "\nError: Connection closed ($prog): $router\n"
  5362. return 1
  5363. }
  5364. }
  5365. eof { send_user "\nError: Couldn't login: $router\n"; wait; return 1 }
  5366. -nocase "unknown host\r" {
  5367. catch {close};
  5368. send_user "\nError: Unknown host $router\n"; wait; return 1
  5369. }
  5370. "Host is unreachable" {
  5371. catch {close};
  5372. send_user "\nError: Host Unreachable: $router\n"; wait; return 1
  5373. }
  5374. "No address associated with name" {
  5375. catch {close};
  5376. send_user "\nError: Unknown host $router\n"; wait; return 1
  5377. }
  5378. -re "(Host key not found |The authenticity of host .* be established).* \\(yes/no\\)\\?" {
  5379. send "yes\r"
  5380. send_user "\nHost $router added to the list of known hosts.\n"
  5381. exp_continue }
  5382. -re "HOST IDENTIFICATION HAS CHANGED.* \\(yes/no\\)\\?" {
  5383. send "no\r"
  5384. send_user "\nError: The host key for $router has changed. Update the SSH known_hosts file accordingly.\n"
  5385. return 1 }
  5386. -re "HOST IDENTIFICATION HAS CHANGED\[^\n\r]+" {
  5387. send_user "\nError: The host key for $router has changed. Update the SSH known_hosts file accordingly.\n"
  5388. return 1
  5389. }
  5390. -re "Offending key for .* \\(yes/no\\)\\?" {
  5391. send "no\r"
  5392. send_user "\nError: host key mismatch for $router. Update the SSH known_hosts file accordingly.\n"
  5393. return 1 }
  5394. -nocase -re "^warning: remote host denied authentication agent forwarding." {
  5395. exp_continue;
  5396. }
  5397. -re "(denied|Sorry)" {
  5398. send_user "\nError: Check your passwd for $router\n"
  5399. catch {close}; wait; return 1
  5400. }
  5401. "Login failed" {
  5402. send_user "\nError: Check your passwd for $router\n"
  5403. return 1
  5404. }
  5405. -re "% (Bad passwords|Authentication failed)" {
  5406. send_user "\nError: Check your passwd for $router\n"
  5407. return 1
  5408. }
  5409. "Press any key to continue." {
  5410. # send_user "Pressing the ANY key\n"
  5411. send "\r"
  5412. exp_continue
  5413. }
  5414. -re "Enter Selection: " {
  5415. # Catalyst 1900s have some lame menu. Enter
  5416. # K to reach a command-line.
  5417. send "K\r"
  5418. exp_continue;
  5419. }
  5420. -re "Netopia.*always start from this main screen" {
  5421. # send control-N to escape from the Playskool menu
  5422. send -- "\x0e"
  5423. set platform "netopia"
  5424. set prompt "#"
  5425. set autoenable 1
  5426. return 0
  5427. }
  5428. -re "@\[^\r\n]+ $p_prompt" {
  5429. # ssh pwd prompt
  5430. sleep 1
  5431. send -- "$userpswd\r"
  5432. exp_continue
  5433. }
  5434. -re "$u_prompt" {
  5435. send -- "$user\r"
  5436. set uprompt_seen 1
  5437. exp_continue
  5438. }
  5439. -re "(s/key|otp-\[0-9a-zA-Z]+) +\[0-9]+ +\[-0-9a-zA-Z]+\[ \r\n]" {
  5440. if { !$otpinuse} {
  5441. exp_continue
  5442. }
  5443. set challenge $expect_out(0,string)
  5444. regsub {[ \r\n]$} $challenge {} challenge
  5445. if [catch {exec otphelper $router "$challenge"} userpswd] {
  5446. send_error "\nError: login: 'otphelper $router $challenge' failed.\nRun otphelper standalone to diagnose further.\n"
  5447. exit 1
  5448. }
  5449. exp_continue
  5450. }
  5451. -re "$p_prompt" {
  5452. sleep 1
  5453. if {$uprompt_seen == 1} {
  5454. send -- "$userpswd\r"
  5455. } else {
  5456. send -- "$passwd\r"
  5457. }
  5458. exp_continue
  5459. }
  5460. -re "$prompt" { break; }
  5461. "Login invalid" {
  5462. send_user "\nError: Invalid login: $router\n";
  5463. catch {close}; wait; return 1
  5464. }
  5465. }
  5466. }
  5467.  
  5468. set in_proc 0
  5469. return 0
  5470. }
  5471.  
  5472. # Enable
  5473. proc do_enable { enauser enapasswd } {
  5474. global prompt in_proc
  5475. global u_prompt e_prompt
  5476. global router otpinuse
  5477. set in_proc 1
  5478.  
  5479. send "enable\r"
  5480. expect {
  5481. -re "(s/key|otp-\[0-9a-zA-Z]+) +\[0-9]+ +\[-0-9a-zA-Z]+\[ \r\n]" {
  5482. if { !$otpinuse} {
  5483. exp_continue
  5484. }
  5485. set challenge $expect_out(0,string)
  5486. regsub {[ \r\n]$} $challenge {} challenge
  5487. if [catch {exec otphelper $router "$challenge"} enapasswd] {
  5488. send_error "\nError: enable: 'otphelper $router $challenge' failed.\nRun otphelper standalone to diagnose further.\n"
  5489. exit 1
  5490. }
  5491. exp_continue
  5492. }
  5493. -re "$u_prompt" { send -- "$enauser\r"; exp_continue}
  5494. -re "$e_prompt" { send -- "$enapasswd\r"; exp_continue}
  5495. "#" { set prompt "#" }
  5496. "(enable)" { set prompt "> (enable) " }
  5497. -re "(denied|Sorry|Incorrect)" {
  5498. # % Access denied - from local auth and poss. others
  5499. send_user "\nError: Check your Enable passwd\n";
  5500. return 1
  5501. }
  5502. "% Error in authentication" {
  5503. send_user "\nError: Check your Enable passwd\n"
  5504. return 1
  5505. }
  5506. "% Bad passwords" {
  5507. send_user "\nError: Check your Enable passwd\n"
  5508. return 1
  5509. }
  5510. }
  5511. # We set the prompt variable (above) so script files don't need
  5512. # to know what it is.
  5513. set in_proc 0
  5514. return 0
  5515. }
  5516.  
  5517. # Run commands given on the command line.
  5518. proc run_commands { prompt command } {
  5519. global in_proc platform
  5520. set in_proc 1
  5521.  
  5522. # If the prompt is (enable), then we are on a switch and the
  5523. # command is "set length 0"; otherwise its "term length 0".
  5524. # skip if its an extreme (since the pager can not be disabled on a
  5525. # per-vty basis).
  5526. if { [string compare "extreme" "$platform"] } {
  5527. if [regexp -- ".*> .*enable" "$prompt"] {
  5528. send "set length 0\r"
  5529. # This is ugly, but reduces code duplication, allowing the
  5530. # subsequent expects to handle everything as normal.
  5531. set command "set logging session disable;$command"
  5532. } elseif { ![string compare "netopia" "$platform"] } {
  5533. # kludge - should instead skip re-sensing prompt if platform netopia
  5534. set prompt "#"
  5535. } else {
  5536. send "term length 0\r"
  5537. }
  5538. # match cisco config mode prompts too, such as router(config-if)#
  5539. regsub -all {^(.{1,14}).*([#>])$} $prompt {\1} reprompt
  5540. # escape any parens in the prompt, such as "(enable)"
  5541. regsub -all {[)(]} $reprompt {\\&} reprompt
  5542. append reprompt {([^#>\r\n]+)?[#>](\\([^)\\r\\n]+\\))?}
  5543. expect {
  5544. -re $reprompt {}
  5545. -re "\[\n\r]+" { exp_continue }
  5546. }
  5547. } else {
  5548. regsub -all "\[)(]" $prompt {\\&} reprompt
  5549. }
  5550.  
  5551. # this is the only way i see to get rid of more prompts in o/p..grrrrr
  5552. log_user 0
  5553.  
  5554. # handle escaped ;s in commands, and ;; and ^;
  5555. regsub -all {([^\\]);;} $command "\\1;\u002;" esccommand
  5556. regsub {^;} $esccommand "\u002;" command
  5557. set sep "\\1\u001"
  5558. regsub -all {([^\\])\;} $command "$sep" esccommand
  5559. set sep "\u001"
  5560. set commands [split $esccommand $sep]
  5561. set num_commands [llength $commands]
  5562. # the pager can not be turned off on the PIX, so we have to look
  5563. # for the "More" prompt. the extreme is equally obnoxious, with a
  5564. # global switch in the config.
  5565. for {set i 0} {$i < $num_commands} { incr i} {
  5566. send -- "[subst -nocommands [lindex $commands $i]]\r"
  5567. expect {
  5568. -re "\b+" { exp_continue }
  5569. -re "^\[^\n\r *]*$reprompt" { send_user -- "$expect_out(buffer)"
  5570. }
  5571. -re "^\[^\n\r]*$reprompt." { send_user -- "$expect_out(buffer)"
  5572. exp_continue }
  5573. -re "\[\n\r]+" { send_user -- "$expect_out(buffer)"
  5574. exp_continue }
  5575. -re "\[^\r\n]*Press <SPACE> to cont\[^\r\n]*" {
  5576. send " "
  5577. # bloody ^[[2K after " "
  5578. expect {
  5579. -re "^\[^\r\n]*\r" {}
  5580. }
  5581. exp_continue
  5582. }
  5583. -re "^ *--More--\[^\n\r]*" {
  5584. send " "
  5585. exp_continue }
  5586. -re "^<-+ More -+>\[^\n\r]*" {
  5587. send_user -- "$expect_out(buffer)"
  5588. send " "
  5589. exp_continue }
  5590. }
  5591. }
  5592. log_user 1
  5593.  
  5594. if { [string compare "extreme" "$platform"] } {
  5595. send "exit\r"
  5596. } else {
  5597. send "quit\r"
  5598. }
  5599. expect {
  5600. -re "^\[^\n\r *]*$reprompt" {
  5601. # the Cisco CE and Jnx ERX
  5602. # return to non-enabled mode
  5603. # on exit in enabled mode.
  5604. send "exit\r"
  5605. exp_continue;
  5606. }
  5607. "Do you wish to save your configuration changes" {
  5608. send "n\r"
  5609. exp_continue
  5610. }
  5611. -re "\[\n\r]+" { exp_continue }
  5612. timeout { close; return 0 }
  5613. eof { return 0 }
  5614. }
  5615. set in_proc 0
  5616. }
  5617.  
  5618. #
  5619. # For each router... (this is main loop)
  5620. #
  5621. source_password_file $password_file
  5622. set in_proc 0
  5623. foreach router [lrange $argv $i end] {
  5624. set router [string tolower $router]
  5625. send_user "$router\n"
  5626.  
  5627. # device timeout
  5628. set timeout [find timeout $router]
  5629. if { [llength $timeout] == 0 } {
  5630. set timeout $timeoutdflt
  5631. }
  5632.  
  5633. # Figure out prompt.
  5634. # Since autoenable is off by default, if we have it defined, it
  5635. # was done on the command line. If it is not specifically set on the
  5636. # command line, check the password file.
  5637. if $avautoenable {
  5638. set autoenable 1
  5639. set enable 0
  5640. set prompt "(#| \\(enable\\))"
  5641. } else {
  5642. set ae [find autoenable $router]
  5643. if { "$ae" == "1" } {
  5644. set autoenable 1
  5645. set enable 0
  5646. set prompt "(#| \\(enable\\))"
  5647. } else {
  5648. set autoenable 0
  5649. set enable $avenable
  5650. set prompt ">"
  5651. }
  5652. }
  5653.  
  5654. # look for noenable option in .cloginrc
  5655. if { [find noenable $router] == "1" } {
  5656. set enable 0
  5657. }
  5658.  
  5659. # is OTP in use? If so, bypass password checks
  5660. set otpinuse 0
  5661. if { [find otp_secret $router] != "" } {
  5662. set otpinuse 1
  5663. }
  5664.  
  5665. # Figure out passwords
  5666. if { $do_passwd || $do_enapasswd } {
  5667. set pswd [find password $router]
  5668. if { [llength $pswd] == 0 && !$otpinuse} {
  5669. send_user "\nError: no password for $router in $password_file.\n"
  5670. continue
  5671. }
  5672. if { $enable && $do_enapasswd && $autoenable == 0 && [llength $pswd] < 2 && !$otpinuse } {
  5673. send_user "\nError: no enable password for $router in $password_file.\n"
  5674. continue
  5675. }
  5676. set passwd [join [lindex $pswd 0] ""]
  5677. set enapasswd [join [lindex $pswd 1] ""]
  5678. }
  5679.  
  5680. # Figure out username
  5681. if {[info exists username]} {
  5682. # command line username
  5683. set ruser $username
  5684. } else {
  5685. set ruser [join [find user $router] ""]
  5686. if { "$ruser" == "" } { set ruser $default_user }
  5687. }
  5688.  
  5689. # Figure out username's password (if different from the vty password)
  5690. if {[info exists userpasswd]} {
  5691. # command line username
  5692. set userpswd $userpasswd
  5693. } else {
  5694. set userpswd [join [find userpassword $router] ""]
  5695. if { "$userpswd" == "" } { set userpswd $passwd }
  5696. }
  5697.  
  5698. # Figure out enable username
  5699. if {[info exists enausername]} {
  5700. # command line enausername
  5701. set enauser $enausername
  5702. } else {
  5703. set enauser [join [find enauser $router] ""]
  5704. if { "$enauser" == "" } { set enauser $ruser }
  5705. }
  5706.  
  5707. # Figure out prompts
  5708. set u_prompt [find userprompt $router]
  5709. if { "$u_prompt" == "" } {
  5710. set u_prompt "(Username|Login|login|user name|name):"
  5711. } else {
  5712. set u_prompt [join [lindex $u_prompt 0] ""]
  5713. }
  5714. set p_prompt [find passprompt $router]
  5715. if { "$p_prompt" == "" } {
  5716. set p_prompt "(\[Pp]assword|passwd):"
  5717. } else {
  5718. set p_prompt [join [lindex $p_prompt 0] ""]
  5719. }
  5720. set e_prompt [find enableprompt $router]
  5721. if { "$e_prompt" == "" } {
  5722. set e_prompt "\[Pp]assword:"
  5723. } else {
  5724. set e_prompt [join [lindex $e_prompt 0] ""]
  5725. }
  5726.  
  5727. # Figure out cypher type
  5728. if {[info exists cypher]} {
  5729. # command line cypher type
  5730. set cyphertype $cypher
  5731. } else {
  5732. set cyphertype [find cyphertype $router]
  5733. if { "$cyphertype" == "" } { set cyphertype "3des" }
  5734. }
  5735.  
  5736. # Figure out connection method
  5737. set cmethod [find method $router]
  5738. if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} }
  5739.  
  5740. # Figure out the SSH executable name
  5741. set sshcmd [join [lindex [find sshcmd $router] 0] ""]
  5742. if { "$sshcmd" == "" } { set sshcmd {ssh} }
  5743.  
  5744. # If user provides a router-specific connection method, use it
  5745. set usercmd [find usercmd $router]
  5746. set usercmd_chat [find usercmd_chat $router]
  5747.  
  5748. # Login to the router
  5749. if {[login $router $ruser $userpswd $passwd $enapasswd $cmethod $cyphertype]} {
  5750. continue
  5751. }
  5752. if { $enable } {
  5753. if {[do_enable $enauser $enapasswd]} {
  5754. if { $do_command || $do_script } {
  5755. close; wait
  5756. continue
  5757. }
  5758. }
  5759. }
  5760. # we are logged in, now figure out the full prompt
  5761. send "\r"
  5762. expect {
  5763. -re "\[\r\n]+" { exp_continue; }
  5764. -re "^(.+:)1 $prompt" { # stoopid extreme cmd-line numbers and
  5765. # prompt based on state of config changes,
  5766. # which may have an * at the beginning.
  5767. set junk $expect_out(1,string)
  5768. regsub -all "^\\\* " $expect_out(1,string) {} junk
  5769. set prompt ".? ?$junk\[0-9]+ $expect_out(2,string)";
  5770. set platform "extreme"
  5771. }
  5772. -re "^.+$prompt" { set junk $expect_out(0,string);
  5773. regsub -all "\[\]\[]" $junk {\\&} prompt;
  5774. }
  5775. -re "^.+> \\\(enable\\\)" {
  5776. set junk $expect_out(0,string);
  5777. regsub -all "\[\]\[]" $junk {\\&} prompt;
  5778. }
  5779. }
  5780.  
  5781. if { $do_command } {
  5782. if {[run_commands $prompt $command]} {
  5783. continue
  5784. }
  5785. } elseif { $do_script } {
  5786. # If the prompt is (enable), then we are on a switch and the
  5787. # command is "set length 0"; otherwise its "term length 0".
  5788. if [regexp -- ".*> .*enable" "$prompt"] {
  5789. send "set length 0\r"
  5790. send "set logging session disable\r"
  5791. } elseif { ![string compare "netopia" "$platform"] } {
  5792. # do nothing
  5793. } else {
  5794. send "term length 0\r"
  5795. }
  5796. expect -re $prompt {}
  5797. source $sfile
  5798. close
  5799. } else {
  5800. label $router
  5801. log_user 1
  5802. interact
  5803. }
  5804.  
  5805. # End of for each router
  5806. wait
  5807. sleep 0.3
  5808. }
  5809. exit 0
  5810. #! /usr/bin/expect --
  5811. ##
  5812. ## $Id: tntlogin.in 2376 2012-01-31 22:42:14Z heas $
  5813. ##
  5814. ## rancid 2.3.8
  5815. ## Copyright (c) 1997-2011 by Terrapin Communications, Inc.
  5816. ## All rights reserved.
  5817. ##
  5818. ## This code is derived from software contributed to and maintained by
  5819. ## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan,
  5820. ## Pete Whiting, Austin Schutz, and Andrew Fort.
  5821. ##
  5822. ## Redistribution and use in source and binary forms, with or without
  5823. ## modification, are permitted provided that the following conditions
  5824. ## are met:
  5825. ## 1. Redistributions of source code must retain the above copyright
  5826. ## notice, this list of conditions and the following disclaimer.
  5827. ## 2. Redistributions in binary form must reproduce the above copyright
  5828. ## notice, this list of conditions and the following disclaimer in the
  5829. ## documentation and/or other materials provided with the distribution.
  5830. ## 3. All advertising materials mentioning features or use of this software
  5831. ## must display the following acknowledgement:
  5832. ## This product includes software developed by Terrapin Communications,
  5833. ## Inc. and its contributors for RANCID.
  5834. ## 4. Neither the name of Terrapin Communications, Inc. nor the names of its
  5835. ## contributors may be used to endorse or promote products derived from
  5836. ## this software without specific prior written permission.
  5837. ## 5. It is requested that non-binding fixes and modifications be contributed
  5838. ## back to Terrapin Communications, Inc.
  5839. ##
  5840. ## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS
  5841. ## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  5842. ## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  5843. ## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
  5844. ## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  5845. ## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  5846. ## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  5847. ## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  5848. ## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  5849. ## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  5850. ## POSSIBILITY OF SUCH DAMAGE.
  5851. #
  5852. # The expect login scripts were based on Erik Sherk's gwtn, by permission.
  5853. #
  5854. # Modified by P B Matthews.
  5855.  
  5856. # Usage line
  5857. set usage "Usage: $argv0 \[-dSV\] \[-c command\] \[-Evar=x\] \
  5858. \[-f cloginrc-file\] \[-s script-file\] \[-t timeout\] \[-u username\] \
  5859. \[-v vty-password\] \[-x command-file\] \[-y ssh_cypher_type\] router \
  5860. \[router...\]\n"
  5861.  
  5862. # env(CLOGIN) may contain:
  5863. # x == do not set xterm banner or name
  5864.  
  5865. # Password file
  5866. set password_file $env(HOME)/.cloginrc
  5867. # Default is to login to the router
  5868. set do_command 0
  5869. set do_script 0
  5870. # The default is to automatically enable
  5871. set avenable 0
  5872. # The default is that you login non-enabled (tacacs can have you login already
  5873. # enabled)
  5874. set avautoenable 1
  5875. # The default is to look in the password file to find the passwords. This
  5876. # tracks if we receive them on the command line.
  5877. set do_passwd 1
  5878. # Save config, if prompted
  5879. set do_saveconfig 0
  5880. # Sometimes routers take awhile to answer (the default is 10 sec)
  5881. set timeoutdflt 45
  5882.  
  5883. # Find the user in the ENV, or use the unix userid.
  5884. if {[ info exists env(CISCO_USER) ]} {
  5885. set default_user $env(CISCO_USER)
  5886. } elseif {[ info exists env(USER) ]} {
  5887. set default_user $env(USER)
  5888. } elseif {[ info exists env(LOGNAME) ]} {
  5889. set default_user $env(LOGNAME)
  5890. } else {
  5891. # This uses "id" which I think is portable. At least it has existed
  5892. # (without options) on all machines/OSes I've been on recently -
  5893. # unlike whoami or id -nu.
  5894. if [ catch {exec id} reason ] {
  5895. send_error "\nError: could not exec id: $reason\n"
  5896. exit 1
  5897. }
  5898. regexp {\(([^)]*)} "$reason" junk default_user
  5899. }
  5900. if {[ info exists env(CLOGINRC) ]} {
  5901. set password_file $env(CLOGINRC)
  5902. }
  5903.  
  5904. # Process the command line
  5905. for {set i 0} {$i < $argc} {incr i} {
  5906. set arg [lindex $argv $i]
  5907.  
  5908. switch -glob -- $arg {
  5909. # Expect debug mode
  5910. -d* {
  5911. exp_internal 1
  5912. # Username
  5913. } -u* {
  5914. if {! [ regexp .\[uU\](.+) $arg ignore user]} {
  5915. incr i
  5916. set username [ lindex $argv $i ]
  5917. }
  5918. # VTY Password
  5919. } -v* {
  5920. if {! [ regexp .\[vV\](.+) $arg ignore passwd]} {
  5921. incr i
  5922. set passwd [ lindex $argv $i ]
  5923. }
  5924. set do_passwd 0
  5925. # ssh passphrase
  5926. } -r* {
  5927. # ignore -r
  5928. # Version string
  5929. } -V* {
  5930. send_user "rancid 2.3.8\n"
  5931. exit 0
  5932. # Enable Username
  5933. } -w* {
  5934. # ignore -w
  5935. # Environment variable to pass to -s scripts
  5936. } -E* {
  5937. if {[ regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} {
  5938. incr i
  5939. set E$varname $varvalue
  5940. } else {
  5941. send_user "\nError: invalid format for -E in $arg\n"
  5942. exit 1
  5943. }
  5944. # Enable Password
  5945. } -e* {
  5946. # ignore -e
  5947. # Command to run.
  5948. } -c* {
  5949. if {! [ regexp .\[cC\](.+) $arg ignore command]} {
  5950. incr i
  5951. set command [ lindex $argv $i ]
  5952. }
  5953. set do_command 1
  5954. # Expect script to run.
  5955. } -s* {
  5956. if {! [ regexp .\[sS\](.+) $arg ignore sfile]} {
  5957. incr i
  5958. set sfile [ lindex $argv $i ]
  5959. }
  5960. if { ! [ file readable $sfile ] } {
  5961. send_user "\nError: Can't read $sfile\n"
  5962. exit 1
  5963. }
  5964. set do_script 1
  5965. # save config on exit
  5966. } -S* {
  5967. set do_saveconfig 1
  5968. # 'ssh -c' cypher type
  5969. } -y* {
  5970. if {! [ regexp .\[eE\](.+) $arg ignore cypher]} {
  5971. incr i
  5972. set cypher [ lindex $argv $i ]
  5973. }
  5974. # alternate cloginrc file
  5975. } -f* {
  5976. if {! [ regexp .\[fF\](.+) $arg ignore password_file]} {
  5977. incr i
  5978. set password_file [ lindex $argv $i ]
  5979. }
  5980. # Timeout
  5981. } -t* {
  5982. if {! [ regexp .\[tT\](.+) $arg ignore timeout]} {
  5983. incr i
  5984. set timeoutdflt [ lindex $argv $i ]
  5985. }
  5986. # Command file
  5987. } -x* {
  5988. if {! [ regexp .\[xX\](.+) $arg ignore cmd_file]} {
  5989. incr i
  5990. set cmd_file [ lindex $argv $i ]
  5991. }
  5992. if [ catch {set cmd_fd [open $cmd_file r]} reason ] {
  5993. send_user "\nError: $reason\n"
  5994. exit 1
  5995. }
  5996. set cmd_text [read $cmd_fd]
  5997. close $cmd_fd
  5998. set command [join [split $cmd_text \n] \;]
  5999. set do_command 1
  6000. # Do we enable?
  6001. } -noenable {
  6002. # ignore -noenable
  6003. # Does tacacs automatically enable us?
  6004. } -autoenable {
  6005. # ignore -autoenable
  6006. } -* {
  6007. send_user "\nError: Unknown argument! $arg\n"
  6008. send_user $usage
  6009. exit 1
  6010. } default {
  6011. break
  6012. }
  6013. }
  6014. }
  6015. # Process routers...no routers listed is an error.
  6016. if { $i == $argc } {
  6017. send_user "\nError: $usage"
  6018. }
  6019.  
  6020. # Only be quiet if we are running a script (it can log its output
  6021. # on its own)
  6022. if { $do_script } {
  6023. log_user 0
  6024. } else {
  6025. log_user 1
  6026. }
  6027.  
  6028. #
  6029. # Done configuration/variable setting. Now run with it...
  6030. #
  6031.  
  6032. # Sets Xterm title if interactive...if its an xterm and the user cares
  6033. proc label { host } {
  6034. global env
  6035. # if CLOGIN has an 'x' in it, don't set the xterm name/banner
  6036. if [info exists env(CLOGIN)] {
  6037. if {[string first "x" $env(CLOGIN)] != -1} { return }
  6038. }
  6039. # take host from ENV(TERM)
  6040. if [info exists env(TERM)] {
  6041. if [regexp \^(xterm|vs) $env(TERM) ignore ] {
  6042. send_user "\033]1;[lindex [split $host "."] 0]\a"
  6043. send_user "\033]2;$host\a"
  6044. }
  6045. }
  6046. }
  6047.  
  6048. # This is a helper function to make the password file easier to
  6049. # maintain. Using this the password file has the form:
  6050. # add password sl* pete cow
  6051. # add password at* steve
  6052. # add password * hanky-pie
  6053. proc add {var args} { global int_$var ; lappend int_$var $args}
  6054. proc include {args} {
  6055. global env
  6056. regsub -all "(^{|}$)" $args {} args
  6057. if { [ regexp "^/" $args ignore ] == 0 } {
  6058. set args $env(HOME)/$args
  6059. }
  6060. source_password_file $args
  6061. }
  6062.  
  6063. proc find {var router} {
  6064. upvar int_$var list
  6065. if { [info exists list] } {
  6066. foreach line $list {
  6067. if { [string match [lindex $line 0] $router ] } {
  6068. return [lrange $line 1 end]
  6069. }
  6070. }
  6071. }
  6072. return {}
  6073. }
  6074.  
  6075. # Loads the password file. Note that as this file is tcl, and that
  6076. # it is sourced, the user better know what to put in there, as it
  6077. # could install more than just password info... I will assume however,
  6078. # that a "bad guy" could just as easy put such code in the clogin
  6079. # script, so I will leave .cloginrc as just an extention of that script
  6080. proc source_password_file { password_file } {
  6081. global env
  6082. if { ! [file exists $password_file] } {
  6083. send_user "\nError: password file ($password_file) does not exist\n"
  6084. exit 1
  6085. }
  6086. file stat $password_file fileinfo
  6087. if { [expr ($fileinfo(mode) & 007)] != 0000 } {
  6088. send_user "\nError: $password_file must not be world readable/writable\n"
  6089. exit 1
  6090. }
  6091. if [ catch {source $password_file} reason ] {
  6092. send_user "\nError: $reason\n"
  6093. exit 1
  6094. }
  6095. }
  6096.  
  6097. # Log into the router.
  6098. # returns: 0 on success, 1 on failure
  6099. proc login { router user userpswd passwd prompt cmethod cyphertype } {
  6100. global spawn_id in_proc do_command do_script
  6101. global u_prompt p_prompt sshcmd
  6102. set in_proc 1
  6103. set uprompt_seen 0
  6104.  
  6105. # try each of the connection methods in $cmethod until one is successful
  6106. set progs [llength $cmethod]
  6107. foreach prog [lrange $cmethod 0 end] {
  6108. incr progs -1
  6109. if [string match "telnet*" $prog] {
  6110. regexp {telnet(:([^[:space:]]+))*} $prog command suffix port
  6111. if {"$port" == ""} {
  6112. set retval [ catch {spawn telnet $router} reason ]
  6113. } else {
  6114. set retval [ catch {spawn telnet $router $port} reason ]
  6115. }
  6116. if { $retval } {
  6117. send_user "\nError: telnet failed: $reason\n"
  6118. return 1
  6119. }
  6120. } elseif ![string compare $prog "ssh"] {
  6121. regexp {ssh(:([^[:space:]]+))*} $prog methcmd suffix port
  6122. set cmd $sshcmd
  6123. if {"$port" != ""} {
  6124. set cmd "$cmd -p $port"
  6125. }
  6126. set retval [ catch {eval spawn [split "$cmd -c $cyphertype -x -l $user $router" { }]} reason ]
  6127. if { $retval } {
  6128. send_user "\nError: $cmd failed: $reason\n"
  6129. return 1
  6130. }
  6131. } elseif ![string compare $prog "rsh"] {
  6132. send_error "\nError: unsupported method: rsh\n"
  6133. if { $progs == 0 } {
  6134. return 1
  6135. }
  6136. continue;
  6137. } else {
  6138. send_user "\nError: unknown connection method: $prog\n"
  6139. return 1
  6140. }
  6141. sleep 0.3
  6142.  
  6143. # This helps cleanup each expect clause.
  6144. expect_after {
  6145. timeout {
  6146. send_user "\nError: TIMEOUT reached\n"
  6147. catch {close}; catch {wait};
  6148. if { $in_proc} {
  6149. return 1
  6150. } else {
  6151. continue
  6152. }
  6153. } eof {
  6154. send_user "\nError: EOF received\n"
  6155. catch {close}; catch {wait};
  6156. if { $in_proc} {
  6157. return 1
  6158. } else {
  6159. continue
  6160. }
  6161. }
  6162. }
  6163.  
  6164. expect {
  6165. "Connection refused" {
  6166. catch {close}; catch {wait};
  6167. sleep 0.3
  6168. expect eof
  6169. send_user "\nError: Connection Refused\n"; wait; return 1
  6170. }
  6171. eof { send_user "\nError: Couldn't login\n"; wait; return 1
  6172. } "Unknown host\r\n" {
  6173. expect eof
  6174. send_user "\nError: Unknown host\n"; wait; return 1
  6175. } "Host is unreachable" {
  6176. expect eof
  6177. send_user "\nError: Host Unreachable!\n"; wait; return 1
  6178. } "No address associated with name" {
  6179. expect eof
  6180. send_user "\nError: Unknown host\n"; wait; return 1
  6181. }
  6182. -re "(Host key not found |The authenticity of host .* be established).* \\(yes/no\\)\\?" {
  6183. send "yes\r"
  6184. send_user "\nHost $router added to the list of known hosts.\n"
  6185. exp_continue
  6186. }
  6187. -re "HOST IDENTIFICATION HAS CHANGED.* \\(yes/no\\)\\?" {
  6188. send "no\r"
  6189. send_user "\nError: The host key for $router has changed. Update the SSH known_hosts file accordingly.\n"
  6190. return 1
  6191. }
  6192. -re "HOST IDENTIFICATION HAS CHANGED\[^\n\r]+" {
  6193. send_user "\nError: The host key for $router has changed. Update the SSH known_hosts file accordingly.\n"
  6194. return 1
  6195. }
  6196. -re "Offending key for .* \\(yes/no\\)\\?" {
  6197. send "no\r"
  6198. send_user "\nError: host key mismatch for $router. Update the SSH known_hosts file accordingly.\n"
  6199. return 1
  6200. }
  6201. -re "$u_prompt" {
  6202. send -- "$user\r"
  6203. set uprompt_seen 1
  6204. exp_continue
  6205. }
  6206. -re "$p_prompt" {
  6207. sleep 1
  6208. if {$uprompt_seen == 1} {
  6209. send -- "$userpswd\r"
  6210. } else {
  6211. send -- "$passwd\r"
  6212. }
  6213. exp_continue
  6214. }
  6215. -re "^Confirm seeing above note" {
  6216. send "y\r"
  6217. exp_continue
  6218. }
  6219. "Password incorrect" { send_user "\nError: Check your password for $router\n";
  6220. catch {close}; catch {wait}; return 1 }
  6221. -re "$prompt" { break; }
  6222. denied { send_user "\nError: Check your passwd for $router\n"
  6223. catch {close}; catch {wait}; return 1
  6224. }
  6225. "\r\n" { exp_continue; }
  6226. }
  6227. }
  6228. set in_proc 0
  6229. return 0
  6230. }
  6231.  
  6232. # Run commands given on the command line.
  6233. proc run_commands { prompt command } {
  6234. global in_proc
  6235. set in_proc 1
  6236.  
  6237. send "lines 0\r"
  6238. expect -re $prompt {}
  6239. regsub -all "\[)(]" $prompt {\\&} reprompt
  6240.  
  6241. set commands [split $command \;]
  6242. set num_commands [llength $commands]
  6243. for {set i 0} {$i < $num_commands} { incr i} {
  6244. send -- "[subst -nocommands [lindex $commands $i]]\r"
  6245. expect {
  6246. -re "^\[^\n\r]*$reprompt" {}
  6247. -re "^\[^\n\r ]*>>.*$reprompt" { exp_continue }
  6248. -re "\[\n\r]+" { exp_continue }
  6249. }
  6250. }
  6251.  
  6252. send "quit\r"
  6253. # expect {
  6254. # -re "^WARNING: the current user has insufficient rights to view password fields. A configuration saved under this circumstance should not be used to restore profiles containing passwords. Save anyway? [y/n]"
  6255. # {
  6256. # send "y\r"
  6257. exp_continue
  6258. }
  6259. "\n" { exp_continue }
  6260. "\[^\n\r *]*Session terminated" { return 0 }
  6261. timeout { catch {close}; catch {wait};
  6262. return 0
  6263. }
  6264. eof { return 0 }
  6265. }
  6266. set in_proc 0
  6267. }
  6268.  
  6269. #
  6270. # For each router... (this is main loop)
  6271. #
  6272. source_password_file $password_file
  6273. set in_proc 0
  6274. set exitval 0
  6275. foreach router [lrange $argv $i end] {
  6276. set router [string tolower $router]
  6277. send_user "$router\n"
  6278.  
  6279. # device timeout
  6280. set timeout [find timeout $router]
  6281. if { [llength $timeout] == 0 } {
  6282. set timeout $timeoutdflt
  6283. }
  6284.  
  6285. # Figure out prompt.
  6286. set prompt "admin>"
  6287. # TNT only "enables" based on the password used at login time
  6288. set autoenable 1
  6289. set enable 0
  6290.  
  6291. # Figure out passwords
  6292. if { $do_passwd } {
  6293. set pswd [find password $router]
  6294. if { [llength $pswd] == 0 } {
  6295. send_user "\nError - no password for $router in $password_file.\n"
  6296. continue
  6297. }
  6298. set passwd [join [lindex $pswd 0] ""]
  6299. }
  6300.  
  6301. # Figure out username
  6302. if {[info exists username]} {
  6303. # command line username
  6304. set ruser $username
  6305. } else {
  6306. set ruser [join [find user $router] ""]
  6307. if { "$ruser" == "" } { set ruser $default_user }
  6308. }
  6309.  
  6310. # Figure out username's password (if different from the vty password)
  6311. if {[info exists userpasswd]} {
  6312. # command line username
  6313. set userpswd $userpasswd
  6314. } else {
  6315. set userpswd [join [find userpassword $router] ""]
  6316. if { "$userpswd" == "" } { set userpswd $passwd }
  6317. }
  6318.  
  6319. # Figure out prompts
  6320. set u_prompt [find userprompt $router]
  6321. if { "$u_prompt" == "" } {
  6322. set u_prompt "(User|Username|login| Login):"
  6323. } else {
  6324. set u_prompt [join [lindex $u_prompt 0] ""]
  6325. }
  6326.  
  6327. set p_prompt [find passprompt $router]
  6328. if { "$p_prompt" == "" } {
  6329. set p_prompt "\[Pp]assword:"
  6330. } else {
  6331. set p_prompt [join [lindex $p_prompt 0] ""]
  6332. }
  6333.  
  6334. # Figure out cypher type
  6335. if {[info exists cypher]} {
  6336. # command line cypher type
  6337. set cyphertype $cypher
  6338. } else {
  6339. set cyphertype [find cyphertype $router]
  6340. if { "$cyphertype" == "" } { set cyphertype "3des" }
  6341. }
  6342.  
  6343. # Figure out connection method
  6344. set cmethod [find method $router]
  6345. if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} }
  6346.  
  6347. # Figure out the SSH executable name
  6348. set sshcmd [join [lindex [find sshcmd $router] 0] ""]
  6349. if { "$sshcmd" == "" } { set sshcmd {ssh} }
  6350.  
  6351. # Login to the router
  6352. if {[login $router $ruser $userpswd $passwd $prompt $cmethod $cyphertype]} {
  6353. incr exitval
  6354. continue
  6355. }
  6356.  
  6357. if { $do_command } {
  6358. if {[run_commands $prompt $command]} {
  6359. incr exitval
  6360. continue
  6361. }
  6362. } elseif { $do_script } {
  6363. expect -re $prompt {}
  6364. source $sfile
  6365. send "y\r"
  6366. catch {close};
  6367. } else {
  6368. label $router
  6369. log_user 1
  6370. interact
  6371. }
  6372.  
  6373. # End of for each router
  6374. catch {wait};
  6375. sleep 0.3
  6376. }
  6377. exit $exitval
  6378. #! /usr/bin/perl
  6379. ##
  6380. ## $Id: tntrancid.in 2279 2011-01-31 22:41:00Z heas $
  6381. ##
  6382. ## rancid 2.3.8
  6383. ## Copyright (c) 1997-2008 by Terrapin Communications, Inc.
  6384. ## All rights reserved.
  6385. ##
  6386. ## This code is derived from software contributed to and maintained by
  6387. ## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan,
  6388. ## Pete Whiting, Austin Schutz, and Andrew Fort.
  6389. ##
  6390. ## Redistribution and use in source and binary forms, with or without
  6391. ## modification, are permitted provided that the following conditions
  6392. ## are met:
  6393. ## 1. Redistributions of source code must retain the above copyright
  6394. ## notice, this list of conditions and the following disclaimer.
  6395. ## 2. Redistributions in binary form must reproduce the above copyright
  6396. ## notice, this list of conditions and the following disclaimer in the
  6397. ## documentation and/or other materials provided with the distribution.
  6398. ## 3. All advertising materials mentioning features or use of this software
  6399. ## must display the following acknowledgement:
  6400. ## This product includes software developed by Terrapin Communications,
  6401. ## Inc. and its contributors for RANCID.
  6402. ## 4. Neither the name of Terrapin Communications, Inc. nor the names of its
  6403. ## contributors may be used to endorse or promote products derived from
  6404. ## this software without specific prior written permission.
  6405. ## 5. It is requested that non-binding fixes and modifications be contributed
  6406. ## back to Terrapin Communications, Inc.
  6407. ##
  6408. ## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS
  6409. ## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  6410. ## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  6411. ## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
  6412. ## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  6413. ## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  6414. ## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  6415. ## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  6416. ## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  6417. ## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  6418. ## POSSIBILITY OF SUCH DAMAGE.
  6419. #
  6420. # Modified by Paul B Matthews & Richard Vander Reyden.
  6421. # I'm suprised it still works....
  6422. #
  6423. # RANCID - Really Awesome New Cisco confIg Differ
  6424. #
  6425. # usage: tntrancid [-dV] [-l] [-f filename | hostname]
  6426. #
  6427. use Getopt::Std;
  6428. getopts('dflV');
  6429. if ($opt_V) {
  6430. print "rancid 2.3.8\n";
  6431. exit(0);
  6432. }
  6433. $log = $opt_l;
  6434. $debug = $opt_d;
  6435. $file = $opt_f;
  6436. $host = $ARGV[0];
  6437. $clean_run = 0;
  6438. $found_end = 0;
  6439. $timeo = 90; # tntlogin timeout in seconds
  6440. $prompt = "admin> ";
  6441. $always_y = "y"; # cause its a pain.
  6442.  
  6443. my(@commandtable, %commands, @commands);# command lists
  6444. my($aclsort) = ("ipsort"); # ACL sorting mode
  6445. my($filter_commstr); # SNMP community string filtering
  6446. my($filter_pwds); # password filtering mode
  6447.  
  6448. # This routine is used to print out the router configuration
  6449. sub ProcessHistory {
  6450. my($new_hist_tag,$new_command,$command_string,@string) = (@_);
  6451. if ((($new_hist_tag ne $hist_tag) || ($new_command ne $command))
  6452. && scalar(%history)) {
  6453. print eval "$command \%history";
  6454. undef %history;
  6455. }
  6456. if (($new_hist_tag) && ($new_command) && ($command_string)) {
  6457. if ($history{$command_string}) {
  6458. $history{$command_string} = "$history{$command_string}@string";
  6459. } else {
  6460. $history{$command_string} = "@string";
  6461. }
  6462. } elsif (($new_hist_tag) && ($new_command)) {
  6463. $history{++$#history} = "@string";
  6464. } else {
  6465. print "@string";
  6466. }
  6467. $hist_tag = $new_hist_tag;
  6468. $command = $new_command;
  6469. 1;
  6470. }
  6471.  
  6472. sub numerically { $a <=> $b; }
  6473.  
  6474. # This is a sort routine that will sort numerically on the
  6475. # keys of a hash as if it were a normal array.
  6476. sub keynsort {
  6477. local(%lines) = @_;
  6478. local($i) = 0;
  6479. local(@sorted_lines);
  6480. foreach $key (sort numerically keys(%lines)) {
  6481. $sorted_lines[$i] = $lines{$key};
  6482. $i++;
  6483. }
  6484. @sorted_lines;
  6485. }
  6486.  
  6487. # This is a sort routine that will sort on the
  6488. # keys of a hash as if it were a normal array.
  6489. sub keysort {
  6490. local(%lines) = @_;
  6491. local($i) = 0;
  6492. local(@sorted_lines);
  6493. foreach $key (sort keys(%lines)) {
  6494. $sorted_lines[$i] = $lines{$key};
  6495. $i++;
  6496. }
  6497. @sorted_lines;
  6498. }
  6499.  
  6500. # This is a sort routine that will sort on the
  6501. # values of a hash as if it were a normal array.
  6502. sub valsort{
  6503. local(%lines) = @_;
  6504. local($i) = 0;
  6505. local(@sorted_lines);
  6506. foreach $key (sort values %lines) {
  6507. $sorted_lines[$i] = $key;
  6508. $i++;
  6509. }
  6510. @sorted_lines;
  6511. }
  6512.  
  6513. # This is a numerical sort routine (ascending).
  6514. sub numsort {
  6515. local(%lines) = @_;
  6516. local($i) = 0;
  6517. local(@sorted_lines);
  6518. foreach $num (sort {$a <=> $b} keys %lines) {
  6519. $sorted_lines[$i] = $lines{$num};
  6520. $i++;
  6521. }
  6522. @sorted_lines;
  6523. }
  6524.  
  6525. # This is a sort routine that will sort on the
  6526. # ip address when the ip address is anywhere in
  6527. # the strings.
  6528. sub ipsort {
  6529. local(%lines) = @_;
  6530. local($i) = 0;
  6531. local(@sorted_lines);
  6532. foreach $addr (sort sortbyipaddr keys %lines) {
  6533. $sorted_lines[$i] = $lines{$addr};
  6534. $i++;
  6535. }
  6536. @sorted_lines;
  6537. }
  6538.  
  6539. # These two routines will sort based upon IP addresses
  6540. sub ipaddrval {
  6541. my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#);
  6542. $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0]));
  6543. }
  6544. sub sortbyipaddr {
  6545. &ipaddrval($a) <=> &ipaddrval($b);
  6546. }
  6547.  
  6548. # This routine processes a "save con"
  6549. sub SaveConf {
  6550. print STDERR " In SaveConf: $_" if ($debug);
  6551.  
  6552. while (<INPUT>) {
  6553. tr/\015//d;
  6554. last if(/^$prompt/);
  6555.  
  6556. # Leave software revision, but strip out saved date,
  6557. # which causes rancid to think it changes each poll
  6558. if (/^; saved from /) {
  6559. ProcessHistory("","","","$_");
  6560. next;
  6561. }
  6562. /^; saved / && next;
  6563.  
  6564. # catch anything that wasnt match above.
  6565. ProcessHistory("","","","$_");
  6566.  
  6567. # end of config
  6568. if (/; profiles saved$/) {
  6569. printf STDERR " End SaveConf: $_" if ($debug);
  6570. $found_end = 1;
  6571. print STDOUT "$found_end = found_end within test\n";
  6572. return(1);
  6573. }
  6574. # XXX what is the purpose of this?
  6575. $found_end = 1;
  6576. #### print STDOUT "$found_end = found_end at test\n";
  6577. }
  6578. $found_end = 1;
  6579. return(0);
  6580. }
  6581. $found_end = 1;
  6582. print STDOUT "$found_end = found_end at end test\n";
  6583.  
  6584.  
  6585.  
  6586.  
  6587. # dummy function
  6588. sub DoNothing {print STDOUT;}
  6589.  
  6590. # Main
  6591. @commandtable = (
  6592. {'save con' => 'SaveConf'}
  6593. );
  6594. # Use an array to preserve the order of the commands and a hash for mapping
  6595. # commands to the subroutine and track commands that have been completed.
  6596. @commands = map(keys(%$_), @commandtable);
  6597. %commands = map(%$_, @commandtable);
  6598.  
  6599. $tnt_cmds=join(";",@commands);
  6600. $cmds_regexp = join("|", map quotemeta($_), @commands);
  6601.  
  6602. if (length($host) == 0) {
  6603. if ($file) {
  6604. print(STDERR "Too few arguments: file name required\n");
  6605. exit(1);
  6606. } else {
  6607. print(STDERR "Too few arguments: host name required\n");
  6608. exit(1);
  6609. }
  6610. }
  6611. open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n";
  6612. select(OUTPUT);
  6613. # make OUTPUT unbuffered if debugging
  6614. if ($debug) { $| = 1; }
  6615.  
  6616. if ($file) {
  6617. print STDERR "opening file $host\n" if ($debug);
  6618. print STDOUT "opening file $host\n" if ($log);
  6619. open(INPUT,"<$host") || die "open failed for $host: $!\n";
  6620. } else {
  6621. print STDERR "executing tntlogin -t $timeo -c\"$tnt_cmds\" $host\n" if ($debug);
  6622. print STDOUT "executing tntlogin -t $timeo -c\"$tnt_cmds\" $host\n" if ($log);
  6623. if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
  6624. system "tntlogin -t $timeo -c \"$tnt_cmds\" $host </dev/null > $host.raw 2>&1" || die "tntlogin failed for $host: $!\n";
  6625. open(INPUT, "< $host.raw") || die "tntlogin failed for $host: $!\n";
  6626. } else {
  6627. open(INPUT,"tntlogin -t $timeo -c \"$tnt_cmds\" $host </dev/null |") || die "tntlogin failed for $host: $!\n";
  6628. }
  6629. }
  6630.  
  6631. # determine ACL sorting mode
  6632. if ($ENV{"ACLSORT"} =~ /no/i) {
  6633. $aclsort = "";
  6634. }
  6635. # determine community string filtering mode
  6636. if (defined($ENV{"NOCOMMSTR"}) &&
  6637. ($ENV{"NOCOMMSTR"} =~ /yes/i || $ENV{"NOCOMMSTR"} =~ /^$/)) {
  6638. $filter_commstr = 1;
  6639. } else {
  6640. $filter_commstr = 0;
  6641. }
  6642. # determine password filtering mode
  6643. if ($ENV{"FILTER_PWDS"} =~ /no/i) {
  6644. $filter_pwds = 0;
  6645. } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) {
  6646. $filter_pwds = 2;
  6647. } else {
  6648. $filter_pwds = 1;
  6649. }
  6650.  
  6651. ProcessHistory("","","","#RANCID-CONTENT-TYPE: tnt\n#\n");
  6652. ProcessHistory("COMMENTS","keysort","X0",";\n");
  6653. TOP: while(<INPUT>) {
  6654. tr/\015//d;
  6655.  
  6656. if (/^Error:/) {
  6657. print STDOUT ("$host tntlogin error: $_");
  6658. print STDERR ("$host tntlogin error: $_") if ($debug);
  6659. $clean_run=0;
  6660. last;
  6661. }
  6662. while (/$prompt\s*($cmds_regexp)\s*$/) {
  6663. $cmd = $1;
  6664. if (!defined($prompt)) {
  6665. $prompt = ($_ =~ /^([^#]+#)/)[0];
  6666. $prompt =~ s/([][}{)(\\])/\\$1/g;
  6667. $prompt =~ s/:(\d+ ?)#/:\\d+ ?#/;
  6668. print STDERR ("PROMPT MATCH: $prompt\n") if ($debug);
  6669. }
  6670. print STDERR ("HIT COMMAND:$_") if ($debug);
  6671. if (! defined($commands{$cmd})) {
  6672. print STDERR "$host: found unexpected command - \"$cmd\"\n";
  6673. $clean_run = 0;
  6674. last TOP;
  6675. }
  6676. $rval = &{$commands{$cmd}};
  6677. delete($commands{$cmd});
  6678. if ($rval == -1) {
  6679. printf STDERR "rval = -1\n" if ($debug);
  6680. $clean_run = 0;
  6681. last TOP;
  6682. }
  6683. }
  6684. }
  6685. print STDOUT "Done $logincmd: $_\n" if ($log);
  6686. # Flush History
  6687. ProcessHistory("","","","");
  6688. # Cleanup
  6689. $clean_run = 1;
  6690. print STDOUT "$clean_run - clean\n";
  6691. close(INPUT);
  6692. close(OUTPUT);
  6693.  
  6694. if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
  6695. unlink("$host.raw") if (! $debug);
  6696. }
  6697.  
  6698. # check for completeness
  6699. if (scalar(%commands) || !$clean_run || !$found_end) {
  6700. if (scalar(%commands)) {
  6701. printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands)));
  6702. printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug);
  6703. }
  6704. if (!$clean_run || !$found_end) {
  6705. print STDOUT "$host: End of run not found\n";
  6706. print STDERR "$host: End of run not found\n" if ($debug);
  6707. system("/usr/bin/tail -1 $host.new");
  6708. }
  6709. unlink "$host.new" if (! $debug);
  6710. }
  6711. #! /usr/bin/perl
  6712. ##
  6713. ## $Id: trancid.in 2880 2014-09-29 18:23:24Z heas $
  6714. ##
  6715. ## rancid 3.4.1
  6716. ## Copyright (c) 1997-2016 by Terrapin Communications, Inc.
  6717. ## All rights reserved.
  6718. ##
  6719. ## This code is derived from software contributed to and maintained by
  6720. ## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan,
  6721. ## Pete Whiting, Austin Schutz, and Andrew Fort.
  6722. ##
  6723. ## Redistribution and use in source and binary forms, with or without
  6724. ## modification, are permitted provided that the following conditions
  6725. ## are met:
  6726. ## 1. Redistributions of source code must retain the above copyright
  6727. ## notice, this list of conditions and the following disclaimer.
  6728. ## 2. Redistributions in binary form must reproduce the above copyright
  6729. ## notice, this list of conditions and the following disclaimer in the
  6730. ## documentation and/or other materials provided with the distribution.
  6731. ## 3. All advertising materials mentioning features or use of this software
  6732. ## must display the following acknowledgement:
  6733. ## This product includes software developed by Terrapin Communications,
  6734. ## Inc. and its contributors for RANCID.
  6735. ## 4. Neither the name of Terrapin Communications, Inc. nor the names of its
  6736. ## contributors may be used to endorse or promote products derived from
  6737. ## this software without specific prior written permission.
  6738. ## 5. It is requested that non-binding fixes and modifications be contributed
  6739. ## back to Terrapin Communications, Inc.
  6740. ##
  6741. ## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS
  6742. ## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  6743. ## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  6744. ## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
  6745. ## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  6746. ## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  6747. ## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  6748. ## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  6749. ## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  6750. ## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  6751. ## POSSIBILITY OF SUCH DAMAGE.
  6752. #
  6753. # RANCID - Really Awesome New Cisco confIg Differ
  6754. #
  6755. # usage: trancid [-dltCV] [-f filename | hostname]
  6756. #
  6757. # Modified by Ed Ravin for Netopia.
  6758. use Getopt::Std;
  6759. getopts('dflt:CV');
  6760. if ($opt_V) {
  6761. print "rancid 3.4.1\n";
  6762. exit(0);
  6763. }
  6764. $log = $opt_l;
  6765. $debug = $opt_d;
  6766. $file = $opt_f;
  6767. $host = $ARGV[0];
  6768. $clean_run = 0;
  6769. $found_end = 0;
  6770. $found_version = 0;
  6771. $found_env = 0;
  6772. $found_diag = 0;
  6773. $timeo = 90; # clogin timeout in seconds
  6774.  
  6775. my(%filter_pwds); # password filtering mode
  6776.  
  6777. # This routine is used to print out the router configuration
  6778. sub ProcessHistory {
  6779. my($new_hist_tag,$new_command,$command_string,@string)=(@_);
  6780. if((($new_hist_tag ne $hist_tag) || ($new_command ne $command))
  6781. && scalar(%history)) {
  6782. print eval "$command \%history";
  6783. undef %history;
  6784. }
  6785. if (($new_hist_tag) && ($new_command) && ($command_string)) {
  6786. if ($history{$command_string}) {
  6787. $history{$command_string} = "$history{$command_string}@string";
  6788. } else {
  6789. $history{$command_string} = "@string";
  6790. }
  6791. } elsif (($new_hist_tag) && ($new_command)) {
  6792. $history{++$#history} = "@string";
  6793. } else {
  6794. print "@string";
  6795. }
  6796. $hist_tag = $new_hist_tag;
  6797. $command = $new_command;
  6798. 1;
  6799. }
  6800.  
  6801. sub numerically { $a <=> $b; }
  6802.  
  6803. # This is a sort routing that will sort numerically on the
  6804. # keys of a hash as if it were a normal array.
  6805. sub keynsort {
  6806. local(%lines)=@_;
  6807. local($i) = 0;
  6808. local(@sorted_lines);
  6809. foreach $key (sort numerically keys(%lines)) {
  6810. $sorted_lines[$i] = $lines{$key};
  6811. $i++;
  6812. }
  6813. @sorted_lines;
  6814. }
  6815.  
  6816. # This is a sort routing that will sort on the
  6817. # keys of a hash as if it were a normal array.
  6818. sub keysort {
  6819. local(%lines)=@_;
  6820. local($i) = 0;
  6821. local(@sorted_lines);
  6822. foreach $key (sort keys(%lines)) {
  6823. $sorted_lines[$i] = $lines{$key};
  6824. $i++;
  6825. }
  6826. @sorted_lines;
  6827. }
  6828.  
  6829. # This is a sort routing that will sort on the
  6830. # values of a hash as if it were a normal array.
  6831. sub valsort{
  6832. local(%lines)=@_;
  6833. local($i) = 0;
  6834. local(@sorted_lines);
  6835. foreach $key (sort values %lines) {
  6836. $sorted_lines[$i] = $key;
  6837. $i++;
  6838. }
  6839. @sorted_lines;
  6840. }
  6841.  
  6842. # This is a numerical sort routing (ascending).
  6843. sub numsort {
  6844. local(%lines)=@_;
  6845. local($i) = 0;
  6846. local(@sorted_lines);
  6847. foreach $num (sort {$a <=> $b} keys %lines) {
  6848. $sorted_lines[$i] = $lines{$num};
  6849. $i++;
  6850. }
  6851. @sorted_lines;
  6852. }
  6853.  
  6854. # This is a sort routine that will sort on the
  6855. # ip address when the ip address is anywhere in
  6856. # the strings.
  6857. sub ipsort {
  6858. local(%lines)=@_;
  6859. local($i) = 0;
  6860. local(@sorted_lines);
  6861. foreach $addr (sort sortbyipaddr keys %lines) {
  6862. $sorted_lines[$i] = $lines{$addr};
  6863. $i++;
  6864. }
  6865. @sorted_lines;
  6866. }
  6867.  
  6868. # These two routines will sort based upon IP addresses
  6869. sub ipaddrval {
  6870. my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#);
  6871. $a[3]+256*($a[2]+256*($a[1]+256*$a[0]));
  6872. }
  6873. sub sortbyipaddr {
  6874. &ipaddrval($a) <=> &ipaddrval($b);
  6875. }
  6876.  
  6877. # This routine parses "show version"
  6878. sub ShowVersion {
  6879. print STDERR " In ShowVersion: $_" if ($debug);
  6880.  
  6881. while (<INPUT>) {
  6882. tr/\015//d;
  6883. if (/^$prompt/) { $found_version=1; last};
  6884. next if(/^(\s*|\s*$cmd\s*)$/);
  6885. return(1) if /(Invalid input detected|Type help or )/;
  6886. return(-1) if (/command authorization failed/i);
  6887. return(0) if ($found_version); # Only do this routine once
  6888.  
  6889. # no pagers in Netopia-land, but shouldn't hurt
  6890. s/^<-+ More -+>\s*//;
  6891.  
  6892. ### sample output:
  6893. ### #show version
  6894. ### cli version: 01.00d00
  6895. ### firmware version: 05.03.09f06
  6896. ### hardware version: 01.00f00
  6897. ### mib version: 01.00f00
  6898. ### html version: 01.01d07
  6899.  
  6900. ProcessHistory("COMMENTS","keysort","A1","# $_");
  6901. }
  6902.  
  6903. return(0);
  6904. }
  6905.  
  6906. sub ShowConfig {
  6907. print STDERR " In ShowConfig: $_" if ($debug);
  6908.  
  6909. while (<INPUT>) {
  6910. tr/\015//d;
  6911. if (/^$prompt/) { $found_end=1; $clean_run=1; return 0};
  6912. next if(/^(\s*|\s*$cmd\s*)$/);
  6913. return(1) if /(Invalid input detected|Type help or )/;
  6914. return(-1) if (/command authorization failed/i);
  6915.  
  6916. # no pagers in Netopia-land, but shouldn't hurt
  6917. s/^<-+ More -+>\s*//;
  6918.  
  6919. # no post-processing needed - just file it
  6920. ProcessHistory("","","","$_");
  6921. }
  6922. }
  6923.  
  6924. # Main
  6925. @commandtable=(
  6926. {'show version' => "ShowVersion"},
  6927. {'show config' => "ShowConfig"},
  6928. );
  6929.  
  6930. # Use array to preserve order of commands, and hash for mapping to subroutine
  6931. my (%commands, @commands);
  6932. foreach (@commandtable) {
  6933. push @commands, (keys(%{$_}))[0];
  6934. $commands{$commands[$#commands]}= (values(%{$_}))[0];
  6935. };
  6936. $commandstr=join(";",@commands);
  6937. $cmds_regexp = join("|", map quotemeta($_), @commands);
  6938. $commandcnt = scalar(keys %commands);
  6939.  
  6940. if (length($host) == 0) {
  6941. if ($file) {
  6942. print(STDERR "Too few arguments: file name required\n");
  6943. exit(1);
  6944. } else {
  6945. print(STDERR "Too few arguments: host name required\n");
  6946. exit(1);
  6947. }
  6948. }
  6949. if ($opt_C) {
  6950. print "tlogin -t $timeo -c\'$commandstr\' $host\n";
  6951. exit(0);
  6952. }
  6953. open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n";
  6954. select(OUTPUT);
  6955. # make OUTPUT unbuffered if debugging
  6956. if ($debug) { $| = 1; }
  6957.  
  6958. if ($file) {
  6959. print STDERR "opening file $host\n" if ($debug);
  6960. print STDOUT "opening file $host\n" if ($log);
  6961. open(INPUT,"<$host") || die "open failed for $host: $!\n";
  6962. } else {
  6963. print STDERR "executing tlogin -t $timeo -c\"$commandstr\" $host\n" if ($debug);
  6964. print STDOUT "executing tlogin -t $timeo -c\"$commandstr\" $host\n" if ($log);
  6965. if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
  6966. system "tlogin -t $timeo -c \"$commandstr\" $host </dev/null > $host.raw 2>&1" || die "tlogin failed for $host: $!\n";
  6967. open(INPUT, "< $host.raw") || die "tlogin failed for $host: $!\n";
  6968. } else {
  6969. open(INPUT,"tlogin -t $timeo -c \"$commandstr\" $host </dev/null |") || die "tlogin failed for $host: $!\n";
  6970. }
  6971. }
  6972.  
  6973. # determine password filtering mode
  6974. if ($ENV{"FILTER_PWDS"} =~ /no/i) {
  6975. $filter_pwds = 0;
  6976. } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) {
  6977. $filter_pwds = 2;
  6978. } else {
  6979. $filter_pwds = 1;
  6980. }
  6981.  
  6982. ProcessHistory("","","","#RANCID-CONTENT-TYPE: netopia\n#\n");
  6983. ProcessHistory("COMMENTS","keysort","B0","#\n");
  6984. ProcessHistory("COMMENTS","keysort","D0","#\n");
  6985. ProcessHistory("COMMENTS","keysort","F0","#\n");
  6986. ProcessHistory("COMMENTS","keysort","G0","#\n");
  6987. TOP: while(<INPUT>) {
  6988. tr/\015//d;
  6989. if (/[>#]\s?exit$/) {
  6990. $clean_run=1;
  6991. last;
  6992. }
  6993. if (/^Error:/) {
  6994. print STDOUT ("$host tlogin error: $_");
  6995. print STDERR ("$host tlogin error: $_") if ($debug);
  6996. $clean_run=0;
  6997. last;
  6998. }
  6999. while (/#\s*($cmds_regexp)\s*$/) {
  7000. $cmd = $1;
  7001. if (!defined($prompt)) {
  7002. $prompt = "#"; # crude but effective
  7003. $prompt =~ s/([][}{)(\\])/\\$1/g;
  7004. print STDERR ("PROMPT MATCH: $prompt\n") if ($debug);
  7005. }
  7006. print STDERR ("HIT COMMAND:$_") if ($debug);
  7007. if (! defined($commands{$cmd})) {
  7008. print STDERR "$host: found unexpected command - \"$cmd\"\n";
  7009. $clean_run = 0;
  7010. last TOP;
  7011. }
  7012. $rval = &{$commands{$cmd}}(*INPUT, *OUTPUT, $cmd);
  7013. delete($commands{$cmd});
  7014. if ($rval == -1) {
  7015. $clean_run = 0;
  7016. last TOP;
  7017. }
  7018. }
  7019. }
  7020. print STDOUT "Done $logincmd: $_\n" if ($log);
  7021. # Flush History
  7022. ProcessHistory("","","","");
  7023. # Cleanup
  7024. close(INPUT);
  7025. close(OUTPUT);
  7026.  
  7027. if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
  7028. unlink("$host.raw") if (! $debug);
  7029. }
  7030.  
  7031. # check for completeness
  7032. if (scalar(%commands) || !$clean_run || !$found_end) {
  7033. if (scalar(keys %commands) eq $commandcnt) {
  7034. printf(STDERR "$host: missed cmd(s): all commands\n");
  7035. } elsif (scalar(%commands)) {
  7036. printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands)));
  7037. printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug);
  7038. }
  7039. if (!$clean_run || !$found_end) {
  7040. print STDOUT "$host: End of run not found\n";
  7041. print STDERR "$host: End of run not found\n" if ($debug);
  7042. system("/usr/bin/tail -1 $host.new");
  7043. }
  7044. unlink "$host.new" if (! $debug);
  7045. }
  7046. #! /usr/bin/expect --
  7047. ##
  7048. ## $Id: wlogin.in 3201 2015-11-05 00:48:01Z heas $
  7049. ##
  7050. ## rancid 3.4.1
  7051. ## Copyright (c) 1997-2016 by Terrapin Communications, Inc.
  7052. ## All rights reserved.
  7053. ##
  7054. ## This code is derived from software contributed to and maintained by
  7055. ## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan,
  7056. ## Pete Whiting, Austin Schutz, and Andrew Fort.
  7057. ##
  7058. ## Redistribution and use in source and binary forms, with or without
  7059. ## modification, are permitted provided that the following conditions
  7060. ## are met:
  7061. ## 1. Redistributions of source code must retain the above copyright
  7062. ## notice, this list of conditions and the following disclaimer.
  7063. ## 2. Redistributions in binary form must reproduce the above copyright
  7064. ## notice, this list of conditions and the following disclaimer in the
  7065. ## documentation and/or other materials provided with the distribution.
  7066. ## 3. All advertising materials mentioning features or use of this software
  7067. ## must display the following acknowledgement:
  7068. ## This product includes software developed by Terrapin Communications,
  7069. ## Inc. and its contributors for RANCID.
  7070. ## 4. Neither the name of Terrapin Communications, Inc. nor the names of its
  7071. ## contributors may be used to endorse or promote products derived from
  7072. ## this software without specific prior written permission.
  7073. ## 5. It is requested that non-binding fixes and modifications be contributed
  7074. ## back to Terrapin Communications, Inc.
  7075. ##
  7076. ## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS
  7077. ## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  7078. ## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  7079. ## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
  7080. ## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  7081. ## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  7082. ## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  7083. ## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  7084. ## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  7085. ## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  7086. ## POSSIBILITY OF SUCH DAMAGE.
  7087. ##
  7088. ## It is the request of the authors, but not a condition of license, that
  7089. ## parties packaging or redistributing RANCID NOT distribute altered versions
  7090. ## of the etc/rancid.types.base file nor alter how this file is processed nor
  7091. ## when in relation to etc/rancid.types.conf. The goal of this is to help
  7092. ## suppress our support costs. If it becomes a problem, this could become a
  7093. ## condition of license.
  7094. #
  7095. # The expect login scripts were based on Erik Sherk's gwtn, by permission.
  7096. #
  7097. # The original looking glass software was written by Ed Kern, provided by
  7098. # permission and modified beyond recognition.
  7099. #
  7100. # wlogin - Cisco Wireless Lan Controller login
  7101. #
  7102. # Modified from clogin for use with WLCs 4/17/2008 - Josh Yost
  7103. #
  7104. # Most options are intuitive for logging into a Cisco router.
  7105. # The default is to enable (thus -noenable). Some folks have
  7106. # setup tacacs to have a user login at priv-lvl = 15 (enabled)
  7107. # so the -autoenable flag was added for this case (don't go through
  7108. # the process of enabling and the prompt will be the "#" prompt.
  7109. # The default username password is the same as the vty password.
  7110. #
  7111.  
  7112. # Usage line
  7113. set usage "Usage: $argv0 \[-dSV\] \[-autoenable\] \[-noenable\] \[-c command\] \
  7114. \[-Evar=x\] \[-e enable-password\] \[-f cloginrc-file\] \[-p user-password\] \
  7115. \[-r passphrase\] \[-s script-file\] \[-t timeout\] \[-u username\] \
  7116. \[-v vty-password\] \[-w enable-username\] \[-x command-file\] \
  7117. \[-y ssh_cypher_type\] router \[router...\]\n"
  7118.  
  7119. # env(CLOGIN) may contain:
  7120. # x == do not set xterm banner or name
  7121.  
  7122. # Password file
  7123. set password_file $env(HOME)/.cloginrc
  7124. # Default is to login to the router
  7125. set do_command 0
  7126. set do_script 0
  7127. # The default is to automatically enable
  7128. set avenable 1
  7129. # The default is that you login non-enabled (tacacs can have you login already
  7130. # enabled)
  7131. set avautoenable 0
  7132. # The default is to look in the password file to find the passwords. This
  7133. # tracks if we receive them on the command line.
  7134. set do_passwd 1
  7135. set do_enapasswd 1
  7136. # Sometimes routers take awhile to answer (the default is 10 sec)
  7137. set timeoutdflt 10
  7138. # Some CLIs having problems if we write too fast (Extreme, PIX, Cat)
  7139. set send_human {.2 .1 .4 .2 1}
  7140.  
  7141. # Find the user in the ENV, or use the unix userid.
  7142. if {[ info exists env(CISCO_USER) ]} {
  7143. set default_user $env(CISCO_USER)
  7144. } elseif {[ info exists env(USER) ]} {
  7145. set default_user $env(USER)
  7146. } elseif {[ info exists env(LOGNAME) ]} {
  7147. set default_user $env(LOGNAME)
  7148. } else {
  7149. # This uses "id" which I think is portable. At least it has existed
  7150. # (without options) on all machines/OSes I've been on recently -
  7151. # unlike whoami or id -nu.
  7152. if [ catch {exec id} reason ] {
  7153. send_error "\nError: could not exec id: $reason\n"
  7154. exit 1
  7155. }
  7156. regexp {\(([^)]*)} "$reason" junk default_user
  7157. }
  7158.  
  7159. # Sometimes routers take awhile to answer (the default is 10 sec)
  7160. set timeout 45
  7161.  
  7162. # Process the command line
  7163. for {set i 0} {$i < $argc} {incr i} {
  7164. set arg [lindex $argv $i]
  7165.  
  7166. switch -glob -- $arg {
  7167. # Command to run.
  7168. -c* {
  7169. if {! [ regexp .\[cC\](.+) $arg ignore command]} {
  7170. incr i
  7171. set command [ lindex $argv $i ]
  7172. }
  7173. set do_command 1
  7174. # Expect debug mode
  7175. } -d* {
  7176. exp_internal 1
  7177. # Environment variable to pass to -s scripts
  7178. } -E*
  7179. {
  7180. if {[ regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} {
  7181. set E$varname $varvalue
  7182. } else {
  7183. send_user "\nError: invalid format for -E in $arg\n"
  7184. exit 1
  7185. }
  7186. # alternate cloginrc file
  7187. } -f* {
  7188. if {! [ regexp .\[fF\](.+) $arg ignore password_file]} {
  7189. incr i
  7190. set password_file [ lindex $argv $i ]
  7191. }
  7192. # VTY Password
  7193. } -p* -
  7194. -P* {
  7195. if {! [ regexp .\[pP\](.+) $arg ignore userpasswd]} {
  7196. incr i
  7197. set userpasswd [ lindex $argv $i ]
  7198. }
  7199. set do_passwd 0
  7200. # Enable Password
  7201. } -e*
  7202. {
  7203. if {! [ regexp .\[e\](.+) $arg ignore enapasswd]} {
  7204. incr i
  7205. set enapasswd [ lindex $argv $i ]
  7206. }
  7207. set do_enapasswd 0
  7208. # Expect script to run.
  7209. } -s* {
  7210. if {! [ regexp .\[sS\](.+) $arg ignore sfile]} {
  7211. incr i
  7212. set sfile [ lindex $argv $i ]
  7213. }
  7214. if { ! [ file readable $sfile ] } {
  7215. send_user "\nError: Can't read $sfile\n"
  7216. exit 1
  7217. }
  7218. set do_script 1
  7219. # save config on exit
  7220. } -S* {
  7221. set do_saveconfig 1
  7222. # Timeout
  7223. } -t* {
  7224. if {! [ regexp .\[tT\](.+) $arg ignore timeout]} {
  7225. incr i
  7226. set timeout [ lindex $argv $i ]
  7227. }
  7228. # VTY Password
  7229. } -v* {
  7230. if {! [ regexp .\[vV\](.+) $arg ignore passwd]} {
  7231. incr i
  7232. set passwd [ lindex $argv $i ]
  7233. }
  7234. set do_passwd 0
  7235. # Version string
  7236. } -V* {
  7237. send_user "rancid 3.4.1\n"
  7238. exit 0
  7239. # Enable Username
  7240. } -w* -
  7241. -W* {
  7242. if {! [ regexp .\[wW\](.+) $arg ignore enauser]} {
  7243. incr i
  7244. set enausername [ lindex $argv $i ]
  7245. }
  7246. # Username
  7247. } -u* {
  7248. if {! [ regexp .\[uU\](.+) $arg ignore user]} {
  7249. incr i
  7250. set username [ lindex $argv $i ]
  7251. }
  7252. # Timeout
  7253. } -t* {
  7254. if {! [regexp .\[tT\](.+) $arg ignore timeout]} {
  7255. incr i
  7256. set timeoutdflt [lindex $argv $i]
  7257. }
  7258. # Command file
  7259. } -x* {
  7260. if {! [ regexp .\[xX\](.+) $arg ignore cmd_file]} {
  7261. incr i
  7262. set cmd_file [ lindex $argv $i ]
  7263. }
  7264. if [ catch {set cmd_fd [open $cmd_file r]} reason ] {
  7265. send_user "\nError: $reason\n"
  7266. exit 1
  7267. }
  7268. set cmd_text [read $cmd_fd]
  7269. close $cmd_fd
  7270. set command [join [split $cmd_text \n] \;]
  7271. set do_command 1
  7272. # 'ssh -c' cypher type
  7273. } -y* {
  7274. if {! [ regexp .\[eE\](.+) $arg ignore cypher]} {
  7275. incr i
  7276. set cypher [ lindex $argv $i ]
  7277. }
  7278. # Do we enable?
  7279. } -noenable {
  7280. set avenable 0
  7281. # Does tacacs automatically enable us?
  7282. } -autoenable {
  7283. set avautoenable 1
  7284. set avenable 0
  7285. } -* {
  7286. send_user "\nError: Unknown argument! $arg\n"
  7287. send_user $usage
  7288. exit 1
  7289. } default {
  7290. break
  7291. }
  7292. }
  7293. }
  7294. # Process routers...no routers listed is an error.
  7295. if { $i == $argc } {
  7296. send_user "\nError: $usage"
  7297. }
  7298.  
  7299. # Only be quiet if we are running a script (it can log its output
  7300. # on its own)
  7301. if { $do_script } {
  7302. log_user 0
  7303. } else {
  7304. log_user 1
  7305. }
  7306.  
  7307. #
  7308. # Done configuration/variable setting. Now run with it...
  7309. #
  7310.  
  7311. # Sets Xterm title if interactive...if its an xterm and the user cares
  7312. proc label { host } {
  7313. global env
  7314. # if CLOGIN has an 'x' in it, don't set the xterm name/banner
  7315. if [info exists env(CLOGIN)] {
  7316. if {[string first "x" $env(CLOGIN)] != -1} { return }
  7317. }
  7318. # take host from ENV(TERM)
  7319. if [info exists env(TERM)] {
  7320. if [regexp \^(xterm|vs) $env(TERM) ignore ] {
  7321. send_user "\033]1;[lindex [split $host "."] 0]\a"
  7322. send_user "\033]2;$host\a"
  7323. }
  7324. }
  7325. }
  7326.  
  7327. # This is a helper function to make the password file easier to
  7328. # maintain. Using this the password file has the form:
  7329. # add password sl* pete cow
  7330. # add password at* steve
  7331. # add password * hanky-pie
  7332. proc add {var args} { global int_$var ; lappend int_$var $args}
  7333. proc include {args} {
  7334. global env
  7335. regsub -all "(^{|}$)" $args {} args
  7336. if { [ regexp "^/" $args ignore ] == 0 } {
  7337. set args $env(HOME)/$args
  7338. }
  7339. source_password_file $args
  7340. }
  7341.  
  7342. proc find {var router} {
  7343. upvar int_$var list
  7344. if { [info exists list] } {
  7345. foreach line $list {
  7346. if { [string match -nocase [lindex $line 0] $router ] } {
  7347. return [lrange $line 1 end]
  7348. }
  7349. }
  7350. }
  7351. return {}
  7352. }
  7353.  
  7354. # Loads the password file. Note that as this file is tcl, and that
  7355. # it is sourced, the user better know what to put in there, as it
  7356. # could install more than just password info... I will assume however,
  7357. # that a "bad guy" could just as easy put such code in the clogin
  7358. # script, so I will leave .cloginrc as just an extention of that script
  7359. proc source_password_file { password_file } {
  7360. global env
  7361. if { ! [file exists $password_file] } {
  7362. send_user "\nError: password file ($password_file) does not exist\n"
  7363. exit 1
  7364. }
  7365. file stat $password_file fileinfo
  7366. if { [expr ($fileinfo(mode) & 007)] != 0000 } {
  7367. send_user "\nError: $password_file must not be world readable/writable\n"
  7368. exit 1
  7369. }
  7370. if [ catch {source $password_file} reason ] {
  7371. send_user "\nError: $reason\n"
  7372. exit 1
  7373. }
  7374. }
  7375.  
  7376. # Log into the router.
  7377. # returns: 0 on success, 1 on failure, -1 if rsh was used successfully
  7378. proc login { router user userpswd passwd enapasswd cmethod cyphertype } {
  7379. global spawn_id in_proc do_command do_script platform
  7380. global prompt u_prompt p_prompt e_prompt sshcmd
  7381. set in_proc 1
  7382. set uprompt_seen 0
  7383.  
  7384. # try each of the connection methods in $cmethod until one is successful
  7385. set progs [llength $cmethod]
  7386. foreach prog [lrange $cmethod 0 end] {
  7387. incr progs -1
  7388. if [string match "telnet*" $prog] {
  7389. regexp {telnet(:([^[:space:]]+))*} $prog methcmd suffix port
  7390. if {"$port" == ""} {
  7391. set retval [catch {spawn telnet $router} reason]
  7392. } else {
  7393. set retval [catch {spawn telnet $router $port} reason]
  7394. }
  7395. if { $retval } {
  7396. send_user "\nError: telnet failed: $reason\n"
  7397. return 1
  7398. }
  7399. } elseif [string match "ssh*" $prog] {
  7400. # ssh to the router & try to login
  7401. regexp {ssh(:([^[:space:]]+))*} $prog methcmd suffix port
  7402. set cmd $sshcmd
  7403. if {"$port" != ""} {
  7404. set cmd "$cmd -p $port"
  7405. }
  7406. set retval [catch {eval spawn [split "$cmd -c $cyphertype -x -l $user $router" { }]} reason]
  7407. if { $retval } {
  7408. send_user "\nError: $cmd failed: $reason\n"
  7409. return 1
  7410. }
  7411. } elseif ![string compare $prog "rsh"] {
  7412. global command
  7413.  
  7414. if { ! $do_command } {
  7415. if { [llength $cmethod] == 1 } {
  7416. send_user "\nError: rsh is an invalid method for -x and "
  7417. send_user "interactive logins\n"
  7418. }
  7419. if { $progs == 0 } {
  7420. return 1
  7421. }
  7422. continue;
  7423. }
  7424.  
  7425. # handle escaped ;s in commands, and ;; and ^;
  7426. regsub -all {([^\\]);;} $command "\\1;\u002;" esccommand
  7427. regsub {^;} $esccommand "\u002;" command
  7428. set sep "\\1\u001"
  7429. regsub -all {([^\\])\;} $command "$sep" esccommand
  7430. set sep "\u001"
  7431. set commands [split $esccommand $sep]
  7432. set num_commands [llength $commands]
  7433. set rshfail 0
  7434. for {set i 0} {$i < $num_commands && !$rshfail} { incr i} {
  7435. log_user 0
  7436. set retval [ catch {spawn rsh $user@$router [lindex $commands $i] } reason ]
  7437. if { $retval } {
  7438. send_user "\nError: rsh failed: $reason\n"
  7439. log_user 1; return 1
  7440. }
  7441. send_user "$router# [lindex $commands $i]\n"
  7442.  
  7443. # rcmd does not get a pager and no prompts, so we just have to
  7444. # look for failures & lines.
  7445. expect {
  7446. "Connection refused" { catch {close}; wait;
  7447. send_user "\nError: Connection\
  7448. Refused ($prog): $router\n"
  7449. set rshfail 1
  7450. }
  7451. -re "(Connection closed by|Connection to \[^\n\r]+ closed)" {
  7452. catch {close}; wait;
  7453. send_user "\nError: Connection\
  7454. closed ($prog): $router\n"
  7455. set rshfail 1
  7456. }
  7457. "Host is unreachable" { catch {close}; wait;
  7458. send_user "\nError: Host Unreachable:\
  7459. $router\n"
  7460. set rshfail 1
  7461. }
  7462. "No address associated with" {
  7463. catch {close}; wait;
  7464. send_user "\nError: Unknown host\
  7465. $router\n"
  7466. set rshfail 1
  7467. }
  7468. -re "\b+" { exp_continue }
  7469. -re "\[\n\r]+" { send_user -- "$expect_out(buffer)"
  7470. exp_continue
  7471. }
  7472. timeout { catch {close}; wait
  7473. send_user "\nError: TIMEOUT reached\n"
  7474. set rshfail 1
  7475. }
  7476. eof { catch {close}; wait }
  7477. }
  7478. log_user 1
  7479. }
  7480. if { $rshfail } {
  7481. if { !$progs } {
  7482. return 1
  7483. } else {
  7484. continue
  7485. }
  7486. }
  7487. # fake the end of the session for rancid.
  7488. send_user "$router# logout\n"
  7489. # return rsh "success"
  7490. return -1
  7491. } else {
  7492. send_user "\nError: unknown connection method: $prog\n"
  7493. return 1
  7494. }
  7495. sleep 0.3
  7496.  
  7497. # This helps cleanup each expect clause.
  7498. expect_after {
  7499. timeout {
  7500. send_user "\nError: TIMEOUT reached\n"
  7501. catch {close}; wait
  7502. if { $in_proc} {
  7503. return 1
  7504. } else {
  7505. continue
  7506. }
  7507. } eof {
  7508. send_user "\nError: EOF received\n"
  7509. catch {close}; wait
  7510. if { $in_proc} {
  7511. return 1
  7512. } else {
  7513. continue
  7514. }
  7515. }
  7516. }
  7517.  
  7518. # Here we get a little tricky. There are several possibilities:
  7519. # the router can ask for a username and passwd and then
  7520. # talk to the TACACS server to authenticate you, or if the
  7521. # TACACS server is not working, then it will use the enable
  7522. # passwd. Or, the router might not have TACACS turned on,
  7523. # then it will just send the passwd.
  7524. # if telnet fails with connection refused, try ssh
  7525. expect {
  7526. -re "(Connection refused|Secure connection \[^\n\r]+ refused)" {
  7527. catch {close}; wait
  7528. if !$progs {
  7529. send_user "\nError: Connection Refused ($prog): $router\n"
  7530. return 1
  7531. }
  7532. }
  7533. -re "(Connection closed by|Connection to \[^\n\r]+ closed)" {
  7534. catch {close}; wait
  7535. if !$progs {
  7536. send_user "\nError: Connection closed ($prog): $router\n"
  7537. return 1
  7538. }
  7539. }
  7540. eof { send_user "\nError: Couldn't login: $router\n"; wait; return 1 }
  7541. -nocase "unknown host\r" {
  7542. catch {close};
  7543. send_user "\nError: Unknown host $router\n"; wait; return 1
  7544. }
  7545. "Host is unreachable" {
  7546. catch {close};
  7547. send_user "\nError: Host Unreachable: $router\n"; wait; return 1
  7548. }
  7549. "No address associated with name" {
  7550. catch {close};
  7551. send_user "\nError: Unknown host $router\n"; wait; return 1
  7552. }
  7553. -re "(Host key not found |The authenticity of host .* be established).*\(yes\/no\)\?" {
  7554. send "yes\r"
  7555. send_user "\nHost $router added to the list of known hosts.\n"
  7556. exp_continue }
  7557. -re "HOST IDENTIFICATION HAS CHANGED.* \(yes\/no\)\?" {
  7558. send "no\r"
  7559. send_user "\nError: The host key for $router has changed. Update the SSH known_hosts file accordingly.\n"
  7560. return 1 }
  7561. -re "Offending key for .* \(yes\/no\)\?" {
  7562. send "no\r"
  7563. send_user "\nError: host key mismatch for $router. Update the SSH known_hosts file accordingly.\n"
  7564. return 1 }
  7565. -nocase -re "^warning: remote host denied authentication agent forwarding." {
  7566. exp_continue;
  7567. }
  7568. -re "(denied|Sorry)" {
  7569. send_user "\nError: Check your passwd for $router\n"
  7570. catch {close}; wait; return 1
  7571. }
  7572. "Login failed" {
  7573. send_user "\nError: Check your passwd for $router\n"
  7574. return 1
  7575. }
  7576. -re "% (Bad passwords|Authentication failed)" {
  7577. send_user "\nError: Check your passwd for $router\n"
  7578. return 1
  7579. }
  7580. "Press any key to continue." {
  7581. # send_user "Pressing the ANY key\n"
  7582. send "\r"
  7583. exp_continue
  7584. }
  7585. -re "Enter Selection: " {
  7586. # Catalyst 1900s have some lame menu. Enter
  7587. # K to reach a command-line.
  7588. send "K\r"
  7589. exp_continue;
  7590. }
  7591. -re "@\[^\r\n]+ $p_prompt" {
  7592. # ssh pwd prompt
  7593. sleep 1
  7594. send "$userpswd\r"
  7595. exp_continue
  7596. }
  7597. -re "$u_prompt" {
  7598. send "$user\r"
  7599. set uprompt_seen 1
  7600. exp_continue
  7601. }
  7602. -re "$p_prompt" {
  7603. sleep 1
  7604. if {$uprompt_seen == 1} {
  7605. send "$userpswd\r"
  7606. } else {
  7607. send "$passwd\r"
  7608. }
  7609. exp_continue
  7610. }
  7611. -re "$prompt" { break; }
  7612. "Login invalid" {
  7613. send_user "\nError: Invalid login: $router\n";
  7614. catch {close}; wait; return 1
  7615. }
  7616. }
  7617. }
  7618.  
  7619. set in_proc 0
  7620. return 0
  7621. }
  7622.  
  7623. # Enable
  7624. proc do_enable { enauser enapasswd } {
  7625. global prompt in_proc
  7626. global u_prompt e_prompt
  7627. set in_proc 1
  7628.  
  7629. send "enable\r"
  7630. expect {
  7631. -re "$u_prompt" { send "$enauser\r"; exp_continue}
  7632. -re "$e_prompt" { send "$enapasswd\r"; exp_continue}
  7633. "#" { set prompt "#" }
  7634. "(enable)" { set prompt "> (enable) " }
  7635. -re "(denied|Sorry|Incorrect)" {
  7636. # % Access denied - from local auth and poss. others
  7637. send_user "\nError: Check your Enable passwd\n";
  7638. return 1
  7639. }
  7640. "% Error in authentication" {
  7641. send_user "\nError: Check your Enable passwd\n"
  7642. return 1
  7643. }
  7644. "% Bad passwords" {
  7645. send_user "\nError: Check your Enable passwd\n"
  7646. return 1
  7647. }
  7648. }
  7649. # We set the prompt variable (above) so script files don't need
  7650. # to know what it is.
  7651. set in_proc 0
  7652. return 0
  7653. }
  7654.  
  7655. # Run commands given on the command line.
  7656. proc run_commands { prompt command } {
  7657. global in_proc platform
  7658. set in_proc 1
  7659.  
  7660. # If the prompt is (enable), then we are on a switch and the
  7661. # command is "set length 0"; otherwise its "term length 0".
  7662. # skip if its an extreme (since the pager can not be disabled on a
  7663. # per-vty basis).
  7664. if { [ string compare "extreme" "$platform" ] } {
  7665. if [ regexp -- ".*> .*enable" "$prompt" ] {
  7666. send "set length 0\r"
  7667. # This is ugly, but reduces code duplication, allowing the
  7668. # subsequent expects to handle everything as normal.
  7669. set command "set logging session disable;$command"
  7670. } else {
  7671. send "term length 0\r"
  7672. }
  7673. # match cisco config mode prompts too, such as router(config-if)#,
  7674. # but catalyst does not change in this fashion.
  7675. regsub -all {^(.{1,11}).*([#>])$} $prompt {\1} reprompt
  7676. # escape any parens in the prompt, such as "(enable)"
  7677. regsub -all {[)(]} $reprompt {\\&} reprompt
  7678. append reprompt {([^#>\r\n]+)?[#>](\\([^)\\r\\n]+\\))?}
  7679. expect {
  7680. -re $reprompt {}
  7681. -re "\[\n\r]+" { exp_continue }
  7682. }
  7683. } else {
  7684. regsub -all "\[)(]" $prompt {\\&} reprompt
  7685. }
  7686.  
  7687. # this is the only way i see to get rid of more prompts in o/p..grrrrr
  7688. log_user 0
  7689.  
  7690. # handle escaped ;s in commands, and ;; and ^;
  7691. regsub -all {([^\\]);;} $command "\\1;\u002;" esccommand
  7692. regsub {^;} $esccommand "\u002;" command
  7693. set sep "\\1\u001"
  7694. regsub -all {([^\\])\;} $command "$sep" esccommand
  7695. set sep "\u001"
  7696. set commands [split $esccommand $sep]
  7697. set num_commands [llength $commands]
  7698. # the pager can not be turned off on the PIX, so we have to look
  7699. # for the "More" prompt. the extreme is equally obnoxious, with a
  7700. # global switch in the config.
  7701. for {set i 0} {$i < $num_commands} { incr i} {
  7702. send "[subst -nocommands [lindex $commands $i]]\r"
  7703. expect {
  7704. -re "\b+" { exp_continue }
  7705. -re "^\[^\n\r *]*$reprompt" { send_user -- "$expect_out(buffer)"
  7706. }
  7707. -re "^\[^\n\r]*$reprompt." { send_user -- "$expect_out(buffer)"
  7708. exp_continue }
  7709. -re "^--More--\r\n" { # specific match c1900 pager
  7710. send " "
  7711. exp_continue }
  7712. -re "\[\n\r]+" { send_user -- "$expect_out(buffer)"
  7713. exp_continue }
  7714. -re "\[^\r\n]*Press <SPACE> to cont\[^\r\n]*" {
  7715. send " "
  7716. # bloody ^[[2K after " "
  7717. expect {
  7718. -re "^\[^\r\n]*\r" {}
  7719. }
  7720. exp_continue
  7721. }
  7722. -re "^Press Enter to continue\.\.\.\[^\n\r]*" {
  7723. send "\r"
  7724. exp_continue }
  7725. -re "^Press Enter to continue or \[^\n\r]* abort" {
  7726. send "\r"
  7727. exp_continue }
  7728. -re "^--More or \[^\n\r]* abort" {
  7729. send " "
  7730. exp_continue }
  7731. -re "^ *--More--\[^\n\r]*" {
  7732. send " "
  7733. exp_continue }
  7734. -re "^<-+ More -+>\[^\n\r]*" {
  7735. send_user -- "$expect_out(buffer)"
  7736. send " "
  7737. exp_continue }
  7738. }
  7739. }
  7740. log_user 1
  7741.  
  7742. # Send an Unconditional CTRL Z to exit out of any context the WLC prompt
  7743. # may be in
  7744. send "\032"
  7745.  
  7746. expect {
  7747. -re "(.+)>" { # the Cisco CE and Jnx ERX
  7748. # return to non-enabled mode
  7749. # on exit in enabled mode.
  7750. send "logout\r"
  7751. exp_continue;
  7752. }
  7753. -re "Would you like to save them .+" {
  7754. send "n\r"
  7755. exp_continue
  7756. }
  7757. -re "\[\n\r]+" { exp_continue }
  7758. timeout { return 0 }
  7759. eof { return 0 }
  7760. }
  7761. set in_proc 0
  7762. }
  7763.  
  7764. #
  7765. # For each router... (this is main loop)
  7766. #
  7767. source_password_file $password_file
  7768. set in_proc 0
  7769. foreach router [lrange $argv $i end] {
  7770. set router [string tolower $router]
  7771. # attempt at platform switching.
  7772. set platform ""
  7773. send_user -- "$router\n"
  7774.  
  7775. # device timeout
  7776. set timeout [find timeout $router]
  7777. if { [llength $timeout] == 0 } {
  7778. set timeout $timeoutdflt
  7779. }
  7780.  
  7781. # Figure out the prompt.
  7782. # autoenable is off by default. If we have it defined, it was done
  7783. # on the command line. If it is not specifically set on the command
  7784. # line, check the password file.
  7785. if $avautoenable {
  7786. set autoenable 1
  7787. set enable 0
  7788. set prompt "(#| \\(enable\\))"
  7789. } else {
  7790. set ae [find autoenable $router]
  7791. if { "$ae" == "1" } {
  7792. set autoenable 1
  7793. set enable 0
  7794. set prompt "(#| \\(enable\\)|>)"
  7795. } else {
  7796. set autoenable 0
  7797. set enable $avenable
  7798. set prompt ">"
  7799. }
  7800. }
  7801.  
  7802. # look for noenable option in .cloginrc
  7803. if { [find noenable $router] != "" } {
  7804. set enable 0
  7805. }
  7806.  
  7807. # Figure out passwords
  7808. if { $do_passwd || $do_enapasswd } {
  7809. set pswd [find password $router]
  7810. if { [llength $pswd] == 0 } {
  7811. send_user -- "\nError: no password for $router in $password_file.\n"
  7812. continue
  7813. }
  7814. if { $enable && $do_enapasswd && $autoenable == 0 && [llength $pswd] < 2 } {
  7815. send_user -- "\nError: no enable password for $router in $password_file.\n"
  7816. continue
  7817. }
  7818. set passwd [join [lindex $pswd 0] ""]
  7819. set enapasswd [join [lindex $pswd 1] ""]
  7820. }
  7821.  
  7822. # Figure out username
  7823. if {[info exists username]} {
  7824. # command line username
  7825. set ruser $username
  7826. } else {
  7827. set ruser [join [find user $router] ""]
  7828. if { "$ruser" == "" } { set ruser $default_user }
  7829. }
  7830.  
  7831. # Figure out username's password (if different from the vty password)
  7832. if {[info exists userpasswd]} {
  7833. # command line username
  7834. set userpswd $userpasswd
  7835. } else {
  7836. set userpswd [join [find userpassword $router] ""]
  7837. if { "$userpswd" == "" } { set userpswd $passwd }
  7838. }
  7839.  
  7840. # Figure out enable username
  7841. if {[info exists enausername]} {
  7842. # command line enausername
  7843. set enauser $enausername
  7844. } else {
  7845. set enauser [join [find enauser $router] ""]
  7846. if { "$enauser" == "" } { set enauser $ruser }
  7847. }
  7848.  
  7849. # Figure out prompts
  7850. set u_prompt [find userprompt $router]
  7851. if { "$u_prompt" == "" } {
  7852. set u_prompt "(Username|Login|login|user name|User):"
  7853. } else {
  7854. set u_prompt [join [lindex $u_prompt 0] ""]
  7855. }
  7856. set p_prompt [find passprompt $router]
  7857. if { "$p_prompt" == "" } {
  7858. set p_prompt "(\[Pp]assword|passwd):"
  7859. } else {
  7860. set p_prompt [join [lindex $p_prompt 0] ""]
  7861. }
  7862. set e_prompt [find enableprompt $router]
  7863. if { "$e_prompt" == "" } {
  7864. set e_prompt "\[Pp]assword:"
  7865. } else {
  7866. set e_prompt [join [lindex $e_prompt 0] ""]
  7867. }
  7868.  
  7869. # Figure out cypher type
  7870. if {[info exists cypher]} {
  7871. # command line cypher type
  7872. set cyphertype $cypher
  7873. } else {
  7874. set cyphertype [find cyphertype $router]
  7875. if { "$cyphertype" == "" } { set cyphertype "3des" }
  7876. }
  7877.  
  7878. # Figure out connection method
  7879. set cmethod [find method $router]
  7880. if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} }
  7881.  
  7882. # Figure out the SSH executable name
  7883. set sshcmd [join [lindex [find sshcmd $router] 0] ""]
  7884. if { "$sshcmd" == "" } { set sshcmd {ssh} }
  7885.  
  7886. # Login to the router
  7887. if {[login $router $ruser $userpswd $passwd $enapasswd $cmethod $cyphertype]} {
  7888. # if login failed or rsh was successful, move on to the next device
  7889. continue
  7890. }
  7891. if { $enable } {
  7892. if {[do_enable $enauser $enapasswd]} {
  7893. if { $do_command || $do_script } {
  7894. close; wait
  7895. continue
  7896. }
  7897. }
  7898. }
  7899. # we are logged in, now figure out the full prompt
  7900. send "\r"
  7901. expect {
  7902. -re "\[\r\n]+" { exp_continue; }
  7903. -re "^(.+\[:.])1 $prompt" { # stoopid extreme cmd-line numbers and
  7904. # prompt based on state of config changes,
  7905. # which may have an * at the beginning.
  7906. set junk $expect_out(1,string)
  7907. regsub -all "^\\\* " $expect_out(1,string) {} junk
  7908. set prompt ".? ?$junk\[0-9]+ $expect_out(2,string)";
  7909. set platform "extreme"
  7910. }
  7911. -re "^.+$prompt" { set junk $expect_out(0,string);
  7912. regsub -all "\[\]\[]" $junk {\\&} prompt;
  7913. }
  7914. -re "^.+> \\\(enable\\\)" {
  7915. set junk $expect_out(0,string);
  7916. regsub -all "\[\]\[]" $junk {\\&} prompt;
  7917. }
  7918. -re "\(Cisco Controller\) \>" {
  7919. set junk $expect_out(0,string);
  7920. regsub -all "\[\]\[]" $junk {\\&} prompt;
  7921. }
  7922.  
  7923. }
  7924.  
  7925. if { $do_command } {
  7926. if {[run_commands $prompt $command]} {
  7927. continue
  7928. }
  7929. } elseif { $do_script } {
  7930. # If the prompt is (enable), then we are on a switch and the
  7931. # command is "set length 0"; otherwise its "term length 0".
  7932. if [ regexp -- ".*> .*enable" "$prompt" ] {
  7933. send "set length 0\r"
  7934. send "set logging session disable\r"
  7935. } else {
  7936. send "term length 0\r"
  7937. }
  7938. expect -re $prompt {}
  7939. source $sfile
  7940. close
  7941. } else {
  7942. label $router
  7943. log_user 1
  7944. interact
  7945. }
  7946.  
  7947. # End of for each router
  7948. wait
  7949. sleep 0.3
  7950. }
  7951. exit 0
  7952.  
  7953. #! /usr/bin/expect --
  7954. ##
  7955. ## $Id: xilogin.in 2255 2010-10-06 20:31:24Z heas $
  7956. ##
  7957. ## rancid 3.4.1
  7958. ## Copyright (c) 1997-2016 by Terrapin Communications, Inc.
  7959. ## All rights reserved.
  7960. ##
  7961. ## This code is derived from software contributed to and maintained by
  7962. ## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan,
  7963. ## Pete Whiting, Austin Schutz, and Andrew Fort.
  7964. ##
  7965. ## Redistribution and use in source and binary forms, with or without
  7966. ## modification, are permitted provided that the following conditions
  7967. ## are met:
  7968. ## 1. Redistributions of source code must retain the above copyright
  7969. ## notice, this list of conditions and the following disclaimer.
  7970. ## 2. Redistributions in binary form must reproduce the above copyright
  7971. ## notice, this list of conditions and the following disclaimer in the
  7972. ## documentation and/or other materials provided with the distribution.
  7973. ## 3. All advertising materials mentioning features or use of this software
  7974. ## must display the following acknowledgement:
  7975. ## This product includes software developed by Terrapin Communications,
  7976. ## Inc. and its contributors for RANCID.
  7977. ## 4. Neither the name of Terrapin Communications, Inc. nor the names of its
  7978. ## contributors may be used to endorse or promote products derived from
  7979. ## this software without specific prior written permission.
  7980. ## 5. It is requested that non-binding fixes and modifications be contributed
  7981. ## back to Terrapin Communications, Inc.
  7982. ##
  7983. ## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS
  7984. ## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  7985. ## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  7986. ## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
  7987. ## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  7988. ## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  7989. ## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  7990. ## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  7991. ## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  7992. ## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  7993. ## POSSIBILITY OF SUCH DAMAGE.
  7994. ##
  7995. ## It is the request of the authors, but not a condition of license, that
  7996. ## parties packaging or redistributing RANCID NOT distribute altered versions
  7997. ## of the etc/rancid.types.base file nor alter how this file is processed nor
  7998. ## when in relation to etc/rancid.types.conf. The goal of this is to help
  7999. ## suppress our support costs. If it becomes a problem, this could become a
  8000. ## condition of license.
  8001. #
  8002. # The expect login scripts were based on Erik Sherk's gwtn, by permission.
  8003. #
  8004. # The original looking glass software was written by Ed Kern, provided by
  8005. # permission and modified beyond recognition.
  8006. #
  8007. # xilogin - Xirrus login
  8008. #
  8009. # Most options are intuitive for logging into a Xirrus array.
  8010. # The default is to not enable.
  8011. #
  8012.  
  8013. # Usage line
  8014. set usage "Usage: $argv0 \[-dSV\] \[-autoenable\] \[-noenable\] \[-c command\] \
  8015. \[-Evar=x\] \[-e enable-password\] \[-f cloginrc-file\] \[-p user-password\] \
  8016. \[-r passphrase\] \[-s script-file\] \[-t timeout\] \[-u username\] \
  8017. \[-v vty-password\] \[-w enable-username\] \[-x command-file\] \
  8018. \[-y ssh_cypher_type\] router \[router...\]\n"
  8019.  
  8020. # env(CLOGIN) may contain:
  8021. # x == do not set xterm banner or name
  8022.  
  8023. # Password file
  8024. set password_file $env(HOME)/.cloginrc
  8025. # Default is to login to the router
  8026. set do_command 0
  8027. set do_script 0
  8028. # The default is to automatically enable
  8029. set avenable 1
  8030. # The default is that you login non-enabled (tacacs can have you login already
  8031. # enabled)
  8032. set avautoenable 0
  8033. # The default is to look in the password file to find the passwords. This
  8034. # tracks if we receive them on the command line.
  8035. set do_passwd 1
  8036. set do_enapasswd 1
  8037. # Save config, if prompted
  8038. set do_saveconfig 0
  8039. # Sometimes routers take awhile to answer (the default is 10 sec)
  8040. set timeoutdflt 45
  8041. # Some CLIs having problems if we write too fast (Extreme, PIX, Cat)
  8042. set send_human {.2 .1 .4 .2 1}
  8043.  
  8044. # Find the user in the ENV, or use the unix userid.
  8045. if {[info exists env(CISCO_USER)]} {
  8046. set default_user $env(CISCO_USER)
  8047. } elseif {[info exists env(USER)]} {
  8048. set default_user $env(USER)
  8049. } elseif {[info exists env(LOGNAME)]} {
  8050. set default_user $env(LOGNAME)
  8051. } else {
  8052. # This uses "id" which I think is portable. At least it has existed
  8053. # (without options) on all machines/OSes I've been on recently -
  8054. # unlike whoami or id -nu.
  8055. if [catch {exec id} reason] {
  8056. send_error "\nError: could not exec id: $reason\n"
  8057. exit 1
  8058. }
  8059. regexp {\(([^)]*)} "$reason" junk default_user
  8060. }
  8061. if {[info exists env(CLOGINRC)]} {
  8062. set password_file $env(CLOGINRC)
  8063. }
  8064.  
  8065. # Process the command line
  8066. for {set i 0} {$i < $argc} {incr i} {
  8067. set arg [lindex $argv $i]
  8068.  
  8069. switch -glob -- $arg {
  8070. # Expect debug mode
  8071. -d* {
  8072. exp_internal 1
  8073. # Username
  8074. } -u* {
  8075. if {! [regexp .\[uU\](.+) $arg ignore user]} {
  8076. incr i
  8077. set username [lindex $argv $i]
  8078. }
  8079. # VTY Password
  8080. } -p* {
  8081. if {! [regexp .\[pP\](.+) $arg ignore userpasswd]} {
  8082. incr i
  8083. set userpasswd [lindex $argv $i]
  8084. }
  8085. set do_passwd 0
  8086. # ssh passphrase
  8087. } -r* {
  8088. if {! [regexp .\[rR\](.+) $arg ignore passphrase]} {
  8089. incr i
  8090. set vapassphrase [lindex $argv $i]
  8091. }
  8092. # VTY Password
  8093. } -v* {
  8094. if {! [regexp .\[vV\](.+) $arg ignore passwd]} {
  8095. incr i
  8096. set passwd [lindex $argv $i]
  8097. }
  8098. set do_passwd 0
  8099. # Version string
  8100. } -V* {
  8101. send_user "rancid 3.4.1\n";
  8102. exit 0
  8103. # Enable Username
  8104. } -w* {
  8105. if {! [regexp .\[wW\](.+) $arg ignore enauser]} {
  8106. incr i
  8107. set enausername [lindex $argv $i]
  8108. }
  8109. # Environment variable to pass to -s scripts
  8110. } -E* {
  8111. if {[regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} {
  8112. set E$varname $varvalue
  8113. } else {
  8114. send_user "\nError: invalid format for -E in $arg\n"
  8115. exit 1
  8116. }
  8117. # Enable Password
  8118. } -e* {
  8119. if {! [regexp .\[e\](.+) $arg ignore enapasswd]} {
  8120. incr i
  8121. set enapasswd [lindex $argv $i]
  8122. }
  8123. set do_enapasswd 0
  8124. # Command to run.
  8125. } -c* {
  8126. if {! [regexp .\[cC\](.+) $arg ignore command]} {
  8127. incr i
  8128. set command [lindex $argv $i]
  8129. }
  8130. set do_command 1
  8131. # Expect script to run.
  8132. } -s* {
  8133. if {! [regexp .\[sS\](.+) $arg ignore sfile]} {
  8134. incr i
  8135. set sfile [lindex $argv $i]
  8136. }
  8137. if { ! [file readable $sfile] } {
  8138. send_user "\nError: Can't read $sfile\n"
  8139. exit 1
  8140. }
  8141. set do_script 1
  8142. # save config on exit
  8143. } -S* {
  8144. set do_saveconfig 1
  8145. # 'ssh -c' cypher type
  8146. } -y* {
  8147. if {! [regexp .\[eE\](.+) $arg ignore cypher]} {
  8148. incr i
  8149. set cypher [lindex $argv $i]
  8150. }
  8151. # alternate cloginrc file
  8152. } -f* {
  8153. if {! [regexp .\[fF\](.+) $arg ignore password_file]} {
  8154. incr i
  8155. set password_file [lindex $argv $i]
  8156. }
  8157. # Timeout
  8158. } -t* {
  8159. if {! [regexp .\[tT\](.+) $arg ignore timeout]} {
  8160. incr i
  8161. set timeoutdflt [lindex $argv $i]
  8162. }
  8163. # Command file
  8164. } -x* {
  8165. if {! [regexp .\[xX\](.+) $arg ignore cmd_file]} {
  8166. incr i
  8167. set cmd_file [lindex $argv $i]
  8168. }
  8169. if [catch {set cmd_fd [open $cmd_file r]} reason] {
  8170. send_user "\nError: $reason\n"
  8171. exit 1
  8172. }
  8173. set cmd_text [read $cmd_fd]
  8174. close $cmd_fd
  8175. set command [join [split $cmd_text \n] \;]
  8176. set do_command 1
  8177. # Do we enable?
  8178. } -noenable {
  8179. set avenable 0
  8180. # Does tacacs automatically enable us?
  8181. } -autoenable {
  8182. set avautoenable 1
  8183. set avenable 0
  8184. } -* {
  8185. send_user "\nError: Unknown argument! $arg\n"
  8186. send_user $usage
  8187. exit 1
  8188. } default {
  8189. break
  8190. }
  8191. }
  8192. }
  8193. # Process routers...no routers listed is an error.
  8194. if { $i == $argc } {
  8195. send_user "\nError: $usage"
  8196. }
  8197.  
  8198. # Only be quiet if we are running a script (it can log its output
  8199. # on its own)
  8200. if { $do_script } {
  8201. log_user 0
  8202. } else {
  8203. log_user 1
  8204. }
  8205.  
  8206. #
  8207. # Done configuration/variable setting. Now run with it...
  8208. #
  8209.  
  8210. # Sets Xterm title if interactive...if its an xterm and the user cares
  8211. proc label { host } {
  8212. global env
  8213. # if CLOGIN has an 'x' in it, don't set the xterm name/banner
  8214. if [info exists env(CLOGIN)] {
  8215. if {[string first "x" $env(CLOGIN)] != -1} { return }
  8216. }
  8217. # take host from ENV(TERM)
  8218. if [info exists env(TERM)] {
  8219. if [regexp \^(xterm|vs) $env(TERM) ignore] {
  8220. send_user "\033]1;[lindex [split $host "."] 0]\a"
  8221. send_user "\033]2;$host\a"
  8222. }
  8223. }
  8224. }
  8225.  
  8226. # This is a helper function to make the password file easier to
  8227. # maintain. Using this the password file has the form:
  8228. # add password sl* pete cow
  8229. # add password at* steve
  8230. # add password * hanky-pie
  8231. proc add {var args} { global int_$var ; lappend int_$var $args}
  8232. proc include {args} {
  8233. global env
  8234. regsub -all "(^{|}$)" $args {} args
  8235. if { [regexp "^/" $args ignore] == 0 } {
  8236. set args $env(HOME)/$args
  8237. }
  8238. source_password_file $args
  8239. }
  8240.  
  8241. proc find {var router} {
  8242. upvar int_$var list
  8243. if { [info exists list] } {
  8244. foreach line $list {
  8245. if { [string match -nocase [lindex $line 0] $router] } {
  8246. return [lrange $line 1 end]
  8247. }
  8248. }
  8249. }
  8250. return {}
  8251. }
  8252.  
  8253. # Loads the password file. Note that as this file is tcl, and that
  8254. # it is sourced, the user better know what to put in there, as it
  8255. # could install more than just password info... I will assume however,
  8256. # that a "bad guy" could just as easy put such code in the xilogin
  8257. # script, so I will leave .cloginrc as just an extention of that script
  8258. proc source_password_file { password_file } {
  8259. global env
  8260. if { ! [file exists $password_file] } {
  8261. send_user "\nError: password file ($password_file) does not exist\n"
  8262. exit 1
  8263. }
  8264. file stat $password_file fileinfo
  8265. if { [expr ($fileinfo(mode) & 007)] != 0000 } {
  8266. send_user "\nError: $password_file must not be world readable/writable\n"
  8267. exit 1
  8268. }
  8269. if [catch {source $password_file} reason] {
  8270. send_user "\nError: $reason\n"
  8271. exit 1
  8272. }
  8273. }
  8274.  
  8275. # Log into the router.
  8276. # returns: 0 on success, 1 on failure, -1 if rsh was used successfully
  8277. proc login { router user userpswd passwd enapasswd cmethod cyphertype identfile } {
  8278. global command spawn_id in_proc do_command do_script passphrase
  8279. global prompt u_prompt p_prompt sshcmd
  8280. set in_proc 1
  8281. set uprompt_seen 0
  8282.  
  8283. # try each of the connection methods in $cmethod until one is successful
  8284. set progs [llength $cmethod]
  8285. foreach prog [lrange $cmethod 0 end] {
  8286. incr progs -1
  8287. if [string match "telnet*" $prog] {
  8288. regexp {telnet(:([^[:space:]]+))*} $prog methcmd suffix port
  8289. if {"$port" == ""} {
  8290. set retval [catch {spawn telnet $router} reason]
  8291. } else {
  8292. set retval [catch {spawn telnet $router $port} reason]
  8293. }
  8294. if { $retval } {
  8295. send_user "\nError: telnet failed: $reason\n"
  8296. return 1
  8297. }
  8298. } elseif [string match "ssh*" $prog] {
  8299. # ssh to the router & try to login with or without an identfile.
  8300. regexp {ssh(:([^[:space:]]+))*} $prog methcmd suffix port
  8301. set cmd $sshcmd
  8302. if {"$port" != ""} {
  8303. set cmd "$cmd -p $port"
  8304. }
  8305. if {"$identfile" != ""} {
  8306. set cmd "$cmd -i $identfile"
  8307. }
  8308. set retval [catch {eval spawn [split "$cmd -c $cyphertype -x -l $user $router" { }]} reason]
  8309. if { $retval } {
  8310. send_user "\nError: $cmd failed: $reason\n"
  8311. return 1
  8312. }
  8313. } elseif ![string compare $prog "rsh"] {
  8314. if { ! $do_command } {
  8315. if { [llength $cmethod] == 1 } {
  8316. send_user "\nError: rsh is an invalid method for -x and "
  8317. send_user "interactive logins\n"
  8318. }
  8319. if { $progs == 0 } {
  8320. return 1
  8321. }
  8322. continue;
  8323. }
  8324.  
  8325. # handle escaped ;s in commands, and ;; and ^;
  8326. regsub -all {([^\\]);;} $command "\\1;\u002;" esccommand
  8327. regsub {^;} $esccommand "\u002;" command
  8328. set sep "\\1\u001"
  8329. regsub -all {([^\\])\;} $command "$sep" esccommand
  8330. set sep "\u001"
  8331. set commands [split $esccommand $sep]
  8332. set num_commands [llength $commands]
  8333. set rshfail 0
  8334. for {set i 0} {$i < $num_commands && !$rshfail} { incr i} {
  8335. log_user 0
  8336. set retval [catch {spawn rsh $user@$router [lindex $commands $i] } reason]
  8337. if { $retval } {
  8338. send_user "\nError: rsh failed: $reason\n"
  8339. log_user 1; return 1
  8340. }
  8341. send_user "$router# [lindex $commands $i]\n"
  8342.  
  8343. # rcmd does not get a pager and no prompts, so we just have to
  8344. # look for failures & lines.
  8345. expect {
  8346. "Connection refused" { catch {close}; catch {wait};
  8347. send_user "\nError: Connection\
  8348. Refused ($prog): $router\n"
  8349. set rshfail 1
  8350. }
  8351. -re "(Connection closed by|Connection to \[^\n\r]+ closed)" {
  8352. catch {close}; catch {wait};
  8353. send_user "\nError: Connection\
  8354. closed ($prog): $router\n"
  8355. set rshfail 1
  8356. }
  8357. "Host is unreachable" { catch {close}; catch {wait};
  8358. send_user "\nError: Host Unreachable:\
  8359. $router\n"
  8360. set rshfail 1
  8361. }
  8362. "No address associated with" {
  8363. catch {close}; catch {wait};
  8364. send_user "\nError: Unknown host\
  8365. $router\n"
  8366. set rshfail 1
  8367. }
  8368. -re "\b+" { exp_continue }
  8369. -re "\[\n\r]+" { send_user -- "$expect_out(buffer)"
  8370. exp_continue
  8371. }
  8372. timeout { catch {close}; catch {wait};
  8373. send_user "\nError: TIMEOUT reached\n"
  8374. set rshfail 1
  8375. }
  8376. eof { catch {close}; catch {wait}; }
  8377. }
  8378. log_user 1
  8379. }
  8380. if { $rshfail } {
  8381. if { !$progs } {
  8382. return 1
  8383. } else {
  8384. continue
  8385. }
  8386. }
  8387. # fake the end of the session for rancid.
  8388. send_user "$router# exit\n"
  8389. # return rsh "success"
  8390. return -1
  8391. } else {
  8392. send_user "\nError: unknown connection method: $prog\n"
  8393. return 1
  8394. }
  8395. sleep 0.3
  8396.  
  8397. # This helps cleanup each expect clause.
  8398. expect_after {
  8399. timeout {
  8400. send_user "\nError: TIMEOUT reached\n"
  8401. catch {close}; catch {wait};
  8402. if { $in_proc} {
  8403. return 1
  8404. } else {
  8405. continue
  8406. }
  8407. } eof {
  8408. send_user "\nError: EOF received\n"
  8409. catch {close}; catch {wait};
  8410. if { $in_proc} {
  8411. return 1
  8412. } else {
  8413. continue
  8414. }
  8415. }
  8416. }
  8417.  
  8418. # Here we get a little tricky. There are several possibilities:
  8419. # the router can ask for a username and passwd and then
  8420. # talk to the TACACS server to authenticate you, or if the
  8421. # TACACS server is not working, then it will use the enable
  8422. # passwd. Or, the router might not have TACACS turned on,
  8423. # then it will just send the passwd.
  8424. # if telnet fails with connection refused, try ssh
  8425. expect {
  8426. -re "(Connection refused|Secure connection \[^\n\r]+ refused)" {
  8427. catch {close}; catch {wait};
  8428. if !$progs {
  8429. send_user "\nError: Connection Refused ($prog): $router\n"
  8430. return 1
  8431. }
  8432. }
  8433. -re "(Connection closed by|Connection to \[^\n\r]+ closed)" {
  8434. catch {close}; catch {wait};
  8435. if !$progs {
  8436. send_user "\nError: Connection closed ($prog): $router\n"
  8437. return 1
  8438. }
  8439. }
  8440. eof { send_user "\nError: Couldn't login: $router\n"; wait; return 1 }
  8441. -nocase "unknown host\r" {
  8442. send_user "\nError: Unknown host $router\n";
  8443. catch {close}; catch {wait};
  8444. return 1
  8445. }
  8446. "Host is unreachable" {
  8447. send_user "\nError: Host Unreachable: $router\n";
  8448. catch {close}; catch {wait};
  8449. return 1
  8450. }
  8451. "No address associated with name" {
  8452. send_user "\nError: Unknown host $router\n";
  8453. catch {close}; catch {wait};
  8454. return 1
  8455. }
  8456. -re "(Host key not found |The authenticity of host .* be established).* \\(yes/no\\)\\?" {
  8457. send "yes\r"
  8458. send_user "\nHost $router added to the list of known hosts.\n"
  8459. exp_continue
  8460. }
  8461. -re "HOST IDENTIFICATION HAS CHANGED.* \\(yes/no\\)\\?" {
  8462. send "no\r"
  8463. send_user "\nError: The host key for $router has changed. Update the SSH known_hosts file accordingly.\n"
  8464. catch {close}; catch {wait};
  8465. return 1
  8466. }
  8467. -re "HOST IDENTIFICATION HAS CHANGED\[^\n\r]+" {
  8468. send_user "\nError: The host key for $router has changed. Update the SSH known_hosts file accordingly.\n"
  8469. return 1
  8470. }
  8471. -re "Offending key for .* \\(yes/no\\)\\?" {
  8472. send "no\r"
  8473. send_user "\nError: host key mismatch for $router. Update the SSH known_hosts file accordingly.\n"
  8474. catch {close}; catch {wait};
  8475. return 1
  8476. }
  8477. -nocase -re "^warning: remote host denied authentication agent forwarding." {
  8478. exp_continue;
  8479. }
  8480. -nocase -re "^warning:" { exp_continue }
  8481. -re "(denied|Sorry)" {
  8482. send_user "\nError: Check your passwd for $router\n"
  8483. catch {close}; catch {wait}; return 1
  8484. }
  8485. "Login failed" {
  8486. send_user "\nError: Check your passwd for $router\n"
  8487. catch {close}; catch {wait}; return 1
  8488. }
  8489. -re "% (Bad passwords|Authentication failed)" {
  8490. send_user "\nError: Check your passwd for $router\n"
  8491. catch {close}; catch {wait}; return 1
  8492. }
  8493. "Press any key to continue" {
  8494. # send_user "Pressing the ANY key\n"
  8495. send "\r"
  8496. exp_continue
  8497. }
  8498. -re "Enter Selection: " {
  8499. # Catalyst 1900s have some lame menu. Enter
  8500. # K to reach a command-line.
  8501. send "K\r"
  8502. exp_continue
  8503. }
  8504. -re "Last login:" {
  8505. exp_continue
  8506. }
  8507. -re "@\[^\r\n]+ $p_prompt" {
  8508. # ssh pwd prompt
  8509. sleep 1
  8510. send -- "$userpswd\r"
  8511. exp_continue
  8512. }
  8513. -re "Enter passphrase.*: " {
  8514. # sleep briefly to allow time for stty -echo
  8515. sleep .3
  8516. send -- "$passphrase\r"
  8517. exp_continue
  8518. }
  8519. -re "$u_prompt" {
  8520. send -- "$user\r"
  8521. set uprompt_seen 1
  8522. exp_continue
  8523. }
  8524. -re "$p_prompt" {
  8525. sleep 1
  8526. if {$uprompt_seen == 1} {
  8527. send -- "$userpswd\r"
  8528. } else {
  8529. send -- "$passwd\r"
  8530. }
  8531. exp_continue
  8532. }
  8533. -re "$prompt" { break; }
  8534. "Login invalid" {
  8535. send_user "\nError: Invalid login: $router\n";
  8536. catch {close}; catch {wait}; return 1
  8537. }
  8538. }
  8539. }
  8540.  
  8541. set in_proc 0
  8542. return 0
  8543. }
  8544.  
  8545. # New subroutine to provide "login" command capabilities, using the enable user and enable password
  8546. # Login
  8547. proc do_login { enauser enapasswd } {
  8548. global prompt in_proc
  8549. global u_prompt
  8550. set in_proc 1
  8551.  
  8552. send "login\r"
  8553. expect {
  8554. -re "$u_prompt" { send "$enauser\r"; exp_continue}
  8555. "#" { set prompt "#" }
  8556. "(login)" { set prompt "> (login) " }
  8557. -re "(denied|Sorry|Incorrect)" {
  8558. # % Access denied - from local auth and poss. others
  8559. send_user "\nError: Check your Login passwd\n";
  8560. return 1
  8561. }
  8562. "% Error in authentication" {
  8563. send_user "\nError: Check your Login passwd\n"
  8564. return 1
  8565. }
  8566. "% Bad passwords" {
  8567. send_user "\nError: Check your Login passwd\n"
  8568. return 1
  8569. }
  8570. }
  8571. # We set the prompt variable (above) so script files don't need
  8572. # to know what it is.
  8573. set in_proc 0
  8574. return 0
  8575. }
  8576.  
  8577. # Run commands given on the command line.
  8578. proc run_commands { prompt command } {
  8579. global do_saveconfig in_proc
  8580. set in_proc 1
  8581.  
  8582. # Disable paging
  8583. send "more off \r"
  8584. # escape any parens in the prompt, such as "(enable)"
  8585. regsub -all {[)(]} $prompt {\\&} reprompt
  8586. expect {
  8587. -re $reprompt {}
  8588. -re "\[\n\r]+" { exp_continue }
  8589. }
  8590.  
  8591. # Disable command auto-completion
  8592. send "auto-complete off \r"
  8593. expect {
  8594. -re $reprompt {}
  8595. -re "\[\n\r]+" { exp_continue }
  8596. }
  8597.  
  8598. # this is the only way i see to get rid of more prompts in o/p..grrrrr
  8599. log_user 0
  8600.  
  8601. # handle escaped ;s in commands, and ;; and ^;
  8602. regsub -all {([^\\]);;} $command "\\1;\u002;" esccommand
  8603. regsub {^;} $esccommand "\u002;" command
  8604. set sep "\\1\u001"
  8605. regsub -all {([^\\])\;} $command "$sep" esccommand
  8606. set sep "\u001"
  8607. set commands [split $esccommand $sep]
  8608. set num_commands [llength $commands]
  8609. # the pager can not be turned off on the PIX, so we have to look
  8610. # for the "More" prompt. the extreme is equally obnoxious, with a
  8611. # global switch in the config.
  8612. for {set i 0} {$i < $num_commands} { incr i} {
  8613. send -- "[subst -nocommands [lindex $commands $i]]\r"
  8614. expect {
  8615. -re "\b+" { exp_continue }
  8616. -re "^\[^\n\r *]*$reprompt" { send_user -- "$expect_out(buffer)"
  8617. }
  8618. -re "^\[^\n\r]*$reprompt." { send_user -- "$expect_out(buffer)"
  8619. exp_continue
  8620. }
  8621. -re "^--MORE--\[\r\n]+" { # match Xirrus pager
  8622. send " "
  8623. exp_continue
  8624. }
  8625. -re "\[\n\r]+" { send_user -- "$expect_out(buffer)"
  8626. exp_continue
  8627. }
  8628. }
  8629. }
  8630. log_user 1
  8631.  
  8632. send -h "quit\r"
  8633. expect {
  8634. "Do you want to save changes to flash" { # Xirrus
  8635. if {$do_saveconfig} {
  8636. catch {send "y\r"}
  8637. } else {
  8638. catch {send "n\r"}
  8639. }
  8640. exp_continue
  8641. }
  8642. -re "\[\n\r]+" { exp_continue }
  8643. timeout { catch {close}; catch {wait};
  8644. return 0
  8645. }
  8646. eof { return 0 }
  8647. }
  8648. set in_proc 0
  8649. }
  8650.  
  8651. #
  8652. # For each router... (this is main loop)
  8653. #
  8654. source_password_file $password_file
  8655. set in_proc 0
  8656. set exitval 0
  8657. foreach router [lrange $argv $i end] {
  8658. set router [string tolower $router]
  8659. send_user -- "$router\n"
  8660.  
  8661. # device timeout
  8662. set timeout [find timeout $router]
  8663. if { [llength $timeout] == 0 } {
  8664. set timeout $timeoutdflt
  8665. }
  8666.  
  8667. # Default prompt.
  8668. set prompt "(>|#)"
  8669.  
  8670. # Figure out passwords
  8671. if { $do_passwd || $do_enapasswd } {
  8672. set pswd [find password $router]
  8673. if { [llength $pswd] == 0 } {
  8674. send_user -- "\nError: no password for $router in $password_file.\n"
  8675. continue
  8676. }
  8677. set passwd [join [lindex $pswd 0] ""]
  8678. set enapasswd [join [lindex $pswd 1] ""]
  8679. } else {
  8680. set passwd $userpasswd
  8681. set enapasswd $enapasswd
  8682. }
  8683.  
  8684. # Figure out username
  8685. if {[info exists username]} {
  8686. # command line username
  8687. set ruser $username
  8688. } else {
  8689. set ruser [join [find user $router] ""]
  8690. if { "$ruser" == "" } { set ruser $default_user }
  8691. }
  8692.  
  8693. # Figure out username's password (if different from the vty password)
  8694. if {[info exists userpasswd]} {
  8695. # command line username
  8696. set userpswd $userpasswd
  8697. } else {
  8698. set userpswd [join [find userpassword $router] ""]
  8699. if { "$userpswd" == "" } { set userpswd $passwd }
  8700. }
  8701.  
  8702. # Figure out prompts
  8703. set u_prompt [find userprompt $router]
  8704. if { "$u_prompt" == "" } {
  8705. set u_prompt "(Username|Login|login|user name|User):"
  8706. } else {
  8707. set u_prompt [join [lindex $u_prompt 0] ""]
  8708. }
  8709. set p_prompt [find passprompt $router]
  8710. if { "$p_prompt" == "" } {
  8711. set p_prompt "(\[Pp]assword|passwd|Enter password for \[^ :]+):"
  8712. } else {
  8713. set p_prompt [join [lindex $p_prompt 0] ""]
  8714. }
  8715.  
  8716. # Figure out identity file to use
  8717. set identfile [join [lindex [find identity $router] 0] ""]
  8718.  
  8719. # Figure out passphrase to use
  8720. if {[info exists avpassphrase]} {
  8721. set passphrase $avpassphrase
  8722. } else {
  8723. set passphrase [join [lindex [find passphrase $router] 0] ""]
  8724. }
  8725. if { ! [string length "$passphrase"]} {
  8726. set passphrase $passwd
  8727. }
  8728.  
  8729. # Figure out cypher type
  8730. if {[info exists cypher]} {
  8731. # command line cypher type
  8732. set cyphertype $cypher
  8733. } else {
  8734. set cyphertype [find cyphertype $router]
  8735. if { "$cyphertype" == "" } { set cyphertype "3des" }
  8736. }
  8737.  
  8738. # Figure out connection method
  8739. set cmethod [find method $router]
  8740. if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} }
  8741.  
  8742. # Figure out the SSH executable name
  8743. set sshcmd [join [lindex [find sshcmd $router] 0] ""]
  8744. if { "$sshcmd" == "" } { set sshcmd {ssh} }
  8745.  
  8746. # Login to the router
  8747. if {[login $router $ruser $userpswd $passwd $enapasswd $cmethod $cyphertype $identfile]} {
  8748. incr exitval
  8749. # if login failed or rsh was unsuccessful, move on to the next device
  8750. continue
  8751. }
  8752.  
  8753. # we are logged in, now figure out the full prompt
  8754. send "\r"
  8755. expect {
  8756. -re "\[\r\n]+" { exp_continue; }
  8757. -re "^.+$prompt" { set junk $expect_out(0,string);
  8758. regsub -all "\[\]\[\(\)]" $junk {\\&} prompt;
  8759. }
  8760. }
  8761.  
  8762. if { $do_command } {
  8763. if {[run_commands $prompt $command]} {
  8764. incr exitval
  8765. continue
  8766. }
  8767. } elseif { $do_script } {
  8768. source $sfile
  8769. catch {close};
  8770. } else {
  8771. label $router
  8772. log_user 1
  8773. interact
  8774. }
  8775.  
  8776. # End of for each router
  8777. catch {wait};
  8778. sleep 0.3
  8779. }
  8780. exit $exitval
  8781. #! /usr/bin/perl
  8782. ##
  8783. ## $Id: xirancid.in 2246 2010-09-08 01:36:07Z heas $
  8784. ##
  8785. ## rancid 3.4.1
  8786. ## Copyright (c) 1997-2016 by Terrapin Communications, Inc.
  8787. ## All rights reserved.
  8788. ##
  8789. ## This code is derived from software contributed to and maintained by
  8790. ## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan,
  8791. ## Pete Whiting, Austin Schutz, and Andrew Fort.
  8792. ##
  8793. ## Redistribution and use in source and binary forms, with or without
  8794. ## modification, are permitted provided that the following conditions
  8795. ## are met:
  8796. ## 1. Redistributions of source code must retain the above copyright
  8797. ## notice, this list of conditions and the following disclaimer.
  8798. ## 2. Redistributions in binary form must reproduce the above copyright
  8799. ## notice, this list of conditions and the following disclaimer in the
  8800. ## documentation and/or other materials provided with the distribution.
  8801. ## 3. All advertising materials mentioning features or use of this software
  8802. ## must display the following acknowledgement:
  8803. ## This product includes software developed by Terrapin Communications,
  8804. ## Inc. and its contributors for RANCID.
  8805. ## 4. Neither the name of Terrapin Communications, Inc. nor the names of its
  8806. ## contributors may be used to endorse or promote products derived from
  8807. ## this software without specific prior written permission.
  8808. ## 5. It is requested that non-binding fixes and modifications be contributed
  8809. ## back to Terrapin Communications, Inc.
  8810. ##
  8811. ## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS
  8812. ## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  8813. ## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  8814. ## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
  8815. ## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  8816. ## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  8817. ## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  8818. ## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  8819. ## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  8820. ## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  8821. ## POSSIBILITY OF SUCH DAMAGE.
  8822. #
  8823. # hacked version of Hank's rancid - this one tries to deal with Xirrus arrays.
  8824. #
  8825. # RANXID - Really Awesome New Xirrus confIg Differ
  8826. #
  8827. # usage: xirancid [-dltCV] [-f filename | hostname]
  8828. #
  8829. use Getopt::Std;
  8830. getopts('dflt:CV');
  8831. if ($opt_V) {
  8832. print "rancid 3.4.1\n";
  8833. exit(0);
  8834. }
  8835. $log = $opt_l;
  8836. $debug = $opt_d;
  8837. $file = $opt_f;
  8838. $host = $ARGV[0];
  8839. $clean_run = 0;
  8840. $timeo = 90; # xilogin timeout in seconds
  8841.  
  8842. my(@commandtable, %commands, @commands);# command lists
  8843.  
  8844. # This routine is used to print out the router configuration
  8845. sub ProcessHistory {
  8846. my($new_hist_tag,$new_command,$command_string,@string) = (@_);
  8847. if ((($new_hist_tag ne $hist_tag) || ($new_command ne $command))
  8848. && scalar(%history)) {
  8849. print eval "$command \%history";
  8850. undef %history;
  8851. }
  8852. if (($new_hist_tag) && ($new_command) && ($command_string)) {
  8853. if ($history{$command_string}) {
  8854. $history{$command_string} = "$history{$command_string}@string";
  8855. } else {
  8856. $history{$command_string} = "@string";
  8857. }
  8858. } elsif (($new_hist_tag) && ($new_command)) {
  8859. $history{++$#history} = "@string";
  8860. } else {
  8861. print "@string";
  8862. }
  8863. $hist_tag = $new_hist_tag;
  8864. $command = $new_command;
  8865. 1;
  8866. }
  8867.  
  8868. # This routine parses "show config"
  8869. sub ShowConfig {
  8870. print STDERR " In ShowConfig: $_\n" if ($debug);
  8871.  
  8872. while (<INPUT>) {
  8873. tr/\015//d;
  8874. last if (/^$prompt/);
  8875. next if (/^(\s*|\s*$cmd\s*)$/);
  8876. ProcessHistory("","","","$_");
  8877. }
  8878. return(0);
  8879. }
  8880.  
  8881. # Main
  8882. @commandtable = (
  8883. {'show boot-env' => "ShowConfig"},
  8884. {'show running-config inc-defaults' => "ShowConfig"}
  8885. );
  8886. # Use an array to preserve the order of the commands and a hash for mapping
  8887. # commands to the subroutine and track commands that have been completed.
  8888. @commands = map(keys(%$_), @commandtable);
  8889. %commands = map(%$_, @commandtable);
  8890. $commandcnt = scalar(keys %commands);
  8891.  
  8892. $xirrus_cmds=join(";",@commands);
  8893. $cmds_regexp = join("|", map quotemeta($_), @commands);
  8894.  
  8895. if (length($host) == 0) {
  8896. if ($file) {
  8897. print(STDERR "Too few arguments: file name required\n");
  8898. exit(1);
  8899. } else {
  8900. print(STDERR "Too few arguments: host name required\n");
  8901. exit(1);
  8902. }
  8903. }
  8904. if ($opt_C) {
  8905. print "xilogin -t $timeo -c\'$xirrus_cmds\' $host\n";
  8906. exit(0);
  8907. }
  8908. open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n";
  8909. select(OUTPUT);
  8910. # make OUTPUT unbuffered if debugging
  8911. if ($debug) { $| = 1; }
  8912.  
  8913. if ($file) {
  8914. print STDERR "opening file $host\n" if ($debug);
  8915. print STDOUT "opening file $host\n" if ($log);
  8916. open(INPUT,"<$host") || die "open failed for $host: $!\n";
  8917. } else {
  8918. print STDERR "executing xilogin -t $timeo -c\"$xirrus_cmds\" $host\n" if ($debug);
  8919. print STDOUT "executing xilogin -t $timeo -c\"$xirrus_cmds\" $host\n" if ($log);
  8920. if (defined($ENV{NOPIPE})) {
  8921. system "xilogin -t $timeo -c \"$xirrus_cmds\" $host </dev/null > $host.raw 2>&1" || die "xilogin failed for $host: $!\n";
  8922. open(INPUT, "< $host.raw") || die "xilogin failed for $host: $!\n";
  8923. } else {
  8924. open(INPUT,"xilogin -t $timeo -c \"$xirrus_cmds\" $host </dev/null |") || die "xilogin failed for $host: $!\n";
  8925. }
  8926. }
  8927.  
  8928. ProcessHistory("","","","!RANCID-CONTENT-TYPE: xirrus\n!\n");
  8929. TOP: while(<INPUT>) {
  8930. tr/\015//d;
  8931. if (/^end/) {
  8932. $clean_run=1;
  8933. last;
  8934. }
  8935. if (/^Error:/) {
  8936. print STDOUT ("$host xilogin error: $_");
  8937. print STDERR ("$host xilogin error: $_") if ($debug);
  8938. $clean_run=0;
  8939. last;
  8940. }
  8941. while (/[>#]\s*($cmds_regexp)\s*$/) {
  8942. $cmd = $1;
  8943. if (!defined($prompt)) {
  8944. $prompt = ($_ =~ /^([^:]+:)/)[0];
  8945. }
  8946. print STDERR ("HIT COMMAND:$_") if ($debug);
  8947. if (! defined($commands{$cmd})) {
  8948. print STDERR "$host: found unexpected command - \"$cmd\"\n";
  8949. $clean_run = 0;
  8950. last TOP;
  8951. }
  8952. $rval = &{$commands{$cmd}}(*INPUT, *OUTPUT, $cmd);
  8953. delete($commands{$cmd});
  8954. if ($rval == -1) {
  8955. $clean_run = 0;
  8956. last TOP;
  8957. }
  8958. }
  8959. }
  8960. print STDOUT "Done $logincmd: $_\n" if ($log);
  8961. # Flush History
  8962. ProcessHistory("","","","");
  8963. # Cleanup
  8964. close(INPUT);
  8965. close(OUTPUT);
  8966.  
  8967. if (defined($ENV{NOPIPE})) {
  8968. unlink("$host.raw") if (! $debug);
  8969. }
  8970.  
  8971. # check for completeness
  8972. if (scalar(%commands) || !$clean_run ) {
  8973. if (scalar(keys %commands) eq $commandcnt) {
  8974. printf(STDERR "$host: missed cmd(s): all commands\n");
  8975. } elsif (scalar(%commands)) {
  8976. printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands)));
  8977. printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug);
  8978. }
  8979. if (!$clean_run ) {
  8980. print STDOUT "$host: End of run not found\n";
  8981. print STDERR "$host: End of run not found\n" if ($debug);
  8982. system("/usr/bin/tail -1 $host.new");
  8983. }
  8984. unlink "$host.new" if (! $debug);
  8985. }
  8986. #! /usr/bin/perl
  8987. ##
  8988. ## $Id: xrancid.in 3018 2015-01-11 05:51:49Z heas $
  8989. ##
  8990. ## rancid 3.4.1
  8991. ## Copyright (c) 1997-2016 by Terrapin Communications, Inc.
  8992. ## All rights reserved.
  8993. ##
  8994. ## This code is derived from software contributed to and maintained by
  8995. ## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan,
  8996. ## Pete Whiting, Austin Schutz, and Andrew Fort.
  8997. ##
  8998. ## Redistribution and use in source and binary forms, with or without
  8999. ## modification, are permitted provided that the following conditions
  9000. ## are met:
  9001. ## 1. Redistributions of source code must retain the above copyright
  9002. ## notice, this list of conditions and the following disclaimer.
  9003. ## 2. Redistributions in binary form must reproduce the above copyright
  9004. ## notice, this list of conditions and the following disclaimer in the
  9005. ## documentation and/or other materials provided with the distribution.
  9006. ## 3. All advertising materials mentioning features or use of this software
  9007. ## must display the following acknowledgement:
  9008. ## This product includes software developed by Terrapin Communications,
  9009. ## Inc. and its contributors for RANCID.
  9010. ## 4. Neither the name of Terrapin Communications, Inc. nor the names of its
  9011. ## contributors may be used to endorse or promote products derived from
  9012. ## this software without specific prior written permission.
  9013. ## 5. It is requested that non-binding fixes and modifications be contributed
  9014. ## back to Terrapin Communications, Inc.
  9015. ##
  9016. ## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS
  9017. ## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  9018. ## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  9019. ## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
  9020. ## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  9021. ## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  9022. ## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  9023. ## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  9024. ## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  9025. ## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  9026. ## POSSIBILITY OF SUCH DAMAGE.
  9027. #
  9028. # RANCID - Really Awesome New Cisco confIg Differ
  9029. #
  9030. # usage: xrancid [-dltCV] [-f filename | hostname]
  9031. #
  9032. use Getopt::Std;
  9033. getopts('dflt:CV');
  9034. if ($opt_V) {
  9035. print "rancid 3.4.1\n";
  9036. exit(0);
  9037. }
  9038. $log = $opt_l;
  9039. $debug = $opt_d;
  9040. $file = $opt_f;
  9041. $host = $ARGV[0];
  9042. $clean_run = 0;
  9043. $found_end = 0;
  9044. $timeo = 90; # clogin timeout in seconds
  9045.  
  9046. my(@commandtable, %commands, @commands);# command lists
  9047. my($aclsort) = ("ipsort"); # ACL sorting mode
  9048. my($filter_commstr); # SNMP community string filtering
  9049. my($filter_pwds); # password filtering mode
  9050.  
  9051. # This routine is used to print out the router configuration
  9052. sub ProcessHistory {
  9053. my($new_hist_tag,$new_command,$command_string,@string) = (@_);
  9054. if ((($new_hist_tag ne $hist_tag) || ($new_command ne $command))
  9055. && scalar(%history)) {
  9056. print eval "$command \%history";
  9057. undef %history;
  9058. }
  9059. if (($new_hist_tag) && ($new_command) && ($command_string)) {
  9060. if ($history{$command_string}) {
  9061. $history{$command_string} = "$history{$command_string}@string";
  9062. } else {
  9063. $history{$command_string} = "@string";
  9064. }
  9065. } elsif (($new_hist_tag) && ($new_command)) {
  9066. $history{++$#history} = "@string";
  9067. } else {
  9068. print "@string";
  9069. }
  9070. $hist_tag = $new_hist_tag;
  9071. $command = $new_command;
  9072. 1;
  9073. }
  9074.  
  9075. sub numerically { $a <=> $b; }
  9076.  
  9077. # This is a sort routine that will sort numerically on the
  9078. # keys of a hash as if it were a normal array.
  9079. sub keynsort {
  9080. local(%lines) = @_;
  9081. local($i) = 0;
  9082. local(@sorted_lines);
  9083. foreach $key (sort numerically keys(%lines)) {
  9084. $sorted_lines[$i] = $lines{$key};
  9085. $i++;
  9086. }
  9087. @sorted_lines;
  9088. }
  9089.  
  9090. # This is a sort routine that will sort on the
  9091. # keys of a hash as if it were a normal array.
  9092. sub keysort {
  9093. local(%lines) = @_;
  9094. local($i) = 0;
  9095. local(@sorted_lines);
  9096. foreach $key (sort keys(%lines)) {
  9097. $sorted_lines[$i] = $lines{$key};
  9098. $i++;
  9099. }
  9100. @sorted_lines;
  9101. }
  9102.  
  9103. # This is a sort routine that will sort on the
  9104. # values of a hash as if it were a normal array.
  9105. sub valsort{
  9106. local(%lines) = @_;
  9107. local($i) = 0;
  9108. local(@sorted_lines);
  9109. foreach $key (sort values %lines) {
  9110. $sorted_lines[$i] = $key;
  9111. $i++;
  9112. }
  9113. @sorted_lines;
  9114. }
  9115.  
  9116. # This is a numerical sort routine (ascending).
  9117. sub numsort {
  9118. local(%lines) = @_;
  9119. local($i) = 0;
  9120. local(@sorted_lines);
  9121. foreach $num (sort {$a <=> $b} keys %lines) {
  9122. $sorted_lines[$i] = $lines{$num};
  9123. $i++;
  9124. }
  9125. @sorted_lines;
  9126. }
  9127.  
  9128. # This is a sort routine that will sort on the
  9129. # ip address when the ip address is anywhere in
  9130. # the strings.
  9131. sub ipsort {
  9132. local(%lines) = @_;
  9133. local($i) = 0;
  9134. local(@sorted_lines);
  9135. foreach $addr (sort sortbyipaddr keys %lines) {
  9136. $sorted_lines[$i] = $lines{$addr};
  9137. $i++;
  9138. }
  9139. @sorted_lines;
  9140. }
  9141.  
  9142. # These two routines will sort based upon IP addresses
  9143. sub ipaddrval {
  9144. my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#);
  9145. $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0]));
  9146. }
  9147. sub sortbyipaddr {
  9148. &ipaddrval($a) <=> &ipaddrval($b);
  9149. }
  9150.  
  9151. # This routine parses "show version"
  9152. sub ShowVersion {
  9153. print STDERR " In ShowVersion: $_" if ($debug);
  9154.  
  9155. while (<INPUT>) {
  9156. tr/\015//d;
  9157. last if(/^$prompt/);
  9158. next if(/^(\s*|\s*$cmd\s*)$/);
  9159.  
  9160. /^\S+ Serial Number:/i &&
  9161. ProcessHistory("COMMENTS","keysort","B0","#$_") && next;
  9162. /^(\S+) Power Supply ([^:]+):\s+(.*)/i &&
  9163. ProcessHistory("COMMENTS","keysort","C0","#Power: $1 $2 $3\n")
  9164. && next;
  9165. /^image\s*:\s*(.*)\s+by\s+/i &&
  9166. ProcessHistory("COMMENTS","keysort","D0","#Image: $1\n")
  9167. && next;
  9168. /^bootrom\s+:\s+(.*)/i &&
  9169. ProcessHistory("COMMENTS","keysort","D1","#\n#Bootrom: $1\n")
  9170. && next;
  9171.  
  9172. #heas: need to collect this from show vers for ShowSlot where rev #s are excluded
  9173. #SLOT 1 : 702005-06 0025S-00877 CPLD Rev <FF>
  9174. #SLOT 2 : 702005-06 0021S-00131 CPLD Rev 02
  9175. #SLOT 3 : 702009-06 0024S-00170 CPLD Rev <FF>
  9176. #SLOT 4 : 702009-06 0024S-00319 CPLD Rev <FF>
  9177. }
  9178. return(0);
  9179. }
  9180.  
  9181. # This routine parses "show memory"
  9182. sub ShowMemory {
  9183. print STDERR " In ShowMemory: $_" if ($debug);
  9184.  
  9185. while (<INPUT>) {
  9186. tr/\015//d;
  9187. last if(/^$prompt/);
  9188. next if(/^(\s*|\s*$cmd\s*)$/);
  9189.  
  9190. /^Total DRAM (Size|\(KB\)): (.*)/ &&
  9191. ProcessHistory("COMMENTS","keysort","B1","#\n#Memory: $2\n")
  9192. }
  9193. return(0);
  9194. }
  9195.  
  9196. # This routine parses "show diag"
  9197. sub ShowDiag {
  9198. print STDERR " In ShowDiag: $_" if ($debug);
  9199.  
  9200. while (<INPUT>) {
  9201. tr/\015//d;
  9202. last if (/^$prompt/);
  9203. last if (/^Syntax error at token/);
  9204. next if (/^(\s*|\s*$cmd\s*)$/);
  9205.  
  9206. /platform\s+:\s+(.*)$/i &&
  9207. ProcessHistory("COMMENTS","keysort","A0","#Chassis type: $1\n") &&
  9208. next;
  9209. /(\S+) part no\s+:\s+(.*)$/i &&
  9210. ProcessHistory("COMMENTS","keysort","E0","#$1 PN: $2\n") &&
  9211. next;
  9212. /(\S+ \S+) no\s+:\s+(.*)$/i &&
  9213. ProcessHistory("COMMENTS","keysort","E0","#$1 PN: $2\n") &&
  9214. next;
  9215. /(mac address)\s+:\s+(.*)$/i &&
  9216. ProcessHistory("COMMENTS","keysort","B0","#$1: $2\n") &&
  9217. next;
  9218. }
  9219. return(0);
  9220. }
  9221.  
  9222. # This routine parses "show slot"
  9223. sub ShowSlot {
  9224. print STDERR " In ShowSlot: $_" if ($debug);
  9225.  
  9226. while (<INPUT>) {
  9227. tr/\015//d;
  9228. last if (/^$prompt/);
  9229. next if (/^(\s*|\s*$cmd\s*)$/);
  9230.  
  9231. if (/^Slot\s+(\d+)\s+/i) {
  9232. my($slot) = $1;
  9233. my($hwtype, $conftype, $sn, $state);
  9234. ProcessHistory("COMMENTS","keysort","F$slot","#\n");
  9235. while (<INPUT>) {
  9236. tr/\015//d;
  9237. last if (/^$prompt/ || /^\s*$/);
  9238. if (/State:\s+(.*)$/i) { $state = $1; }
  9239. if (/serial number:\s+(.*)$/i) { $sn = $1; }
  9240. if (/hw module type:\s+(.*)$/i) { $hwtype = $1; }
  9241. if (/configured type:\s+(.*)$/i) { $conftype = $1; }
  9242. }
  9243. ProcessHistory("COMMENTS","keysort","F$slot","#Slot $slot: type "
  9244. . "$hwtype,"
  9245. . " $conftype\n#Slot $slot: serial $sn\n#Slot $slot: state "
  9246. . " $state\n");
  9247. return if (/^$prompt/);
  9248. next;
  9249. }
  9250. }
  9251. return(0);
  9252. }
  9253.  
  9254. # This routine parses "show switch"
  9255. sub ShowSwitch {
  9256. print STDERR " In ShowSwitch: $_" if ($debug);
  9257.  
  9258. while (<INPUT>) {
  9259. tr/\015//d;
  9260. last if(/^$prompt/);
  9261. next if(/^(\s*|\s*$cmd\s*)$/);
  9262.  
  9263. /^\s*$/i && next;
  9264. /^(primary|secondary) configuration:/i && next;
  9265. /^(boot |next reboot)/i && next;
  9266. /^(auto |qos mode|sys\S*:|temperature|time)/i && next;
  9267.  
  9268. /^power supply: (.*)/i &&
  9269. ProcessHistory("COMMENTS","keysort","C0","#$1") && next;
  9270. /^license/i && ProcessHistory("COMMENTS","keysort","D0","#Image: $_")
  9271. && next;
  9272. s/^software image (\S+):/Image: $1:/i &&
  9273. ProcessHistory("COMMENTS","keysort","D0","#$_") && next;
  9274. /^\S+ software version:/i &&
  9275. ProcessHistory("COMMENTS","keysort","D0","#Image: $_") && next;
  9276. /^(\S+ )?software/i &&
  9277. ProcessHistory("COMMENTS","keysort","D0","# $_") && next;
  9278. /System MAC:\s+(.*)$/ &&
  9279. ProcessHistory("COMMENTS","keysort","B0","#MAC: $1\n") &&
  9280. next;
  9281. /System Type:\s+(.*)$/ &&
  9282. ProcessHistory("COMMENTS","keysort","A0","#Chassis type: $1\n")
  9283. && next;
  9284. /^(Image Selected):\s+(\S+)/ &&
  9285. ProcessHistory("COMMENTS","keysort","A0","#$1: $2\n") && next;
  9286. /^(Image Booted):\s+(\S+)/ &&
  9287. ProcessHistory("COMMENTS","keysort","A0","#$1: $2\n") && next;
  9288. /^(Primary (\S+ )?ver):\s+(\S+)/i &&
  9289. ProcessHistory("COMMENTS","keysort","A0","#$1: $3\n") && next;
  9290. /^(Secondary (\S+ )?ver):\s+(\S+)/i &&
  9291. ProcessHistory("COMMENTS","keysort","A0","#$1: $3\n") && next;
  9292. /^(Config Selected):\s+(\S+)/ &&
  9293. ProcessHistory("COMMENTS","keysort","A0","#$1: $2\n") && next;
  9294. /^(Config Booted):\s+(\S+)/ &&
  9295. ProcessHistory("COMMENTS","keysort","A0","#$1: $2\n") && next;
  9296. }
  9297. return(0);
  9298. }
  9299.  
  9300. # This routine processes a "show configuration {detail}"
  9301. sub WriteTerm {
  9302. my($lines) = 0;
  9303. print STDERR " In WriteTerm: $_" if ($debug);
  9304. my($comment) = 1; # strip extra comments, esp to preserve chassis type
  9305.  
  9306. while (<INPUT>) {
  9307. tr/\015//d;
  9308. last if(/^$prompt/);
  9309. next if(/^\s*$/);
  9310. return(0) if (/^syntax error at token /i);
  9311. return(0) if (/^%% Invalid input detected at /i);
  9312. return(0) if (/^%% Ambiguous command:/i);
  9313. # the pager can not be disabled per-session on the PIX
  9314. s/^<-+ More -+>\s*//;
  9315. return(0) if ($found_end);
  9316.  
  9317. s/^\s*$/#/;
  9318. next if (/full detail configuration/i);
  9319.  
  9320. # filter extra comments and lead comments in config so we can preserve
  9321. # the chassis type at the top of muched o/p before the process history
  9322. # key changes.
  9323. if (/^#\s*$/) {
  9324. if ($comment) {
  9325. next;
  9326. } else {
  9327. $comment++;
  9328. }
  9329. } else {
  9330. $comment = 0;
  9331. }
  9332. $lines++;
  9333.  
  9334. # Dog gone Cool matches to process the rest of the config
  9335. # some chassis report their chassis type in show diag...oh, but
  9336. # others do not. grab it here, if available. so, nothing else
  9337. # can change the keysort key until this is grabbed. sigh.
  9338. /# (\S+) configuration generated/i &&
  9339. ProcessHistory("COMMENTS","keysort","A0","#Chassis type: $1\n") &&
  9340. ($comment = 0) && next;
  9341. /configuration generated/i && next;
  9342. /# system name/i && next;
  9343. /# software version/i && next;
  9344.  
  9345. if (/((create|configure) account \S+ \S+) / && $filter_pwds >= 2) {
  9346. ProcessHistory("COMMENTS","keysort","H0","# $1 <key removed>\n");
  9347. next;
  9348. }
  9349. if (/configure ssh2 key/ && $filter_pwds >= 1) {
  9350. ProcessHistory("COMMENTS","keysort","H0","# $_# <key removed>\n");
  9351. while (<INPUT>) {
  9352. if (/^(#|enable|conf|disable|unconf)/) {
  9353. tr/\015//d;
  9354. last;
  9355. }
  9356. }
  9357. }
  9358.  
  9359. # filter out any RCS/CVS tags to avoid confusing local CVS storage
  9360. s/\$(Revision|Id):/ $1:/;
  9361. if (/^((config|configure) bgp (neighbor|peer-group) \S+ password encrypted)/i && $filter_pwds >= 1) {
  9362. ProcessHistory("COMMENTS","keysort","H0","# $1 <removed>\n");
  9363. next;
  9364. }
  9365.  
  9366. # order logging statements
  9367. /^configure syslog add logging (\d+\.\d+\.\d+\.\d+)/ &&
  9368. ProcessHistory("LOGGING","ipsort","$1","$_") && next;
  9369. # order/prune snmp-server host statements
  9370. # we only prune lines of the form
  9371.  
  9372. # configure snmp add trapreceiver a.b.c.d <community>
  9373. if (/^(configure snmp add trapreceiver )(\d+\.\d+\.\d+\.\d+) (community) \S+/) {
  9374. if ($filter_commstr) {
  9375. ProcessHistory("SNMPSVRHOST","ipsort","$2","# $1$2 $3 <removed> $'\n");
  9376. } else {
  9377. ProcessHistory("SNMPSVRHOST","ipsort","$2","$_\n");
  9378. }
  9379. next;
  9380. }
  9381. if (/^(configure snmp community (readonly|readwrite)( encrypted)?) (\S+)/) {
  9382. if ($filter_commstr) {
  9383. ProcessHistory("SNMPSVRCOMM","keysort","$_","#$1 <removed>$'");
  9384. next;
  9385. } else {
  9386. ProcessHistory("SNMPSVRCOMM","keysort","$_","$_") && next;
  9387. }
  9388. }
  9389. # order/prune tacacs/radius server statements
  9390. if (/^(configure radius (primary|secondary) (tacacs-server|radius-server) shared-secret encrypted)/ && $filter_pwds >= 1) {
  9391. ProcessHistory("COMMENTS","keysort","H0","# $1 <removed>\n");
  9392. next;
  9393. }
  9394.  
  9395. # catch anything that wasnt match above.
  9396. ProcessHistory("COMMENTS","keysort","H0","$_");
  9397. # end of config
  9398. if (/^# End of configuration file/i) {
  9399. printf STDERR " End WriteTerm: $_" if ($debug);
  9400. $found_end = 1;
  9401. return(0);
  9402. }
  9403. }
  9404.  
  9405. printf STDERR " End WriteTerm: $_" if ($debug);
  9406.  
  9407. if ($lines < 3) {
  9408. printf(STDERR "ERROR: $host configuration appears to be truncated.\n");
  9409. $found_end = 0;
  9410. return(-1);
  9411. }
  9412. $found_end = 1;
  9413.  
  9414. return(0);
  9415. }
  9416.  
  9417. # Main
  9418. @commandtable = (
  9419. {'show version' => 'ShowVersion'},
  9420. {'show memory' => 'ShowMemory'},
  9421. {'show diag' => 'ShowDiag'},
  9422. {'show switch' => 'ShowSwitch'},
  9423. {'show slot' => 'ShowSlot'},
  9424. {'show configuration detail' => 'WriteTerm'},
  9425. {'show configuration' => 'WriteTerm'},
  9426. );
  9427. # Use an array to preserve the order of the commands and a hash for mapping
  9428. # commands to the subroutine and track commands that have been completed.
  9429. @commands = map(keys(%$_), @commandtable);
  9430. %commands = map(%$_, @commandtable);
  9431. $commandcnt = scalar(keys %commands);
  9432.  
  9433. $commandstr = join(";",@commands);
  9434. $cmds_regexp = join("|", map quotemeta($_), @commands);
  9435.  
  9436. if (length($host) == 0) {
  9437. if ($file) {
  9438. print(STDERR "Too few arguments: file name required\n");
  9439. exit(1);
  9440. } else {
  9441. print(STDERR "Too few arguments: host name required\n");
  9442. exit(1);
  9443. }
  9444. }
  9445. if ($opt_C) {
  9446. print "clogin -t $timeo -c\'$commandstr\' $host\n";
  9447. exit(0);
  9448. }
  9449. open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n";
  9450. select(OUTPUT);
  9451. # make OUTPUT unbuffered if debugging
  9452. if ($debug) { $| = 1; }
  9453.  
  9454. if ($file) {
  9455. print STDERR "opening file $host\n" if ($debug);
  9456. print STDOUT "opening file $host\n" if ($log);
  9457. open(INPUT,"<$host") || die "open failed for $host: $!\n";
  9458. } else {
  9459. print STDERR "executing clogin -t $timeo -c \"$commandstr\" $host\n" if ($debug);
  9460. print STDOUT "executing clogin -t $timeo -c \"$commandstr\" $host\n" if ($log);
  9461. if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
  9462. system "clogin -t $timeo -c \"$commandstr\" $host </dev/null > $host.raw 2>&1" || die "clogin failed for $host: $!\n";
  9463. open(INPUT, "< $host.raw") || die "clogin failed for $host: $!\n";
  9464. } else {
  9465. open(INPUT,"clogin -t $timeo -c \"$commandstr\" $host </dev/null |") || die "clogin failed for $host: $!\n";
  9466. }
  9467. }
  9468.  
  9469. # determine ACL sorting mode
  9470. if ($ENV{"ACLSORT"} =~ /no/i) {
  9471. $aclsort = "";
  9472. }
  9473. # determine community string filtering mode
  9474. if (defined($ENV{"NOCOMMSTR"}) &&
  9475. ($ENV{"NOCOMMSTR"} =~ /yes/i || $ENV{"NOCOMMSTR"} =~ /^$/)) {
  9476. $filter_commstr = 1;
  9477. } else {
  9478. $filter_commstr = 0;
  9479. }
  9480. # determine password filtering mode
  9481. if ($ENV{"FILTER_PWDS"} =~ /no/i) {
  9482. $filter_pwds = 0;
  9483. } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) {
  9484. $filter_pwds = 2;
  9485. } else {
  9486. $filter_pwds = 1;
  9487. }
  9488.  
  9489. ProcessHistory("","","","#RANCID-CONTENT-TYPE: extreme\n#\n");
  9490. ProcessHistory("COMMENTS","keysort","B0","#\n"); # chassis info
  9491. ProcessHistory("COMMENTS","keysort","C0","#\n"); # power supply info
  9492. ProcessHistory("COMMENTS","keysort","D0","#\n"); # image name
  9493. ProcessHistory("COMMENTS","keysort","E0","#\n"); # h/w info
  9494. ProcessHistory("COMMENTS","keysort","F0","#\n"); # slot info
  9495. ProcessHistory("COMMENTS","keysort","H0","#\n"); # config
  9496. ProcessHistory("COMMENTS","keysort","X0","#\n");
  9497. TOP: while(<INPUT>) {
  9498. tr/\015//d;
  9499. # note: this match sucks rocks, but currently the extreme bits are
  9500. # unreliable about echoing the 'exit\n' command. this match might really
  9501. # be a bad idea, but instead rely upon WriteTerm's found_end?
  9502. if (/($prompt\s?(quit|exit)|Connection( to \S+)? closed)/ && $found_end) {
  9503. $clean_run = 1;
  9504. last;
  9505. }
  9506. if (/^Error:/) {
  9507. print STDOUT ("$host clogin error: $_");
  9508. print STDERR ("$host clogin error: $_") if ($debug);
  9509. $clean_run = 0;
  9510. last;
  9511. }
  9512. while (/$prompt\s*($cmds_regexp)\s*$/) {
  9513. $cmd = $1;
  9514. if (!defined($prompt)) {
  9515. $prompt = ($_ =~ /^([^#]+#)/)[0];
  9516. $prompt =~ s/([][}{)(\\])/\\$1/g;
  9517. $prompt =~ s/[:.](\d+ ?)#/[:.]\\d+ ?#/;
  9518. $prompt =~ s/\*/\\\*/;
  9519. print STDERR ("PROMPT MATCH: $prompt\n") if ($debug);
  9520. }
  9521. print STDERR ("HIT COMMAND:$_") if ($debug);
  9522. if (! defined($commands{$cmd})) {
  9523. print STDERR "$host: found unexpected command - \"$cmd\"\n";
  9524. $clean_run = 0;
  9525. last TOP;
  9526. }
  9527. $rval = &{$commands{$cmd}}(*INPUT, *OUTPUT, $cmd);
  9528. delete($commands{$cmd});
  9529. if ($rval == -1) {
  9530. printf STDERR "rval = -1\n" if ($debug);
  9531. $clean_run = 0;
  9532. last TOP;
  9533. }
  9534. }
  9535. }
  9536. print STDOUT "Done $logincmd: $_\n" if ($log);
  9537. # Flush History
  9538. ProcessHistory("","","","");
  9539. # Cleanup
  9540. close(INPUT);
  9541. close(OUTPUT);
  9542.  
  9543. if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
  9544. unlink("$host.raw") if (! $debug);
  9545. }
  9546.  
  9547. # check for completeness
  9548. if (scalar(%commands) || !$clean_run || !$found_end) {
  9549. if (scalar(keys %commands) eq $commandcnt) {
  9550. printf(STDERR "$host: missed cmd(s): all commands\n");
  9551. } elsif (scalar(%commands)) {
  9552. printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands)));
  9553. printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug);
  9554. }
  9555. if (!$clean_run || !$found_end) {
  9556. print STDOUT "$host: End of run not found\n";
  9557. print STDERR "$host: End of run not found\n" if ($debug);
  9558. system("/usr/bin/tail -1 $host.new");
  9559. }
  9560. unlink "$host.new" if (! $debug);
  9561. }
  9562. #! /usr/bin/perl
  9563. ##
  9564. ## $Id: xrrancid.in 2369 2012-01-30 21:06:03Z heas $
  9565. ##
  9566. ## rancid 2.3.8
  9567. ## Copyright (c) 1997-2010 by Terrapin Communications, Inc.
  9568. ## All rights reserved.
  9569. ##
  9570. ## This code is derived from software contributed to and maintained by
  9571. ## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan,
  9572. ## Pete Whiting, Austin Schutz, and Andrew Fort.
  9573. ##
  9574. ## Redistribution and use in source and binary forms, with or without
  9575. ## modification, are permitted provided that the following conditions
  9576. ## are met:
  9577. ## 1. Redistributions of source code must retain the above copyright
  9578. ## notice, this list of conditions and the following disclaimer.
  9579. ## 2. Redistributions in binary form must reproduce the above copyright
  9580. ## notice, this list of conditions and the following disclaimer in the
  9581. ## documentation and/or other materials provided with the distribution.
  9582. ## 3. All advertising materials mentioning features or use of this software
  9583. ## must display the following acknowledgement:
  9584. ## This product includes software developed by Terrapin Communications,
  9585. ## Inc. and its contributors for RANCID.
  9586. ## 4. Neither the name of Terrapin Communications, Inc. nor the names of its
  9587. ## contributors may be used to endorse or promote products derived from
  9588. ## this software without specific prior written permission.
  9589. ## 5. It is requested that non-binding fixes and modifications be contributed
  9590. ## back to Terrapin Communications, Inc.
  9591. ##
  9592. ## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS
  9593. ## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  9594. ## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  9595. ## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
  9596. ## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  9597. ## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  9598. ## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  9599. ## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  9600. ## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  9601. ## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  9602. ## POSSIBILITY OF SUCH DAMAGE.
  9603. #
  9604. # RANCID - Really Awesome New Cisco confIg Differ
  9605. #
  9606. # usage: rancid [-dV] [-l] [-f filename | hostname]
  9607. #
  9608. use Getopt::Std;
  9609. getopts('dflV');
  9610. if ($opt_V) {
  9611. print "rancid 2.3.8\n";
  9612. exit(0);
  9613. }
  9614. $log = $opt_l;
  9615. $debug = $opt_d;
  9616. $file = $opt_f;
  9617. $host = $ARGV[0];
  9618. $proc = "";
  9619. $clean_run = 0;
  9620. $found_end = 0;
  9621. $found_version = 0;
  9622. $found_env = 0;
  9623. $found_diag = 0;
  9624. $timeo = 90; # clogin timeout in seconds
  9625.  
  9626. my(@commandtable, %commands, @commands);# command lists
  9627. my($aclsort) = ("ipsort"); # ACL sorting mode
  9628. my($config_register); # configuration register value
  9629. my($filter_commstr); # SNMP community string filtering
  9630. my($filter_pwds); # password filtering mode
  9631.  
  9632. # This routine is used to print out the router configuration
  9633. sub ProcessHistory {
  9634. my($new_hist_tag,$new_command,$command_string,@string) = (@_);
  9635. if ((($new_hist_tag ne $hist_tag) || ($new_command ne $command))
  9636. && scalar(%history)) {
  9637. print eval "$command \%history";
  9638. undef %history;
  9639. }
  9640. if (($new_hist_tag) && ($new_command) && ($command_string)) {
  9641. if ($history{$command_string}) {
  9642. $history{$command_string} = "$history{$command_string}@string";
  9643. } else {
  9644. $history{$command_string} = "@string";
  9645. }
  9646. } elsif (($new_hist_tag) && ($new_command)) {
  9647. $history{++$#history} = "@string";
  9648. } else {
  9649. print "@string";
  9650. }
  9651. $hist_tag = $new_hist_tag;
  9652. $command = $new_command;
  9653. 1;
  9654. }
  9655.  
  9656. sub numerically { $a <=> $b; }
  9657.  
  9658. # This is a sort routine that will sort numerically on the
  9659. # keys of a hash as if it were a normal array.
  9660. sub keynsort {
  9661. local(%lines) = @_;
  9662. local($i) = 0;
  9663. local(@sorted_lines);
  9664. foreach $key (sort numerically keys(%lines)) {
  9665. $sorted_lines[$i] = $lines{$key};
  9666. $i++;
  9667. }
  9668. @sorted_lines;
  9669. }
  9670.  
  9671. # This is a sort routine that will sort on the
  9672. # keys of a hash as if it were a normal array.
  9673. sub keysort {
  9674. local(%lines) = @_;
  9675. local($i) = 0;
  9676. local(@sorted_lines);
  9677. foreach $key (sort keys(%lines)) {
  9678. $sorted_lines[$i] = $lines{$key};
  9679. $i++;
  9680. }
  9681. @sorted_lines;
  9682. }
  9683.  
  9684. # This is a sort routine that will sort on the
  9685. # values of a hash as if it were a normal array.
  9686. sub valsort{
  9687. local(%lines) = @_;
  9688. local($i) = 0;
  9689. local(@sorted_lines);
  9690. foreach $key (sort values %lines) {
  9691. $sorted_lines[$i] = $key;
  9692. $i++;
  9693. }
  9694. @sorted_lines;
  9695. }
  9696.  
  9697. # This is a numerical sort routine (ascending).
  9698. sub numsort {
  9699. local(%lines) = @_;
  9700. local($i) = 0;
  9701. local(@sorted_lines);
  9702. foreach $num (sort {$a <=> $b} keys %lines) {
  9703. $sorted_lines[$i] = $lines{$num};
  9704. $i++;
  9705. }
  9706. @sorted_lines;
  9707. }
  9708.  
  9709. # This is a sort routine that will sort on the
  9710. # ip address when the ip address is anywhere in
  9711. # the strings.
  9712. sub ipsort {
  9713. local(%lines) = @_;
  9714. local($i) = 0;
  9715. local(@sorted_lines);
  9716. foreach $addr (sort sortbyipaddr keys %lines) {
  9717. $sorted_lines[$i] = $lines{$addr};
  9718. $i++;
  9719. }
  9720. @sorted_lines;
  9721. }
  9722.  
  9723. # These two routines will sort based upon IP addresses
  9724. sub ipaddrval {
  9725. my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#);
  9726. $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0]));
  9727. }
  9728. sub sortbyipaddr {
  9729. &ipaddrval($a) <=> &ipaddrval($b);
  9730. }
  9731.  
  9732. # This routine parses "admin show version"
  9733. sub ShowVersion {
  9734. print STDERR " In ShowVersion: $_" if ($debug);
  9735. my($slaveslot);
  9736.  
  9737. while (<INPUT>) {
  9738. tr/\015//d;
  9739. if (/^$prompt/) { $found_version = 1; last};
  9740. next if (/^(\s*|\s*$cmd\s*)$/);
  9741. return(1) if (/Line has invalid autocommand /);
  9742. return(1) if (/(Invalid (input|command) detected|Type help or )/i);
  9743. return(0) if ($found_version); # Only do this routine once
  9744. return(-1) if (/command authorization failed/i);
  9745.  
  9746. if (/^Slave in slot (\d+) is running/) {
  9747. $slave = " Slave:";
  9748. $slaveslot = ", slot $1";
  9749. next;
  9750. }
  9751. /^(Cisco )?IOS .* Software,? \(([A-Za-z0-9_-]*)\), .*Version\s+(.*)$/ &&
  9752. ProcessHistory("COMMENTS","keysort","F1",
  9753. "!Image:$slave Software: $2, $3\n") && next;
  9754. /^([A-Za-z-0-9_]*) Synced to mainline version: (.*)$/ &&
  9755. ProcessHistory("COMMENTS","keysort","F2",
  9756. "!Image:$slave $1 Synced to mainline version: $2\n") && next;
  9757. /^Compiled (.*)$/ &&
  9758. ProcessHistory("COMMENTS","keysort","F3",
  9759. "!Image:$slave Compiled: $1\n") && next;
  9760. /^ROM: (IOS \S+ )?(System )?Bootstrap.*(Version.*)$/ &&
  9761. ProcessHistory("COMMENTS","keysort","G1",
  9762. "!ROM Bootstrap: $3\n") && next;
  9763. if (/^Hardware:\s+(.*), (.* RAM), CPU (.*)$/) {
  9764. ProcessHistory("COMMENTS","keysort","A1",
  9765. "!Chassis type: $1 - a PIX\n");
  9766. ProcessHistory("COMMENTS","keysort","A2",
  9767. "!CPU: $3\n");
  9768. ProcessHistory("COMMENTS","keysort","B1", "!Memory: $2\n");
  9769. }
  9770. /^Serial Number:\s+(.*)$/ &&
  9771. ProcessHistory("COMMENTS","keysort","C1", "!$_") && next;
  9772. # More PIX stuff
  9773. /^Encryption hardware device\s+:\s+(.*)/ &&
  9774. ProcessHistory("COMMENTS","keysort","A3", "!Encryption: $1\n") &&
  9775. next;
  9776. /^running activation key\s*:\s+(.*)/i &&
  9777. ProcessHistory("COMMENTS","keysort","D2", "!Key: $1\n") &&
  9778. next;
  9779. # Flash on the PIX or FWSM (FireWall Switch Module)
  9780. /^Flash(\s+\S+)+ \@ 0x\S+,\s+(\S+)/ &&
  9781. ProcessHistory("COMMENTS","keysort","B2", "!Memory: Flash $2\n") &&
  9782. next;
  9783. # CatOS 3500xl stuff
  9784. /^System serial number(:\s+.*)$/ &&
  9785. ProcessHistory("COMMENTS","keysort","C1", "!Serial Number$1\n") &&
  9786. next;
  9787. /^Model / &&
  9788. ProcessHistory("COMMENTS","keysort","C2", "!$_") && next;
  9789. /^Motherboard / &&
  9790. ProcessHistory("COMMENTS","keysort","C3", "!$_") && next;
  9791. /^Power supply / &&
  9792. ProcessHistory("COMMENTS","keysort","C4", "!$_") && next;
  9793.  
  9794. /^Activation Key:\s+(.*)$/ &&
  9795. ProcessHistory("COMMENTS","keysort","C2", "!$_") && next;
  9796. /^ROM: \d+ Bootstrap .*(Version.*)$/ &&
  9797. ProcessHistory("COMMENTS","keysort","G2",
  9798. "!ROM Image: Bootstrap $1\n!\n") && next;
  9799. /^ROM: .*(Version.*)$/ &&
  9800. ProcessHistory("COMMENTS","keysort","G3","!ROM Image: $1\n") && next;
  9801. /^BOOTFLASH: .*(Version.*)$/ &&
  9802. ProcessHistory("COMMENTS","keysort","G4","!BOOTFLASH: $1\n") && next;
  9803. /^BOOTLDR: .*(Version.*)$/ &&
  9804. ProcessHistory("COMMENTS","keysort","G4","!BOOTLDR: $1\n") && next;
  9805. /^System image file is "([^\"]*)", booted via (\S*)/ &&
  9806. # removed the booted source due to
  9807. # CSCdk28131: cycling info in 'sh ver'
  9808. # ProcessHistory("COMMENTS","keysort","F4","!Image: booted via $2, $1\n") &&
  9809. ProcessHistory("COMMENTS","keysort","F4","!Image: booted $1\n") &&
  9810. next;
  9811. /^System image file is "([^\"]*)"$/ &&
  9812. ProcessHistory("COMMENTS","keysort","F5","!Image: $1\n") && next;
  9813. if (/(\S+(?:\sseries)?)\s+(?:\((\S+)\)\s+processor|\(revision[^)]+\)).*\s+with (\S+k) bytes/i) {
  9814. $proc = $1;
  9815. my($cpu) = $2;
  9816. my($mem) = $3;
  9817. my($device) = "router";
  9818.  
  9819. # the next line ought to be the more specific cpu info, grab it.
  9820. # yet, some boards/IOS vers have a processor ID line between these
  9821. # two. grrr. make sure we dont grab the "software" junk that
  9822. # follows these lines by looking for "CPU at " or the 2600s
  9823. # "processor: " unique string. there are undoubtedly many other
  9824. # incantations. for a slave, we dont get this info, its just a
  9825. # blank line.
  9826. $_ = <INPUT>;
  9827. if (/processor board id/i) {
  9828. my($sn);
  9829.  
  9830. if (/processor board id (\S+)/i) {
  9831. $sn = $1;
  9832. $sn =~ s/,$//;
  9833. ProcessHistory("COMMENTS","keysort","D9",
  9834. "!Processor ID: $sn\n");
  9835. }
  9836. $_ = <INPUT>;
  9837. }
  9838. $_ = "" if (! /(cpu at |processor: |$cpu processor,)/i);
  9839. tr/\015//d;
  9840. s/implementation/impl/i;
  9841. if ($_ !~ /^\s*$/) {
  9842. chomp;
  9843. s/^/, /;
  9844. }
  9845.  
  9846. if ($proc eq "CSC") {
  9847. $type = "AGS";
  9848. } elsif ($proc eq "CSC4") {
  9849. $type = "AGS+";
  9850. } elsif ($proc =~ /1900/) {
  9851. $type = "1900";
  9852. $device = "switch";
  9853. } elsif ($proc =~ /^(AS)?25[12][12]/) {
  9854. $type = "2500";
  9855. } elsif ($proc =~ /261[01]/ || $proc =~ /262[01]/ ) {
  9856. $type = "2600";
  9857. } elsif ($proc =~ /WS-C29/) {
  9858. $type = "2900XL";
  9859. $device = "switch";
  9860. } elsif ($proc =~ /WS-C355/) {
  9861. $type = "3550";
  9862. $device = "switch";
  9863. } elsif ($proc =~ /WS-C35/) {
  9864. $type = "3500XL";
  9865. $device = "switch";
  9866. } elsif ($proc =~ /^36[0246][0-9]/) {
  9867. $type = "3600";
  9868. } elsif ($proc =~ /^37/) {
  9869. $type = "3700";
  9870. } elsif ($proc =~ /^38/) {
  9871. $type = "3800";
  9872. } elsif ($proc =~ /WS-C45/) {
  9873. $type = "4500";
  9874. $device = "switch";
  9875. } elsif ( $proc =~ /^AS5300/) {
  9876. $type = "AS5300";
  9877. } elsif ( $proc =~ /^AS5350/) {
  9878. $type = "AS5350";
  9879. } elsif ( $proc =~ /^AS5400/) {
  9880. $type = "AS5400";
  9881. } elsif ($proc =~ /6000/) {
  9882. $type = "6000";
  9883. $device = "switch";
  9884. } elsif ($proc eq "WK-C65") {
  9885. $type = "6500";
  9886. } elsif ($proc eq "RP") {
  9887. $type = "7000";
  9888. } elsif ($proc eq "RP1") {
  9889. $type = "7000";
  9890. } elsif ($proc =~ /720[246]/) {
  9891. $type = "7200";
  9892. } elsif ( $proc =~ /^73/) {
  9893. $type = "7300";
  9894. } elsif ($proc eq "RSP7000") {
  9895. $type = "7500";
  9896. } elsif ($proc =~ /RSP\d/) {
  9897. $type = "7500";
  9898. } elsif ($proc =~ /OSR-76/) {
  9899. $type = "7600";
  9900. } elsif ($proc =~ /CISCO76/) {
  9901. $type = "7600";
  9902. } elsif ($proc =~ /1200[48]\/(GRP|PRP)/ || $proc =~ /1201[26]\/(GRP|PRP)/) {
  9903. $type = "12000";
  9904. } elsif ($proc =~ /1201[26]-8R\/(GRP|PRP)/) {
  9905. $type = "12000";
  9906. } elsif ($proc =~ /1240[48]\/(GRP|PRP)/ || $proc =~ /1241[06]\/(GRP|PRP)/) {
  9907. $type = "12400";
  9908. } else {
  9909. $type = $proc;
  9910. }
  9911.  
  9912. print STDERR "TYPE = $type\n" if ($debug);
  9913. ProcessHistory("COMMENTS","keysort","A1",
  9914. "!Chassis type:$slave $proc - a $type $device\n");
  9915. ProcessHistory("COMMENTS","keysort","B1",
  9916. "!Memory:$slave main $mem\n");
  9917. if (defined($cpu)) {
  9918. ProcessHistory("COMMENTS","keysort","A3",
  9919. "!CPU:$slave $cpu$_$slaveslot\n");
  9920. }
  9921. next;
  9922. }
  9923. if (/(\S+) Silicon\s*Switch Processor/) {
  9924. if (!defined($C0)) {
  9925. $C0 = 1; ProcessHistory("COMMENTS","keysort","C0","!\n");
  9926. }
  9927. ProcessHistory("COMMENTS","keysort","C2","!SSP: $1\n");
  9928. $ssp = 1;
  9929. $sspmem = $1;
  9930. next;
  9931. }
  9932. /^(\d+[kK]) bytes of multibus/ &&
  9933. ProcessHistory("COMMENTS","keysort","B2",
  9934. "!Memory: multibus $1\n") && next;
  9935. /^(\d+[kK]) bytes of (non-volatile|NVRAM)/ &&
  9936. ProcessHistory("COMMENTS","keysort","B3",
  9937. "!Memory: nvram $1\n") && next;
  9938. /^(\d+[kK]) bytes of flash memory/ &&
  9939. ProcessHistory("COMMENTS","keysort","B5","!Memory: flash $1\n") &&
  9940. next;
  9941. /^(\d+[kK]) bytes of .*flash partition/ &&
  9942. ProcessHistory("COMMENTS","keysort","B6",
  9943. "!Memory: flash partition $1\n") && next;
  9944. /^(\d+[kK]) bytes of Flash internal/ &&
  9945. ProcessHistory("COMMENTS","keysort","B4",
  9946. "!Memory: bootflash $1\n") && next;
  9947. if (/^(\d+[kK]) bytes of (Flash|ATA)?.*PCMCIA .*(slot|disk) ?(\d)/i) {
  9948. ProcessHistory("COMMENTS","keysort","B7",
  9949. "!Memory: pcmcia $2 $3$4 $1\n");
  9950. next;
  9951. }
  9952. if (/^(\d+[kK]) bytes of (slot|disk)(\d)/i) {
  9953. ProcessHistory("COMMENTS","keysort","B7",
  9954. "!Memory: pcmcia $2$3 $1\n");
  9955. next;
  9956. }
  9957. if (/^WARNING/) {
  9958. if (!defined($I0)) {
  9959. $I0 = 1;
  9960. ProcessHistory("COMMENTS","keysort","I0","!\n");
  9961. }
  9962. ProcessHistory("COMMENTS","keysort","I1","! $_");
  9963. }
  9964. if (/^Configuration register is (.*)$/) {
  9965. $config_register = $1;
  9966. next;
  9967. }
  9968. if (/^Configuration register on node \S+ is (.*)$/) {
  9969. $config_register = $1 if (length($config_register) < 1);
  9970. next;
  9971. }
  9972. }
  9973. return(0);
  9974. }
  9975.  
  9976. # This routine parses "admin show diag".
  9977. # This will create arrays for hw info.
  9978. sub AdminShowDiag {
  9979. print STDERR " In ShowDiag: $_" if ($debug);
  9980.  
  9981. while (<INPUT>) {
  9982. tr/\015//d;
  9983. if (/^$prompt/) { $found_diag = 1; last};
  9984. next if (/^(\s*|\s*$cmd\s*)$/);
  9985. return(1) if (/Line has invalid autocommand /);
  9986. return(1) if (/(Invalid (input|command) detected|Type help or )/i);
  9987. return(-1) if (/command authorization failed/i);
  9988. /^$/ && next;
  9989.  
  9990. s/^NODE //;
  9991. # wtf are these?
  9992. next if (/(New Deviation|UDI_VID|Board State)/);
  9993. # skip insertion time
  9994. next if (/insertion time/i);
  9995. # skip board h/w revision junk
  9996. next if (/^(\s{2}board |\s{3,})/i);
  9997.  
  9998. ProcessHistory("SLOT","","","!$_");
  9999. }
  10000. ProcessHistory("SLOT","","","!\n");
  10001. return(0);
  10002. }
  10003.  
  10004. # This routine parses "admin show running".
  10005. # This will create arrays for hw info.
  10006. sub AdminShowRunning {
  10007. print STDERR " In ShowRunning: $_" if ($debug);
  10008.  
  10009. while (<INPUT>) {
  10010. tr/\015//d;
  10011. if (/^$prompt/) { $found_diag = 1; last};
  10012. next if (/^(\s*|\s*$cmd\s*)$/);
  10013. return(1) if (/Line has invalid autocommand /);
  10014. return(1) if (/(Invalid (input|command) detected|Type help or )/i);
  10015. return(-1) if (/command authorization failed/i);
  10016. /^$/ && next;
  10017.  
  10018. /^building configuration/i && next;
  10019. if (/^(\s*secret) / && $filter_pwds >= 2) {
  10020. ProcessHistory("SLOT","","","!$1 <removed>\n");
  10021. next;
  10022. }
  10023. /^end$/ && last;
  10024.  
  10025. ProcessHistory("SLOT","","","!$_");
  10026. }
  10027. ProcessHistory("SLOT","","","!\n");
  10028. return(0);
  10029. }
  10030.  
  10031. # This routine parses "admin show redundancy"
  10032. sub ShowRedundancy {
  10033. print STDERR " In ShowRedundancy: $_" if ($debug);
  10034.  
  10035. while (<INPUT>) {
  10036. tr/\015//d;
  10037. last if (/^$prompt/);
  10038. next if (/^(\s*|\s*$cmd\s*)$/);
  10039. return(1) if (/Line has invalid autocommand /);
  10040. return(1) if (/(Invalid (input|command) detected|Type help or )/i);
  10041.  
  10042. if (/^Version information for secondary in slot (\d+):/) {
  10043. $slave = " Slave:";
  10044. $slaveslot = ", slot $1";
  10045. next;
  10046. }
  10047.  
  10048. /^IOS .* Software \(([A-Za-z0-9_-]*)\), .*Version\s+(.*)$/ &&
  10049. ProcessHistory("COMMENTS","keysort","F1",
  10050. "!Image:$slave Software: $1, $2\n") && next;
  10051. /^Compiled (.*)$/ &&
  10052. ProcessHistory("COMMENTS","keysort","F3",
  10053. "!Image:$slave Compiled: $1\n") && next;
  10054. }
  10055. return(0);
  10056. }
  10057.  
  10058. # This routine parses "show install active"
  10059. sub ShowInstallActive {
  10060. print STDERR " In ShowInstallActive: $_" if ($debug);
  10061.  
  10062. while (<INPUT>) {
  10063. tr/\015//d;
  10064. last if (/^$prompt/);
  10065. next if (/^(\s*|\s*$cmd\s*)$/);
  10066. return(1) if (/^\s*\^\s*$/);
  10067. return(1) if (/Line has invalid autocommand /);
  10068. return(1) if (/(Invalid (input|command) detected|Type help or )/i);
  10069. return(-1) if (/command authorization failed/i);
  10070.  
  10071. ProcessHistory("COMMENTS","keysort","F5","!Image: $_") && next;
  10072. }
  10073. return(0);
  10074. }
  10075.  
  10076. # This routine parses "admin show env all"
  10077. sub ShowEnv {
  10078. # Skip if this is not a 7500, 7200, or 7000.
  10079. print STDERR " In ShowEnv: $_" if ($debug);
  10080.  
  10081. while (<INPUT>) {
  10082. tr/\015//d;
  10083. if (/^$prompt/) { $found_env = 1; last};
  10084. next if (/^(\s*|\s*$cmd\s*)$/);
  10085. #return(1) if ($type !~ /^7/);
  10086. return(1) if (/Line has invalid autocommand /);
  10087. return(1) if (/(Invalid (input|command) detected|Type help or )/i);
  10088. return(0) if ($found_env); # Only do this routine once
  10089. return(-1) if (/command authorization failed/i);
  10090.  
  10091. if (!defined($E0)) {
  10092. $E0 = 1;
  10093. ProcessHistory("COMMENTS","keysort","E0","!\n");
  10094. }
  10095. if (/^Arbiter type (\d), backplane type (\S+)/) {
  10096. if (!defined($C0)) {
  10097. $C0 = 1; ProcessHistory("COMMENTS","keysort","C0","!\n");
  10098. }
  10099. ProcessHistory("COMMENTS","keysort","C1",
  10100. "!Enviromental Arbiter Type: $1\n");
  10101. ProcessHistory("COMMENTS","keysort","A2",
  10102. "!Chassis type: $2 backplane\n");
  10103. next;
  10104. }
  10105. /^Power Supply Information$/ && next;
  10106. /^\s*Power Module\s+Voltage\s+Current$/ && next;
  10107. /^\s*(Power [^:\n]+)$/ &&
  10108. ProcessHistory("COMMENTS","keysort","E1","!Power: $1\n") && next;
  10109. /^\s*(Lower Power .*)/i &&
  10110. ProcessHistory("COMMENTS","keysort","E2","!Power: $1\n") && next;
  10111. /^\s*(redundant .*)/i &&
  10112. ProcessHistory("COMMENTS","keysort","E2","!Power: $1\n") && next;
  10113. /^\s*(RPS is .*)/i &&
  10114. ProcessHistory("COMMENTS","keysort","E2","!Power: $1\n") && next;
  10115. }
  10116. ProcessHistory("COMMENTS","","","!\n");
  10117. return(0);
  10118. }
  10119.  
  10120. # This routine parses "dir /all ((disk|slot)N|bootflash|nvram):"
  10121. sub DirSlotN {
  10122. print STDERR " In DirSlotN: $_" if ($debug);
  10123.  
  10124. my($dev) = (/\s([^\s]+):/);
  10125.  
  10126. while (<INPUT>) {
  10127. tr/\015//d;
  10128. last if (/^$prompt/);
  10129. next if (/^(\s*|\s*$cmd\s*)$/);
  10130. return(1) if /^\s*\^\s*$/;
  10131. return(1) if (/Line has invalid autocommand /);
  10132. return(1) if (/(Invalid (input|command) detected|Type help or )/i);
  10133. return(1) if (/(No such device|Error Sending Request)/i);
  10134. return(1) if (/\%Error: No such file or directory/);
  10135. return(1) if (/No space information available/);
  10136. # Corrupt flash
  10137. /\%Error calling getdents / &&
  10138. ProcessHistory("FLASH","","","!Flash: $dev: $_") && next;
  10139. return(-1) if (/\%Error calling/);
  10140. return(-1) if (/(: device being squeezed|ATA_Status time out)/i); # busy
  10141. return(-1) if (/\%Error opening \S+:\S+ \(Device or resource busy\)/i);
  10142. return(-1) if (/command authorization failed/i);
  10143. return(1) if (/(Open device \S+ failed|Error opening \S+:)/);
  10144. # filter frequently changing files from IOX bootflash
  10145. if ($dev =~ /bootflash/) {
  10146. next if (/temp_cont\s*$/);
  10147. next if (/uptime_cont\s*$/);
  10148. }
  10149. # Filter dhcp database
  10150. if (/dhcp_[^. ]*\.txt/) {
  10151. next;
  10152. }
  10153. # Filter debugging file dlbg.txt & dlbg.txt-1 only on ASR9k w/ XR
  10154. if ($proc =~ /ASR9K/ && /dlbg\.txt/) {
  10155. next;
  10156. }
  10157. if (/.*\((\d+) bytes free\)/) {
  10158. my($tmp) = $1;
  10159. if ($tmp >= (1024 * 1024 * 1024)) {
  10160. $tmp = int($tmp / (1024 * 1024 * 1024));
  10161. s/$1 bytes free/$tmp GB free/;
  10162. } else {
  10163. $tmp = int($tmp / (1024 * 1024));
  10164. s/$1 bytes free/$tmp MB free/;
  10165. }
  10166. }
  10167.  
  10168. ProcessHistory("FLASH","","","!Flash: $dev: $_");
  10169. }
  10170. ProcessHistory("","","","!\n");
  10171. return(0);
  10172. }
  10173.  
  10174. # This routine parses "admin show variables boot"
  10175. sub ShowBootVar {
  10176. print STDERR " In ShowBootVar: $_" if ($debug);
  10177.  
  10178. while (<INPUT>) {
  10179. # delete non-ascii chars, except new line
  10180. tr/ -~\n//cd;
  10181. last if (/^$prompt/);
  10182. next if (/\s*$cmd\s*$/);
  10183. return(1) if (/^\s*\^\s*$/);
  10184. return(1) if (/Line has invalid autocommand /);
  10185. return(1) if (/(Invalid (input|command) detected|Type help or )/i);
  10186. return(1) if (/Ambiguous command/i);
  10187. return(1) if (/(Open device \S+ failed|Error opening \S+:)/);
  10188. return(-1) if (/command authorization failed/i);
  10189.  
  10190. # skip blank lines
  10191. next if (/^\s*$/);
  10192.  
  10193. ProcessHistory("COMMENTS", "keysort", "C30", "! $_");
  10194. }
  10195. ProcessHistory("COMMENTS", "keysort", "C39", "!\n");
  10196.  
  10197. return(0);
  10198. }
  10199.  
  10200. # This routine parses "show controllers"
  10201. sub ShowContAll {
  10202. # Skip if this is a 70[01]0, 7500, or 12000.
  10203. print STDERR " In ShowContAll: $_" if ($debug);
  10204.  
  10205. while (<INPUT>) {
  10206. tr/\015//d;
  10207. last if (/^$prompt/);
  10208. next if (/^(\s*|\s*$cmd\s*)$/);
  10209. return(1) if (/(Invalid (input|command) detected|Type help or )/i);
  10210. # return(1) if ($type =~ /^(12[40]|7[05])/);
  10211. return(-1) if (/command authorization failed/i);
  10212.  
  10213. if (/^Interface ([^ \n(]*)/) { $INT = "$1, "; next; }
  10214. /^(BRI unit \d)/ &&
  10215. ProcessHistory("INT","","","!Interface: $1\n") && next;
  10216. /^LANCE unit \d, NIM/ &&
  10217. ProcessHistory("INT","","","!Interface: $_") && next;
  10218. /^(LANCE unit \d)/ &&
  10219. ProcessHistory("INT","","","!Interface: $1\n") && next;
  10220. /(Media Type is \S+),/ &&
  10221. ProcessHistory("INT","","","!\t$1\n");
  10222. if (/(M\dT[^ :]*:) show controller:$/) {
  10223. my($ctlr) = $1;
  10224. $_ = <INPUT>; tr/\015//d; s/ subunit \d,//;
  10225. ProcessHistory("INT","","","!Interface: $ctlr $_");
  10226. }
  10227. if (/^(\S+) : show controller:$/) {
  10228. my($ctlr) = $1;
  10229. $_ = <INPUT>; tr/\015//d; s/ subunit \d,//;
  10230. ProcessHistory("INT","","","!Interface: $ctlr: $_");
  10231. }
  10232. /^(HD unit \d), idb/ &&
  10233. ProcessHistory("INT","","","!Interface: $1\n") && next;
  10234. /^HD unit \d, NIM/ &&
  10235. ProcessHistory("INT","","","!Interface: $_") && next;
  10236. /^buffer size \d+ HD unit \d, (.*)/ &&
  10237. ProcessHistory("INT","","","!\t$1\n") && next;
  10238. /^AM79970 / && ProcessHistory("INT","","","!Interface: $_") && next;
  10239. /^buffer size \d+ (Universal Serial: .*)/ &&
  10240. ProcessHistory("INT","","","!\t$1\n") && next;
  10241. /^Hardware is (.*)/ &&
  10242. ProcessHistory("INT","","","!Interface: $INT$1\n") && next;
  10243. /^(QUICC Serial unit \d),/ &&
  10244. ProcessHistory("INT","","","!$1\n") && next;
  10245. /^QUICC Ethernet .*/ &&
  10246. ProcessHistory("INT","","","!$_") && next;
  10247. /^DTE .*\.$/ &&
  10248. ProcessHistory("INT","","","!\t$_") && next;
  10249. /^(cable type :.*),/ &&
  10250. ProcessHistory("INT","","","!\t$1\n") && next;
  10251. /^(.* cable.*), received clockrate \d+$/ &&
  10252. ProcessHistory("INT","","","!\t$1\n") && next;
  10253. /^.* cable.*$/ &&
  10254. ProcessHistory("INT","","","!\t$_") && next;
  10255. }
  10256. return(0);
  10257. }
  10258.  
  10259. # This routine parses "show debug"
  10260. sub ShowDebug {
  10261. print STDERR " In ShowDebug: $_" if ($debug);
  10262. my($lines) = 0;
  10263.  
  10264. while (<INPUT>) {
  10265. tr/\015//d;
  10266. last if (/^$prompt/);
  10267. next if (/^(\s*|\s*$cmd\s*)$/);
  10268. return(1) if (/Line has invalid autocommand /);
  10269. return(1) if (/(Invalid (input|command) detected|Type help or )/i);
  10270. return(-1) if (/command authorization failed/i);
  10271.  
  10272. /^No matching debug flags set$/ && next;
  10273. /^No debug flags set$/ && next;
  10274. ProcessHistory("COMMENTS","keysort","J1","!DEBUG: $_");
  10275. $lines++;
  10276. }
  10277. if ($lines) {
  10278. ProcessHistory("COMMENTS","keysort","J0","!\n");
  10279. }
  10280. return(0);
  10281. }
  10282.  
  10283. # This routine parses "admin show install summary"
  10284. sub ShowInstallSummary {
  10285. print STDERR " In ShowInstallSummary: $_" if ($debug);
  10286.  
  10287. while (<INPUT>) {
  10288. # delete non-ascii chars, except new line
  10289. tr/ -~\n//cd;
  10290. last if (/^$prompt/);
  10291. next if (/\s*$cmd\s*$/);
  10292. return(1) if (/^\s*\^\s*$/);
  10293. return(1) if (/Line has invalid autocommand /);
  10294. return(1) if (/(Invalid (input|command) detected|Type help or )/i);
  10295. return(1) if (/Ambiguous command/i);
  10296. return(1) if (/(Open device \S+ failed|Error opening \S+:)/);
  10297. return(-1) if (/command authorization failed/i);
  10298.  
  10299. # skip blank lines
  10300. next if (/^\s*$/);
  10301.  
  10302. ProcessHistory("COMMENTS", "keysort", "C15", "! $_");
  10303. }
  10304. ProcessHistory("COMMENTS", "keysort", "C10", "!\n");
  10305. ProcessHistory("COMMENTS", "keysort", "C19", "!\n");
  10306.  
  10307. return(0);
  10308. }
  10309.  
  10310. # This routine parses "show inventory".
  10311. sub ShowInventory {
  10312. print STDERR " In ShowInventory: $_" if ($debug);
  10313.  
  10314. while (<INPUT>) {
  10315. # delete non-ascii chars, except new line
  10316. tr/ -~\n//cd;
  10317. return if (/^\s*\^$/);
  10318. last if (/^$prompt/);
  10319. next if (/^(\s*|\s*$cmd\s*)$/);
  10320. return(1) if (/Line has invalid autocommand /);
  10321. return(1) if (/(Invalid (input|command) detected|Type help or )/i);
  10322. return(-1) if (/command authorization failed/i);
  10323.  
  10324. # remove spaces after quotes
  10325. s/\"\s+/\"/g;
  10326. if (/^(NAME: "[^"]*",) (DESCR: "[^"]+")/) {
  10327. ProcessHistory("INVENTORY","","", sprintf("!%-30s %s\n", $1, $2));
  10328. next;
  10329. }
  10330. # split PID/VID/SN line
  10331. if (/^PID: (\S*)\s*, VID: (\S*)\s*, SN: (\S*)\s*$/) {
  10332. my($pid,$vid,$sn) = ($1, $2, $3);
  10333. my($entries) = "";
  10334. # filter <empty>, "0x" and "N/A" lines
  10335. if ($pid !~ /^(|0x|N\/A)$/) {
  10336. $entries .= "!PID: $pid\n";
  10337. }
  10338. if ($vid !~ /^(|0x|N\/A)$/) {
  10339. $entries .= "!VID: $vid\n";
  10340. }
  10341. if ($sn !~ /^(|0x|N\/A)$/) {
  10342. $entries .= "!SN: $sn\n";
  10343. }
  10344. ProcessHistory("INVENTORY","","", "$entries");
  10345. next;
  10346. }
  10347. ProcessHistory("INVENTORY","","","!$_");
  10348. }
  10349. ProcessHistory("INVENTORY","","","!\n");
  10350.  
  10351. return(0);
  10352. }
  10353.  
  10354. # This routine parses "admin show license"
  10355. sub ShowLicense {
  10356. print STDERR " In ShowLicense: $_" if ($debug);
  10357.  
  10358. while (<INPUT>) {
  10359. # delete non-ascii chars, except new line
  10360. tr/ -~\n//cd;
  10361. last if (/^$prompt/);
  10362. next if (/\s*$cmd\s*$/);
  10363. return(1) if (/^\s*\^\s*$/);
  10364. return(1) if (/Line has invalid autocommand /);
  10365. return(1) if (/(Invalid (input|command) detected|Type help or )/i);
  10366. return(1) if (/Ambiguous command/i);
  10367. return(1) if (/(Open device \S+ failed|Error opening \S+:)/);
  10368. return(-1) if (/command authorization failed/i);
  10369.  
  10370. # skip blank lines
  10371. next if (/^\s*$/);
  10372.  
  10373. ProcessHistory("COMMENTS", "keysort", "C20", "! $_");
  10374. }
  10375. ProcessHistory("COMMENTS", "keysort", "C29", "!\n");
  10376.  
  10377. return(0);
  10378. }
  10379.  
  10380. # This routine parses "show rpl maximum"
  10381. sub ShowRPL {
  10382. print STDERR " In ShowRPL: $_" if ($debug);
  10383.  
  10384. while (<INPUT>) {
  10385. tr/\015//d;
  10386. last if (/^$prompt/);
  10387. next if (/^(\s*|\s*$cmd\s*)$/);
  10388. return(1) if /^\s*\^\s*$/;
  10389. return(1) if (/Line has invalid autocommand /);
  10390. return(1) if (/(Invalid (input|command) detected|Type help or )/i);
  10391. return(1) if (/Ambiguous command/i);
  10392. return(-1) if (/command authorization failed/i);
  10393.  
  10394. ProcessHistory("COMMENTS","keysort","RPLMAX","! $_");
  10395. }
  10396. ProcessHistory("COMMENTS","keysort","RPLMAX","!\n");
  10397. return(0);
  10398. }
  10399.  
  10400. # This routine parses "show vlan"
  10401. sub ShowVLAN {
  10402. print STDERR " In ShowVLAN: $_" if ($debug);
  10403.  
  10404. ($_ = <INPUT>, return(1)) if (!$DO_SHOW_VLAN);
  10405.  
  10406. while (<INPUT>) {
  10407. tr/\015//d;
  10408. last if (/^$prompt/);
  10409. next if (/^(\s*|\s*$cmd\s*)$/);
  10410. return(1) if /^\s*\^\s*$/;
  10411. return(1) if (/Line has invalid autocommand /);
  10412. return(1) if (/(Invalid (input|command) detected|Type help or )/i);
  10413. return(1) if (/Ambiguous command/i);
  10414. return(-1) if (/command authorization failed/i);
  10415.  
  10416. ProcessHistory("COMMENTS","keysort","IO","!VLAN: $_");
  10417. }
  10418. ProcessHistory("COMMENTS","keysort","IO","!\n");
  10419. return(0);
  10420. }
  10421.  
  10422. # This routine processes a "write term"
  10423. sub WriteTerm {
  10424. print STDERR " In WriteTerm: $_" if ($debug);
  10425. my($lineauto,$comment,$linecnt) = (0,0,0);
  10426.  
  10427. while (<INPUT>) {
  10428. tr/\015//d;
  10429. last if (/^$prompt/);
  10430. return(1) if (!$linecnt && /^\s+\^\s*$/);
  10431. return(1) if (/Line has invalid autocommand /);
  10432. return(1) if (/(Invalid (input|command) detected|Type help or )/i);
  10433. return(1) if (/\%Error: No such file or directory/);
  10434. return(0) if ($found_end); # Only do this routine once
  10435. return(-1) if (/command authorization failed/i);
  10436. return(-1) if (/% ?configuration buffer full/i);
  10437. /^! no configuration change since last restart/i && next;
  10438. # skip emtpy lines at the beginning
  10439. if (!$linecnt && /^\s*$/) {
  10440. next;
  10441. }
  10442. if (!$linecnt && defined($config_register)) {
  10443. ProcessHistory("","","", "!\nconfig-register $config_register\n");
  10444. }
  10445.  
  10446. /Non-Volatile memory is in use/ && return(-1); # NvRAM is locked
  10447. /% Configuration buffer full, / && return(-1); # buffer is in use
  10448. $linecnt++;
  10449. $lineauto = 0 if (/^[^ ]/);
  10450. # skip the crap
  10451. if (/^(##+|(building|current) configuration)/i) {
  10452. while (<INPUT>) {
  10453. next if (/^Current configuration\s*:/i);
  10454. next if (/^:/);
  10455. next if (/^([%!].*|\s*)$/);
  10456. next if (/^ip add.*ipv4:/); # band-aid for 3620 12.0S
  10457. last;
  10458. }
  10459. tr/\015//d;
  10460. }
  10461. # some versions have other crap mixed in with the bits in the
  10462. # block above
  10463. /^! (Last configuration|NVRAM config last)/ && next;
  10464. # and for the ASA
  10465. /^: (Written by \S+ at|Saved)/ && next;
  10466.  
  10467. # skip consecutive comment lines to avoid oscillating extra comment
  10468. # line on some access servers. grrr.
  10469. if (/^!\s*$/) {
  10470. next if ($comment);
  10471. ProcessHistory("","","",$_);
  10472. $comment++;
  10473. next;
  10474. }
  10475. $comment = 0;
  10476.  
  10477. # Dog gone Cool matches to process the rest of the config
  10478. /^tftp-server flash / && next; # kill any tftp remains
  10479. /^ntp clock-period / && next; # kill ntp clock-period
  10480. /^ length / && next; # kill length on serial lines
  10481. /^ width / && next; # kill width on serial lines
  10482. $lineauto = 1 if /^ modem auto/;
  10483. /^ speed / && $lineauto && next; # kill speed on serial lines
  10484. /^ clockrate / && next; # kill clockrate on serial interfaces
  10485. if (/^(enable )?(password|passwd)( level \d+)? / && $filter_pwds >= 1) {
  10486. ProcessHistory("ENABLE","","","!$1$2$3 <removed>\n");
  10487. next;
  10488. }
  10489. if (/^(enable secret) / && $filter_pwds >= 2) {
  10490. ProcessHistory("ENABLE","","","!$1 <removed>\n");
  10491. next;
  10492. }
  10493. if (/^username (\S+)(\s.*)? secret /) {
  10494. if ($filter_pwds >= 2) {
  10495. ProcessHistory("USER","keysort","$1",
  10496. "!username $1$2 secret <removed>\n");
  10497. } else {
  10498. ProcessHistory("USER","keysort","$1","$_");
  10499. }
  10500. next;
  10501. }
  10502. if (/^username (\S+)(\s.*)? password ((\d) \S+|\S+)/) {
  10503. if ($filter_pwds >= 2) {
  10504. ProcessHistory("USER","keysort","$1",
  10505. "!username $1$2 password <removed>\n");
  10506. } elsif ($filter_pwds >= 1 && $4 ne "5"){
  10507. ProcessHistory("USER","keysort","$1",
  10508. "!username $1$2 password <removed>\n");
  10509. } else {
  10510. ProcessHistory("USER","keysort","$1","$_");
  10511. }
  10512. next;
  10513. }
  10514. if (/^( set session-key (in|out)bound ah \d+ )/ && $filter_pwds >= 1) {
  10515. ProcessHistory("","","","!$1<removed>\n");
  10516. next;
  10517. }
  10518. if (/^( set session-key (in|out)bound esp \d+ (authenticator|cypher) )/
  10519. && $filter_pwds >= 1) {
  10520. ProcessHistory("","","","!$1<removed>\n");
  10521. next;
  10522. }
  10523. if (/^(\s*)password / && $filter_pwds >= 1) {
  10524. ProcessHistory("LINE-PASS","","","!$1password <removed>\n");
  10525. next;
  10526. }
  10527. if (/^(\s*)secret / && $filter_pwds >= 2) {
  10528. ProcessHistory("LINE-PASS","","","!$1secret <removed>\n");
  10529. next;
  10530. }
  10531. if (/^\s*neighbor (\S*) password / && $filter_pwds >= 1) {
  10532. ProcessHistory("","","","! neighbor $1 password <removed>\n");
  10533. next;
  10534. }
  10535. if (/^(ppp .* password) 7 .*/ && $filter_pwds >= 1) {
  10536. ProcessHistory("","","","!$1 <removed>\n"); next;
  10537. }
  10538. if (/^(ip ftp password) / && $filter_pwds >= 1) {
  10539. ProcessHistory("","","","!$1 <removed>\n"); next;
  10540. }
  10541. if (/^( ip ospf authentication-key) / && $filter_pwds >= 1) {
  10542. ProcessHistory("","","","!$1 <removed>\n"); next;
  10543. }
  10544. # isis passwords appear to be completely plain-text
  10545. if (/^\s+isis password (\S+)( .*)?/ && $filter_pwds >= 1) {
  10546. ProcessHistory("","","","!isis password <removed>$2\n"); next;
  10547. }
  10548. if (/^\s+(domain-password|area-password) (\S+)( .*)?/
  10549. && $filter_pwds >= 1) {
  10550. ProcessHistory("","","","!$1 <removed>$3\n"); next;
  10551. }
  10552. # this is reversable, despite 'md5' in the cmd
  10553. if (/^( ip ospf message-digest-key \d+ md5) / && $filter_pwds >= 1) {
  10554. ProcessHistory("","","","!$1 <removed>\n"); next;
  10555. }
  10556. # this is also reversable, despite 'md5 encrypted' in the cmd
  10557. if (/^( message-digest-key \d+ md5 (7|encrypted)) /
  10558. && $filter_pwds >= 1) {
  10559. ProcessHistory("","","","!$1 <removed>\n"); next;
  10560. }
  10561. if (/^((crypto )?isakmp key) \S+ / && $filter_pwds >= 1) {
  10562. ProcessHistory("","","","!$1 <removed> $'"); next;
  10563. }
  10564. # filter HSRP passwords
  10565. if (/^(\s+standby \d+ authentication) / && $filter_pwds >= 1) {
  10566. ProcessHistory("","","","!$1 <removed>\n"); next;
  10567. }
  10568. # this appears in "measurement/sla" images
  10569. if (/^(\s+key-string \d?)/ && $filter_pwds >= 1) {
  10570. ProcessHistory("","","","!$1 <removed>\n"); next;
  10571. }
  10572. if (/^( l2tp tunnel \S+ password)/ && $filter_pwds >= 1) {
  10573. ProcessHistory("","","","!$1 <removed>\n"); next;
  10574. }
  10575. # i am told these are plain-text on the PIX
  10576. if (/^(vpdn username (\S+) password)/) {
  10577. if ($filter_pwds >= 1) {
  10578. ProcessHistory("USER","keysort","$2","!$1 <removed>\n");
  10579. } else {
  10580. ProcessHistory("USER","keysort","$2","$_");
  10581. }
  10582. next;
  10583. }
  10584. # ASA/PIX keys in more system:running-config
  10585. if (/^( pre-shared-key | key |failover key ).*/ && $filter_pwds >= 1) {
  10586. ProcessHistory("","","","!$1 <removed> $'"); next;
  10587. }
  10588. if (/(\s+ldap-login-password )\S+(.*)/ && $filter_pwds >= 1) {
  10589. ProcessHistory("","","","!$1 <removed> $'"); next;
  10590. }
  10591. #
  10592. if (/^( cable shared-secret )/ && $filter_pwds >= 1) {
  10593. ProcessHistory("","","","!$1 <removed>\n");
  10594. next;
  10595. }
  10596. /fair-queue individual-limit/ && next;
  10597. # sort ip explicit-paths.
  10598. if (/^ip explicit-path name (\S+)/) {
  10599. my($key) = $1;
  10600. my($expath) = $_;
  10601. while (<INPUT>) {
  10602. tr/\015//d;
  10603. last if (/^$prompt/);
  10604. last if (! /^(ip explicit-path name |[ !])/);
  10605. if (/^ip explicit-path name (\S+)/) {
  10606. ProcessHistory("EXPATH","keysort","$key","$expath");
  10607. $key = $1;
  10608. $expath = $_;
  10609. } else {
  10610. $expath .= $_;
  10611. }
  10612. }
  10613. ProcessHistory("EXPATH","keysort","$key","$expath");
  10614. }
  10615. # sort route-maps
  10616. if (/^route-map (\S+)/) {
  10617. my($key) = $1;
  10618. my($routemap) = $_;
  10619. while (<INPUT>) {
  10620. tr/\015//d;
  10621. last if (/^$prompt/ || ! /^(route-map |[ !])/);
  10622. if (/^route-map (\S+)/) {
  10623. ProcessHistory("ROUTEMAP","keysort","$key","$routemap");
  10624. $key = $1;
  10625. $routemap = $_;
  10626. } else {
  10627. $routemap .= $_;
  10628. }
  10629. }
  10630. ProcessHistory("ROUTEMAP","keysort","$key","$routemap");
  10631. }
  10632. # filter out any RCS/CVS tags to avoid confusing local CVS storage
  10633. s/\$(Revision|Id):/ $1:/;
  10634. # order access-lists
  10635. /^access-list\s+(\d\d?)\s+(\S+)\s+(\S+)/ &&
  10636. ProcessHistory("ACL $1 $2","$aclsort","$3","$_") && next;
  10637. # order extended access-lists
  10638. /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+host\s+(\S+)/ &&
  10639. ProcessHistory("EACL $1 $2","$aclsort","$3","$_") && next;
  10640. /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+(\d\S+)/ &&
  10641. ProcessHistory("EACL $1 $2","$aclsort","$3","$_") && next;
  10642. /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+any/ &&
  10643. ProcessHistory("EACL $1 $2","$aclsort","0.0.0.0","$_") && next;
  10644. # sort ipv{4,6} access-lists
  10645. if (/^ipv(4|6) access-list (\S+)\s*$/) {
  10646. my($nlri, $key) = ($1, $2);
  10647. my($seq, $cmd);
  10648. ProcessHistory("ACL $nlri $key","","","$_");
  10649. while (<INPUT>) {
  10650. tr/\015//d;
  10651. last if (/^$prompt/ || /^\S/);
  10652. ($seq, $cmd, $misc, $ip) = ($_ =~ /^\s+(\d+) (\w+) (.*\s)(\w+)/);
  10653. if ($cmd =~ /(permit|deny)/) {
  10654. ProcessHistory("ACL $nlri $key $cmd","$aclsort","$ip",
  10655. " $cmd $misc$ip\n");
  10656. } else {
  10657. ProcessHistory("ACL $nlri $key","",""," $cmd $misc$ip\n");
  10658. }
  10659. }
  10660. }
  10661. # order arp lists
  10662. /^arp\s+(\d+\.\d+\.\d+\.\d+)\s+/ &&
  10663. ProcessHistory("ARP","$aclsort","$1","$_") && next;
  10664. /^ip prefix-list\s+(\S+)\s+seq\s+(\d+)\s+(permit|deny)\s+(\d\S+)(\/.*)$/ &&
  10665. ProcessHistory("PACL $1 $3","$aclsort","$4","ip prefix-list $1 $3 $4$5\n")
  10666. && next;
  10667. # order logging statements
  10668. /^logging (\d+\.\d+\.\d+\.\d+)/ &&
  10669. ProcessHistory("LOGGING","ipsort","$1","$_") && next;
  10670. # order/prune snmp-server host statements
  10671. # we only prune lines of the form
  10672. # snmp-server host a.b.c.d <community>
  10673. if (/^snmp-server host (\d+\.\d+\.\d+\.\d+) /) {
  10674. if ($filter_commstr) {
  10675. my($ip) = $1;
  10676. my($line) = "snmp-server host $ip";
  10677. my(@tokens) = split(' ', $');
  10678. my($token);
  10679. while ($token = shift(@tokens)) {
  10680. if ($token eq 'version') {
  10681. $line .= " " . join(' ', ($token, shift(@tokens)));
  10682. if ($token eq '3') {
  10683. $line .= " " . join(' ', ($token, shift(@tokens)));
  10684. }
  10685. } elsif ($token eq 'vrf') {
  10686. $line .= " " . join(' ', ($token, shift(@tokens)));
  10687. } elsif ($token =~ /^(informs?|traps?|(no)?auth)$/) {
  10688. $line .= " " . $token;
  10689. } else {
  10690. $line = "!$line " . join(' ', ("<removed>",
  10691. join(' ',@tokens)));
  10692. last;
  10693. }
  10694. }
  10695. ProcessHistory("SNMPSERVERHOST","ipsort","$ip","$line\n");
  10696. } else {
  10697. ProcessHistory("SNMPSERVERHOST","ipsort","$1","$_");
  10698. }
  10699. next;
  10700. }
  10701. if (/^(snmp-server community) (\S+)/) {
  10702. if ($filter_commstr) {
  10703. ProcessHistory("SNMPSERVERCOMM","keysort","$_",
  10704. "!$1 <removed>$'") && next;
  10705. } else {
  10706. ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && next;
  10707. }
  10708. }
  10709. # prune tacacs/radius server keys
  10710. if (/^((tacacs|radius)-server\s(\w*[-\s(\s\S+])*\s?key) (\d )?\w+/
  10711. && $filter_pwds >= 1) {
  10712. ProcessHistory("","","","!$1 <removed>$'"); next;
  10713. }
  10714. # order clns host statements
  10715. /^clns host \S+ (\S+)/ &&
  10716. ProcessHistory("CLNS","keysort","$1","$_") && next;
  10717. # order alias statements
  10718. /^alias / && ProcessHistory("ALIAS","keysort","$_","$_") && next;
  10719. # delete ntp auth password - this md5 is a reversable too
  10720. if (/^(ntp authentication-key \d+ md5) / && $filter_pwds >= 1) {
  10721. ProcessHistory("","","","!$1 <removed>\n"); next;
  10722. }
  10723. # order ntp peers/servers
  10724. if (/^ntp (server|peer) (\d+)\.(\d+)\.(\d+)\.(\d+)/) {
  10725. $sortkey = sprintf("$1 %03d%03d%03d%03d",$2,$3,$4,$5);
  10726. ProcessHistory("NTP","keysort",$sortkey,"$_");
  10727. next;
  10728. }
  10729. # order ip host statements
  10730. /^ip host (\S+) / &&
  10731. ProcessHistory("IPHOST","keysort","$1","$_") && next;
  10732. # order ip nat source static statements
  10733. /^ip nat (\S+) source static (\S+)/ &&
  10734. ProcessHistory("IP NAT $1","ipsort","$2","$_") && next;
  10735. # order atm map-list statements
  10736. /^\s+ip\s+(\d+\.\d+\.\d+\.\d+)\s+atm-vc/ &&
  10737. ProcessHistory("ATM map-list","ipsort","$1","$_") && next;
  10738. # order ip rcmd lines
  10739. /^ip rcmd/ && ProcessHistory("RCMD","keysort","$_","$_") && next;
  10740.  
  10741. # system controller
  10742. /^syscon address (\S*) (\S*)/ &&
  10743. ProcessHistory("","","","!syscon address $1 <removed>\n") &&
  10744. next;
  10745. if (/^syscon password (\S*)/ && $filter_pwds >= 1) {
  10746. ProcessHistory("","","","!syscon password <removed>\n");
  10747. next;
  10748. }
  10749.  
  10750. /^ *Cryptochecksum:/ && next;
  10751.  
  10752. # catch anything that wasnt matched above.
  10753. ProcessHistory("","","","$_");
  10754. # end of config.
  10755. if (/^end$/) {
  10756. $found_end = 1;
  10757. return(0);
  10758. }
  10759. }
  10760.  
  10761. return(0);
  10762. }
  10763.  
  10764. # This routine processes a "write term"
  10765. sub FilterAll {
  10766. print STDERR " In FilterAll: $_" if ($debug);
  10767.  
  10768. while (<INPUT>) {
  10769. tr/\015//d;
  10770. last if (/^$prompt/);
  10771. return(1) if (/Line has invalid autocommand /);
  10772. return(1) if (/(Invalid (input|command) detected|Type help or )/i);
  10773. return(1) if (/\%Error: No such file or directory/);
  10774. return(-1) if (/command authorization failed/i);
  10775. return(-1) if (/% ?configuration buffer full/i);
  10776. }
  10777. }
  10778.  
  10779. # dummy function
  10780. sub DoNothing {print STDOUT;}
  10781.  
  10782. # Main
  10783. @commandtable = (
  10784. # Disable timestamps in output
  10785. {'terminal no-timestamp' => 'FilterAll' }, # XR 3.6 style
  10786. {'terminal exec prompt no-timestamp' => 'FilterAll' }, # XR 3.8 style
  10787.  
  10788. {'admin show version' => 'ShowVersion'},
  10789.  
  10790. # XR IMAGE commands
  10791. {'admin show install summary' => 'ShowInstallSummary'},
  10792. {'admin show license' => 'ShowLicense'},
  10793. {'admin show variables boot' => 'ShowBootVar'},
  10794.  
  10795. {'show redundancy secondary' => 'ShowRedundancy'},
  10796. {'show install active' => 'ShowInstallActive'},
  10797. {'admin show env all' => 'ShowEnv'},
  10798. {'dir /all nvram:' => 'DirSlotN'},
  10799. {'dir /all bootflash:' => 'DirSlotN'},
  10800. {'dir /all compactflash:' => 'DirSlotN'},
  10801. {'dir /all compactflasha:' => 'DirSlotN'},
  10802. {'dir /all slot0:' => 'DirSlotN'},
  10803. {'dir /all disk0:' => 'DirSlotN'},
  10804. {'dir /all disk0a:' => 'DirSlotN'},
  10805. {'dir /all slot1:' => 'DirSlotN'},
  10806. {'dir /all disk1:' => 'DirSlotN'},
  10807. {'dir /all disk1a:' => 'DirSlotN'},
  10808. {'dir /all slot2:' => 'DirSlotN'},
  10809. {'dir /all disk2:' => 'DirSlotN'},
  10810. {'dir /all harddisk:' => 'DirSlotN'},
  10811. {'dir /all harddiska:' => 'DirSlotN'},
  10812. {'dir /all harddiskb:' => 'DirSlotN'},
  10813. {'dir /all slavenvram:' => 'DirSlotN'},
  10814. {'dir /all slavebootflash:' => 'DirSlotN'},
  10815. {'dir /all slaveslot0:' => 'DirSlotN'},
  10816. {'dir /all slavedisk0:' => 'DirSlotN'},
  10817. {'dir /all slaveslot1:' => 'DirSlotN'},
  10818. {'dir /all slavedisk1:' => 'DirSlotN'},
  10819. {'dir /all slaveslot2:' => 'DirSlotN'},
  10820. {'dir /all slavedisk2:' => 'DirSlotN'},
  10821. {'dir /all sec-nvram:' => 'DirSlotN'},
  10822. {'dir /all sec-bootflash:' => 'DirSlotN'},
  10823. {'dir /all sec-slot0:' => 'DirSlotN'},
  10824. {'dir /all sec-disk0:' => 'DirSlotN'},
  10825. {'dir /all sec-slot1:' => 'DirSlotN'},
  10826. {'dir /all sec-disk1:' => 'DirSlotN'},
  10827. {'dir /all sec-slot2:' => 'DirSlotN'},
  10828. {'dir /all sec-disk2:' => 'DirSlotN'},
  10829. {'show controllers' => 'ShowContAll'},
  10830. {'admin show running' => 'AdminShowRunning'},
  10831. {'admin show diag' => 'AdminShowDiag'},
  10832. {'admin show inventory raw' => 'ShowInventory'},
  10833. {'show vlan' => 'ShowVLAN'},
  10834. {'show debug' => 'ShowDebug'},
  10835. {'show rpl maximum' => 'ShowRPL'},
  10836. {'show running-config' => 'WriteTerm'},
  10837. );
  10838. # Use an array to preserve the order of the commands and a hash for mapping
  10839. # commands to the subroutine and track commands that have been completed.
  10840. @commands = map(keys(%$_), @commandtable);
  10841. %commands = map(%$_, @commandtable);
  10842.  
  10843. $cisco_cmds = join(";",@commands);
  10844. $cmds_regexp = join("|", map quotemeta($_), @commands);
  10845.  
  10846. if (length($host) == 0) {
  10847. if ($file) {
  10848. print(STDERR "Too few arguments: file name required\n");
  10849. exit(1);
  10850. } else {
  10851. print(STDERR "Too few arguments: host name required\n");
  10852. exit(1);
  10853. }
  10854. }
  10855. open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n";
  10856. select(OUTPUT);
  10857. # make OUTPUT unbuffered if debugging
  10858. if ($debug) { $| = 1; }
  10859.  
  10860. if ($file) {
  10861. print STDERR "opening file $host\n" if ($debug);
  10862. print STDOUT "opening file $host\n" if ($log);
  10863. open(INPUT,"<$host") || die "open failed for $host: $!\n";
  10864. } else {
  10865. print STDERR "executing clogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($debug);
  10866. print STDOUT "executing clogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($log);
  10867. if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
  10868. system "clogin -t $timeo -c \"$cisco_cmds\" $host </dev/null > $host.raw 2>&1" || die "clogin failed for $host: $!\n";
  10869. open(INPUT, "< $host.raw") || die "clogin failed for $host: $!\n";
  10870. } else {
  10871. open(INPUT,"clogin -t $timeo -c \"$cisco_cmds\" $host </dev/null |") || die "clogin failed for $host: $!\n";
  10872. }
  10873. }
  10874.  
  10875. # determine ACL sorting mode
  10876. if ($ENV{"ACLSORT"} =~ /no/i) {
  10877. $aclsort = "";
  10878. }
  10879. # determine community string filtering mode
  10880. if (defined($ENV{"NOCOMMSTR"}) &&
  10881. ($ENV{"NOCOMMSTR"} =~ /yes/i || $ENV{"NOCOMMSTR"} =~ /^$/)) {
  10882. $filter_commstr = 1;
  10883. } else {
  10884. $filter_commstr = 0;
  10885. }
  10886. # determine password filtering mode
  10887. if ($ENV{"FILTER_PWDS"} =~ /no/i) {
  10888. $filter_pwds = 0;
  10889. } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) {
  10890. $filter_pwds = 2;
  10891. } else {
  10892. $filter_pwds = 1;
  10893. }
  10894.  
  10895. ProcessHistory("","","","!RANCID-CONTENT-TYPE: cisco-xr\n!\n");
  10896. ProcessHistory("COMMENTS","keysort","B0","!\n");
  10897. ProcessHistory("COMMENTS","keysort","D0","!\n");
  10898. ProcessHistory("COMMENTS","keysort","F0","!\n");
  10899. ProcessHistory("COMMENTS","keysort","G0","!\n");
  10900. TOP: while(<INPUT>) {
  10901. tr/\015//d;
  10902. if (/[>#]\s?exit$/) {
  10903. $clean_run = 1;
  10904. last;
  10905. }
  10906. if (/^Error:/) {
  10907. print STDOUT ("$host clogin error: $_");
  10908. print STDERR ("$host clogin error: $_") if ($debug);
  10909. $clean_run = 0;
  10910. last;
  10911. }
  10912. while (/#\s*($cmds_regexp)\s*$/) {
  10913. $cmd = $1;
  10914. if (!defined($prompt)) {
  10915. $prompt = ($_ =~ /^([^#]+#)/)[0];
  10916. $prompt =~ s/([][}{)(\\])/\\$1/g;
  10917. print STDERR ("PROMPT MATCH: $prompt\n") if ($debug);
  10918. }
  10919. print STDERR ("HIT COMMAND:$_") if ($debug);
  10920. if (! defined($commands{$cmd})) {
  10921. print STDERR "$host: found unexpected command - \"$cmd\"\n";
  10922. $clean_run = 0;
  10923. last TOP;
  10924. }
  10925. $rval = &{$commands{$cmd}};
  10926. delete($commands{$cmd});
  10927. if ($rval == -1) {
  10928. $clean_run = 0;
  10929. last TOP;
  10930. }
  10931. }
  10932. }
  10933. print STDOUT "Done $logincmd: $_\n" if ($log);
  10934. # Flush History
  10935. ProcessHistory("","","","");
  10936. # Cleanup
  10937. close(INPUT);
  10938. close(OUTPUT);
  10939.  
  10940. if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
  10941. unlink("$host.raw") if (! $debug);
  10942. }
  10943.  
  10944. # check for completeness
  10945. if (scalar(%commands) || !$clean_run || !$found_end) {
  10946. if (scalar(%commands)) {
  10947. printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands)));
  10948. printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug);
  10949. }
  10950. if (!$clean_run || !$found_end) {
  10951. print STDOUT "$host: End of run not found\n";
  10952. print STDERR "$host: End of run not found\n" if ($debug);
  10953. system("/usr/bin/tail -1 $host.new");
  10954. }
  10955. unlink "$host.new" if (! $debug);
  10956. }
  10957. #! /usr/bin/perl
  10958. ##
  10959. ## $Id: zrancid.in 3135 2015-07-02 18:59:15Z heas $
  10960. ##
  10961. ## rancid 3.4.1
  10962. ## Copyright (c) 1997-2016 by Terrapin Communications, Inc.
  10963. ## All rights reserved.
  10964. ##
  10965. ## This code is derived from software contributed to and maintained by
  10966. ## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan,
  10967. ## Pete Whiting, Austin Schutz, and Andrew Fort.
  10968. ##
  10969. ## Redistribution and use in source and binary forms, with or without
  10970. ## modification, are permitted provided that the following conditions
  10971. ## are met:
  10972. ## 1. Redistributions of source code must retain the above copyright
  10973. ## notice, this list of conditions and the following disclaimer.
  10974. ## 2. Redistributions in binary form must reproduce the above copyright
  10975. ## notice, this list of conditions and the following disclaimer in the
  10976. ## documentation and/or other materials provided with the distribution.
  10977. ## 3. All advertising materials mentioning features or use of this software
  10978. ## must display the following acknowledgement:
  10979. ## This product includes software developed by Terrapin Communications,
  10980. ## Inc. and its contributors for RANCID.
  10981. ## 4. Neither the name of Terrapin Communications, Inc. nor the names of its
  10982. ## contributors may be used to endorse or promote products derived from
  10983. ## this software without specific prior written permission.
  10984. ## 5. It is requested that non-binding fixes and modifications be contributed
  10985. ## back to Terrapin Communications, Inc.
  10986. ##
  10987. ## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS
  10988. ## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  10989. ## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  10990. ## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
  10991. ## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  10992. ## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  10993. ## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  10994. ## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  10995. ## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  10996. ## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  10997. ## POSSIBILITY OF SUCH DAMAGE.
  10998. #
  10999. # This version of rancid tries to deal with zebra s/w.
  11000. #
  11001. # RANCID - Really Awesome New Cisco confIg Differ
  11002. #
  11003. # usage: zrancid [-dltCV] [-f filename | hostname]
  11004. #
  11005. use Getopt::Std;
  11006. getopts('dflt:CV');
  11007. if ($opt_V) {
  11008. print "rancid 3.4.1\n";
  11009. exit(0);
  11010. }
  11011. $log = $opt_l;
  11012. $debug = $opt_d;
  11013. $file = $opt_f;
  11014. $host = $ARGV[0];
  11015. $clean_run = 0;
  11016. $found_end = 0;
  11017. $timeo = 90; # clogin timeout in seconds
  11018.  
  11019. my(@commandtable, %commands, @commands);# command lists
  11020. my($aclsort) = ("ipsort"); # ACL sorting mode
  11021. my($filter_commstr); # SNMP community string filtering
  11022. my($filter_pwds); # password filtering mode
  11023.  
  11024. # force a terminal type so as not to confuse Linux
  11025. $ENV{'TERM'} = "ansi";
  11026.  
  11027. # This routine is used to print out the router configuration
  11028. sub ProcessHistory {
  11029. my($new_hist_tag,$new_command,$command_string,@string) = (@_);
  11030. if ((($new_hist_tag ne $hist_tag) || ($new_command ne $command))
  11031. && scalar(%history)) {
  11032. print eval "$command \%history";
  11033. undef %history;
  11034. }
  11035. if (($new_hist_tag) && ($new_command) && ($command_string)) {
  11036. if ($history{$command_string}) {
  11037. $history{$command_string} = "$history{$command_string}@string";
  11038. } else {
  11039. $history{$command_string} = "@string";
  11040. }
  11041. } elsif (($new_hist_tag) && ($new_command)) {
  11042. $history{++$#history} = "@string";
  11043. } else {
  11044. print "@string";
  11045. }
  11046. $hist_tag = $new_hist_tag;
  11047. $command = $new_command;
  11048. 1;
  11049. }
  11050.  
  11051. sub numerically { $a <=> $b; }
  11052.  
  11053. # This is a sort routine that will sort numerically on the
  11054. # keys of a hash as if it were a normal array.
  11055. sub keynsort {
  11056. local(%lines) = @_;
  11057. local($i) = 0;
  11058. local(@sorted_lines);
  11059. foreach $key (sort numerically keys(%lines)) {
  11060. $sorted_lines[$i] = $lines{$key};
  11061. $i++;
  11062. }
  11063. @sorted_lines;
  11064. }
  11065.  
  11066. # This is a sort routine that will sort on the
  11067. # keys of a hash as if it were a normal array.
  11068. sub keysort {
  11069. local(%lines) = @_;
  11070. local($i) = 0;
  11071. local(@sorted_lines);
  11072. foreach $key (sort keys(%lines)) {
  11073. $sorted_lines[$i] = $lines{$key};
  11074. $i++;
  11075. }
  11076. @sorted_lines;
  11077. }
  11078.  
  11079. # This is a sort routine that will sort on the
  11080. # values of a hash as if it were a normal array.
  11081. sub valsort{
  11082. local(%lines) = @_;
  11083. local($i) = 0;
  11084. local(@sorted_lines);
  11085. foreach $key (sort values %lines) {
  11086. $sorted_lines[$i] = $key;
  11087. $i++;
  11088. }
  11089. @sorted_lines;
  11090. }
  11091.  
  11092. # This is a numerical sort routine (ascending).
  11093. sub numsort {
  11094. local(%lines) = @_;
  11095. local($i) = 0;
  11096. local(@sorted_lines);
  11097. foreach $num (sort {$a <=> $b} keys %lines) {
  11098. $sorted_lines[$i] = $lines{$num};
  11099. $i++;
  11100. }
  11101. @sorted_lines;
  11102. }
  11103.  
  11104. # This is a sort routine that will sort on the
  11105. # ip address when the ip address is anywhere in
  11106. # the strings.
  11107. sub ipsort {
  11108. local(%lines) = @_;
  11109. local($i) = 0;
  11110. local(@sorted_lines);
  11111. foreach $addr (sort sortbyipaddr keys %lines) {
  11112. $sorted_lines[$i] = $lines{$addr};
  11113. $i++;
  11114. }
  11115. @sorted_lines;
  11116. }
  11117.  
  11118. # These two routines will sort based upon IP addresses
  11119. sub ipaddrval {
  11120. my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#);
  11121. $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0]));
  11122. }
  11123. sub sortbyipaddr {
  11124. &ipaddrval($a) <=> &ipaddrval($b);
  11125. }
  11126.  
  11127. # This routine parses "show version"
  11128. sub ShowVersion {
  11129. print STDERR " In ShowVersion: $_" if ($debug);
  11130.  
  11131. while (<INPUT>) {
  11132. tr/\015//d;
  11133. last if(/^$prompt/);
  11134. next if(/^(\s*|\s*$cmd\s*)$/);
  11135. return(-1) if (/command authorization failed/i);
  11136.  
  11137. ProcessHistory("COMMENTS","keysort","B0", "!$_") && next;
  11138.  
  11139. }
  11140. return(0);
  11141. }
  11142.  
  11143. # This routine processes a "write term"
  11144. sub WriteTerm {
  11145. print STDERR " In WriteTerm: $_" if ($debug);
  11146.  
  11147. while (<INPUT>) {
  11148. tr/\015//d;
  11149. last if(/^$prompt/);
  11150. return(-1) if (/command authorization failed/i);
  11151.  
  11152. /Non-Volatile memory is in use/ && return(-1); # NvRAM is locked
  11153. # skip the crap
  11154. if (/^(##+$|(Building|Current) configuration)/i) {
  11155. while (<INPUT>) {
  11156. next if (/^Current configuration\s*:/i);
  11157. next if (/^([%!].*|\s*)$/);
  11158. last;
  11159. }
  11160. tr/\015//d;
  11161. }
  11162. # some versions have other crap mixed in with the bits in the
  11163. # block above
  11164. /^! Last Changed:/ && next;
  11165.  
  11166. # Dog gone Cool matches to process the rest of the config
  11167. # /^tftp-server flash / && next; # kill any tftp remains
  11168. # /^ntp clock-period / && next; # kill ntp clock-period
  11169. # /^ length / && next; # kill length on serial lines
  11170. # /^ width / && next; # kill width on serial lines
  11171. # /^ clockrate / && next; # kill clockrate on serial interfaces
  11172.  
  11173. if (/^((enable )?password( \d)?) / && $filter_pwds >= 1) {
  11174. ProcessHistory("ENABLE","","","!$1 <removed>\n");
  11175. next;
  11176. }
  11177. if (/^username (\S+)(\s.*)? password ((\d) \S+|\S+)/) {
  11178. if ($filter_pwds == 2) {
  11179. ProcessHistory("USER","keysort","$1","!username $1$2 password <removed>\n");
  11180. } elsif ($filter_pwds == 1 && $4 ne "5"){
  11181. ProcessHistory("USER","keysort","$1","!username $1$2 password <removed>\n");
  11182. } else {
  11183. ProcessHistory("USER","keysort","$1","$_");
  11184. }
  11185. next;
  11186. }
  11187.  
  11188. # prune passwords {bgp, ...}
  11189. if (/^\s*neighbor (\S*) password / && $filter_pwds >= 1) {
  11190. ProcessHistory("","","","! neighbor $1 password <removed>\n");
  11191. next;
  11192. }
  11193. # sort route-maps
  11194. if (/^route-map (\S+)/) {
  11195. my($key) = $1;
  11196. my($routemap) = $_;
  11197. while (<INPUT>) {
  11198. tr/\015//d;
  11199. last if (/^$prompt/ || ! /^(route-map |[ !])/);
  11200. if (/^route-map (\S+)/) {
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement