From 989312339ea2e16579803a48700628c5469e327a Mon Sep 17 00:00:00 2001 From: Tar Committer Date: Mon, 12 Jan 2004 03:17:26 +0000 Subject: Imported from rancid-2.3.rc1.tar.gz. --- bin/Makefile.am | 103 +++-- bin/Makefile.in | 746 ++++++++++++++++++++++-------------- bin/alogin.in | 84 +++-- bin/arancid.in | 25 +- bin/blogin.in | 85 +++-- bin/brancid.in | 20 +- bin/cat5rancid.in | 31 +- bin/clogin.in | 156 +++++--- bin/control_rancid.in | 79 ++-- bin/create_cvs.in | 89 ----- bin/cssrancid.in | 660 ++++++++++++++++++++++++++++++++ bin/do-diffs.in | 128 ------- bin/elogin.in | 44 ++- bin/env.in | 48 --- bin/erancid.in | 23 +- bin/f10rancid.in | 31 +- bin/flogin.in | 95 +++-- bin/fnrancid.in | 275 ++++++++++++++ bin/francid.in | 25 +- bin/hlogin.in | 92 +++-- bin/hpfilter.c | 397 ------------------- bin/hpuifilter.c | 400 ++++++++++++++++++++ bin/hrancid.in | 32 +- bin/htlogin.in | 492 ++++++++++++++++++++++++ bin/htrancid.in | 266 +++++++++++++ bin/jerancid.in | 645 +++++++++++++++++++++++++++++++ bin/jlogin.in | 50 ++- bin/jrancid.in | 102 +++-- bin/lg.cgi.in | 867 ++++++++++++++++++++++++++++++++++++++++++ bin/lgform.cgi.in | 259 +++++++++++++ bin/mrancid.in | 30 +- bin/nlogin.in | 524 ++++++++++++++++++++++++++ bin/nrancid.in | 302 +++++++++++++++ bin/nslogin.in | 642 +++++++++++++++++++++++++++++++ bin/nsrancid.in | 313 +++++++++++++++ bin/par.in | 17 +- bin/prancid.in | 569 ++++++++++++++++++++++++++++ bin/rancid-cvs.in | 94 +++++ bin/rancid-fe.in | 51 ++- bin/rancid-run.in | 136 +++++++ bin/rancid.in | 445 +++++++++++++++++++--- bin/rename.in | 113 ------ bin/rivlogin.in | 1005 +++++++++++++++++++++++++++++++++++++++++++++++++ bin/rivrancid.in | 344 +++++++++++++++++ bin/rrancid.in | 23 +- bin/tntlogin.in | 528 ++++++++++++++++++++++++++ bin/tntrancid.in | 292 ++++++++++++++ bin/xrancid.in | 64 ++-- bin/zrancid.in | 411 ++++++++++++++++++++ 49 files changed, 10693 insertions(+), 1559 deletions(-) mode change 100755 => 100644 bin/cat5rancid.in mode change 100755 => 100644 bin/clogin.in mode change 100755 => 100644 bin/control_rancid.in delete mode 100755 bin/create_cvs.in create mode 100644 bin/cssrancid.in delete mode 100755 bin/do-diffs.in mode change 100755 => 100644 bin/elogin.in delete mode 100644 bin/env.in mode change 100755 => 100644 bin/erancid.in mode change 100755 => 100644 bin/f10rancid.in mode change 100755 => 100644 bin/flogin.in create mode 100644 bin/fnrancid.in mode change 100755 => 100644 bin/francid.in mode change 100755 => 100644 bin/hlogin.in delete mode 100644 bin/hpfilter.c create mode 100644 bin/hpuifilter.c mode change 100755 => 100644 bin/hrancid.in create mode 100644 bin/htlogin.in create mode 100644 bin/htrancid.in create mode 100644 bin/jerancid.in mode change 100755 => 100644 bin/jlogin.in mode change 100755 => 100644 bin/jrancid.in create mode 100644 bin/lg.cgi.in create mode 100644 bin/lgform.cgi.in mode change 100755 => 100644 bin/mrancid.in create mode 100644 bin/nlogin.in create mode 100644 bin/nrancid.in create mode 100644 bin/nslogin.in create mode 100644 bin/nsrancid.in mode change 100755 => 100644 bin/par.in create mode 100755 bin/prancid.in create mode 100644 bin/rancid-cvs.in mode change 100755 => 100644 bin/rancid-fe.in create mode 100644 bin/rancid-run.in mode change 100755 => 100644 bin/rancid.in delete mode 100755 bin/rename.in create mode 100644 bin/rivlogin.in create mode 100644 bin/rivrancid.in mode change 100755 => 100644 bin/rrancid.in create mode 100644 bin/tntlogin.in create mode 100644 bin/tntrancid.in mode change 100755 => 100644 bin/xrancid.in create mode 100755 bin/zrancid.in (limited to 'bin') diff --git a/bin/Makefile.am b/bin/Makefile.am index 67c8966..21fac52 100644 --- a/bin/Makefile.am +++ b/bin/Makefile.am @@ -1,26 +1,46 @@ ## Process this file with automake to produce Makefile.in ## A Makefile.in is supplied, in case you do not have automake. -## Copyright (C) 1997-2001 by Henry Kilmer, Erik Sherk and Pete Whiting. +## $Id: Makefile.am,v 1.28 2004/01/11 07:15:23 hank Exp $ +## +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. ## All rights reserved. ## -## This software may be freely copied, modified and redistributed without -## fee for non-commerical purposes provided that this copyright notice is -## preserved intact on all copies and modified copies. +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. ## ## There is no warranty or other guarantee of fitness of this software. -## It is provided solely "as is". The author(s) disclaim(s) all +## It is provided solely "as is". The author(s) disclaim(s) all ## responsibility and liability with respect to this software's usage ## or its effect upon hardware, computer systems, other software, or ## anything else. +## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. +## #AUTOMAKE_OPTIONS=foreign no-dependencies AUTOMAKE_OPTIONS=foreign -PREFIX = @prefix@ +bin_PROGRAMS = hpuifilter +bin_SCRIPTS = cat5rancid control_rancid \ + alogin arancid clogin blogin brancid cssrancid \ + elogin erancid f10rancid flogin francid fnrancid \ + jlogin jrancid jerancid \ + hlogin hrancid htlogin htrancid \ + mrancid nlogin nrancid nslogin nsrancid par prancid \ + rancid rancid-fe rivlogin rivrancid rrancid \ + tntlogin tntrancid xrancid zrancid + +bin_SCRIPTS += lg.cgi lgform.cgi rancid-cvs rancid-run +EXTRA_DIST= lg.cgi.in lgform.cgi.in rancid-cvs.in rancid-run.in +#dist_bin_SCRIPTS= $(bin_SCRIPTS:%=%.in) + +CLEANFILES= lg.cgi lgform.cgi rancid-cvs rancid-run +#CLEANFILES= $(bin_SCRIPTS) -bin_PROGRAMS = hpfilter -hpfilter_SOURCES = hpfilter.c +hpuifilter_SOURCES = hpuifilter.c #CPPFLAGS += @PG_CPPFLAGS@ #INCLUDES += -I$(top_srcdir)/include @PG_CPPFLAGS@ @@ -35,35 +55,46 @@ YFLAGS = -d # no idea why automake doesnt clean these targets #CLEANFILES= y.tab.c y.tab.h lex.yy.c conf.h conf.c conflex.c -BIN_PROGS=@RD_BIN_PROGS@ -BIN_DATAS=@RD_BIN_DATAS@ - -install: all - for prog in $(BIN_PROGS) ; do \ - $(INSTALL) $$prog $(bindir); \ - done; \ - if test -f $(bindir)/env ; then \ - echo "WARNING: *** $(bindir)/env exists: installing as env.new."; \ - echo " *** review env.new for new/deprecated switches"; \ - $(INSTALL_DATA) env $(bindir)/env.new; \ - else \ - $(INSTALL_DATA) env $(bindir); \ - fi -# BIN_DATAS are empty at the moment. -# for prog in $(BIN_DATAS) ; do \ -# $(INSTALL_DATA) $$prog $(PREFIX)/bin; \ -# done; \ - #clean: # rm -f Makefile env $(BIN_DATAS) $(BIN_PROGS) -#distclean: clean -# rm -f config.log config.status +# auto_edit does the autoconf variable substitution. This allows the +# substitution to have the full expansion of the variables, e.g.: $sysconfdir +# will be /prefix/etc instead of ${prefix}/etc. +# +# This is a bit of a PITA, but is the method recommended by the autoconf +# documentation. +auto_edit = sed \ + -e 's,@prefix\@,$(prefix),g' \ + -e 's,@localstatedir\@,$(localstatedir),g' \ + -e 's,@sysconfdir\@,$(sysconfdir),g' \ + -e 's,@EXPECT_PATH\@,$(EXPECT_PATH),g' \ + -e 's,@PERLV\@,$(PERLV),g' \ + -e 's,@PERLV_PATH\@,$(PERLV_PATH),g' \ + -e 's,@LG_PING_CMD\@,$(LG_PING_CMD),g' \ + -e 's,@ADMINMAILPLUS\@,$(ADMINMAILPLUS),g' \ + -e 's,@MAILPLUS\@,$(MAILPLUS),g' + +lg.cgi: Makefile $(srcdir)/lg.cgi.in + rm -f lg.cgi lg.cgi.tmp; \ + $(auto_edit) $(srcdir)/lg.cgi.in >lg.cgi.tmp; \ + chmod +x lg.cgi.tmp; \ + mv lg.cgi.tmp lg.cgi + +lgform.cgi: Makefile $(srcdir)/lgform.cgi.in + rm -f lgform.cgi lgform.cgi.tmp; \ + $(auto_edit) $(srcdir)/lgform.cgi.in >lgform.cgi.tmp; \ + chmod +x lgform.cgi.tmp; \ + mv lgform.cgi.tmp lgform.cgi + +rancid-cvs: Makefile $(srcdir)/rancid-cvs.in + rm -f rancid-cvs rancid-cvs.tmp; \ + $(auto_edit) $(srcdir)/rancid-cvs.in >rancid-cvs.tmp; \ + chmod +x rancid-cvs.tmp; \ + mv rancid-cvs.tmp rancid-cvs -#distdir: -# for file in Makefile.in configure.in env.in $(BIN_DATAS:=.in) ; do \ -# $(INSTALL_DATA) $$file $(distdir); \ -# done -# for file in configure $(BIN_PROGS:=.in) ; do \ -# $(INSTALL) $$file $(distdir); \ -# done +rancid-run: Makefile $(srcdir)/rancid-run.in + rm -f rancid-run rancid-run.tmp; \ + $(auto_edit) $(srcdir)/rancid-run.in >rancid-run.tmp; \ + chmod +x rancid-run.tmp; \ + mv rancid-run.tmp rancid-run diff --git a/bin/Makefile.in b/bin/Makefile.in index ad98aa8..eedc795 100644 --- a/bin/Makefile.in +++ b/bin/Makefile.in @@ -1,6 +1,8 @@ -# Makefile.in generated automatically by automake 1.4-p5 from Makefile.am +# Makefile.in generated by automake 1.8 from Makefile.am. +# @configure_input@ -# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc. +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -10,397 +12,595 @@ # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. -#AUTOMAKE_OPTIONS=foreign no-dependencies +@SET_MAKE@ -SHELL = @SHELL@ +SOURCES = $(hpuifilter_SOURCES) srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ -prefix = @prefix@ -exec_prefix = @exec_prefix@ - -bindir = @bindir@ -sbindir = @sbindir@ -libexecdir = @libexecdir@ -datadir = @datadir@ -sysconfdir = @sysconfdir@ -sharedstatedir = @sharedstatedir@ -localstatedir = @localstatedir@ -libdir = @libdir@ -infodir = @infodir@ -mandir = @mandir@ -includedir = @includedir@ -oldincludedir = /usr/include - -DESTDIR = - pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ - top_builddir = .. - -ACLOCAL = @ACLOCAL@ -AUTOCONF = @AUTOCONF@ -AUTOMAKE = @AUTOMAKE@ -AUTOHEADER = @AUTOHEADER@ - +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -transform = @program_transform_name@ - +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : +bin_PROGRAMS = hpuifilter$(EXEEXT) +subdir = bin +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/alogin.in $(srcdir)/arancid.in $(srcdir)/blogin.in \ + $(srcdir)/brancid.in $(srcdir)/cat5rancid.in \ + $(srcdir)/clogin.in $(srcdir)/control_rancid.in \ + $(srcdir)/cssrancid.in $(srcdir)/elogin.in \ + $(srcdir)/erancid.in $(srcdir)/f10rancid.in \ + $(srcdir)/flogin.in $(srcdir)/fnrancid.in $(srcdir)/francid.in \ + $(srcdir)/hlogin.in $(srcdir)/hrancid.in $(srcdir)/htlogin.in \ + $(srcdir)/htrancid.in $(srcdir)/jerancid.in \ + $(srcdir)/jlogin.in $(srcdir)/jrancid.in $(srcdir)/mrancid.in \ + $(srcdir)/nlogin.in $(srcdir)/nrancid.in $(srcdir)/nslogin.in \ + $(srcdir)/nsrancid.in $(srcdir)/par.in $(srcdir)/prancid.in \ + $(srcdir)/rancid-fe.in $(srcdir)/rancid.in \ + $(srcdir)/rivlogin.in $(srcdir)/rivrancid.in \ + $(srcdir)/rrancid.in $(srcdir)/tntlogin.in \ + $(srcdir)/tntrancid.in $(srcdir)/xrancid.in \ + $(srcdir)/zrancid.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = control_rancid par rancid-fe alogin arancid \ + blogin brancid cat5rancid clogin rancid cssrancid elogin \ + erancid f10rancid flogin francid fnrancid jlogin jrancid \ + jerancid hlogin hrancid htlogin htrancid mrancid nlogin \ + nrancid nslogin nsrancid prancid rivlogin rivrancid rrancid \ + tntlogin tntrancid xrancid zrancid +am__installdirs = $(DESTDIR)$(bindir) $(DESTDIR)$(bindir) +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(bin_PROGRAMS) +am_hpuifilter_OBJECTS = hpuifilter.$(OBJEXT) +hpuifilter_OBJECTS = $(am_hpuifilter_OBJECTS) +hpuifilter_LDADD = $(LDADD) +binSCRIPT_INSTALL = $(INSTALL_SCRIPT) +SCRIPTS = $(bin_SCRIPTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/hpuifilter.Po +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(hpuifilter_SOURCES) +DIST_SOURCES = $(hpuifilter_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ADMINMAILPLUS = @ADMINMAILPLUS@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ CC = @CC@ +CCDEPMODE = @CCDEPMODE@ + +#CPPFLAGS += @PG_CPPFLAGS@ +#INCLUDES += -I$(top_srcdir)/include @PG_CPPFLAGS@ +#INCLUDES += -I$(top_srcdir)/include + +#CFLAGS += -g +CFLAGS = -g -O0 COMM = @COMM@ CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ CVS = @CVS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ DIFF = @DIFF@ DIFF_CMD = @DIFF_CMD@ DIRNAME = @DIRNAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ ENV_PATH = @ENV_PATH@ +EXEEXT = @EXEEXT@ EXPECT_PATH = @EXPECT_PATH@ FIND = @FIND@ GREP = @GREP@ ID = @ID@ -INST_PROGS = @INST_PROGS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ LG_PING_CMD = @LG_PING_CMD@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ MAILPLUS = @MAILPLUS@ -MAINT = @MAINT@ MAKE = @MAKE@ MAKEINFO = @MAKEINFO@ MKDIR = @MKDIR@ +OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ PERLV = @PERLV@ PERLV_PATH = @PERLV_PATH@ PING_PATH = @PING_PATH@ -RD_BIN_DATAS = @RD_BIN_DATAS@ -RD_BIN_PROGS = @RD_BIN_PROGS@ -RD_UTIL_LG_PROGS = @RD_UTIL_LG_PROGS@ -RD_UTIL_PROGS = @RD_UTIL_PROGS@ RSH = @RSH@ SENDMAIL = @SENDMAIL@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ SORT = @SORT@ SSH = @SSH@ +STRIP = @STRIP@ TAR = @TAR@ TELNET = @TELNET@ TOUCH = @TOUCH@ U = @U@ VERSION = @VERSION@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +#AUTOMAKE_OPTIONS=foreign no-dependencies AUTOMAKE_OPTIONS = foreign - -PREFIX = @prefix@ - -bin_PROGRAMS = hpfilter -hpfilter_SOURCES = hpfilter.c - -#CPPFLAGS += @PG_CPPFLAGS@ -#INCLUDES += -I$(top_srcdir)/include @PG_CPPFLAGS@ -#INCLUDES += -I$(top_srcdir)/include - -#CFLAGS += -g -CFLAGS = -g -O0 - +bin_SCRIPTS = cat5rancid control_rancid \ + alogin arancid clogin blogin brancid cssrancid \ + elogin erancid f10rancid flogin francid fnrancid \ + jlogin jrancid jerancid \ + hlogin hrancid htlogin htrancid \ + mrancid nlogin nrancid nslogin nsrancid par prancid \ + rancid rancid-fe rivlogin rivrancid rrancid \ + tntlogin tntrancid xrancid zrancid\ +lg.cgi lgform.cgi rancid-cvs rancid-run +EXTRA_DIST = lg.cgi.in lgform.cgi.in rancid-cvs.in rancid-run.in +#dist_bin_SCRIPTS= $(bin_SCRIPTS:%=%.in) +CLEANFILES = lg.cgi lgform.cgi rancid-cvs rancid-run +#CLEANFILES= $(bin_SCRIPTS) +hpuifilter_SOURCES = hpuifilter.c YFLAGS = -d #LFLAGS = -i # no idea why automake doesnt clean these targets #CLEANFILES= y.tab.c y.tab.h lex.yy.c conf.h conf.c conflex.c -BIN_PROGS = @RD_BIN_PROGS@ -BIN_DATAS = @RD_BIN_DATAS@ -mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs -CONFIG_HEADER = ../include/config.h -CONFIG_CLEAN_FILES = alogin arancid blogin brancid cat5rancid clogin \ -control_rancid create_cvs do-diffs elogin env erancid f10rancid flogin \ -francid jlogin jrancid hlogin hrancid mrancid par rancid-fe rancid \ -rename rrancid xrancid -PROGRAMS = $(bin_PROGRAMS) - - -DEFS = @DEFS@ -I. -I$(srcdir) -I../include -CPPFLAGS = @CPPFLAGS@ -LDFLAGS = @LDFLAGS@ -LIBS = @LIBS@ -hpfilter_OBJECTS = hpfilter.o -hpfilter_LDADD = $(LDADD) -hpfilter_DEPENDENCIES = -hpfilter_LDFLAGS = -COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -CCLD = $(CC) -LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ -DIST_COMMON = Makefile.am Makefile.in alogin.in arancid.in blogin.in \ -brancid.in cat5rancid.in clogin.in control_rancid.in create_cvs.in \ -do-diffs.in elogin.in env.in erancid.in f10rancid.in flogin.in \ -francid.in hlogin.in hrancid.in jlogin.in jrancid.in mrancid.in par.in \ -rancid-fe.in rancid.in rename.in rrancid.in xrancid.in - - -DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) +#clean: +# rm -f Makefile env $(BIN_DATAS) $(BIN_PROGS) -GZIP_ENV = --best -SOURCES = $(hpfilter_SOURCES) -OBJECTS = $(hpfilter_OBJECTS) +# auto_edit does the autoconf variable substitution. This allows the +# substitution to have the full expansion of the variables, e.g.: $sysconfdir +# will be /prefix/etc instead of ${prefix}/etc. +# +# This is a bit of a PITA, but is the method recommended by the autoconf +# documentation. +auto_edit = sed \ + -e 's,@prefix\@,$(prefix),g' \ + -e 's,@localstatedir\@,$(localstatedir),g' \ + -e 's,@sysconfdir\@,$(sysconfdir),g' \ + -e 's,@EXPECT_PATH\@,$(EXPECT_PATH),g' \ + -e 's,@PERLV\@,$(PERLV),g' \ + -e 's,@PERLV_PATH\@,$(PERLV_PATH),g' \ + -e 's,@LG_PING_CMD\@,$(LG_PING_CMD),g' \ + -e 's,@ADMINMAILPLUS\@,$(ADMINMAILPLUS),g' \ + -e 's,@MAILPLUS\@,$(MAILPLUS),g' + +all: all-am -all: all-redirect .SUFFIXES: -.SUFFIXES: .S .c .o .s -$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) - cd $(top_srcdir) && $(AUTOMAKE) --foreign --include-deps bin/Makefile - -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - cd $(top_builddir) \ - && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status - -alogin: $(top_builddir)/config.status alogin.in - cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status -arancid: $(top_builddir)/config.status arancid.in - cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status -blogin: $(top_builddir)/config.status blogin.in - cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status -brancid: $(top_builddir)/config.status brancid.in - cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status -cat5rancid: $(top_builddir)/config.status cat5rancid.in - cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status -clogin: $(top_builddir)/config.status clogin.in - cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status -control_rancid: $(top_builddir)/config.status control_rancid.in - cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status -create_cvs: $(top_builddir)/config.status create_cvs.in - cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status -do-diffs: $(top_builddir)/config.status do-diffs.in - cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status -elogin: $(top_builddir)/config.status elogin.in - cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status -env: $(top_builddir)/config.status env.in - cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status -erancid: $(top_builddir)/config.status erancid.in - cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status -f10rancid: $(top_builddir)/config.status f10rancid.in - cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status -flogin: $(top_builddir)/config.status flogin.in - cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status -francid: $(top_builddir)/config.status francid.in - cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status -jlogin: $(top_builddir)/config.status jlogin.in - cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status -jrancid: $(top_builddir)/config.status jrancid.in - cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status -hlogin: $(top_builddir)/config.status hlogin.in - cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status -hrancid: $(top_builddir)/config.status hrancid.in - cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status -mrancid: $(top_builddir)/config.status mrancid.in - cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status -par: $(top_builddir)/config.status par.in - cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status -rancid-fe: $(top_builddir)/config.status rancid-fe.in - cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status -rancid: $(top_builddir)/config.status rancid.in - cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status -rename: $(top_builddir)/config.status rename.in - cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status -rrancid: $(top_builddir)/config.status rrancid.in - cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status -xrancid: $(top_builddir)/config.status xrancid.in - cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status - -mostlyclean-binPROGRAMS: - -clean-binPROGRAMS: - -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) - -distclean-binPROGRAMS: - -maintainer-clean-binPROGRAMS: - +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign bin/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign bin/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +control_rancid: $(top_builddir)/config.status $(srcdir)/control_rancid.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +par: $(top_builddir)/config.status $(srcdir)/par.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +rancid-fe: $(top_builddir)/config.status $(srcdir)/rancid-fe.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +alogin: $(top_builddir)/config.status $(srcdir)/alogin.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +arancid: $(top_builddir)/config.status $(srcdir)/arancid.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +blogin: $(top_builddir)/config.status $(srcdir)/blogin.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +brancid: $(top_builddir)/config.status $(srcdir)/brancid.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +cat5rancid: $(top_builddir)/config.status $(srcdir)/cat5rancid.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +clogin: $(top_builddir)/config.status $(srcdir)/clogin.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +rancid: $(top_builddir)/config.status $(srcdir)/rancid.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +cssrancid: $(top_builddir)/config.status $(srcdir)/cssrancid.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +elogin: $(top_builddir)/config.status $(srcdir)/elogin.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +erancid: $(top_builddir)/config.status $(srcdir)/erancid.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +f10rancid: $(top_builddir)/config.status $(srcdir)/f10rancid.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +flogin: $(top_builddir)/config.status $(srcdir)/flogin.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +francid: $(top_builddir)/config.status $(srcdir)/francid.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +fnrancid: $(top_builddir)/config.status $(srcdir)/fnrancid.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +jlogin: $(top_builddir)/config.status $(srcdir)/jlogin.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +jrancid: $(top_builddir)/config.status $(srcdir)/jrancid.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +jerancid: $(top_builddir)/config.status $(srcdir)/jerancid.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +hlogin: $(top_builddir)/config.status $(srcdir)/hlogin.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +hrancid: $(top_builddir)/config.status $(srcdir)/hrancid.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +htlogin: $(top_builddir)/config.status $(srcdir)/htlogin.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +htrancid: $(top_builddir)/config.status $(srcdir)/htrancid.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +mrancid: $(top_builddir)/config.status $(srcdir)/mrancid.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +nlogin: $(top_builddir)/config.status $(srcdir)/nlogin.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +nrancid: $(top_builddir)/config.status $(srcdir)/nrancid.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +nslogin: $(top_builddir)/config.status $(srcdir)/nslogin.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +nsrancid: $(top_builddir)/config.status $(srcdir)/nsrancid.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +prancid: $(top_builddir)/config.status $(srcdir)/prancid.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +rivlogin: $(top_builddir)/config.status $(srcdir)/rivlogin.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +rivrancid: $(top_builddir)/config.status $(srcdir)/rivrancid.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +rrancid: $(top_builddir)/config.status $(srcdir)/rrancid.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +tntlogin: $(top_builddir)/config.status $(srcdir)/tntlogin.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +tntrancid: $(top_builddir)/config.status $(srcdir)/tntrancid.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +xrancid: $(top_builddir)/config.status $(srcdir)/xrancid.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +zrancid: $(top_builddir)/config.status $(srcdir)/zrancid.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) - $(mkinstalldirs) $(DESTDIR)$(bindir) + $(mkdir_p) $(DESTDIR)$(bindir) @list='$(bin_PROGRAMS)'; for p in $$list; do \ - if test -f $$p; then \ - echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ - $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f"; \ + $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f || exit 1; \ else :; fi; \ done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) - list='$(bin_PROGRAMS)'; for p in $$list; do \ - rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f $(DESTDIR)$(bindir)/$$f"; \ + rm -f $(DESTDIR)$(bindir)/$$f; \ done -.c.o: - $(COMPILE) -c $< - -.s.o: - $(COMPILE) -c $< +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) +hpuifilter$(EXEEXT): $(hpuifilter_OBJECTS) $(hpuifilter_DEPENDENCIES) + @rm -f hpuifilter$(EXEEXT) + $(LINK) $(hpuifilter_LDFLAGS) $(hpuifilter_OBJECTS) $(hpuifilter_LDADD) $(LIBS) +install-binSCRIPTS: $(bin_SCRIPTS) + @$(NORMAL_INSTALL) + $(mkdir_p) $(DESTDIR)$(bindir) + @list='$(bin_SCRIPTS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + if test -f $$d$$p; then \ + f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \ + echo " $(binSCRIPT_INSTALL) $$d$$p $(DESTDIR)$(bindir)/$$f"; \ + $(binSCRIPT_INSTALL) $$d$$p $(DESTDIR)$(bindir)/$$f; \ + else :; fi; \ + done -.S.o: - $(COMPILE) -c $< +uninstall-binSCRIPTS: + @$(NORMAL_UNINSTALL) + @list='$(bin_SCRIPTS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \ + echo " rm -f $(DESTDIR)$(bindir)/$$f"; \ + rm -f $(DESTDIR)$(bindir)/$$f; \ + done mostlyclean-compile: - -rm -f *.o core *.core - -clean-compile: + -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c -maintainer-clean-compile: - -hpfilter: $(hpfilter_OBJECTS) $(hpfilter_DEPENDENCIES) - @rm -f hpfilter - $(LINK) $(hpfilter_LDFLAGS) $(hpfilter_OBJECTS) $(hpfilter_LDADD) $(LIBS) +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hpuifilter.Po@am__quote@ +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique tags: TAGS -TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ - list='$(SOURCES) $(HEADERS)'; \ - unique=`for i in $$list; do echo $$i; done | \ - awk ' { files[$$0] = 1; } \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ - test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ - || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) - -mostlyclean-tags: + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique -clean-tags: +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here distclean-tags: - -rm -f TAGS ID - -maintainer-clean-tags: - -distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) - -subdir = bin + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) - @for file in $(DISTFILES); do \ - d=$(srcdir); \ + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ if test -d $$d/$$file; then \ - cp -pr $$d/$$file $(distdir)/$$file; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ - || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ - || cp -p $$d/$$file $(distdir)/$$file || :; \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ fi; \ done - -info-am: -info: info-am -dvi-am: -dvi: dvi-am check-am: all-am check: check-am -installcheck-am: -installcheck: installcheck-am -install-exec-am: install-binPROGRAMS +all-am: Makefile $(PROGRAMS) $(SCRIPTS) +installdirs: + $(mkdir_p) $(DESTDIR)$(bindir) $(DESTDIR)$(bindir) +install: install-am install-exec: install-exec-am - -install-data-am: install-data: install-data-am +uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am -install: install-am -uninstall-am: uninstall-binPROGRAMS -uninstall: uninstall-am -all-am: Makefile $(PROGRAMS) -all-redirect: all-am -install-strip: - $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install -installdirs: - $(mkinstalldirs) $(DESTDIR)$(bindir) - +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: - -rm -f Makefile $(CONFIG_CLEAN_FILES) - -rm -f config.cache config.log stamp-h stamp-h[0-9]* + -rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: -mostlyclean-am: mostlyclean-binPROGRAMS mostlyclean-compile \ - mostlyclean-tags mostlyclean-generic + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am -mostlyclean: mostlyclean-am +clean-am: clean-binPROGRAMS clean-generic mostlyclean-am -clean-am: clean-binPROGRAMS clean-compile clean-tags clean-generic \ - mostlyclean-am +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags -clean: clean-am +dvi: dvi-am -distclean-am: distclean-binPROGRAMS distclean-compile distclean-tags \ - distclean-generic clean-am +dvi-am: -distclean: distclean-am +html: html-am -maintainer-clean-am: maintainer-clean-binPROGRAMS \ - maintainer-clean-compile maintainer-clean-tags \ - maintainer-clean-generic distclean-am - @echo "This command is intended for maintainers to use;" - @echo "it deletes files that may require special tools to rebuild." +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-binPROGRAMS install-binSCRIPTS + +install-info: install-info-am + +install-man: + +installcheck-am: maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic -.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \ -maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \ -mostlyclean-compile distclean-compile clean-compile \ -maintainer-clean-compile tags mostlyclean-tags distclean-tags \ -clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \ -check-am installcheck-am installcheck install-exec-am install-exec \ -install-data-am install-data install-am install uninstall-am uninstall \ -all-redirect all-am all installdirs mostlyclean-generic \ -distclean-generic clean-generic maintainer-clean-generic clean \ -mostlyclean distclean maintainer-clean - - -install: all - for prog in $(BIN_PROGS) ; do \ - $(INSTALL) $$prog $(bindir); \ - done; \ - if test -f $(bindir)/env ; then \ - echo "WARNING: *** $(bindir)/env exists: installing as env.new."; \ - echo " *** review env.new for new/deprecated switches"; \ - $(INSTALL_DATA) env $(bindir)/env.new; \ - else \ - $(INSTALL_DATA) env $(bindir); \ - fi -# BIN_DATAS are empty at the moment. -# for prog in $(BIN_DATAS) ; do \ -# $(INSTALL_DATA) $$prog $(PREFIX)/bin; \ -# done; \ +mostlyclean: mostlyclean-am -#clean: -# rm -f Makefile env $(BIN_DATAS) $(BIN_PROGS) +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS \ + uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-binSCRIPTS install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-binSCRIPTS uninstall-info-am + + +lg.cgi: Makefile $(srcdir)/lg.cgi.in + rm -f lg.cgi lg.cgi.tmp; \ + $(auto_edit) $(srcdir)/lg.cgi.in >lg.cgi.tmp; \ + chmod +x lg.cgi.tmp; \ + mv lg.cgi.tmp lg.cgi -#distclean: clean -# rm -f config.log config.status +lgform.cgi: Makefile $(srcdir)/lgform.cgi.in + rm -f lgform.cgi lgform.cgi.tmp; \ + $(auto_edit) $(srcdir)/lgform.cgi.in >lgform.cgi.tmp; \ + chmod +x lgform.cgi.tmp; \ + mv lgform.cgi.tmp lgform.cgi -#distdir: -# for file in Makefile.in configure.in env.in $(BIN_DATAS:=.in) ; do \ -# $(INSTALL_DATA) $$file $(distdir); \ -# done -# for file in configure $(BIN_PROGS:=.in) ; do \ -# $(INSTALL) $$file $(distdir); \ -# done +rancid-cvs: Makefile $(srcdir)/rancid-cvs.in + rm -f rancid-cvs rancid-cvs.tmp; \ + $(auto_edit) $(srcdir)/rancid-cvs.in >rancid-cvs.tmp; \ + chmod +x rancid-cvs.tmp; \ + mv rancid-cvs.tmp rancid-cvs +rancid-run: Makefile $(srcdir)/rancid-run.in + rm -f rancid-run rancid-run.tmp; \ + $(auto_edit) $(srcdir)/rancid-run.in >rancid-run.tmp; \ + chmod +x rancid-run.tmp; \ + mv rancid-run.tmp rancid-run # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: diff --git a/bin/alogin.in b/bin/alogin.in index 03f12ca..91623fb 100644 --- a/bin/alogin.in +++ b/bin/alogin.in @@ -1,21 +1,26 @@ -#!@EXPECT_PATH@ -- +#! @EXPECT_PATH@ -- ## +## $Id: alogin.in,v 1.22 2004/01/11 05:39:15 heas Exp $ ## -## Copyright (C) 1997-2001 by Henry Kilmer, Erik Sherk and Pete Whiting. +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. ## All rights reserved. ## -## This software may be freely copied, modified and redistributed without -## fee for non-commerical purposes provided that this copyright notice is -## preserved intact on all copies and modified copies. +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. ## ## There is no warranty or other guarantee of fitness of this software. -## It is provided solely "as is". The author(s) disclaim(s) all +## It is provided solely "as is". The author(s) disclaim(s) all ## responsibility and liability with respect to this software's usage ## or its effect upon hardware, computer systems, other software, or ## anything else. ## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. ## # +# The login expect scripts were based on Erik Sherk's gwtn, by permission. +# # alogin - Alteon WebOS switch login # # afort@choqolat.org is responsible for this particular mess @@ -39,8 +44,9 @@ set do_command 0 set do_script 0 # The default is to automatically enable set enable 1 -# The default is that you login non-enabled (tacacs can have you login already enabled) -set autoenable 0 +# The default is that you login non-enabled (tacacs can have you login already +# enabled) +set avautoenable 0 # The default is to look in the password file to find the passwords. This # tracks if we receive them on the command line. set do_passwd 1 @@ -50,12 +56,14 @@ if {[ info exists env(CISCO_USER) ] } { set default_user $env(CISCO_USER) } elseif {[ info exists env(USER) ]} { set default_user $env(USER) +} elseif {[ info exists env(LOGNAME) ]} { + set default_user $env(LOGNAME) } else { # This uses "id" which I think is portable. At least it has existed # (without options) on all machines/OSes I've been on recently - # unlike whoami or id -nu. if [ catch {exec id} reason ] { - send_error "Error: could not exec id: $reason\n" + send_error "\nError: could not exec id: $reason\n" exit 1 } regexp {\(([^)]*)} "$reason" junk default_user @@ -95,7 +103,7 @@ for {set i 0} {$i < $argc} {incr i} { incr i set E$varname $varvalue } else { - send_user "Error: invalid format for -E in $arg\n" + send_user "\nError: invalid format for -E in $arg\n" exit 1 } # Enable Password @@ -118,7 +126,7 @@ for {set i 0} {$i < $argc} {incr i} { set sfile [ lindex $argv $i ] } if { ! [ file readable $sfile ] } { - send_user "Error: Can't read $sfile\n" + send_user "\nError: Can't read $sfile\n" exit 1 } set do_script 1 @@ -160,12 +168,12 @@ for {set i 0} {$i < $argc} {incr i} { set do_command 1 # Do we enable? } -noenable { - # ignore -noenable + # ignore -noenable # Does tacacs automatically enable us? } -autoenable { - # ignore -autoenable + # ignore -autoenable } -* { - send_user "Error: Unknown argument! $arg\n" + send_user "\nError: Unknown argument! $arg\n" send_user $usage exit 1 } default { @@ -175,7 +183,7 @@ for {set i 0} {$i < $argc} {incr i} { } # Process routers...no routers listed is an error. if { $i == $argc } { - send_user "Error: $usage" + send_user "\nError: $usage" } # Only be quiet if we are running a script (it can log its output @@ -241,16 +249,16 @@ proc find {var router} { proc source_password_file { password_file } { global env if { ! [file exists $password_file] } { - send_user "Error: password file ($password_file) does not exist\n" + send_user "\nError: password file ($password_file) does not exist\n" exit 1 } file stat $password_file fileinfo if { [expr ($fileinfo(mode) & 007)] != 0000 } { - send_user "Error: $password_file must not be world readable/writable\n" + send_user "\nError: $password_file must not be world readable/writable\n" exit 1 } if [ catch {source $password_file} reason ] { - send_user "Error: $reason\n" + send_user "\nError: $reason\n" exit 1 } } @@ -258,7 +266,7 @@ proc source_password_file { password_file } { # Log into the router. proc login { router user userpswd passwd prompt cmethod cyphertype } { global spawn_id in_proc do_command do_script - global u_prompt p_prompt + global u_prompt p_prompt sshcmd set in_proc 1 set uprompt_seen 0 @@ -277,17 +285,17 @@ proc login { router user userpswd passwd prompt cmethod cyphertype } { exit 1 } } elseif ![string compare $prog "ssh"] { - if [ catch {spawn ssh -c $cyphertype -x -l $user $router} reason ] { - send_user "Error: ssh failed: $reason\n" + if [ catch {spawn $sshcmd -c $cyphertype -x -l $user $router} reason ] { + send_user "\nError: $sshcmd failed: $reason\n" exit 1 } } elseif ![string compare $prog "rsh"] { if [ catch {spawn rsh -l $user $router} reason ] { - send_user "Error: rsh failed: $reason\n" + send_user "\nError: rsh failed: $reason\n" exit 1 } } else { - puts "ERROR: unknown connection method: $prog" + puts "\nError: unknown connection method: $prog" return 1 } incr progs -1 @@ -319,17 +327,17 @@ proc login { router user userpswd passwd prompt cmethod cyphertype } { close; wait sleep 0.3 expect eof - send_user "Error: Connection Refused\n"; wait; return 1 - } eof { send_user "Error: Couldn't login\n"; wait; return 1 + send_user "\nError: Connection Refused\n"; wait; return 1 + } eof { send_user "\nError: Couldn't login\n"; wait; return 1 } "Unknown host\r\n" { expect eof - send_user "Error: Unknown host\n"; wait; return 1 + send_user "\nError: Unknown host\n"; wait; return 1 } "Host is unreachable" { expect eof - send_user "Error: Host Unreachable!\n"; wait; return 1 + send_user "\nError: Host Unreachable!\n"; wait; return 1 } "No address associated with name" { expect eof - send_user "Error: Unknown host\n"; wait; return 1 + send_user "\nError: Unknown host\n"; wait; return 1 } -re "(Host key not found |The authenticity of host .* be established).*\(yes\/no\)\?" { send "yes\r" @@ -362,10 +370,10 @@ proc login { router user userpswd passwd prompt cmethod cyphertype } { send "y\r" exp_continue } - "Password incorrect" { send_user "Error: Check your password for $router\n"; + "Password incorrect" { send_user "\nError: Check your password for $router\n"; catch {close}; wait; return 1 } -re "$prompt" { break; } - denied { send_user "Error: Check your passwd for $router\n" + denied { send_user "\nError: Check your passwd for $router\n" catch {close}; wait; return 1 } "\r\n" { exp_continue; } @@ -439,10 +447,10 @@ foreach router [lrange $argv $i end] { if { $do_passwd } { set pswd [find password $router] if { [llength $pswd] == 0 } { - send_user "Error - no password for $router in $password_file.\n" + send_user "\nError - no password for $router in $password_file.\n" continue } - set passwd [lindex $pswd 0] + set passwd [join [lindex $pswd 0] ""] } # Figure out username @@ -450,7 +458,7 @@ foreach router [lrange $argv $i end] { # command line username set ruser $username } else { - set ruser [find user $router] + set ruser [join [find user $router] ""] if { "$ruser" == "" } { set ruser $default_user } } @@ -459,7 +467,7 @@ foreach router [lrange $argv $i end] { # command line username set userpswd $userpasswd } else { - set userpswd [find userpassword $router] + set userpswd [join [find userpassword $router] ""] if { "$userpswd" == "" } { set userpswd $passwd } } @@ -468,13 +476,13 @@ foreach router [lrange $argv $i end] { if { "$u_prompt" == "" } { set u_prompt "(Username|login| Login):" } else { - set u_prompt [lindex $u_prompt 0] + set u_prompt [join [lindex $u_prompt 0] ""] } set p_prompt [find passprompt $router] if { "$p_prompt" == "" } { set p_prompt "\[Pp]assword:" } else { - set p_prompt [lindex $p_prompt 0] + set p_prompt [join [lindex $p_prompt 0] ""] } # Figure out cypher type @@ -490,6 +498,10 @@ foreach router [lrange $argv $i end] { set cmethod [find method $router] if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} } + # Figure out the SSH executable name + set sshcmd [find sshcmd $router] + if { "$sshcmd" == "" } { set sshcmd {ssh} } + # Login to the router if {[login $router $ruser $userpswd $passwd $prompt $cmethod $cyphertype]} { continue diff --git a/bin/arancid.in b/bin/arancid.in index f51a6c3..a2bf1ef 100644 --- a/bin/arancid.in +++ b/bin/arancid.in @@ -1,23 +1,26 @@ -#!@PERLV_PATH@ +#! @PERLV_PATH@ +## +## $Id: arancid.in,v 1.14 2004/01/11 03:49:13 heas Exp $ ## ## Hacked version of rancid for Alteon WebOS switches ## tested with: ad3 v8.1.18 ## afort@choqolat.org (andrew fort) ## -## -## Copyright (C) 1997-2001 by Henry Kilmer. +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. ## All rights reserved. ## -## This software may be freely copied, modified and redistributed without -## fee for non-commerical purposes provided that this copyright notice is -## preserved intact on all copies and modified copies. +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. ## ## There is no warranty or other guarantee of fitness of this software. -## It is provided solely "as is". The author(s) disclaim(s) all +## It is provided solely "as is". The author(s) disclaim(s) all ## responsibility and liability with respect to this software's usage ## or its effect upon hardware, computer systems, other software, or ## anything else. ## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. ## # # RANCID - Really Awesome New Cisco confIg Differ @@ -27,7 +30,7 @@ # usage: arancid [-d] [-l] [-f filename | $host] # use Getopt::Std; -getopts('dflm'); +getopts('dfl'); $log = $opt_l; $debug = $opt_d; $file = $opt_f; @@ -240,7 +243,11 @@ TOP: while() { while (/>>.*$prompt\s*($cmds_regexp)\s*$/) { $cmd = $1; - if (!defined($prompt)) {$prompt = ($_ =~ /^([^#]+#)/)[0]; } + if (!defined($prompt)) { + $prompt = ($_ =~ /^([^#]+#)/)[0]; + $prompt =~ s/([][}{)(\\])/\\$1/g; + print STDERR ("PROMPT MATCH: $prompt\n") if ($debug); + } print STDERR ("HIT COMMAND:$_") if ($debug); if (!defined($commands{$cmd})) { print STDERR "$host: found unexpected command - \"$cmd\"\n"; diff --git a/bin/blogin.in b/bin/blogin.in index 23bf97c..92d2e8c 100644 --- a/bin/blogin.in +++ b/bin/blogin.in @@ -1,26 +1,33 @@ -#!@EXPECT_PATH@ -- +#! @EXPECT_PATH@ -- ## +## $Id: blogin.in,v 1.22 2004/01/11 05:39:15 heas Exp $ ## -## Copyright (C) 1997-2001 by Henry Kilmer, Erik Sherk and Pete Whiting. +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. ## All rights reserved. ## -## This software may be freely copied, modified and redistributed without -## fee for non-commerical purposes provided that this copyright notice is -## preserved intact on all copies and modified copies. +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. ## ## There is no warranty or other guarantee of fitness of this software. -## It is provided solely "as is". The author(s) disclaim(s) all +## It is provided solely "as is". The author(s) disclaim(s) all ## responsibility and liability with respect to this software's usage ## or its effect upon hardware, computer systems, other software, or ## anything else. ## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. ## # +# The login expect scripts were based on Erik Sherk's gwtn, by permission. +# # blogin - Bay Networks(Nortel) login # -# Unlike the Cisco's, there is no enable function on the Bay's. -# Instead there are seperate User and Manager accounts. A 'system' command -# exists, which i am told does nothing. +# Unlike the Cisco's, there is no enable function on the Bay's. Instead +# there are seperate User and Manager accounts. A 'system' command exists, +# which I am told does nothing. +# +# The "bcc>" prompt changes to "box#", not "bcc#" after the config command. # # Usage line @@ -40,8 +47,9 @@ set do_command 0 set do_script 0 # The default is to automatically enable set enable 0 -# The default is that you login non-enabled (tacacs can have you login already enabled) -set autoenable 0 +# The default is that you login non-enabled (tacacs can have you login already +# enabled) +set avautoenable 0 # The default is to look in the password file to find the passwords. This # tracks if we receive them on the command line. set do_passwd 1 @@ -52,6 +60,8 @@ if {[ info exists env(CISCO_USER) ] } { set default_user $env(CISCO_USER) } elseif {[ info exists env(USER) ]} { set default_user $env(USER) +} elseif {[ info exists env(LOGNAME) ]} { + set default_user $env(LOGNAME) } else { # This uses "id" which I think is portable. At least it has existed # (without options) on all machines/OSes I've been on recently - @@ -107,7 +117,7 @@ for {set i 0} {$i < $argc} {incr i} { if {[ regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} { set E$varname $varvalue } else { - send_user "Error: invalid format for -E in $arg\n" + send_user "\nError: invalid format for -E in $arg\n" exit 1 } # Enable Password @@ -176,7 +186,7 @@ for {set i 0} {$i < $argc} {incr i} { set enable 0 # Does tacacs automatically enable us? } -autoenable { - set autoenable 1 + set avautoenable 1 set enable 0 } -* { send_user "\nError: Unknown argument! $arg\n" @@ -272,7 +282,7 @@ proc source_password_file { password_file } { # Log into the router. proc login { router user userpswd passwd enapasswd prompt cmethod cyphertype } { global spawn_id in_proc do_command do_script - global u_prompt p_prompt e_prompt + global u_prompt p_prompt e_prompt sshcmd set in_proc 1 # try each of the connection methods in $cmethod until one is successful @@ -290,8 +300,8 @@ proc login { router user userpswd passwd enapasswd prompt cmethod cyphertype } { exit 1 } } elseif ![string compare $prog "ssh"] { - if [ catch {spawn ssh -c $cyphertype -x -l $user $router} reason ] { - send_user "\nError: ssh failed: $reason\n" + if [ catch {spawn $sshcmd -c $cyphertype -x -l $user $router} reason ] { + send_user "\nError: $sshcmd failed: $reason\n" exit 1 } } elseif ![string compare $prog "rsh"] { @@ -408,10 +418,13 @@ proc do_enable { enauser enapasswd } { -re "$e_prompt" { send "$enapasswd\r"; exp_continue} "#" { set prompt "#" } "(enable)" { set prompt "> (enable) " } - denied { send_user "\nError: Check your Enable passwd\n"; return 1} - "% Bad passwords" { send_user "\nError: Check your Enable passwd\n" - return 1 - } + denied { send_user "\nError: Check your Enable passwd\n" + return 1 + } + "% Bad passwords" { + send_user "\nError: Check your Enable passwd\n" + return 1 + } } # We set the prompt variable (above) so script files don't need # to know what it is. @@ -440,7 +453,7 @@ proc run_commands { prompt command } { expect { -re "^\[^\n\r *]*$reprompt" {} -re "^\[^\n\r]*$reprompt." { exp_continue } - -re "\[\n\r]" { exp_continue } + -re "\[\n\r]+" { exp_continue } } } } else { @@ -448,7 +461,7 @@ proc run_commands { prompt command } { expect { -re "^\[^\n\r *]*$reprompt" {} -re "^\[^\n\r]*$reprompt." { exp_continue } - -re "\[\n\r]" { exp_continue } + -re "\[\n\r]+" { exp_continue } } } send "logout\r" @@ -473,7 +486,9 @@ foreach router [lrange $argv $i end] { # Since autoenable is off by default, if we have it defined, it # was done on the command line. If it is not specifically set on the # command line, check the password file. - if $autoenable { + if $avautoenable { + set autoenable 1 + set enable 0 set prompt "#" } else { set ae [find autoenable $router] @@ -496,15 +511,15 @@ foreach router [lrange $argv $i end] { if { $do_passwd || $do_enapasswd } { set pswd [find password $router] if { [llength $pswd] == 0 } { - send_user "Error - no password for $router in $password_file.\n" + send_user "\nError - no password for $router in $password_file.\n" continue } if { $do_enapasswd && $autoenable == 0 && [llength $pswd] < 2 } { - send_user "Error - no enable password for $router in $password_file.\n" + send_user "\nError - no enable password for $router in $password_file.\n" continue } - set passwd [lindex $pswd 0] - set enapasswd [lindex $pswd 1] + set passwd [join [lindex $pswd 0] ""] + set enapasswd [join [lindex $pswd 1] ""] } # Figure out username @@ -512,7 +527,7 @@ foreach router [lrange $argv $i end] { # command line username set ruser $username } else { - set ruser [find user $router] + set ruser [join [find user $router] ""] if { "$ruser" == "" } { set ruser $default_user } } @@ -521,7 +536,7 @@ foreach router [lrange $argv $i end] { # command line username set userpswd $userpasswd } else { - set userpswd [find userpassword $router] + set userpswd [join [find userpassword $router] ""] if { "$userpswd" == "" } { set userpswd $passwd } } @@ -530,7 +545,7 @@ foreach router [lrange $argv $i end] { # command line enausername set enauser $enausername } else { - set enauser [find enauser $router] + set enauser [join [find enauser $router] ""] if { "$enauser" == "" } { set enauser $ruser } } @@ -539,19 +554,19 @@ foreach router [lrange $argv $i end] { if { "$u_prompt" == "" } { set u_prompt "(Username|login|user name):" } else { - set u_prompt [lindex $u_prompt 0] + set u_prompt [join [lindex $u_prompt 0] ""] } set p_prompt [find passprompt $router] if { "$p_prompt" == "" } { set p_prompt "(\[Pp]assword|passwd):" } else { - set p_prompt [lindex $p_prompt 0] + set p_prompt [join [lindex $p_prompt 0] ""] } set e_prompt [find enableprompt $router] if { "$e_prompt" == "" } { set e_prompt "\[Pp]assword:" } else { - set e_prompt [lindex $e_prompt 0] + set e_prompt [join [lindex $e_prompt 0] ""] } # Figure out cypher type @@ -567,6 +582,10 @@ foreach router [lrange $argv $i end] { set cmethod [find method $router] if { "$cmethod" == "" } { set cmethod {{telnet}} } + # Figure out the SSH executable name + set sshcmd [find sshcmd $router] + if { "$sshcmd" == "" } { set sshcmd {ssh} } + # Login to the router if {[login $router $ruser $userpswd $passwd $enapasswd $prompt $cmethod $cyphertype]} { continue diff --git a/bin/brancid.in b/bin/brancid.in index 2ea7e3b..c2e602e 100644 --- a/bin/brancid.in +++ b/bin/brancid.in @@ -1,20 +1,23 @@ -#!@PERLV_PATH@ +#! @PERLV_PATH@ ## +## $Id: brancid.in,v 1.16 2004/01/11 03:49:13 heas Exp $ ## hacked version of Hank's rancid - this one tries to deal with Bay's. ## -## Copyright (C) 1997-2001 by Henry Kilmer. +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. ## All rights reserved. ## -## This software may be freely copied, modified and redistributed without -## fee for non-commerical purposes provided that this copyright notice is -## preserved intact on all copies and modified copies. +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. ## ## There is no warranty or other guarantee of fitness of this software. -## It is provided solely "as is". The author(s) disclaim(s) all +## It is provided solely "as is". The author(s) disclaim(s) all ## responsibility and liability with respect to this software's usage ## or its effect upon hardware, computer systems, other software, or ## anything else. ## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. ## # # RANCID - Really Awesome New Cisco confIg Differ @@ -22,7 +25,7 @@ # usage: rancid [-d] [-l] [-f filename | $host] # use Getopt::Std; -getopts('dflm'); +getopts('dfl'); $log = $opt_l; $debug = $opt_d; $file = $opt_f; @@ -246,7 +249,8 @@ TOP: while() { $cmd = $1; if (!defined($prompt)) { $prompt = ($_ =~ /^([^>]+>)/)[0]; - $prompt =~ s/([][])/\\$1/g; + $prompt =~ s/([][}{)(\\])/\\$1/g; + print STDERR ("PROMPT MATCH: $prompt\n") if ($debug); } print STDERR ("HIT COMMAND:$_") if ($debug); if (! defined($commands{$cmd})) { diff --git a/bin/cat5rancid.in b/bin/cat5rancid.in old mode 100755 new mode 100644 index c8219d8..f1214a1 --- a/bin/cat5rancid.in +++ b/bin/cat5rancid.in @@ -1,19 +1,22 @@ -#!@PERLV_PATH@ +#! @PERLV_PATH@ ## +## $Id: cat5rancid.in,v 1.36 2004/01/11 03:49:13 heas Exp $ ## -## Copyright (C) 1997-2001 by Henry Kilmer. +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. ## All rights reserved. ## -## This software may be freely copied, modified and redistributed without -## fee for non-commerical purposes provided that this copyright notice is -## preserved intact on all copies and modified copies. +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. ## ## There is no warranty or other guarantee of fitness of this software. -## It is provided solely "as is". The author(s) disclaim(s) all +## It is provided solely "as is". The author(s) disclaim(s) all ## responsibility and liability with respect to this software's usage ## or its effect upon hardware, computer systems, other software, or ## anything else. ## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. ## # # RANCID - Really Awesome New Cisco confIg Differ @@ -21,7 +24,7 @@ # usage: rancid [-d] [-l] [-f filename | $host] # use Getopt::Std; -getopts('dflm'); +getopts('dfl'); $log = $opt_l; $debug = $opt_d; $file = $opt_f; @@ -783,7 +786,7 @@ sub ShowPortIfindex { } } -# This routine processes a "write term" +# This routine processes a "write term {all}" sub WriteTerm { print STDERR " In WriteTerm: $_" if ($debug); @@ -791,7 +794,10 @@ sub WriteTerm { while () { tr/\015//d; last if (/^$prompt/); + last if (/^Unknown host /); # error when write term all + # is not supported next if (/^\.+$/ | /^$/); + return(0) if ($found_end); /Non-Volatile memory is in use/ && return(-1); # NvRAM is locked # skip the crap next if (/^This command shows non-default configurations only./i); @@ -862,6 +868,7 @@ sub WriteTerm { next; } /fair-queue individual-limit/ && next; + /^set port security \d+\/\d+ \S+-\S+\-/ && next; # sort ip explicit-paths. if (/^ip explicit-path name (\S+)/) { my($key) = $1; @@ -995,6 +1002,7 @@ sub DoNothing {print STDOUT;} 'dir sup-microcode:' => "DirSlotN", 'show module' => "ShowModule", 'show port ifindex' => "ShowPortIfindex", + 'write term all' => "WriteTerm", 'write term' => "WriteTerm" ); # keys() doesnt return things in the order entered and the order of the @@ -1010,6 +1018,7 @@ sub DoNothing {print STDOUT;} "dir sup-microcode:", "show module", "show port ifindex", + "write term all", "write term" ); $cisco_cmds=join(";",@commands); @@ -1062,7 +1071,11 @@ TOP: while() { } while (/> \(enable\)\s*($cmds_regexp)\s*$/) { $cmd = $1; - if (!defined($prompt)) {$prompt = ($_ =~ /^([^>]+>)/)[0]; } + if (!defined($prompt)) { + $prompt = ($_ =~ /^([^>]+>)/)[0]; + $prompt =~ s/([][}{)(\\])/\\$1/g; + print STDERR ("PROMPT MATCH: $prompt\n") if ($debug); + } print STDERR ("HIT COMMAND:$_") if ($debug); if (! defined($commands{$cmd})) { print STDERR "$host: found unexpected command - \"$cmd\"\n"; diff --git a/bin/clogin.in b/bin/clogin.in old mode 100755 new mode 100644 index c026699..281d634 --- a/bin/clogin.in +++ b/bin/clogin.in @@ -1,21 +1,26 @@ -#!@EXPECT_PATH@ -- +#! @EXPECT_PATH@ -- ## +## $Id: clogin.in,v 1.72 2004/01/11 05:39:15 heas Exp $ ## -## Copyright (C) 1997-2001 by Henry Kilmer, Erik Sherk and Pete Whiting. +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. ## All rights reserved. ## -## This software may be freely copied, modified and redistributed without -## fee for non-commerical purposes provided that this copyright notice is -## preserved intact on all copies and modified copies. +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. ## ## There is no warranty or other guarantee of fitness of this software. -## It is provided solely "as is". The author(s) disclaim(s) all +## It is provided solely "as is". The author(s) disclaim(s) all ## responsibility and liability with respect to this software's usage ## or its effect upon hardware, computer systems, other software, or ## anything else. ## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. ## # +# The login expect scripts were based on Erik Sherk's gwtn, by permission. +# # clogin - Cisco login # # Most options are intuitive for logging into a Cisco router. @@ -43,8 +48,9 @@ set do_command 0 set do_script 0 # The default is to automatically enable set enable 1 -# The default is that you login non-enabled (tacacs can have you login already enabled) -set autoenable 0 +# The default is that you login non-enabled (tacacs can have you login already +# enabled) +set avautoenable 0 # The default is to look in the password file to find the passwords. This # tracks if we receive them on the command line. set do_passwd 1 @@ -57,6 +63,8 @@ if {[ info exists env(CISCO_USER) ] } { set default_user $env(CISCO_USER) } elseif {[ info exists env(USER) ]} { set default_user $env(USER) +} elseif {[ info exists env(LOGNAME) ]} { + set default_user $env(LOGNAME) } else { # This uses "id" which I think is portable. At least it has existed # (without options) on all machines/OSes I've been on recently - @@ -112,7 +120,7 @@ for {set i 0} {$i < $argc} {incr i} { if {[ regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} { set E$varname $varvalue } else { - send_user "Error: invalid format for -E in $arg\n" + send_user "\nError: invalid format for -E in $arg\n" exit 1 } # Enable Password @@ -184,7 +192,7 @@ for {set i 0} {$i < $argc} {incr i} { set enable 0 # Does tacacs automatically enable us? } -autoenable { - set autoenable 1 + set avautoenable 1 set enable 0 } -* { send_user "\nError: Unknown argument! $arg\n" @@ -280,7 +288,7 @@ proc source_password_file { password_file } { # Log into the router. proc login { router user userpswd passwd enapasswd cmethod cyphertype } { global spawn_id in_proc do_command do_script platform - global prompt u_prompt p_prompt e_prompt + global prompt u_prompt p_prompt e_prompt sshcmd set in_proc 1 set uprompt_seen 0 @@ -299,8 +307,8 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype } { exit 1 } } elseif ![string compare $prog "ssh"] { - if [ catch {spawn ssh -c $cyphertype -x -l $user $router} reason ] { - send_user "\nError: ssh failed: $reason\n" + if [ catch {spawn $sshcmd -c $cyphertype -x -l $user $router} reason ] { + send_user "\nError: $sshcmd failed: $reason\n" exit 1 } } elseif ![string compare $prog "rsh"] { @@ -344,24 +352,32 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype } { # then it will just send the passwd. # if telnet fails with connection refused, try ssh expect { - -re "(Connection refused|Secure connection \[^\n\r]+ refused|Connection closed by)" { + -re "(Connection refused|Secure connection \[^\n\r]+ refused)" { + catch {close}; wait + if !$progs { + send_user "\nError: Connection Refused ($prog): $router\n" + return 1 + } + } + -re "(Connection closed by|Connection to \[^\n\r]+ closed)" { catch {close}; wait if !$progs { - send_user "\nError: Connection Refused ($prog)\n"; return 1 + send_user "\nError: Connection closed ($prog): $router\n" + return 1 } } - eof { send_user "\nError: Couldn't login\n"; wait; return 1 } + eof { send_user "\nError: Couldn't login: $router\n"; wait; return 1 } -nocase "unknown host\r" { catch {close}; - send_user "\nError: Unknown host\n"; wait; return 1 + send_user "\nError: Unknown host $router\n"; wait; return 1 } "Host is unreachable" { catch {close}; - send_user "\nError: Host Unreachable!\n"; wait; return 1 + send_user "\nError: Host Unreachable: $router\n"; wait; return 1 } "No address associated with name" { catch {close}; - send_user "\nError: Unknown host\n"; wait; return 1 + send_user "\nError: Unknown host $router\n"; wait; return 1 } -re "(Host key not found |The authenticity of host .* be established).*\(yes\/no\)\?" { send "yes\r" @@ -387,6 +403,12 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype } { send_user "\nError: Check your passwd for $router\n" return 1 } + -re "^Enter Selection: " { + # Catalyst 1900s have some lame menu. Enter + # K to reach a command-line. + send "K\r" + exp_continue; + } -re "@\[^\r\n]+ $p_prompt" { # ssh pwd prompt sleep 1 @@ -407,9 +429,9 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype } { } exp_continue } - "$prompt" { break; } + -re "$prompt" { break; } "Login invalid" { - send_user "\nError: Invalid login\n"; + send_user "\nError: Invalid login: $router\n"; catch {close}; wait; return 1 } } @@ -431,10 +453,19 @@ proc do_enable { enauser enapasswd } { -re "$e_prompt" { send "$enapasswd\r"; exp_continue} "#" { set prompt "#" } "(enable)" { set prompt "> (enable) " } - denied { send_user "\nError: Check your Enable passwd\n"; return 1} - "% Bad passwords" { send_user "\nError: Check your Enable passwd\n" - return 1 - } + "denied" { + # % Access denied - from local auth + send_user "\nError: Check your Enable passwd\n"; + return 1 + } + "% Error in authentication" { + send_user "\nError: Check your Enable passwd\n" + return 1 + } + "% Bad passwords" { + send_user "\nError: Check your Enable passwd\n" + return 1 + } } # We set the prompt variable (above) so script files don't need # to know what it is. @@ -449,16 +480,19 @@ proc run_commands { prompt command } { # If the prompt is (enable), then we are on a switch and the # command is "set length 0"; otherwise its "term length 0". - # skip if its an extreme. + # skip if its an extreme (since the pager can not be disabled on a + # per-vty basis). if { [ string compare "extreme" "$platform" ] } { if [ regexp -- ".*> .*enable" "$prompt" ] { send "set length 0\r" } else { send "term length 0\r" } - regsub -all "\[)(]" $prompt {\\&} reprompt - # match cisco config mode prompts too, but not for catalyst ie: (enable) - regsub -all "\[#>]$" $reprompt {(\\([^\\r\\n]+\\))?&} reprompt + # escape any parens in the prompt, such as "(enable)" + regsub -all {[)(]} $prompt {\\&} reprompt + # match cisco config mode prompts too, such as router(config-if)#, + # but catalyst does not change in this fashion. + regsub -all {^(.{1,14}).*([#>])$} $reprompt {\1([^#>\r\n]+)?[#>](\\([^)\\r\\n]+\\))?} reprompt expect { -re $reprompt {} -re "\[\n\r]+" { exp_continue } @@ -466,6 +500,7 @@ proc run_commands { prompt command } { } else { regsub -all "\[)(]" $prompt {\\&} reprompt } + # this is the only way i see to get rid of more prompts in o/p..grrrrr log_user 0 # Is this a multi-command? @@ -540,11 +575,18 @@ proc run_commands { prompt command } { send "quit\r" } expect { + -re "^\[^\n\r *]*$reprompt" { + # the Cisco CE and Jnx ERX + # return to non-enabled mode + # on exit in enabled mode. + send "exit\r" + exp_continue; + } "Do you wish to save your configuration changes" { send "n\r" exp_continue } - "\n" { exp_continue } + -re "\[\n\r]+" { exp_continue } timeout { return 0 } eof { return 0 } } @@ -564,14 +606,16 @@ foreach router [lrange $argv $i end] { # Since autoenable is off by default, if we have it defined, it # was done on the command line. If it is not specifically set on the # command line, check the password file. - if $autoenable { - set prompt "#" + if $avautoenable { + set autoenable 1 + set enable 0 + set prompt "(#| \\(enable\\))" } else { set ae [find autoenable $router] if { "$ae" == "1" } { set autoenable 1 set enable 0 - set prompt "#" + set prompt "(#| \\(enable\\))" } else { set autoenable 0 set prompt ">" @@ -587,15 +631,15 @@ foreach router [lrange $argv $i end] { if { $do_passwd || $do_enapasswd } { set pswd [find password $router] if { [llength $pswd] == 0 } { - send_user "Error: no password for $router in $password_file.\n" + send_user "\nError: no password for $router in $password_file.\n" continue } if { $enable && $do_enapasswd && $autoenable == 0 && [llength $pswd] < 2 } { - send_user "Error: no enable password for $router in $password_file.\n" + send_user "\nError: no enable password for $router in $password_file.\n" continue } - set passwd [lindex $pswd 0] - set enapasswd [lindex $pswd 1] + set passwd [join [lindex $pswd 0] ""] + set enapasswd [join [lindex $pswd 1] ""] } # Figure out username @@ -603,7 +647,7 @@ foreach router [lrange $argv $i end] { # command line username set ruser $username } else { - set ruser [find user $router] + set ruser [join [find user $router] ""] if { "$ruser" == "" } { set ruser $default_user } } @@ -612,7 +656,7 @@ foreach router [lrange $argv $i end] { # command line username set userpswd $userpasswd } else { - set userpswd [find userpassword $router] + set userpswd [join [find userpassword $router] ""] if { "$userpswd" == "" } { set userpswd $passwd } } @@ -621,7 +665,7 @@ foreach router [lrange $argv $i end] { # command line enausername set enauser $enausername } else { - set enauser [find enauser $router] + set enauser [join [find enauser $router] ""] if { "$enauser" == "" } { set enauser $ruser } } @@ -630,34 +674,38 @@ foreach router [lrange $argv $i end] { if { "$u_prompt" == "" } { set u_prompt "(Username|Login|login|user name):" } else { - set u_prompt [lindex $u_prompt 0] + set u_prompt [join [lindex $u_prompt 0] ""] } set p_prompt [find passprompt $router] if { "$p_prompt" == "" } { set p_prompt "(\[Pp]assword|passwd):" } else { - set p_prompt [lindex $p_prompt 0] + set p_prompt [join [lindex $p_prompt 0] ""] } set e_prompt [find enableprompt $router] if { "$e_prompt" == "" } { set e_prompt "\[Pp]assword:" } else { - set e_prompt [lindex $e_prompt 0] + set e_prompt [join [lindex $e_prompt 0] ""] } # Figure out cypher type if {[info exists cypher]} { - # command line cypher type - set cyphertype $cypher + # command line cypher type + set cyphertype $cypher } else { - set cyphertype [find cyphertype $router] - if { "$cyphertype" == "" } { set cyphertype "3des" } + set cyphertype [find cyphertype $router] + if { "$cyphertype" == "" } { set cyphertype "3des" } } # Figure out connection method set cmethod [find method $router] if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} } + # Figure out the SSH executable name + set sshcmd [find sshcmd $router] + if { "$sshcmd" == "" } { set sshcmd {ssh} } + # Login to the router if {[login $router $ruser $userpswd $passwd $enapasswd $cmethod $cyphertype]} { continue @@ -675,16 +723,20 @@ foreach router [lrange $argv $i end] { expect { -re "\[\r\n]+" { exp_continue; } -re "^(.+:)1 $prompt" { # stoopid extreme cmd-line numbers and - # prompt based on state of config changes + # prompt based on state of config changes, + # which may have an * at the beginning. set junk $expect_out(1,string) regsub -all "^\\\* " $expect_out(1,string) {} junk - set prompt ".? ?$junk\[0-9]+ $prompt"; + set prompt ".? ?$junk\[0-9]+ $expect_out(2,string)"; set platform "extreme" } -re "^.+$prompt" { set junk $expect_out(0,string); - regsub -all "\[\]\[]" $junk {\\&} prompt; } - -re "^.+> \\\(enable\\\)" { set junk $expect_out(0,string); - regsub -all "\[\]\[]" $junk {\\&} prompt; } + regsub -all "\[\]\[]" $junk {\\&} prompt; + } + -re "^.+> \\\(enable\\\)" { + set junk $expect_out(0,string); + regsub -all "\[\]\[]" $junk {\\&} prompt; + } } if { $do_command } { diff --git a/bin/control_rancid.in b/bin/control_rancid.in old mode 100755 new mode 100644 index 42f14ae..f51a21b --- a/bin/control_rancid.in +++ b/bin/control_rancid.in @@ -1,19 +1,22 @@ -#!/bin/sh +#! /bin/sh ## +## $Id: control_rancid.in,v 1.61 2004/01/11 05:25:13 hank Exp $ ## -## Copyright (C) 1996-2001 by Henry Kilmer. +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. ## All rights reserved. ## -## This software may be freely copied, modified and redistributed without -## fee for non-commerical purposes provided that this copyright notice is -## preserved intact on all copies and modified copies. +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. ## ## There is no warranty or other guarantee of fitness of this software. -## It is provided solely "as is". The author(s) disclaim(s) all +## It is provided solely "as is". The author(s) disclaim(s) all ## responsibility and liability with respect to this software's usage ## or its effect upon hardware, computer systems, other software, or ## anything else. ## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. ## # # control_rancid $GROUP @@ -80,6 +83,7 @@ trap 'rm -fr $TMP;' 1 2 15 # the receipient(s) of diffs mailrcpt=${mailrcpt:-"@MAILPLUS@$GROUP"}; export mailrcpt +adminmailrcpt=${mailrcpt:-"@ADMINMAILPLUS@$GROUP"}; export adminmailrcpt # Number of things par should run in parallel. PAR_COUNT=${PAR_COUNT:-5} @@ -88,14 +92,14 @@ PAR_COUNT=${PAR_COUNT:-5} if [ ! -d $DIR ] then echo "$DIR does not exist." - echo "Run bin/create_cvs $GROUP to make all of the needed directories." + echo "Run bin/rancid-cvs $GROUP to make all of the needed directories." ( - echo "To: @MAILPLUS@admin-$GROUP" + echo "To: $adminmailrcpt" echo "Subject: no $GROUP directory" echo "Precedence: bulk" echo "" echo "$DIR does not exist." - echo "Run bin/create_cvs $GROUP to make all of the needed directories." + echo "Run bin/rancid-cvs $GROUP to make all of the needed directories." ) | sendmail -t exit 1 fi @@ -116,7 +120,7 @@ rm -f $TMP if [ ! -f $DIR/router.db ] then ( - echo "To: @MAILPLUS@admin-$GROUP" + echo "To: $adminmailrcpt" echo "Subject: no $GROUP/router.db file" echo "Precedence: bulk" echo "" @@ -132,16 +136,17 @@ fi cd $DIR trap 'rm -fr routers.db routers.all.new routers.down.new routers.up.new \ routers.mail routers.added routers.deleted $TMP;' 1 2 15 -grep -v '^#' router.db > routers.db -cut -d: -f1,2 routers.db | sort -u > routers.all.new +sed -e '/^#/d' -e 's/^ *//' -e 's/ *$//' -e 's/ *: */:/g' router.db | + sort -u > routers.db +cut -d: -f1,2 routers.db > routers.all.new if [ ! -f routers.all ] ; then touch routers.all; fi diff routers.all routers.all.new > /dev/null 2>&1; RALL=$? @PERLV@ -F: -ane '{($F[0] =~ tr@A-Z@a-z@,print $_) - if ($F[2] !~ /^up$/i);}' routers.db | sort -u > routers.down.new + if ($F[2] !~ /^up$/i);}' routers.db > routers.down.new if [ ! -f routers.down ] ; then touch routers.down; fi diff routers.down routers.down.new > /dev/null 2>&1; RDOWN=$? @PERLV@ -F: -ane '{($F[0] =~ tr@A-Z@a-z@,print "$F[0]:$F[1]\n") - if ($F[2] =~ /^up$/i);}' routers.db | sort -u > routers.up.new + if ($F[2] =~ /^up$/i);}' routers.db > routers.up.new if [ ! -f routers.up ] ; then touch routers.up; fi diff routers.up routers.up.new > /dev/null 2>&1; RUP=$? @@ -207,7 +212,7 @@ then if [ -s routers.mail ] ; then ( - echo "To: @MAILPLUS@admin-$GROUP" + echo "To: $adminmailrcpt" echo "Subject: changes in $GROUP routers" echo "Precedence: bulk" echo "" @@ -236,9 +241,18 @@ then cd $DIR fi -mv routers.all.new routers.all -mv routers.down.new routers.down -mv routers.up.new routers.up +mv -f routers.all.new routers.all +if [ $? -ne 0 ]; then + echo "Error: could not rename routers.all.new" +fi +mv -f routers.down.new routers.down +if [ $? -ne 0 ]; then + echo "Error: could not rename routers.down.new" +fi +mv -f routers.up.new routers.up +if [ $? -ne 0 ]; then + echo "Error: could not rename routers.up.new" +fi rm -f routers.db trap 'rm -fr $TMP;' 1 2 15 @@ -290,6 +304,7 @@ cd $DIR/configs # The number of processes running at any given time can be # tailored to the specific installation. +echo "" echo "Trying to get all of the configs." par -q -n $PAR_COUNT -c "rancid-fe \{}" $devlistfile @@ -331,19 +346,27 @@ do done echo -# Make sure that all of the new configs are not empty. -for config in *.new -do - if [ ! -s $config ] +# Make sure that no empty configs are accepted. Those that are non-empty +# are renamed from device_name.new -> device_name. +for router in `cat $devlistfile` +do + OFS=$IFS + IFS=':' + set $router + IFS=$OFS + router=$1; + + if [ ! -s $router.new ] then - rm -f $config + rm -f $router.new + else + mv $router.new $router + if [ $? -ne 0 ]; then + echo "Error: could not rename $router.new to $router" + fi fi done -# Now that we have the new configs, rename them to their proper -# name. -rename 's/.new$//' *.new - # This has been different for different machines... # Diff the directory and then checkin. trap 'rm -fr $TMP $TMP.diff $DIR/routers.single;' 1 2 15 @@ -387,7 +410,7 @@ fi if [ -s $DIR/routers.failed ] then ( - echo "To: @MAILPLUS@admin-$GROUP" + echo "To: $adminmailrcpt" echo "Subject: config fetcher problems - $GROUP" echo "Precedence: bulk" echo "" diff --git a/bin/create_cvs.in b/bin/create_cvs.in deleted file mode 100755 index 06d414b..0000000 --- a/bin/create_cvs.in +++ /dev/null @@ -1,89 +0,0 @@ -#!/bin/sh -## -## -## Copyright (C) 1996-2001 by Henry Kilmer. -## All rights reserved. -## -## This software may be freely copied, modified and redistributed without -## fee for non-commerical purposes provided that this copyright notice is -## preserved intact on all copies and modified copies. -## -## There is no warranty or other guarantee of fitness of this software. -## It is provided solely "as is". The author(s) disclaim(s) all -## responsibility and liability with respect to this software's usage -## or its effect upon hardware, computer systems, other software, or -## anything else. -## -## -# -# Create all of the misc files & dirs needed. -# -# create_cvs -# - -# Read in the environment -ENVFILE="`dirname $0`/env" - -. $ENVFILE - -# Base dir -if [ ! -d $BASEDIR ]; then - mkdir -p $BASEDIR -fi - -cd $BASEDIR - -# Top level CVS stuff -if [ ! -d $CVSROOT ]; then - cvs init -fi - -# Log dir -if [ ! -d logs ]; then - mkdir logs -fi - -# Which groups to do -if [ $# -ge 1 ] ; then - LIST_OF_GROUPS="$*"; export LIST_OF_GROUPS -elif [ "$LIST_OF_GROUPS" = "" ] ; then - echo "LIST_OF_GROUPS is empty in $ENVFILE" - exit 1 -fi - -for GROUP in `echo $LIST_OF_GROUPS` ; -do - - DIR=$BASEDIR/$GROUP - - # Directory for the group and the configs - if [ ! -d $DIR ]; then - mkdir -p $DIR - cd $DIR - cvs import -m "$GROUP" $GROUP new rancid - cd $BASEDIR - cvs co $GROUP - fi - cd $DIR - if [ ! -d configs ]; then - mkdir configs - cvs add configs - cvs commit -m 'new' configs - fi - - # main files - if [ ! -f routers.all ]; then - touch routers.all - fi - if [ ! -f routers.down ]; then - touch routers.down - fi - if [ ! -f routers.up ]; then - touch routers.up - fi - if [ ! -f router.db ]; then - touch router.db - cvs add router.db - cvs commit -m 'new' router.db - fi -done diff --git a/bin/cssrancid.in b/bin/cssrancid.in new file mode 100644 index 0000000..27049df --- /dev/null +++ b/bin/cssrancid.in @@ -0,0 +1,660 @@ +#! @PERLV_PATH@ +## +## $Id: cssrancid.in,v 1.4 2004/01/11 03:49:13 heas Exp $ +## +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## All rights reserved. +## +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. +## +## There is no warranty or other guarantee of fitness of this software. +## It is provided solely "as is". The author(s) disclaim(s) all +## responsibility and liability with respect to this software's usage +## or its effect upon hardware, computer systems, other software, or +## anything else. +## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. +## +# +# RANCID - Really Awesome New Cisco confIg Differ +# +# usage: rancid [-d] [-l] [-f filename | $host] +# +use Getopt::Std; +getopts('dfl'); +$log = $opt_l; +$debug = $opt_d; +$file = $opt_f; +$host = $ARGV[0]; +$clean_run = 0; +$found_end = 0; +$timeo = 90; # clogin timeout in seconds + +my(%filter_pwds); # password filtering mode + +# This routine is used to print out the router configuration +sub ProcessHistory { + my($new_hist_tag,$new_command,$command_string,@string)=(@_); + if((($new_hist_tag ne $hist_tag) || ($new_command ne $command)) + && defined %history) { + print eval "$command \%history"; + undef %history; + } + if (($new_hist_tag) && ($new_command) && ($command_string)) { + if ($history{$command_string}) { + $history{$command_string} = "$history{$command_string}@string"; + } else { + $history{$command_string} = "@string"; + } + } elsif (($new_hist_tag) && ($new_command)) { + $history{++$#history} = "@string"; + } else { + print "@string"; + } + $hist_tag = $new_hist_tag; + $command = $new_command; + 1; +} + +sub numerically { $a <=> $b; } + +# This is a sort routine that will sort numerically on the +# keys of a hash as if it were a normal array. +sub keynsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort numerically keys(%lines)) { + $sorted_lines[$i] = $lines{$key}; + $i++; + } + @sorted_lines; +} + +# This is a sort routine that will sort on the +# keys of a hash as if it were a normal array. +sub keysort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort keys(%lines)) { + $sorted_lines[$i] = $lines{$key}; + $i++; + } + @sorted_lines; +} + +# This is a sort routine that will sort on the +# values of a hash as if it were a normal array. +sub valsort{ + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort values %lines) { + $sorted_lines[$i] = $key; + $i++; + } + @sorted_lines; +} + +# This is a numerical sort routine (ascending). +sub numsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $num (sort {$a <=> $b} keys %lines) { + $sorted_lines[$i] = $lines{$num}; + $i++; + } + @sorted_lines; +} + +# This is a sort routine that will sort on the +# ip address when the ip address is anywhere in +# the strings. +sub ipsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $addr (sort sortbyipaddr keys %lines) { + $sorted_lines[$i] = $lines{$addr}; + $i++; + } + @sorted_lines; +} + +# These two routines will sort based upon IP addresses +sub ipaddrval { + my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#); + $a[3]+256*($a[2]+256*($a[1]+256*$a[0])); +} +sub sortbyipaddr { + &ipaddrval($a) <=> &ipaddrval($b); +} + +# This routine parses "show version" +sub ShowVersion { + print STDERR " In ShowVersion: $_" if ($debug); + + while () { + tr/\015//d; + study; + last if(/^$prompt/); + next if(/^(\s*|\s*$cmd\s*)$/); + return(-1) if (/command authorization failed/i); + if (/^Slave in slot (\d+) is running/) { + $slave = " Slave:"; + next; + } + /^Cisco Secure PIX /i && + ProcessHistory("COMMENTS","keysort","F1", "!Image: $_") && next; + /^IOS .* Software \(([A-Za-z-0-9]*)\), .*Version\s+(.*)$/ && + ProcessHistory("COMMENTS","keysort","F1", + "!Image:$slave Software: $1, $2\n") && next; + /^([A-Za-z-0-9_]*) Synced to mainline version: (.*)$/ && + ProcessHistory("COMMENTS","keysort","F2", + "!Image:$slave $1 Synced to mainline version: $2\n") && next; + /^Compiled (.*)$/ && + ProcessHistory("COMMENTS","keysort","F3", + "!Image:$slave Compiled: $1\n") && next; + /^ROM: (System )?Bootstrap.*(Version.*)$/ && + ProcessHistory("COMMENTS","keysort","G1", + "!ROM Bootstrap: $2\n") && next; + if (/^Hardware:\s+(.*), (.* RAM), CPU (.*)$/) { + ProcessHistory("COMMENTS","keysort","A1", + "!Chassis type: $1 - a PIX\n"); + ProcessHistory("COMMENTS","keysort","A2", + "!CPU: $3\n"); + ProcessHistory("COMMENTS","keysort","B1", "!Memory: $2\n"); + } + /^Serial Number:\s+(.*)$/ && + ProcessHistory("COMMENTS","keysort","C1", "!$_") && next; + /^Activation Key:\s+(.*)$/ && + ProcessHistory("COMMENTS","keysort","C2", "!$_") && next; + /^ROM: \d+ Bootstrap .*(Version.*)$/ && + ProcessHistory("COMMENTS","keysort","G2", + "!ROM Image: Bootstrap $1\n!\n") && next; + /^ROM: .*(Version.*)$/ && + ProcessHistory("COMMENTS","keysort","G3","!ROM Image: $1\n") && next; + /^BOOTFLASH: .*(Version.*)$/ && + ProcessHistory("COMMENTS","keysort","G4","!BOOTFLASH: $1\n") && next; + /^BOOTLDR: .*(Version.*)$/ && + ProcessHistory("COMMENTS","keysort","G4","!BOOTLDR: $1\n") && next; + /^System image file is "([^\"]*)", booted via (\S*)/ && + ProcessHistory("COMMENTS","keysort","F4","!Image: booted $1\n") && + next; + /^System image file is "([^\"]*)"$/ && + ProcessHistory("COMMENTS","keysort","F5","!Image: $1\n") && next; + if (/(\S+)\s+\((\S+)\)\s+processor.*with (\S+[kK]) bytes/) { + my($proc) = $1; + my($cpu) = $2; + my($mem) = $3; + my($device) = "router"; + $type = "CSS"; + print STDERR "TYPE = $type\n" if ($debug); + ProcessHistory("COMMENTS","keysort","A1", + "!Chassis type:$slave $proc - a $type $device\n"); + ProcessHistory("COMMENTS","keysort","B1", + "!Memory:$slave main $mem\n"); + ProcessHistory("COMMENTS","keysort","A3","!CPU:$slave $cpu\n"); + next; + } + if (/(\S+) Silicon\s*Switch Processor/) { + if (!defined($C0)) { + $C0=1; ProcessHistory("COMMENTS","keysort","C0","!\n"); + } + ProcessHistory("COMMENTS","keysort","C2","!SSP: $1\n"); + $ssp = 1; + $sspmem = $1; + next; + } + /^(\d+[kK]) bytes of multibus/ && + ProcessHistory("COMMENTS","keysort","B2", + "!Memory: multibus $1\n") && next; + /^(\d+[kK]) bytes of non-volatile/ && + ProcessHistory("COMMENTS","keysort","B3", + "!Memory: nvram $1\n") && next; + /^(\d+[kK]) bytes of flash memory/ && + ProcessHistory("COMMENTS","keysort","B5","!Memory: flash $1\n") && + next; + /^(\d+[kK]) bytes of .*flash partition/ && + ProcessHistory("COMMENTS","keysort","B6", + "!Memory: flash partition $1\n") && next; + /^(\d+[kK]) bytes of Flash internal/ && + ProcessHistory("COMMENTS","keysort","B4", + "!Memory: bootflash $1\n") && next; + if(/^(\d+[kK]) bytes of (Flash|ATA)?.*PCMCIA .*(slot|disk) ?(\d)/i) { + ProcessHistory("COMMENTS","keysort","B7", + "!Memory: pcmcia $2 $3$4 $1\n"); + next; + } + if(/^WARNING/) { + if (!defined($I0)) { + $I0=1; + ProcessHistory("COMMENTS","keysort","I0","!\n"); + } + ProcessHistory("COMMENTS","keysort","I1","! $_"); + # The line after the WARNING is what to do about it. + $_ = ; tr/\015//d; + ProcessHistory("COMMENTS","keysort","I1","! $_"); + } + if (/^Configuration register is (.*)$/) { + $config_register=$1; + next; + } + } + return(0); +} + + +# Dummy routine to set term length.... +sub TermLength { + # Dummy subroutine.. need to set term length differently for CSS + # boxes as term length 0 doesnt work correctly. POS. + return(0); +} + +# Dummy routine to copy profile... +sub CopyProfile { + ## Because the term length gets changed twice, the stupid + ## box will ask you to save or discard changes. This prompt + ## of couse breaks the interaction... strangely enough tho + ## in a failover environment, only the secondary behaves this + ## way.. the primary lets you log out and does not complain. + return(0); +} + + +# This routine parses "show boot" +sub ShowBoot { + # Pick up boot variables if 7000/7200/7500/12000/2900/3500; + # otherwise pick up bootflash. + print STDERR " In ShowBoot: $_" if ($debug); + + while () { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^\s*\^\s*$/; + return(-1) if (/command authorization failed/i); + return(1) if /Ambiguous command/i; + # return(1) if /(Invalid input detected|Type help or )/; + return(1) if /(Open device \S+ failed|Error opening \S+:)/; + next if /CONFGEN variable/; + if (!defined($H0)) { + $H0=1; ProcessHistory("COMMENTS","keysort","H0","!\n"); + } + if ($type !~ /^(12[04]|7)/) { + if ($type !~ /^(29|35)00/) { + ProcessHistory("COMMENTS","keysort","H2","!BootFlash: $_"); + } else { + ProcessHistory("COMMENTS","keysort","H1","!Variable: $_"); + } + } elsif (/variable/) { + ProcessHistory("COMMENTS","keysort","H1","!Variable: $_"); + } + } + ProcessHistory("COMMENTS","","","!\n"); + return(0); +} + + +# This routine processes a "show run" +sub ShowRun { + print STDERR " In ShowRun: $_" if ($debug); + my($lineauto) = 0; + + while () { + tr/\015//d; + study; + last if(/^$prompt/); + return(-1) if (/command authorization failed/i); + # the pager can not be disabled per-session on the PIX + s/^<-+ More -+>\s*//; + /Non-Volatile memory is in use/ && return(-1); # NvRAM is locked + $lineauto = 0 if (/^[^ ]/); + # skip the crap + if (/^(##+$|(Building|Current) configuration)/i) { + while () { + next if (/^Current configuration\s*:/i); + next if (/^:/); + next if (/^([%!].*|\s*)$/); + next if (/^ip add.*ipv4:/); # band-aid for 3620 12.0S + last; + } + if (defined($config_register)) { + ProcessHistory("","","","!\nconfig-register $config_register\n"); + } + tr/\015//d; + } + # some versions have other crap mixed in with the bits in the + # block above + /^! (Last configuration|NVRAM config last)/ && next; + ## CSS specific.... + /Generated on/ && next; + + # Dog gone Cool matches to process the rest of the config + /^tftp-server flash / && next; # kill any tftp remains + /^ntp clock-period / && next; # kill ntp clock-period + /^ length / && next; # kill length on serial lines + /^ width / && next; # kill width on serial lines + $lineauto = 1 if /^ modem auto/; + /^ speed / && $lineauto && next; # kill speed on serial lines + /^ clockrate / && next; # kill clockrate on serial interfaces + if (/^(enable )?(password|passwd) / && $filter_pwds >= 1) { + ProcessHistory("ENABLE","","","!$1$2 \n"); + next; + } + if (/^(enable secret) / && $filter_pwds >= 2) { + ProcessHistory("ENABLE","","","!$1 \n"); + next; + } + if (/^username (\S+)(\s.*)? secret /) { + if ($filter_pwds >= 2) { + ProcessHistory("USER","keysort","$1","!username $1$2 secret \n"); + } else { + ProcessHistory("USER","keysort","$1","$_"); + } + next; + } + if (/^username (\S+)(\s.*)? password ((\d) \S+|\S+)/) { + if ($filter_pwds == 2) { + ProcessHistory("USER","keysort","$1","!username $1$2 password \n"); + } elsif ($filter_pwds == 1 && $4 ne "5"){ + ProcessHistory("USER","keysort","$1","!username $1$2 password \n"); + } else { + ProcessHistory("USER","keysort","$1","$_"); + } + next; + } + if (/^(\s*)password / && $filter_pwds >= 1) { + ProcessHistory("LINE-PASS","","","!$1password \n"); + next; + } + if (/^\s*neighbor (\S*) password / && $filter_pwds >= 1) { + ProcessHistory("","","","! neighbor $1 password \n"); + next; + } + if (/^(ppp .* password) 7 .*/ && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); next; + } + if (/^(ip ftp password) / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); next; + } + if (/^( ip ospf authentication-key) / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); next; + } + # isis passwords appear to be completely plain-text + if (/^\s+isis password (\S+)( .*)?/ && $filter_pwds >= 1) { + ProcessHistory("","","","!isis password $2\n"); next; + } + if (/^\s+(domain-password|area-password) (\S+)( .*)?/ + && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 $2\n"); next; + } + # this is reversable, despite 'md5' in the cmd + if (/^( ip ospf message-digest-key \d+ md5) / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); next; + } + if (/^((crypto )?isakmp key) \S+ / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 $'"); next; + } + # i am told these are plain-text on the PIX + if (/^(vpdn username \S+ password)/ && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); next; + } + /fair-queue individual-limit/ && next; + # sort ip explicit-paths. + if (/^ip explicit-path name (\S+)/) { + my($key) = $1; + my($expath) = $_; + while () { + tr/\015//d; + last if (/^$prompt/); + last if (/^$prompt/ || ! /^(ip explicit-path name |[ !])/); + if (/^ip explicit-path name (\S+)/) { + ProcessHistory("EXPATH","keysort","$key","$expath"); + $key = $1; + $expath = $_; + } else { + $expath .= $_; + } + } + ProcessHistory("EXPATH","keysort","$key","$expath"); + } + # sort route-maps + if (/^route-map (\S+)/) { + my($key) = $1; + my($routemap) = $_; + while () { + tr/\015//d; + last if (/^$prompt/ || ! /^(route-map |[ !])/); + if (/^route-map (\S+)/) { + ProcessHistory("ROUTEMAP","keysort","$key","$routemap"); + $key = $1; + $routemap = $_; + } else { + $routemap .= $_; + } + } + ProcessHistory("ROUTEMAP","keysort","$key","$routemap"); + } + # filter out any RCS/CVS tags to avoid confusing local CVS storage + s/\$(Revision|Id):/ $1:/; + # order access-lists + /^access-list\s+(\d\d?)\s+(\S+)\s+(\S+)/ && + ProcessHistory("ACL $1 $2","ipsort","$3","$_") && next; + # order extended access-lists + /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+host\s+(\S+)/ && + ProcessHistory("EACL $1 $2","ipsort","$3","$_") && next; + /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+(\d\S+)/ && + ProcessHistory("EACL $1 $2","ipsort","$3","$_") && next; + /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+any/ && + ProcessHistory("EACL $1 $2","ipsort","0.0.0.0","$_") && next; + # order arp lists + /^arp\s+(\d+\.\d+\.\d+\.\d+)\s+/ && + ProcessHistory("ARP","ipsort","$1","$_") && next; + /^ip prefix-list\s+(\S+)\s+seq\s+(\d+)\s+(permit|deny)\s+(\d\S+)(\/.*)$/ && + ProcessHistory("PACL $1 $3","ipsort","$4","ip prefix-list $1 $3 $4$5\n") + && next; + # order logging statements + /^logging (\d+\.\d+\.\d+\.\d+)/ && + ProcessHistory("LOGGING","ipsort","$1","$_") && next; + # order/prune snmp-server host statements + # we only prune lines of the form + # snmp-server host a.b.c.d + if (/^snmp-server host (\d+\.\d+\.\d+\.\d+) /) { + if (defined($ENV{'NOCOMMSTR'})) { + my($ip) = $1; + my($line) = "snmp-server host $ip"; + my(@tokens) = split(' ', $'); + my($token); + while ($token = shift(@tokens)) { + if ($token eq 'version') { + $line .= " " . join(' ', ($token, shift(@tokens))); + } elsif ($token =~ /^(informs?|traps?|(no)?auth)$/) { + $line .= " " . $token; + } else { + $line = "!$line " . join(' ', ("", join(' ',@tokens))); + last; + } + } + ProcessHistory("SNMPSERVERHOST","ipsort","$ip","$line\n"); + } else { + ProcessHistory("SNMPSERVERHOST","ipsort","$1","$_"); + } + next; + } + if (/^(snmp-server community) (\S+)/) { + if (defined($ENV{'NOCOMMSTR'})) { + ProcessHistory("SNMPSERVERCOMM","keysort","$_","!$1 $'") && next; + } else { + ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && next; + } + } + # order/prune tacacs/radius server statements + if (/^(tacacs-server|radius-server) key / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 key \n"); next; + } + # order clns host statements + /^clns host \S+ (\S+)/ && + ProcessHistory("CLNS","keysort","$1","$_") && next; + # order alias statements + /^alias / && ProcessHistory("ALIAS","keysort","$_","$_") && next; + # delete ntp auth password - this md5 is a reversable too + if (/^(ntp authentication-key \d+ md5) / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); next; + } + # order ntp peers/servers + if (/^ntp (server|peer) (\d+)\.(\d+)\.(\d+)\.(\d+)/) { + $sortkey = sprintf("$1 %03d%03d%03d%03d",$2,$3,$4,$5); + ProcessHistory("NTP","keysort",$sortkey,"$_"); + next; + } + # order ip host line statements + /^ip host line(\d+)/ && + ProcessHistory("IPHOST","numsort","$1","$_") && next; + # order ip nat source static statements + /^ip nat (\S+) source static (\S+)/ && + ProcessHistory("IP NAT $1","ipsort","$2","$_") && next; + # order atm map-list statements + /^\s+ip\s+(\d+\.\d+\.\d+\.\d+)\s+atm-vc/ && + ProcessHistory("ATM map-list","ipsort","$1","$_") && next; + # order ip rcmd lines + /^ip rcmd/ && ProcessHistory("RCMD","keysort","$_","$_") && next; + + # system controller + /^syscon address (\S*) (\S*)/ && + ProcessHistory("","","","!syscon address $1 \n") && + next; + if (/^syscon password (\S*)/ && $filter_pwds >= 1) { + ProcessHistory("","","","!syscon password \n"); + next; + } + + # catch anything that wasnt matched above. + ProcessHistory("","","","$_"); + # end of config. the ": " game is for the PIX + if (/^(: +)?end$/ || /CSS.*#/ || /$prompt/ ) { + $found_end = 1; + return(1); + } + } + return(0); +} + +# dummy function +sub DoNothing {print STDOUT;} + +# Main +%commands=( + 'term length 65535' => "TermLength", + 'copy profile user-profile' => "CopyProfile", + 'show version' => "ShowVersion", + 'show boot' => "ShowBoot", + 'show run' => "ShowRun" +); +# keys() doesnt return things in the order entered and the order of the +# cmds is important (show version first and show run last). pita +@commands=( + "term length 65535", + "copy profile user-profile", + "show version", + "show boot", + "show run" +); +$cisco_cmds=join(";",@commands); +$cmds_regexp=join("|",@commands); + +open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; +select(OUTPUT); +# make OUTPUT unbuffered if debugging +if ($debug) { $| = 1; } + +if ($file) { + print STDERR "opening file $host\n" if ($debug); + print STDOUT "opening file $host\n" if ($log); + open(INPUT,"<$host") || die "open failed for $host: $!\n"; +} else { + print STDERR "executing clogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($debug); + print STDOUT "executing clogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($log); + if (defined($ENV{NOPIPE})) { + system "clogin -t $timeo -c \"$cisco_cmds\" $host $host.raw 2>&1" || die "clogin failed for $host: $!\n"; + open(INPUT, "< $host.raw") || die "clogin failed for $host: $!\n"; + } else { + open(INPUT,"clogin -t $timeo -c \"$cisco_cmds\" $host ) { + tr/\015//d; + if (/\#\s?exit/) { + $clean_run=1; + last; + } + if (/^Error:/) { + print STDOUT ("$host clogin error: $_"); + print STDERR ("$host clogin error: $_") if ($debug); + $clean_run=0; + last; + } + while (/#\s*($cmds_regexp)\s*$/) { + $cmd = $1; + if (!defined($prompt)) {$prompt = ($_ =~ /^([^#]+#)/)[0]; } + print STDERR ("HIT COMMAND:$_") if ($debug); + if (! defined($commands{$cmd})) { + print STDERR "$host: found unexpected command - \"$cmd\"\n"; + # $clean_run = 0; + # last TOP; + next TOP; + } else { + $rval = &{$commands{$cmd}}; + delete($commands{$cmd}); + if ($rval == -1) { + $clean_run = 0; + last TOP; + } + } + } +} +print STDOUT "Done $logincmd: $_\n" if ($log); +# Flush History +ProcessHistory("","","",""); +# Cleanup +close(INPUT); +close(OUTPUT); + +if (defined($ENV{NOPIPE})) { + unlink("$host.raw") if (! $debug); +} + +# check for completeness +if (scalar(%commands) || !$clean_run || !$found_end) { + if (scalar(%commands)) { + printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands))); + printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug); + } + if (!$clean_run || !$found_end) { + print STDOUT "$host: End of run not found\n"; + print STDERR "$host: End of run not found\n" if ($debug); + system("/usr/bin/tail -1 $host.new"); + } + unlink "$host.new" if (! $debug); +} diff --git a/bin/do-diffs.in b/bin/do-diffs.in deleted file mode 100755 index 874007c..0000000 --- a/bin/do-diffs.in +++ /dev/null @@ -1,128 +0,0 @@ -#!/bin/sh -## Copyright (C) 1997-2001 by Henry Kilmer. -## All rights reserved. -## -## This software may be freely copied, modified and redistributed without -## fee for non-commerical purposes provided that this copyright notice is -## preserved intact on all copies and modified copies. -## -## There is no warranty or other guarantee of fitness of this software. -## It is provided solely "as is". The author(s) disclaim(s) all -## responsibility and liability with respect to this software's usage -## or its effect upon hardware, computer systems, other software, or -## anything else. -## -# do diffs for each of the diff groups ($LIST_OF_GROUPS) from /bin/env -## - -ENVFILE="`dirname $0`/env" - -. $ENVFILE - -TMPDIR=${TMPDIR:=/tmp}; export TMPDIR - -# control_rancid argv -CR_ARGV=""; export CR_ARGV - -# print a usage message to stderr -pr_usage() { - echo "usage: $0 [-r device_name] [-m mail rcpt] [group [group ...]]" >&2; -} - -# command-line options -# -r -if [ $# -ge 1 ] ; then - - while [ 1 ] ; do - case $1 in - -r) - shift - # next arg is the device name - CR_ARGV="$CR_ARGV -r $1"; export CR_ARGV - shift - ;; - -m) - shift - # next arg is the mailto name - CR_ARGV="$CR_ARGV -m $1"; export CR_ARGV - shift - ;; - --) - shift; break; - ;; - -h) - pr_usage - exit - ;; - -*) - echo "unknown option: $1" >&2 - pr_usage - exit 1 - ;; - *) - break; - ;; - esac - done -fi - -if [ $# -ge 1 ] ; then - LIST_OF_GROUPS="$*"; export LIST_OF_GROUPS -elif [ "$LIST_OF_GROUPS" = "" ] ; then - echo "LIST_OF_GROUPS is empty in $ENVFILE" - exit 1 -fi - -if [ ! -d $BASEDIR/logs ] ; then - mkdir $BASEDIR/logs -fi - -for GROUP in $LIST_OF_GROUPS -do - - LOCKFILE=$TMPDIR/.$GROUP.run.lock - - ( - echo starting: `date` - echo - - if [ -f $LOCKFILE ] - then - echo hourly config diffs failed: $LOCKFILE exists - ls -l $LOCKFILE - - # Send email if the lock file is old. - if [ "X$LOCKTIME" = "X" ] ; then - LOCKTIME=4 - fi - @PERLV@ -e "\$t = (stat(\"$LOCKFILE\"))[9]; print \"OLD\\n\" if (time() - \$t >= $LOCKTIME*60*60);" > $TMPDIR/.$GROUP.old - if [ -s $TMPDIR/.$GROUP.old ] - then - ( - echo "To: @MAILPLUS@admin-$GROUP" - echo "Subject: rancid hung - $GROUP" - echo "Precedence: bulk" - echo "" - - cat <$BASEDIR/logs/$GROUP.`date +%Y%m%d.%H%M%S` 2>&1 -done diff --git a/bin/elogin.in b/bin/elogin.in old mode 100755 new mode 100644 index 1b647fa..651d7fb --- a/bin/elogin.in +++ b/bin/elogin.in @@ -1,19 +1,22 @@ -#!@EXPECT_PATH@ -- +#! @EXPECT_PATH@ -- ## +## $Id: elogin.in,v 1.27 2004/01/11 05:39:15 heas Exp $ ## -## Copyright (C) 1997-2001 by Henry Kilmer, Erik Sherk and Pete Whiting. +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. ## All rights reserved. ## -## This software may be freely copied, modified and redistributed without -## fee for non-commerical purposes provided that this copyright notice is -## preserved intact on all copies and modified copies. +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. ## ## There is no warranty or other guarantee of fitness of this software. -## It is provided solely "as is". The author(s) disclaim(s) all +## It is provided solely "as is". The author(s) disclaim(s) all ## responsibility and liability with respect to this software's usage ## or its effect upon hardware, computer systems, other software, or ## anything else. ## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. ## # # elogin - ADC EZT3 login @@ -38,8 +41,9 @@ set do_command 0 set do_script 0 # The default is to automatically enable set enable 1 -# The default is that you login non-enabled (tacacs can have you login already enabled) -set autoenable 0 +# The default is that you login non-enabled (tacacs can have you login already +# enabled) +set avautoenable 0 # The default is to look in the password file to find the passwords. This # tracks if we receive them on the command line. set do_passwd 1 @@ -49,6 +53,8 @@ if {[ info exists env(CISCO_USER) ] } { set default_user $env(CISCO_USER) } elseif {[ info exists env(USER) ]} { set default_user $env(USER) +} elseif {[ info exists env(LOGNAME) ]} { + set default_user $env(LOGNAME) } else { # This uses "id" which I think is portable. At least it has existed # (without options) on all machines/OSes I've been on recently - @@ -101,7 +107,7 @@ for {set i 0} {$i < $argc} {incr i} { if {[ regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} { set E$varname $varvalue } else { - send_user "Error: invalid format for -E in $arg\n" + send_user "\nError: invalid format for -E in $arg\n" exit 1 } # Enable Password @@ -166,10 +172,10 @@ for {set i 0} {$i < $argc} {incr i} { set do_command 1 # Do we enable? } -noenable { - # ignore -noenable + # ignore -noenable # Does tacacs automatically enable us? } -autoenable { - # ignore -autoenable + # ignore -autoenable } -* { send_user "\nError: Unknown argument! $arg\n" send_user $usage @@ -406,17 +412,17 @@ foreach router [lrange $argv $i end] { # Figure out prompt. set prompt "Active) > " - set autoenable 1 - set enable 0 + set autoenable 1 + set enable 0 # Figure out passwords if { $do_passwd } { set pswd [find password $router] if { [llength $pswd] == 0 } { - send_user "Error: no password for $router in $password_file.\n" + send_user "\nError: no password for $router in $password_file.\n" continue } - set passwd [lindex $pswd 0] + set passwd [join [lindex $pswd 0] ""] } # Figure out username @@ -424,7 +430,7 @@ foreach router [lrange $argv $i end] { # command line username set ruser $username } else { - set ruser [find user $router] + set ruser [join [find user $router] ""] if { "$ruser" == "" } { set ruser $default_user } } @@ -433,7 +439,7 @@ foreach router [lrange $argv $i end] { # command line username set userpswd $userpasswd } else { - set userpswd [find userpassword $router] + set userpswd [join [find userpassword $router] ""] if { "$userpswd" == "" } { set userpswd $passwd } } @@ -442,13 +448,13 @@ foreach router [lrange $argv $i end] { if { "$u_prompt" == "" } { set u_prompt "(Username|login| Login):" } else { - set u_prompt [lindex $u_prompt 0] + set u_prompt [join [lindex $u_prompt 0] ""] } set p_prompt [find passprompt $router] if { "$p_prompt" == "" } { set p_prompt "\[Pp]assword:" } else { - set p_prompt [lindex $p_prompt 0] + set p_prompt [join [lindex $p_prompt 0] ""] } # Figure out cypher type diff --git a/bin/env.in b/bin/env.in deleted file mode 100644 index e3c2ba4..0000000 --- a/bin/env.in +++ /dev/null @@ -1,48 +0,0 @@ -# -# This file setups up the environment used for rancid. see env(5) -# -# This will be site specific -# -TERM=network;export TERM -# -# Under $BASEDIR, there will be a bin directory for the rancid programs, -# a log directory for the logs from rancid and a directory for each group -# of routers (LIST_OF_GROUPS). In addition to these directories, there -# will be the CVS repositories as well. -# use a full path (no sym-links) for BASEDIR. some versions of CVS seemingly -# don't take kindly to sym-links. -# -TMPDIR=/tmp; export TMPDIR -BASEDIR=@prefix@; export BASEDIR -PATH=$BASEDIR/bin:@ENV_PATH@; export PATH -CVSROOT=$BASEDIR/CVS; export CVSROOT -# -# if NOPIPE is set, temp files will be used instead of a cmd pipe during -# collection from the router(s). -#NOPIPE=YES; export NOPIPE -# -# FILTER_PWDS determines which passwords are filtered from configs by the -# value set (NO | YES | ALL). see env(5). -#FILTER_PWDS=YES; export FILTER_PWDS -# -# if NOCOMMSTR is set, snmp community strings will be stripped from the configs -#NOCOMMSTR=YES; export NOCOMMSTR -# -# How many hours to go by before complaining about routers that -# can not be reached. The value should be greater than the number -# of hours between your do-diffs cron job. -OLDTIME=4; export OLDTIME -# -# The number of devices to collect simultaneously. -#PAR_COUNT=5; export PAR_COUNT -# -# list of rancid groups -LIST_OF_GROUPS="sl joebobisp" -# -# For each group, define a list of people to receive the diffs. -# in sendmail's /etc/aliases. -# rancid-group: joe,moe@foo -# rancid-group-admin: hostmaster -# be sure to read ../README regarding aliases. -# -umask 027 diff --git a/bin/erancid.in b/bin/erancid.in old mode 100755 new mode 100644 index 01a6268..20da43d --- a/bin/erancid.in +++ b/bin/erancid.in @@ -1,22 +1,22 @@ -#!@PERLV_PATH@ +#! @PERLV_PATH@ ## -## Hacked version of rancid for ADC EZT3 series muxes. Only tested -## with switch software 1.50 so far - terry@tmk.com +## $Id: erancid.in,v 1.18 2004/01/11 03:49:13 heas Exp $ ## -## -## Copyright (C) 1997-2001 by Henry Kilmer. +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. ## All rights reserved. ## -## This software may be freely copied, modified and redistributed without -## fee for non-commerical purposes provided that this copyright notice is -## preserved intact on all copies and modified copies. +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. ## ## There is no warranty or other guarantee of fitness of this software. -## It is provided solely "as is". The author(s) disclaim(s) all +## It is provided solely "as is". The author(s) disclaim(s) all ## responsibility and liability with respect to this software's usage ## or its effect upon hardware, computer systems, other software, or ## anything else. ## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. ## # # RANCID - Really Awesome New Cisco confIg Differ @@ -24,7 +24,7 @@ # usage: rancid [-d] [-l] [-f filename | $host] # use Getopt::Std; -getopts('dflm'); +getopts('dfl'); $log = $opt_l; $debug = $opt_d; $file = $opt_f; @@ -268,7 +268,8 @@ while() { $cmd = $1; if (!defined($prompt)) { $prompt = ($_ =~ /^([^#]+#)/)[0]; - $prompt =~ s/([}{)(\\])/\\$1/g; + $prompt =~ s/([][}{)(\\])/\\$1/g; + print STDERR ("PROMPT MATCH: $prompt\n") if ($debug); } print STDERR ("HIT COMMAND:$_") if ($debug); if (! defined($commands{$cmd})) { diff --git a/bin/f10rancid.in b/bin/f10rancid.in old mode 100755 new mode 100644 index 06528c5..2c4e485 --- a/bin/f10rancid.in +++ b/bin/f10rancid.in @@ -1,28 +1,32 @@ -#!@PERLV_PATH@ +#! @PERLV_PATH@ ## -## This version of rancid tries to deal with Force10s. +## $Id: f10rancid.in,v 1.11 2004/01/11 03:49:13 heas Exp $ ## -## Copyright (C) 1997-2001 by Henry Kilmer. +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. ## All rights reserved. ## -## This software may be freely copied, modified and redistributed without -## fee for non-commerical purposes provided that this copyright notice is -## preserved intact on all copies and modified copies. +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. ## ## There is no warranty or other guarantee of fitness of this software. -## It is provided solely "as is". The author(s) disclaim(s) all +## It is provided solely "as is". The author(s) disclaim(s) all ## responsibility and liability with respect to this software's usage ## or its effect upon hardware, computer systems, other software, or ## anything else. ## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. ## # +# This version of rancid tries to deal with Force10s. +# # RANCID - Really Awesome New Cisco confIg Differ # # usage: rancid [-d] [-l] [-f filename | $host] # use Getopt::Std; -getopts('dflm'); +getopts('dfl'); $log = $opt_l; $debug = $opt_d; $file = $opt_f; @@ -139,7 +143,6 @@ sub ShowVersion { while () { tr/\015//d; - study; last if(/^$prompt/); next if(/^(\s*|\s*$cmd\s*)$/); return(-1) if (/command authorization failed/i); @@ -479,7 +482,6 @@ sub ShowContAll { while () { tr/\015//d; - study; last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); # return(1) if ($type =~ /^(12[40]|7[05])/); @@ -583,7 +585,6 @@ sub ShowDiagbus { while () { tr/\015//d; - study; last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); #return(1) if ($type !~ /^7[05]/); @@ -670,7 +671,6 @@ sub ShowDiag { while () { tr/\015//d; - study; last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); # return(1) if ($type !~ /^(12[40]|720|36|26)/); @@ -882,7 +882,6 @@ sub WriteTerm { while () { tr/\015//d; - study; last if(/^$prompt/); return(-1) if (/command authorization failed/i); # the pager can not be disabled per-session on the PIX @@ -1216,7 +1215,11 @@ TOP: while() { } while (/#\s*($cmds_regexp)\s*$/) { $cmd = $1; - if (!defined($prompt)) {$prompt = ($_ =~ /^([^#]+#)/)[0]; } + if (!defined($prompt)) { + $prompt = ($_ =~ /^([^#]+#)/)[0]; + $prompt =~ s/([][}{)(\\])/\\$1/g; + print STDERR ("PROMPT MATCH: $prompt\n") if ($debug); + } print STDERR ("HIT COMMAND:$_") if ($debug); if (! defined($commands{$cmd})) { print STDERR "$host: found unexpected command - \"$cmd\"\n"; diff --git a/bin/flogin.in b/bin/flogin.in old mode 100755 new mode 100644 index 1a34068..169e522 --- a/bin/flogin.in +++ b/bin/flogin.in @@ -1,21 +1,26 @@ -#!@EXPECT_PATH@ -- +#! @EXPECT_PATH@ -- ## +## $Id: flogin.in,v 1.32 2004/01/11 05:39:15 heas Exp $ ## -## Copyright (C) 1997-2001 by Henry Kilmer, Erik Sherk and Pete Whiting. +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. ## All rights reserved. ## -## This software may be freely copied, modified and redistributed without -## fee for non-commerical purposes provided that this copyright notice is -## preserved intact on all copies and modified copies. -## +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. +## ## There is no warranty or other guarantee of fitness of this software. -## It is provided solely "as is". The author(s) disclaim(s) all +## It is provided solely "as is". The author(s) disclaim(s) all ## responsibility and liability with respect to this software's usage ## or its effect upon hardware, computer systems, other software, or ## anything else. ## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. ## # +# The login expect scripts were based on Erik Sherk's gwtn, by permission. +# # flogin - foundry login # # Most options are intuitive for logging into a foundry switch. @@ -46,8 +51,9 @@ set do_command 0 set do_script 0 # The default is to automatically enable set enable 1 -# The default is that you login non-enabled (tacacs can have you login already enabled) -set autoenable 0 +# The default is that you login non-enabled (tacacs can have you login already +# enabled) +set avautoenable 0 # The default is to look in the password file to find the passwords. This # tracks if we receive them on the command line. set do_passwd 1 @@ -58,6 +64,8 @@ if {[ info exists env(CISCO_USER) ] } { set default_user $env(CISCO_USER) } elseif {[ info exists env(USER) ]} { set default_user $env(USER) +} elseif {[ info exists env(LOGNAME) ]} { + set default_user $env(LOGNAME) } else { # This uses "id" which I think is portable. At least it has existed # (without options) on all machines/OSes I've been on recently - @@ -113,7 +121,7 @@ for {set i 0} {$i < $argc} {incr i} { if {[ regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} { set E$varname $varvalue } else { - send_user "Error: invalid format for -E in $arg\n" + send_user "\nError: invalid format for -E in $arg\n" exit 1 } # Enable Password @@ -181,7 +189,7 @@ for {set i 0} {$i < $argc} {incr i} { set enable 0 # Does tacacs automatically enable us? } -autoenable { - set autoenable 1 + set avautoenable 1 set enable 0 } -* { send_user "\nError: Unknown argument! $arg\n" @@ -277,7 +285,7 @@ proc source_password_file { password_file } { # Log into the router. proc login { router user userpswd passwd enapasswd cmethod cyphertype } { global spawn_id in_proc do_command do_script platform - global prompt u_prompt p_prompt e_prompt + global prompt u_prompt p_prompt e_prompt sshcmd set in_proc 1 set uprompt_seen 0 @@ -296,8 +304,8 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype } { exit 1 } } elseif ![string compare $prog "ssh"] { - if [ catch {spawn ssh -c $cyphertype -x -l $user $router} reason ] { - send_user "\nError: ssh failed: $reason\n" + if [ catch {spawn $sshcmd -c $cyphertype -x -l $user $router} reason ] { + send_user "\nError: $sshcmd failed: $reason\n" exit 1 } } elseif ![string compare $prog "rsh"] { @@ -341,24 +349,39 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype } { # then it will just send the passwd. # if telnet fails with connection refused, try ssh expect { - -re "(Connection refused|Secure connection \[^\n\r]+ refused|Connection closed by|Telnet server disabled)" { + -re "(Connection refused|Secure connection \[^\n\r]+ refused)" { + catch {close}; wait + if !$progs { + send_user "\nError: Connection Refused ($prog): $router\n" + return 1 + } + } + -re "(Connection closed by|Connection to \[^\n\r]+ closed)" { catch {close}; wait if !$progs { - send_user "\nError: Connection Refused ($prog)\n"; return 1 + send_user "\nError: Connection closed ($prog): $router\n" + return 1 + } + } + -re "Telnet server disabled" { + catch {close}; wait + if !$progs { + send_user "\nError: Connection Refused ($prog): $router\n" + return 1 } } eof { send_user "\nError: Couldn't login\n"; wait; return 1 } -nocase "unknown host\r" { catch {close}; - send_user "\nError: Unknown host\n"; wait; return 1 + send_user "\nError: Unknown host $router\n"; wait; return 1 } "Host is unreachable" { catch {close}; - send_user "\nError: Host Unreachable!\n"; wait; return 1 + send_user "\nError: Host Unreachable: $router\n"; wait; return 1 } "No address associated with name" { catch {close}; - send_user "\nError: Unknown host\n"; wait; return 1 + send_user "\nError: Unknown host $router\n"; wait; return 1 } -re "(Host key not found |The authenticity of host .* be established).*\(yes\/no\)\?" { send "yes\r" @@ -406,7 +429,7 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype } { } "$prompt" { break; } "Login invalid" { - send_user "\nError: Invalid login\n"; + send_user "\nError: Invalid login: $router\n"; catch {close}; wait; return 1 } } @@ -432,6 +455,10 @@ proc do_enable { enauser enapasswd } { denied { send_user "\nError: Check your Enable passwd\n"; return 1 } + "Incorrect username or password" { + send_user "\nError: Check your Enable passwd\n"; + return 1 + } "% Bad passwords" { send_user "\nError: Check your Enable passwd\n"; return 1 } @@ -496,7 +523,9 @@ foreach router [lrange $argv $i end] { # Since autoenable is off by default, if we have it defined, it # was done on the command line. If it is not specifically set on the # command line, check the password file. - if $autoenable { + if $avautoenable { + set autoenable 1 + set enable 0 set prompt "#" } else { set ae [find autoenable $router] @@ -514,15 +543,15 @@ foreach router [lrange $argv $i end] { if { $do_passwd || $do_enapasswd } { set pswd [find password $router] if { [llength $pswd] == 0 } { - send_user "Error: no password for $router in $password_file.\n" + send_user "\nError: no password for $router in $password_file.\n" continue } if { $enable && $do_enapasswd && $autoenable == 0 && [llength $pswd] < 2 } { - send_user "Error: no enable password for $router in $password_file.\n" + send_user "\nError: no enable password for $router in $password_file.\n" continue } - set passwd [lindex $pswd 0] - set enapasswd [lindex $pswd 1] + set passwd [join [lindex $pswd 0] ""] + set enapasswd [join [lindex $pswd 1] ""] } # Figure out username @@ -530,7 +559,7 @@ foreach router [lrange $argv $i end] { # command line username set ruser $username } else { - set ruser [find user $router] + set ruser [join [find user $router] ""] if { "$ruser" == "" } { set ruser $default_user } } @@ -539,7 +568,7 @@ foreach router [lrange $argv $i end] { # command line username set userpswd $userpasswd } else { - set userpswd [find userpassword $router] + set userpswd [join [find userpassword $router] ""] if { "$userpswd" == "" } { set userpswd $passwd } } @@ -548,7 +577,7 @@ foreach router [lrange $argv $i end] { # command line enausername set enauser $enausername } else { - set enauser [find enauser $router] + set enauser [join [find enauser $router] ""] if { "$enauser" == "" } { set enauser $ruser } } @@ -557,19 +586,19 @@ foreach router [lrange $argv $i end] { if { "$u_prompt" == "" } { set u_prompt "(Username|login|Name|User Name):" } else { - set u_prompt [lindex $u_prompt 0] + set u_prompt [join [lindex $u_prompt 0] ""] } set p_prompt [find passprompt $router] if { "$p_prompt" == "" } { set p_prompt "(\[Pp]assword):" } else { - set p_prompt [lindex $p_prompt 0] + set p_prompt [join [lindex $p_prompt 0] ""] } set e_prompt [find enableprompt $router] if { "$e_prompt" == "" } { set e_prompt "\[Pp]assword:" } else { - set e_prompt [lindex $e_prompt 0] + set e_prompt [join [lindex $e_prompt 0] ""] } # Figure out cypher tpye @@ -585,6 +614,10 @@ foreach router [lrange $argv $i end] { set cmethod [find method $router] if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} } + # Figure out the SSH executable name + set sshcmd [find sshcmd $router] + if { "$sshcmd" == "" } { set sshcmd {ssh} } + # Login to the router if {[login $router $ruser $userpswd $passwd $enapasswd $cmethod $cyphertype]} { continue diff --git a/bin/fnrancid.in b/bin/fnrancid.in new file mode 100644 index 0000000..815227b --- /dev/null +++ b/bin/fnrancid.in @@ -0,0 +1,275 @@ +#! @PERLV_PATH@ +## +## $Id: fnrancid.in,v 1.3 2004/01/11 03:49:13 heas Exp $ +## +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## All rights reserved. +## +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. +## +## There is no warranty or other guarantee of fitness of this software. +## It is provided solely "as is". The author(s) disclaim(s) all +## responsibility and liability with respect to this software's usage +## or its effect upon hardware, computer systems, other software, or +## anything else. +## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. +## +# +# A library built on Stephen Gill's Netscreen stuff to accomodate +# the Fortinet product line. [d_pfleger@juniper.net] +# +# RANCID - Really Awesome New Cisco confIg Differ +# +# usage: rancid [-d] [-l] [-f filename | $host] +# +use Getopt::Std; +getopts('dfl'); +$log = $opt_l; +$debug = $opt_d; +#$debug = 1; +$file = $opt_f; +$host = $ARGV[0]; +$found_end = 0; +$timeo = 90; # nlogin timeout in seconds + +my(%filter_pwds); # password filtering mode + +# This routine is used to print out the router configuration +sub ProcessHistory { + my($new_hist_tag,$new_command,$command_string,@string)=(@_); + if((($new_hist_tag ne $hist_tag) || ($new_command ne $command)) + && defined %history) { + print eval "$command \%history"; + undef %history; + } + if (($new_hist_tag) && ($new_command) && ($command_string)) { + if ($history{$command_string}) { + $history{$command_string} = "$history{$command_string}@string"; + } else { + $history{$command_string} = "@string"; + } + } elsif (($new_hist_tag) && ($new_command)) { + $history{++$#history} = "@string"; + } else { + print "@string"; + } + $hist_tag = $new_hist_tag; + $command = $new_command; + 1; +} + +sub numerically { $a <=> $b; } + +# This is a sort routing that will sort numerically on the +# keys of a hash as if it were a normal array. +sub keynsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort numerically keys(%lines)) { + $sorted_lines[$i] = $lines{$key}; + $i++; + } + @sorted_lines; +} + +# This is a sort routing that will sort on the +# keys of a hash as if it were a normal array. +sub keysort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort keys(%lines)) { + $sorted_lines[$i] = $lines{$key}; + $i++; + } + @sorted_lines; +} + +# This is a sort routing that will sort on the +# values of a hash as if it were a normal array. +sub valsort{ + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort values %lines) { + $sorted_lines[$i] = $key; + $i++; + } + @sorted_lines; +} + +# This is a numerical sort routing (ascending). +sub numsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $num (sort {$a <=> $b} keys %lines) { + $sorted_lines[$i] = $lines{$num}; + $i++; + } + @sorted_lines; +} + +# This is a sort routine that will sort on the +# ip address when the ip address is anywhere in +# the strings. +sub ipsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $addr (sort sortbyipaddr keys %lines) { + $sorted_lines[$i] = $lines{$addr}; + $i++; + } + @sorted_lines; +} + +# These two routines will sort based upon IP addresses +sub ipaddrval { + my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#); + $a[3]+256*($a[2]+256*($a[1]+256*$a[0])); +} +sub sortbyipaddr { + &ipaddrval($a) <=> &ipaddrval($b); +} + +# This routine parses "get system" +sub GetSystem { + print STDERR " In GetSystem: $_" if ($debug); + + while () { + tr/\015//d; + next if /^\s*$/; + last if(/$prompt/); + ProcessHistory("","","","$_"); + #print STDOUT "$_"; + } + print STDOUT "Vendor: $vendor"; + ProcessHistory("SYSTEM","","","\n"); + return(0); +} + +sub GetFile { + print STDERR " In GetFile: $_" if ($debug); + while () { + last if(/$prompt/); + } + ProcessHistory("FILE","","","\n"); + return(0); +} + +sub GetConf { + print STDERR " In GetConf: $_" if ($debug); + while () { + tr/\015//d; + next if /^\s*$/; + last if(/$prompt/); + if (/(^set.*)('Enc .*')(.*)/) { + ProcessHistory("ENC","","","!$1 'Enc **encoding removed**' $3\n"); + next; + } + ProcessHistory("","","","$_"); + #print STDOUT "$_"; + } + $found_end=1; + return(1); +} + +# dummy function +sub DoNothing {print STDOUT;} + +# Main +%commands=( + 'get system status' => "GetSystem", + 'get conf' => "GetConf" +); +# keys() doesnt return things in the order entered and the order of the +# cmds is important. pita +@commands=( + "get system status", + "get conf" +); +$cisco_cmds=join(";",@commands); +$cmds_regexp=join("|",@commands); + +open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; +select(OUTPUT); +# make OUTPUT unbuffered if debugging +if ($debug) { $| = 1; } + +if ($file) { + print STDERR "opening file $host\n" if ($debug); + print STDOUT "opening file $host\n" if ($log); + open(INPUT,"<$host") || die "open failed for $host: $!\n"; } else { + print STDERR "executing nlogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($debug); + print STDOUT "executing nlogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($log); + if (defined($ENV{NOPIPE})) { + system "nlogin -t $timeo -c \"$cisco_cmds\" $host $host.raw 2>&1" || die "nlogin failed for $host: $!\n"; + open(INPUT, "< $host.raw") || die "nlogin failed for $host: $!\n"; + } else { + open(INPUT,"nlogin -t $timeo -c \"$cisco_cmds\" $host ) { + tr/\015//d; + if (/^Error:/) { + print STDOUT ("$host nlogin error: $_"); + print STDERR ("$host nlogin error: $_") if ($debug); + last; + } + while (/>\s*($cmds_regexp)\s*$/) { + $cmd = $1; + if (!defined($prompt)) { $prompt = " >\s*"; } + print STDERR ("HIT COMMAND:$_") if ($debug); + if (!defined($commands{$cmd})) { + print STDERR "$host: found unexpected command - \"$cmd\"\n"; + last TOP; + } + $rval = &{$commands{$cmd}}; + delete($commands{$cmd}); + if ($rval == -1) { + last TOP; + } + } +} +print STDOUT "Done $logincmd: $_\n" if ($log); +# Flush History +ProcessHistory("","","",""); +# Cleanup +close(INPUT); +close(OUTPUT); + +if (defined($ENV{NOPIPE})) { + unlink("$host.raw") if (! $debug); +} + +# check for completeness +if (scalar(%commands) || !$found_end) { + if (scalar(%commands)) { + printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands))); + printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug); + } + if (!$found_end) { + print STDOUT "$found_end: found end\n"; + print STDOUT "$host: End of run not found\n"; + print STDERR "$host: End of run not found\n" if ($debug); + system("/usr/bin/tail -1 $host.new"); + } + unlink "$host.new" if (! $debug); +} diff --git a/bin/francid.in b/bin/francid.in old mode 100755 new mode 100644 index b03052e..e1fd284 --- a/bin/francid.in +++ b/bin/francid.in @@ -1,29 +1,33 @@ -#!@PERLV_PATH@ +#! @PERLV_PATH@ ## -## Amazingly hacked version of Hank's rancid - this one tries to -## deal with foundrys and foundrys OEM'd by HP as Procurves. +## $Id: francid.in,v 1.26 2004/01/11 03:49:13 heas Exp $ ## -## Copyright (C) 1997-2001 by Henry Kilmer. +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. ## All rights reserved. ## -## This software may be freely copied, modified and redistributed without -## fee for non-commerical purposes provided that this copyright notice is -## preserved intact on all copies and modified copies. +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. ## ## There is no warranty or other guarantee of fitness of this software. -## It is provided solely "as is". The author(s) disclaim(s) all +## It is provided solely "as is". The author(s) disclaim(s) all ## responsibility and liability with respect to this software's usage ## or its effect upon hardware, computer systems, other software, or ## anything else. ## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. ## # +# Amazingly hacked version of Hank's rancid - this one tries to +# deal with foundrys and foundrys OEM'd by HP as Procurves. +# # RANCID - Really Awesome New Cisco confIg Differ # # usage: rancid [-d] [-l] [-f filename | $host] # use Getopt::Std; -getopts('dflm'); +getopts('dfl'); $log = $opt_l; $debug = $opt_d; $file = $opt_f; @@ -376,7 +380,8 @@ TOP: while() { $cmd = $1; if (!defined($prompt)) { $prompt = ($_ =~ /^([^#]+#)/)[0]; - $prompt =~ s/([}{)(\\])/\\$1/g; + $prompt =~ s/([][}{)(\\])/\\$1/g; + print STDERR ("PROMPT MATCH: $prompt\n") if ($debug); } print STDERR ("HIT COMMAND:$_") if ($debug); if (! defined($commands{$cmd})) { diff --git a/bin/hlogin.in b/bin/hlogin.in old mode 100755 new mode 100644 index 917ea83..6af11b4 --- a/bin/hlogin.in +++ b/bin/hlogin.in @@ -1,21 +1,26 @@ -#!@EXPECT_PATH@ -- +#! @EXPECT_PATH@ -- ## +## $Id: hlogin.in,v 1.21 2004/01/11 05:39:15 heas Exp $ ## -## Copyright (C) 1997-2001 by Henry Kilmer, Erik Sherk and Pete Whiting. +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. ## All rights reserved. ## -## This software may be freely copied, modified and redistributed without -## fee for non-commerical purposes provided that this copyright notice is -## preserved intact on all copies and modified copies. +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. ## ## There is no warranty or other guarantee of fitness of this software. -## It is provided solely "as is". The author(s) disclaim(s) all +## It is provided solely "as is". The author(s) disclaim(s) all ## responsibility and liability with respect to this software's usage ## or its effect upon hardware, computer systems, other software, or ## anything else. ## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. ## # +# The login expect scripts were based on Erik Sherk's gwtn, by permission. +# # hlogin - hp login # # Most options are intuitive for logging into a Cisco router. @@ -43,8 +48,9 @@ set do_command 0 set do_script 0 # The default is to automatically enable set enable 1 -# The default is that you login non-enabled (tacacs can have you login already enabled) -set autoenable 0 +# The default is that you login non-enabled (tacacs can have you login already +# enabled) +set avautoenable 0 # The default is to look in the password file to find the passwords. This # tracks if we receive them on the command line. set do_passwd 1 @@ -57,6 +63,8 @@ if {[ info exists env(CISCO_USER) ] } { set default_user $env(CISCO_USER) } elseif {[ info exists env(USER) ]} { set default_user $env(USER) +} elseif {[ info exists env(LOGNAME) ]} { + set default_user $env(LOGNAME) } else { # This uses "id" which I think is portable. At least it has existed # (without options) on all machines/OSes I've been on recently - @@ -112,7 +120,7 @@ for {set i 0} {$i < $argc} {incr i} { if {[ regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} { set E$varname $varvalue } else { - send_user "Error: invalid format for -E in $arg\n" + send_user "\nError: invalid format for -E in $arg\n" exit 1 } # Enable Password @@ -281,30 +289,35 @@ proc source_password_file { password_file } { # Log into the router. proc login { router user userpswd passwd enapasswd cmethod cyphertype } { global spawn_id in_proc do_command do_script platform - global prompt u_prompt p_prompt e_prompt + global prompt u_prompt p_prompt e_prompt sshcmd set in_proc 1 # try each of the connection methods in $cmethod until one is successful set progs [llength $cmethod] foreach prog [lrange $cmethod 0 end] { + regexp {(telnet|ssh)(:([^[:space:]]+))*} $prog command suffix junk port if [string match "telnet*" $prog] { - regexp {telnet(:([^[:space:]]+))*} $prog command suffix port if {"$port" == ""} { - set retval [ catch {spawn hpfilter telnet $router} reason ] + set retval [ catch {spawn hpuifilter telnet $router} reason ] } else { - set retval [ catch {spawn hpfilter telnet $router $port} reason ] + set retval [ catch {spawn hpuifilter telnet $router $port} reason ] } if { $retval } { send_user "\nError: telnet failed: $reason\n" exit 1 } - } elseif ![string compare $prog "ssh"] { - if [ catch {spawn hpfilter ssh -c $cyphertype -x -l $user $router} reason ] { - send_user "\nError: ssh failed: $reason\n" + } elseif [string match "ssh*" $prog] { + if {"$port" == ""} { + set retval [ catch {spawn hpuifilter $sshcmd -c $cyphertype -x -l $user $router} reason ] + } else { + set retval [ catch {spawn hpuifilter $sshcmd -c $cyphertype -p $port -x -l $user $router} reason ] + } + if { $retval } { + send_user "\nError: $sshcmd failed: $reason\n" exit 1 } } elseif ![string compare $prog "rsh"] { - if [ catch {spawn hpfilter rsh -l $user $router} reason ] { + if [ catch {spawn hpuifilter rsh -l $user $router} reason ] { send_user "\nError: rsh failed: $reason\n" exit 1 } @@ -353,14 +366,17 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype } { if !$progs { send_user "\nError: Connection Refused ($prog)\n"; return 1 } - } eof { send_user "\nError: Couldn't login\n"; wait; return 1 - } -nocase "unknown host\r" { + } + eof { send_user "\nError: Couldn't login\n"; wait; return 1 } + -nocase "unknown host\r" { catch {close}; send_user "\nError: Unknown host\n"; wait; return 1 - } "Host is unreachable" { + } + "Host is unreachable" { catch {close}; send_user "\nError: Host Unreachable!\n"; wait; return 1 - } "No address associated with name" { + } + "No address associated with name" { catch {close}; send_user "\nError: Unknown host\n"; wait; return 1 } @@ -542,7 +558,9 @@ foreach router [lrange $argv $i end] { # Since autoenable is off by default, if we have it defined, it # was done on the command line. If it is not specifically set on the # command line, check the password file. - if $autoenable { + if $avautoenable { + set autoenable 1 + set enable 0 set prompt "#" } else { set ae [find autoenable $router] @@ -565,15 +583,15 @@ foreach router [lrange $argv $i end] { if { $do_passwd || $do_enapasswd } { set pswd [find password $router] if { [llength $pswd] == 0 } { - send_user "Error: no password for $router in $password_file.\n" + send_user "\nError: no password for $router in $password_file.\n" continue } if { $enable && $do_enapasswd && $autoenable == 0 && [llength $pswd] < 2 } { - send_user "Error: no enable password for $router in $password_file.\n" + send_user "\nError: no enable password for $router in $password_file.\n" continue } - set passwd [lindex $pswd 0] - set enapasswd [lindex $pswd 1] + set passwd [join [lindex $pswd 0] ""] + set enapasswd [join [lindex $pswd 1] ""] } # Figure out username @@ -581,7 +599,7 @@ foreach router [lrange $argv $i end] { # command line username set ruser $username } else { - set ruser [find user $router] + set ruser [join [find user $router] ""] if { "$ruser" == "" } { set ruser $default_user } } @@ -590,7 +608,7 @@ foreach router [lrange $argv $i end] { # command line username set userpswd $userpasswd } else { - set userpswd [find userpassword $router] + set userpswd [join [find userpassword $router] ""] if { "$userpswd" == "" } { set userpswd $passwd } } @@ -599,7 +617,7 @@ foreach router [lrange $argv $i end] { # command line enausername set enauser $enausername } else { - set enauser [find enauser $router] + set enauser [join [find enauser $router] ""] if { "$enauser" == "" } { set enauser $ruser } } @@ -608,19 +626,19 @@ foreach router [lrange $argv $i end] { if { "$u_prompt" == "" } { set u_prompt "(Username|login|user name):" } else { - set u_prompt [lindex $u_prompt 0] + set u_prompt [join [lindex $u_prompt 0] ""] } set p_prompt [find passprompt $router] if { "$p_prompt" == "" } { set p_prompt "(\[Pp]assword|passwd):" } else { - set p_prompt [lindex $p_prompt 0] + set p_prompt [join [lindex $p_prompt 0] ""] } set e_prompt [find enableprompt $router] if { "$e_prompt" == "" } { set e_prompt "\[Pp]assword:" } else { - set e_prompt [lindex $e_prompt 0] + set e_prompt [join [lindex $e_prompt 0] ""] } # Figure out cypher type @@ -636,6 +654,16 @@ foreach router [lrange $argv $i end] { set cmethod [find method $router] if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} } + # Figure out the SSH executable name + set sshcmd [find sshcmd $router] + if { "$sshcmd" == "" } { set sshcmd {ssh} } + + # Adjust our path to find hpuifilter + regexp {(.*)/[^/]+} $argv0 junk hpf_path + if { "$hpf_path" != "" && "$hpf_path" != "." } { + append env(PATH) ":$hpf_path" + } + # Login to the router if {[login $router $ruser $userpswd $passwd $enapasswd $cmethod $cyphertype]} { continue diff --git a/bin/hpfilter.c b/bin/hpfilter.c deleted file mode 100644 index 83d799e..0000000 --- a/bin/hpfilter.c +++ /dev/null @@ -1,397 +0,0 @@ -/* - * Copyright (C) 1997-2002 by Henry Kilmer, Erik Sherk and Pete Whiting. - * All rights reserved. - * - * This software may be freely copied, modified and redistributed without - * fee for non-commerical purposes provided that this copyright notice is - * preserved intact on all copies and modified copies. - * - * There is no warranty or other guarantee of fitness of this software. - * It is provided solely "as is". The author(s) disclaim(s) all - * responsibility and liability with respect to this software's usage - * or its effect upon hardware, computer systems, other software, or - * anything else. - * - * - * run telnet or ssh to connect to device specified on the command line. the - * point of hpfilter is to filter all the bloody vt100 (curses) escape codes - * that the HP procurve switches belch and make hlogin a real bitch. - */ - -#define DFLT_TO 60 /* default timeout */ - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -char *progname; -int debug = 0; - -int filter __P((char *, int)); -void usage __P((void)); -void vers __P((void)); -RETSIGTYPE reapchild __P((void)); - -int -main(int argc, char **argv) -{ - extern char *optarg; - extern int optind; - char ch, - hbuf[LINE_MAX * 2], /* hlogin buffer */ - *hbufp, - tbuf[LINE_MAX * 2], /* telnet buffer */ - *tbufp; - int bytes, /* bytes read/written */ - child, - r[2], /* recv pipe */ - s[2]; /* send pipe */ - ssize_t hlen = 0, /* len of hbuf */ - tlen = 0; /* len of tbuf */ - struct timeval to = { DFLT_TO, 0 }; - fd_set rfds, /* select() */ - wfds; - struct termios tios; - - /* get just the basename() of our exec() name and strip a .* off the end */ - if ((progname = strrchr(argv[0], '/')) != NULL) - progname += 1; - else - progname = argv[0]; - if (strrchr(progname, '.') != NULL) - *(strrchr(progname, '.')) = '\0'; - - while ((ch = getopt(argc, argv, "dhv")) != -1 ) - switch (ch) { - case 'd': - debug++; - break; - case 'v': - vers(); - return(EX_OK); - case 'h': - default: - usage(); - return(EX_USAGE); - } - - if (argc - optind != 2) { - usage(); - return(EX_USAGE); - } - - /* reap our children */ - signal(SIGCHLD, (void *) reapchild); - signal(SIGHUP, (void *) reapchild); - signal(SIGINT, (void *) reapchild); - signal(SIGTERM, (void *) reapchild); - - /* create 2 pipes for send/recv and then fork and exec telnet */ - for (child = 3; child < 10; child++) - close(child); - if (pipe(s) || pipe(r)) { - fprintf(stderr, "%s: pipe() failed: %s\n", progname, - strerror(errno)); - return(EX_TEMPFAIL); - } - - /* if a tty, make it raw as the hp echos _everything_, including - * passwords. - */ - if (isatty(0)) { - if (tcgetattr(0, &tios)) { - fprintf(stderr, "%s: tcgetattr() failed: %s\n", progname, - strerror(errno)); - return(EX_OSERR); - } - tios.c_lflag &= ~ECHO; - tios.c_lflag &= ~ICANON; -#ifdef VMIN - tios.c_cc[VMIN] = 1; - tios.c_cc[VTIME] = 0; -#endif - if (tcsetattr(0, TCSANOW, &tios)) { - fprintf(stderr, "%s: tcsetattr() failed: %s\n", progname, - strerror(errno)); - return(EX_OSERR); - } - } - - if ((child = fork()) == -1) { - fprintf(stderr, "%s: fork() failed: %s\n", progname, - strerror(errno)); - return(EX_TEMPFAIL); - } - - /* zero the buffers */ - bzero(hbuf, LINE_MAX * 2); - bzero(tbuf, LINE_MAX * 2); - - if (child == 0) { - /* close the parent's side of the pipes; we write r[1], read s[0] */ - close(s[1]); - close(r[0]); - /* close stdin/out/err and attach them to the pipes */ - if (dup2(s[0], 0) == -1 || dup2(r[1], 1) == -1 || dup2(r[1], 2) == -1) { - fprintf(stderr, "%s: dup2() failed: %s\n", progname, - strerror(errno)); - return(EX_OSERR); - } - close(s[0]); - close(r[1]); - /* exec telnet */ - if (execvp(argv[optind], argv + optind)) { - fprintf(stderr, "%s: execlp() failed: %s\n", progname, - strerror(errno)); - return(EX_TEMPFAIL); - } - /* not reached */ - } else { - /* parent */ - if (debug) - fprintf(stderr, "child %d\n", child); - - /* close the child's side of the pipes; we write s[1], read r[0] */ - close(s[0]); - close(r[1]); - - /* make FDs non-blocking */ - if (fcntl(s[1], F_SETFL, O_NONBLOCK) || - fcntl(r[0], F_SETFL, O_NONBLOCK) || - fcntl(0, F_SETFL, O_NONBLOCK) || - fcntl(1, F_SETFL, O_NONBLOCK)) { - fprintf(stderr, "%s: fcntl(NONBLOCK) failed: %s\n", progname, - strerror(errno)); - exit(EX_OSERR); - } - - /* loop to read on stdin and r[0] */ - FD_ZERO(&rfds); FD_ZERO(&wfds); - hbufp = hbuf; tbufp = tbuf; - - while (1) { - FD_SET(0, &rfds); FD_SET(r[0], &rfds); - /* if we have stuff in our buffer(s), we select on writes too */ - FD_ZERO(&wfds); - if (hlen) { - FD_SET(s[1], &wfds); - } - if (tlen) { - FD_SET(1, &wfds); - } - - switch (select(r[1], &rfds, &wfds, NULL, &to)) { - case 0: - /* timeout */ - /* HEAS: what do i do here? */ - break; - case -1: - switch (errno) { - case EINTR: /* interrupted syscall */ - break; - default: - exit(EX_IOERR); - } - break; - default: - /* check exceptions first */ - - /* which FD is ready? write our buffers asap. */ - /* write hbuf (stdin) -> s[1] */ - if (FD_ISSET(s[1], &wfds) && hlen) { - if ((hlen = write(s[1], hbuf, hlen)) < 0) { - fprintf(stderr, "%s: write() failed: %s\n", progname, - strerror(errno)); - close(s[1]); - } else - strcpy(hbuf, hbuf + hlen); - - hlen = strlen(hbuf); - } - /* write tbuf -> stdout */ - if (FD_ISSET(1, &wfds) && tlen) { - /* if there is an escape char that didnt get filter()'d, - * we need to only write up to that point and wait for - * the bits that complete the escape sequence - */ - if ((tbufp = index(tbuf, 0x1b)) != NULL) - tlen = tbufp - tbuf; - - if ((tlen = write(1, tbuf, tlen)) < 0) { - fprintf(stderr, "%s: write() failed: %s\n", progname, - strerror(errno)); - close(1); - } else - strcpy(tbuf, tbuf + tlen); - - tlen = strlen(tbuf); - } - if (FD_ISSET(0, &rfds)) { - /* read stdin into hbuf */ - if (LINE_MAX * 2 - hlen > 1) { - hlen += read(0, hbuf + hlen, - (LINE_MAX * 2 - 1) - hlen); - if (hlen > 0) { - hbuf[hlen] = '\0'; - } else if (hlen == 0 || errno != EAGAIN) - /* EOF or read error */ - close(0); - - hlen = strlen(hbuf); - } - } else if (FD_ISSET(r[0], &rfds)) { - /* read telnet into tbuf, then filter */ - if (LINE_MAX * 2 - tlen > 1) { - tlen += read(r[0], tbuf + tlen, - (LINE_MAX * 2 - 1) - tlen); - if (tlen > 0) { - tbuf[tlen] = '\0'; - tlen = filter(tbuf, tlen); - } else if (tlen == 0 || errno != EAGAIN) - /* EOF or read error */ - close(r[0]); - - tlen = strlen(tbuf); - } - } - - break; - } - } - /* close */ - close(0); - close(1); - close(s[1]); - close(r[0]); - - } - - if (! kill(child, SIGQUIT)) - reapchild(); - - return(EX_OK); -} - -int -filter(buf, len) - char *buf; - int len; -{ - static regmatch_t pmatch[1]; -#define N_REG 11 /* number of regexes in reg[][] */ - static regex_t preg[N_REG]; - static char reg[N_REG][50] = { /* vt100/220 escape codes */ - "\e7\e\\[1;24r\e8", /* ds */ - "\e8", /* fs */ - - "\e\\[2J", - "\e\\[2K", /* kE */ - - "\e\\[[0-9]+;[0-9]+r", /* cs */ - "\e\\[[0-9]+;[0-9]+H", /* cm */ - - "\e\\[\\?6l", - "\e\\[\\?7l", /* RA */ - "\e\\[\\?25h", /* ve */ - "\e\\[\\?25l", /* vi */ - - "\eE", /* replace w/ CR */ - }; - char ebuf[256]; - size_t nmatch = 1; - int err, - x; - static int init = 0; - - if (index(buf, 0x1b) == 0 || len == 0) - return(len); - - for (x = 0; x < N_REG - 1; x++) { - if (! init) { - if ((err = regcomp(&preg[x], reg[x], REG_EXTENDED))) { - regerror(err, &preg[x], ebuf, 256); - fprintf(stderr, "%s: regex compile failed: %s\n", progname, - ebuf); - abort(); - } - } - if ((err = regexec(&preg[x], buf, nmatch, pmatch, 0))) { - if (err != REG_NOMATCH) { - regerror(err, &preg[x], ebuf, 256); - fprintf(stderr, "%s: regexec failed: %s\n", progname, ebuf); - abort(); - } - } else { - strcpy(buf + pmatch[0].rm_so, buf + pmatch[0].rm_eo); - x = 0; - } - } - - /* replace \eE w/ CR NL */ - if (! init++) { - if ((err = regcomp(&preg[N_REG - 1], reg[N_REG - 1], REG_EXTENDED))) { - regerror(err, &preg[N_REG - 1], ebuf, 256); - fprintf(stderr, "%s: regex compile failed: %s\n", progname, - ebuf); - abort(); - } - } - while (1) - if ((err = regexec(&preg[N_REG - 1], buf, nmatch, pmatch, 0))) { - if (err != REG_NOMATCH) { - regerror(err, &preg[N_REG - 1], ebuf, 256); - fprintf(stderr, "%s: regexec failed: %s\n", progname, ebuf); - abort(); - } else - break; - } else { - *(buf + pmatch[0].rm_so) = '\n'; - strcpy(buf + pmatch[0].rm_so + 1, buf + pmatch[0].rm_eo); - x = 0; - } - - return(strlen(buf)); -} - -RETSIGTYPE -reapchild(void) -{ - int status; - pid_t pid; - - /* HEAS: this needs to deal with/without wait3 via HAVE_WAIT3 */ - while ((pid = wait3(&status, WNOHANG, 0)) > 0) - if (debug) - fprintf(stderr, "reap child %d\n", pid); - - /*exit(1);*/ -return; - - /* not reached */ -} - -void -usage(void) -{ - fprintf(stderr, -"usage: %s [-hv] -", progname); - return; -} - -void -vers(void) -{ - fprintf(stderr, -"%s: %s version %s -", progname, package, version); - return; -} diff --git a/bin/hpuifilter.c b/bin/hpuifilter.c new file mode 100644 index 0000000..8f7005a --- /dev/null +++ b/bin/hpuifilter.c @@ -0,0 +1,400 @@ +/* + * $Id: hpuifilter.c,v 1.17 2004/01/11 03:49:13 heas Exp $ + * + * Copyright (C) 1997-2004 by Terrapin Communications, Inc. + * All rights reserved. + * + * This software may be freely copied, modified and redistributed + * without fee for non-commerical purposes provided that this license + * remains intact and unmodified with any RANCID distribution. + * + * There is no warranty or other guarantee of fitness of this software. + * It is provided solely "as is". The author(s) disclaim(s) all + * responsibility and liability with respect to this software's usage + * or its effect upon hardware, computer systems, other software, or + * anything else. + * + * Except where noted otherwise, rancid was written by and is maintained by + * Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. + * + * Run telnet or ssh to connect to device specified on the command line. The + * point of hpfilter is to filter all the bloody vt100 (curses) escape codes + * that the HP procurve switches belch out, which are a real bitch to handle + * in hlogin. + */ + +#define DFLT_TO 60 /* default timeout */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +char *progname; +int debug = 0; + +int filter __P((char *, int)); +void usage __P((void)); +void vers __P((void)); +RETSIGTYPE reapchild __P((void)); + +int +main(int argc, char **argv) +{ + extern char *optarg; + extern int optind; + char ch, + hbuf[LINE_MAX * 2], /* hlogin buffer */ + *hbufp, + tbuf[LINE_MAX * 2], /* telnet buffer */ + *tbufp; + int bytes, /* bytes read/written */ + child, + r[2], /* recv pipe */ + s[2]; /* send pipe */ + ssize_t hlen = 0, /* len of hbuf */ + tlen = 0; /* len of tbuf */ + struct timeval to = { DFLT_TO, 0 }; + fd_set rfds, /* select() */ + wfds; + struct termios tios; + + /* get just the basename() of our exec() name and strip a .* off the end */ + if ((progname = strrchr(argv[0], '/')) != NULL) + progname += 1; + else + progname = argv[0]; + if (strrchr(progname, '.') != NULL) + *(strrchr(progname, '.')) = '\0'; + + while ((ch = getopt(argc, argv, "dhv")) != -1 ) + switch (ch) { + case 'd': + debug++; + break; + case 'v': + vers(); + return(EX_OK); + case 'h': + default: + usage(); + return(EX_USAGE); + } + + if (argc - optind < 2) { + usage(); + return(EX_USAGE); + } + + /* reap our children */ + signal(SIGCHLD, (void *) reapchild); + signal(SIGHUP, (void *) reapchild); + signal(SIGINT, (void *) reapchild); + signal(SIGTERM, (void *) reapchild); + + /* create 2 pipes for send/recv and then fork and exec telnet */ + for (child = 3; child < 10; child++) + close(child); + if (pipe(s) || pipe(r)) { + fprintf(stderr, "%s: pipe() failed: %s\n", progname, + strerror(errno)); + return(EX_TEMPFAIL); + } + + /* if a tty, make it raw as the hp echos _everything_, including + * passwords. + */ + if (isatty(0)) { + if (tcgetattr(0, &tios)) { + fprintf(stderr, "%s: tcgetattr() failed: %s\n", progname, + strerror(errno)); + return(EX_OSERR); + } + tios.c_lflag &= ~ECHO; + tios.c_lflag &= ~ICANON; +#ifdef VMIN + tios.c_cc[VMIN] = 1; + tios.c_cc[VTIME] = 0; +#endif + if (tcsetattr(0, TCSANOW, &tios)) { + fprintf(stderr, "%s: tcsetattr() failed: %s\n", progname, + strerror(errno)); + return(EX_OSERR); + } + } + + if ((child = fork()) == -1) { + fprintf(stderr, "%s: fork() failed: %s\n", progname, + strerror(errno)); + return(EX_TEMPFAIL); + } + + /* zero the buffers */ + bzero(hbuf, LINE_MAX * 2); + bzero(tbuf, LINE_MAX * 2); + + if (child == 0) { + /* close the parent's side of the pipes; we write r[1], read s[0] */ + close(s[1]); + close(r[0]); + /* close stdin/out/err and attach them to the pipes */ + if (dup2(s[0], 0) == -1 || dup2(r[1], 1) == -1 || dup2(r[1], 2) == -1) { + fprintf(stderr, "%s: dup2() failed: %s\n", progname, + strerror(errno)); + return(EX_OSERR); + } + close(s[0]); + close(r[1]); + /* exec telnet */ + if (execvp(argv[optind], argv + optind)) { + fprintf(stderr, "%s: execlp() failed: %s\n", progname, + strerror(errno)); + return(EX_TEMPFAIL); + } + /* not reached */ + } else { + /* parent */ + if (debug) + fprintf(stderr, "child %d\n", child); + + /* close the child's side of the pipes; we write s[1], read r[0] */ + close(s[0]); + close(r[1]); + + /* make FDs non-blocking */ + if (fcntl(s[1], F_SETFL, O_NONBLOCK) || + fcntl(r[0], F_SETFL, O_NONBLOCK) || + fcntl(0, F_SETFL, O_NONBLOCK) || + fcntl(1, F_SETFL, O_NONBLOCK)) { + fprintf(stderr, "%s: fcntl(NONBLOCK) failed: %s\n", progname, + strerror(errno)); + exit(EX_OSERR); + } + + /* loop to read on stdin and r[0] */ + FD_ZERO(&rfds); FD_ZERO(&wfds); + hbufp = hbuf; tbufp = tbuf; + + while (1) { + FD_SET(0, &rfds); FD_SET(r[0], &rfds); + /* if we have stuff in our buffer(s), we select on writes too */ + FD_ZERO(&wfds); + if (hlen) { + FD_SET(s[1], &wfds); + } + if (tlen) { + FD_SET(1, &wfds); + } + + switch (select(r[1], &rfds, &wfds, NULL, &to)) { + case 0: + /* timeout */ + /* HEAS: what do i do here? */ + break; + case -1: + switch (errno) { + case EINTR: /* interrupted syscall */ + break; + default: + exit(EX_IOERR); + } + break; + default: + /* check exceptions first */ + + /* which FD is ready? write our buffers asap. */ + /* write hbuf (stdin) -> s[1] */ + if (FD_ISSET(s[1], &wfds) && hlen) { + if ((hlen = write(s[1], hbuf, hlen)) < 0) { + fprintf(stderr, "%s: write() failed: %s\n", progname, + strerror(errno)); + close(s[1]); + } else + strcpy(hbuf, hbuf + hlen); + + hlen = strlen(hbuf); + } + /* write tbuf -> stdout */ + if (FD_ISSET(1, &wfds) && tlen) { + /* if there is an escape char that didnt get filter()'d, + * we need to only write up to that point and wait for + * the bits that complete the escape sequence + */ + if ((tbufp = index(tbuf, 0x1b)) != NULL) + tlen = tbufp - tbuf; + + if ((tlen = write(1, tbuf, tlen)) < 0) { + fprintf(stderr, "%s: write() failed: %s\n", progname, + strerror(errno)); + close(1); + } else + strcpy(tbuf, tbuf + tlen); + + tlen = strlen(tbuf); + } + if (FD_ISSET(0, &rfds)) { + /* read stdin into hbuf */ + if (LINE_MAX * 2 - hlen > 1) { + hlen += read(0, hbuf + hlen, + (LINE_MAX * 2 - 1) - hlen); + if (hlen > 0) { + hbuf[hlen] = '\0'; + } else if (hlen == 0 || errno != EAGAIN) + /* EOF or read error */ + close(0); + + hlen = strlen(hbuf); + } + } else if (FD_ISSET(r[0], &rfds)) { + /* read telnet into tbuf, then filter */ + if (LINE_MAX * 2 - tlen > 1) { + tlen += read(r[0], tbuf + tlen, + (LINE_MAX * 2 - 1) - tlen); + if (tlen > 0) { + tbuf[tlen] = '\0'; + tlen = filter(tbuf, tlen); + } else if (tlen == 0 || errno != EAGAIN) + /* EOF or read error */ + close(r[0]); + + tlen = strlen(tbuf); + } + } + + break; + } + } + /* close */ + close(0); + close(1); + close(s[1]); + close(r[0]); + + } + + if (! kill(child, SIGQUIT)) + reapchild(); + + return(EX_OK); +} + +int +filter(buf, len) + char *buf; + int len; +{ + static regmatch_t pmatch[1]; +#define N_REG 11 /* number of regexes in reg[][] */ + static regex_t preg[N_REG]; + static char reg[N_REG][50] = { /* vt100/220 escape codes */ + "\e7\e\\[1;24r\e8", /* ds */ + "\e8", /* fs */ + + "\e\\[2J", + "\e\\[2K", /* kE */ + + "\e\\[[0-9]+;[0-9]+r", /* cs */ + "\e\\[[0-9]+;[0-9]+H", /* cm */ + + "\e\\[\\?6l", + "\e\\[\\?7l", /* RA */ + "\e\\[\\?25h", /* ve */ + "\e\\[\\?25l", /* vi */ + + "\eE", /* replace w/ CR */ + }; + char ebuf[256]; + size_t nmatch = 1; + int err, + x; + static int init = 0; + + if (index(buf, 0x1b) == 0 || len == 0) + return(len); + + for (x = 0; x < N_REG - 1; x++) { + if (! init) { + if ((err = regcomp(&preg[x], reg[x], REG_EXTENDED))) { + regerror(err, &preg[x], ebuf, 256); + fprintf(stderr, "%s: regex compile failed: %s\n", progname, + ebuf); + abort(); + } + } + if ((err = regexec(&preg[x], buf, nmatch, pmatch, 0))) { + if (err != REG_NOMATCH) { + regerror(err, &preg[x], ebuf, 256); + fprintf(stderr, "%s: regexec failed: %s\n", progname, ebuf); + abort(); + } + } else { + strcpy(buf + pmatch[0].rm_so, buf + pmatch[0].rm_eo); + x = 0; + } + } + + /* replace \eE w/ CR NL */ + if (! init++) { + if ((err = regcomp(&preg[N_REG - 1], reg[N_REG - 1], REG_EXTENDED))) { + regerror(err, &preg[N_REG - 1], ebuf, 256); + fprintf(stderr, "%s: regex compile failed: %s\n", progname, + ebuf); + abort(); + } + } + while (1) + if ((err = regexec(&preg[N_REG - 1], buf, nmatch, pmatch, 0))) { + if (err != REG_NOMATCH) { + regerror(err, &preg[N_REG - 1], ebuf, 256); + fprintf(stderr, "%s: regexec failed: %s\n", progname, ebuf); + abort(); + } else + break; + } else { + *(buf + pmatch[0].rm_so) = '\n'; + strcpy(buf + pmatch[0].rm_so + 1, buf + pmatch[0].rm_eo); + x = 0; + } + + return(strlen(buf)); +} + +RETSIGTYPE +reapchild(void) +{ + int status; + pid_t pid; + + /* HEAS: this needs to deal with/without wait3 via HAVE_WAIT3 */ + while ((pid = wait3(&status, WNOHANG, 0)) > 0) + if (debug) + fprintf(stderr, "reap child %d\n", pid); + + /*exit(1);*/ +return; + + /* not reached */ +} + +void +usage(void) +{ + fprintf(stderr, +"usage: %s [-hv] [] []\n", + progname); + return; +} + +void +vers(void) +{ + fprintf(stderr, "%s: %s version %s\n", progname, package, version); + return; +} diff --git a/bin/hrancid.in b/bin/hrancid.in old mode 100755 new mode 100644 index d0bcc55..fa048ce --- a/bin/hrancid.in +++ b/bin/hrancid.in @@ -1,29 +1,33 @@ -#!@PERLV_PATH@ +#! @PERLV_PATH@ ## -## Amazingly hacked version of Hank's rancid - this one tries to -## deal with HP procurves. +## $Id: hrancid.in,v 1.17 2004/01/11 03:49:13 heas Exp $ ## -## Copyright (C) 1997-2001 by Henry Kilmer. +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. ## All rights reserved. ## -## This software may be freely copied, modified and redistributed without -## fee for non-commerical purposes provided that this copyright notice is -## preserved intact on all copies and modified copies. +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. ## ## There is no warranty or other guarantee of fitness of this software. -## It is provided solely "as is". The author(s) disclaim(s) all +## It is provided solely "as is". The author(s) disclaim(s) all ## responsibility and liability with respect to this software's usage ## or its effect upon hardware, computer systems, other software, or ## anything else. ## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. ## # +# Amazingly hacked version of Hank's rancid - this one tries to +# deal with HP procurves. +# # RANCID - Really Awesome New Cisco confIg Differ # # usage: rancid [-d] [-l] [-f filename | $host] # use Getopt::Std; -getopts('dflm'); +getopts('dfl'); $log = $opt_l; $debug = $opt_d; $file = $opt_f; @@ -334,7 +338,7 @@ sub WriteTerm { ProcessHistory("","","",";$_") && next; - # the rest are from rancid (ie: cisco), but suspect they will someday + # the rest are from rancid (i.e.: cisco), but suspect they will someday # be applicable or close to it. /^tftp-server flash / && next; # kill any tftp remains @@ -493,8 +497,12 @@ TOP: while() { } while (/#\s*($cmds_regexp)\s*$/) { $cmd = $1; - if (!defined($prompt)) {$prompt = ($_ =~ /^([^#]+)/)[0]; - $prompt .= "[#>]"; } + if (!defined($prompt)) { + $prompt = ($_ =~ /^([^#]+)/)[0]; + $prompt =~ s/([][}{)(\\])/\\$1/g; + $prompt .= "[#>]"; + print STDERR ("PROMPT MATCH: $prompt\n") if ($debug); + } print STDERR ("HIT COMMAND:$_") if ($debug); if (! defined($commands{$cmd})) { print STDERR "$host: found unexpected command - \"$cmd\"\n"; diff --git a/bin/htlogin.in b/bin/htlogin.in new file mode 100644 index 0000000..8e9c5f5 --- /dev/null +++ b/bin/htlogin.in @@ -0,0 +1,492 @@ +#! @EXPECT_PATH@ -- +## +## $Id: htlogin.in,v 1.7 2004/01/11 05:39:15 heas Exp $ +## +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## All rights reserved. +## +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. +## +## There is no warranty or other guarantee of fitness of this software. +## It is provided solely "as is". The author(s) disclaim(s) all +## responsibility and liability with respect to this software's usage +## or its effect upon hardware, computer systems, other software, or +## anything else. +## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. +## +# +# The login expect scripts were based on Erik Sherk's gwtn, by permission. +# +# htlogin - Hitachi router login +# +# Most options are intuitive for logging into an Hitachi router login. +# + +# Usage line +set usage "Usage: $argv0 \[-noenable\] \[-c command\] \ +\[-Evar=x\] \[-f cloginrc-file\] \[-p user-password\] \ +\[-s script-file\] \[-t timeout\] \[-u username\] \ +\[-v vty-password\] \[-w enable-username\] \[-x command-file\] \ +\[-y ssh_cypher_type\] router \[router...\]\n" + +# env(CLOGIN) may contain: +# x == do not set xterm banner or name + +# Password file +set password_file $env(HOME)/.cloginrc +# Default is to login to the router +set do_command 0 +set do_script 0 +# The default is to automatically enable +set enable 1 +# The default is that you login non-enabled (tacacs can have you login already +# enabled) +set avautoenable 0 +# The default is to look in the password file to find the passwords. This +# tracks if we receive them on the command line. +set do_passwd 1 + +# Find the user in the ENV, or use the unix userid. +if {[ info exists env(CISCO_USER) ] } { + set default_user $env(CISCO_USER) +} elseif {[ info exists env(USER) ]} { + set default_user $env(USER) +} elseif {[ info exists env(LOGNAME) ]} { + set default_user $env(LOGNAME) +} else { + # This uses "id" which I think is portable. At least it has existed + # (without options) on all machines/OSes I've been on recently - + # unlike whoami or id -nu. + if [ catch {exec id} reason ] { + send_error "\nError: could not exec id: $reason\n" + exit 1 + } + regexp {\(([^)]*)} "$reason" junk default_user +} + +# Sometimes routers take awhile to answer (the default is 10 sec) +set timeout 45 + +# Process the command line +for {set i 0} {$i < $argc} {incr i} { + set arg [lindex $argv $i] + + switch -glob -- $arg { + # Username + -u* - + -U* { + if {! [ regexp .\[uU\](.+) $arg ignore user]} { + incr i + set username [ lindex $argv $i ] + } + # VTY Password + } -p* - + -P* { + if {! [ regexp .\[pP\](.+) $arg ignore userpasswd]} { + incr i + set userpasswd [ lindex $argv $i ] + } + set do_passwd 0 + # VTY Password + } -v* - + -v* { + if {! [ regexp .\[vV\](.+) $arg ignore passwd]} { + incr i + set passwd [ lindex $argv $i ] + } + set do_passwd 0 + # Enable Username + } -w* - + -W* { + # ignore -w + # Environment variable to pass to -s scripts + } -E* + { + if {[ regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} { + set E$varname $varvalue + } else { + send_user "Error: invalid format for -E in $arg\n" + exit 1 + } + # Enable Password + } -e* + { + # ignore -e + # Command to run. + } -c* - + -C* { + if {! [ regexp .\[cC\](.+) $arg ignore command]} { + incr i + set command [ lindex $argv $i ] + } + set do_command 1 + # Expect script to run. + } -s* - + -S* { + if {! [ regexp .\[sS\](.+) $arg ignore sfile]} { + incr i + set sfile [ lindex $argv $i ] + } + if { ! [ file readable $sfile ] } { + send_user "\nError: Can't read $sfile\n" + exit 1 + } + set do_script 1 + # 'ssh -c' cypher type + } -y* - + -Y* { + if {! [ regexp .\[eE\](.+) $arg ignore cypher]} { + incr i + set cypher [ lindex $argv $i ] + } + # alternate cloginrc file + } -f* - + -F* { + if {! [ regexp .\[fF\](.+) $arg ignore password_file]} { + incr i + set password_file [ lindex $argv $i ] + } + # Timeout + } -t* - + -T* { + if {! [ regexp .\[tT\](.+) $arg ignore timeout]} { + incr i + set timeout [ lindex $argv $i ] + } + # Command file + } -x* - + -X { + if {! [ regexp .\[xX\](.+) $arg ignore cmd_file]} { + incr i + set cmd_file [ lindex $argv $i ] + } + if [ catch {set cmd_fd [open $cmd_file r]} reason ] { + send_user "\nError: $reason\n" + exit 1 + } + set cmd_text [read $cmd_fd] + close $cmd_fd + set command [join [split $cmd_text \n] \;] + set do_command 1 + # Do we enable? + } -noenable { + # ignore -noenable + # Does tacacs automatically enable us? + } -autoenable { + # ignore -autoenable + } -* { + send_user "\nError: Unknown argument! $arg\n" + send_user $usage + exit 1 + } default { + break + } + } +} +# Process routers...no routers listed is an error. +if { $i == $argc } { + send_user "\nError: $usage" +} + +# Only be quiet if we are running a script (it can log its output +# on its own) +if { $do_script } { + log_user 0 +} else { + log_user 1 +} + +# +# Done configuration/variable setting. Now run with it... +# + +# Sets Xterm title if interactive...if its an xterm and the user cares +proc label { host } { + global env + # if CLOGIN has an 'x' in it, don't set the xterm name/banner + if [info exists env(CLOGIN)] { + if {[string first "x" $env(CLOGIN)] != -1} { return } + } + # take host from ENV(TERM) + if [info exists env(TERM)] { + if [regexp \^(xterm|vs) $env(TERM) ignore ] { + send_user "\033]1;[lindex [split $host "."] 0]\a" + send_user "\033]2;$host\a" + } + } +} + +# This is a helper function to make the password file easier to +# maintain. Using this the password file has the form: +# add password sl* pete cow +# add password at* steve +# add password * hanky-pie +proc add {var args} { global int_$var ; lappend int_$var $args} +proc include {args} { + global env + regsub -all "(^{|}$)" $args {} args + if { [ regexp "^/" $args ignore ] == 0 } { + set args $env(HOME)/$args + } + source_password_file $args +} + +proc find {var router} { + upvar int_$var list + if { [info exists list] } { + foreach line $list { + if { [string match [lindex $line 0] $router ] } { + return [lrange $line 1 end] + } + } + } + return {} +} + +# Loads the password file. Note that as this file is tcl, and that +# it is sourced, the user better know what to put in there, as it +# could install more than just password info... I will assume however, +# that a "bad guy" could just as easy put such code in the clogin +# script, so I will leave .cloginrc as just an extention of that script +proc source_password_file { password_file } { + global env + if { ! [file exists $password_file] } { + send_user "\nError: password file ($password_file) does not exist\n" + exit 1 + } + file stat $password_file fileinfo + if { [expr ($fileinfo(mode) & 007)] != 0000 } { + send_user "\nError: $password_file must not be world readable/writable\n" + exit 1 + } + if [ catch {source $password_file} reason ] { + send_user "\nError: $reason\n" + exit 1 + } +} + +# Log into the router. +proc login { router user userpswd passwd prompt cmethod cyphertype } { + global spawn_id in_proc do_command do_script + global u_prompt p_prompt + set in_proc 1 + set uprompt_seen 0 + + # try each of the connection methods in $cmethod until one is successful + set progs [llength $cmethod] + foreach prog [lrange $cmethod 0 end] { + if [string match "telnet*" $prog] { + regexp {telnet(:([^[:space:]]+))*} $prog command suffix port + if {"$port" == ""} { + set retval [ catch {spawn telnet $router} reason ] + } else { + set retval [ catch {spawn telnet $router $port} reason ] + } + if { $retval } { + send_user "\nError: telnet failed: $reason\n" + exit 1 + } + } else { + puts "\nError: unknown connection method: $prog" + return 1 + } + incr progs -1 + sleep 0.3 + + # This helps cleanup each expect clause. + expect_after { + timeout { + send_user "\nError: TIMEOUT reached\n" + catch {close}; wait + if { $in_proc} { + return 1 + } else { + continue + } + } eof { + send_user "\nError: EOF received\n" + catch {close}; wait + if { $in_proc} { + return 1 + } else { + continue + } + } + } + + expect { + "Connection refused" { + close; wait + sleep 0.3 + expect eof + send_user "\nError: Connection Refused\n"; wait; return 1 + } eof { send_user "\nError: Couldn't login\n"; wait; return 1 + } "Unknown host\r\n" { + expect eof + send_user "\nError: Unknown host\n"; wait; return 1 + } "Host is unreachable" { + expect eof + send_user "\nError: Host Unreachable!\n"; wait; return 1 + } "No address associated with name" { + expect eof + send_user "\nError: Unknown host\n"; wait; return 1 + } + -re "$u_prompt" { + send "$user\r" + set uprompt_seen 1 + exp_continue + } + -re "$p_prompt" { + sleep 1 + if {$uprompt_seen == 1} { + send "$userpswd\r" + } else { + send "$passwd\r" + } + exp_continue + } + "Password incorrect" { send_user "\nError: Check your password for $router\n"; + catch {close}; wait; return 1 + } + "$prompt" { break; } + denied { send_user "\nError: Check your passwd for $router\n" + catch {close}; wait; return 1 + } + "\r\n" { exp_continue; } + } + } + set in_proc 0 + return 0 +} + +# Run commands given on the command line. +proc run_commands { prompt command } { + global in_proc + set in_proc 1 + + # Is this a multi-command? + if [ string match "*\;*" "$command" ] { + set commands [split $command \;] + set num_commands [llength $commands] + + for {set i 0} {$i < $num_commands} { incr i} { + send "[lindex $commands $i]\r" + expect { + -re "^\[^\n\r]*$prompt" {} + -re "^\[^\n\r *]*$prompt" {} + -re "\[\n\r]" { exp_continue } + } + } + } else { + send "$command\r" + expect { + -re "^\[^\n\r]*$prompt" {} + -re "^\[^\n\r *]*$prompt" {} + -re "\[\n\r]" { exp_continue } + } + } + send "exit\r" + expect { + "\n" { exp_continue } + timeout { return 0 } + eof { return 0 } + } + set in_proc 0 +} + +# +# For each router... (this is main loop) +# +source_password_file $password_file +set in_proc 0 +foreach router [lrange $argv $i end] { + set router [string tolower $router] + send_user "$router\n" + + # Figure out prompt. + set prompt "command: " + set autoenable 1 + set enable 0 + + # Figure out passwords + if { $do_passwd } { + set pswd [find password $router] + if { [llength $pswd] == 0 } { + send_user "Error: no password for $router in $password_file.\n" + continue + } + set passwd [join [lindex $pswd 0] ""] + } + + # Figure out username + if {[info exists username]} { + # command line username + set ruser $username + } else { + set ruser [join [find user $router] ""] + if { "$ruser" == "" } { set ruser $default_user } + } + + # Figure out username's password (if different from the vty password) + if {[info exists userpasswd]} { + # command line username + set userpswd $userpasswd + } else { + set userpswd [join [find userpassword $router] ""] + if { "$userpswd" == "" } { set userpswd $passwd } + } + + # Figure out prompts + set u_prompt [find userprompt $router] + if { "$u_prompt" == "" } { + set u_prompt "(Username|login| Login):" + } else { + set u_prompt [join [lindex $u_prompt 0] ""] + } + set p_prompt [find passprompt $router] + if { "$p_prompt" == "" } { + set p_prompt "\[Pp]assword:" + } else { + set p_prompt [join [lindex $p_prompt 0] ""] + } + + # Figure out cypher type + if {[info exists cypher]} { + # command line cypher type + set cyphertype $cypher + } else { + set cyphertype [find cyphertype $router] + if { "$cyphertype" == "" } { set cyphertype "3des" } + } + + # Figure out connection method + set cmethod [find method $router] + if { "$cmethod" == "" } { set cmethod {{telnet}} } + + # Login to the router + if {[login $router $ruser $userpswd $passwd $prompt $cmethod $cyphertype]} { + continue + } + + if { $do_command } { + if {[run_commands $prompt $command]} { + continue + } + } elseif { $do_script } { + source $sfile + close + } else { + label $router + log_user 1 + interact + } + + # End of for each router + wait + sleep 0.3 +} +exit 0 diff --git a/bin/htrancid.in b/bin/htrancid.in new file mode 100644 index 0000000..2b2eaaa --- /dev/null +++ b/bin/htrancid.in @@ -0,0 +1,266 @@ +#! @PERLV_PATH@ +## +## $Id: htrancid.in,v 1.5 2004/01/11 03:49:13 heas Exp $ +## +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## All rights reserved. +## +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. +## +## There is no warranty or other guarantee of fitness of this software. +## It is provided solely "as is". The author(s) disclaim(s) all +## responsibility and liability with respect to this software's usage +## or its effect upon hardware, computer systems, other software, or +## anything else. +## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. +## +# +# hacked version of Hank's rancid - this one tries to deal with Hitachi's. +# +# RANCID - Really Awesome New Cisco confIg Differ +# +# usage: htrancid [-d] [-l] [-f filename | $host] +# +use Getopt::Std; +getopts('dfl'); +$log = $opt_l; +$debug = $opt_d; +$file = $opt_f; +$host = $ARGV[0]; +$clean_run = 0; +$found_end = 0; +$timeo = 90; # blogin timeout in seconds + +my(%filter_pwds); # password filtering mode + +# This routine is used to print out the router configuration +sub ProcessHistory { + my($new_hist_tag,$new_command,$command_string,@string)=(@_); + if((($new_hist_tag ne $hist_tag) || ($new_command ne $command)) + && defined %history) { + print eval "$command \%history"; + undef %history; + } + if (($new_hist_tag) && ($new_command) && ($command_string)) { + if ($history{$command_string}) { + $history{$command_string} = "$history{$command_string}@string"; + } else { + $history{$command_string} = "@string"; + } + } elsif (($new_hist_tag) && ($new_command)) { + $history{++$#history} = "@string"; + } else { + print "@string"; + } + $hist_tag = $new_hist_tag; + $command = $new_command; + 1; +} + +sub numerically { $a <=> $b; } + +# This is a sort routing that will sort numerically on the +# keys of a hash as if it were a normal array. +sub keynsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort numerically keys(%lines)) { + $sorted_lines[$i] = $lines{$key}; + $i++; + } + @sorted_lines; +} + +# This is a sort routing that will sort on the +# keys of a hash as if it were a normal array. +sub keysort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort keys(%lines)) { + $sorted_lines[$i] = $lines{$key}; + $i++; + } + @sorted_lines; +} + +# This is a sort routing that will sort on the +# values of a hash as if it were a normal array. +sub valsort{ + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort values %lines) { + $sorted_lines[$i] = $key; + $i++; + } + @sorted_lines; +} + +# This is a numerical sort routing (ascending). +sub numsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $num (sort {$a <=> $b} keys %lines) { + $sorted_lines[$i] = $lines{$num}; + $i++; + } + @sorted_lines; +} + +# This is a sort routine that will sort on the +# ip address when the ip address is anywhere in +# the strings. +sub ipsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $addr (sort sortbyipaddr keys %lines) { + $sorted_lines[$i] = $lines{$addr}; + $i++; + } + @sorted_lines; +} + +# These two routines will sort based upon IP addresses +sub ipaddrval { + my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#); + $a[3]+256*($a[2]+256*($a[1]+256*$a[0])); +} +sub sortbyipaddr { + &ipaddrval($a) <=> &ipaddrval($b); +} + +# This routine parses "show config" +sub ShowConfig { + print STDERR " In ShowConfig: $_" if ($debug); + + while () { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + ProcessHistory("","","","$_"); + } + return(0); +} + +# This routine parses single command's that return no required info +sub ShowVersion { + print STDERR " In ShowVersion: $_" if ($debug); + + while () { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + } + return(0) +} + +# dummy function +sub DoNothing {print STDOUT;} + +# Main +%commands=( + 'version -a' => "ShowVersion", + 'cat /config/router.cnf' => "ShowConfig" +); +# keys() doesnt return things in the order entered and the order of the +# cmds is important (show version first and write term last). pita +@commands=( + "version -a", + "cat /config/router.cnf" +); +$cisco_cmds=join(";",@commands); +$cmds_regexp=join("|",@commands); + +open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; +select(OUTPUT); +# make OUTPUT unbuffered if debugging +if ($debug) { $| = 1; } + +if ($file) { + print STDERR "opening file $host\n" if ($debug); + print STDOUT "opening file $host\n" if ($log); + open(INPUT,"<$host") || die "open failed for $host: $!\n"; +} else { + print STDERR "executing htlogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($debug); + print STDOUT "executing htlogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($log); + if (defined($ENV{NOPIPE})) { + system "htlogin -t $timeo -c \"$cisco_cmds\" $host $host.raw 2>&1" || die "htlogin failed for $host: $!\n"; + open(INPUT, "< $host.raw") || die "htlogin failed for $host: $!\n"; + } else { + open(INPUT,"htlogin -t $timeo -c \"$cisco_cmds\" $host ) { + tr/\015//d; + if (/^.*logout$/) { + $clean_run=1; + last; + } + if (/^Error:/) { + print STDOUT ("$host htlogin error: $_"); + print STDERR ("$host htlogin error: $_") if ($debug); + $clean_run=0; + last; + } + while (/command:\s*($cmds_regexp)\s*$/) { + $cmd = $1; + if (!defined($prompt)) { + $prompt = ($_ =~ /^([^:]+:)/)[0]; + } + print STDERR ("HIT COMMAND:$_") if ($debug); + if (! defined($commands{$cmd})) { + print STDERR "$host: found unexpected command - \"$cmd\"\n"; + $clean_run = 0; + last TOP; + } + $rval = &{$commands{$cmd}}; + delete($commands{$cmd}); + if ($rval == -1) { + $clean_run = 0; + last TOP; + } + } +} +print STDOUT "Done $logincmd: $_\n" if ($log); +# Flush History +ProcessHistory("","","",""); +# Cleanup +close(INPUT); +close(OUTPUT); + +if (defined($ENV{NOPIPE})) { + unlink("$host.raw") if (! $debug); +} + +# check for completeness +if (scalar(%commands) || !$clean_run ) { + if (scalar(%commands)) { + printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands))); + printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug); + } + if (!$clean_run ) { + print STDOUT "$host: End of run not found\n"; + print STDERR "$host: End of run not found\n" if ($debug); + system("/usr/bin/tail -1 $host.new"); + } + unlink "$host.new" if (! $debug); +} diff --git a/bin/jerancid.in b/bin/jerancid.in new file mode 100644 index 0000000..1b72737 --- /dev/null +++ b/bin/jerancid.in @@ -0,0 +1,645 @@ +#! @PERLV_PATH@ +## +## $Id: jerancid.in,v 1.25 2004/01/11 03:49:13 heas Exp $ +## +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## All rights reserved. +## +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. +## +## There is no warranty or other guarantee of fitness of this software. +## It is provided solely "as is". The author(s) disclaim(s) all +## responsibility and liability with respect to this software's usage +## or its effect upon hardware, computer systems, other software, or +## anything else. +## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. +## +# +# jerancid - tries to deal with Juniper ERXs. +# +# RANCID - Really Awesome New Cisco confIg Differ +# +# usage: rancid [-d] [-l] [-f filename | $host] +# +use Getopt::Std; +getopts('dfl'); +$log = $opt_l; +$debug = $opt_d; +$file = $opt_f; +$host = $ARGV[0]; +$clean_run = 0; +$found_end = 0; +$timeo = 90; # clogin timeout in seconds + +my(%filter_pwds); # password filtering mode + +# This routine is used to print out the router configuration +sub ProcessHistory { + my($new_hist_tag,$new_command,$command_string,@string)=(@_); + if((($new_hist_tag ne $hist_tag) || ($new_command ne $command)) + && defined %history) { + print eval "$command \%history"; + undef %history; + } + if (($new_hist_tag) && ($new_command) && ($command_string)) { + if ($history{$command_string}) { + $history{$command_string} = "$history{$command_string}@string"; + } else { + $history{$command_string} = "@string"; + } + } elsif (($new_hist_tag) && ($new_command)) { + $history{++$#history} = "@string"; + } else { + print "@string"; + } + $hist_tag = $new_hist_tag; + $command = $new_command; + 1; +} + +sub numerically { $a <=> $b; } + +# This is a sort routing that will sort numerically on the +# keys of a hash as if it were a normal array. +sub keynsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort numerically keys(%lines)) { + $sorted_lines[$i] = $lines{$key}; + $i++; + } + @sorted_lines; +} + +# This is a sort routing that will sort on the +# keys of a hash as if it were a normal array. +sub keysort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort keys(%lines)) { + $sorted_lines[$i] = $lines{$key}; + $i++; + } + @sorted_lines; +} + +# This is a sort routing that will sort on the +# values of a hash as if it were a normal array. +sub valsort{ + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort values %lines) { + $sorted_lines[$i] = $key; + $i++; + } + @sorted_lines; +} + +# This is a numerical sort routing (ascending). +sub numsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $num (sort {$a <=> $b} keys %lines) { + $sorted_lines[$i] = $lines{$num}; + $i++; + } + @sorted_lines; +} + +# This is a sort routine that will sort on the +# ip address when the ip address is anywhere in +# the strings. +sub ipsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $addr (sort sortbyipaddr keys %lines) { + $sorted_lines[$i] = $lines{$addr}; + $i++; + } + @sorted_lines; +} + +# These two routines will sort based upon IP addresses +sub ipaddrval { + my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#); + $a[3]+256*($a[2]+256*($a[1]+256*$a[0])); +} +sub sortbyipaddr { + &ipaddrval($a) <=> &ipaddrval($b); +} + +# This routine parses "show version" +sub ShowVersion { + print STDERR " In ShowVersion: $_" if ($debug); + my($slots); + + while () { + tr/\015//d; + last if(/^$prompt/); + next if(/^(\s*|\s*$cmd\s*)$/); + next if (/^Please wait/i); + return(-1) if (/command authorization failed/i); + + /^Juniper Edge .* (\S+)$/ && + ProcessHistory("COMMENTS","keysort","A1", + "!Chassis type: $1 - a $_") && next; + /^System Release: / && + ProcessHistory("COMMENTS","keysort","B1", "!$_") && next; + /^\s+(Version: .*)$/ && + ProcessHistory("COMMENTS","keysort","B1", "!System $1\n") && + next; + + if (/^(slot .*)\s+slot uptime/i) { + ($slots++); + ProcessHistory("COMMENTS","keysort","B2", "!\n! $1\n"); + next; + } + /^(--.*) --+$/ && $slots && + ProcessHistory("COMMENTS","keysort","B2", "! $1\n") && next; + if (/^(\d+ +\S+ +(\S+).*) \S+$/ && $slots) { + my($line) = $1; + if ($2 != /--+/) { + ProcessHistory("COMMENTS","keysort","B3", "! $line\n"); + } + next; + } + } + ProcessHistory("COMMENTS","keysort","B4","!\n"); + return(0); +} + +# This routine parses "show redundancy" +sub ShowRedundancy { + print STDERR " In ShowRedundancy: $_" if ($debug); + + while () { + tr/\015//d; + last if(/^$prompt/); + next if(/^(\s*|\s*$cmd\s*)$/); + next if (/^Please wait/i); + + ProcessHistory("","","","! $_"); + } + ProcessHistory("","","","!\n"); + return(0); +} + +# This routine parses "show environment all" +sub ShowEnv { + print STDERR " In ShowEnv: $_" if ($debug); + + while () { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + next if (/^Please wait/i); + return(-1) if (/command authorization failed/i); + + # skip the temperature goop + if (/processor\s+processor/) { + ; ; ; + next; + } + /^\d+\s+\d+\s+\S+/ && next; + + # strip nvs usage + s/, \d+% \S+\)/\)/; + + s/^ //; + ProcessHistory("COMMENTS","keysort","D1","! $_"); + } + ProcessHistory("COMMENTS","keysort","D1","!\n"); + return(0); +} + +# This routine parses "show boot" +sub ShowBoot { + print STDERR " In ShowBoot: $_" if ($debug); + + while () { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + next if (/^Please wait/i); + next if (/^\s*$/); + return(1) if /^\s*\^\s*$/; + return(-1) if (/command authorization failed/i); + return(1) if /Ambiguous command/i; + + /System Release:\s+(.*)/ && + ProcessHistory("COMMENTS","keysort","C1","!Boot Release: $1\n") + && next; + /System Configuration:\s+(.*)/ && + ProcessHistory("COMMENTS","keysort","C1", + "!Boot Configuration: $1\n") && next; + + ProcessHistory("COMMENTS","keysort","C1","!$_"); + } + ProcessHistory("COMMENTS","keysort","C1","!\n"); + return(0); +} + +# This routine parses "dir" +sub DirSlotN { + print STDERR " In DirSlotN: $_" if ($debug); + + my($dev) = (/\s([^\s]+):/); + + while () { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + next if (/^Please wait/i); + next if (/^system\.log/); + + ProcessHistory("FLASH","","","!Flash: $_"); + } + ProcessHistory("","","","!\n"); + return(0); +} + +# This routine parses "show hardware" +sub ShowHardware { + print STDERR " In ShowHardware: $_" if ($debug); + + while () { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + next if (/^Please wait/i); + # return(1) if ($type =~ /^(12[40]|7[05])/); + return(-1) if (/command authorization failed/i); + next if (/^Please wait/i); + + # wow...a clean table + ProcessHistory("","","","!$_"); + } + ProcessHistory("","","","!\n"); + return(0); +} + +# This routine processes a "show configuration" +sub WriteTerm { + print STDERR " In WriteTerm: $_" if ($debug); + my($lineauto) = 0; + + while () { + tr/\015//d; + last if(/^$prompt/); + next if (/^Please wait/i); + return(-1) if (/command authorization failed/i); + /Non-Volatile memory is in use/ && return(-1); # NvRAM is locked + $lineauto = 0 if (/^[^ ]/); + + # skip the crap + /^! Configuration script /i && next; + /^! Copyright /i && next; + + # Dog gone Cool matches to process the rest of the config + /^ntp clock-period / && next; # kill ntp clock-period + /^ length / && next; # kill length on serial lines + /^ width / && next; # kill width on serial lines + $lineauto = 1 if /^ modem auto/; + /^ speed / && $lineauto && next; # kill speed on serial lines + /^ clockrate / && next; # kill clockrate on serial interfaces + if (/^(enable )?(password|passwd) / && $filter_pwds >= 1) { + ProcessHistory("ENABLE","","","!$1$2 \n"); + next; + } + if (/^(enable secret) / && $filter_pwds >= 2) { + ProcessHistory("ENABLE","","","!$1 \n"); + next; + } + + # XXX: ERX appears to not have local usernames, but leaving these in + # case I am wrong. + if (/^username (\S+)(\s.*)? secret /) { + if ($filter_pwds >= 2) { + ProcessHistory("USER","keysort","$1", + "!username $1$2 secret \n"); + } else { + ProcessHistory("USER","keysort","$1","$_"); + } + next; + } + if (/^username (\S+)(\s.*)? password ((\d) \S+|\S+)/) { + if ($filter_pwds == 2) { + ProcessHistory("USER","keysort","$1", + "!username $1$2 password \n"); + } elsif ($filter_pwds == 1 && $4 ne "5"){ + ProcessHistory("USER","keysort","$1", + "!username $1$2 password \n"); + } else { + ProcessHistory("USER","keysort","$1","$_"); + } + next; + } + + if (/^(\s*)password / && $filter_pwds >= 1) { + ProcessHistory("LINE-PASS","","","!$1password \n"); + next; + } + if (/^\s*neighbor (\S*) password / && $filter_pwds >= 1) { + ProcessHistory("","","","! neighbor $1 password \n"); + next; + } + if (/^(ppp .* password) 7 .*/ && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); next; + } + if (/^( ip ospf authentication-key) / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); next; + } + # isis interface passwords + if (/^(\s+isis authentication-key \S+)( \d)? \S+/ && + $filter_pwds >= 1) { + ProcessHistory("","","","!$1 $'\n"); next; + } + if (/^(\s+isis message-digest-key \d+ hmac-md5)( \d)?( \S+)/ && + $filter_pwds >= 1) { + ProcessHistory("","","","!$1 $'"); next; + } + + # this is reversable, despite 'md5' in the cmd + if (/^(\s+ip ospf authentication-key \S+)( \d)? \S+/ && + $filter_pwds >= 1) { + ProcessHistory("","","","!$1 $'\n"); next; + } + if (/^(\s+ip ospf message-digest-key \d+ hmac-md5)( \d)?( \S+)/ && + $filter_pwds >= 1) { + ProcessHistory("","","","!$1 $'"); next; + } + if (/^( ip ospf message-digest-key \d+ md5) / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); next; + } + + # filter VRRP passwords + if (/^(\s+ip vrrp authentication-key \d+)( \d)? \s+ / && + $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); next; + } + + # ftp host encrypted password oscillates + if (/^(host \S+ \S+ ftp) /) { + if ($filter_pwds >= 1 || /^host \S+ \S+ ftp \d /) { + ProcessHistory("","","","!$1 \n"); next; + } + } + + # sort ip explicit-paths. + if (/^ip explicit-path name (\S+)/) { + my($key) = $1; + my($expath) = $_; + while () { + tr/\015//d; + last if (/^$prompt/); + last if (/^$prompt/ || ! /^(ip explicit-path name |[ !])/); + if (/^ip explicit-path name (\S+)/) { + ProcessHistory("EXPATH","keysort","$key","$expath"); + $key = $1; + $expath = $_; + } else { + $expath .= $_; + } + } + ProcessHistory("EXPATH","keysort","$key","$expath"); + } + # sort route-maps + if (/^route-map (\S+)/) { + my($key) = $1; + my($routemap) = $_; + while () { + tr/\015//d; + last if (/^$prompt/ || ! /^(route-map |[ !])/); + if (/^route-map (\S+)/) { + ProcessHistory("ROUTEMAP","keysort","$key","$routemap"); + $key = $1; + $routemap = $_; + } else { + $routemap .= $_; + } + } + ProcessHistory("ROUTEMAP","keysort","$key","$routemap"); + } + # filter out any RCS/CVS tags to avoid confusing local CVS storage + s/\$(Revision|Id):/ $1:/; + + # order arp lists + /^arp\s+(\d+\.\d+\.\d+\.\d+)\s+/ && + ProcessHistory("ARP","ipsort","$1","$_") && next; + + /^ip prefix-list\s+(\S+)\s+seq\s+(\d+)\s+(permit|deny)\s+(\d\S+)(\/.*)$/ && + ProcessHistory("PACL $1 $3","ipsort","$4","ip prefix-list $1 $3 $4$5\n") + && next; + + + # order/prune snmp-server host statements + # we only prune lines of the form + # snmp-server host a.b.c.d + if (/^snmp-server host (\d+\.\d+\.\d+\.\d+) /) { + if (defined($ENV{'NOCOMMSTR'})) { + my($ip) = $1; + my($line) = "snmp-server host $ip"; + my(@tokens) = split(' ', $'); + my($token); + while ($token = shift(@tokens)) { + if ($token eq 'version' || $tokens[0] == 1) { + $line .= " " . join(' ', ($token, shift(@tokens))); + } elsif ($token =~ /^(informs?|traps?|(no)?auth)$/) { + $line .= " " . $token; + } else { + $line = "!$line " . + join(' ', ("", join(' ',@tokens))); + last; + } + } + ProcessHistory("SNMPSERVERHOST","ipsort","$ip","$line\n"); + } else { + ProcessHistory("SNMPSERVERHOST","ipsort","$1","$_"); + } + next; + } + if (/^(snmp-server community) (\S+)/) { + if (defined($ENV{'NOCOMMSTR'})) { + ProcessHistory("SNMPSERVERCOMM","keysort","$_","!$1 $'"); + next; + } else { + ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && next; + } + } + + # prune tacacs/radius server keys + if (/^(tacacs-server|radius-server) key / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 key \n"); next; + } + if (/^((tacacs-server|radius-server) host \S+ key)( \d)? \S+/ && + $filter_pwds >= 1) { + ProcessHistory("","","","!$1 $'"); next; + } + if (/^( key )(\d )?\S+/ && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 $'"); next; + } + + # order clns host statements + /^clns host \S+ (\S+)/ && + ProcessHistory("CLNS","keysort","$1","$_") && next; + # order alias statements + /^alias / && ProcessHistory("ALIAS","keysort","$_","$_") && next; + # filter isis keys + if (/^( (area|domain)-message-digest-key \d+ hmac-md5)( \d)? \S+/ && + $filter_pwds >= 1) { + ProcessHistory("","","","!$1 $'\n"); next; + } + if (/^( (area|domain)-authentication-key)( \d)? \S+( \d)?/ && + $filter_pwds >= 1) { + ProcessHistory("","","","!$1 $'\n"); next; + } + + # delete ntp auth password - this md5 is a reversable too + if (/^(ntp authentication-key \d+ md5) / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); next; + } + + # order ntp peers/servers + if (/^ntp (server|peer) (\d+)\.(\d+)\.(\d+)\.(\d+)/) { + $sortkey = sprintf("$1 %03d%03d%03d%03d",$2,$3,$4,$5); + ProcessHistory("NTP","keysort",$sortkey,"$_"); + next; + } + + # catch anything that wasnt matched above. + ProcessHistory("","","","$_"); + # end of config...is a comment. + if (/^! end of /i) { + $found_end = 1; + return(1); + } + } + return(0); +} + +# dummy function +sub DoNothing {print STDOUT;} + +# Main +%commands=( + 'show version' => "ShowVersion", + 'show redundancy' => "ShowRedundancy", + 'show boot' => "ShowBoot", + 'show environment all' => "ShowEnv", + 'dir' => "DirSlotN", + 'show hardware' => "ShowHardware", + 'show configuration' => "WriteTerm" +); +# keys() doesnt return things in the order entered and the order of the +# cmds is important (show version first and write term last). pita +@commands=( + "show version", + "show redundancy", + "show boot", + "show environment all", + "dir", + "show hardware", + "show configuration" +); +$jnxe_cmds=join(";",@commands); +$cmds_regexp=join("|",@commands); + +open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; +select(OUTPUT); +# make OUTPUT unbuffered if debugging +if ($debug) { $| = 1; } + +if ($file) { + print STDERR "opening file $host\n" if ($debug); + print STDOUT "opening file $host\n" if ($log); + open(INPUT,"<$host") || die "open failed for $host: $!\n"; +} else { + print STDERR "executing clogin -t $timeo -c\"$jnxe_cmds\" $host\n" if ($debug); + print STDOUT "executing clogin -t $timeo -c\"$jnxe_cmds\" $host\n" if ($log); + if (defined($ENV{NOPIPE})) { + system "clogin -t $timeo -c \"$jnxe_cmds\" $host $host.raw 2>&1" || die "clogin failed for $host: $!\n"; + open(INPUT, "< $host.raw") || die "clogin failed for $host: $!\n"; + } else { + open(INPUT,"clogin -t $timeo -c \"$jnxe_cmds\" $host ) { + tr/\015//d; + if (/\#\s?exit$/) { + $clean_run=1; + last; + } + if (/^Error:/) { + print STDOUT ("$host clogin error: $_"); + print STDERR ("$host clogin error: $_") if ($debug); + $clean_run=0; + last; + } + while (/#\s*($cmds_regexp)\s*$/) { + $cmd = $1; + if (!defined($prompt)) { + $prompt = ($_ =~ /^([^#]+#)/)[0]; + $prompt =~ s/([][}{)(\\])/\\$1/g; + print STDERR ("PROMPT MATCH: $prompt\n") if ($debug); + } + print STDERR ("HIT COMMAND:$_") if ($debug); + if (! defined($commands{$cmd})) { + print STDERR "$host: found unexpected command - \"$cmd\"\n"; + $clean_run = 0; + last TOP; + } + $rval = &{$commands{$cmd}}; + delete($commands{$cmd}); + if ($rval == -1) { + $clean_run = 0; + last TOP; + } + } +} +print STDOUT "Done $logincmd: $_\n" if ($log); +# Flush History +ProcessHistory("","","",""); +# Cleanup +close(INPUT); +close(OUTPUT); + +if (defined($ENV{NOPIPE})) { + unlink("$host.raw") if (! $debug); +} + +# check for completeness +if (scalar(%commands) || !$clean_run || !$found_end) { + if (scalar(%commands)) { + printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands))); + printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug); + } + if (!$clean_run || !$found_end) { + print STDOUT "$host: End of run not found\n"; + print STDERR "$host: End of run not found\n" if ($debug); + system("/usr/bin/tail -1 $host.new"); + } + unlink "$host.new" if (! $debug); +} diff --git a/bin/jlogin.in b/bin/jlogin.in old mode 100755 new mode 100644 index 0f005d7..31be4f6 --- a/bin/jlogin.in +++ b/bin/jlogin.in @@ -1,25 +1,30 @@ -#!@EXPECT_PATH@ -- +#! @EXPECT_PATH@ -- ## +## $Id: jlogin.in,v 1.41 2004/01/11 05:39:15 heas Exp $ ## -## Copyright (C) 1997-2001 by Henry Kilmer, Erik Sherk and Pete Whiting. +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. ## All rights reserved. ## -## This software may be freely copied, modified and redistributed without -## fee for non-commerical purposes provided that this copyright notice is -## preserved intact on all copies and modified copies. +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. ## ## There is no warranty or other guarantee of fitness of this software. -## It is provided solely "as is". The author(s) disclaim(s) all +## It is provided solely "as is". The author(s) disclaim(s) all ## responsibility and liability with respect to this software's usage ## or its effect upon hardware, computer systems, other software, or ## anything else. ## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. ## # -# jlogin - juniper ssh login +# The login expect scripts were based on Erik Sherk's gwtn, by permission. # -## Most options are intuitive for logging into a Cisco router. -## The default username password is the same as the vty password. +# jlogin - juniper login +# +# Most options are intuitive for logging into a Cisco router. +# The default username password is the same as the vty password. # # Usage line @@ -49,6 +54,8 @@ if {[ info exists env(CISCO_USER) ] } { set default_user $env(CISCO_USER) } elseif {[ info exists env(USER) ]} { set default_user $env(USER) +} elseif {[ info exists env(LOGNAME) ]} { + set default_user $env(LOGNAME) } else { # This uses "id" which I think is portable. At least it has existed # (without options) on all machines/OSes I've been on recently - @@ -82,7 +89,7 @@ for {set i 0} {$i < $argc} {incr i} { if {[ regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} { set E$varname $varvalue } else { - send_user "Error: invalid format for -E in $arg\n" + send_user "\nError: invalid format for -E in $arg\n" exit 1 } # alternate cloginrc file @@ -249,6 +256,7 @@ proc source_password_file { password_file } { # Log into the router. proc login { router user passwd cmethod cyphertype identfile} { global spawn_id in_proc do_command do_script passphrase prompt + global sshcmd set in_proc 1 # try each of the connection methods in $cmethod until one is successful @@ -270,13 +278,13 @@ proc login { router user passwd cmethod cyphertype identfile} { # We use two calls to spawn since spawn does not seem to parse # spaces correctly. if {$identfile != ""} { - if [ catch {spawn ssh -c $cyphertype -x -l $user -i $identfile $router} reason ] { - send_user "\nError: failed to ssh: $reason\n" + if [ catch {spawn $sshcmd -c $cyphertype -x -l $user -i $identfile $router} reason ] { + send_user "\nError: failed to $sshcmd: $reason\n" exit 1 } } else { - if [ catch {spawn ssh -c $cyphertype -x -l $user $router} reason ] { - send_user "\nError: failed to ssh: $reason\n" + if [ catch {spawn $sshcmd -c $cyphertype -x -l $user $router} reason ] { + send_user "\nError: failed to $sshcmd: $reason\n" exit 1 } } @@ -438,7 +446,7 @@ foreach router [lrange $argv $i end] { # command line username set loginname $username } else { - set loginname [find user $router] + set loginname [join [find user $router] ""] if { "$loginname" == "" } { set loginname $default_user } } @@ -447,11 +455,11 @@ foreach router [lrange $argv $i end] { # command line passwd set passwd $userpasswd } else { - set passwd [lindex [find userpassword $router] 0] + set passwd [join [lindex [find userpassword $router] 0] ""] if { "$passwd" == "" } { - set passwd [lindex [find password $router] 0] + set passwd [join [lindex [find password $router] 0] ""] if { "$passwd" == "" } { - send_user "Error: no password for $router in $password_file.\n" + send_user "\nError: no password for $router in $password_file.\n" continue } } @@ -460,7 +468,7 @@ foreach router [lrange $argv $i end] { # figure out identity file to use set identfile "" if {[info exists identity]} { - set identfile [lindex [find identity $router] 0] + set identfile [join [lindex [find identity $router] 0] ""] } # Figure out ssh cypher type @@ -476,6 +484,10 @@ foreach router [lrange $argv $i end] { set cmethod [find method $router] if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} } + # Figure out the SSH executable name + set sshcmd [find sshcmd $router] + if { "$sshcmd" == "" } { set sshcmd {ssh} } + # Login to the router if {[login $router $loginname $passwd $cmethod $cyphertype $identfile]} { continue diff --git a/bin/jrancid.in b/bin/jrancid.in old mode 100755 new mode 100644 index 238e704..2793446 --- a/bin/jrancid.in +++ b/bin/jrancid.in @@ -1,23 +1,27 @@ -#!@PERLV_PATH@ +#! @PERLV_PATH@ ## -## Amazingly hacked version of Hank's rancid - this one tries to -## deal with Junipers. +## $Id: jrancid.in,v 1.58 2004/01/11 03:49:13 heas Exp $ ## -## Original Rancid: Copyright (C) 1997-2001 by Henry Kilmer. +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. ## All rights reserved. ## -## This software may be freely copied, modified and redistributed without -## fee for non-commerical purposes provided that this copyright notice is -## preserved intact on all copies and modified copies. +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. ## ## There is no warranty or other guarantee of fitness of this software. -## It is provided solely "as is". The author(s) disclaim(s) all +## It is provided solely "as is". The author(s) disclaim(s) all ## responsibility and liability with respect to this software's usage ## or its effect upon hardware, computer systems, other software, or ## anything else. ## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. ## # +# Amazingly hacked version of Hank's rancid - this one tries to +# deal with Junipers. +# # RANCID - Really Awesome New Cisco confIg Differ # # usage: jrancid [-d] [-l] [-f filename | $host] @@ -147,6 +151,8 @@ sub ShowChassisClocks { while () { tr/\015//d; last if(/^$prompt/); + next if(/^system (shutdown message from|going down )/i); + next if(/^\{(master|backup)}/); /error: the chassis subsystem is not running/ && return; /Couldn\'t initiate connection/ && return; @@ -171,6 +177,8 @@ sub ShowChassisEnvironment { while () { tr/\015//d; last if(/^$prompt/); + next if(/^system (shutdown message from|going down )/i); + next if(/^\{(master|backup)}/); /error: the chassis subsystem is not running/ && return; /Couldn\'t initiate connection/ && return; @@ -199,6 +207,8 @@ sub ShowChassisFirmware { while () { tr/\015//d; last if(/^$prompt/); + next if(/^system (shutdown message from|going down )/i); + next if(/^\{(master|backup)}/); /error: the chassis subsystem is not running/ && return; /Couldn\'t initiate connection/ && return; @@ -220,6 +230,8 @@ sub ShowChassisFpcDetail { while () { tr/\015//d; last if(/^$prompt/); + next if(/^system (shutdown message from|going down )/i); + next if(/^\{(master|backup)}/); /error: the chassis subsystem is not running/ && return; /Couldn\'t initiate connection/ && return; @@ -244,6 +256,8 @@ sub ShowChassisHardware { while () { tr/\015//d; last if(/^$prompt/); + next if(/^system (shutdown message from|going down )/i); + next if(/^\{(master|backup)}/); /error: the chassis subsystem is not running/ && return; /Couldn\'t initiate connection/ && return; @@ -266,6 +280,8 @@ sub ShowChassisRoutingEngine { while () { tr/\015//d; last if(/^$prompt/); + next if(/^system (shutdown message from|going down )/i); + next if(/^\{(master|backup)}/); /error: the chassis subsystem is not running/ && return; /Couldn\'t initiate connection/ && return; @@ -284,8 +300,8 @@ sub ShowChassisRoutingEngine { return; } -# This routine parses "show chassis feb" "show chassis scb", "show -# chassis sfm detail", and "show chassis ssb". +# This routine parses "show chassis cfeb", "show chassis feb", "show +# chassis scb", "show chassis sfm detail", and "show chassis ssb". # Only do this routine once. sub ShowChassisSCB { print STDERR " In ShowChassisSCB: $_" if ($debug); @@ -295,6 +311,8 @@ sub ShowChassisSCB { while () { tr/\015//d; last if(/^$prompt/); + next if(/^system (shutdown message from|going down )/i); + next if(/^\{(master|backup)}/); return if ($ShowChassisSCB); /error: the chassis subsystem is not running/ && return; @@ -315,6 +333,25 @@ sub ShowChassisSCB { return; } +# This routine parses "show system boot-messages" +sub ShowChassisAlarms { + print STDERR " In ShowChassisAlarms: $_" if ($debug); + + ProcessHistory("","","","# $_"); + while () { + tr/\015//d; + last if(/^$prompt/); + next if(/^system (shutdown message from|going down )/i); + next if(/^\{(master|backup)}/); + + /Unrecognized command/ && return; + /^\s+\^/ && return; + /syntax error/ && return; + ProcessHistory("","","","# $_"); + } + return; +} + # This routine parses "show system boot-messages" sub ShowSystemBootMessages { print STDERR " In ShowSystemBootMessages: $_" if ($debug); @@ -324,6 +361,8 @@ sub ShowSystemBootMessages { while () { tr/\015//d; last if(/^$prompt/); + next if(/^system (shutdown message from|going down )/i); + next if(/^\{(master|backup)}/); /Unrecognized command/ && return; /^\s+\^/ && return; @@ -347,10 +386,15 @@ sub ShowVersion { while () { tr/\015//d; last if(/^$prompt/); + next if(/^\s*$/); + next if(/^system (shutdown message from|going down )/i); + next if(/^\{(master|backup)}/); /^Juniper Networks is:/ && ProcessHistory("","","","# \n# $_") && next; ProcessHistory("","","","# $_"); } + ProcessHistory("","","","#\n"); + return; } @@ -371,11 +415,14 @@ sub ShowConfiguration { $found_end++; last; } + next if(/^system (shutdown message from|going down )/i); + next if(/^\{(master|backup)}/); $lines++; /^database header mismatch: / && return(-1); /^version .*;\d+$/ && return(-1); + s/ # SECRET-DATA$//; # filter snmp community, when in snmp { stanza } /^snmp/ && $snmp++; /^}/ && ($snmp = 0); @@ -384,24 +431,30 @@ sub ShowConfiguration { $_ = "$1$2 \"\"$3\n"; } } - if (/(\s*authentication-key ).*$/ && $filter_pwds >= 1) { - s/(\s*authentication-key ).*$/#$1;/; + if (/(\s*authentication-key )[^ ;]+/ && $filter_pwds >= 1) { + ProcessHistory("","","","#$1$'"); + next; } - if (/(\s*hello-authentication-key ).*$/ && $filter_pwds >= 1) { - s/(\s*hello-authentication-key ).*$/#$1;/; + if (/(\s*hello-authentication-key )[^ ;]+/ && $filter_pwds >= 1) { + ProcessHistory("","","","#$1$'"); + next; } - if (/^(.*\ssecret \")\$9\$.*(\".*)$/ && $filter_pwds >= 1) { - s/^(.*\ssecret \")\$9\$.*(\".*)$/#$1$2/; + if (/^(.*\ssecret )[^ ;]+/ && $filter_pwds >= 1) { + ProcessHistory("","","","#$1$'"); + next; } - if (/(\s+encrypted-password ).*$/ && $filter_pwds >= 2) { - ProcessHistory("","","","#$1;\n"); + if (/(\s+encrypted-password )[^ ;]+/ && $filter_pwds >= 2) { + ProcessHistory("","","","#$1$'"); next; } if (/(\s+ssh-(rsa|dsa) )\"/ && $filter_pwds >= 2) { ProcessHistory("","","","#$1;\n"); next; } - s/ # SECRET-DATA$//; + if (/^(\s+(pre-shared-|)key (ascii-text|hexadecimal) )[^ ;]+/ && $filter_pwds >= 1) { + ProcessHistory("","","","#$1$'"); + next; + } ProcessHistory("","","","$_"); } @@ -433,8 +486,10 @@ sub DoNothing {print STDOUT;} "show chassis sfm detail" => "ShowChassisSCB", "show chassis ssb" => "ShowChassisSCB", "show chassis feb" => "ShowChassisSCB", + "show chassis cfeb" => "ShowChassisSCB", + "show chassis alarms" => "ShowChassisAlarms", "show system boot-messages" => "ShowSystemBootMessages", - "show version" => "ShowVersion", + "show version detail" => "ShowVersion", "show configuration" => "ShowConfiguration" ); @commands=( @@ -448,8 +503,10 @@ sub DoNothing {print STDOUT;} "show chassis sfm detail", "show chassis ssb", "show chassis feb", + "show chassis cfeb", + "show chassis alarms", "show system boot-messages", - "show version", + "show version detail", "show configuration" ); @@ -512,7 +569,8 @@ TOP: while() { $cmd = $1; if (!defined($prompt)) { $prompt = ($_ =~ /^([^>]+>)/)[0]; - $prompt =~ s/([}{)(\\])/\\$1/g; + $prompt =~ s/([][}{)(\\])/\\$1/g; + print STDERR ("PROMPT MATCH: $prompt\n") if ($debug); } print STDERR ("HIT COMMAND:$_") if ($debug); if (! defined($commands{$cmd})) { diff --git a/bin/lg.cgi.in b/bin/lg.cgi.in new file mode 100644 index 0000000..ad08c68 --- /dev/null +++ b/bin/lg.cgi.in @@ -0,0 +1,867 @@ +#! @PERLV_PATH@ +## +## $Id: lg.cgi.in,v 1.47 2004/01/11 03:49:13 heas Exp $ +## +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## All rights reserved. +## +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. +## +## There is no warranty or other guarantee of fitness of this software. +## It is provided solely "as is". The author(s) disclaim(s) all +## responsibility and liability with respect to this software's usage +## or its effect upon hardware, computer systems, other software, or +## anything else. +## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. +## +# +# The original original lookingglass s/w was written by Ed Kern. It was +# a single script that used to be available at http://nitrous.digex.net/. +# Provided by permission and modified beyond recognition. +# +# Looking glass +# vars: query, router, args + +BEGIN { +$me = $0; +$me =~ s/.*\/(\S+)$/$1/; +} + +use CGI qw/:standard escapeHTML/; +use POSIX qw(strftime); +use Sys::Syslog; +use LockFile::Simple qw(lock trylock unlock); + +my($BASEDIR) = "@prefix@"; +my($SYSCONFDIR) = "@sysconfdir@"; +my($pingcmd) = "@LG_PING_CMD@"; + +my($query, $max_time_diff, $cache_dir, $cloginrc, @results); +my($type, $router_param, $remote_user, $arg, $router, $mfg); + +my($LG_CACHE_DIR, $LG_CLOGINRC, $LG_IMAGE, $LG_LOG, $LG_ROUTERDB, $LG_AS_REG); +my($LG_BGP_RT, $LG_CACHE_TIME, $LG_SINGLE, $LG_STRIP); + +if (!defined($ENV{HOME})) { $ENV{HOME} = "."; } + +# note: the following functions are duplicated between lgform.cgi and lg.cgi +# to avoid the need for module inclusion headaches from within a httpd context. +# it is just easier to be self-contained. +# SO, ANY CHANGES HERE SHOULD BE REFLECTED IN THE OTHER .cgi. + +# logging +sub dolog +{ + my($level, $msg) = @_; + + if (defined($LG_LOG) && $LG_LOG !~ /\//) { + openlog($me, "pid", $LG_LOG); + syslog($level, "%s", $msg); + closelog; + } else { + local(*LOG); + my($file); + if (defined($LG_LOG)) { + $file = $LG_LOG; + } else { + $file = "$cache_dir/lg.log"; + } + # log date, hostname, query, addr + if (open(LOG, ">>$file") == 0) { + # stderr, if all else fails + printf(STDERR "[" . strftime("%a %b %e %H:%M:%S %Y", gmtime) . + "] could not open log file $file: $!\n"); + printf(STDERR $msg); + } else { + printf(LOG $msg); + close(LOG); + } + } + return; +} + +# read LG configuration file +sub readconf +{ + my($conffile, $cmds); + local(*CONF); + if (defined($ENV{LG_CONF})) { + $conffile = $ENV{LG_CONF}; + } elsif (-e "lg.conf") { + $conffile = "lg.conf"; + } else { + $conffile = "$SYSCONFDIR/lg.conf"; + } + + if (! -f $conffile) { + return; + } + + if (open(CONF, "< $conffile")) { + while () { + next if (/^\s*(#|$)/); + $cmds .= $_; + } + close(CONF); + eval $cmds; + } else { + printf(STDERR "ERROR: couldn\'t open the configuration file: " . + "$conffile: $!\n"); + exit(1); + } + + return; +} + +# read router.db file +sub readrouters +{ + my($rtrdb); + local(*RTR); + + if (defined($LG_ROUTERDB)) { + $rtrdb = $LG_ROUTERDB; + } else { + $rtrdb = "$SYSCONFDIR/router.db"; + } + + if (! -f $rtrdb) { + my(@dirs, $dir); + # if the router.db file does not exist, try to compile the list from + # the rancid group router.db files. + local(*DIR); + if (! opendir(DIR, $BASEDIR)) { + dolog(LOG_ERR, "ERROR: couldn\'t read $BASEDIR: $!\n"); + } else { + while ($dir = readdir(DIR)) { + next if ($dir =~ /^(\.|\.\.|CVS|bin|etc|logs|util)$/); + push(@dirs, $dir) if (-d "$BASEDIR/$dir"); + } + closedir(DIR); + + foreach $dir (@dirs) { + if (! opendir(DIR, "$BASEDIR/$dir")) { + dolog(LOG_ERR, "ERROR: couldn\'t read $BASEDIR/$dir: $!\n"); + next; + } + closedir(DIR); + next if (! -f "$BASEDIR/$dir/router.db"); + if (open(RTR, "< $BASEDIR/$dir/router.db")) { + while () { + next if (/^\s*(#|$)/); + # fqdn:mfg:state + @record = split('\:', $_); + next if ($record[2] !~ /up/i || $record[1] !~ /(cisco|foundry|juniper)/); + push(@rtrlist, join(':', ($record[0], $record[1]))); + $rtrlabels{join(':', ($record[0], $record[1]))} = $record[0]; + } + close(RTR); + } else { + dolog(LOG_ERR, "ERROR: couldn\'t open the router.db " . + "file: $BASEDIR/$dir/router.db: $!\n"); + } + } + } + } else { + if (open(RTR, "< $rtrdb")) { + while () { + next if (/^\s*(#|$)/); + # fqdn:mfg:state + @record = split('\:', $_); + next if ($record[2] !~ /up/i || $record[1] !~ /(cisco|foundry|juniper)/); + push(@rtrlist, join(':', ($record[0], $record[1]))); + $rtrlabels{join(':', ($record[0], $record[1]))} = $record[0]; + } + close(RTR); + } else { + dolog(LOG_ERR, "ERROR: couldn\'t open the router.db file: " . + "$rtrdb: $!\n"); + exit(1); + } + } + + return; +} + +# the remaining functions are particular to lg.cgi. + +# return true if $router is a member of @rtrlist +sub arraymember { + my($rtrlist) = shift; + my($router) = shift; + my($r); + + foreach $r (@$rtrlist) { + $r = (split(':', $r))[0]; + return(1) if ($r eq $router); + } + + return(0); +} + +# check reachability and lock file before attempting to connect to device +# return non-zero on error. +sub DoRsh +{ + my ($router, $mfg, $cmd, $arg) = @_; + my($ctime) = time(); + my($val); + + my($lckobj) = LockFile::Simple->make(-delay => $lock_int, + -max => $max_lock_wait, -hold => $max_lock_hold); + + if ($pingcmd =~ /\d$/) { + `$pingcmd $router`; + } else { + `$pingcmd $router 56 1`; + } + if ($?) { + print "$router is unreachable. Try again later.\n"; + return(-1); + } + if (! $lckobj->lock("$cache_dir/$router")) { + print "$router is busy. Try again later.\n"; + return(-1); + } + $val = &DoCmd($router, $mfg, $cmd, $arg); + $lckobj->unlock("$cache_dir/$router"); + return($val); +} + +# run commands on the router. return non-zero on error. +sub DoCmd +{ + my($rtr, $mfg, $cmd, $arg) = @_; + local(*CMD); + + if ($mfg =~ /foundry/i) { + open(CMD, "sh -c \"flogin -f $cloginrc -c \'$cmd $arg\' $rtr\" 2>&1 |"); + } elsif ($mfg =~ /juniper/i) { + open(CMD, "sh -c \"jlogin -f $cloginrc -c \'$cmd $arg\' $rtr\" 2>&1 |"); + } else { + open(CMD, "sh -c \"clogin -noenable -f $cloginrc -c \'$cmd $arg\' $rtr\" 2>&1 |"); + } + while () { + tr/\015//d; + if (/^error:/i) { + dolog(LOG_ERR, $_); + if ($LG_STRIP) { undef(@results); } + push(@results, $_); + print @results; + return(-1); + } + push(@results, $_); + if (/$cmd/) { + ($prompt) = /^(\S*)[\#>]/; + if ($LG_STRIP) { + undef(@results); + } else { + print @results; + } + last; + } + } + + while () { + last if /^$prompt[\#>]/; + tr/\015//d; + print $_; + push(@results, $_); + } + while () {} + close(CMD); + + return(0); +} + +## +# Subroutine: Error +# Usage: &Error("msg")); +# Description: displays an error and exits. +## +sub Error { + my($msg) = @_; + + my($q) = new CGI(); + print $q->header; + if ($LG_STYLE) { + print $query->start_html(-title => "LookingGlass Results - $router", + -style => {'src' => $LG_STYLE}); + } else { + print $query->start_html(-title => "LookingGlass Results - $router"); + } + + # add the company image, LG_IMAGE + print $LG_IMAGE; + + + print < + Looking Glass Error: +

+ $msg +
+


+ $LG_INFO +EOF + + print $q->end_html; + exit(0); +} + +# convert an ipv4 address mask to prefix length +sub mask2len { + my($mask) = shift; + my($a, $b, $c, $d) = split('\.', $mask); + my($p, $len); + + $p = ~ (($a << 24) + ($b << 16) + ($c << 8) + $d); + for ($len = 32; $p > 0; $len --) { + $p = $p >> 1; + } + + return($len); +} + +# end the page and exit. +sub end_page { + + print < + + +END + + print $query->end_html; + exit(0); +} + +# start the page and log the transaction... +sub start_page { + my($mfg) = @_; + my($cmd); + + my($timestr) = strftime("%a %b %e %H:%M:%S %Y", gmtime); + dolog(LOG_INFO, sprintf("%s %s %s %s\n", + $ENV{REMOTE_HOST}, $ENV{REMOTE_ADDR}, $ENV{REMOTE_USER}, + "- - [$timestr] $type $router $arg")); + print $query->header; + if ($LG_STYLE) { + print $query->start_html(-title =>"LookingGlass form", + -style => {'src' => $LG_STYLE}); + } else { + print $query->start_html(-title =>"LookingGlass from"); + } + + $timestr = strftime("%a %b %e %H:%M:%S %Y %Z", gmtime); + + # add the company image, LG_IMAGE + print $LG_IMAGE; + + if ($mfg =~ /foundry/i) { + $cmd = $foundryCmd{$type}; + } elsif ($mfg =~ /juniper/i) { + $cmd = $juniperCmd{$type}; + } else { + $cmd = $ciscoCmd{$type}; + } + + print < +

Looking Glass Results - $router +

+
+ +
+ Date: $timestr +

+ Query: $cmd +
+HEAD + + if ($arg) { print "Argument(s): $arg\n"; } + print "

\n"; + + print < + +

+

+END
+
+    return;
+}
+
+
+# Main()
+# read the configuration file if it exists.
+readconf();
+
+# The script will now cache the results as simple files in the $cache_dir,
+# named after the type of query (queries must, of course, be one word with
+# no spaces).  Modify $LG_CACHE_TIME to set the lifetime for cache entries.
+# for most web servers, cache_dir must be writable by uid nobody
+if (defined($LG_CACHE_DIR)) {
+    $cache_dir = $LG_CACHE_DIR;
+} else {
+    $cache_dir = "./tmp";
+}
+
+# read routers table to get @rtrlist
+readrouters();
+
+# when to display cache?  max time difference (in seconds)
+if (defined($LG_CACHE_TIME)) {
+    $max_time_diff = $LG_CACHE_TIME;
+} else {
+    $max_time_diff = "600" ;
+}
+
+# max seconds to wait for a 'router' lock to free up
+$max_lock_wait = 30;
+$lock_int = 5;
+$max_lock_hold = 300;
+
+# clogin setup
+if (defined($LG_CLOGINRC)) {
+    $cloginrc = $LG_CLOGINRC;
+} else {
+    $cloginrc = "$ENV(HOME)/.cloginrc";
+}
+
+$query = new CGI;
+
+# get form data and validate
+$type = ($query->param('query'))[0];
+$router_param = ($query->param('router'))[0];
+$remote_user = $ENV{REMOTE_USER};
+$arg = ($query->param('args'))[0];
+# handle multiple args
+$arg =~ s/["'`]//g;			# these are BS in any arg for any query
+@arg = split(' ', $arg);
+
+# verify router, commands, arguments, etc.
+($router, $mfg) = split(':', $router_param);
+if (!defined($type) || !defined($router) || $router eq "") {
+    &Error("You must at least choose a Query and a router.  Try buying " .
+								"a clue.\n");
+}
+
+if ($arg !~ /^[-A-Za-z0-9|_\/ \.^\$]*$/) {
+    &Error("Funny characters in argument; ignoring.\n");
+}
+if (length($arg) >= 50) {
+    &Error("Argument string too long; ignoring. \n");
+}
+
+if (! arraymember(\@rtrlist, $router)) {
+    my($timestr) = strftime("%a %b %e %H:%M:%S %Y", gmtime);
+    dolog(LOG_WARNING, sprintf("%s %s %s %s\n",
+	$ENV{REMOTE_HOST}, $ENV{REMOTE_ADDR}, $ENV{REMOTE_USER},
+	"- - [$timestr] lg.cgi: attempt to access $router\n"));
+    Error("access to $router not permitted");
+}
+
+# conversion of command "type" passed from lgform.cgi to the vendor's syntax.
+if ($mfg =~ /cisco/i) {
+    %mfgCmd = (
+		# Debug Queries
+		log => "show logging",
+		# Interface Queries
+		framerelay => "show frame-relay pvc",
+		interface => "show interface",
+		intbrief => "show ip interface",	# switch in {interface}
+		# Routing Queries
+		damp => "show ip bgp dampened-paths",
+		neighbor => "show ip bgp neighbor",
+		# Multicast Queries
+		mbgp => "show ip mbgp",
+		mbgpsum => "show ip mbgp summary",
+		mneighbor => "show ip bgp neighbor",
+		msdp => "show ip msdp summary",
+		msdpsa => "show ip msdp sa-cache",
+		msess => "show ip sdr",
+		mroute => "show ip mroute",
+		pim_interface => "show ip pim interface",
+		pim_neighbor => "show ip pim neighbor",
+		pim_rp => "show ip pim rp mapping",
+		# IPv6 Queries
+		#
+		#acl => "show access-list",
+		#aspath => "show ip as-path-access-list",
+		#communitylist => "show ip community-list",
+		ping => "ping",
+		prefix => "show ip bgp",
+		prefixlist => "show ip prefix-list",
+		regex => "show ip bgp regex",
+		route => "show ip route",
+		routemap => "show route-map",
+		rpf => "show ip rpf",
+		summary => "show ip bgp summary",
+		trace => "traceroute",
+		v6_bgp => "show bgp ipv6",
+		v6_interface => "show ipv6 interface",
+		v6_summary => "show bgp ipv6 summary"
+    );
+} elsif ($mfg =~ /foundry/i) {
+    %mfgCmd = (
+		# Debug Queries
+		log => "show log",
+		ping => "ping",
+		trace => "traceroute",
+		# Interface Queries
+		#framerelay => "show frame-relay pvc",	# no compatible command
+		interface => "show interface",
+		# Routing Queries
+		damp => "show ip bgp dampened-paths",
+		neighbor => "show ip bgp neighbor",
+		#regex => "show ip bgp aspath-regex",
+		route => "show ip route",
+		summary => "show ip bgp summary",
+		# Multicast Queries
+		#mbgp => "show ip mbgp",
+		#mbgpsum => "show bgp summary",
+		#mneighbor => "show ip bgp neighbor",
+		mroute => "show ip mroute",
+		msdp => "show ip msdp summary",
+		msdpsa => "show ip msdp sa-cache",
+		msess => "show ip sdr",
+		pim_interface => "show ip pim interface",
+		pim_neighbor => "show ip pim neighbor",
+		pim_rp => "show ip pim rp mapping",
+		rpf => "show ip rpf",
+		# IPv6 Queries
+		# v6_bgp => "show bgp ipv6",
+		# v6_interface => "show ipv6 interface",
+		# v6_summary => "show bgp ipv6 summary"
+		#
+		#acl => "show access-list",
+		#aspath => "show ip as-path-access-list",
+		#communitylist => "show ip community-list",
+		routemap => "show route-map",
+		prefix => "show ip bgp",
+		prefixlist => "show ip prefix-list"
+	);
+} elsif ($mfg =~ /juniper/i) {
+    %mfgCmd = (
+		# Debug Queries
+		log => "show log messages",
+		ping => "ping rapid count 5",
+		trace => "traceroute",
+		# Interface Queries
+		framerelay => "show frame-relay pvc",
+		interface => "show interface",
+		#intbrief => "show ip interface",	# switch in {interface}
+		# Routing Queries
+		damp => "show route damping suppressed terse table inet.0",
+		neighbor => "show bgp neighbor",
+		regex => "show route table inet.0 aspath-regex",
+		summary => "show bgp summary",
+		# Multicast Queries
+		mbgp => "show route table inet.2 terse",
+		mbgpsum => "show bgp summary",
+		mneighbor => "show bgp neighbor",
+		mroute => "show multicast route extensive",
+		msdp => "show msdp",
+		msdpsa => "show msdp source-active",
+		msess => "show multicast sessions",
+		pim_interface => "show pim interface",
+		pim_neighbor => "show pim neighbors",
+		pim_rp => "show pim rps",
+		pim_join => "show pim join",
+		rpf => "show multicast rpf",
+		# IPv6 Queries
+		v6_bgp => "show route table inet6.0",
+		v6_interface => "show interface",
+		v6_summary => "show bgp summary",
+		#
+		#acl => "show access-list",
+		#aspath => "show ip as-path-access-list",
+		#communitylist => "show ip community-list",
+		prefix => "show route table inet.0",
+		prefixlist => "show policy",
+		route => "show route table inet.0 terse",
+		routemap => "show policy"
+	);
+}
+
+# construct Display command from configuration
+%cmdDisp=();
+foreach $qtype (sort keys(%$queries)) {
+    next if (! scalar(%{$queries->{$qtype}}));
+    foreach $sub_type (sort keys(%{$queries->{$qtype}})) {
+	$cmdDisp{$sub_type} = $queries->{$qtype}->{$sub_type};
+    }
+}
+
+# make sure the command is not disabled
+if (! defined($cmdDisp{$type})) {
+    &Error("Unknown command type: $type\n");
+}
+
+# not all cmds/queries are implemented for all platforms
+if (! defined($mfgCmd{$type})) {
+    Error("$cmdDisp{$type} not implemented for $mfg or no suitable " .
+						"equivalent exists.  sorry.\n");
+}
+$cmd = $mfgCmd{$type};
+
+# handle each query/command type
+if ($type eq "prefix" || $type eq "mbgp" || $type eq "route" ) {
+    if ($arg[0] !~ /^\d+\.\d+\.\d+\.\d+$/) {
+	&Error("The IP address \"$arg[0]\" is not valid and lacking an " .
+				"address would over-burden our router.\n");
+    } elsif (defined($arg[1]) && $arg[1] !~ /^\d+\.\d+\.\d+\.\d+$/) {
+	&Error("The IP netmask \"$arg[1]\" is not valid.\n");
+    }
+    if ($mfg =~ /juniper/i && defined($arg[1])) {
+	$arg = $arg[0] . "/" . mask2len($arg[1]);
+    }
+} elsif ($type eq "v6_route" ){
+    # XXX: is this check of the address arg correct and pedantic?
+    if ($arg[0] !~ /[0-9a-fA-F:]+$/) {
+	&Error("The IPv6 address \"$arg[0]\" is not valid.\n");
+    }
+} elsif ($type eq "framerelay") {
+    if ($mfg =~ /juniper/) {
+	&Error("Juniper does not have a show frame-relay pvc command.  " .
+						"Use show interface.\n");
+    }
+    if ($arg[0] > 15 && $arg[0] < 1024) {
+	$arg = $arg[0];
+    } else {
+	undef($arg);
+    }
+} elsif ($type eq "interface" || $type eq "v6_interface") {
+
+	# XXX: wtf is arg[1]?
+#    if ($arg[1] =~ /[-\/0-9:.]+/) {
+#       $arg = $arg[0] . " " . $arg[1];
+#    } else {
+
+    if ($mfg =~ /(cisco|foundry)/) {
+	if ($arg[0] !~ /^b[^ ]+[0-9]/i && $arg[0] =~ /^b/i) {
+	    $type = "intbrief";
+	    $arg = "brief";
+	} else {
+	    $arg = $arg[0];
+	}
+    } elsif ($mfg =~ /juniper/) {
+	my($optind) = 0;
+	# arg 0 may be an intf name or a display option, but there can
+	# only be 2 args
+	$arg = "";
+	while ($optind <= $#arg && $optind < 2) {
+	    $arg[$optind] =~ s/brief/terse/;
+	    if ($arg[$optind] =~ /^([a-z0-9]{2}\-\d+\/\d+\/\d+(:\d+)?)/i) {
+		$arg .= " $1";
+	    } elsif ($arg[$optind] =~ /^det/i) {
+		$arg .= " detail";
+	    } elsif ($arg[$optind] =~ /^ter/i) {
+		$arg .= " terse";
+	    } elsif ($arg[$optind] =~ /^ext/i) {
+		$arg .= " extensive";
+	    }
+	    $optind += 1;
+	}
+    }
+} elsif ($type eq "log") {
+    if ($arg[0] =~ /^\s*\|?$/) {
+	shift(@arg);
+    }
+    $arg[0] =~ s/^\s*\|?//;
+    if ($arg[0] !~ /^\s*$/) {
+	if ($mfg =~ /cisco/i) {
+	    $arg = " | include " . join(' ', @arg);
+	} elsif ($mfg =~ /juniper/i) {
+	    $arg = " | match \"" . join(' ', @arg) . "\"";
+	} else {
+	    undef($arg);
+	}
+    } else {
+	undef($arg);
+    }
+} elsif ($type eq "ping" || $type eq "trace") {
+    if ($arg[0] !~ /^\d+\.\d+\.\d+\.\d+$/) {
+	if ($arg[0] !~ /^[A-Za-z0-9._-]+$/) {
+	    &Error("That argument ($arg[0]) is not valid.\n");
+	}
+    }
+    $arg = $arg[0];
+} elsif ($type eq "aspath" || $type eq "communitylist") {
+    if ($arg[0] !~ /^\d+$/ || ($arg[0] < 1 && $arg[0] > 199)) {
+	&Error("That argument ($arg[0]) is not valid.\n");
+    }
+    $arg = $arg[0];
+} elsif ($type eq "acl") {
+    if ($arg[0] !~ /^\d+$/ || ($arg[0] < 100 && $arg[0] > 199) ||
+					($arg[0] < 1300 && $arg[0] > 2699)) {
+	&Error("That argument ($arg[0]) is not valid.\n");
+    }
+    $arg = $arg[0];
+    # don't show the jewels
+    # XXX: this error msg is useless, but show acl is un-implemented.
+    &Error($mfg) if ($arg == 98 || $arg == 99);
+} elsif ($type eq "prefixlist" || $type eq "routemap") {
+    if ($arg[0] !~ /^[0-9A-Za-z][^\s\"]*$/) {
+	&Error("That argument ($arg[0]) is not valid.\n");
+    }
+    $arg = $arg[0];
+} elsif ($type eq "regex") {
+    # bgp as-path regex
+    $arg = $arg[0];
+    if ($#arg >= 1) {
+	for ($n = 1; $n <= $#arg; $n++) { $arg .= " " . $arg[$n]; }
+    }
+    # remove leading/trailing whitespace
+    $arg =~ s/^\s*//; $arg =~ s/\s*$//;
+    if ($arg !~ /^[0-9_ ^.*+?[\])\(-]*\$?$/ || $arg =~ /^\s*$/) {
+	&Error("That argument ($arg[0]) is not valid.\n");
+    }
+    # pathetic excuses for lookups
+    if ($arg =~ /^[_.* ^]*(\*|1|701|1239|1280|1740|3561|5462|10303)+[_\$]*$/ ||
+	$arg =~ /^[_.* ^]*(1|701|1239|1280|1740|3561|5462|10303)+[_ .]*[\[*.]/) {
+	&Error("Get real.  Such a query has potential to over-burden our " .
+		"router.\nLook that up on your own router.\n");
+    }
+    if ($mfg =~ /juniper/) {
+	$arg =~ s/_/ /g;
+	# pre-junos 4.4 does not allow anchors
+	if ($arg =~ /\^\$/) {
+	    $arg =~ "()";
+	} else {
+	    $arg =~ s/[\$^]/ /g;
+	}
+	$arg = "\"$arg\"";
+    }
+    # escape any ()s
+    $arg =~ s/([\(\)])/\\$1/g;
+} elsif ($type eq "neighbor") {
+    if ($arg[0] !~ /^\d+\.\d+\.\d+\.\d+$/) {
+	if ($arg[0] !~ /([A-Za-z0-9-]*.)*[A-Za-z0-9-]*.(com|edu|net|org)/) {
+	    &Error("That argument ($arg[0]) is not valid.\n");
+	}
+    }
+    $arg = $arg[0];
+    if (defined($arg[1]) && $arg[1] =~ /^(a|ro|f|re)/) {
+	if ($mfg =~ /juniper/) {
+	    if ($arg[1] =~ /^a/) {
+		if (defined($LG_BGP_RT)) {
+		    $cmd = "show route table inet.0 all advertising-protocol ".
+			"bgp";
+		}
+	    } elsif ($arg[1] =~ /^f/) {
+		if (defined($LG_BGP_RT)) {
+		    $cmd = "show route damping table inet.0 all ".
+			"receive-protocol bgp";
+		}
+	    } elsif ($arg[1] =~ /^r/) {
+		if (defined($LG_BGP_RT)) {
+		    $cmd = "show route table inet.0 all receive-protocol bgp";
+		}
+	    }
+	} else {
+	    if ($arg[1] =~ /^a/) {
+		if (defined($LG_BGP_RT)) { $arg .= " advertised-routes"; }
+	    } elsif ($arg[1] =~ /^f/) {
+		$arg .= " flap-statistics";
+	    } elsif ($arg[1] =~ /^ro/) {
+		if (defined($LG_BGP_RT)) { $arg .= " routes"; }
+	    } elsif ($arg[1] =~ /^re/) {
+		if (defined($LG_BGP_RT)) { $arg .= " received-routes"; }
+	    }
+	}
+    }
+} elsif ($type eq "mneighbor") {
+    if ($arg[0] !~ /^\d+\.\d+\.\d+\.\d+$/) {
+	if ($arg[0] !~ /([A-Za-z0-9-]*.)*[A-Za-z0-9-]*.(com|edu|net|org)/) {
+	    &Error("That argument ($arg[0]) is not valid.\n");
+	}
+    }
+    $arg = $arg[0];
+    if (defined($arg[1]) && $arg[1] =~ /^(a|ro|f|re)/) {
+	if ($mfg =~ /juniper/) {
+	    if ($arg[1] =~ /^a/) {
+		$cmd .= " advertised-routes";
+	    } elsif ($arg[1] =~ /^f/) {
+		$cmd .= " flap-statistics";
+	    } elsif ($arg[1] =~ /^ro/) {
+		$cmd .= " routes";
+	    } elsif ($arg[1] =~ /^re/) {
+		$cmd .= " received-routes";
+	    }
+	} else {
+	    if ($arg[1] =~ /^a/) {
+		$arg .= " advertised-routes";
+	    } elsif ($arg[1] =~ /^f/) {
+		$arg .= " flap-statistics";
+	    } elsif ($arg[1] =~ /^ro/) {
+		$arg .= " routes";
+	    } elsif ($arg[1] =~ /^re/) {
+		$arg .= " received-routes";
+	    }
+	}
+    }
+} elsif ($type eq "damp" || $type eq "summary" || $type eq "mbgpsum") {
+    undef($arg);
+}
+
+# make stdout unbuffered, so result page streams.
+$| = 1;
+start_page();
+
+# cache the following
+if ($type eq "summary" || $type eq "mbgpsu" || $type eq "damp"
+							|| $type eq "log") {
+    if (!$arg) {
+	# cache requests with no addr/argument
+	local(*CACHE);
+
+	my($file) = "$cache_dir/$type" ;
+	$file =~ s/\s+/_/g;
+	$file .= "_$router";
+
+	if (-e $file) {
+	    # see if cache exists
+	    @stat = stat($file);
+	    $ftime = $stat[9];
+	    $dtime = time() - $stat[9];
+
+	    # see if we are within cache time
+	    if ($dtime <= $max_time_diff) {
+		if (open(CACHE, "<$file") == 0) {
+		    dolog(LOG_ERR, "couldnt open cache file $file: $!\n");
+		} else {
+		    print "From cache (number of seconds old (max " .
+			"$max_time_diff)): $dtime\n\n";
+		    while () { print $_; }
+		    close(CACHE);
+		    &end_page();
+		}
+	    }
+	}
+
+	# else, execute command and save to a new cache file
+	if (! &DoRsh($router, $mfg, $cmd, $arg)) {
+	    if (open(CACHE, ">$file") == 0) {
+		dolog(LOG_ERR, "couldnt create cache file $file: $!\n");
+		exit(1);
+	    } else {
+		printf(CACHE "@results");
+		close(CACHE);
+	    }
+	}
+    } else {
+	&DoRsh($router, $mfg, $cmd, $arg);
+    }
+    &end_page();
+} else {
+    &DoRsh($router, $mfg, $cmd, $arg);
+    &end_page();
+}
+
+exit(0);
diff --git a/bin/lgform.cgi.in b/bin/lgform.cgi.in
new file mode 100644
index 0000000..461ae68
--- /dev/null
+++ b/bin/lgform.cgi.in
@@ -0,0 +1,259 @@
+#! @PERLV_PATH@
+##
+## $Id: lgform.cgi.in,v 1.25 2004/01/11 03:49:13 heas Exp $
+##
+## Copyright (C) 1997-2004 by Terrapin Communications, Inc.
+## All rights reserved.
+##
+## This software may be freely copied, modified and redistributed
+## without fee for non-commerical purposes provided that this license
+## remains intact and unmodified with any RANCID distribution.
+##
+## There is no warranty or other guarantee of fitness of this software.
+## It is provided solely "as is".  The author(s) disclaim(s) all
+## responsibility and liability with respect to this software's usage
+## or its effect upon hardware, computer systems, other software, or
+## anything else.
+##
+## Except where noted otherwise, rancid was written by and is maintained by
+## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz.
+##
+#
+# The original original lookingglass s/w was written by Ed Kern.  It was
+# a single script that used to be available at http://nitrous.digex.net/.
+# Provided by permission and modified beyond recognition.
+#
+# lgform.cgi - Looking glass front-end
+# produces html form for calling lg.cgi
+
+use CGI qw/:standard/;
+
+my(@rtrlist, %rtrlabels);
+my($BASEDIR) = "@prefix@";
+my($SYSCONFDIR) = "@sysconfdir@";
+
+# note: the following functions are duplicated between lgform.cgi and lg.cgi
+# to avoid the need for module inclusion headaches from within a httpd context.
+# it is just easier to be self-contained.
+# SO, ANY CHANGES HERE SHOULD BE REFLECTED IN THE OTHER .cgi.
+
+# logging
+sub dolog
+{
+    my($level, $msg) = @_;
+
+    if (defined($LG_LOG) && $LG_LOG !~ /\//) {
+	openlog($me, "pid", $LG_LOG);
+	syslog($level, "%s", $msg);
+	closelog;
+    } else {
+	local(*LOG);
+	my($file);
+	if (defined($LG_LOG)) {
+	    $file = $LG_LOG;
+	} else {
+	    $file = "$cache_dir/lg.log";
+	}
+	#  log date, hostname, query, addr
+	if (open(LOG, ">>$file") == 0) {
+	    # stderr, if all else fails
+	    printf(STDERR "[" . strftime("%a %b %e %H:%M:%S %Y", gmtime) .
+			"] could not open log file $file: $!\n");
+	    printf(STDERR $msg);
+	} else {
+	    printf(LOG $msg);
+	    close(LOG);
+	}
+    }
+    return;
+}
+
+# read LG configuration file
+sub readconf
+{
+    my($conffile, $cmds);
+    local(*CONF);
+    if (defined($ENV{LG_CONF})) {
+	$conffile = $ENV{LG_CONF};
+    } elsif (-e "lg.conf") {
+	$conffile = "lg.conf";
+    } else {
+	$conffile = "$SYSCONFDIR/lg.conf";
+    }
+
+    if (! -f $conffile) {
+	return;
+    }
+
+    if (open(CONF, "< $conffile")) {
+	while () {
+	    next if (/^\s*(#|$)/);
+	    $cmds .= $_;
+	}
+	close(CONF);
+	eval $cmds;
+    } else {
+	printf(STDERR "ERROR: couldn\'t open the configuration file: " .
+							"$conffile: $!\n");
+	exit(1);
+    }
+
+    return;
+}
+
+# read router.db file
+sub readrouters
+{
+    my($rtrdb);
+    local(*RTR);
+
+    if (defined($LG_ROUTERDB)) {
+	$rtrdb = $LG_ROUTERDB;
+    } else {
+	$rtrdb = "$SYSCONFDIR/router.db";
+    }
+
+    if (! -f $rtrdb) {
+	my(@dirs, $dir);
+	# if the router.db file does not exist, try to compile the list from
+	# the rancid group router.db files.
+	local(*DIR);
+	if (! opendir(DIR, $BASEDIR)) {
+	    dolog(LOG_ERR, "ERROR: couldn\'t read $BASEDIR: $!\n");
+	} else {
+	    while ($dir = readdir(DIR)) {
+		next if ($dir =~ /^(\.|\.\.|CVS|bin|etc|logs|util)$/);
+		push(@dirs, $dir) if (-d "$BASEDIR/$dir");
+	    }
+	    closedir(DIR);
+
+	    foreach $dir (@dirs) {
+		if (! opendir(DIR, "$BASEDIR/$dir")) {
+		    dolog(LOG_ERR, "ERROR: couldn\'t read $BASEDIR/$dir: $!\n");
+		    next;
+		}
+		closedir(DIR);
+		next if (! -f "$BASEDIR/$dir/router.db");
+		if (open(RTR, "< $BASEDIR/$dir/router.db")) {
+		    while () {
+			next if (/^\s*(#|$)/);
+			# fqdn:mfg:state
+			@record = split('\:', $_);
+			next if ($record[2] !~ /up/i || $record[1] !~ /(cisco|foundry|juniper)/);
+			push(@rtrlist, join(':', ($record[0], $record[1])));
+			$rtrlabels{join(':', ($record[0], $record[1]))} = $record[0];
+		    }
+		    close(RTR);
+		} else {
+		    dolog(LOG_ERR, "ERROR: couldn\'t open the router.db " .
+					"file: $BASEDIR/$dir/router.db: $!\n");
+		}
+	    }
+	}
+    } else {
+	if (open(RTR, "< $rtrdb")) {
+	    while () {
+		next if (/^\s*(#|$)/);
+		# fqdn:mfg:state
+		@record = split('\:', $_);
+		next if ($record[2] !~ /up/i || $record[1] !~ /(cisco|foundry|juniper)/);
+		push(@rtrlist, join(':', ($record[0], $record[1])));
+		$rtrlabels{join(':', ($record[0], $record[1]))} = $record[0];
+	    }
+	    close(RTR);
+	} else {
+	    dolog(LOG_ERR, "ERROR: couldn\'t open the router.db file: " .
+								"$rtrdb: $!\n");
+	    exit(1);
+	}
+    }
+
+    return;
+}
+
+# Main()
+# read the configuration file if it exists.
+readconf();
+
+$query = new CGI;
+
+print $query->header;
+if ($LG_STYLE) {
+    print $query->start_html(-title =>"LookingGlass form",
+						-style => {'src' => $LG_STYLE});
+} else {
+    print $query->start_html(-title =>"LookingGlass form");
+}
+
+# add the company image, LG_IMAGE
+print $LG_IMAGE;
+
+print <
+Looking Glass
+
+
+HEAD + +# start table, etc here +print $query->startform( -action => 'lg.cgi', -method => 'POST'); +print < + + +DOTABLE + +# available query types here +print < + + + + + +
Query:Router:
+TABLEHEAD + +foreach $sub_type (sort keys(%$queries)) { + next if (! scalar(%{$queries->{$sub_type}})); + print $query->radio_group (-name => 'query', + -values => $queries->{$sub_type}, + -default => '-', -linebreak => 'true'); + print "\n" . $query->hr . "\n"; +} + +print <Argument(s):

+
+QTYPES + +# read routers table and create the scrolling list +readrouters(); +print $query->scrolling_list(-name => 'router', + -values => \@rtrlist, + -size => 20, + -labels => \%rtrlabels); + +# end +print < +
+

+TABLEEND + +print $query->submit(-name => 'submit', -value =>'Submit'); +print $query->reset; +print $query->endform; + +print < +
+Looking Glass notes +

+$LG_INFO +TAIL + +print $query->end_html; + +exit(0); diff --git a/bin/mrancid.in b/bin/mrancid.in old mode 100755 new mode 100644 index 8054917..8d52c27 --- a/bin/mrancid.in +++ b/bin/mrancid.in @@ -1,29 +1,33 @@ -#!@PERLV_PATH@ +#! @PERLV_PATH@ ## -## Amazingly hacked version of Hank's rancid - this one tries to -## deal with MRTd. +## $Id: mrancid.in,v 1.11 2004/01/11 03:49:13 heas Exp $ ## -## Copyright (C) 1997-2001 by Henry Kilmer. +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. ## All rights reserved. ## -## This software may be freely copied, modified and redistributed without -## fee for non-commerical purposes provided that this copyright notice is -## preserved intact on all copies and modified copies. +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. ## ## There is no warranty or other guarantee of fitness of this software. -## It is provided solely "as is". The author(s) disclaim(s) all +## It is provided solely "as is". The author(s) disclaim(s) all ## responsibility and liability with respect to this software's usage ## or its effect upon hardware, computer systems, other software, or ## anything else. ## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. ## # +# Amazingly hacked version of Hank's rancid - this one tries to +# deal with MRTd. +# # RANCID - Really Awesome New Cisco confIg Differ # # usage: rancid [-d] [-l] [-f filename | $host] # use Getopt::Std; -getopts('dflm'); +getopts('dfl'); $log = $opt_l; $debug = $opt_d; $file = $opt_f; @@ -355,8 +359,12 @@ TOP: while() { } while (/#\s*($cmds_regexp)\s*$/) { $cmd = $1; - if (!defined($prompt)) {$prompt = ($_ =~ /^([^#]+)/)[0]; - $prompt .= "[#>]"; } + if (!defined($prompt)) { + $prompt = ($_ =~ /^([^#]+)/)[0]; + $prompt =~ s/([][}{)(\\])/\\$1/g; + $prompt .= "[#>]"; + print STDERR ("PROMPT MATCH: $prompt\n") if ($debug); + } print STDERR ("HIT COMMAND:$_") if ($debug); if (! defined($commands{$cmd})) { print STDERR "$host: found unexpected command - \"$cmd\"\n"; diff --git a/bin/nlogin.in b/bin/nlogin.in new file mode 100644 index 0000000..685c759 --- /dev/null +++ b/bin/nlogin.in @@ -0,0 +1,524 @@ +#! @EXPECT_PATH@ -- +## +## $Id: nlogin.in,v 1.14 2004/01/11 05:39:15 heas Exp $ +## +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## All rights reserved. +## +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. +## +## There is no warranty or other guarantee of fitness of this software. +## It is provided solely "as is". The author(s) disclaim(s) all +## responsibility and liability with respect to this software's usage +## or its effect upon hardware, computer systems, other software, or +## anything else. +## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. +## +# +# The login expect scripts were based on Erik Sherk's gwtn, by permission. +# +# nlogin - netscreen login +# +# Most options are intuitive for logging into a netscreen firewall. +# + +# Usage line +set usage "Usage: $argv0 \[-c command\] \[-Evar=x\] \[-f cloginrc-file\] +\[-s script-file\] \[-t timeout\] \[-u user\] \ +\[-p user-password\] \[-y ssh_cypher_type\] firewall \[firewall...\]\n" + +# env(CLOGIN) may contain: +# x == do not set xterm banner or name + +# Password file +set password_file $env(HOME)/.cloginrc +# Default is to login to the firewall +set do_command 0 +set do_script 0 +# The default is to automatically enable +set enable 0 +# The default is that you login non-enabled (tacacs can have you login already +# enabled) +set avautoenable 1 +# The default is to look in the password file to find the passwords. This +# tracks if we receive them on the command line. +set do_passwd 1 +set do_enapasswd 1 + +# Find the user in the ENV, or use the unix userid. +if {[ info exists env(CISCO_USER) ] } { + set default_user $env(CISCO_USER) +} elseif {[ info exists env(USER) ]} { + set default_user $env(USER) +} elseif {[ info exists env(LOGNAME) ]} { + set default_user $env(LOGNAME) +} else { + # This uses "id" which I think is portable. At least it has existed + # (without options) on all machines/OSes I've been on recently - + # unlike whoami or id -nu. + if [ catch {exec id} reason ] { + send_error "\nError: could not exec id: $reason\n" + exit 1 + } + regexp {\(([^)]*)} "$reason" junk default_user +} + +# Sometimes firewall take awhile to answer (the default is 10 sec) +set timeout 45 + +# Process the command line +for {set i 0} {$i < $argc} {incr i} { + set arg [lindex $argv $i] + + switch -glob -- $arg { + # Username + -u* - + -U* { + if {! [ regexp .\[uU\](.+) $arg ignore user]} { + incr i + set username [ lindex $argv $i ] + } + # VTY Password + } -p* - + -P* { + if {! [ regexp .\[pP\](.+) $arg ignore userpasswd]} { + incr i + set userpasswd [ lindex $argv $i ] + } + set do_passwd 0 + # Environment variable to pass to -s scripts + } -E* + { + if {[ regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} { + set E$varname $varvalue + } else { + send_user "\nError: invalid format for -E in $arg\n" + exit 1 + } + # Command to run. + } -c* - + -C* { + if {! [ regexp .\[cC\](.+) $arg ignore command]} { + incr i + set command [ lindex $argv $i ] + } + set do_command 1 + # Expect script to run. + } -s* - + -S* { + if {! [ regexp .\[sS\](.+) $arg ignore sfile]} { + incr i + set sfile [ lindex $argv $i ] + } + if { ! [ file readable $sfile ] } { + send_user "\nError: Can't read $sfile\n" + exit 1 + } + set do_script 1 + # cypher type + } -y* - + -Y* { + if {! [ regexp .\[eE\](.+) $arg ignore cypher]} { + incr i + set cypher [ lindex $argv $i ] + } + # alternate cloginrc file + } -f* - + -F* { + if {! [ regexp .\[fF\](.+) $arg ignore password_file]} { + incr i + set password_file [ lindex $argv $i ] + } + } -t* - + -T* { + incr i + set timeout [ lindex $argv $i ] + } -x* - + -X { + if {! [ regexp .\[xX\](.+) $arg ignore cmd_file]} { + incr i + set cmd_file [ lindex $argv $i ] + } + if [ catch {set cmd_fd [open $cmd_file r]} reason ] { + send_user "\nError: $reason\n" + exit 1 + } + set cmd_text [read $cmd_fd] + close $cmd_fd + set command [join [split $cmd_text \n] \;] + set do_command 1 + # Does tacacs automatically enable us? + } -autoenable { + # ignore autoenable + #set avautoenable 1 + } -* { + send_user "\nError: Unknown argument! $arg\n" + send_user $usage + exit 1 + } default { + break + } + } +} +# Process firewalls...no firewalls listed is an error. +if { $i == $argc } { + send_user "\nError: $usage" +} + +# Only be quiet if we are running a script (it can log its output +# on its own) +if { $do_script } { + log_user 0 +} else { + log_user 1 +} + +# +# Done configuration/variable setting. Now run with it... +# + +# Sets Xterm title if interactive...if its an xterm and the user cares +proc label { host } { + global env + # if CLOGIN has an 'x' in it, don't set the xterm name/banner + if [info exists env(CLOGIN)] { + if {[string first "x" $env(CLOGIN)] != -1} { return } + } + # take host from ENV(TERM) + if [info exists env(TERM)] { + if [regexp \^(xterm|vs) $env(TERM) ignore ] { + send_user "\033]1;[lindex [split $host "."] 0]\a" + send_user "\033]2;$host\a" + } + } +} + +# This is a helper function to make the password file easier to +# maintain. Using this the password file has the form: +# add password sl* pete cow +# add password at* steve +# add password * hanky-pie +proc add {var args} { global int_$var ; lappend int_$var $args} +proc include {args} { + global env + regsub -all "(^{|}$)" $args {} args + if { [ regexp "^/" $args ignore ] == 0 } { + set args $env(HOME)/$args + } + source_password_file $args +} + +proc find {var firewall} { + upvar int_$var list + if { [info exists list] } { + foreach line $list { + if { [string match [lindex $line 0] $firewall ] } { + return [lrange $line 1 end] + } + } + } + return {} +} + +# Loads the password file. Note that as this file is tcl, and that +# it is sourced, the user better know what to put in there, as it +# could install more than just password info... I will assume however, +# that a "bad guy" could just as easy put such code in the clogin +# script, so I will leave .cloginrc as just an extention of that script +proc source_password_file { password_file } { + global env + if { ! [file exists $password_file] } { + send_user "\nError: password file ($password_file) does not exist\n" + exit 1 + } + file stat $password_file fileinfo + if { [expr ($fileinfo(mode) & 007)] != 0000 } { + send_user "\nError: $password_file must not be world readable/writable\n" + exit 1 + } + if [ catch {source $password_file} reason ] { + send_user "\nError: $reason\n" + exit 1 + } +} + +# Log into the firewall. +proc login { firewall user userpswd passwd enapasswd prompt cmethod +cyphertype } { + global spawn_id in_proc do_command do_script sshcmd + set in_proc 1 + set uprompt_seen 0 + + # Telnet to the firewall & try to login. + set progs [llength $cmethod] + foreach prog [lrange $cmethod 0 end] { + if [string match "telnet*" $prog] { + regexp {telnet(:([^[:space:]]+))*} $prog command suffix port + if {"$port" == ""} { + set retval [ catch {spawn telnet $firewall} reason ] + } else { + set retval [ catch {spawn telnet $firewall $port} reason ] + } + if { $retval } { + send_user "\nError: telnet failed: $reason\n" + exit 1 + } + } elseif ![string compare $prog "ssh"] { + if [ catch {spawn $sshcmd -c $cyphertype -x -l $user $firewall} reason ] { + send_user "\nError: $sshcmd failed: $reason\n" + exit 1 + } + } elseif ![string compare $prog "rsh"] { + if [ catch {spawn rsh -l $user $firewall} reason ] { + send_user "\nError: rsh failed: $reason\n" + exit 1 + } + } else { + puts "\nError: unknown connection method: $prog" + return 1 + } + incr progs -1 + + sleep 0.3 + + # This helps cleanup each expect clause. + expect_after { + timeout { + send_user "\nError: TIMEOUT reached\n" + catch {close}; wait + if { $in_proc} { + return 1 + } else { + continue + } + } eof { + send_user "\nError: EOF received\n" + catch {close}; wait + if { $in_proc} { + return 1 + } else { + continue + } + } + } + + # Here we get a little tricky. There are several possibilities: + # the firewall can ask for a username and passwd and then + # talk to the TACACS server to authenticate you, or if the + # TACACS server is not working, then it will use the enable + # passwd. Or, the firewall might not have TACACS turned on, + # then it will just send the passwd. + # if telnet fails with connection refused, try ssh + expect { + "Connection refused" { + send_user "\nError: Connection Refused\n"; wait; return 1 + } eof { send_user "\nError: Couldn't login\n"; wait; return 1 + } "Unknown host\r\n" { + expect eof + send_user "\nError: Unknown host\n"; wait; return 1 + } "Host is unreachable" { + expect eof + send_user "\nError: Host Unreachable!\n"; wait; return 1 + } "No address associated with name" { + expect eof + send_user "\nError: Unknown host\n"; wait; return 1 + } + -re "Are you sure you want to continue connecting .*" { + send "yes\r" + send_user "Host $firewall added to the list of known hosts.\n" + exp_continue } + -re "Host key not found .* \(yes\/no\)\?" { + send "yes\r" + send_user "Host $firewall added to the list of known hosts.\n" + exp_continue } + -re "HOST IDENTIFICATION HAS CHANGED.* \(yes\/no\)\?" { + send "no\r" + send_user "\nError: The host key for $firewall has changed. Update the SSH known_hosts file accordingly.\n" + return 1 } + -re "Offending key for .* \(yes\/no\)\?" { + send "no\r" + send_user "\nError: host key mismatch for $firewall. Update the SSH known_hosts file accordingly.\n" + return 1 } + denied { send_user "\nError: Check your passwd for $firewall\n" + catch {close}; wait; return 1 + } + " ### Login failed" {send_user "\nError: Check your passwd for $firewall\n"; return 1 } + -re "(login:)" { + sleep 1; + send "$user\r" + set uprompt_seen 1 + exp_continue + } + "@\[^\r\n]+\[Pp]assword:" { + # ssh pwd prompt + sleep 1 + send "$userpswd\r" + exp_continue + } + "\[Pp]assword:" { + sleep 1; + if {$uprompt_seen == 1} { + send "$userpswd\r" + } else { + send "$passwd\r" + } + exp_continue + } + "$prompt" { break; } + } + } + set in_proc 0 + return 0 +} + +# Run commands given on the command line. +proc run_commands { prompt command } { + global in_proc + set in_proc 1 + + send "set console page 0\r" + expect $prompt {} + + # Is this a multi-command? + if [ string match "*\;*" "$command" ] { + set commands [split $command \;] + set num_commands [llength $commands] + + for {set i 0} {$i < $num_commands} { incr i} { + send "[subst [lindex $commands $i]]\r" + expect { + -re "$prompt" {} + } + } + } else { + send "[subst $command]\r" + expect { + -re "$prompt" {} + } + } + send "exit\r" + expect { + "\n" { exp_continue } + -re "$prompt" { + send "exit\r" + exp_continue } + -re "Configuration modified, save?" { + send "n\r" + exp_continue } + timeout { return 0 } + eof { return 0 } + } + set in_proc 0 +} + +# +# For each firewall... (this is main loop) +# +source_password_file $password_file +set in_proc 0 +foreach firewall [lrange $argv $i end] { + set firewall [string tolower $firewall] + send_user "$firewall\n" + + set prompt ">" + + # Figure out passwords + if { $do_passwd || $do_enapasswd } { + set pswd [find password $firewall] + if { [llength $pswd] == 0 } { + send_user "\nError: no password for $firewall in $password_file.\n" + continue + } + set passwd [join [lindex $pswd 0]""] + set enapasswd [join [lindex $pswd 1] ""] + } + + # Figure out username + if {[info exists username]} { + # command line username + set ruser $username + } else { + set ruser [join [find user $firewall] ""] + if { "$ruser" == "" } { set ruser $default_user } + } + + # Figure out username's password (if different from the vty password) + if {[info exists userpasswd]} { + # command line username + set userpswd $userpasswd + } else { + set userpswd [join [find userpassword $firewall] ""] + if { "$userpswd" == "" } { set userpswd $passwd } + } + + # Figure out enable username + if {[info exists enausername]} { + # command line enausername + set enauser $enausername + } else { + set enauser [join [find enauser $firewall] ""] + if { "$enauser" == "" } { set enauser $ruser } + } + + # Figure out cypher type + if {[info exists cypher]} { + # command line cypher type + set cyphertype $cypher + } else { + set cyphertype [find cyphertype $firewall] + if { "$cyphertype" == "" } { set cyphertype "3des" } + } + + # Figure out connection method + set cmethod [find method $firewall] + if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} } + + # Figure out the SSH executable name + set sshcmd [find sshcmd $router] + if { "$sshcmd" == "" } { set sshcmd {ssh} } + + # Login to the firewall + if {[login $firewall $ruser $userpswd $passwd $enapasswd $prompt $cmethod $cyphertype]} { + continue + } + if { $enable } { + if {[do_enable $enauser $enapasswd]} { + if { $do_command || $do_script } { + close; wait + continue + } + } + } + # we are logged in, now figure out the full prompt + send "\r" + expect { + -re "\[\r\n]+" { exp_continue; } + -re "^.+$prompt" { set junk $expect_out(0,string); + regsub -all "\[\]\(\)\[]" $junk {\\&} prompt; + } + } + + if { $do_command } { + if {[run_commands $prompt $command]} { + continue + } + } elseif { $do_script } { + send "set console page 0\r" + expect $prompt {} + source $sfile + close + } else { + label $firewall + log_user 1 + interact + } + + # End of for each firewall + wait + sleep 0.3 +} +exit 0 diff --git a/bin/nrancid.in b/bin/nrancid.in new file mode 100644 index 0000000..9b965a2 --- /dev/null +++ b/bin/nrancid.in @@ -0,0 +1,302 @@ +#! @PERLV_PATH@ +## +## $Id: nrancid.in,v 1.13 2004/01/11 03:49:13 heas Exp $ +## +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## All rights reserved. +## +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. +## +## There is no warranty or other guarantee of fitness of this software. +## It is provided solely "as is". The author(s) disclaim(s) all +## responsibility and liability with respect to this software's usage +## or its effect upon hardware, computer systems, other software, or +## anything else. +## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. +## +# +# Amazingly hacked version of Hank's rancid - this one tries to +# deal with Netscreen firewalls +# +# Original Netscreen hacks implemented by Stephen Gill [gillsr@yahoo.com] +# +# RANCID - Really Awesome New Cisco confIg Differ +# +# usage: rancid [-d] [-l] [-f filename | $host] +# +use Getopt::Std; +getopts('dfl'); +$log = $opt_l; +$debug = $opt_d; +$file = $opt_f; +$host = $ARGV[0]; +$found_end = 0; +$timeo = 90; # nlogin timeout in seconds + +my(%filter_pwds); # password filtering mode + +# This routine is used to print out the firewall configuration +sub ProcessHistory { + my($new_hist_tag,$new_command,$command_string,@string)=(@_); + if((($new_hist_tag ne $hist_tag) || ($new_command ne $command)) + && defined %history) { + print eval "$command \%history"; + undef %history; + } + if (($new_hist_tag) && ($new_command) && ($command_string)) { + if ($history{$command_string}) { + $history{$command_string} = "$history{$command_string}@string"; + } else { + $history{$command_string} = "@string"; + } + } elsif (($new_hist_tag) && ($new_command)) { + $history{++$#history} = "@string"; + } else { + print "@string"; + } + $hist_tag = $new_hist_tag; + $command = $new_command; + 1; +} + +sub numerically { $a <=> $b; } + +# This is a sort routing that will sort numerically on the +# keys of a hash as if it were a normal array. +sub keynsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort numerically keys(%lines)) { + $sorted_lines[$i] = $lines{$key}; + $i++; + } + @sorted_lines; +} + +# This is a sort routing that will sort on the +# keys of a hash as if it were a normal array. +sub keysort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort keys(%lines)) { + $sorted_lines[$i] = $lines{$key}; + $i++; + } + @sorted_lines; +} + +# This is a sort routing that will sort on the +# values of a hash as if it were a normal array. +sub valsort{ + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort values %lines) { + $sorted_lines[$i] = $key; + $i++; + } + @sorted_lines; +} + +# This is a numerical sort routing (ascending). +sub numsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $num (sort {$a <=> $b} keys %lines) { + $sorted_lines[$i] = $lines{$num}; + $i++; + } + @sorted_lines; +} + +# This is a sort routine that will sort on the +# ip address when the ip address is anywhere in +# the strings. +sub ipsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $addr (sort sortbyipaddr keys %lines) { + $sorted_lines[$i] = $lines{$addr}; + $i++; + } + @sorted_lines; +} + +# These two routines will sort based upon IP addresses +sub ipaddrval { + my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#); + $a[3]+256*($a[2]+256*($a[1]+256*$a[0])); +} +sub sortbyipaddr { + &ipaddrval($a) <=> &ipaddrval($b); +} + +# This routine parses "get system" +sub GetSystem { + print STDERR " In GetSystem: $_" if ($debug); + + while () { + tr/\015//d; + next if /^\s*$/; + last if(/$prompt/); + + /^Serial Number: (\d+), Control Number: \d+$/ && + ProcessHistory("SYSTEM","","", "!SN: $1\n") && next; + /^Product Name: (\S+)$/ && + ProcessHistory("SYSTEM","","", "!Product: $1\n") && next; + /^Hardware Version: (\S+), / && + ProcessHistory("SYSTEM","","", "!HW: $1\n") && next; + /^Software Version: (\S+), Type: (\S+)$/ && + ProcessHistory("SYSTEM","","", "!Netscreen Type: $2\n!Software Version: $1\n") && next; + /^Image: (\S+), / && + ProcessHistory("SYSTEM","","", "!Image: $1\n") && next; + /^Feature: (\S+)$/ && + ProcessHistory("SYSTEM","","", "!Feature: $1\n") && next; + /^File Name: (\S+), Checksum: (\S+)$/ && + ProcessHistory("SYSTEM","","", "!File Name: $1, Checksum: $2\n") && next; + + } + ProcessHistory("SYSTEM","","","!\n"); + return(0); +} + +sub GetFile { + print STDERR " In GetFile: $_" if ($debug); + while () { + last if(/$prompt/); + } + ProcessHistory("FILE","","","!\n"); + return(0); +} + +sub GetConf { + print STDERR " In GetConf: $_" if ($debug); + while () { + tr/\015//d; + next if /^\s*$/; + last if(/$prompt/); + + if (/^set admin name "(\S+)"$/ && $filter_pwds >= 1) { + ProcessHistory("ADMIN","","","!set admin name \n"); + next; + } + if (/^set admin password (\S+)$/ && $filter_pwds >= 1) { + ProcessHistory("ADMIN","","","!set admin password \n"); + next; + } + if (/^set admin user (\S+) password (\S+) privilege (\S+)$/ && + $filter_pwds >= 1) { + ProcessHistory("ADMIN","","", + "!set admin user $1 password privilege $3\n"); + next; + ProcessHistory("","","","$_"); + } + $found_end=1; + return(1); +} + +# dummy function +sub DoNothing {print STDOUT;} + +# Main +%commands=( + 'get system' => "GetSystem", + 'get conf' => "GetConf" +); +# keys() doesnt return things in the order entered and the order of the +# cmds is important. pita +@commands=( + "get system", + "get conf" +); +$cisco_cmds=join(";",@commands); +$cmds_regexp=join("|",@commands); + +open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; +select(OUTPUT); +# make OUTPUT unbuffered if debugging +if ($debug) { $| = 1; } + +if ($file) { + print STDERR "opening file $host\n" if ($debug); + print STDOUT "opening file $host\n" if ($log); + open(INPUT,"<$host") || die "open failed for $host: $!\n"; +} else { + print STDERR "executing nlogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($debug); + print STDOUT "executing nlogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($log); + if (defined($ENV{NOPIPE})) { + system "nlogin -t $timeo -c \"$cisco_cmds\" $host $host.raw 2>&1" || die "nlogin failed for $host: $!\n"; + open(INPUT, "< $host.raw") || die "nlogin failed for $host: $!\n"; + } else { + open(INPUT,"nlogin -t $timeo -c \"$cisco_cmds\" $host ) { + tr/\015//d; + if (/^Error:/) { + print STDOUT ("$host nlogin error: $_"); + print STDERR ("$host nlogin error: $_") if ($debug); + last; + } + while (/>\s*($cmds_regexp)\s*$/) { + $cmd = $1; + if (!defined($prompt)) { + $prompt = "\-\>\s*"; + print STDERR ("PROMPT MATCH: $prompt\n") if ($debug); + } + print STDERR ("HIT COMMAND:$_") if ($debug); + if (!defined($commands{$cmd})) { + print STDERR "$host: found unexpected command - \"$cmd\"\n"; + last TOP; + } + $rval = &{$commands{$cmd}}; + delete($commands{$cmd}); + if ($rval == -1) { + last TOP; + } + } +} +print STDOUT "Done $logincmd: $_\n" if ($log); +# Flush History +ProcessHistory("","","",""); +# Cleanup +close(INPUT); +close(OUTPUT); + +if (defined($ENV{NOPIPE})) { + unlink("$host.raw") if (! $debug); +} + +# check for completeness +if (scalar(%commands) || !$found_end) { + if (scalar(%commands)) { + printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands))); + printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug); + } + if (!$found_end) { + print STDOUT "$found_end: found end\n"; + print STDOUT "$host: End of run not found\n"; + print STDERR "$host: End of run not found\n" if ($debug); + system("/usr/bin/tail -1 $host.new"); + } + unlink "$host.new" if (! $debug); +} diff --git a/bin/nslogin.in b/bin/nslogin.in new file mode 100644 index 0000000..385f530 --- /dev/null +++ b/bin/nslogin.in @@ -0,0 +1,642 @@ +#! @EXPECT_PATH@ -- +## +## $Id: nslogin.in,v 1.10 2004/01/11 05:39:15 heas Exp $ +## +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## All rights reserved. +## +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. +## +## There is no warranty or other guarantee of fitness of this software. +## It is provided solely "as is". The author(s) disclaim(s) all +## responsibility and liability with respect to this software's usage +## or its effect upon hardware, computer systems, other software, or +## anything else. +## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. +## +# +# The login expect scripts were based on Erik Sherk's gwtn, by permission. +# +# nslogin - Netscaler login +# +# Hacks from Anshuman Kanwar. +# +# Most options are intuitive for logging into a Cisco router. +# The default is to enable (thus -noenable). Some folks have +# setup tacacs to have a user login at priv-lvl = 15 (enabled) +# so the -autoenable flag was added for this case (don't go through +# the process of enabling and the prompt will be the "#" prompt. +# The default username password is the same as the vty password. +# + +# Usage line +set usage "Usage: $argv0 \[-autoenable\] \[-noenable\] \[-c command\] \ +\[-Evar=x\] \[-e enable-password\] \[-f cloginrc-file\] \[-p user-password\] \ +\[-s script-file\] \[-t timeout\] \[-u username\] \ +\[-v vty-password\] \[-w enable-username\] \[-x command-file\] \ +\[-y ssh_cypher_type\] router \[router...\]\n" + +# env(CLOGIN) may contain: +# x == do not set xterm banner or name + +# Password file +set password_file $env(HOME)/.cloginrc +# Default is to login to the router +set do_command 1 +set do_script 0 +# The default is to automatically enable +set enable 0 +# The default is that you login non-enabled (tacacs can have you login already +# enabled) +set avautoenable 0 +# The default is to look in the password file to find the passwords. This +# tracks if we receive them on the command line. +set do_passwd 1 +set do_enapasswd 1 +# attempt at platform switching. +set platform "" + +# Find the user in the ENV, or use the unix userid. +if {[ info exists env(CISCO_USER) ] } { + set default_user $env(CISCO_USER) +} elseif {[ info exists env(USER) ]} { + set default_user $env(USER) +} elseif {[ info exists env(LOGNAME) ]} { + set default_user $env(LOGNAME) +} else { + # This uses "id" which I think is portable. At least it has existed + # (without options) on all machines/OSes I've been on recently - + # unlike whoami or id -nu. + if [ catch {exec id} reason ] { + send_error "\nError: could not exec id: $reason\n" + exit 1 + } + regexp {\(([^)]*)} "$reason" junk default_user +} + +# Sometimes routers take awhile to answer (the default is 10 sec) +set timeout 45 + +# Process the command line +for {set i 0} {$i < $argc} {incr i} { + set arg [lindex $argv $i] + + switch -glob -- $arg { + # Username + -u* - + -U* { + if {! [ regexp .\[uU\](.+) $arg ignore user]} { + incr i + set username [ lindex $argv $i ] + } + # VTY Password + } -p* - + -P* { + if {! [ regexp .\[pP\](.+) $arg ignore userpasswd]} { + incr i + set userpasswd [ lindex $argv $i ] + } + set do_passwd 0 + # VTY Password + } -v* - + -v* { + if {! [ regexp .\[vV\](.+) $arg ignore passwd]} { + incr i + set passwd [ lindex $argv $i ] + } + set do_passwd 0 + # Enable Username + } -w* - + -W* { + if {! [ regexp .\[wW\](.+) $arg ignore enauser]} { + incr i + set enausername [ lindex $argv $i ] + } + # Environment variable to pass to -s scripts + } -E* + { + if {[ regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} { + set E$varname $varvalue + } else { + send_user "\nError: invalid format for -E in $arg\n" + exit 1 + } + # Enable Password + } -e* + { + if {! [ regexp .\[e\](.+) $arg ignore enapasswd]} { + incr i + set enapasswd [ lindex $argv $i ] + } + set do_enapasswd 0 + # Command to run. + } -c* - + -C* { + if {! [ regexp .\[cC\](.+) $arg ignore command]} { + incr i + set command [ lindex $argv $i ] + } + set do_command 1 + # Expect script to run. + } -s* - + -S* { + if {! [ regexp .\[sS\](.+) $arg ignore sfile]} { + incr i + set sfile [ lindex $argv $i ] + } + if { ! [ file readable $sfile ] } { + send_user "\nError: Can't read $sfile\n" + exit 1 + } + set do_script 1 + # 'ssh -c' cypher type + } -y* - + -Y* { + if {! [ regexp .\[eE\](.+) $arg ignore cypher]} { + incr i + set cypher [ lindex $argv $i ] + } + # alternate cloginrc file + } -f* - + -F* { + if {! [ regexp .\[fF\](.+) $arg ignore password_file]} { + incr i + set password_file [ lindex $argv $i ] + } + # Timeout + } -t* - + -T* { + if {! [ regexp .\[tT\](.+) $arg ignore timeout]} { + incr i + set timeout [ lindex $argv $i ] + } + # Command file + } -x* - + -X { + if {! [ regexp .\[xX\](.+) $arg ignore cmd_file]} { + incr i + set cmd_file [ lindex $argv $i ] + } + if [ catch {set cmd_fd [open $cmd_file r]} reason ] { + send_user "\nError: $reason\n" + exit 1 + } + set cmd_text [read $cmd_fd] + close $cmd_fd + set command [join [split $cmd_text \n] \;] + set do_command 1 + # Do we enable? + } -noenable { + set enable 0 + # Does tacacs automatically enable us? + } -autoenable { + set avautoenable 1 + set enable 0 + } -* { + send_user "\nError: Unknown argument! $arg\n" + send_user $usage + exit 1 + } default { + break + } + } +} +# Process routers...no routers listed is an error. +if { $i == $argc } { + send_user "\nError: $usage" +} + +# Only be quiet if we are running a script (it can log its output +# on its own) +if { $do_script } { + log_user 0 +} else { + log_user 1 +} + +# +# Done configuration/variable setting. Now run with it... +# + +# Sets Xterm title if interactive...if its an xterm and the user cares +proc label { host } { + global env + # if CLOGIN has an 'x' in it, don't set the xterm name/banner + if [info exists env(CLOGIN)] { + if {[string first "x" $env(CLOGIN)] != -1} { return } + } + # take host from ENV(TERM) + if [info exists env(TERM)] { + if [regexp \^(xterm|vs) $env(TERM) ignore ] { + send_user "\033]1;[lindex [split $host "."] 0]\a" + send_user "\033]2;$host\a" + } + } +} + +# This is a helper function to make the password file easier to +# maintain. Using this the password file has the form: +# add password sl* pete cow +# add password at* steve +# add password * hanky-pie +proc add {var args} { global int_$var ; lappend int_$var $args} +proc include {args} { + global env + regsub -all "(^{|}$)" $args {} args + if { [ regexp "^/" $args ignore ] == 0 } { + set args $env(HOME)/$args + } + source_password_file $args +} + +proc find {var router} { + upvar int_$var list + if { [info exists list] } { + foreach line $list { + if { [string match [lindex $line 0] $router ] } { + return [lrange $line 1 end] + } + } + } + return {} +} + +# Loads the password file. Note that as this file is tcl, and that +# it is sourced, the user better know what to put in there, as it +# could install more than just password info... I will assume however, +# that a "bad guy" could just as easy put such code in the clogin +# script, so I will leave .cloginrc as just an extention of that script +proc source_password_file { password_file } { + global env + if { ! [file exists $password_file] } { + send_user "\nError: password file ($password_file) does not exist\n" + exit 1 + } + file stat $password_file fileinfo + if { [expr ($fileinfo(mode) & 007)] != 0000 } { + send_user "\nError: $password_file must not be world readable/writable\n" + exit 1 + } + if [ catch {source $password_file} reason ] { + send_user "\nError: $reason\n" + exit 1 + } +} + +# Log into the router. +proc login { router user userpswd passwd enapasswd cmethod cyphertype } { + global spawn_id in_proc do_command do_script platform + global prompt u_prompt p_prompt e_prompt sshcmd + set in_proc 1 + set uprompt_seen 0 + + # try each of the connection methods in $cmethod until one is successful + set progs [llength $cmethod] + foreach prog [lrange $cmethod 0 end] { + if ![string compare $prog "ssh"] { + if [ catch {spawn $sshcmd -c $cyphertype -x -l $user $router} reason ] { + send_user "\nError: $sshcmd failed: $reason\n" + exit 1 + } + } else { + puts "\nError: unknown connection method: $prog" + return 1 + } + incr progs -1 + sleep 0.3 + + # This helps cleanup each expect clause. + expect_after { + timeout { + send_user "\nError: TIMEOUT reached\n" + catch {close}; wait + if { $in_proc} { + return 1 + } else { + continue + } + } eof { + send_user "\nError: EOF received\n" + catch {close}; wait + if { $in_proc} { + return 1 + } else { + continue + } + } + } + + # Here we get a little tricky. There are several possibilities: + # the router can ask for a username and passwd and then + # talk to the TACACS server to authenticate you, or if the + # TACACS server is not working, then it will use the enable + # passwd. Or, the router might not have TACACS turned on, + # then it will just send the passwd. + # if telnet fails with connection refused, try ssh + expect { + -re "(Connection refused|Secure connection \[^\n\r]+ refused|Connection closed by)" { + catch {close}; wait + if !$progs { + send_user "\nError: Connection Refused ($prog)\n"; return 1 + } + } + eof { send_user "\nError: Couldn't login\n"; wait; return 1 } + -nocase "unknown host\r" { + catch {close}; + send_user "\nError: Unknown host\n"; wait; return 1 + } + "Host is unreachable" { + catch {close}; + send_user "\nError: Host Unreachable!\n"; wait; return 1 + } + "No address associated with name" { + catch {close}; + send_user "\nError: Unknown host\n"; wait; return 1 + } + -re "(Host key not found |The authenticity of host .* be established).*\(yes\/no\)\?" { + send "yes\r" + send_user "\nHost $router added to the list of known hosts.\n" + exp_continue } + -re "HOST IDENTIFICATION HAS CHANGED.* \(yes\/no\)\?" { + send "no\r" + send_user "\nError: The host key for $router has changed. Update the SSH known_hosts file accordingly.\n" + return 1 } + -re "Offending key for .* \(yes\/no\)\?" { + send "no\r" + send_user "\nError: host key mismatch for $router. Update the SSH known_hosts file accordingly.\n" + return 1 } + -re "(denied|Sorry)" { + send_user "\nError: Check your passwd for $router\n" + catch {close}; wait; return 1 + } + "Login failed" { + send_user "\nError: Check your passwd for $router\n" + return 1 + } + -re "% (Bad passwords|Authentication failed)" { + send_user "\nError: Check your passwd for $router\n" + return 1 + } + -re "@\[^\r\n]+ $p_prompt" { + # ssh pwd prompt + sleep 1 + send "$userpswd\r" + exp_continue + } + + "$prompt" { break; } + "Login invalid" { + send_user "\nError: Invalid login\n"; + catch {close}; wait; return 1 + } + } + } + + set in_proc 0 + return 0 +} + + +# Run commands given on the command line. + +proc run_commands { prompt command } { + global in_proc platform + set in_proc 1 + + regsub -all "\[)(]" $prompt {\\&} reprompt + # this is the only way i see to get rid of more prompts in o/p..grrrrr + log_user 0 + # Is this a multi-command? + if [ string match "*\;*" "$command" ] { + set commands [split $command \;] + set num_commands [llength $commands] + # the pager can not be turned off on the PIX, so we have to look + # for the "More" prompt. the extreme is equally obnoxious, with a + # global switch in the config. + for {set i 0} {$i < $num_commands} { incr i} { + send "[subst -nocommands [lindex $commands $i]]\r" + expect { + -re "\b+" { exp_continue } + -re "^\[^\n\r *]*$reprompt" { send_user -- "$expect_out(buffer)" + } + -re "^\[^\n\r]*$reprompt." { send_user -- "$expect_out(buffer)" + exp_continue } + -re "\[\n\r]+" { send_user -- "$expect_out(buffer)" + exp_continue } + -re "\[^\r\n]*Press to cont\[^\r\n]*" { + send " " + # bloody ^[[2K after " " + expect { + -re "^\[^\r\n]*\r" {} + } + exp_continue + } + -re "^ --More--\[^\n\r]*" { + send " " + exp_continue } + -re "^<-+ More -+>\[^\n\r]*" { + send_user -- "$expect_out(buffer)" + send " " + exp_continue } + } + } + } else { + # the pager can not be turned off on the PIX, so we have to look + # for the "More" prompt. the extreme is equally obnoxious, with a + # global switch in the config. + send "[subst -nocommands $command]\r" + expect { + -re "\b+" { exp_continue } + -re "^\[^\n\r *]*$reprompt" { send_user -- "$expect_out(buffer)" + } + -re "^\[^\n\r]*$reprompt." { send_user -- "$expect_out(buffer)" + exp_continue } + -re "\[\n\r]+" { send_user -- "$expect_out(buffer)" + exp_continue } + -re "\[^\r\n]*Press to cont\[^\r\n]*" { + send " " + # bloody ^[[2K after " " + expect { + -re "^\[^\r\n]*\r" {} + } + exp_continue + } + -re "^ --More--\[^\n\r]*" { + send " " + exp_continue } + -re "^<-+ More -+>\[^\n\r]*" { + send_user -- "$expect_out(buffer)" + send " " + exp_continue } + } + } + log_user 1 + + if { [ string compare "extreme" "$platform" ] } { + send "exit\r" + } else { + send "quit\r" + } + expect { + "Do you wish to save your configuration changes" { + send "n\r" + exp_continue + } + "\n" { exp_continue } + timeout { return 0 } + eof { return 0 } + } + set in_proc 0 +} + + + +# +# For each router... (this is main loop) +# +source_password_file $password_file +set in_proc 0 +foreach router [lrange $argv $i end] { + set router [string tolower $router] + send_user "$router\n" + + # Figure out prompt. + set prompt "#" + + # look for noenable option in .cloginrc + if { [find noenable $router] != "" } { + set enable 0 + } + + # Figure out passwords + if { $do_passwd } { + set pswd [find password $router] + if { [llength $pswd] == 0 } { + send_user "\nError: no password for $router in $password_file.\n" + continue + } + if { $enable && $autoenable == 0 && [llength $pswd] < 2 } { + send_user "\nError: no enable password for $router in $password_file.\n" + continue + } + set passwd [join [lindex $pswd 0] ""] + set enapasswd [join [lindex $pswd 1] ""] + } + + # Figure out username + if {[info exists username]} { + # command line username + set ruser $username + } else { + set ruser [join [find user $router] ""] + if { "$ruser" == "" } { set ruser $default_user } + } + + # Figure out username's password (if different from the vty password) + if {[info exists userpasswd]} { + # command line username + set userpswd $userpasswd + } else { + set userpswd [join [find userpassword $router] ""] + if { "$userpswd" == "" } { set userpswd $passwd } + } + + # Figure out enable username + if {[info exists enausername]} { + # command line enausername + set enauser $enausername + } else { + set enauser [join [find enauser $router] ""] + if { "$enauser" == "" } { set enauser $ruser } + } + + # Figure out prompts + set u_prompt [find userprompt $router] + if { "$u_prompt" == "" } { + set u_prompt "(Username|Login|login|user name):" + } else { + set u_prompt [join [lindex $u_prompt 0] ""] + } + set p_prompt [find passprompt $router] + if { "$p_prompt" == "" } { + set p_prompt "(\[Pp]assword|passwd):" + } else { + set p_prompt [join [lindex $p_prompt 0] ""] + } + set e_prompt [find enableprompt $router] + if { "$e_prompt" == "" } { + set e_prompt "\[Pp]assword:" + } else { + set e_prompt [join [lindex $e_prompt 0] ""] + } + + # Figure out cypher type + if {[info exists cypher]} { + # command line cypher type + set cyphertype $cypher + } else { + set cyphertype [find cyphertype $router] + if { "$cyphertype" == "" } { set cyphertype "3des" } + } + + # Figure out connection method + set cmethod [find method $router] + if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} } + + # Figure out the SSH executable name + set sshcmd [find sshcmd $router] + if { "$sshcmd" == "" } { set sshcmd {ssh} } + + # Login to the router + if {[login $router $ruser $userpswd $passwd $enapasswd $cmethod $cyphertype]} { + continue + } + + # we are logged in, now figure out the full prompt + send "\r" + expect { + -re "\[\r\n]+" { exp_continue; } + -re "^(.+:)1 $prompt" { # stoopid extreme cmd-line numbers and + # prompt based on state of config changes + set junk $expect_out(1,string) + regsub -all "^\\\* " $expect_out(1,string) {} junk + set prompt ".? ?$junk\[0-9]+ $prompt"; + set platform "extreme" + } + -re "^.+$prompt" { set junk $expect_out(0,string); + regsub -all "\[\]\[]" $junk {\\&} prompt; } + -re "^.+> \\\(enable\\\)" { set junk $expect_out(0,string); + regsub -all "\[\]\[]" $junk {\\&} prompt; } + } + + if { $do_command } { + if {[run_commands $prompt $command]} { + continue + } + } elseif { $do_script } { + # If the prompt is (enable), then we are on a switch and the + # command is "set length 0"; otherwise its "term length 0". + if [ regexp -- ".*> .*enable" "$prompt" ] { + send "set length 0\r" + send "set logging session disable\r" + } else { + send "term length 0\r" + } + expect -re $prompt {} + source $sfile + close + } else { + label $router + log_user 1 + interact + } + + # End of for each router + wait + sleep 0.3 +} +exit 0 diff --git a/bin/nsrancid.in b/bin/nsrancid.in new file mode 100644 index 0000000..40a286f --- /dev/null +++ b/bin/nsrancid.in @@ -0,0 +1,313 @@ +#! @PERLV_PATH@ +## +## $Id: nsrancid.in,v 1.7 2004/01/11 03:49:13 heas Exp $ +## +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## All rights reserved. +## +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. +## +## There is no warranty or other guarantee of fitness of this software. +## It is provided solely "as is". The author(s) disclaim(s) all +## responsibility and liability with respect to this software's usage +## or its effect upon hardware, computer systems, other software, or +## anything else. +## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. +## +# +# hacked version of Hank's rancid - this one tries to deal with Netscalers. +# Hacks from Anshuman Kanwar. +# +# RANCID - Really Awesome New Cisco confIg Differ +# +# usage: rancid [-d] [-l] [-f filename | $host] +# +use Getopt::Std; +getopts('dfl'); +$log = $opt_l; +$debug = $opt_d; +$file = $opt_f; +$host = $ARGV[0]; +$clean_run = 0; +$found_end = 0; +$timeo = 90; # nslogin timeout in seconds + + +@temp1 = split (/\./,$host); +$prompt = "$temp1[0]#"; +$prompt = "netscaler#"; + +my(%filter_pwds); # password filtering mode + +# This routine is used to print out the router configuration +sub ProcessHistory { + my($new_hist_tag,$new_command,$command_string,@string)=(@_); + if((($new_hist_tag ne $hist_tag) || ($new_command ne $command)) + && defined %history) { + print eval "$command \%history"; + undef %history; + } + if (($new_hist_tag) && ($new_command) && ($command_string)) { + if ($history{$command_string}) { + $history{$command_string} = "$history{$command_string}@string"; + } else { + $history{$command_string} = "@string"; + } + } elsif (($new_hist_tag) && ($new_command)) { + $history{++$#history} = "@string"; + } else { + print "@string"; + } + $hist_tag = $new_hist_tag; + $command = $new_command; + 1; +} + +sub numerically { $a <=> $b; } + +# This is a sort routing that will sort numerically on the +# keys of a hash as if it were a normal array. +sub keynsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort numerically keys(%lines)) { + $sorted_lines[$i] = $lines{$key}; + $i++; + } + @sorted_lines; +} + +# This is a sort routing that will sort on the +# keys of a hash as if it were a normal array. +sub keysort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort keys(%lines)) { + $sorted_lines[$i] = $lines{$key}; + $i++; + } + @sorted_lines; +} + +# This is a sort routing that will sort on the +# values of a hash as if it were a normal array. +sub valsort{ + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort values %lines) { + $sorted_lines[$i] = $key; + $i++; + } + @sorted_lines; +} + +# This is a numerical sort routing (ascending). +sub numsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $num (sort {$a <=> $b} keys %lines) { + $sorted_lines[$i] = $lines{$num}; + $i++; + } + @sorted_lines; +} + +# This is a sort routine that will sort on the +# ip address when the ip address is anywhere in +# the strings. +sub ipsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $addr (sort sortbyipaddr keys %lines) { + $sorted_lines[$i] = $lines{$addr}; + $i++; + } + @sorted_lines; +} + +# These two routines will sort based upon IP addresses +sub ipaddrval { + my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#); + $a[3]+256*($a[2]+256*($a[1]+256*$a[0])); +} +sub sortbyipaddr { + &ipaddrval($a) <=> &ipaddrval($b); +} + +# This routine parses "show config" +sub ShowConfig { + print STDERR " In ShowConfig: $_" if ($debug); + + while () { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + next if (/^Reading configuration information/); + next if (/^Can\'t find object or class named \"\-all\"\s*$/); + next if (/lock-address .*$/); + next if (/^\# *uptime +\d+\s*$/); + if (/community label /) { + if (defined($ENV{'NOCOMMSTR'})) { + $_ =~ s/community label .*$/community label /; + } + } + return(1) if /(invalid command name)/; + ProcessHistory("","","","$_"); + } + + if (/exit$/) { + $found_end = 1; + $clean_run = 1; + return(1); + } + return(0); +} + +# This routine parses "get log setting" +sub GetLogSet { + print STDERR " In GetLogSet: $_" if ($debug); + + while () { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + next if (/^Reading configuration information/); + next if (/^Can\'t find object or class named \"\-all\"\s*$/); + return(1) if /(invalid command name)/; + + ProcessHistory("","","","$_"); + } + return(0); +} + +# This routine parses single command's that return no required info +sub RunCommand { + print STDERR " In RunCommand: $_" if ($debug); + + while () { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + } + return(0) +} + +# dummy function +sub DoNothing {print STDOUT;} + +# Main +#-------------------------------------------------- +%commands=( + 'cat /etc/ns.conf' => "ShowConfig", + 'get log setting' => "GetLogSet" +); +# keys() doesnt return things in the order entered and the order of the +# cmds is important (show version first and write term last). pita +@commands=( + "cat /etc/ns.conf", + "get log setting" +); +$cisco_cmds=join(";",@commands); +$cmds_regexp=join("|",@commands); + +open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; +select(OUTPUT); +# make OUTPUT unbuffered if debugging +if ($debug) { $| = 1; } + +if ($file) { + print STDERR "opening file $host\n" if ($debug); + print STDOUT "opening file $host\n" if ($log); + open(INPUT,"<$host") || die "open failed for $host: $!\n"; +} else { + print STDERR "executing nslogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($debug); + print STDOUT "executing nslogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($log); + if (defined($ENV{NOPIPE})) { + system "nslogin -t $timeo -c \"$cisco_cmds\" $host $host.raw 2>&1" || die "nslogin failed for $host: $!\n"; + open(INPUT, "< $host.raw") || die "nslogin failed for $host: $!\n"; + } else { + open(INPUT,"nslogin -t $timeo -c \"$cisco_cmds\" $host ) { + tr/\015//d; +#print STDOUT " --IN--$_"; + # if ( (/exit/) || $found_end ) { +# $clean_run=1; +#print STDOUT "\n\nhere11\n"; +#last; +# } + + # if ( (/netscaler#/) || $found_end ) { +#print STDOUT "\n\nhere1\n"; +# $clean_run=1; +# last; +# } + + if (/^Error:/) { + print STDOUT ("$host nslogin error: $_"); + print STDERR ("$host nslogin error: $_") if ($debug); + $clean_run=0; + last; + } + while (/#\s*($cmds_regexp)\s*$/) { + $cmd = $1; + print STDERR ("HIT COMMAND:$_") if ($debug); + if (! defined($commands{$cmd})) { + print STDERR "$host: found unexpected command - \"$cmd\"\n"; + $clean_run = 0; + last TOP; + } + $rval = &{$commands{$cmd}}; + delete($commands{$cmd}); + if ($rval == -1) { + $clean_run = 0; + last TOP; + } + } +} +print STDOUT "Done $logincmd: $_\n" if ($log); +# Flush History +ProcessHistory("","","",""); +# Cleanup +close(INPUT); +close(OUTPUT); + +if (defined($ENV{NOPIPE})) { + unlink("$host.raw") if (! $debug); +} + +# check for completeness +if (scalar(%commands) || !$clean_run || !$found_end) { + if (scalar(%commands)) { + printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands))); + printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug); + } + if (!$clean_run || !$found_end) { + print STDOUT "$host: End of run not found\n"; + print STDERR "$host: End of run not found\n" if ($debug); + system("/usr/bin/tail -1 $host.new"); + } + unlink "$host.new" if (! $debug); +} diff --git a/bin/par.in b/bin/par.in old mode 100755 new mode 100644 index 02a5383..b50bd05 --- a/bin/par.in +++ b/bin/par.in @@ -1,19 +1,22 @@ -#!@PERLV_PATH@ +#! @PERLV_PATH@ ## +## $Id: par.in,v 1.10 2004/01/11 03:49:13 heas Exp $ ## -## Copyright (C) 1997-2001 by Henry Kilmer and Peter Whiting. +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. ## All rights reserved. ## -## This software may be freely copied, modified and redistributed without -## fee for non-commerical purposes provided that this copyright notice is -## preserved intact on all copies and modified copies. -## +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. +## ## There is no warranty or other guarantee of fitness of this software. -## It is provided solely "as is". The author(s) disclaim(s) all +## It is provided solely "as is". The author(s) disclaim(s) all ## responsibility and liability with respect to this software's usage ## or its effect upon hardware, computer systems, other software, or ## anything else. ## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. ## # # PAR - parallel processing of command diff --git a/bin/prancid.in b/bin/prancid.in new file mode 100755 index 0000000..7ded178 --- /dev/null +++ b/bin/prancid.in @@ -0,0 +1,569 @@ +#! @PERLV_PATH@ +## +## $Id: prancid.in,v 1.29 2004/01/11 03:49:13 heas Exp $ +## +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## All rights reserved. +## +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. +## +## There is no warranty or other guarantee of fitness of this software. +## It is provided solely "as is". The author(s) disclaim(s) all +## responsibility and liability with respect to this software's usage +## or its effect upon hardware, computer systems, other software, or +## anything else. +## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. +## +# +# This version of rancid tries to deal with Prockets. +# +# RANCID - Really Awesome New Cisco confIg Differ +# +# usage: rancid [-d] [-l] [-f filename | $host] +# +use Getopt::Std; +getopts('dfl'); +$log = $opt_l; +$debug = $opt_d; +$file = $opt_f; +$host = $ARGV[0]; +$clean_run = 0; +$found_end = 0; +$timeo = 90; # clogin timeout in seconds + +my($platform); # platform/cpu type +my(%filter_pwds); # password filtering mode + +# This routine is used to print out the router configuration +sub ProcessHistory { + my($new_hist_tag,$new_command,$command_string,@string)=(@_); + if((($new_hist_tag ne $hist_tag) || ($new_command ne $command)) + && defined %history) { + print eval "$command \%history"; + undef %history; + } + if (($new_hist_tag) && ($new_command) && ($command_string)) { + if ($history{$command_string}) { + $history{$command_string} = "$history{$command_string}@string"; + } else { + $history{$command_string} = "@string"; + } + } elsif (($new_hist_tag) && ($new_command)) { + $history{++$#history} = "@string"; + } else { + print "@string"; + } + $hist_tag = $new_hist_tag; + $command = $new_command; + 1; +} + +sub numerically { $a <=> $b; } + +# This is a sort routing that will sort numerically on the +# keys of a hash as if it were a normal array. +sub keynsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort numerically keys(%lines)) { + $sorted_lines[$i] = $lines{$key}; + $i++; + } + @sorted_lines; +} + +# This is a sort routing that will sort on the +# keys of a hash as if it were a normal array. +sub keysort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort keys(%lines)) { + $sorted_lines[$i] = $lines{$key}; + $i++; + } + @sorted_lines; +} + +# This is a sort routing that will sort on the +# values of a hash as if it were a normal array. +sub valsort{ + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort values %lines) { + $sorted_lines[$i] = $key; + $i++; + } + @sorted_lines; +} + +# This is a numerical sort routing (ascending). +sub numsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $num (sort {$a <=> $b} keys %lines) { + $sorted_lines[$i] = $lines{$num}; + $i++; + } + @sorted_lines; +} + +# This is a sort routine that will sort on the +# ip address when the ip address is anywhere in +# the strings. +sub ipsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $addr (sort sortbyipaddr keys %lines) { + $sorted_lines[$i] = $lines{$addr}; + $i++; + } + @sorted_lines; +} + +# These two routines will sort based upon IP addresses +sub ipaddrval { + my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#); + $a[3]+256*($a[2]+256*($a[1]+256*$a[0])); +} +sub sortbyipaddr { + &ipaddrval($a) <=> &ipaddrval($b); +} + +# This routine parses "show version" +sub ShowVersion { + print STDERR " In ShowVersion: $_" if ($debug); + + while () { + tr/\015//d; + last if(/^$prompt/); + next if(/^(\s*|\s*$cmd\s*)$/); + return(-1) if (/command authorization failed/i); + + if (/(lynxos|kernel) Version: .* (\S+)/i) { + $platform = $2; + } + /Procket/ && ProcessHistory("COMMENTS","keysort","B0", "! $_") && next; + /System Uptime:/ && next; + /Protocol Uptime:/ && next; + ProcessHistory("COMMENTS","keysort","B0", "!$_") && next; + + } + return(0); +} + +# This routine parses "show package" +sub ShowPackage { + print STDERR " In ShowPackage: $_" if ($debug); + + while () { + tr/\015//d; + last if(/^$prompt/); + next if(/^(\s*|\s*$cmd\s*)$/); + return(-1) if (/command authorization failed/i); + + ProcessHistory("COMMENTS","keysort","C0", "! $_") && next; + + } + return(0); +} + +# This routine parses "show hardware" +sub ShowHardware { + print STDERR " In ShowHardware: $_" if ($debug); + + while () { + tr/\015//d; + last if(/^$prompt/); + next if(/^(\s*|\s*$cmd\s*)$/); + # skip show hardware on titanium + return(0) if ($platform =~ /i386/i); + return(-1) if (/command authorization failed/i); + return(-1) if (/cli: couldn.t communicate with/); + + ProcessHistory("COMMENTS","keysort","D0", "! $_") && next; + + } + return(0); +} + +# This routine parses "show inventory" +sub ShowInventory { + print STDERR " In ShowInventory: $_" if ($debug); + + while () { + tr/\015//d; + last if(/^$prompt/); + next if(/^(\s*|\s*$cmd\s*)$/); + return(0) if (/^\s+\^/); + return(-1) if (/command authorization failed/i); + + /Procket/ && ProcessHistory("COMMENTS","keysort","E0", "! $_") && next; + /System Uptime:/ && next; + /Protocol Uptime:/ && next; + ProcessHistory("COMMENTS","keysort","E0", "!$_") && next; + + } + return(0); +} + +# This routine processes a "write term" +sub WriteTerm { + print STDERR " In WriteTerm: $_" if ($debug); + + while () { + tr/\015//d; + last if(/^$prompt/); + return(-1) if (/command authorization failed/i); + + /Non-Volatile memory is in use/ && return(-1); # NvRAM is locked + # skip the crap + if (/^(##+$|(Building|Current) configuration)/i) { + while () { + next if (/^Current configuration\s*:/i); + next if (/^([%!].*|\s*)$/); + last; + } + tr/\015//d; + } + # some versions have other crap mixed in with the bits in the + # block above + /^! Last Changed:/ && next; + + # Dog gone Cool matches to process the rest of the config +# /^tftp-server flash / && next; # kill any tftp remains +# /^ntp clock-period / && next; # kill ntp clock-period +# /^ length / && next; # kill length on serial lines +# /^ width / && next; # kill width on serial lines +# /^ clockrate / && next; # kill clockrate on serial interfaces + + if (/^(enable secret( level \d)?) / && $filter_pwds >= 2) { + ProcessHistory("ENABLE","","","!$1 \n"); + next; + } + if (/^username (\S+)(\s.*)? password ((\d) \S+|\S+)/) { + if ($filter_pwds == 2) { + ProcessHistory("USER","keysort","$1","!username $1$2 password \n"); + } elsif ($filter_pwds == 1 && $4 ne "5"){ + ProcessHistory("USER","keysort","$1","!username $1$2 password \n"); + } else { + ProcessHistory("USER","keysort","$1","$_"); + } + next; + } + + # prune passwords {bgp, ...} + if (/^(\s*)password / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1password \n"); + next; + } + # prune authentication keys {vrrp vrid N, router isis...} + if (/^(\s*authentication \S+ key) / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); + next; + } + if (/^(\s*authentication-key) \d \S+( .*)/ && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 $2\n"); + next; + } + +# if (/^\s*neighbor (\S*) password / && $filter_pwds >= 1) { +# ProcessHistory("","","","! neighbor $1 password \n"); +# next; +# } +# if (/^(ppp .* password) 7 .*/ && $filter_pwds >= 1) { +# ProcessHistory("","","","!$1 \n"); next; +# } +# if (/^(ip ftp password) / && $filter_pwds >= 1) { +# ProcessHistory("","","","!$1 \n"); next; +# } + + # prune ospf keys + if (/^( ip ospf authentication-key) / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); next; + } + # this is reversable, despite 'md5' in the cmd + if (/^( ip ospf message-digest-key \d+ md5) / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); next; + } + # this is reversable, despite 'md5' in the cmd + if (/^(\s*message-digest-key \d+ md5) / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); next; + } + +# if (/^((crypto )?isakmp key) \S+ / && $filter_pwds >= 1) { +# ProcessHistory("","","","!$1 $'"); next; +# } + + # sort ip explicit-paths. + if (/^ip explicit-path name (\S+)/) { + my($key) = $1; + my($expath) = $_; + while () { + tr/\015//d; + last if (/^$prompt/); + last if (/^$prompt/ || ! /^(ip explicit-path name |[ !])/); + if (/^ip explicit-path name (\S+)/) { + ProcessHistory("EXPATH","keysort","$key","$expath"); + $key = $1; + $expath = $_; + } else { + $expath .= $_; + } + } + ProcessHistory("EXPATH","keysort","$key","$expath"); + } + + # sort route-maps + if (/^route-map (\S+)/) { + my($key) = $1; + my($routemap) = $_; + while () { + tr/\015//d; + last if (/^$prompt/ || ! /^(route-map |[ !])/); + if (/^route-map (\S+)/) { + ProcessHistory("ROUTEMAP","keysort","$key","$routemap"); + $key = $1; + $routemap = $_; + } else { + $routemap .= $_; + } + } + ProcessHistory("ROUTEMAP","keysort","$key","$routemap"); + } + + # filter out any RCS/CVS tags to avoid confusing local CVS storage + s/\$(Revision|Id):/ $1:/; + +# # order access-lists +# /^access-list\s+(\d\d?)\s+(\S+)\s+(\S+)/ && +# ProcessHistory("ACL $1 $2","ipsort","$3","$_") && next; +# # order extended access-lists +# /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+host\s+(\S+)/ && +# ProcessHistory("EACL $1 $2","ipsort","$3","$_") && next; +# /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+(\d\S+)/ && +# ProcessHistory("EACL $1 $2","ipsort","$3","$_") && next; +# /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+any/ && +# ProcessHistory("EACL $1 $2","ipsort","0.0.0.0","$_") && next; +# # order arp lists +# /^arp\s+(\d+\.\d+\.\d+\.\d+)\s+/ && +# ProcessHistory("ARP","ipsort","$1","$_") && next; +# /^ip prefix-list\s+(\S+)\s+seq\s+(\d+)\s+(permit|deny)\s+(\d\S+)(\/.*)$/ && +# ProcessHistory("PACL $1 $3","ipsort","$4","ip prefix-list $1 $3 $4$5\n") +# && next; + + # order logging statements + /^logging (\d+\.\d+\.\d+\.\d+)/ && + ProcessHistory("LOGGING","ipsort","$1","$_") && next; + + # order/prune snmp-server host statements + # we only prune lines of the form + # snmp-server host a.b.c.d + if (/^snmp-server host (\d+\.\d+\.\d+\.\d+) /) { + if (defined($ENV{'NOCOMMSTR'})) { + my($ip) = $1; + my($line) = "snmp-server host $ip"; + my(@tokens) = split(' ', $'); + my($token); + while ($token = shift(@tokens)) { + if ($token eq 'version') { + $line .= " " . join(' ', ($token, shift(@tokens))); + } elsif ($token =~ /^(informs?|traps?|(no)?auth)$/) { + $line .= " " . $token; + } else { + $line = "!$line " . join(' ', ("", join(' ',@tokens))); + last; + } + } + ProcessHistory("SNMPSERVERHOST","ipsort","$ip","$line\n"); + } else { + ProcessHistory("SNMPSERVERHOST","ipsort","$1","$_"); + } + next; + } + if (/^(snmp-server community) (\S+)/) { + if (defined($ENV{'NOCOMMSTR'})) { + ProcessHistory("SNMPSERVERCOMM","keysort","$_","!$1 $'") && next; + } else { + ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && next; + } + } + + # prune tacacs/radius server keys + if (/^(tacacs-server|radius-server) key / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 key \n"); next; + } + if (/^(tacacs-server host \S+( .*)? key) (\d )?\S+/ + && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); next; + } + + # order clns host statements +# /^clns host \S+ (\S+)/ && +# ProcessHistory("CLNS","keysort","$1","$_") && next; + + # prune vrrp password + if (/^( ip vrrp authentication .* key) / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); next; + } + # prune isis password + if (/^( isis authentication-key) \d \S+/ && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 $'"); next; + } + # prune msdp password + if (/^(ip msdp password \S+) / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); next; + } + # delete ntp auth password - this md5 is a reversable too + if (/^(ntp authentication-key \d+ md5) / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); next; + } + # order ntp peers/servers + if (/^ntp (server|peer) (\d+)\.(\d+)\.(\d+)\.(\d+)/) { + $sortkey = sprintf("$1 %03d%03d%03d%03d",$2,$3,$4,$5); + ProcessHistory("NTP","keysort",$sortkey,"$_"); + next; + } + +# # order ip host line statements +# /^ip host line(\d+)/ && +# ProcessHistory("IPHOST","numsort","$1","$_") && next; +# # order ip nat source static statements +# /^ip nat (\S+) source static (\S+)/ && +# ProcessHistory("IP NAT $1","ipsort","$2","$_") && next; +# # order atm map-list statements +# /^\s+ip\s+(\d+\.\d+\.\d+\.\d+)\s+atm-vc/ && +# ProcessHistory("ATM map-list","ipsort","$1","$_") && next; +# # order ip rcmd lines +# /^ip rcmd/ && ProcessHistory("RCMD","keysort","$_","$_") && next; + + # catch anything that wasnt matched above. + ProcessHistory("","","","$_"); + # end of config. + if (/^end$/) { + $found_end = 1; + return(1); + } + } + return(0); +} + +# dummy function +sub DoNothing {print STDOUT;} + +# Main +%commands=( + 'show version all' => "ShowVersion", + 'show package' => "ShowPackage", + 'show hardware' => "ShowHardware", + 'show inventory' => "ShowInventory", + 'write term' => "WriteTerm" +); +# keys() doesnt return things in the order entered and the order of the +# cmds is important (show version first and write term last). pita +@commands=( + "show version all", + "show package", + "show hardware", + "show inventory", + "write term" +); +$cisco_cmds=join(";",@commands); +$cmds_regexp=join("|",@commands); + +open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; +select(OUTPUT); +# make OUTPUT unbuffered if debugging +if ($debug) { $| = 1; } + +if ($file) { + print STDERR "opening file $host\n" if ($debug); + print STDOUT "opening file $host\n" if ($log); + open(INPUT,"<$host") || die "open failed for $host: $!\n"; +} else { + print STDERR "executing clogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($debug); + print STDOUT "executing clogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($log); + if (defined($ENV{NOPIPE})) { + system "clogin -t $timeo -c \"$cisco_cmds\" $host $host.raw 2>&1" || die "clogin failed for $host: $!\n"; + open(INPUT, "< $host.raw") || die "clogin failed for $host: $!\n"; + } else { + open(INPUT,"clogin -t $timeo -c \"$cisco_cmds\" $host ) { + tr/\015//d; + if (/\#\s?exit$/) { + $clean_run=1; + last; + } + if (/^Error:/) { + print STDOUT ("$host clogin error: $_"); + print STDERR ("$host clogin error: $_") if ($debug); + $clean_run=0; + last; + } + while (/#\s*($cmds_regexp)\s*$/) { + $cmd = $1; + if (!defined($prompt)) {$prompt = ($_ =~ /^([^#]+#)/)[0]; } + print STDERR ("HIT COMMAND:$_") if ($debug); + if (! defined($commands{$cmd})) { + print STDERR "$host: found unexpected command - \"$cmd\"\n"; + $clean_run = 0; + last TOP; + } + $rval = &{$commands{$cmd}}; + delete($commands{$cmd}); + if ($rval == -1) { + $clean_run = 0; + last TOP; + } + } +} +print STDOUT "Done $logincmd: $_\n" if ($log); +# Flush History +ProcessHistory("","","",""); +# Cleanup +close(INPUT); +close(OUTPUT); + +if (defined($ENV{NOPIPE})) { + unlink("$host.raw") if (! $debug); +} + +# check for completeness +if (scalar(%commands) || !$clean_run || !$found_end) { + if (scalar(%commands)) { + printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands))); + printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug); + } + if (!$clean_run || !$found_end) { + print STDOUT "$host: End of run not found\n"; + print STDERR "$host: End of run not found\n" if ($debug); + system("/usr/bin/tail -1 $host.new"); + } + unlink "$host.new" if (! $debug); +} diff --git a/bin/rancid-cvs.in b/bin/rancid-cvs.in new file mode 100644 index 0000000..22d5fd2 --- /dev/null +++ b/bin/rancid-cvs.in @@ -0,0 +1,94 @@ +#! /bin/sh +## +## $Id: rancid-cvs.in,v 1.16 2004/01/11 03:49:13 heas Exp $ +## +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## All rights reserved. +## +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. +## +## There is no warranty or other guarantee of fitness of this software. +## It is provided solely "as is". The author(s) disclaim(s) all +## responsibility and liability with respect to this software's usage +## or its effect upon hardware, computer systems, other software, or +## anything else. +## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. +## +# +# Create all of the misc files & dirs needed for each group and import them +# into CVS. +# +# rancid-cvs +# + +# Read in the environment +ENVFILE="@sysconfdir@/rancid.conf" + +. $ENVFILE + +# Base dir +if [ ! -d $BASEDIR ]; then + mkdir -p $BASEDIR || + (echo "Could not create local state directory: $BASEDIR"; exit 1) +fi + +cd $BASEDIR + +# Top level CVS stuff +if [ ! -d $CVSROOT ]; then + cvs init +fi + +# Log dir +if [ ! -d logs ]; then + mkdir logs +fi + +# Which groups to do +if [ $# -ge 1 ] ; then + LIST_OF_GROUPS="$*"; export LIST_OF_GROUPS +elif [ "$LIST_OF_GROUPS" = "" ] ; then + echo "LIST_OF_GROUPS is empty in $ENVFILE" + exit 1 +fi + +for GROUP in `echo $LIST_OF_GROUPS` ; +do + + DIR=$BASEDIR/$GROUP + + # Directory for the group and the configs + if [ ! -d $DIR ]; then + mkdir -p $DIR + cd $DIR + cvs import -m "$GROUP" $GROUP new rancid + cd $BASEDIR + cvs co $GROUP + fi + cd $DIR + if [ ! -d configs ]; then + mkdir configs + cvs add configs + cvs commit -m 'new' configs + fi + + # main files + if [ ! -f routers.all ]; then + touch routers.all + fi + if [ ! -f routers.down ]; then + touch routers.down + fi + if [ ! -f routers.up ]; then + touch routers.up + fi + if [ ! -f router.db ]; then + touch router.db + cvs add router.db + cvs commit -m 'new' router.db + fi +done diff --git a/bin/rancid-fe.in b/bin/rancid-fe.in old mode 100755 new mode 100644 index b25dcb1..b80a194 --- a/bin/rancid-fe.in +++ b/bin/rancid-fe.in @@ -1,22 +1,25 @@ -#!@PERLV_PATH@ +#! @PERLV_PATH@ ## +## $Id: rancid-fe.in,v 1.36 2004/01/11 03:49:13 heas Exp $ ## -## Copyright (C) 1997-2001 by Henry Kilmer. +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. ## All rights reserved. ## -## This software may be freely copied, modified and redistributed without -## fee for non-commerical purposes provided that this copyright notice is -## preserved intact on all copies and modified copies. +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. ## ## There is no warranty or other guarantee of fitness of this software. -## It is provided solely "as is". The author(s) disclaim(s) all +## It is provided solely "as is". The author(s) disclaim(s) all ## responsibility and liability with respect to this software's usage ## or its effect upon hardware, computer systems, other software, or ## anything else. ## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. ## # -# rancid-FE - front-end to rancid/jrancid for use with par. +# rancid-FE - front-end to rancid/jrancid/etc. for use with par. # # usage: rancid-fe : # @@ -25,18 +28,28 @@ require 5; ($router, $vendor) = split('\:', $ARGV[0]); - if ($vendor =~ /^alteon$/i) { exec('arancid', $router); } -elsif ($vendor =~ /^baynet$/i) { exec('brancid', $router); } -elsif ($vendor =~ /^cat5$/i) { exec('cat5rancid', $router); } -elsif ($vendor =~ /^cisco$/i) { exec('rancid', $router); } -elsif ($vendor =~ /^extreme$/i) { exec('xrancid', $router); } -elsif ($vendor =~ /^ezt3$/i) { exec('erancid', $router); } -elsif ($vendor =~ /^force10$/i) { exec('f10rancid', $router); } -elsif ($vendor =~ /^foundry$/i) { exec('francid', $router); } -elsif ($vendor =~ /^hp$/i) { exec('hrancid', $router); } -elsif ($vendor =~ /^juniper$/i) { exec('jrancid', $router); } -elsif ($vendor =~ /^mrtd$/i) { exec('mrancid', $router); } -elsif ($vendor =~ /^redback$/i) { exec('rrancid', $router); } + if ($vendor =~ /^alteon$/i) { exec('arancid', $router); } +elsif ($vendor =~ /^baynet$/i) { exec('brancid', $router); } +elsif ($vendor =~ /^cat5$/i) { exec('cat5rancid', $router); } +elsif ($vendor =~ /^cisco$/i) { exec('rancid', $router); } +elsif ($vendor =~ /^css$/i) { exec('cssrancid', $router); } +elsif ($vendor =~ /^enterasys$/i) { exec('rivrancid', $router); } +elsif ($vendor =~ /^erx$/i) { exec('jerancid', $router); } +elsif ($vendor =~ /^extreme$/i) { exec('xrancid', $router); } +elsif ($vendor =~ /^ezt3$/i) { exec('erancid', $router); } +elsif ($vendor =~ /^force10$/i) { exec('f10rancid', $router); } +elsif ($vendor =~ /^foundry$/i) { exec('francid', $router); } +elsif ($vendor =~ /^hitachi$/i) { exec('htrancid', $router); } +elsif ($vendor =~ /^hp$/i) { exec('hrancid', $router); } +elsif ($vendor =~ /^juniper$/i) { exec('jrancid', $router); } +elsif ($vendor =~ /^mrtd$/i) { exec('mrancid', $router); } +elsif ($vendor =~ /^netscaler$/i) { exec('nsrancid', $router); } +elsif ($vendor =~ /^netscreen$/i) { exec('nrancid', $router); } +elsif ($vendor =~ /^procket$/i) { exec('prancid', $router); } +elsif ($vendor =~ /^redback$/i) { exec('rrancid', $router); } +elsif ($vendor =~ /^riverstone$/i) { exec('rivrancid', $router); } +elsif ($vendor =~ /^tnt$/i) { exec('tntrancid', $router); } +elsif ($vendor =~ /^zebra$/i) { exec('zrancid', $router); } else { printf(STDERR "unknown router manufacturer for $router: $vendor\n"); exit(-1); diff --git a/bin/rancid-run.in b/bin/rancid-run.in new file mode 100644 index 0000000..b59b026 --- /dev/null +++ b/bin/rancid-run.in @@ -0,0 +1,136 @@ +#! /bin/sh +## +## $Id: rancid-run.in,v 1.28 2004/01/11 06:11:23 hank Exp $ +## +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## All rights reserved. +## +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. +## +## There is no warranty or other guarantee of fitness of this software. +## It is provided solely "as is". The author(s) disclaim(s) all +## responsibility and liability with respect to this software's usage +## or its effect upon hardware, computer systems, other software, or +## anything else. +## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. +## +# +# Run rancid for each of the rancid groups defined by $LIST_OF_GROUPS in +# @sysconfdir@/rancid.conf or those specified on the command-line. +# + +ENVFILE="@sysconfdir@/rancid.conf" + +. $ENVFILE + +TMPDIR=${TMPDIR:=/tmp}; export TMPDIR + +# control_rancid argv +CR_ARGV=""; export CR_ARGV + +# print a usage message to stderr +pr_usage() { + echo "usage: $0 [-r device_name] [-m mail rcpt] [group [group ...]]" >&2; +} + +# command-line options +# -r +if [ $# -ge 1 ] ; then + + while [ 1 ] ; do + case $1 in + -r) + shift + # next arg is the device name + CR_ARGV="$CR_ARGV -r $1"; export CR_ARGV + shift + ;; + -m) + shift + # next arg is the mailto name + CR_ARGV="$CR_ARGV -m $1"; export CR_ARGV + shift + ;; + --) + shift; break; + ;; + -h) + pr_usage + exit + ;; + -*) + echo "unknown option: $1" >&2 + pr_usage + exit 1 + ;; + *) + break; + ;; + esac + done +fi + +if [ $# -ge 1 ] ; then + LIST_OF_GROUPS="$*"; export LIST_OF_GROUPS +elif [ "$LIST_OF_GROUPS" = "" ] ; then + echo "LIST_OF_GROUPS is empty in $ENVFILE" + exit 1 +fi + +if [ ! -d $LOGDIR ] ; then + mkdir $LOGDIR || (echo "Could not create log directory: $LOGDIR"; exit 1) +fi + +for GROUP in $LIST_OF_GROUPS +do + + LOCKFILE=$TMPDIR/.$GROUP.run.lock + + ( + echo starting: `date` + echo + + if [ -f $LOCKFILE ] + then + echo hourly config diffs failed: $LOCKFILE exists + ls -l $LOCKFILE + + # Send email if the lock file is old. + if [ "X$LOCKTIME" = "X" ] ; then + LOCKTIME=4 + fi + @PERLV@ -e "\$t = (stat(\"$LOCKFILE\"))[9]; print \"OLD\\n\" if (time() - \$t >= $LOCKTIME*60*60);" > $TMPDIR/.$GROUP.old + if [ -s $TMPDIR/.$GROUP.old ] + then + ( + echo "To: @ADMINMAILPLUS@$GROUP" + echo "Subject: rancid hung - $GROUP" + echo "Precedence: bulk" + echo "" + + cat <$LOGDIR/$GROUP.`date +%Y%m%d.%H%M%S` 2>&1 +done diff --git a/bin/rancid.in b/bin/rancid.in old mode 100755 new mode 100644 index 4566b58..27a5a48 --- a/bin/rancid.in +++ b/bin/rancid.in @@ -1,19 +1,22 @@ -#!@PERLV_PATH@ +#! @PERLV_PATH@ ## +## $Id: rancid.in,v 1.168 2004/01/12 00:52:47 asp Exp $ ## -## Copyright (C) 1997-2001 by Henry Kilmer. +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. ## All rights reserved. ## -## This software may be freely copied, modified and redistributed without -## fee for non-commerical purposes provided that this copyright notice is -## preserved intact on all copies and modified copies. +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. ## ## There is no warranty or other guarantee of fitness of this software. -## It is provided solely "as is". The author(s) disclaim(s) all +## It is provided solely "as is". The author(s) disclaim(s) all ## responsibility and liability with respect to this software's usage ## or its effect upon hardware, computer systems, other software, or ## anything else. ## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. ## # # RANCID - Really Awesome New Cisco confIg Differ @@ -21,7 +24,7 @@ # usage: rancid [-d] [-l] [-f filename | $host] # use Getopt::Std; -getopts('dflm'); +getopts('dfl'); $log = $opt_l; $debug = $opt_d; $file = $opt_f; @@ -135,31 +138,40 @@ sub sortbyipaddr { # This routine parses "show version" sub ShowVersion { print STDERR " In ShowVersion: $_" if ($debug); + my($slaveslot); while () { tr/\015//d; - study; last if(/^$prompt/); next if(/^(\s*|\s*$cmd\s*)$/); return(-1) if (/command authorization failed/i); + # the pager can not be disabled per-session on the PIX + s/^<-+ More -+>\s*//; if (/^Slave in slot (\d+) is running/) { $slave = " Slave:"; + $slaveslot = ", slot $1"; next; } + if (/^Application and Content Networking Software/) { $type="CE"; } + /^Application and Content Networking Software Release /i && + ProcessHistory("COMMENTS","keysort","F1", "!Image: $_") && next; /^Cisco Secure PIX /i && ProcessHistory("COMMENTS","keysort","F1", "!Image: $_") && next; - /^IOS .* Software \(([A-Za-z-0-9]*)\), .*Version\s+(.*)$/ && + # PIX fail-over license + /^This PIX has an?\s+(.*)$/ && + ProcessHistory("COMMENTS","keysort","C1", "!$_") && next; + /^(Cisco )?IOS .* Software,? \(([A-Za-z-0-9]*)\), .*Version\s+(.*)$/ && ProcessHistory("COMMENTS","keysort","F1", - "!Image:$slave Software: $1, $2\n") && next; + "!Image:$slave Software: $2, $3\n") && next; /^([A-Za-z-0-9_]*) Synced to mainline version: (.*)$/ && ProcessHistory("COMMENTS","keysort","F2", "!Image:$slave $1 Synced to mainline version: $2\n") && next; /^Compiled (.*)$/ && ProcessHistory("COMMENTS","keysort","F3", "!Image:$slave Compiled: $1\n") && next; - /^ROM: (System )?Bootstrap.*(Version.*)$/ && + /^ROM: (IOS \S+ )?(System )?Bootstrap.*(Version.*)$/ && ProcessHistory("COMMENTS","keysort","G1", - "!ROM Bootstrap: $2\n") && next; + "!ROM Bootstrap: $3\n") && next; if (/^Hardware:\s+(.*), (.* RAM), CPU (.*)$/) { ProcessHistory("COMMENTS","keysort","A1", "!Chassis type: $1 - a PIX\n"); @@ -169,6 +181,17 @@ sub ShowVersion { } /^Serial Number:\s+(.*)$/ && ProcessHistory("COMMENTS","keysort","C1", "!$_") && next; + # CatOS 3500xl stuff + /^System serial number(:\s+.*)$/ && + ProcessHistory("COMMENTS","keysort","C1", "!Serial Number$1\n") && + next; + /^Model / && + ProcessHistory("COMMENTS","keysort","C2", "!$_") && next; + /^Motherboard / && + ProcessHistory("COMMENTS","keysort","C3", "!$_") && next; + /^Power supply / && + ProcessHistory("COMMENTS","keysort","C4", "!$_") && next; + /^Activation Key:\s+(.*)$/ && ProcessHistory("COMMENTS","keysort","C2", "!$_") && next; /^ROM: \d+ Bootstrap .*(Version.*)$/ && @@ -193,48 +216,80 @@ sub ShowVersion { my($cpu) = $2; my($mem) = $3; my($device) = "router"; - if ( $1 eq "CSC") { + + # the next line ought to be the more specific cpu info, grab it. + # yet, some boards/IOS vers have a processor ID line between these + # two. grrr. make sure we dont grab the "software" junk that + # follows these lines by looking for "CPU at " or the 2600s + # "processor: " unique string. there are undoubtedly many other + # incantations. for a slave, we dont get this info and its just a + # blank line. + $_ = ; + $_ = if (/processor board id/i); + $_ = "" if (! /(cpu at |processor: |$cpu processor,)/i); + tr/\015//d; + s/implementation/impl/i; + if ($_ !~ /^\s*$/) { + chomp; + s/^/, /; + } + + if ( $proc eq "CSC") { $type = "AGS"; - } elsif ( $1 eq "CSC4") { + } elsif ( $proc eq "CSC4") { $type = "AGS+"; - } elsif ( $1 eq "2511" || $1 eq "2524" || $1 eq "AS2511-RJ") { + } elsif ( $proc =~ /^(AS)?25[12][12]/) { $type = "2500"; - } elsif ( $1 =~ /261[01]/ || $1 =~ /262[01]/ ) { + } elsif ( $proc =~ /261[01]/ || $proc =~ /262[01]/ ) { $type = "2600"; - } elsif ( $1 eq "3620" || $1 eq "3640") { + } elsif ( $proc =~ /^36[0246][0-9]/) { $type = "3600"; - } elsif ( $1 eq "RSP7000") { + } elsif ( $proc =~ /^37/) { + $type = "3700"; + } elsif ( $proc eq "RSP7000") { $type = "7500"; - } elsif ( $1 =~ /RSP\d/) { + } elsif ( $proc =~ /RSP\d/) { $type = "7500"; - } elsif ( $1 eq "RP1") { + } elsif ( $proc eq "RP1") { $type = "7000"; - } elsif ( $1 eq "RP") { + } elsif ( $proc eq "RP") { $type = "7000"; - } elsif ( $1 =~ /720[246]/) { + } elsif ( $proc =~ /720[246]/) { $type = "7200"; - } elsif ( $1 =~ /1200[48]\/GRP/ || $1 =~ /1201[26]\/GRP/) { + } elsif ( $proc =~ /1200[48]\/GRP/ || $proc =~ /1201[26]\/GRP/) { $type = "12000"; - } elsif ( $1 =~ /1201[26]-8R\/GRP/) { + } elsif ( $proc =~ /1201[26]-8R\/GRP/) { $type = "12000"; - } elsif ( $1 =~ /WS-C29/) { + } elsif ( $proc =~ /WS-C29/) { $type = "2900XL"; $device = "switch"; - } elsif ( $1 =~ /WS-C35/) { + } elsif ( $proc =~ /WS-C355/) { + $type = "3550"; + $device = "switch"; + } elsif ( $proc =~ /WS-C35/) { $type = "3500XL"; $device = "switch"; - } elsif ( $1 =~ /6000/) { + } elsif ( $proc =~ /WS-C45/) { + $type = "4500"; + $device = "switch"; + } elsif ( $proc =~ /6000/) { $type = "6000"; $device = "switch"; + } elsif ( $proc =~ /CISCO76/) { + $type = "7600"; + $device = "router"; + } elsif ( $proc =~ /1900/) { + $type = "1900"; + $device = "switch"; } else { - $type = $1; + $type = $proc; } print STDERR "TYPE = $type\n" if ($debug); ProcessHistory("COMMENTS","keysort","A1", "!Chassis type:$slave $proc - a $type $device\n"); ProcessHistory("COMMENTS","keysort","B1", "!Memory:$slave main $mem\n"); - ProcessHistory("COMMENTS","keysort","A3","!CPU:$slave $cpu\n"); + ProcessHistory("COMMENTS","keysort","A3","!CPU:$slave $cpu$_$slaveslot\n"); next; } if (/(\S+) Silicon\s*Switch Processor/) { @@ -249,7 +304,7 @@ sub ShowVersion { /^(\d+[kK]) bytes of multibus/ && ProcessHistory("COMMENTS","keysort","B2", "!Memory: multibus $1\n") && next; - /^(\d+[kK]) bytes of non-volatile/ && + /^(\d+[kK]) bytes of (non-volatile|NVRAM)/ && ProcessHistory("COMMENTS","keysort","B3", "!Memory: nvram $1\n") && next; /^(\d+[kK]) bytes of flash memory/ && @@ -272,9 +327,6 @@ sub ShowVersion { ProcessHistory("COMMENTS","keysort","I0","!\n"); } ProcessHistory("COMMENTS","keysort","I1","! $_"); - # The line after the WARNING is what to do about it. - $_ = ; tr/\015//d; - ProcessHistory("COMMENTS","keysort","I1","! $_"); } if (/^Configuration register is (.*)$/) { $config_register=$1; @@ -284,6 +336,57 @@ sub ShowVersion { return(0); } +# This routine parses "show redundancy" +sub ShowRedundancy { + print STDERR " In ShowRedundancy: $_" if ($debug); + + while () { + tr/\015//d; + last if(/^$prompt/); + next if(/^(\s*|\s*$cmd\s*)$/); + # the pager can not be disabled per-session on the PIX + s/^<-+ More -+>\s*//; + + /^IOS .* Software \(([A-Za-z-0-9]*)\), .*Version\s+(.*)$/ && + ProcessHistory("COMMENTS","keysort","F1", + "!Image:$slave Software: $1, $2\n") && next; + /^Compiled (.*)$/ && + ProcessHistory("COMMENTS","keysort","F3", + "!Image:$slave Compiled: $1\n") && next; + } + return(0); +} + +# This routine parses "show IDprom" +sub ShowIDprom { + my($tmp); + + print STDERR " In ShowIDprom: $_" if ($debug); + + while () { + tr/\015//d; + last if(/^$prompt/); + next if(/^(\s*|\s*$cmd\s*)$/); + # the pager can not be disabled per-session on the PIX + s/^<-+ More -+>\s*//; + + /FRU is .(.*)\'/ && ($tmp = $1); + /Product Number = .(.*)\'/ && + ProcessHistory("COMMENTS","keysort","D0","!\n") && + ProcessHistory("COMMENTS","keysort","D0", + "!Catalyst Chassis type: $1, $tmp\n"); + /Serial Number = .([0-9A-Za-z]+)/ && + ProcessHistory("COMMENTS","keysort","D1", + "!Catalyst Chassis S/N: $1\n"); + /Manufacturing Assembly Number = .([-0-9]+)/ && ($tmp = $1); + /Manufacturing Assembly Revision = .(.*)\'/ && ($tmp .= ", rev " . $1); + /Hardware Revision = ([0-9.]+)/ && + ProcessHistory("COMMENTS","keysort","D2", + "!Catalyst Chassis assembly: $tmp, ver $1\n"); + } + return(0); +} + # This routine parses "show install active" sub ShowInstallActive { print STDERR " In ShowInstallActive: $_" if ($debug); @@ -295,6 +398,8 @@ sub ShowInstallActive { return(1) if /^\s*\^\s*$/; return(1) if /(Invalid input detected|Type help or )/; return(-1) if (/command authorization failed/i); + # the pager can not be disabled per-session on the PIX + s/^<-+ More -+>\s*//; ProcessHistory("COMMENTS","keysort","F5","!Image: $_") && next; } return(0); @@ -311,6 +416,8 @@ sub ShowEnv { next if (/^(\s*|\s*$cmd\s*)$/); #return(1) if ($type !~ /^7/); return(-1) if (/command authorization failed/i); + # the pager can not be disabled per-session on the PIX + s/^<-+ More -+>\s*//; if (!defined($E0)) { $E0=1; ProcessHistory("COMMENTS","keysort","E0","!\n"); @@ -331,11 +438,42 @@ sub ShowEnv { ProcessHistory("COMMENTS","keysort","E2","!Power: $1\n") && next; /^\s*(redundant .*)/i && ProcessHistory("COMMENTS","keysort","E2","!Power: $1\n") && next; + /^\s*(RPS is .*)/i && + ProcessHistory("COMMENTS","keysort","E2","!Power: $1\n") && next; } ProcessHistory("COMMENTS","","","!\n"); return(0); } +# This routine parses "show rsp chassis-info" for the rsp +# This will create arrays for hw info. +sub ShowRSP { + print STDERR " In ShowRSP: $_" if ($debug); + + while () { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(-1) if (/command authorization failed/i); + # return(1) if ($type !~ /^12[40]/); + # the pager can not be disabled per-session on the PIX + s/^<-+ More -+>\s*//; + /^$/ && next; + + /^\s+Chassis model: (\S+)/ && + ProcessHistory("COMMENTS","keysort","D0","!\n") && + ProcessHistory("COMMENTS","keysort","D1", + "!RSP Chassis model: $1\n") && + next; + /^\s+Chassis S\/N: (.*)$/ && + ProcessHistory("COMMENTS","keysort","D2", + "!RSP Chassis S/N: $1\n") && + next; + } + + return(0); +} + # This routine parses "show gsr chassis-info" for the gsr # This will create arrays for hw info. sub ShowGSR { @@ -348,6 +486,8 @@ sub ShowGSR { next if (/^(\s*|\s*$cmd\s*)$/); return(-1) if (/command authorization failed/i); # return(1) if ($type !~ /^12[40]/); + # the pager can not be disabled per-session on the PIX + s/^<-+ More -+>\s*//; /^$/ && next; /^\s+Chassis: type (\S+) Fab Ver: (\S+)/ && ProcessHistory("COMMENTS","keysort","D0","!\n") && @@ -386,15 +526,17 @@ sub ShowBoot { return(1) if /Ambiguous command/i; return(1) if /(Invalid input detected|Type help or )/; return(1) if /(Open device \S+ failed|Error opening \S+:)/; + # the pager can not be disabled per-session on the PIX + s/^<-+ More -+>\s*//; next if /CONFGEN variable/; if (!defined($H0)) { $H0=1; ProcessHistory("COMMENTS","keysort","H0","!\n"); } if ($type !~ /^(12[04]|7)/) { if ($type !~ /^(29|35)00/) { - ProcessHistory("COMMENTS","keysort","H2","!BootFlash: $_"); + ProcessHistory("COMMENTS","keysort","H2","!BootFlash: $_"); } else { - ProcessHistory("COMMENTS","keysort","H1","!Variable: $_"); + ProcessHistory("COMMENTS","keysort","H1","!Variable: $_"); } } elsif (/variable/) { ProcessHistory("COMMENTS","keysort","H1","!Variable: $_"); @@ -418,6 +560,8 @@ sub ShowFlash { return(-1) if (/command authorization failed/i); return(1) if /^\s*\^\s*$/; return(1) if /(Invalid input detected|Type help or )/; + # the pager can not be disabled per-session on the PIX + s/^<-+ More -+>\s*//; ProcessHistory("FLASH","","","!Flash: $_"); } ProcessHistory("","","","!\n"); @@ -438,13 +582,15 @@ sub DirSlotN { # return(1) if ($type !~ /^(12[40]|7|36)/); return(1) if /^\s*\^\s*$/; return(1) if /(Invalid input detected|Type help or )/; - return(1) if /No such device/i; + return(1) if /(No such device|Error Sending Request)/i; return(1) if /\%Error: No such file or directory/; return(1) if /No space information available/; return(-1) if /\%Error calling/; return(-1) if /(: device being squeezed|ATA_Status time out)/i; # busy return(-1) if (/command authorization failed/i); return(1) if /(Open device \S+ failed|Error opening \S+:)/; + # the pager can not be disabled per-session on the PIX + s/^<-+ More -+>\s*//; ProcessHistory("FLASH","","","!Flash: $dev: $_"); } ProcessHistory("","","","!\n"); @@ -458,11 +604,12 @@ sub ShowContAll { while () { tr/\015//d; - study; last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); # return(1) if ($type =~ /^(12[40]|7[05])/); return(-1) if (/command authorization failed/i); + # the pager can not be disabled per-session on the PIX + s/^<-+ More -+>\s*//; if (/^Interface ([^ \n(]*)/) { $INT = "$1, "; next; } /^(BRI unit \d)/ && ProcessHistory("INT","","","!Interface: $1\n") && next; @@ -521,6 +668,8 @@ sub ShowContCbus { next if (/^(\s*|\s*$cmd\s*)$/); #return(1) if ($type !~ /^7[05]0/); return(-1) if (/command authorization failed/i); + # the pager can not be disabled per-session on the PIX + s/^<-+ More -+>\s*//; if (/^\s*slot(\d+): ([^,]+), hw (\S+), sw (\S+), ccb/) { $slot = $1; $board{$slot} = $2; @@ -562,11 +711,12 @@ sub ShowDiagbus { while () { tr/\015//d; - study; last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); #return(1) if ($type !~ /^7[05]/); return(-1) if (/command authorization failed/i); + # the pager can not be disabled per-session on the PIX + s/^<-+ More -+>\s*//; if (/^\s*Slot (\d+):/i) { $slot = $1; next; @@ -641,7 +791,7 @@ sub ShowDiagbus { return(0); } -# This routine parses "show diag" for the gsr, 7200, 3600, 2600. +# This routine parses "show diag" for the gsr, 7200, 3700, 3600, 2600. # This will create arrarys for hw info. sub ShowDiag { # Skip if this is not a 12000. @@ -649,12 +799,14 @@ sub ShowDiag { while () { tr/\015//d; - study; last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); # return(1) if ($type !~ /^(12[40]|720|36|26)/); return(-1) if (/command authorization failed/i); /^$/ && next; + # the pager can not be disabled per-session on the PIX + s/^<-+ More -+>\s*//; + s/Port Packet Over SONET/POS/; if (/^\s*SLOT\s+(\d+)\s+\((.*)\): (.*)/) { $slot = $1; @@ -663,11 +815,22 @@ sub ShowDiag { next; } if (/^\s+MAIN:\s* type \d+,\s+(.*)/) { - ProcessHistory("SLOT","keysort","AM","!Slot $slot/MAIN: part $1\n") && next; + ProcessHistory("SLOT","keysort","AM","!Slot $slot/MAIN: part $1\n"); + next; + } + if (/^c3700\s+(io-board|mid-plane)/i) { + $slot=$1; + ProcessHistory("SLOT","","","!\n"); + ProcessHistory("SLOT","keysort","A","!Slot $slot: part $1\n"); + next; } if (/ Engine:\s+(.*)/) { ProcessHistory("SLOT","keysort","AE","!Slot $slot/Engine: $1\n"); } + if (/FRU:\s+Linecard\/Module:\s+(\S+)/) { + ProcessHistory("SLOT","keysort","AF","!Slot $slot/FRU: Linecard/Module: $1\n"); + next; + } if (/^\s+PCA:\s+(.*)/) { local($part) = $1; $_ = ; @@ -707,35 +870,78 @@ sub ShowDiag { } next; } - # 7200 and 3600 stuff - if (/^(Slot)\s+(\d+(\/\d+)?):/ || /^\s+(WIC|VIC) Slot (\d):/) { + # 7200, 3600, 2600, and 1700 stuff + if (/^(Slot)\s+(\d+(\/\d+)?):/ + || /^\s+(WIC|VIC|WIC\/VIC) Slot (\d):/ + || /^(Encryption AIM) (\d):/) { if ($1 eq "WIC") { $WIC = "/$2"; } elsif ($1 eq "VIC") { $WIC = "/$2"; + } elsif ($1 eq "WIC/VIC") { + $WIC = "/$2"; + } elsif ($1 eq "Encryption AIM") { + $slot = "$2"; + undef($WIC); + ProcessHistory("SLOT","","","!\n"); + ProcessHistory("SLOT","keysort","B","!Slot $slot: type $1\n"); + next; } else { $slot = $2; undef($WIC); } $_ = ; tr/\015//d; - # clean up hideous 7200 format to look more like 7500 output + # clean up hideous 7200/etc formats to look more like 7500 output s/Fast-ethernet on C7200 I\/O card/FE-IO/; s/ with MII or RJ45/-TX/; s/Fast-ethernet /100Base/; s/[)(]//g; + s/intermediate reach/IR/i; ProcessHistory("SLOT","","","!\n"); /\s+(.*) port adapter,?\s+(\d+)\s+/i && - ProcessHistory("SLOT","keysort","B","!Slot $slot: type $1, $2 ports\n"); + ProcessHistory("SLOT","keysort","B","!Slot $slot: type $1, $2 ports\n") && next; # I/O controller with no interfaces /\s+(.*)\s+port adapter\s*$/i && - ProcessHistory("SLOT","keysort","B","!Slot $slot: type $1, 0 ports\n"); + ProcessHistory("SLOT","keysort","B","!Slot $slot: type $1, 0 ports\n") && next; /\s+(.*)\s+daughter card(.*)$/ && - ProcessHistory("SLOT","keysort","B","!Slot $slot$WIC: type $1$2\n"); + ProcessHistory("SLOT","keysort","B","!Slot $slot$WIC: type $1$2\n") && next; /\s+(FT1)$/ && - ProcessHistory("SLOT","keysort","B","!Slot $slot$WIC: type $1\n"); + ProcessHistory("SLOT","keysort","B","!Slot $slot$WIC: type $1\n") && next; + # handle WICs lacking "daughter card" in the 2nd line of their + # show diag o/p + if (defined($WIC)) { + s/^\s+//; + ProcessHistory("SLOT","keysort","B","!Slot $slot$WIC: type $_"); + } next; } + # yet another format. seen on 2600s w/ 12.1, but appears to be all + # 12.1, including 7200s & 3700s. Sometimes the PCB serial appears + # before the hardware revision. + if (/(pcb serial number|hardware revision)\s+:\s+(\S+)$/i) { + my($hw, $pn, $rev, $sn); + if ($1 =~ /^pcb/i) { + $sn = $2; + } else { + $hw = $2; + } + while () { + tr/\015//d; + + if (/0x..: /) { + # no effing idea why break does not work there + goto PerlSucks; + } + if (/hardware revision\s+:\s+(\S+)/i) { $hw = $1; } + if (/part number\s+:\s+(\S+)/i) { $pn = $1; } + if (/board revision\s+:\s+(\S+)/i) { $rev = $1; } + if (/pcb serial number\s+:\s+(\S+)/i) { $sn = $1; } + } +PerlSucks: + ProcessHistory("SLOT","keysort","B","!Slot $slot$WIC: hvers $hw rev $rev\n"); + ProcessHistory("SLOT","keysort","C","!Slot $slot$WIC: part $pn, serial $sn\n"); + } /revision\s+(\S+).*revision\s+(\S+)/ && ProcessHistory("SLOT","keysort","C","!Slot $slot$WIC: hvers $1 rev $2\n") && next; @@ -760,6 +966,8 @@ sub ShowModule { last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); return(-1) if (/command authorization failed/i); + # the pager can not be disabled per-session on the PIX + s/^<-+ More -+>\s*//; # match slot/card info line if (/^ *(\d+)\s+(\d+)\s+(.*)\s+(\S+)\s+(\S+)\s*$/) { @@ -781,6 +989,24 @@ sub ShowModule { return(0); } +# This routine parses "show spe version". +sub ShowSpeVersion { + print STDERR " In ShowSpeVersion: $_" if ($debug); + + while () { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^\s*\^\s*$/; + return(1) if /(Invalid input detected|Type help or )/; + return(-1) if (/command authorization failed/i); + + ProcessHistory("MODEM","","","!Modem: $_") && next; + } + ProcessHistory("MODEM","","","!\n"); + return(0); +} + # This routine parses "show c7200" for the 7200 # This will create arrays for hw info. sub ShowC7200 { @@ -794,6 +1020,8 @@ sub ShowC7200 { #return(1) if ($type !~ /^72/); return(-1) if (/command authorization failed/i); /^$/ && next; + # the pager can not be disabled per-session on the PIX + s/^<-+ More -+>\s*//; if (/^(C7200 )?Midplane EEPROM:/) { $_ = ; /revision\s+(\S+).*revision\s+(\S+)/; @@ -838,6 +1066,8 @@ sub ShowVTP { #return(1) if ($type !~ /^(2900XL|3500XL|6000)$/); return(-1) if (/command authorization failed/i); next if (/^Configuration last modified by/); + # the pager can not be disabled per-session on the PIX + s/^<-+ More -+>\s*//; if (/^VTP Operating Mode\s+:\s+(Transparent|Server)/) { $DO_SHOW_VLAN = 1; } @@ -858,8 +1088,13 @@ sub ShowVLAN { last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); return(1) if /(Invalid input detected|Type help or )/; + # newer releases (~12.1(9)) place the vlan config in the normal + # configuration (write term). + return(1) if ($type =~ /^(3550|4500|7600)$/); #return(1) if ($type !~ /^(2900XL|3500XL|6000)$/); return(-1) if (/command authorization failed/i); + # the pager can not be disabled per-session on the PIX + s/^<-+ More -+>\s*//; ProcessHistory("COMMENTS","keysort","IO","!VLAN: $_"); } ProcessHistory("COMMENTS","keysort","IO","!\n"); @@ -869,16 +1104,17 @@ sub ShowVLAN { # This routine processes a "write term" sub WriteTerm { print STDERR " In WriteTerm: $_" if ($debug); - my($lineauto) = 0; + my($lineauto,$comment,$linecnt) = (0,0,0); while () { tr/\015//d; - study; last if(/^$prompt/); return(-1) if (/command authorization failed/i); # the pager can not be disabled per-session on the PIX s/^<-+ More -+>\s*//; /Non-Volatile memory is in use/ && return(-1); # NvRAM is locked + return(0) if ($found_end); # Only do this routine once + $linecnt++; $lineauto = 0 if (/^[^ ]/); # skip the crap if (/^(##+$|(Building|Current) configuration)/i) { @@ -898,6 +1134,16 @@ sub WriteTerm { # block above /^! (Last configuration|NVRAM config last)/ && next; + # skip consecutive comment lines to avoid oscillating extra comment + # line on some access servers. grrr. + if (/^!/) { + next if ($comment); + ProcessHistory("","","",$_); + $comment++; + next; + } + $comment = 0; + # Dog gone Cool matches to process the rest of the config /^tftp-server flash / && next; # kill any tftp remains /^ntp clock-period / && next; # kill ntp clock-period @@ -932,6 +1178,14 @@ sub WriteTerm { } next; } + if (/^( set session-key (in|out)bound ah \d+ )/ && $filter_pwds >= 1) { + ProcessHistory("","","","!$1\n"); + next; + } + if (/^( set session-key (in|out)bound esp \d+ (authenticator|cypher) )/ && $filter_pwds >= 1) { + ProcessHistory("","","","!$1\n"); + next; + } if (/^(\s*)password / && $filter_pwds >= 1) { ProcessHistory("LINE-PASS","","","!$1password \n"); next; @@ -955,7 +1209,7 @@ sub WriteTerm { } if (/^\s+(domain-password|area-password) (\S+)( .*)?/ && $filter_pwds >= 1) { - ProcessHistory("","","","!$1 $2\n"); next; + ProcessHistory("","","","!$1 $3\n"); next; } # this is reversable, despite 'md5' in the cmd if (/^( ip ospf message-digest-key \d+ md5) / && $filter_pwds >= 1) { @@ -964,10 +1218,25 @@ sub WriteTerm { if (/^((crypto )?isakmp key) \S+ / && $filter_pwds >= 1) { ProcessHistory("","","","!$1 $'"); next; } + # filter HSRP passwords + if (/^(\s+standby \d authentication) / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); next; + } + # this appears in "measurement/sla" images + if (/^(\s+key-string \d?)/ && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); next; + } + if (/^( l2tp tunnel \S+ password)/ && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); next; + } # i am told these are plain-text on the PIX if (/^(vpdn username \S+ password)/ && $filter_pwds >= 1) { ProcessHistory("","","","!$1 \n"); next; } + if (/^( cable shared-secret ) / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); + next; + } /fair-queue individual-limit/ && next; # sort ip explicit-paths. if (/^ip explicit-path name (\S+)/) { @@ -1057,10 +1326,14 @@ sub WriteTerm { ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && next; } } - # order/prune tacacs/radius server statements + # prune tacacs/radius server keys if (/^(tacacs-server|radius-server) key / && $filter_pwds >= 1) { ProcessHistory("","","","!$1 key \n"); next; } + if (/^((tacacs-server|radius-server) host \S+ key) / && + $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); next; + } # order clns host statements /^clns host \S+ (\S+)/ && ProcessHistory("CLNS","keysort","$1","$_") && next; @@ -1076,9 +1349,9 @@ sub WriteTerm { ProcessHistory("NTP","keysort",$sortkey,"$_"); next; } - # order ip host line statements - /^ip host line(\d+)/ && - ProcessHistory("IPHOST","numsort","$1","$_") && next; + # order ip host statements + /^ip host (\S+) / && + ProcessHistory("IPHOST","keysort","$1","$_") && next; # order ip nat source static statements /^ip nat (\S+) source static (\S+)/ && ProcessHistory("IP NAT $1","ipsort","$2","$_") && next; @@ -1105,6 +1378,14 @@ sub WriteTerm { return(1); } } + # The ContentEngine lacks a definitive "end of config" marker. If we + # know that it is a CE and we have seen at least 5 lines of write term + # o/p, we can be reasonably sure that we got the config. + if ($type =~ /^CE$/ && $linecnt > 5) { + $found_end = 1; + return(1); + } + return(0); } @@ -1114,8 +1395,11 @@ sub DoNothing {print STDOUT;} # Main %commands=( 'show version' => "ShowVersion", + 'show redundancy secondary' => "ShowRedundancy", + 'show idprom backplane', => "ShowIDprom", 'show install active' => "ShowInstallActive", 'show env all' => "ShowEnv", + 'show rsp chassis-info',=> "ShowRSP", 'show gsr chassis' => "ShowGSR", 'show boot' => "ShowBoot", 'show bootvar' => "ShowBoot", @@ -1131,22 +1415,44 @@ sub DoNothing {print STDOUT;} 'dir /all disk2:' => "DirSlotN", "dir /all sup-bootflash:"=> "DirSlotN", # cat 6500-ios "dir /all sup-microcode:"=> "DirSlotN", # cat 6500-ios + 'dir /all slavenvram:' => "DirSlotN", + 'dir /all slavebootflash:' => "DirSlotN", + 'dir /all slaveslot0:' => "DirSlotN", + 'dir /all slavedisk0:' => "DirSlotN", + 'dir /all slaveslot1:' => "DirSlotN", + 'dir /all slavedisk1:' => "DirSlotN", + 'dir /all slaveslot2:' => "DirSlotN", + 'dir /all slavedisk2:' => "DirSlotN", + "dir /all slavesup-bootflash:"=> "DirSlotN", # cat 7609 + 'dir /all sec-nvram:' => "DirSlotN", + 'dir /all sec-bootflash:' => "DirSlotN", + 'dir /all sec-slot0:' => "DirSlotN", + 'dir /all sec-disk0:' => "DirSlotN", + 'dir /all sec-slot1:' => "DirSlotN", + 'dir /all sec-disk1:' => "DirSlotN", + 'dir /all sec-slot2:' => "DirSlotN", + 'dir /all sec-disk2:' => "DirSlotN", 'show controllers' => "ShowContAll", 'show controllers cbus' => "ShowContCbus", 'show diagbus' => "ShowDiagbus", 'show diag' => "ShowDiag", 'show module' => "ShowModule", # cat 6500-ios + 'show spe version' => "ShowSpeVersion", 'show c7200' => "ShowC7200", 'show vtp status' => "ShowVTP", 'show vlan' => "ShowVLAN", + 'show running-config' => "WriteTerm", 'write term' => "WriteTerm" ); # keys() doesnt return things in the order entered and the order of the # cmds is important (show version first and write term last). pita @commands=( "show version", + "show redundancy secondary", + "show idprom backplane", "show install active", "show env all", + "show rsp chassis-info", "show gsr chassis", "show boot", "show bootvar", @@ -1162,14 +1468,33 @@ sub DoNothing {print STDOUT;} "dir /all disk2:", "dir /all sup-bootflash:", "dir /all sup-microcode:", + "dir /all slavenvram:", + "dir /all slavebootflash:", + "dir /all slaveslot0:", + "dir /all slavedisk0:", + "dir /all slaveslot1:", + "dir /all slavedisk1:", + "dir /all slaveslot2:", + "dir /all slavedisk2:", + "dir /all slavesup-bootflash:", + "dir /all sec-nvram:", + "dir /all sec-bootflash:", + "dir /all sec-slot0:", + "dir /all sec-disk0:", + "dir /all sec-slot1:", + "dir /all sec-disk1:", + "dir /all sec-slot2:", + "dir /all sec-disk2:", "show controllers", "show controllers cbus", "show diagbus", "show diag", "show module", + "show spe version", "show c7200", "show vtp status", "show vlan", + "show running-config", "write term" ); $cisco_cmds=join(";",@commands); @@ -1196,7 +1521,7 @@ if ($file) { } # determine password filtering mode -if ($ENV{"FILTER_PWDS"} =~ /no/i) { +if ($ENV{"FILTER_PWDS"} =~ /no/i) { $filter_pwds = 0; } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) { $filter_pwds = 2; @@ -1210,7 +1535,7 @@ ProcessHistory("COMMENTS","keysort","F0","!\n"); ProcessHistory("COMMENTS","keysort","G0","!\n"); TOP: while() { tr/\015//d; - if (/\#\s?exit$/) { + if (/[>#]\s?exit$/) { $clean_run=1; last; } @@ -1222,7 +1547,11 @@ TOP: while() { } while (/#\s*($cmds_regexp)\s*$/) { $cmd = $1; - if (!defined($prompt)) {$prompt = ($_ =~ /^([^#]+#)/)[0]; } + if (!defined($prompt)) { + $prompt = ($_ =~ /^([^#]+#)/)[0]; + $prompt =~ s/([][}{)(\\])/\\$1/g; + print STDERR ("PROMPT MATCH: $prompt\n") if ($debug); + } print STDERR ("HIT COMMAND:$_") if ($debug); if (! defined($commands{$cmd})) { print STDERR "$host: found unexpected command - \"$cmd\"\n"; diff --git a/bin/rename.in b/bin/rename.in deleted file mode 100755 index 8c3a111..0000000 --- a/bin/rename.in +++ /dev/null @@ -1,113 +0,0 @@ -#!@PERLV_PATH@ -'di'; -'ig00'; -# -# Revision 3.0.1.2 90/08/09 03:17:57 lwall -# patch19: added man page for relink and rename -# - -if ($ARGV[0] eq '-i') { - shift; - if (open(TTYIN, "/dev/tty")) { - $inspect++; - select((select(TTYOUT),$|=1)[0]); - } -} -($op = shift) || die "Usage: rename [-i] perlexpr [filenames]\n"; -if (!@ARGV) { - @ARGV = ; - chop(@ARGV); -} -for (@ARGV) { - unless (-e) { - print STDERR "$0: $_: $!\n"; - $status = 1; - next; - } - $was = $_; - eval $op; - die $@ if $@; - if ($was ne $_) { - if ($inspect && -e) { - print TTYOUT "remove $_? "; - next unless =~ /^y/i; - } - unless (rename($was, $_)) { - print STDERR "$0: can't rename $was to $_: $!\n"; - $status = 1; - } - } -} -exit $status; -############################################################################## -__END__ - # These next few lines are legal in both Perl and nroff. - -.00; # finish .ig - -'di \" finish diversion--previous line must be blank -.nr nl 0-1 \" fake up transition to first page again -.nr % 0 \" start at page 1 -';<<'.ex'; #__END__ ############# From here on it's a standard manual page ############ -.TH RENAME 1 "July 30, 1990" -.AT 3 -.SH NAME -rename \- renames multiple files -.SH SYNOPSIS -.B rename [-i] perlexpr [files] -.SH DESCRIPTION -.I Rename -renames the filenames supplied according to the rule specified as the -first argument. -The argument is a Perl expression which is expected to modify the $_ -string in Perl for at least some of the filenames specified. -If a given filename is not modified by the expression, it will not be -renamed. -If no filenames are given on the command line, filenames will be read -via standard input. -.PP -The -.B \-i -flag will prompt to remove the old file first if it exists. This -flag will be ignored if there is no tty. -.PP -For example, to rename all files matching *.bak to strip the extension, -you might say -.nf - - rename 's/\e.bak$//' *.bak - -.fi -To translate uppercase names to lower, you'd use -.nf - - rename 'y/A-Z/a-z/' * - -.fi -To do the same thing but leave Makefiles unharmed: -.nf - - rename 'y/A-Z/a-z/ unless /^Make/' * - -.fi -To rename all the *.f files to *.BAD, you'd use -.nf - - rename 's/\e.f$/.BAD/' *.f - -.SH ENVIRONMENT -.fi -No environment variables are used. -.SH FILES -.SH AUTHOR -Larry Wall -.SH "SEE ALSO" -mv(1) -.br -perl(1) -.SH DIAGNOSTICS -If you give an invalid Perl expression you'll get a syntax error. -.SH BUGS -.I Rename -does not check for the existence of target filenames, so use with care. -.ex diff --git a/bin/rivlogin.in b/bin/rivlogin.in new file mode 100644 index 0000000..12554d5 --- /dev/null +++ b/bin/rivlogin.in @@ -0,0 +1,1005 @@ +#! @EXPECT_PATH@ -- +## +## $Id: rivlogin.in,v 1.15 2004/01/11 05:39:15 heas Exp $ +## +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## All rights reserved. +## +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. +## +## There is no warranty or other guarantee of fitness of this software. +## It is provided solely "as is". The author(s) disclaim(s) all +## responsibility and liability with respect to this software's usage +## or its effect upon hardware, computer systems, other software, or +## anything else. +## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. +## +# +# The login expect scripts were based on Erik Sherk's gwtn, by permission. +# +# rivlogin - Riverstone (and Enterasys SSR) login +# +# Based upon rscmd (see nmops.org) +# rscmd - Riverstone Networks Automated login +# by Mike MacFaden, Kiran Addepalli +# Riverstone Networks, 2000 +# +# Returned to the RANCID crowd by andrew fort + +# Global vars section + +# program diagnostics +set verbose 0 +set success 1 +set config 0 + +# in seconds to wait for data back from device +set timeout 10 +set tempfile "/tmp/rivlogin.[exec date]" + +# cli command prompt +set my_prompt ">" +set enable_prompt "\#" + +set default_user "" +set output_file "" +set conf_prompt "*\(config\)# " +set logging 0 +set config_mode 0 + +# Password file for routers to access +set password_file $env(HOME)/.cloginrc + +# If no -c or -s specified, just automate router login ala rsh +set do_command 0 +set do_script 0 +set log_user 0 + +# The default CLI mode to login to is "enable" mode +set enable 1 + +# The default is to look in the password file to find the passwords. This +# tracks if we receive them on the command line. +set do_passwd 1 +set do_enapasswd 1 + +# cmd usage +set usage "Error: Usage: $argv0 \[-noenable\] \ +\[-f cloginrc-file\] \[-c command\] \[-Evar=x\] \[-s script-file\] \ +\[-x command-file\] \[-t timeout\] \[-o output-file\] \ +router \[router...\]\n" + +# Procedures Section + + +# +# Sets Xterm title if interactive...if its an xterm and the user cares +# + +proc label { host } { + + global env + + # if CLOGIN has an 'x' in it, don't set the xterm name/banner + if [info exists env(CLOGIN)] { + if {[string first "x" $env(CLOGIN)] != -1} { return } + } + + if [info exists env(TERM)] { + if [regexp \^(xterm|vs) $env(TERM) ignore ] { + send_user "\033]1;[lindex [split $host "."] 0]\a" + send_user "\033]2;$host\a" + } + } +} + + +# This is a helper function to make the password file easier to +# maintain. +# NOTES: Using this the password file has the form: +# add password sl* pete cow +# add password at* steve +# add password * hanky-pie + +proc add { var args } { + + global $var + lappend $var $args +} + +# Loads the password file. Note that as this file is tcl, and that +# it is sourced, the user better know what to put in there, as it +# could install more than just password info... I will assume however, +# that a "bad guy" could just as easy put such code in the clogin +# script, so I will leave .cloginrc as just an extention of that script + +proc source_password_file { } { + + global env password_file read_password_file + + if { [info exists read_password_file] } { + return 1 + } + + if { [info exists password_file] == 0 } { + set password_file $env(HOME)/.cloginrc + } + + set read_password_file 1 + file stat $password_file fileinfo + + if { [expr ($fileinfo(mode) & 007)] != 0000 } { + puts "ERROR: $password_file must not be group or world readable and writable\n" + return 1 + } + + source $password_file +} + +# pre: var is x, router is y +# post: return routerr entry from database else null string + +proc find { var router } { + + if {[ source_password_file ] == 0 } { + return {} + } + + upvar $var list + if { [info exists list] } { + foreach line $list { + if { [string match [lindex $line 0] $router ] } { + return [lrange $line 1 end] + } + } + } + return {} +} + + +# pre: login completed ok +# post: terminate login session by closing tcp connection + +proc auto_exit { } { + + global telnet_id + + if { $verbose == 1 } { + puts "DEBUG: auto_exit closing connection to pid $telnet_id\n" + } + close -i telnet_id +} + +# perform login basic to a router +# pre: args are valid, router is reachable via network +# post: return 0 on successful login, else 1 +# +# NOTE: a number of globals are setup: my_prompt, telnet_id are key +# and paging of cli output is disabled + +proc login { router user userpswd passwd enapasswd } { + + global login_array + global telnet_id + global expect_out + global spawn_id + global verbose + global config verbose my_prompt + + if { $verbose == 1 } { + puts "DEBUG: login router = $router" + puts "DEBUG: login username = $user" + puts "DEBUG: login userpasswd = $userpswd" + puts "DEBUG: login passwd = $passwd" + puts "DEBUG: login enapasswd = $enapasswd" + } + + spawn -noecho telnet $router + set telnet_id $spawn_id + + if { $telnet_id == 0 } { + puts "ERROR: login: spawn telnet session failed.\n" + return 1 + } + + # wait for initial 'Press RETURN to...' response + sleep 0.3 + + expect "*" + send "\r" + + # If password fails 3 times then expect again + set pass_attempt 0 + + expect { + + -re ".*> " { } + + "Password:" { + incr pass_attempt + send "$passwd\r" + exp_continue + } + + "Username: " { + + set pattempt 0 + + send "$user\r" + expect { + + "Password: " { + + incr pattempt + if {$pattempt == 1} { + send "$userpswd\r"; + } else { + send "$enapasswd\r"; + } + exp_continue + } + + -re ".*> " { exp_continue;} + } + } + + "%TELNETD-W-BADPASSWD" { + puts "ERROR: bad userid or password to telnet." + return 1 + } + "%CONS-W-AUTH_PASSWD" { + exp_continue + } + + "% Authentication failed." { + puts "ERROR: bad userid or password to telnet." + return 1 + } + + + "Authentication Failed:" { + puts "ERROR: bad userid or password to radius/tacacs+" + return 1 + } + + "Connection closed *" { + if {$pass_attempt == 3} { + puts "ERROR: Maximum attempts for password reached. Check password. Exiting."; + puts $expect_out(0,string); + return 1 + } + } + + timeout { + puts "ERROR: Timeout on login. Exiting."; + return 1 + } + + eof { + puts "ERROR: device closed telnet connection during login" + return 1 + } + } + + # save my_prompt for later use + send "\r" + expect -re ".*> " + set abc "$expect_out(buffer)" + set my_prompt "[lindex $abc 0]" + regexp {(.*[^>])} $my_prompt my + + return 0; +} + + +# pre: login completed ok +# post: turn off paging of commands + +proc disable_cli_paging { } { + global my_prompt + + send "cli set terminal rows 0\r" + + expect { + "$my_prompt" {return 0 } + } + return 1 +} + +# pre: login returned 0, prompt at top level +# post: turn off command completion return 0 +# on error, return 1 + +proc disable_cmd_autocomplete { } { + global my_prompt + + send "cli set command completion off\r" + expect { + + $my_prompt { } + + timeout { + puts "ERROR:disable_cmd_autocomplete(TIMEOUT)"; + return 0; + } + + } + + return 0 +} + +# pre: login returned 0, do_enable returned 0, cli is in enable or config mode +# post: issues logout cli to device, returns 0 + +proc logout { prompt } { + global config_mode enable_prompt + + # in case of not being at root cmd... + # verify top level prompt state, move to it if necessary + + if { $config_mode == 1 } { + + send "exit\r" + + expect { + "Do you want*" { + send "no\r" + } + + "$enable_prompt" { } + + timeout { puts "ERROR: logout: timeout from config mode\n" } + eof { puts "ERROR: device dropped connection\n" } + } + set config_mode 0 + } + + send "logout\r" + expect { + + "Are you sure*" { + send "yes\r" + return 0 + } + } +} + +# pre: current mode allows transition to enable mode +# post: enable mode entered, my_prompt updated, return 0 else 1 + +proc do_enable { enauser enapasswd userpswd } { + global expect_out verbose + global my_prompt enable_prompt + set enable_prompt [ string trimright $my_prompt ">" ] + set enable_prompt $enable_prompt\# + + if { $verbose == 1 } { + puts "DEBUG: do_enable: my_prompt = $my_prompt ena_prompt = $enable_prompt" + } + + send "enable\r" + + expect { + Username: { send "$enauser\r"; exp_continue } + Password: { send "$userpswd\r"; exp_continue } + + "$my_prompt" { + puts "ERROR: do_enable failed to gain enable mode." + return 1 + } + + "CONS-W-AUTH_PASSWD" { send "$enapasswd\r"; } + + "$enable_prompt " { } + "%SYS-W-NOPASSWD*" { } + + "Authentication Failed: Access Denied" { + puts "ERROR: Bad user or password for enable mode." + return 1 + } + } + + set my_prompt $enable_prompt + return 0 +} + +# pre: current mode allows transition to enable mode +# post: enable mode entered, my_prompt updated, return 0 else 1 + +proc do_configure { } { + global expect_out verbose config_mode + global my_prompt + set config_prompt [ string trimright $my_prompt "\#" ] + set config_prompt $config_prompt\(config\)\# + + if { $verbose == 1 } { + puts "DEBUG: do_config: my_prompt = $my_prompt cfg_prompt = $config_prompt" + } + + send "configure\r" + expect { + "$config_prompt " { } + "$my_prompt" { + } + + eof { return 1} + timeout { return 1} + } + + set config_mode 1 + set my_prompt $config_prompt + return 0 +} + +# track sent/received from device to output_file +# pre: outut_file is valid filename w/write access +# post: logfile open, global var logging == 1, return 0 , else 1 + +proc start_logfile { output_file } { + global logging + + if { [ string length $output_file ] != 0 } { + set rc [ catch { + log_file -noappend $output_file + } errMsg ] + + if { $rc != 0 } { + puts "ERROR: open file $output_file for write access failed. $errMsg\n" + return 1 + } + set logging 1 + } + + return 0 +} + +proc run_commands { prompt cmdstring } { + global sendstring + + set commands [split $cmdstring \;] + set num_commands [llength $cmdstring] + + for {set i 0} {$i < $num_commands} { incr i} { + regsub -- {[ ]*([^\.]*)} [subst -nocommands [lindex $commands $i]] {\1} sendstring + + if {[ run_single_command $prompt $sendstring ] == 1} { + puts "ERROR: command '$sendstring' not processed by device. Check previous error messages." + return 1 + } + } + return 0 +} + + +# Run commands given on the command line +# pre: prompt is current system cli prompt, cmdstring is command to execute +# post: return 0 on success else 1 +# NOTE: output from router ends up in output_file if specified +# expect internal input buffer is reset to "" after each command + +proc run_single_command { prompt cmdstring } { + global verbose + set rc 0 + set seen_prompt 0 + set seen_timeout 0 + set need_ays 0 + set delay 0 + + if {$verbose == 1} { + puts "DEBUG: run_commands: prompt=$prompt \"$cmdstring\" " + } + + # ays == "are you sure" - must send back yes + if { [string compare $cmdstring "save startup" ] == 0 } { + set need_ays 1 + set delay 1 + if {$verbose == 1} { + puts "DEBUG: save startup cmd seen, set need_ays = 1" + } + } + + # TODO: add case for copy command to startup, also prompts for ok + + # TODO: if we see config command: system set name note it + # if we see a save active, then update system prompts as well + + send "$cmdstring\r" + + if { $delay == 1} { + sleep 1 + } + + expect { + + "%CLI-E-IVCMD*" { + puts "ERROR: run_commands(command rejected by device)\n" + set rc 1 + } + + "%CLI-E-FACUNKNWN*" { + puts "ERROR: run_commands(command rejected by device)\n" + set rc 1 + } + + "%SYS-I-ADDFAILED*" { + puts "ERROR: run_commands(command rejected by device)\n" + set rc 1 + } + "%TFTP-E-REMOTE,*" { + puts "ERROR: run_commands(command rejected by device)\n" + set rc 1 + } + + "%SYS-E-PRIMARY_NO_SUCH_IMAGE*" { + puts "ERROR: run_commands(command rejected by device)\n" + set rc 1 + } + + "want to overwrite " { + send "yes\r" + if {$verbose == 1} { + puts "DEBUG: got overwrite question, set need_ays to 0" + } + set need_ays 0 + } + + + "%CONFIG-E-DUPLICATE,*" { + } + + "$prompt" { + if { $seen_prompt == 0 } { + set seen_prompt 1 + } + + if {$verbose == 1} { + puts "DEBUG: saw double prompt, exiting expect loop\n" + } + + if { $need_ays == 1 } { + exp_continue + } + } + + -re ".* More: m, --- Quit: q --- One line: ---" { + send "q" + exp_continue + } + + + timeout { + if {$verbose == 1} { + puts "DEBUG: timeout occured for the $seen_time time\n" + } + + if { $seen_timeout == 0 } { + set seen_timeout 1 + send "\r\r" + exp_continue + } + + puts "ERROR:run_commands(TIMEOUT)" + set rc 1 + } + + eof { + puts "ERROR:run_commands(connection closed by device)\n" + set rc 1 + } + + "\n" { exp_continue } + } + + # clear input buffer of any remaining data + expect "*" + return $rc +} + + +# pre: RSTONE_USER env var is set +# post: update global "default_user" to this string + +proc init_userid { } { + global default_user + + if {[ info exists env(RSTONE_USER) ] } { + set default_user $env(RSTONE_USER) + } else { + # This uses "id" which I think is portable. At least it has existed + # (without options) on all machines/OSes I've been on recently - + # unlike whoami or id -nu. + regexp {\(([^)]*)} [exec id] junk default_user + } +} + +proc source_script_file { filename } { + global my_prompt + + expect -re "$my_prompt" {} + + source $filename + +} + + +# pre: login completed ok, filename contains set of cli commands one per line +# post: each command is extracted from filename and sent to device +# return 0 on success, return 1 on error +# NOTE: for scripts that begin with "configure", change the mode to configure +# before executing the following commands + +proc process_script_file { filename } { + + global my_prompt verbose + set rc 0 + set ifile "" + + set rc [ catch { + set ifile [ open $filename r] + } errMsg ] + + if { $rc != 0 } { + puts "ERROR: process_script_file: open script file $filename for read access failed. $errMsg\n" + return 1 + } + + set line_cnt 0 + + while { [eof $ifile] != 1 } { + + set bytes [ gets $ifile cmd ] + incr line_cnt + + if { $bytes < 0 } { + break + } elseif { $bytes == 0 } { + continue + } + + if { $verbose == 1 } { + puts "DEBUG: line:$line_cnt cmd = $cmd\n" + } + + # skip comments in script files + if { [regexp "^\#" $cmd] != 1 } { + + # puts "$cmd rc = [string compare $cmd "configure" ]\n" + + if { [string compare $cmd "configure" ] == 0 } { + + do_configure + + } else { + if {[ run_commands $my_prompt $cmd ] == 1} { + puts "ERROR: line $line_cnt in $filename not processed by device. Check previous error msgs." + set rc 1 + break + } + } + } + } + + close $ifile + return $rc +} + + + +# pre: filename is valid file +# post: remove extended ascii sequences and other cruft +# and prepend a header: rscmd: ip-addr : date +# TODO: should watch all file commands more closely + +proc strip_log { filename router } { + + global tempfile + + set rc [ catch { + set ifile [ open $filename r] + } errMsg ] + + if { $rc != 0 } { + puts "ERROR: strip_log: open script file $filename for read access failed. $errMsg\n" + return 1 + } + set rc [ catch { + set ofile [ open $tempfile w] + } errMsg ] + + if { $rc != 0 } { + puts "ERROR: strip_log: open temp file $tempfile for write access failed. $errMsg\n" + return 1 + } + + set nl 0 + + puts $ofile "rscmd: $router : [exec date]" + + while { [eof $ifile] != 1 } { + + set bytes [ gets $ifile cmd ] + if { $bytes <= 0 } { + break + } + incr nl + if { $nl <= 2 } { + continue + } + + regsub -all -- "\r" $cmd "" newcmd + puts $ofile $newcmd + } + + close $ifile + close $ofile + set rc 0 + file copy -force $tempfile $filename + file delete $tempfile + return $rc +} + +# +# main section +# + + +if { $verbose == 1 } { + puts "\n\nrscmd: Version 1.1 started on [exec date]" + puts "[exec uname -a]" + puts "Expect Version: [exp_version]\n" +} + +# send input like in a fast and consistent human style +set send_human {.1 .3 1 .05 2} + +# initialize default_user variable +init_userid + +# Parse Command Line + +for {set idx 0} {$idx < $argc} {incr idx} { + + set arg [lindex $argv $idx] + + switch -glob -- $arg { + + -c* - + -C* { + if {! [ regexp .\[cC\](.+) $arg ignore command]} { + incr idx + set command [ lindex $argv $idx ] + } + set do_command 1 + # Environment variable to pass to -s scripts + } -E* + { + if {[ regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} { + set E$varname $varvalue + } else { + send_user "Error: invalid format for -E in $arg\n" + exit 1 + } + # Expect script to run + } -s* - + -S* { + if {! [ regexp .\[sS\](.+) $arg ignore sfile]} { + incr idx + set sfile [ lindex $argv $idx ] + } + + if { ! [ file exists $sfile ] } { + puts "ERROR: invalid argument script file \"$sfile\" does not exist.\n" + exit 1 + } + if { ! [ file readable $sfile ] } { + puts "ERROR: invalid argument script file \"$sfile\" permissions disallow read access.\n" + exit 1 + } + + set do_script 1 + # Command file + } -x* - + -X { + if {! [ regexp .\[xX\](.+) $arg ignore cmd_file]} { + incr idx + set cmd_file [ lindex $argv $idx ] + } + if [ catch {set cmd_fd [open $cmd_file r]} reason ] { + send_user "\nError: $reason\n" + exit 1 + } + set cmd_text [read $cmd_fd] + close $cmd_fd + set command [join [split $cmd_text \n] \;] + set do_command 1 + } -f* - + -F* { + if {! [ regexp .\[fF\](.+) $arg ignore password_file]} { + incr idx + set password_file [ lindex $argv $idx ] + } + + } -o* - + -O* { + if {! [ regexp .\[fF\](.+) $arg ignore password_file]} { + incr idx + set output_file [ lindex $argv $idx ] + if { $verbose == 1 } { + puts "DEBUG: output file: $output_file" + } + } + + } -t* - + -T* { + incr idx + set timeout [ lindex $argv $idx ] + + } -noenable { + set enable 0 + } -* { + puts "ERROR:unkown argument passed: $arg\n" + puts $usage + exit 1 + + } default { + break + } + } +} + +# Verify at least one router is specified +# +if { $idx == $argc } { + puts "\n$usage" + exit 1 +} + +# main loop + +foreach router [lrange $argv $idx end] { +set router [string tolower $router] + +# Figure out passwords +if {$verbose == 1} { + puts "DEBUG: do_passwd = $do_passwd\n" + puts "DEBUG: do_enablepasswd = $do_enapasswd\n" +} + +if { $do_passwd || $do_enapasswd } { + set pswd [find password $router] + if { [llength $pswd] == 0 } { + puts "ERROR: - no password for $router in $password_file.\n" + exit 1 + } + if { $do_enapasswd && [llength $pswd] < 2 } { + puts "ERROR: no enable password found for $router in $password_file." + exit 1 + } + + set passwd [join [lindex $pswd 0] ""] + set enapasswd [join [lindex $pswd 1] ""] +} + + +# Figure out user to login with if necessary + +if {[info exists username]} { + # command line username + set user $username +} else { + set user [join [find user $router] ""] + if { "$user" == "" } { set user $default_user } +} + +# Figure out username's password + +if {[info exists userpasswd]} { + # command line username + set userpswd $userpasswd +} else { + set userpswd [join [find userpassword $router] ""] + if { "$userpswd" == "" } { set userpswd $passwd } +} + +# Figure out enable username + +if {[info exists enausername]} { + # command line enausername + set enauser $enausername +} else { + set enauser [join [find enauser $router] ""] + if { "$enauser" == "" } { set enauser $user } +} + +# Login to the router, set my_prompt to router's cmd prompt + +if {[login $router $user $userpswd $passwd $enapasswd ]} { + if { $verbose == 1 } { + puts "DEBUG: login to $router failed\n" + } + exit 1 +} + +if {$verbose == 1 } { + puts "DEBUG: login completed ok\n" +} + +if { $enable == 1 } { + + if { [do_enable $enauser $enapasswd $userpswd] == 1} { + if { $verbose == 1 } { + puts "DEBUG: switch to enable mode on $router failed\n" + } + exit 1 + } +} + +# run in one of three modes + +if { $do_command } { + + disable_cmd_autocomplete + disable_cli_paging + + if {[ start_logfile $output_file] != 0 } { + exit 1 + } + + if {[ run_commands $my_prompt $command ]} { + + log_file + exit 1 + + } else { + + logout $my_prompt + + } + +} elseif { $do_script } { + + disable_cmd_autocomplete + disable_cli_paging + + if {[ start_logfile $output_file] != 0 } { + exit 1 + } + + #if { [process_script_file $sfile] == 1} { +# puts "DEBUG: logfile $output_file closed on error\n" +# logout $my_prompt +# exit 1 +# } + + source_script_file $sfile + + logout $my_prompt + +} else { + + label $router + log_user 1 + + if {[ start_logfile $output_file] != 0 } { + exit 1 + } + interact + log_file +} + +if { $verbose == 1 } { + puts "DEBUG: exiting normally.\n" +} + +if { $logging == 1} { + log_file + strip_log $output_file $router +} +} + +# puts "\n" +exit 0 diff --git a/bin/rivrancid.in b/bin/rivrancid.in new file mode 100644 index 0000000..8b9ae03 --- /dev/null +++ b/bin/rivrancid.in @@ -0,0 +1,344 @@ +#! @PERLV_PATH@ +## +## $Id: rivrancid.in,v 1.9 2004/01/11 03:49:13 heas Exp $ +## +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## All rights reserved. +## +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. +## +## There is no warranty or other guarantee of fitness of this software. +## It is provided solely "as is". The author(s) disclaim(s) all +## responsibility and liability with respect to this software's usage +## or its effect upon hardware, computer systems, other software, or +## anything else. +## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. +## +# +# Amazingly hacked version of Hank's rancid - this one tries to +# deal with Cabletron, Riverstone and Enterasys routers/switches +# +# 10/23/2002 -- Initial changes for Riverstone/Cabletron support +# Jim Meehan -- jmeehan@vpizza.org +# +# RANCID - Really Awesome New Cisco confIg Differ +# +# usage: rivrancid [-d] [-l] [-f filename | $host] +# +use Getopt::Std; +getopts('dfl'); +$log = $opt_l; +$debug = $opt_d; +$file = $opt_f; +$host = $ARGV[0]; +$clean_run = 0; +$found_end = 0; +$timeo = 90; # flogin timeout in seconds + +my(%filter_pwds); # password filtering mode + +# This routine is used to print out the router configuration +sub ProcessHistory { + my($new_hist_tag,$new_command,$command_string,@string)=(@_); + if((($new_hist_tag ne $hist_tag) || ($new_command ne $command)) + && defined %history) { + print eval "$command \%history"; + undef %history; + } + if (($new_hist_tag) && ($new_command) && ($command_string)) { + if ($history{$command_string}) { + $history{$command_string} = "$history{$command_string}@string"; + } else { + $history{$command_string} = "@string"; + } + } elsif (($new_hist_tag) && ($new_command)) { + $history{++$#history} = "@string"; + } else { + print "@string"; + } + $hist_tag = $new_hist_tag; + $command = $new_command; + 1; +} + +sub numerically { $a <=> $b; } + +# This is a sort routing that will sort numerically on the +# keys of a hash as if it were a normal array. +sub keynsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort numerically keys(%lines)) { + $sorted_lines[$i] = $lines{$key}; + $i++; + } + @sorted_lines; +} + +# This is a sort routing that will sort on the +# keys of a hash as if it were a normal array. +sub keysort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort keys(%lines)) { + $sorted_lines[$i] = $lines{$key}; + $i++; + } + @sorted_lines; +} + +# This is a sort routing that will sort on the +# values of a hash as if it were a normal array. +sub valsort{ + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort values %lines) { + $sorted_lines[$i] = $key; + $i++; + } + @sorted_lines; +} + +# This is a numerical sort routing (ascending). +sub numsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $num (sort {$a <=> $b} keys %lines) { + $sorted_lines[$i] = $lines{$num}; + $i++; + } + @sorted_lines; +} + +# This is a sort routine that will sort on the +# ip address when the ip address is anywhere in +# the strings. +sub ipsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $addr (sort sortbyipaddr keys %lines) { + $sorted_lines[$i] = $lines{$addr}; + $i++; + } + @sorted_lines; +} + +# These two routines will sort based upon IP addresses +sub ipaddrval { + my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#); + $a[3]+256*($a[2]+256*($a[1]+256*$a[0])); +} +sub sortbyipaddr { + &ipaddrval($a) <=> &ipaddrval($b); +} + +# This routine parses "system show version" +sub ShowVersion { + my($slot); + + print STDERR " In ShowVersion: $_" if ($debug); + + while () { + tr/\015//d; + next if /^\s*$/; + last if(/^$prompt/); + + ProcessHistory("VERSION","","","!SW: $_"); + } + ProcessHistory("VERSION","","","!\n"); + return(0); +} + +# This routine parses "system show hardware" +sub ShowHardware { + print STDERR " In ShowHardware: $_" if ($debug); + + while () { + tr/\015//d; + last if (/^$prompt/); + ProcessHistory("HARDWARE","","","!HW: $_"); + } + ProcessHistory("","","","!\n"); + return(0); +} + +# This routine parses "system show uptime" +sub ShowUptime { + print STDERR " In ShowUptime: $_" if ($debug); + + while () { + tr/\015//d; + last if(/^$prompt/); + next if /^\s*$/; + next if /System up/; + ProcessHistory("UPTIME","","","!UPTIME: $_"); + } + ProcessHistory("","","","!\n"); + return; +} + +# This routine processes a "system show active" +sub ShowActive { + print STDERR " In ShowActive: $_" if ($debug); + + while () { + tr/\015//d; + + # Remove leading whitespace and/or line numbers + s/^\s*(\d+\D: )*//; + + # Riverstone/Cabletron doesn't have an "end" line, so + # we need to set $clean_run here + if (/^$prompt/) { + $clean_run = 1; + last; + } + + next if (/Running system configuration/); + + # filter out any RCS/CVS tags to avoid confusing local CVS storage + s/\$(Revision|Id):/ $1:/; + + if (/^(.*hashed-password \S+)/ && $filter_pwds == 2) { + ProcessHistory("","","","! $1 \n"); + next; + } + + if (/^(snmp set community )\S+/ && defined($ENV{'NOCOMMSTR'})) { + ProcessHistory("","","","! $1$'"); + next; + } + + ProcessHistory("","","","$_"); + } + return; +} + +# dummy function +sub DoNothing {print STDOUT;} + +# Main +%commands=( + 'system show uptime' => "ShowUptime", + 'system show version' => "ShowVersion", + 'system show hardware' => "ShowHardware", + 'system show active-config' => "ShowActive" +); + +# keys() doesnt return things in the order entered and the order of the +# cmds is important. pita + +@commands=( + "system show uptime", + "system show version", + "system show hardware", + "system show active-config" +); + +$cisco_cmds=join(";",@commands); +$cmds_regexp=join("|",@commands); + +open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; +select(OUTPUT); +# make OUTPUT unbuffered if debugging +if ($debug) { $| = 1; } + +if ($file) { + print STDERR "opening file $host\n" if ($debug); + print STDOUT "opening file $host\n" if ($log); + open(INPUT,"<$host") || die "open failed for $host: $!\n"; +} else { + print STDERR "executing rivlogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($debug); + print STDOUT "executing rivlogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($log); + if (defined($ENV{NOPIPE})) { + system "rivlogin -t $timeo -c \"$cisco_cmds\" $host $host.raw 2>&1" || die "rivlogin failed for $host: $!\n"; + open(INPUT, "< $host.raw") || die "rivlogin failed for $host: $!\n"; + } else { + open(INPUT,"rivlogin -t $timeo -c \"$cisco_cmds\" $host ) { + tr/\015//d; + last if ($clean_run); + if (/^Error:/) { + print STDOUT ("$host rivlogin error: $_"); + print STDERR ("$host rivlogin error: $_") if ($debug); + $clean_run=0; + last; + } + + $kradcount++; + + while (/\033(\[\?25l)/) { + s/\033\[\?25l//g; + #print STDERR "krad $1\n"; + #print STDERR $_; + #print STDERR $kradcount; + next; + } + + + while (/#\s*($cmds_regexp)\s*$/) { + $cmd = $1; + if (!defined($prompt)) { + $prompt = ($_ =~ /^([^#]+#)/)[0]; + $prompt =~ s/([}{)(\\])/\\$1/g; + } + print STDERR ("HIT COMMAND:$_") if ($debug); + if (! defined($commands{$cmd})) { + print STDERR "$host: found unexpected command - \"$cmd\"\n"; + $clean_run = 0; + last TOP; + } + $rval = &{$commands{$cmd}}; + delete($commands{$cmd}); + if ($rval == -1) { + $clean_run = 0; + last TOP; + } + } +} +print STDOUT "Done $logincmd: $_\n" if ($log); +# Flush History +ProcessHistory("","","",""); +# Cleanup +close(INPUT); +close(OUTPUT); + +if (defined($ENV{NOPIPE})) { + unlink("$host.raw") if (! $debug); +} + +# check for completeness +if (scalar(%commands) || !$clean_run) { + if (scalar(%commands)) { + printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands))); + printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug); + } + if (!$clean_run) { + print STDOUT "$host: End of run not found\n"; + print STDERR "$host: End of run not found\n" if ($debug); + system("/usr/bin/tail -1 $host.new"); + } + unlink "$host.new" if (! $debug); +} diff --git a/bin/rrancid.in b/bin/rrancid.in old mode 100755 new mode 100644 index f242ec4..7674452 --- a/bin/rrancid.in +++ b/bin/rrancid.in @@ -1,28 +1,32 @@ -#!@PERLV_PATH@ +#! @PERLV_PATH@ ## -## hacked version of Hank's rancid - this one tries to deal with redbacks. +## $Id: rrancid.in,v 1.18 2004/01/11 03:49:13 heas Exp $ ## -## Copyright (C) 1997-2001 by Henry Kilmer. +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. ## All rights reserved. ## -## This software may be freely copied, modified and redistributed without -## fee for non-commerical purposes provided that this copyright notice is -## preserved intact on all copies and modified copies. +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. ## ## There is no warranty or other guarantee of fitness of this software. -## It is provided solely "as is". The author(s) disclaim(s) all +## It is provided solely "as is". The author(s) disclaim(s) all ## responsibility and liability with respect to this software's usage ## or its effect upon hardware, computer systems, other software, or ## anything else. ## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. ## # +# hacked version of Hank's rancid - this one tries to deal with redbacks. +# # RANCID - Really Awesome New Cisco confIg Differ # # usage: rancid [-d] [-l] [-f filename | $host] # use Getopt::Std; -getopts('dflm'); +getopts('dfl'); $log = $opt_l; $debug = $opt_d; $file = $opt_f; @@ -353,7 +357,8 @@ while() { $cmd = $1; if (!defined($prompt)) { $prompt = ($_ =~ /^([^#]*#)/)[0]; - $prompt =~ s/([][])/\\$1/g; # quote the damn []'s + $prompt =~ s/([][}{)(\\])/\\$1/g; # quote the damn []'s + print STDERR ("PROMPT MATCH: $prompt\n") if ($debug); } print STDERR ("HIT COMMAND:$_") if ($debug); if (! defined($commands{$cmd})) { diff --git a/bin/tntlogin.in b/bin/tntlogin.in new file mode 100644 index 0000000..021f0d2 --- /dev/null +++ b/bin/tntlogin.in @@ -0,0 +1,528 @@ +#! @EXPECT_PATH@ -- +## +## $Id: tntlogin.in,v 1.11 2004/01/11 05:39:15 heas Exp $ +## +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## All rights reserved. +## +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. +## +## There is no warranty or other guarantee of fitness of this software. +## It is provided solely "as is". The author(s) disclaim(s) all +## responsibility and liability with respect to this software's usage +## or its effect upon hardware, computer systems, other software, or +## anything else. +## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. +## +# +# The login expect scripts were based on Erik Sherk's gwtn, by permission. +# +# Modified by P B Matthews. + +# Usage line +set usage "Usage: $argv0 \[-c command\] \ +\[-Evar=x\] \[-f cloginrc-file\] \ +\[-s script-file\] \[-t timeout\] \[-u username\] \ +\[-v vty-password\] \[-x command-file\] \ +\[-y ssh_cypher_type\] router \[router...\]\n" + +# env(CLOGIN) may contain: +# x == do not set xterm banner or name + +# Password file +set password_file $env(HOME)/.cloginrc +# Default is to login to the router +set do_command 0 +set do_script 0 +# The default is to automatically enable +set enable 0 +# The default is that you login non-enabled (tacacs can have you login already +# enabled) +set avautoenable 1 +# The default is to look in the password file to find the passwords. This +# tracks if we receive them on the command line. +set do_passwd 1 + +# Find the user in the ENV, or use the unix userid. +if {[ info exists env(CISCO_USER) ] } { + set default_user $env(CISCO_USER) +} elseif {[ info exists env(USER) ]} { + set default_user $env(USER) +} elseif {[ info exists env(LOGNAME) ]} { + set default_user $env(LOGNAME) +} else { + # This uses "id" which I think is portable. At least it has existed + # (without options) on all machines/OSes I've been on recently - + # unlike whoami or id -nu. + if [ catch {exec id} reason ] { + send_error "\nError: could not exec id: $reason\n" + exit 1 + } + regexp {\(([^)]*)} "$reason" junk default_user +} + +# Sometimes routers take awhile to answer (the default is 10 sec) +set timeout 45 + +# Process the command line +for {set i 0} {$i < $argc} {incr i} { + set arg [lindex $argv $i] + + switch -glob -- $arg { + # Username + -u* - + -U* { + if {! [ regexp .\[uU\](.+) $arg ignore user]} { + incr i + set username [ lindex $argv $i ] + } + # VTY Password + } -v* - + -v* { + if {! [ regexp .\[vV\](.+) $arg ignore passwd]} { + incr i + set passwd [ lindex $argv $i ] + } + set do_passwd 0 + # Enable Username + } -w* - + -W* { + # ignore -w + # Environment variable to pass to -s scripts + } -E* + { + if {[ regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} { + incr i + set E$varname $varvalue + } else { + send_user "\nError: invalid format for -E in $arg\n" + exit 1 + } + # Enable Password + } -e* + { + # ignore -e + # Command to run. + } -c* - + -C* { + if {! [ regexp .\[cC\](.+) $arg ignore command]} { + incr i + set command [ lindex $argv $i ] + } + set do_command 1 + # Expect script to run. + } -s* - + -S* { + if {! [ regexp .\[sS\](.+) $arg ignore sfile]} { + incr i + set sfile [ lindex $argv $i ] + } + if { ! [ file readable $sfile ] } { + send_user "\nError: Can't read $sfile\n" + exit 1 + } + set do_script 1 + # 'ssh -c' cypher type + } -y* - + -Y* { + if {! [ regexp .\[eE\](.+) $arg ignore cypher]} { + incr i + set cypher [ lindex $argv $i ] + } + # alternate cloginrc file + } -f* - + -F* { + if {! [ regexp .\[fF\](.+) $arg ignore password_file]} { + incr i + set password_file [ lindex $argv $i ] + } + # Timeout + } -t* - + -T* { + if {! [ regexp .\[tT\](.+) $arg ignore timeout]} { + incr i + set timeout [ lindex $argv $i ] + } + # Command file + } -x* - + -X { + if {! [ regexp .\[xX\](.+) $arg ignore cmd_file]} { + incr i + set cmd_file [ lindex $argv $i ] + } + if [ catch {set cmd_fd [open $cmd_file r]} reason ] { + send_user "\nError: $reason\n" + exit 1 + } + set cmd_text [read $cmd_fd] + close $cmd_fd + set command [join [split $cmd_text \n] \;] + set do_command 1 + # Do we enable? + } -noenable { + # ignore -noenable + # Does tacacs automatically enable us? + } -autoenable { + # ignore -autoenable + } -* { + send_user "\nError: Unknown argument! $arg\n" + send_user $usage + exit 1 + } default { + break + } + } +} +# Process routers...no routers listed is an error. +if { $i == $argc } { + send_user "\nError: $usage" +} + +# Only be quiet if we are running a script (it can log its output +# on its own) +if { $do_script } { + log_user 0 +} else { + log_user 1 +} + +# +# Done configuration/variable setting. Now run with it... +# + +# Sets Xterm title if interactive...if its an xterm and the user cares +proc label { host } { + global env + # if CLOGIN has an 'x' in it, don't set the xterm name/banner + if [info exists env(CLOGIN)] { + if {[string first "x" $env(CLOGIN)] != -1} { return } + } + # take host from ENV(TERM) + if [info exists env(TERM)] { + if [regexp \^(xterm|vs) $env(TERM) ignore ] { + send_user "\033]1;[lindex [split $host "."] 0]\a" + send_user "\033]2;$host\a" + } + } +} + +# This is a helper function to make the password file easier to +# maintain. Using this the password file has the form: +# add password sl* pete cow +# add password at* steve +# add password * hanky-pie +proc add {var args} { global int_$var ; lappend int_$var $args} +proc include {args} { + global env + regsub -all "(^{|}$)" $args {} args + if { [ regexp "^/" $args ignore ] == 0 } { + set args $env(HOME)/$args + } + source_password_file $args +} + +proc find {var router} { + upvar int_$var list + if { [info exists list] } { + foreach line $list { + if { [string match [lindex $line 0] $router ] } { + return [lrange $line 1 end] + } + } + } + return {} +} + +# Loads the password file. Note that as this file is tcl, and that +# it is sourced, the user better know what to put in there, as it +# could install more than just password info... I will assume however, +# that a "bad guy" could just as easy put such code in the clogin +# script, so I will leave .cloginrc as just an extention of that script +proc source_password_file { password_file } { + global env + if { ! [file exists $password_file] } { + send_user "\nError: password file ($password_file) does not exist\n" + exit 1 + } + file stat $password_file fileinfo + if { [expr ($fileinfo(mode) & 007)] != 0000 } { + send_user "\nError: $password_file must not be world readable/writable\n" + exit 1 + } + if [ catch {source $password_file} reason ] { + send_user "\nError: $reason\n" + exit 1 + } +} + +# Log into the router. +proc login { router user userpswd passwd prompt cmethod cyphertype } { + global spawn_id in_proc do_command do_script + global u_prompt p_prompt sshcmd + set in_proc 1 + set uprompt_seen 0 + + # try each of the connection methods in $cmethod until one is successful + set progs [llength $cmethod] + foreach prog [lrange $cmethod 0 end] { + if [string match "telnet*" $prog] { + regexp {telnet(:([^[:space:]]+))*} $prog command suffix port + if {"$port" == ""} { + set retval [ catch {spawn telnet $router} reason ] + } else { + set retval [ catch {spawn telnet $router $port} reason ] + } + if { $retval } { + send_user "\nError: telnet failed: $reason\n" + exit 1 + } + } elseif ![string compare $prog "ssh"] { + if [ catch {spawn $sshcmd -c $cyphertype -x -l $user $router} reason ] { + send_user "\nError: $sshcmd failed: $reason\n" + exit 1 + } + } elseif ![string compare $prog "rsh"] { + if [ catch {spawn rsh -l $user $router} reason ] { + send_user "\nError: rsh failed: $reason\n" + exit 1 + } + } else { + puts "\nError: unknown connection method: $prog" + return 1 + } + incr progs -1 + sleep 0.3 + + # This helps cleanup each expect clause. + expect_after { + timeout { + send_user "\nError: TIMEOUT reached\n" + catch {close}; wait + if { $in_proc} { + return 1 + } else { + continue + } + } eof { + send_user "\nError: EOF received\n" + catch {close}; wait + if { $in_proc} { + return 1 + } else { + continue + } + } + } + + expect { + "Connection refused" { + close; wait + sleep 0.3 + expect eof + send_user "\nError: Connection Refused\n"; wait; return 1 + } eof { send_user "\nError: Couldn't login\n"; wait; return 1 + } "Unknown host\r\n" { + expect eof + send_user "\nError: Unknown host\n"; wait; return 1 + } "Host is unreachable" { + expect eof + send_user "\nError: Host Unreachable!\n"; wait; return 1 + } "No address associated with name" { + expect eof + send_user "\nError: Unknown host\n"; wait; return 1 + } + -re "(Host key not found |The authenticity of host .* be established).*\(yes\/no\)\?" { + send "yes\r" + send_user "\nHost $router added to the list of known hosts.\n" + exp_continue } + -re "HOST IDENTIFICATION HAS CHANGED.* \(yes\/no\)\?" { + send "no\r" + send_user "\nError: The host key for $router has changed. Update the SSH known_hosts file accordingly.\n" + return 1 } + -re "Offending key for .* \(yes\/no\)\?" { + send "no\r" + send_user "\nError: host key mismatch for $router. Update the SSH known_hosts file accordingly.\n" + return 1 } + + -re "$u_prompt" { + send "$user\r" + set uprompt_seen 1 + exp_continue + } + -re "$p_prompt" { + sleep 1 + if {$uprompt_seen == 1} { + send "$userpswd\r" + } else { + send "$passwd\r" + } + exp_continue + } + -re "^Confirm seeing above note" { + send "y\r" + exp_continue + } + "Password incorrect" { send_user "\nError: Check your password for $router\n"; + catch {close}; wait; return 1 } + -re "$prompt" { break; } + denied { send_user "\nError: Check your passwd for $router\n" + catch {close}; wait; return 1 + } + "\r\n" { exp_continue; } + } + } + set in_proc 0 + return 0 +} + +# Run commands given on the command line. +proc run_commands { prompt command } { + global in_proc + set in_proc 1 + + send "lines 0\r" + expect -re $prompt {} + regsub -all "\[)(]" $prompt {\\&} reprompt + + # Is this a multi-command? + if [ string match "*\;*" "$command" ] { + set commands [split $command \;] + set num_commands [llength $commands] + for {set i 0} {$i < $num_commands} { incr i} { + send "[subst -nocommands [lindex $commands $i]]\r" + expect { + -re "^\[^\n\r]*$reprompt" {} + -re "^\[^\n\r ]*>>.*$reprompt" { exp_continue } + -re "\[\n\r]+" { exp_continue } + } + } + } else { + send "[subst -nocommands $command]\r" + send "y\r" + expect { + -re "^\[^\n\r]*$reprompt" {} + -re "^\[^\n\r ]*>>.*$reprompt" { exp_continue } + -re "\[\n\r]+" { exp_continue } + } + } + + send "quit\r" +# expect { +# -re "^WARNING: the current user has insufficient rights to view password fields. A configuration saved under this circumstance should not be used to restore profiles containing passwords. Save anyway? [y/n]" +# { +# send "y\r" + exp_continue + } + "\n" { exp_continue } + "\[^\n\r *]*Session terminated" { return 0 } + timeout { return 0 } + eof { return 0 } + } + set in_proc 0 +} + +# +# For each router... (this is main loop) +# +source_password_file $password_file +set in_proc 0 +foreach router [lrange $argv $i end] { + set router [string tolower $router] + send_user "$router\n" + + # Figure out prompt. + set prompt "admin>" + # TNT only "enables" based on the password used at login time + set autoenable 1 + set enable 0 + + # Figure out passwords + if { $do_passwd } { + set pswd [find password $router] + if { [llength $pswd] == 0 } { + send_user "\nError - no password for $router in $password_file.\n" + continue + } + set passwd [join [lindex $pswd 0] ""] + } + + # Figure out username + if {[info exists username]} { + # command line username + set ruser $username + } else { + set ruser [join [find user $router] ""] + if { "$ruser" == "" } { set ruser $default_user } + } + + # Figure out username's password (if different from the vty password) + if {[info exists userpasswd]} { + # command line username + set userpswd $userpasswd + } else { + set userpswd [join [find userpassword $router] ""] + if { "$userpswd" == "" } { set userpswd $passwd } + } + + # Figure out prompts + set u_prompt [find userprompt $router] + if { "$u_prompt" == "" } { + set u_prompt "(User|Username|login| Login):" + } else { + set u_prompt [join [lindex $u_prompt 0] ""] + } + + set p_prompt [find passprompt $router] + if { "$p_prompt" == "" } { + set p_prompt "\[Pp]assword:" + } else { + set p_prompt [join [lindex $p_prompt 0] ""] + } + + # Figure out cypher type + if {[info exists cypher]} { + # command line cypher type + set cyphertype $cypher + } else { + set cyphertype [find cyphertype $router] + if { "$cyphertype" == "" } { set cyphertype "3des" } + } + + # Figure out connection method + set cmethod [find method $router] + if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} } + + # Figure out the SSH executable name + set sshcmd [find sshcmd $router] + if { "$sshcmd" == "" } { set sshcmd {ssh} } + + # Login to the router + if {[login $router $ruser $userpswd $passwd $prompt $cmethod $cyphertype]} { + continue + } + + if { $do_command } { + if {[run_commands $prompt $command]} { + continue + } + } elseif { $do_script } { +# send "lines 0\r" + expect -re $prompt {} + source $sfile + send "y\r" + close + } else { + label $router + log_user 1 + interact + } + + # End of for each router + wait + sleep 0.3 +} +exit 0 diff --git a/bin/tntrancid.in b/bin/tntrancid.in new file mode 100644 index 0000000..88520fd --- /dev/null +++ b/bin/tntrancid.in @@ -0,0 +1,292 @@ +#! @PERLV_PATH@ +## +## $Id: tntrancid.in,v 1.8 2004/01/11 03:49:13 heas Exp $ +## +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## All rights reserved. +## +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. +## +## There is no warranty or other guarantee of fitness of this software. +## It is provided solely "as is". The author(s) disclaim(s) all +## responsibility and liability with respect to this software's usage +## or its effect upon hardware, computer systems, other software, or +## anything else. +## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. +## +# +# Modified by Paul B Matthews & Richard Vander Reyden. +# I'm suprised it still works.... +# +# RANCID - Really Awesome New Cisco confIg Differ +# +# usage: tntrancid [-d] [-l] [-f filename | $host] +# +use Getopt::Std; +getopts('dfl'); +$log = $opt_l; +$debug = $opt_d; +$file = $opt_f; +$host = $ARGV[0]; +$clean_run = 0; +$found_end = 0; +$timeo = 90; # tntlogin timeout in seconds +$prompt = "admin> "; +$always_y = "y"; # cause its a pain. + +my(%filter_pwds); # password filtering mode + +# This routine is used to print out the router configuration +sub ProcessHistory { + my($new_hist_tag,$new_command,$command_string,@string)=(@_); + if((($new_hist_tag ne $hist_tag) || ($new_command ne $command)) + && defined %history) { + print eval "$command \%history"; + print eval "$always_y \%history"; + undef %history; + } + if (($new_hist_tag) && ($new_command) && ($command_string)) { + if ($history{$command_string}) { + $history{$command_string} = "$history{$command_string}@string"; + } else { + $history{$command_string} = "@string"; + } + } elsif (($new_hist_tag) && ($new_command)) { + $history{++$#history} = "@string"; + } else { + print "@string"; + } + $hist_tag = $new_hist_tag; + $command = $new_command; + 1; +} + +sub numerically { $a <=> $b; } + +# This is a sort routing that will sort numerically on the +# keys of a hash as if it were a normal array. +sub keynsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort numerically keys(%lines)) { + $sorted_lines[$i] = $lines{$key}; + $i++; + } + @sorted_lines; +} + +# This is a sort routing that will sort on the +# keys of a hash as if it were a normal array. +sub keysort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort keys(%lines)) { + $sorted_lines[$i] = $lines{$key}; + $i++; + } + @sorted_lines; +} + +# This is a sort routing that will sort on the +# values of a hash as if it were a normal array. +sub valsort{ + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort values %lines) { + $sorted_lines[$i] = $key; + $i++; + } + @sorted_lines; +} + +# This is a numerical sort routing (ascending). +sub numsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $num (sort {$a <=> $b} keys %lines) { + $sorted_lines[$i] = $lines{$num}; + $i++; + } + @sorted_lines; +} + +# This is a sort routine that will sort on the +# ip address when the ip address is anywhere in +# the strings. +sub ipsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $addr (sort sortbyipaddr keys %lines) { + $sorted_lines[$i] = $lines{$addr}; + $i++; + } + @sorted_lines; +} + +# These two routines will sort based upon IP addresses +sub ipaddrval { + my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#); + $a[3]+256*($a[2]+256*($a[1]+256*$a[0])); +} +sub sortbyipaddr { + &ipaddrval($a) <=> &ipaddrval($b); +} + + +# This routine processes a "save con" +sub SaveConf { + print STDERR " In SaveConf: $_" if ($debug); + my($comment) = 1; # strip extra comments, esp to preserve chassis type + + while () { + tr/\015//d; + last if(/^$prompt/); +# next if(/^\s*$/); + +### s/^\s*$/;/; + +# Leave software revision, but strip out saved date, +# which causes rancid to think it changes each poll + + if (/^; saved from /) { + ProcessHistory("","","","$_"); + next; + } + /^; saved / && next; + + # catch anything that wasnt match above. + ProcessHistory("","","","$_"); + # end of config +# if (/^# End of configuration file/i) { + if (/; profiles saved$/) { + printf STDERR " End SaveConf: $_" if ($debug); + $found_end = 1; + print STDOUT "$found_end = found_end within test\n"; + return(1); + } + $found_end = 1; +#### print STDOUT "$found_end = found_end at test\n"; + } + $found_end = 1; + return(0); +} +$found_end = 1; +print STDOUT "$found_end = found_end at end test\n"; + + + + +# dummy function +sub DoNothing {print STDOUT;} + +# Main +%commands=( + 'save con' => "SaveConf" +); +# keys() doesnt return things in the order entered and the order of the +# cmds is important (show version first and write term last). pita +@commands=( + "save con" +); +$tnt_cmds=join(";",@commands); +$cmds_regexp=join("|",@commands); +$tnt_cmds="save con"; + +open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; +select(OUTPUT); +# make OUTPUT unbuffered if debugging +if ($debug) { $| = 1; } + +if ($file) { + print STDERR "opening file $host\n" if ($debug); + print STDOUT "opening file $host\n" if ($log); + open(INPUT,"<$host") || die "open failed for $host: $!\n"; +} else { + print STDERR "executing tntlogin -t $timeo -c\"$tnt_cmds\" $host\n" if ($debug); + print STDOUT "executing tntlogin -t $timeo -c\"$tnt_cmds\" $host\n" if ($log); + if (defined($ENV{NOPIPE})) { + system "tntlogin -t $timeo -c \"$tnt_cmds\" $host $host.raw 2>&1" || die "tntlogin failed for $host: $!\n"; + open(INPUT, "< $host.raw") || die "tntlogin failed for $host: $!\n"; + } else { + open(INPUT,"tntlogin -t $timeo -c \"$tnt_cmds\" $host ) { + tr/\015//d; + + if (/^Error:/) { + print STDOUT ("$host tntlogin error: $_"); + print STDERR ("$host tntlogin error: $_") if ($debug); + $clean_run=0; + last; + } + while (/$prompt\s*($cmds_regexp)\s*$/) { + $cmd = $1; + if (!defined($prompt)) { + $prompt = ($_ =~ /^([^#]+#)/)[0]; + $prompt =~ s/([][}{)(\\])/\\$1/g; + $prompt =~ s/:(\d+ ?)#/:\\d+ ?#/; + print STDERR ("PROMPT MATCH: $prompt\n") if ($debug); + } + print STDERR ("HIT COMMAND:$_") if ($debug); + if (! defined($commands{$cmd})) { + print STDERR "$host: found unexpected command - \"$cmd\"\n"; + $clean_run = 0; + last TOP; + } + $rval = &{$commands{$cmd}}; + delete($commands{$cmd}); + if ($rval == -1) { + printf STDERR "rval = -1\n" if ($debug); + $clean_run = 0; + last TOP; + } + } +} +print STDOUT "Done $logincmd: $_\n" if ($log); +# Flush History +ProcessHistory("","","",""); +# Cleanup +$clean_run = 1; +print STDOUT "$clean_run - clean\n"; +close(INPUT); +close(OUTPUT); + +if (defined($ENV{NOPIPE})) { + unlink("$host.raw") if (! $debug); +} + +# check for completeness +if (scalar(%commands) || !$clean_run || !$found_end) { + if (scalar(%commands)) { + printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands))); + printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug); + } + if (!$clean_run || !$found_end) { + print STDOUT "$host: End of run not found\n"; + print STDERR "$host: End of run not found\n" if ($debug); + system("/usr/bin/tail -1 $host.new"); + } + unlink "$host.new" if (! $debug); +} diff --git a/bin/xrancid.in b/bin/xrancid.in old mode 100755 new mode 100644 index 06ff30b..4aeb1d3 --- a/bin/xrancid.in +++ b/bin/xrancid.in @@ -1,19 +1,22 @@ -#!@PERLV_PATH@ +#! @PERLV_PATH@ ## +## $Id: xrancid.in,v 1.32 2004/01/11 03:49:13 heas Exp $ ## -## Copyright (C) 1997-2001 by Henry Kilmer. +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. ## All rights reserved. ## -## This software may be freely copied, modified and redistributed without -## fee for non-commerical purposes provided that this copyright notice is -## preserved intact on all copies and modified copies. +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. ## ## There is no warranty or other guarantee of fitness of this software. -## It is provided solely "as is". The author(s) disclaim(s) all +## It is provided solely "as is". The author(s) disclaim(s) all ## responsibility and liability with respect to this software's usage ## or its effect upon hardware, computer systems, other software, or ## anything else. ## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. ## # # RANCID - Really Awesome New Cisco confIg Differ @@ -21,7 +24,7 @@ # usage: rancid [-d] [-l] [-f filename | $host] # use Getopt::Std; -getopts('dflm'); +getopts('dfl'); $log = $opt_l; $debug = $opt_d; $file = $opt_f; @@ -272,10 +275,14 @@ sub WriteTerm { tr/\015//d; last if(/^$prompt/); next if(/^\s*$/); + return(0) if(/^syntax error at token /i); # the pager can not be disabled per-session on the PIX s/^<-+ More -+>\s*//; + return(0) if ($found_end); s/^\s*$/#/; + next if (/full detail configuration/i); + # filter extra comments and lead comments in config so we can preserve # the chassis type at the top of muched o/p before the process history # key changes. @@ -291,7 +298,7 @@ sub WriteTerm { # Dog gone Cool matches to process the rest of the config # some chassis report their chassis type in show diag...oh, but - # other noooo. grab it here, if available. so, nothing else + # others do not. grab it here, if available. so, nothing else # can change the keysort key until this is grabbed. sigh. /# (\S+) configuration generated/i && ProcessHistory("COMMENTS","keysort","A0","#Chassis type: $1\n") && @@ -301,11 +308,11 @@ sub WriteTerm { /# software version/i && next; if (/((create|configure) account \S+ \S+) / && $filter_pwds >= 2) { - ProcessHistory("","","","# $1 \n"); + ProcessHistory("COMMENTS","keysort","H0","# $1 \n"); next; } if (/configure ssh2 key/ && $filter_pwds >= 1) { - ProcessHistory("","","","# $_# \n"); + ProcessHistory("COMMENTS","keysort","H0","# $_# \n"); while () { if (/^(#|enable|conf|disable|unconf)/) { tr/\015//d; @@ -317,7 +324,7 @@ sub WriteTerm { # filter out any RCS/CVS tags to avoid confusing local CVS storage s/\$(Revision|Id):/ $1:/; if (/^((config|configure) bgp (neighbor|peer-group) \S+ password encrypted)/i && $filter_pwds >= 1) { - ProcessHistory("","","","# $1 \n"); + ProcessHistory("COMMENTS","keysort","H0","# $1 \n"); next; } @@ -346,17 +353,17 @@ sub WriteTerm { } # order/prune tacacs/radius server statements if (/^(configure radius (primary|secondary) (tacacs-server|radius-server) shared-secret encrypted)/ && $filter_pwds >= 1) { - ProcessHistory("","","","# $1 \n"); + ProcessHistory("COMMENTS","keysort","H0","# $1 \n"); next; } # catch anything that wasnt match above. - ProcessHistory("","","","$_"); + ProcessHistory("COMMENTS","keysort","H0","$_"); # end of config if (/^# End of configuration file/i) { printf STDERR " End WriteTerm: $_" if ($debug); $found_end = 1; - return(1); + return(0); } } return(0); @@ -367,12 +374,13 @@ sub DoNothing {print STDOUT;} # Main %commands=( - 'show version' => "ShowVersion", - 'show memory' => "ShowMemory", - 'show diagnostics' => "ShowDiag", - 'show switch' => "ShowSwitch", - 'show slot' => "ShowSlot", - 'show configuration' => "WriteTerm" + 'show version' => "ShowVersion", + 'show memory' => "ShowMemory", + 'show diagnostics' => "ShowDiag", + 'show switch' => "ShowSwitch", + 'show slot' => "ShowSlot", + 'show configuration detail' => "WriteTerm", + 'show configuration' => "WriteTerm" ); # keys() doesnt return things in the order entered and the order of the # cmds is important (show version first and write term last). pita @@ -382,6 +390,7 @@ sub DoNothing {print STDOUT;} "show diagnostics", "show switch", "show slot", + "show configuration detail", "show configuration" ); $cisco_cmds=join(";",@commands); @@ -397,13 +406,13 @@ if ($file) { print STDOUT "opening file $host\n" if ($log); open(INPUT,"<$host") || die "open failed for $host: $!\n"; } else { - print STDERR "executing clogin -t $timeo -autoenable -c\"$cisco_cmds\" $host\n" if ($debug); - print STDOUT "executing clogin -t $timeo -autoenable -c\"$cisco_cmds\" $host\n" if ($log); + print STDERR "executing clogin -t $timeo -c \"$cisco_cmds\" $host\n" if ($debug); + print STDOUT "executing clogin -t $timeo -c \"$cisco_cmds\" $host\n" if ($log); if (defined($ENV{NOPIPE})) { - system "clogin -t $timeo -autoenable -c \"$cisco_cmds\" $host $host.raw 2>&1" || die "clogin failed for $host: $!\n"; + system "clogin -t $timeo -c \"$cisco_cmds\" $host $host.raw 2>&1" || die "clogin failed for $host: $!\n"; open(INPUT, "< $host.raw") || die "clogin failed for $host: $!\n"; } else { - open(INPUT,"clogin -t $timeo -autoenable -c \"$cisco_cmds\" $host ) { tr/\015//d; # note: this match sucks rocks, but currently the extreme bits are # unreliable about echoing the 'exit\n' command. this match might really # be a bad idea, but instead rely upon WriteTerm's found_end? - if (/$prompt\s?(quit|exit|Connection closed)/ && $found_end) { + if (/$prompt\s?(quit|exit|Connection( to \S+)? closed)/ && $found_end) { $clean_run=1; last; } @@ -442,8 +452,10 @@ TOP: while() { $cmd = $1; if (!defined($prompt)) { $prompt = ($_ =~ /^([^#]+#)/)[0]; + $prompt =~ s/([][}{)(\\])/\\$1/g; $prompt =~ s/:(\d+ ?)#/:\\d+ ?#/; - print STDERR ("PROMPT MATCH:$prompt\n") if ($debug); + $prompt =~ s/\*/\\\*/; + print STDERR ("PROMPT MATCH: $prompt\n") if ($debug); } print STDERR ("HIT COMMAND:$_") if ($debug); if (! defined($commands{$cmd})) { diff --git a/bin/zrancid.in b/bin/zrancid.in new file mode 100755 index 0000000..a969553 --- /dev/null +++ b/bin/zrancid.in @@ -0,0 +1,411 @@ +#! @PERLV_PATH@ +## +## $Id: zrancid.in,v 1.8 2004/01/11 03:49:13 heas Exp $ +## +## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## All rights reserved. +## +## This software may be freely copied, modified and redistributed +## without fee for non-commerical purposes provided that this license +## remains intact and unmodified with any RANCID distribution. +## +## There is no warranty or other guarantee of fitness of this software. +## It is provided solely "as is". The author(s) disclaim(s) all +## responsibility and liability with respect to this software's usage +## or its effect upon hardware, computer systems, other software, or +## anything else. +## +## Except where noted otherwise, rancid was written by and is maintained by +## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. +## +# +# This version of rancid tries to deal with zebra s/w. +# +# RANCID - Really Awesome New Cisco confIg Differ +# +# usage: rancid [-d] [-l] [-f filename | $host] +# +use Getopt::Std; +getopts('dfl'); +$log = $opt_l; +$debug = $opt_d; +$file = $opt_f; +$host = $ARGV[0]; +$clean_run = 0; +$found_end = 0; +$timeo = 90; # clogin timeout in seconds + +my(%filter_pwds); # password filtering mode + +# This routine is used to print out the router configuration +sub ProcessHistory { + my($new_hist_tag,$new_command,$command_string,@string)=(@_); + if((($new_hist_tag ne $hist_tag) || ($new_command ne $command)) + && defined %history) { + print eval "$command \%history"; + undef %history; + } + if (($new_hist_tag) && ($new_command) && ($command_string)) { + if ($history{$command_string}) { + $history{$command_string} = "$history{$command_string}@string"; + } else { + $history{$command_string} = "@string"; + } + } elsif (($new_hist_tag) && ($new_command)) { + $history{++$#history} = "@string"; + } else { + print "@string"; + } + $hist_tag = $new_hist_tag; + $command = $new_command; + 1; +} + +sub numerically { $a <=> $b; } + +# This is a sort routing that will sort numerically on the +# keys of a hash as if it were a normal array. +sub keynsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort numerically keys(%lines)) { + $sorted_lines[$i] = $lines{$key}; + $i++; + } + @sorted_lines; +} + +# This is a sort routing that will sort on the +# keys of a hash as if it were a normal array. +sub keysort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort keys(%lines)) { + $sorted_lines[$i] = $lines{$key}; + $i++; + } + @sorted_lines; +} + +# This is a sort routing that will sort on the +# values of a hash as if it were a normal array. +sub valsort{ + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort values %lines) { + $sorted_lines[$i] = $key; + $i++; + } + @sorted_lines; +} + +# This is a numerical sort routing (ascending). +sub numsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $num (sort {$a <=> $b} keys %lines) { + $sorted_lines[$i] = $lines{$num}; + $i++; + } + @sorted_lines; +} + +# This is a sort routine that will sort on the +# ip address when the ip address is anywhere in +# the strings. +sub ipsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $addr (sort sortbyipaddr keys %lines) { + $sorted_lines[$i] = $lines{$addr}; + $i++; + } + @sorted_lines; +} + +# These two routines will sort based upon IP addresses +sub ipaddrval { + my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#); + $a[3]+256*($a[2]+256*($a[1]+256*$a[0])); +} +sub sortbyipaddr { + &ipaddrval($a) <=> &ipaddrval($b); +} + +# This routine parses "show version" +sub ShowVersion { + print STDERR " In ShowVersion: $_" if ($debug); + + while () { + tr/\015//d; + last if(/^$prompt/); + next if(/^(\s*|\s*$cmd\s*)$/); + return(-1) if (/command authorization failed/i); + + ProcessHistory("COMMENTS","keysort","B0", "!$_") && next; + + } + return(0); +} + +# This routine processes a "write term" +sub WriteTerm { + print STDERR " In WriteTerm: $_" if ($debug); + + while () { + tr/\015//d; + last if(/^$prompt/); + return(-1) if (/command authorization failed/i); + + /Non-Volatile memory is in use/ && return(-1); # NvRAM is locked + # skip the crap + if (/^(##+$|(Building|Current) configuration)/i) { + while () { + next if (/^Current configuration\s*:/i); + next if (/^([%!].*|\s*)$/); + last; + } + tr/\015//d; + } + # some versions have other crap mixed in with the bits in the + # block above + /^! Last Changed:/ && next; + + # Dog gone Cool matches to process the rest of the config +# /^tftp-server flash / && next; # kill any tftp remains +# /^ntp clock-period / && next; # kill ntp clock-period +# /^ length / && next; # kill length on serial lines +# /^ width / && next; # kill width on serial lines +# /^ clockrate / && next; # kill clockrate on serial interfaces + + if (/^(enable password( \d)?) / && $filter_pwds >= 1) { + ProcessHistory("ENABLE","","","!$1 \n"); + next; + } + if (/^username (\S+)(\s.*)? password ((\d) \S+|\S+)/) { + if ($filter_pwds == 2) { + ProcessHistory("USER","keysort","$1","!username $1$2 password \n"); + } elsif ($filter_pwds == 1 && $4 ne "5"){ + ProcessHistory("USER","keysort","$1","!username $1$2 password \n"); + } else { + ProcessHistory("USER","keysort","$1","$_"); + } + next; + } + + # prune passwords {bgp, ...} + if (/^\s*neighbor (\S*) password / && $filter_pwds >= 1) { + ProcessHistory("","","","! neighbor $1 password \n"); + next; + } + # sort route-maps + if (/^route-map (\S+)/) { + my($key) = $1; + my($routemap) = $_; + while () { + tr/\015//d; + last if (/^$prompt/ || ! /^(route-map |[ !])/); + if (/^route-map (\S+)/) { + ProcessHistory("ROUTEMAP","keysort","$key","$routemap"); + $key = $1; + $routemap = $_; + } else { + $routemap .= $_; + } + } + ProcessHistory("ROUTEMAP","keysort","$key","$routemap"); + } + + # filter out any RCS/CVS tags to avoid confusing local CVS storage + s/\$(Revision|Id):/ $1:/; + + # order access-lists + /^access-list\s+(\d\d?)\s+(\S+)\s+(\S+)/ && + ProcessHistory("ACL $1 $2","ipsort","$3","$_") && next; + + # order logging statements + /^logging (\d+\.\d+\.\d+\.\d+)/ && + ProcessHistory("LOGGING","ipsort","$1","$_") && next; + + # order/prune snmp-server host statements + # we only prune lines of the form + # snmp-server host a.b.c.d + if (/^snmp-server host (\d+\.\d+\.\d+\.\d+) /) { + if (defined($ENV{'NOCOMMSTR'})) { + my($ip) = $1; + my($line) = "snmp-server host $ip"; + my(@tokens) = split(' ', $'); + my($token); + while ($token = shift(@tokens)) { + if ($token eq 'version') { + $line .= " " . join(' ', ($token, shift(@tokens))); + } elsif ($token =~ /^(informs?|traps?|(no)?auth)$/) { + $line .= " " . $token; + } else { + $line = "!$line " . join(' ', ("", join(' ',@tokens))); + last; + } + } + ProcessHistory("SNMPSERVERHOST","ipsort","$ip","$line\n"); + } else { + ProcessHistory("SNMPSERVERHOST","ipsort","$1","$_"); + } + next; + } + if (/^(snmp-server community) (\S+)/) { + if (defined($ENV{'NOCOMMSTR'})) { + ProcessHistory("SNMPSERVERCOMM","keysort","$_","!$1 $'") && next; + } else { + ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && next; + } + } + + # prune tacacs/radius server keys + if (/^(tacacs-server|radius-server) key / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 key \n"); next; + } + if (/^(tacacs-server host \S+( .*)? key) (\d )?\S+/ + && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); next; + } + + # order clns host statements +# /^clns host \S+ (\S+)/ && +# ProcessHistory("CLNS","keysort","$1","$_") && next; + + # prune isis password + if (/^( isis authentication-key) \d \S+/ && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 $'"); next; + } + # prune msdp password + if (/^(ip msdp password \S+) / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); next; + } + +# # order ip host line statements +# /^ip host line(\d+)/ && +# ProcessHistory("IPHOST","numsort","$1","$_") && next; + + # catch anything that wasnt matched above. + ProcessHistory("","","","$_"); + # end of config. + if (/^end$/) { + $found_end = 1; + return(1); + } + } + return(0); +} + +# dummy function +sub DoNothing {print STDOUT;} + +# Main +%commands=( + 'show version' => "ShowVersion", + 'write term' => "WriteTerm" +); +# keys() doesnt return things in the order entered and the order of the +# cmds is important (show version first and write term last). pita +@commands=( + "show version", + "write term" +); +$cisco_cmds=join(";",@commands); +$cmds_regexp=join("|",@commands); + +open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; +select(OUTPUT); +# make OUTPUT unbuffered if debugging +if ($debug) { $| = 1; } + +if ($file) { + print STDERR "opening file $host\n" if ($debug); + print STDOUT "opening file $host\n" if ($log); + open(INPUT,"<$host") || die "open failed for $host: $!\n"; +} else { + print STDERR "executing clogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($debug); + print STDOUT "executing clogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($log); + if (defined($ENV{NOPIPE})) { + system "clogin -t $timeo -c \"$cisco_cmds\" $host $host.raw 2>&1" || die "clogin failed for $host: $!\n"; + open(INPUT, "< $host.raw") || die "clogin failed for $host: $!\n"; + } else { + open(INPUT,"clogin -t $timeo -c \"$cisco_cmds\" $host ) { + tr/\015//d; + if (/\#\s?exit$/) { + $clean_run=1; + last; + } + if (/^Error:/) { + print STDOUT ("$host clogin error: $_"); + print STDERR ("$host clogin error: $_") if ($debug); + $clean_run=0; + last; + } + while (/#\s*($cmds_regexp)\s*$/) { + $cmd = $1; + if (!defined($prompt)) { + $prompt = ($_ =~ /^([^#]+#)/)[0]; + $prompt =~ s/([][}{)(\\])/\\$1/g; + } + print STDERR ("HIT COMMAND:$_") if ($debug); + if (! defined($commands{$cmd})) { + print STDERR "$host: found unexpected command - \"$cmd\"\n"; + $clean_run = 0; + last TOP; + } + $rval = &{$commands{$cmd}}; + delete($commands{$cmd}); + if ($rval == -1) { + $clean_run = 0; + last TOP; + } + } +} +print STDOUT "Done $logincmd: $_\n" if ($log); +# Flush History +ProcessHistory("","","",""); +# Cleanup +close(INPUT); +close(OUTPUT); + +if (defined($ENV{NOPIPE})) { + unlink("$host.raw") if (! $debug); +} + +# check for completeness +if (scalar(%commands) || !$clean_run || !$found_end) { + if (scalar(%commands)) { + printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands))); + printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug); + } + if (!$clean_run || !$found_end) { + print STDOUT "$host: End of run not found\n"; + print STDERR "$host: End of run not found\n" if ($debug); + system("/usr/bin/tail -1 $host.new"); + } + unlink "$host.new" if (! $debug); +} -- cgit