diff options
Diffstat (limited to 'bin')
46 files changed, 4736 insertions, 2340 deletions
diff --git a/bin/Makefile.am b/bin/Makefile.am index 21fac52..b7fc75f 100644 --- a/bin/Makefile.am +++ b/bin/Makefile.am @@ -1,9 +1,9 @@ ## Process this file with automake to produce Makefile.in ## A Makefile.in is supplied, in case you do not have automake. -## $Id: Makefile.am,v 1.28 2004/01/11 07:15:23 hank Exp $ +## $Id: Makefile.am,v 1.36 2007/01/13 22:01:53 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -25,12 +25,12 @@ AUTOMAKE_OPTIONS=foreign bin_PROGRAMS = hpuifilter bin_SCRIPTS = cat5rancid control_rancid \ - alogin arancid clogin blogin brancid cssrancid \ + agmrancid alogin arancid blogin brancid clogin cssrancid \ elogin erancid f10rancid flogin francid fnrancid \ - jlogin jrancid jerancid \ hlogin hrancid htlogin htrancid \ + jerancid jlogin jrancid \ mrancid nlogin nrancid nslogin nsrancid par prancid \ - rancid rancid-fe rivlogin rivrancid rrancid \ + rancid rancid-fe rivlogin rivrancid rrancid srancid \ tntlogin tntrancid xrancid zrancid bin_SCRIPTS += lg.cgi lgform.cgi rancid-cvs rancid-run @@ -73,7 +73,9 @@ auto_edit = sed \ -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' + -e 's,@MAILPLUS\@,$(MAILPLUS),g' \ + -e 's,@PACKAGE\@,$(PACKAGE),g' \ + -e 's,@VERSION\@,$(VERSION),g' lg.cgi: Makefile $(srcdir)/lg.cgi.in rm -f lg.cgi lg.cgi.tmp; \ diff --git a/bin/Makefile.in b/bin/Makefile.in index eedc795..ca80b2a 100644 --- a/bin/Makefile.in +++ b/bin/Makefile.in @@ -1,8 +1,8 @@ -# Makefile.in generated by automake 1.8 from Makefile.am. +# Makefile.in generated by automake 1.10 from Makefile.am. # @configure_input@ -# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 -# Free Software Foundation, Inc. +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006 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. @@ -15,17 +15,11 @@ @SET_MAKE@ -SOURCES = $(hpuifilter_SOURCES) - -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ -top_builddir = .. am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -INSTALL = @INSTALL@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c @@ -40,22 +34,23 @@ 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)/agmrancid.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 + $(srcdir)/rrancid.in $(srcdir)/srancid.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 @@ -63,13 +58,13 @@ 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) +CONFIG_CLEAN_FILES = control_rancid par rancid-fe agmrancid 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 srancid tntlogin tntrancid xrancid zrancid +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(bin_PROGRAMS) am_hpuifilter_OBJECTS = hpuifilter.$(OBJEXT) @@ -77,10 +72,9 @@ hpuifilter_OBJECTS = $(am_hpuifilter_OBJECTS) hpuifilter_LDADD = $(LDADD) binSCRIPT_INSTALL = $(INSTALL_SCRIPT) SCRIPTS = $(bin_SCRIPTS) -DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/include +DEFAULT_INCLUDES = -I. -I$(top_builddir)/include@am__isrc@ 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) @@ -92,8 +86,6 @@ 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@ @@ -128,6 +120,7 @@ EXPECT_PATH = @EXPECT_PATH@ FIND = @FIND@ GREP = @GREP@ ID = @ID@ +INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ @@ -141,6 +134,7 @@ MAILPLUS = @MAILPLUS@ MAKE = @MAKE@ MAKEINFO = @MAKEINFO@ MKDIR = @MKDIR@ +MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ @@ -152,6 +146,7 @@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERLV = @PERLV@ PERLV_PATH = @PERLV_PATH@ PING_PATH = @PING_PATH@ +RCSSYS = @RCSSYS@ RSH = @RSH@ SENDMAIL = @SENDMAIL@ SET_MAKE = @SET_MAKE@ @@ -159,50 +154,63 @@ SHELL = @SHELL@ SORT = @SORT@ SSH = @SSH@ STRIP = @STRIP@ +SVN = @SVN@ TAR = @TAR@ TELNET = @TELNET@ TOUCH = @TOUCH@ U = @U@ VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ 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@ +am__tar = @am__tar@ +am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ +builddir = @builddir@ datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ +htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ +localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ +psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ #AUTOMAKE_OPTIONS=foreign no-dependencies AUTOMAKE_OPTIONS = foreign -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 +bin_SCRIPTS = cat5rancid control_rancid agmrancid alogin arancid \ + blogin brancid clogin cssrancid elogin erancid f10rancid \ + flogin francid fnrancid hlogin hrancid htlogin htrancid \ + jerancid jlogin jrancid mrancid nlogin nrancid nslogin \ + nsrancid par prancid rancid rancid-fe rivlogin rivrancid \ + rrancid srancid 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 @@ -232,7 +240,9 @@ auto_edit = sed \ -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' + -e 's,@MAILPLUS\@,$(MAILPLUS),g' \ + -e 's,@PACKAGE\@,$(PACKAGE),g' \ + -e 's,@VERSION\@,$(VERSION),g' all: all-am @@ -273,6 +283,8 @@ 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)/$@ +agmrancid: $(top_builddir)/config.status $(srcdir)/agmrancid.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 @@ -333,6 +345,8 @@ 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)/$@ +srancid: $(top_builddir)/config.status $(srcdir)/srancid.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 @@ -343,14 +357,14 @@ zrancid: $(top_builddir)/config.status $(srcdir)/zrancid.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) - $(mkdir_p) $(DESTDIR)$(bindir) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; for p in $$list; do \ 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; \ + echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ else :; fi; \ done @@ -358,24 +372,24 @@ uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @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; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ done 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) + $(LINK) $(hpuifilter_OBJECTS) $(hpuifilter_LDADD) $(LIBS) install-binSCRIPTS: $(bin_SCRIPTS) @$(NORMAL_INSTALL) - $(mkdir_p) $(DESTDIR)$(bindir) + test -z "$(bindir)" || $(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; \ + echo " $(binSCRIPT_INSTALL) '$$d$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(binSCRIPT_INSTALL) "$$d$$p" "$(DESTDIR)$(bindir)/$$f"; \ else :; fi; \ done @@ -383,8 +397,8 @@ 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; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ done mostlyclean-compile: @@ -396,21 +410,18 @@ distclean-compile: @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 +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @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@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(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 +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @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@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(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)'; \ @@ -432,9 +443,11 @@ TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ - test -z "$(ETAGS_ARGS)$$tags$$unique" \ - || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$tags $$unique + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) @@ -459,22 +472,21 @@ distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) - @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; \ + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ 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 \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ @@ -489,7 +501,9 @@ check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) $(SCRIPTS) installdirs: - $(mkdir_p) $(DESTDIR)$(bindir) $(DESTDIR)$(bindir) + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done install: install-am install-exec: install-exec-am install-data: install-data-am @@ -510,7 +524,7 @@ clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: - -rm -f $(CONFIG_CLEAN_FILES) + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @@ -537,12 +551,20 @@ info-am: install-data-am: +install-dvi: install-dvi-am + install-exec-am: install-binPROGRAMS install-binSCRIPTS +install-html: install-html-am + install-info: install-info-am install-man: +install-pdf: install-pdf-am + +install-ps: install-ps-am + installcheck-am: maintainer-clean: maintainer-clean-am @@ -562,20 +584,23 @@ ps: ps-am ps-am: -uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS \ - uninstall-info-am +uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS + +.MAKE: install-am install-strip .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-binSCRIPTS install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ 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 + uninstall-binSCRIPTS lg.cgi: Makefile $(srcdir)/lg.cgi.in diff --git a/bin/agmrancid.in b/bin/agmrancid.in new file mode 100644 index 0000000..0542bd2 --- /dev/null +++ b/bin/agmrancid.in @@ -0,0 +1,493 @@ +#! @PERLV_PATH@ +## +## $Id: agmrancid.in,v 1.2 2006/12/06 00:40:54 heas Exp $ +## +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 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 Cisco AGMs. +# +# RANCID - Really Awesome New Cisco confIg Differ +# +# usage: rancid [-dV] [-l] [-f filename | hostname] +# +use Getopt::Std; +getopts('dflV'); +if ($opt_V) { + print "@PACKAGE@ @VERSION@\n"; + exit(0); +} +$log = $opt_l; +$debug = $opt_d; +$file = $opt_f; +$host = $ARGV[0]; +$clean_run = 0; +$found_end = 0; +$found_version = 0; +$found_env = 0; +$found_diag = 0; +$timeo = 90; # clogin timeout in seconds + +# the AGM kicks us off if it does not know our terminal type +$ENV{'TERM'} = "dumb"; + +my(@commandtable, %commands, @commands);# command lists +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); + my($slaveslot); + + while (<INPUT>) { + tr/\015//d; + if (/^$prompt/) { $found_version=1; last}; + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(-1) if (/command authorization failed/i); + return(0) if ($found_version); # Only do this routine once + # the pager can not be disabled per-session on the PIX + if (/^(-+More-+)/i) { + my($len) = length($1); + s/^$1\s{$len}//; + } + + /^Cisco Anomaly Guard Image /i && + ProcessHistory("COMMENTS","keysort","B1", "! $_") && next; + /^MDM agent /i && + ProcessHistory("COMMENTS","keysort","B1", "! $_") && next; + } + return(0); +} + +# This routine parses "show diag" +# This will create arrarys for hw info. +sub ShowDiag { + print STDERR " In ShowDiag: $_" if ($debug); + + while (<INPUT>) { + tr/\015//d; + if (/^$prompt/) { $found_diag=1; last}; + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(-1) if (/command authorization failed/i); + return(0) if ($found_diag); # Only do this routine once + /^$/ && next; + # the pager can not be disabled per-session on the PIX + if (/^(-+More-+)/i) { + my($len) = length($1); + s/^$1\s{$len}//; + } + + /^Cisco Anomaly Guard Image /i && next; + /^... ... \d+ \d+:\d+:\d+ \w \d+$/ && next; + /^Copyright /i && next; + /^All rights /i && next; + /sample loss:/i && next; + /forward failures /i && next; + + ProcessHistory("DIAG","keysort","C1","! $_"); + } + ProcessHistory("DIAG","","","!\n"); + return(0); +} + +# This routine processes a "write term" +sub WriteTerm { + print STDERR " In WriteTerm: $_" if ($debug); + my($lineauto,$comment,$linecnt) = (0,0,0); + + while (<INPUT>) { + tr/\015//d; + last if (/^$prompt/); + return(1) if /Line has invalid autocommand /; + return(1) if (/(Invalid input detected|Type help or )/i); + return(-1) if (/command authorization failed/i); + # the pager can not be disabled per-session on the PIX + if (/^(-+More-+)/i) { + my($len) = length($1); + s/^$1\s{$len}//; + } + + /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 consecutive comment/blank 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 + /^ 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)( level \w+)? encrypted ((.)\S+)/) { + if ($filter_pwds >= 2) { + ProcessHistory("USER","keysort","$1", + "!$1$2$3 encrypted <removed>\n"); + } elsif ($filter_pwds >= 1 && $5 ne "\$") { + ProcessHistory("USER","keysort","$1", + "!$1$2$3 encrypted <removed>\n"); + } else { + ProcessHistory("USER","keysort","$1","$_"); + } + next; + } + + if ((/^(enable )?(password|passwd)( level \w+)? encrypted [^\$]/ && + $filter_pwds >= 1) || + (/^(enable )?(password|passwd)( level \w+)? encrypted [^\$]/ && + $filter_pwds >= 2)) { + ProcessHistory("ENABLE","","","!$1$2$3 <removed>\n"); + next; + } + if (/^username (\S+)(\s.*)? encrypted ((.)\S+)/) { + if ($filter_pwds >= 2) { + ProcessHistory("USER","keysort","$1", + "!username $1$2 encrypted <removed>\n"); + } elsif ($filter_pwds >= 1 && $4 ne "\$") { + ProcessHistory("USER","keysort","$1", + "!username $1$2 encrypted <removed>\n"); + } else { + ProcessHistory("USER","keysort","$1","$_"); + } + next; + } + if (/^(\s*)password / && $filter_pwds >= 1) { + ProcessHistory("LINE-PASS","","","!$1password <removed>\n"); + next; + } + if (/^(\s*)secret / && $filter_pwds >= 2) { + ProcessHistory("LINE-PASS","","","!$1secret <removed>\n"); + next; + } + # 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; + + # order logging statements + /^logging host (\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 <community> + if (/^snmp-server trap-dest (\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))); + if ($token eq '3') { + $line .= " " . join(' ', ($token, shift(@tokens))); + } + } elsif ($token eq 'vrf') { + $line .= " " . join(' ', ($token, shift(@tokens))); + } elsif ($token =~ /^(informs?|traps?|(no)?auth)$/) { + $line .= " " . $token; + } else { + $line = "!$line " . join(' ', ("<removed>", join(' ',@tokens))); + last; + } + } + ProcessHistory("SNMPSERVERHOST","ipsort","$ip","$line\n"); + } else { + ProcessHistory("SNMPSERVERHOST","ipsort","$1","$_"); + } + next; + } + if (/^(snmp community) (\S+)/) { + if (defined($ENV{'NOCOMMSTR'})) { + ProcessHistory("SNMPSERVERCOMM","keysort","$_","!$1 <removed>$'") && next; + } else { + ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && next; + } + } + # prune tacacs/radius server keys + if (/^((tacacs-server|radius-server)\s(\w*[-\s(\s\S+])*\s?key) \d \w+/ + && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 <removed>$'"); next; + } + + # delete ntp auth password - this md5 is a reversable too + if (/^(ntp authentication-key \d+ md5) / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 <removed>\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. the ": " game is for the PIX + if (/^(: +)?end$/) { + $found_end = 1; + return(1); + } + } + # The AGM lacks a definitive "end of config" marker. If we have seen at + # least 5 lines of write term o/p, we can be reasonably sure that we got + # the config. + if ($linecnt > 5) { + $found_end = 1; + return(1); + } + + return(0); +} + +# dummy function +sub DoNothing {print STDOUT;} + +# Main +@commandtable = ( + {'show version' => 'ShowVersion'}, + {'show diagnostic-info' => 'ShowDiag'}, + {'show running-config' => 'WriteTerm'}, +); +# Use an array to preserve the order of the commands and a hash for mapping +# commands to the subroutine and track commands that have been completed. +@commands = map(keys(%$_), @commandtable); +%commands = map(%$_, @commandtable); + +$cisco_cmds=join(";",@commands); +$cmds_regexp=join("|",@commands); + +if (length($host) == 0) { + if ($file) { + print(STDERR "Too few arguments: file name required\n"); + exit(1); + } else { + print(STDERR "Too few arguments: host name required\n"); + exit(1); + } +} +open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; +select(OUTPUT); +# make OUTPUT unbuffered if 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 hlogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($debug); + print STDOUT "executing hlogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($log); + if (defined($ENV{NOPIPE})) { + system "hlogin -t $timeo -c \"$cisco_cmds\" $host </dev/null > $host.raw 2>&1" || die "hlogin failed for $host: $!\n"; + open(INPUT, "< $host.raw") || die "hlogin failed for $host: $!\n"; + } else { + open(INPUT,"hlogin -t $timeo -c \"$cisco_cmds\" $host </dev/null |") || die "hlogin failed for $host: $!\n"; + } +} + +# determine password filtering mode +if ($ENV{"FILTER_PWDS"} =~ /no/i) { + $filter_pwds = 0; +} elsif ($ENV{"FILTER_PWDS"} =~ /all/i) { + $filter_pwds = 2; +} else { + $filter_pwds = 1; +} + +ProcessHistory("","","","!RANCID-CONTENT-TYPE: riverhead\n!\n"); +ProcessHistory("COMMENTS","keysort","B0","!\n"); +ProcessHistory("COMMENTS","keysort","C0","!\n"); +TOP: while(<INPUT>) { + 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; + } + if (/[>#]\s?exit$/) { + $clean_run=1; + last; + } + } +} +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 $clean_run . " " . $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/alogin.in b/bin/alogin.in index 91623fb..27286d7 100644 --- a/bin/alogin.in +++ b/bin/alogin.in @@ -1,8 +1,9 @@ #! @EXPECT_PATH@ -- ## -## $Id: alogin.in,v 1.22 2004/01/11 05:39:15 heas Exp $ +## $Id: alogin.in,v 1.35 2006/12/05 16:50:52 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -24,7 +25,7 @@ # alogin - Alteon WebOS switch login # # afort@choqolat.org is responsible for this particular mess -# (andrew fort) +# (andrew fort) # # Usage line @@ -43,7 +44,7 @@ set password_file $env(HOME)/.cloginrc set do_command 0 set do_script 0 # The default is to automatically enable -set enable 1 +set avenable 1 # The default is that you login non-enabled (tacacs can have you login already # enabled) set avautoenable 0 @@ -52,7 +53,7 @@ set avautoenable 0 set do_passwd 1 # Find the user in the ENV, or use the unix userid. -if {[ info exists env(CISCO_USER) ] } { +if {[ info exists env(CISCO_USER) ]} { set default_user $env(CISCO_USER) } elseif {[ info exists env(USER) ]} { set default_user $env(USER) @@ -65,9 +66,12 @@ if {[ info exists env(CISCO_USER) ] } { if [ catch {exec id} reason ] { send_error "\nError: could not exec id: $reason\n" exit 1 - } + } regexp {\(([^)]*)} "$reason" junk default_user -} +} +if {[ info exists env(CLOGINRC) ]} { + set password_file $env(CLOGINRC) +} # Sometimes routers take awhile to answer (the default is 10 sec) set timeout 45 @@ -85,13 +89,16 @@ for {set i 0} {$i < $argc} {incr i} { set username [ lindex $argv $i ] } # VTY Password - } -v* - - -v* { + } -v* { if {! [ regexp .\[vV\](.+) $arg ignore passwd]} { incr i set passwd [ lindex $argv $i ] } set do_passwd 0 + # Version string + } -V* { + send_user "@PACKAGE@ @VERSION@\n" + exit 0 # Enable Username } -w* - -W* { @@ -264,6 +271,7 @@ proc source_password_file { password_file } { } # Log into the router. +# returns: 0 on success, 1 on failure proc login { router user userpswd passwd prompt cmethod cyphertype } { global spawn_id in_proc do_command do_script global u_prompt p_prompt sshcmd @@ -273,6 +281,7 @@ proc login { router user userpswd passwd prompt cmethod cyphertype } { # try each of the connection methods in $cmethod until one is successful set progs [llength $cmethod] foreach prog [lrange $cmethod 0 end] { + incr progs -1 if [string match "telnet*" $prog] { regexp {telnet(:([^[:space:]]+))*} $prog command suffix port if {"$port" == ""} { @@ -282,23 +291,23 @@ proc login { router user userpswd passwd prompt cmethod cyphertype } { } if { $retval } { send_user "\nError: telnet failed: $reason\n" - exit 1 + return 1 } - } elseif ![string compare $prog "ssh"] { + } 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 + return 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" + } elseif ![string compare $prog "rsh"] { + send_error "\nError: unsupported method: rsh\n" + if { $progs == 0 } { + return 1 + } + continue; + } else { + send_user "\nError: unknown connection method: $prog\n" return 1 - } - incr progs -1 + } sleep 0.3 # This helps cleanup each expect clause. @@ -415,15 +424,16 @@ proc run_commands { prompt command } { } send "exit\r" expect { - -re "^WARNING: There are unsaved configuration changes." - { - send "y\r" - exp_continue - } - "\n" { exp_continue } - "\[^\n\r *]*Session terminated" { return 0 } - timeout { return 0 } - eof { return 0 } + -re "^WARNING: There are unsaved configuration changes." { + send "y\r" + exp_continue + } + "\n" { exp_continue } + "\[^\n\r *]*Session terminated" { return 0 } + timeout { catch {close}; wait + return 0 + } + eof { return 0 } } set in_proc 0 } diff --git a/bin/arancid.in b/bin/arancid.in index a2bf1ef..165a187 100644 --- a/bin/arancid.in +++ b/bin/arancid.in @@ -1,12 +1,13 @@ #! @PERLV_PATH@ ## -## $Id: arancid.in,v 1.14 2004/01/11 03:49:13 heas Exp $ +## $Id: arancid.in,v 1.22 2006/10/05 04:27:42 heas Exp $ ## -## Hacked version of rancid for Alteon WebOS switches +## @PACKAGE@ @VERSION@ +## Hacked version of rancid for Alteon WebOS switches ## tested with: ad3 v8.1.18 ## afort@choqolat.org (andrew fort) ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -24,13 +25,17 @@ ## # # RANCID - Really Awesome New Cisco confIg Differ -# +# # arancid - Alteon WebOS plugin for rancid # -# usage: arancid [-d] [-l] [-f filename | $host] +# usage: arancid [-dV] [-l] [-f filename | hostname] # use Getopt::Std; -getopts('dfl'); +getopts('dflV'); +if ($opt_V) { + print "@PACKAGE@ @VERSION@\n"; + exit(0); +} $log = $opt_l; $debug = $opt_d; $file = $opt_f; @@ -38,13 +43,16 @@ $host = $ARGV[0]; $clean_run = 0; $found_end = 0; $prompt = "#"; -$timeo = 90; # clogin timeout in seconds +$timeo = 90; # alogin timeout in seconds + +my(@commandtable, %commands, @commands);# command lists +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) { + 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; } @@ -66,10 +74,10 @@ sub ProcessHistory { sub numerically { $a <=> $b; } -# This is a sort routing that will sort numerically on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort numerically keys(%lines)) { @@ -79,10 +87,10 @@ sub keynsort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort keys(%lines)) { @@ -92,10 +100,10 @@ sub keysort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort values %lines) { @@ -105,9 +113,9 @@ sub valsort{ @sorted_lines; } -# This is a numerical sort routing (ascending). +# This is a numerical sort routine (ascending). sub numsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $num (sort {$a <=> $b} keys %lines) { @@ -121,7 +129,7 @@ sub numsort { # ip address when the ip address is anywhere in # the strings. sub ipsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $addr (sort sortbyipaddr keys %lines) { @@ -134,7 +142,7 @@ sub ipsort { # 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])); + $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0])); } sub sortbyipaddr { &ipaddrval($a) <=> &ipaddrval($b); @@ -142,23 +150,23 @@ sub sortbyipaddr { # This routine parses "/info/sys" (cf. show version) sub ShowVersion { - print STDERR " In ShowVersion: $_" if ($debug); + print STDERR " In ShowVersion: $_" if ($debug); + + while (<INPUT>) { + tr/\015//d; + last if (/^>>.*$prompt/); + next if(/^(\s*|\s*$cmd\s*)$/); - while (<INPUT>) { - tr/\015//d; - last if (/^>>.*$prompt/); - next if(/^(\s*|\s*$cmd\s*)$/); - - /^(ACEdirector.*|ACEswitch.*|Alteon.*)/i && + /^(ACEdirector.*|ACEswitch.*|Alteon.*)/i && ProcessHistory("COMMENTS","keysort","A1", "\/\*Model: $1\n") && next; /^Software Version\s+(.*?)\s\((.*)\)/i && ProcessHistory("COMMENTS","keysort","B1", "\/\*Image: Software: $1 ($2)\n") && next; /^Hardware Part No:\s+(.*?)\s+/i && ProcessHistory("COMMENTS","keysort","A2", "\/\*Hardware part no: $1\n") && next; /^MAC address:\s+([0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2})/i && - ProcessHistory("COMMENTS","keysort","C1", "\/\*Base MAC address: $1\n") && next; - } - return(0); + ProcessHistory("COMMENTS","keysort","C1", "\/\*Base MAC address: $1\n") && next; + } + return(0); } # This routine processes a "/cfg/dump" @@ -170,10 +178,10 @@ sub WriteTerm { # now just copy it verbatim to the history file while (<INPUT>) { - tr/\015//d; - last if(/^>>.*$prompt/); + tr/\015//d; + last if(/^>>.*$prompt/); chop; - if (/(rcomm|wcomm|t1com|t2com)(\s+)(.*)/ && + if (/(rcomm|wcomm|t1com|t2com)(\s+)(.*)/ && defined($ENV{'NOCOMMSTR'})) { ProcessHistory("","","","\/\*\t$1$2\"<removed>\"\n") && next; } @@ -183,8 +191,8 @@ sub WriteTerm { next if (/^\/\* Configuration dump taken/i); next if (/^\/\* Version.*Base MAC.*/i); - if (/^\/?script end/) { - $found_end = 1; + if (/^\/?script end/) { + $found_end = 1; ProcessHistory("","","","$_\n"); return(1); } @@ -198,19 +206,27 @@ sub WriteTerm { sub DoNothing {print STDOUT;} # Main -%commands=( - '/info/sys' => "ShowVersion", - '/cfg/dump' => "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=( - "/info/sys", - "/cfg/dump", +@commandtable = ( + {'/info/sys' => 'ShowVersion'}, + {'/cfg/dump' => 'WriteTerm'} ); +# Use an array to preserve the order of the commands and a hash for mapping +# commands to the subroutine and track commands that have been completed. +@commands = map(keys(%$_), @commandtable); +%commands = map(%$_, @commandtable); + $cisco_cmds=join(";",@commands); $cmds_regexp=join("|",@commands); +if (length($host) == 0) { + if ($file) { + print(STDERR "Too few arguments: file name required\n"); + exit(1); + } else { + print(STDERR "Too few arguments: host name required\n"); + exit(1); + } +} open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; select(OUTPUT); # make OUTPUT unbuffered if debugging @@ -237,13 +253,13 @@ ProcessHistory("COMMENTS","keysort","F0","\/\*\n"); TOP: while(<INPUT>) { tr/\015//d; if (/^>>.*$prompt exit/) { - $clean_run=1; - last; + $clean_run=1; + last; } while (/>>.*$prompt\s*($cmds_regexp)\s*$/) { - $cmd = $1; - if (!defined($prompt)) { + $cmd = $1; + if (!defined($prompt)) { $prompt = ($_ =~ /^([^#]+#)/)[0]; $prompt =~ s/([][}{)(\\])/\\$1/g; print STDERR ("PROMPT MATCH: $prompt\n") if ($debug); @@ -252,7 +268,7 @@ TOP: while(<INPUT>) { if (!defined($commands{$cmd})) { print STDERR "$host: found unexpected command - \"$cmd\"\n"; $clean_run = 0; - last TOP; + last TOP; } $rval = &{$commands{$cmd}}; delete($commands{$cmd}); diff --git a/bin/blogin.in b/bin/blogin.in index 92d2e8c..37c28e8 100644 --- a/bin/blogin.in +++ b/bin/blogin.in @@ -1,8 +1,9 @@ #! @EXPECT_PATH@ -- ## -## $Id: blogin.in,v 1.22 2004/01/11 05:39:15 heas Exp $ +## $Id: blogin.in,v 1.36 2006/12/08 21:28:25 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -46,7 +47,7 @@ set password_file $env(HOME)/.cloginrc set do_command 0 set do_script 0 # The default is to automatically enable -set enable 0 +set avenable 0 # The default is that you login non-enabled (tacacs can have you login already # enabled) set avautoenable 0 @@ -56,7 +57,7 @@ set do_passwd 1 set do_enapasswd 0 # Find the user in the ENV, or use the unix userid. -if {[ info exists env(CISCO_USER) ] } { +if {[ info exists env(CISCO_USER) ]} { set default_user $env(CISCO_USER) } elseif {[ info exists env(USER) ]} { set default_user $env(USER) @@ -72,6 +73,9 @@ if {[ info exists env(CISCO_USER) ] } { } regexp {\(([^)]*)} "$reason" junk default_user } +if {[ info exists env(CLOGINRC) ]} { + set password_file $env(CLOGINRC) +} # Sometimes routers take awhile to answer (the default is 10 sec) set timeout 45 @@ -97,13 +101,16 @@ for {set i 0} {$i < $argc} {incr i} { } set do_passwd 0 # VTY Password - } -v* - - -v* { + } -v* { if {! [ regexp .\[vV\](.+) $arg ignore passwd]} { incr i set passwd [ lindex $argv $i ] } set do_passwd 0 + # Version string + } -V* { + send_user "@PACKAGE@ @VERSION@\n" + exit 0 # Enable Username } -w* - -W* { @@ -112,14 +119,14 @@ for {set i 0} {$i < $argc} {incr i} { set enausername [ lindex $argv $i ] } # Environment variable to pass to -s scripts - } -E* + } -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* { @@ -183,11 +190,11 @@ for {set i 0} {$i < $argc} {incr i} { set do_command 1 # Do we enable? } -noenable { - set enable 0 + set avenable 0 # Does tacacs automatically enable us? } -autoenable { set avautoenable 1 - set enable 0 + set avenable 0 } -* { send_user "\nError: Unknown argument! $arg\n" send_user $usage @@ -237,25 +244,25 @@ proc label { host } { # add password * hanky-pie proc add {var args} { global int_$var ; lappend int_$var $args} proc include {args} { - global env - regsub -all "(^{|}$)" $args {} 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 + upvar int_$var list if { [info exists list] } { foreach line $list { if { [string match [lindex $line 0] $router ] } { return [lrange $line 1 end] - } - } - } - return {} -} + } + } + } + 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 @@ -280,6 +287,7 @@ proc source_password_file { password_file } { } # Log into the router. +# returns: 0 on success, 1 on failure 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 sshcmd @@ -288,6 +296,7 @@ proc login { router user userpswd passwd enapasswd prompt cmethod cyphertype } { # try each of the connection methods in $cmethod until one is successful set progs [llength $cmethod] foreach prog [lrange $cmethod 0 end] { + incr progs -1 if [string match "telnet*" $prog] { regexp {telnet(:([^[:space:]]+))*} $prog command suffix port if {"$port" == ""} { @@ -297,23 +306,23 @@ proc login { router user userpswd passwd enapasswd prompt cmethod cyphertype } { } if { $retval } { send_user "\nError: telnet failed: $reason\n" - exit 1 + return 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 + return 1 } } elseif ![string compare $prog "rsh"] { - if [ catch {spawn rsh -l $user $router} reason ] { - send_user "\nError: rsh failed: $reason\n" - exit 1 + send_error "\nError: unsupported method: rsh\n" + if { $progs == 0 } { + return 1 } + continue; } else { - puts "\nError: unknown connection method: $prog" + send_user "\nError: unknown connection method: $prog\n" return 1 } - incr progs -1 sleep 0.3 # This helps cleanup each expect clause. @@ -466,9 +475,11 @@ proc run_commands { prompt command } { } send "logout\r" expect { - "\n" { exp_continue } - timeout { return 0 } - eof { return 0 } + "\n" { exp_continue } + timeout { catch {close}; wait + return 0 + } + eof { return 0 } } set in_proc 0 } @@ -498,6 +509,7 @@ foreach router [lrange $argv $i end] { set prompt "#" } else { set autoenable 0 + set enable $avenable set prompt ">" } } @@ -520,6 +532,9 @@ foreach router [lrange $argv $i end] { } set passwd [join [lindex $pswd 0] ""] set enapasswd [join [lindex $pswd 1] ""] + } else { + set passwd $userpasswd + set enapasswd $enapasswd } # Figure out username @@ -593,7 +608,7 @@ foreach router [lrange $argv $i end] { if { $enable } { if {[do_enable $enauser $enapasswd]} { if { $do_command || $do_script } { - close; wait + catch {close}; catch {wait} continue } } diff --git a/bin/brancid.in b/bin/brancid.in index c2e602e..35f3f2f 100644 --- a/bin/brancid.in +++ b/bin/brancid.in @@ -1,9 +1,10 @@ #! @PERLV_PATH@ ## -## $Id: brancid.in,v 1.16 2004/01/11 03:49:13 heas Exp $ +## $Id: brancid.in,v 1.24 2006/10/05 04:27:42 heas Exp $ ## hacked version of Hank's rancid - this one tries to deal with Bay's. ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -22,25 +23,30 @@ # # RANCID - Really Awesome New Cisco confIg Differ # -# usage: rancid [-d] [-l] [-f filename | $host] +# usage: rancid [-dV] [-l] [-f filename | hostname] # use Getopt::Std; -getopts('dfl'); +getopts('dflV'); +if ($opt_V) { + print "@PACKAGE@ @VERSION@\n"; + exit(0); +} $log = $opt_l; $debug = $opt_d; $file = $opt_f; $host = $ARGV[0]; $clean_run = 0; $found_end = 0; -$timeo = 90; # blogin timeout in seconds +$timeo = 90; # blogin timeout in seconds -my(%filter_pwds); # password filtering mode +my(@commandtable, %commands, @commands);# command lists +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) { + 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; } @@ -62,10 +68,10 @@ sub ProcessHistory { sub numerically { $a <=> $b; } -# This is a sort routing that will sort numerically on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort numerically keys(%lines)) { @@ -75,10 +81,10 @@ sub keynsort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort keys(%lines)) { @@ -88,10 +94,10 @@ sub keysort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort values %lines) { @@ -101,9 +107,9 @@ sub valsort{ @sorted_lines; } -# This is a numerical sort routing (ascending). +# This is a numerical sort routine (ascending). sub numsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $num (sort {$a <=> $b} keys %lines) { @@ -117,7 +123,7 @@ sub numsort { # ip address when the ip address is anywhere in # the strings. sub ipsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $addr (sort sortbyipaddr keys %lines) { @@ -130,7 +136,7 @@ sub ipsort { # 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])); + $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0])); } sub sortbyipaddr { &ipaddrval($a) <=> &ipaddrval($b); @@ -158,8 +164,8 @@ sub ShowConfig { } # ProcessHistory("","","","!$_"); if (/exit$/) { - $found_end = 1; - return(1); + $found_end = 1; + return(1); } return(0); } @@ -186,23 +192,29 @@ sub RunCommand { sub DoNothing {print STDOUT;} # Main -%commands=( - 'bcc' => "RunCommand", - 'show config' => "ShowConfig", - 'show config -all' => "ShowConfig", - 'exit' => "RunCommand" -); -# 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=( - "bcc", - "show config", - "show config -all", - "exit" +@commandtable = ( + {'bcc' => 'RunCommand'}, + {'show config' => 'ShowConfig'}, + {'show config -all' => 'ShowConfig'}, + {'exit' => 'RunCommand'} ); +# Use an array to preserve the order of the commands and a hash for mapping +# commands to the subroutine and track commands that have been completed. +@commands = map(keys(%$_), @commandtable); +%commands = map(%$_, @commandtable); + $cisco_cmds=join(";",@commands); $cmds_regexp=join("|",@commands); +if (length($host) == 0) { + if ($file) { + print(STDERR "Too few arguments: file name required\n"); + exit(1); + } else { + print(STDERR "Too few arguments: host name required\n"); + exit(1); + } +} open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; select(OUTPUT); # make OUTPUT unbuffered if debugging @@ -225,7 +237,7 @@ if ($file) { # determine password filtering mode if ($ENV{"FILTER_PWDS"} =~ /no/i) { - $filter_pwds = 0; + $filter_pwds = 0; } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) { $filter_pwds = 2; } else { diff --git a/bin/cat5rancid.in b/bin/cat5rancid.in index f1214a1..bd13d65 100644 --- a/bin/cat5rancid.in +++ b/bin/cat5rancid.in @@ -1,8 +1,9 @@ #! @PERLV_PATH@ ## -## $Id: cat5rancid.in,v 1.36 2004/01/11 03:49:13 heas Exp $ +## $Id: cat5rancid.in,v 1.47 2006/10/05 04:27:42 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -21,26 +22,31 @@ # # RANCID - Really Awesome New Cisco confIg Differ # -# usage: rancid [-d] [-l] [-f filename | $host] +# usage: rancid [-dV] [-l] [-f filename | hostname] # use Getopt::Std; -getopts('dfl'); +getopts('dflV'); +if ($opt_V) { + print "@PACKAGE@ @VERSION@\n"; + exit(0); +} $log = $opt_l; $debug = $opt_d; $file = $opt_f; $host = $ARGV[0]; $clean_run = 0; $found_end = 0; -$timeo = 90; # clogin timeout in seconds +$timeo = 90; # clogin timeout in seconds -my(%filter_pwds); # password filtering mode +my(@commandtable, %commands, @commands);# command lists +my(%filter_pwds); # password filtering mode my(%modules); # module info (part from sh ver, part from sh module) # 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) { + 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; } @@ -62,10 +68,10 @@ sub ProcessHistory { sub numerically { $a <=> $b; } -# This is a sort routing that will sort numerically on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort numerically keys(%lines)) { @@ -75,10 +81,10 @@ sub keynsort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort keys(%lines)) { @@ -88,10 +94,10 @@ sub keysort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort values %lines) { @@ -101,9 +107,9 @@ sub valsort{ @sorted_lines; } -# This is a numerical sort routing (ascending). +# This is a numerical sort routine (ascending). sub numsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $num (sort {$a <=> $b} keys %lines) { @@ -117,7 +123,7 @@ sub numsort { # ip address when the ip address is anywhere in # the strings. sub ipsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $addr (sort sortbyipaddr keys %lines) { @@ -130,7 +136,7 @@ sub ipsort { # 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])); + $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0])); } sub sortbyipaddr { &ipaddrval($a) <=> &ipaddrval($b); @@ -665,14 +671,46 @@ sub ShowDiag { return(0); } +# This routine parses "show inventory". +sub ShowInventory { + print STDERR " In ShowInventory: $_" if ($debug); + + while (<INPUT>) { + tr/\015//d; + return if (/^\s*\^$/); + 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*//; + + chomp; + + # split PID/VID line + if (/^(NAME: ".*,) (DESCR: .*)/) { + ProcessHistory("INVENTORY","","", sprintf("!%-30s%s\n", $1, $2)); + next; + } + if (/^(PID: \w?) *, (VID: .*), (SN: .*)$/) { + ProcessHistory("INVENTORY","","", "!$1\n!$2\n!$3\n"); + next; + } + + ProcessHistory("INVENTORY","","","!$_"); + } + ProcessHistory("INVENTORY","","",""); + + return(0); +} + # This routine parses "show module" sub ShowModule { my($slot); print STDERR " In ShowModule: $_" if ($debug); OUTER:while (<INPUT>) { - tr/\015//d; - last if(/^$prompt/); + tr/\015//d; + last if(/^$prompt/); # stuff module type into %module if (/^Mod\s+Slot\s+Ports/) { <INPUT>; @@ -696,7 +734,7 @@ OUTER:while (<INPUT>) { } next; } - # one does it one way... pita + # one does it one way... pita if (/^Mod\s+Module-Name\s+Ports/) { <INPUT>; #my($slot); @@ -713,7 +751,7 @@ OUTER:while (<INPUT>) { } next; } - # daughter boards + # daughter boards if (/^Mod\s+Sub-Type/) { <INPUT>; my($slot, $board); @@ -767,7 +805,7 @@ OUTER:while (<INPUT>) { ProcessHistory("MODS","","",$model); if ($dboards) {ProcessHistory("MODS","","",$dboards);} } -} +} # This routine processes a "show port ifindex" sub ShowPortIfindex { @@ -790,7 +828,10 @@ sub ShowPortIfindex { sub WriteTerm { print STDERR " In WriteTerm: $_" if ($debug); - ProcessHistory("","","","!\n"); + if (! $found_end) { + ProcessHistory("","","","!\n"); + } + while (<INPUT>) { tr/\015//d; last if (/^$prompt/); @@ -822,9 +863,9 @@ sub WriteTerm { /^#Time: / && next; # Dog gone Cool matches to process the rest of the config - /^#time: / && next; # kill time: - /^tftp-server flash / && next; # kill any tftp remains - /^ntp clock-period / && next; # kill ntp clock-period + /^#time: / && next; # kill time: + /^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 if (/^enable password / && $filter_pwds >= 1) { @@ -925,15 +966,15 @@ sub WriteTerm { # order logging statements /^set logging server (\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 <community> + # order/prune snmp-server host statements + # we only prune lines of the form + # snmp-server host a.b.c.d <community> if (/^set snmp trap (\d+\.\d+\.\d+\.\d+) /) { if (defined($ENV{'NOCOMMSTR'})) { ProcessHistory("SNMPSERVERHOST","ipsort","$1","!set snmp trap $1 <removed>\n"); } else { ProcessHistory("SNMPSERVERHOST","ipsort","$1","$_"); - } + } next; } if (/^(set snmp community) (\S+) (\S+)/) { @@ -991,39 +1032,39 @@ sub WriteTerm { sub DoNothing {print STDOUT;} # Main -%commands=( - 'show version' => "ShowVersion", - 'show boot' => "ShowBoot", - 'show flash' => "ShowFlash", - 'dir bootflash:' => "DirSlotN", - 'dir slot0:' => "DirSlotN", - 'dir slot1:' => "DirSlotN", - 'dir sup-bootflash:' => "DirSlotN", - '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 -# cmds is important (show version first and write term last). pita -@commands=( - "show version", - "show boot", - "show flash", - "dir bootflash:", - "dir slot0:", - "dir slot1:", - "dir sup-bootflash:", - "dir sup-microcode:", - "show module", - "show port ifindex", - "write term all", - "write term" +@commandtable = ( + {'show version' => 'ShowVersion'}, + {'show boot' => 'ShowBoot'}, + {'show flash' => 'ShowFlash'}, + {'dir bootflash:' => 'DirSlotN'}, + {'dir slot0:' => 'DirSlotN'}, + {'dir slot1:' => 'DirSlotN'}, + {'dir sup-bootflash:' => 'DirSlotN'}, + {'dir sup-microcode:' => 'DirSlotN'}, + {'show module' => 'ShowModule'}, + {'show inventory raw' => 'ShowInventory'}, + {'show port ifindex' => 'ShowPortIfindex'}, + {'write term all' => 'WriteTerm'}, + {'write term' => 'WriteTerm'}, + {'show running-config' => 'WriteTerm'} ); +# Use an array to preserve the order of the commands and a hash for mapping +# commands to the subroutine and track commands that have been completed. +@commands = map(keys(%$_), @commandtable); +%commands = map(%$_, @commandtable); + $cisco_cmds=join(";",@commands); $cmds_regexp=join("|",@commands); +if (length($host) == 0) { + if ($file) { + print(STDERR "Too few arguments: file name required\n"); + exit(1); + } else { + print(STDERR "Too few arguments: host name required\n"); + exit(1); + } +} open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; select(OUTPUT); # make OUTPUT unbuffered if debugging diff --git a/bin/clogin.in b/bin/clogin.in index b05b56e..b7ac1a2 100644 --- a/bin/clogin.in +++ b/bin/clogin.in @@ -1,8 +1,9 @@ #! @EXPECT_PATH@ -- ## -## $Id: clogin.in,v 1.72 2004/01/11 05:39:15 heas Exp $ +## $Id: clogin.in,v 1.107 2006/12/08 21:28:25 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -47,7 +48,7 @@ set password_file $env(HOME)/.cloginrc set do_command 0 set do_script 0 # The default is to automatically enable -set enable 1 +set avenable 1 # The default is that you login non-enabled (tacacs can have you login already # enabled) set avautoenable 0 @@ -55,11 +56,11 @@ set avautoenable 0 # tracks if we receive them on the command line. set do_passwd 1 set do_enapasswd 1 -# attempt at platform switching. -set platform "" +# +set send_human {.4 .4 .7 .3 5} # Find the user in the ENV, or use the unix userid. -if {[ info exists env(CISCO_USER) ] } { +if {[ info exists env(CISCO_USER) ]} { set default_user $env(CISCO_USER) } elseif {[ info exists env(USER) ]} { set default_user $env(USER) @@ -75,6 +76,9 @@ if {[ info exists env(CISCO_USER) ] } { } regexp {\(([^)]*)} "$reason" junk default_user } +if {[ info exists env(CLOGINRC) ]} { + set password_file $env(CLOGINRC) +} # Sometimes routers take awhile to answer (the default is 10 sec) set timeout 45 @@ -100,13 +104,16 @@ for {set i 0} {$i < $argc} {incr i} { } set do_passwd 0 # VTY Password - } -v* - - -v* { + } -v* { if {! [ regexp .\[vV\](.+) $arg ignore passwd]} { incr i set passwd [ lindex $argv $i ] } set do_passwd 0 + # Version string + } -V* { + send_user "@PACKAGE@ @VERSION@\n" + exit 0 # Enable Username } -w* - -W* { @@ -189,11 +196,11 @@ for {set i 0} {$i < $argc} {incr i} { set do_command 1 # Do we enable? } -noenable { - set enable 0 + set avenable 0 # Does tacacs automatically enable us? } -autoenable { set avautoenable 1 - set enable 0 + set avenable 0 } -* { send_user "\nError: Unknown argument! $arg\n" send_user $usage @@ -286,6 +293,7 @@ proc source_password_file { password_file } { } # Log into the router. +# returns: 0 on success, 1 on failure, -1 if rsh was used successfully proc login { router user userpswd passwd enapasswd cmethod cyphertype } { global spawn_id in_proc do_command do_script platform global prompt u_prompt p_prompt e_prompt sshcmd usercmd usercmd_chat @@ -295,6 +303,7 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype } { # try each of the connection methods in $cmethod until one is successful set progs [llength $cmethod] foreach prog [lrange $cmethod 0 end] { + incr progs -1 if [string match "telnet*" $prog] { regexp {telnet(:([^[:space:]]+))*} $prog command suffix port if {"$port" == ""} { @@ -304,12 +313,19 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype } { } if { $retval } { send_user "\nError: telnet failed: $reason\n" - exit 1 + return 1 } - } elseif ![string compare $prog "ssh"] { - if [ catch {spawn $sshcmd -c $cyphertype -x -l $user $router} reason ] { + } elseif [string match "ssh*" $prog] { + regexp {ssh(:([^[:space:]]+))*} $prog command suffix port + if {"$port" == ""} { + set retval [ catch {spawn $sshcmd -c $cyphertype -x -l $user $router} reason ] + + } else { + set retval [ catch {spawn $sshcmd -c $cyphertype -x -l $user -p $port $router} reason ] + } + if { $retval } { send_user "\nError: $sshcmd failed: $reason\n" - exit 1 + return 1 } } elseif [string match "usercmd" $prog] { # user supplies connect cmd set retval [ catch {eval spawn $usercmd} reason ] @@ -328,15 +344,83 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype } { } } } elseif ![string compare $prog "rsh"] { - if [ catch {spawn rsh -l $user $router} reason ] { - send_user "\nError: rsh failed: $reason\n" - exit 1 + global command + + if { ! $do_command } { + if { [llength $cmethod] == 1 } { + send_user "\nError: rsh is an invalid method for -x and " + send_user "interactive logins\n" + } + if { $progs == 0 } { + return 1 + } + continue; + } + + set commands [split $command \;] + set num_commands [llength $commands] + set rshfail 0 + for {set i 0} {$i < $num_commands && !$rshfail} { incr i} { + log_user 0 + set retval [ catch {spawn rsh $user@$router [lindex $commands $i] } reason ] + if { $retval } { + send_user "\nError: rsh failed: $reason\n" + log_user 1; return 1 + } + send_user "$router# [lindex $commands $i]\n" + + # rcmd does not get a pager and no prompts, so we just have to + # look for failures & lines. + expect { + "Connection refused" { catch {close}; wait; + send_user "\nError: Connection\ + Refused ($prog): $router\n" + set rshfail 1 + } + -re "(Connection closed by|Connection to \[^\n\r]+ closed)" { + catch {close}; wait; + send_user "\nError: Connection\ + closed ($prog): $router\n" + set rshfail 1 + } + "Host is unreachable" { catch {close}; wait; + send_user "\nError: Host Unreachable:\ + $router\n" + set rshfail 1 + } + "No address associated with" { + catch {close}; wait; + send_user "\nError: Unknown host\ + $router\n" + set rshfail 1 + } + -re "\b+" { exp_continue } + -re "\[\n\r]+" { send_user -- "$expect_out(buffer)" + exp_continue + } + timeout { catch {close}; wait + send_user "\nError: TIMEOUT reached\n" + set rshfail 1 + } + eof { catch {close}; wait } + } + log_user 1 + } + if { $rshfail } { + if { !$progs } { + return 1 + } else { + continue + } } + # fake the end of the session for rancid. + send_user "$router# exit\n" + # return rsh "success" + return -1 } else { - puts "\nError: unknown connection method: $prog" + send_user "\nError: unknown connection method: $prog\n" return 1 } - incr progs -1 sleep 0.3 # This helps cleanup each expect clause. @@ -419,18 +503,26 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype } { send_user "\nError: Check your passwd for $router\n" return 1 } - -re "^Enter Selection: " { + "Press any key to continue." { + # send_user "Pressing the ANY key\n" + send "\r" + exp_continue + } + -re "Enter Selection: " { # Catalyst 1900s have some lame menu. Enter # K to reach a command-line. send "K\r" - exp_continue; + exp_continue + } + -re "Last login:" { + exp_continue } -re "@\[^\r\n]+ $p_prompt" { - # ssh pwd prompt - sleep 1 - send "$userpswd\r" - exp_continue - } + # ssh pwd prompt + sleep 1 + send "$userpswd\r" + exp_continue + } -re "$u_prompt" { send "$user\r" set uprompt_seen 1 @@ -469,8 +561,8 @@ proc do_enable { enauser enapasswd } { -re "$e_prompt" { send "$enapasswd\r"; exp_continue} "#" { set prompt "#" } "(enable)" { set prompt "> (enable) " } - "denied" { - # % Access denied - from local auth + -re "(denied|Sorry|Incorrect)" { + # % Access denied - from local auth and poss. others send_user "\nError: Check your Enable passwd\n"; return 1 } @@ -501,6 +593,9 @@ proc run_commands { prompt command } { if { [ string compare "extreme" "$platform" ] } { if [ regexp -- ".*> .*enable" "$prompt" ] { send "set length 0\r" + # This is ugly, but reduces code duplication, allowing the + # subsequent expects to handle everything as normal. + set command "set logging session disable;$command" } else { send "term length 0\r" } @@ -508,7 +603,7 @@ proc run_commands { prompt command } { 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 + regsub -all {^(.{1,11}).*([#>])$} $reprompt {\1([^#>\r\n]+)?[#>](\\([^)\\r\\n]+\\))?} reprompt expect { -re $reprompt {} -re "\[\n\r]+" { exp_continue } @@ -534,6 +629,9 @@ proc run_commands { prompt command } { } -re "^\[^\n\r]*$reprompt." { send_user -- "$expect_out(buffer)" exp_continue } + -re "^--More--\r\n" { # specific match c1900 pager + send " " + exp_continue } -re "\[\n\r]+" { send_user -- "$expect_out(buffer)" exp_continue } -re "\[^\r\n]*Press <SPACE> to cont\[^\r\n]*" { @@ -544,7 +642,7 @@ proc run_commands { prompt command } { } exp_continue } - -re "^ --More--\[^\n\r]*" { + -re "^ *--More--\[^\n\r]*" { send " " exp_continue } -re "^<-+ More -+>\[^\n\r]*" { @@ -564,6 +662,9 @@ proc run_commands { prompt command } { } -re "^\[^\n\r]*$reprompt." { send_user -- "$expect_out(buffer)" exp_continue } + -re "^--More--\r\n" { # specific match c1900 pager + send " " + exp_continue } -re "\[\n\r]+" { send_user -- "$expect_out(buffer)" exp_continue } -re "\[^\r\n]*Press <SPACE> to cont\[^\r\n]*" { @@ -574,7 +675,7 @@ proc run_commands { prompt command } { } exp_continue } - -re "^ --More--\[^\n\r]*" { + -re "^ *--More--\[^\n\r]*" { send " " exp_continue } -re "^<-+ More -+>\[^\n\r]*" { @@ -586,24 +687,34 @@ proc run_commands { prompt command } { log_user 1 if { [ string compare "extreme" "$platform" ] } { - send "exit\r" + send -h "exit\r" } else { - send "quit\r" + send -h "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" + send -h "exit\r" exp_continue; } + "Would you like to save them now" { # Force10 + send "n\r" + exp_continue + } + "Configuration changes have occurred.*" { # Cisco CSS + send "n\r" + exp_continue + } "Do you wish to save your configuration changes" { send "n\r" exp_continue } -re "\[\n\r]+" { exp_continue } - timeout { close; return 0 } + timeout { catch {close}; wait + return 0 + } eof { return 0 } } set in_proc 0 @@ -616,12 +727,14 @@ 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. - # 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. + # attempt at platform switching. + set platform "" + send_user -- "$router\n" + + # Figure out the prompt. + # autoenable is off by default. If we have it defined, it was done + # on the command line. If it is not specifically set on the command + # line, check the password file. if $avautoenable { set autoenable 1 set enable 0 @@ -634,6 +747,7 @@ foreach router [lrange $argv $i end] { set prompt "(#| \\(enable\\))" } else { set autoenable 0 + set enable $avenable set prompt ">" } } @@ -647,15 +761,18 @@ foreach router [lrange $argv $i end] { if { $do_passwd || $do_enapasswd } { set pswd [find password $router] if { [llength $pswd] == 0 } { - send_user "\nError: no password for $router in $password_file.\n" + send_user -- "\nError: no password for $router in $password_file.\n" continue } if { $enable && $do_enapasswd && $autoenable == 0 && [llength $pswd] < 2 } { - send_user "\nError: no enable password for $router in $password_file.\n" + send_user -- "\nError: no enable password for $router in $password_file.\n" continue } set passwd [join [lindex $pswd 0] ""] set enapasswd [join [lindex $pswd 1] ""] + } else { + set passwd $userpasswd + set enapasswd $enapasswd } # Figure out username @@ -728,12 +845,13 @@ foreach router [lrange $argv $i end] { # Login to the router if {[login $router $ruser $userpswd $passwd $enapasswd $cmethod $cyphertype]} { + # if login failed or rsh was unsuccessful, move on to the next device continue } if { $enable } { if {[do_enable $enauser $enapasswd]} { if { $do_command || $do_script } { - close; wait + catch {close}; catch {wait} continue } } @@ -742,7 +860,7 @@ foreach router [lrange $argv $i end] { send "\r" expect { -re "\[\r\n]+" { exp_continue; } - -re "^(.+:)1 $prompt" { # stoopid extreme cmd-line numbers and + -re "^(.+\[:.])1 ($prompt)" { # stoopid extreme cmd-line numbers and # prompt based on state of config changes, # which may have an * at the beginning. set junk $expect_out(1,string) diff --git a/bin/control_rancid.in b/bin/control_rancid.in index f51a21b..388bbf4 100644 --- a/bin/control_rancid.in +++ b/bin/control_rancid.in @@ -1,8 +1,9 @@ #! /bin/sh ## -## $Id: control_rancid.in,v 1.61 2004/01/11 05:25:13 hank Exp $ +## $Id: control_rancid.in,v 1.80 2006/12/07 21:14:06 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -24,22 +25,21 @@ # print a usage message to stderr pr_usage() { - echo "usage: $0 [-r device_name] [-m mail rcpt] [group [group ...]]" >&2; + echo "usage: $0 [-V] [-r device_name] [-m mail rcpt] [group [group ...]]" >&2; } # command-line options -# -r <device name> +# -V print version string # -m <mail recipients> +# -r <device name> alt_mailrcpt=0 if [ $# -ge 1 ] ; then while [ 1 ] ; do case $1 in - -r) - shift - # next arg is the device name - device="$1" - shift + -V) + echo "@PACKAGE@ @VERSION@" + exit 0 ;; -m) shift @@ -52,6 +52,12 @@ if [ $# -ge 1 ] ; then fi shift ;; + -r) + shift + # next arg is the device name + device="$1" + shift + ;; --) shift; break; ;; @@ -81,12 +87,33 @@ DIR=$BASEDIR/$GROUP TMP=${TMPDIR:=/tmp}/rancid.$GROUP.$$ trap 'rm -fr $TMP;' 1 2 15 -# the receipient(s) of diffs -mailrcpt=${mailrcpt:-"@MAILPLUS@$GROUP"}; export mailrcpt -adminmailrcpt=${mailrcpt:-"@ADMINMAILPLUS@$GROUP"}; export adminmailrcpt +# disable noclobber +unset noclobber > /dev/null 2>&1 + +# RCS system +RCSSYS=${RCSSYS:=cvs}; +if [ $RCSSYS != "cvs" -a $RCSSYS != "svn" ] ; then + echo "$RCSSYS is not a valid value for RCSSYS." + exit 1 +fi + +# the receipient(s) of diffs & mail options +mailrcpt=${mailrcpt:-"@MAILPLUS@${GROUP}${MAILDOMAIN}"}; export mailrcpt +adminmailrcpt=${adminmailrcpt:-"@ADMINMAILPLUS@${GROUP}${MAILDOMAIN}"}; +export adminmailrcpt +set | grep MAILHEADERS= > /dev/null 2>&1 +if [ $? -ne 0 ] ; then + MAILHEADERS="Precedence: bulk\n"; export MAILHEADERS +fi # Number of things par should run in parallel. PAR_COUNT=${PAR_COUNT:-5} +# Number of times failed collections should be retried. Minimum 1. +MAX_ROUNDS=${MAX_ROUNDS:-4} +if [ $MAX_ROUNDS -lt 1 ] ; then + echo "Error: MAX_ROUNDS must be at least 1." + MAX_ROUNDS=1 +fi # Bail if we do not have the necessary info to run if [ ! -d $DIR ] @@ -96,20 +123,36 @@ then ( echo "To: $adminmailrcpt" echo "Subject: no $GROUP directory" - echo "Precedence: bulk" + echo "$MAILHEADERS" | awk '{L = "";LN = $0;while (LN ~ /\\n/) { I = index(LN,"\\n");L = L substr(LN,0,I-1) "\n";LN = substr(LN,I+2,length(LN)-I-1);}print L LN;}' echo "" echo "$DIR does not exist." echo "Run bin/rancid-cvs $GROUP to make all of the needed directories." ) | sendmail -t exit 1 fi +cd $DIR + +# create a .cvsignore +if [ ! -f .cvsignore ] +then + rm -f .cvsignore + cat >.cvsignore <<EOF +.cvsignore +routers.all +routers.down +routers.up +EOF + if [ $RCSSYS = svn ] + then + svn propset svn:ignore -F .cvsignore . + fi +fi # do cvs update of router.db in case anyone has fiddled. -cd $DIR -cvs update router.db > $TMP 2>&1 +$RCSSYS update router.db > $TMP 2>&1 grep "^C" $TMP > /dev/null if [ $? -eq 0 ] ; then - echo "There were CVS conflicts during update." + echo "There were $RCSSYS conflicts during update." echo "" cat $TMP rm -f $TMP @@ -119,36 +162,34 @@ rm -f $TMP if [ ! -f $DIR/router.db ] then + echo "$DIR/router.db does not exist." ( echo "To: $adminmailrcpt" echo "Subject: no $GROUP/router.db file" - echo "Precedence: bulk" + echo "$MAILHEADERS" | awk '{L = "";LN = $0;while (LN ~ /\\n/) { I = index(LN,"\\n");L = L substr(LN,0,I-1) "\n";LN = substr(LN,I+2,length(LN)-I-1);}print L LN;}' echo "" echo "$DIR/router.db does not exist." ) | sendmail -t exit 1; -elif [ ! -s $DIR/router.db ] -then - exit fi # generate the list of all, up, & down routers 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 -sed -e '/^#/d' -e 's/^ *//' -e 's/ *$//' -e 's/ *: */:/g' router.db | +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=$? +@DIFF_CMD@ 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 > routers.down.new if [ ! -f routers.down ] ; then touch routers.down; fi -diff routers.down routers.down.new > /dev/null 2>&1; RDOWN=$? +@DIFF_CMD@ 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 > routers.up.new if [ ! -f routers.up ] ; then touch routers.up; fi -diff routers.up routers.up.new > /dev/null 2>&1; RUP=$? +@DIFF_CMD@ routers.up routers.up.new > /dev/null 2>&1; RUP=$? if [ $RALL -ne 0 -o $RDOWN -ne 0 -o $RUP -ne 0 ] then @@ -177,10 +218,10 @@ then WCDOWN=`comm -13 routers.down routers.down.new | wc -l | \ sed -e 's/^ *\([^ ]*\)/\1/'` if [ $WCDOWN -eq 1 ] ; then - echo Routers changed to down: - comm -13 routers.down routers.down.new | \ + echo Routers changed to down: + comm -13 routers.down routers.down.new | \ sed -e 's/^/ /' - echo + echo fi fi fi @@ -195,14 +236,14 @@ then if [ $WCADDED -gt 0 ] then - echo Added routers: - cat routers.added + echo Added routers: + cat routers.added echo fi if [ $WCDELETED -gt 0 ] then - echo Deleted routers: - cat routers.deleted + echo Deleted routers: + cat routers.deleted echo fi @@ -214,7 +255,7 @@ then ( echo "To: $adminmailrcpt" echo "Subject: changes in $GROUP routers" - echo "Precedence: bulk" + echo "$MAILHEADERS" | awk '{L = "";LN = $0;while (LN ~ /\\n/) { I = index(LN,"\\n");L = L substr(LN,0,I-1) "\n";LN = substr(LN,I+2,length(LN)-I-1);}print L LN;}' echo "" cat routers.mail ) | sendmail -t @@ -233,8 +274,12 @@ then router=$1 touch $router - cvs add -ko $router - cvs commit -m 'new router' $router + if [ $RCSSYS = cvs ] ; then + cvs add -ko $router + else + svn add $router + fi + $RCSSYS commit -m 'new router' $router echo "Added $router" done echo @@ -257,23 +302,31 @@ rm -f routers.db trap 'rm -fr $TMP;' 1 2 15 cd $DIR/configs -# check for 'up' routers missing in cvs. no idea how this happens to some folks +# check for 'up' routers missing in RCS. no idea how this happens to some folks for router in `cut -d: -f1 ../routers.up` ; do - cvs status $router | grep -i 'status: unknown' > /dev/null 2>&1 + if [ $RCSSYS = cvs ] ; then + cvs status $router | grep -i 'status: unknown' > /dev/null 2>&1 + else + svn status $router | grep '^?' > /dev/null 2>&1 + fi if [ $? -eq 0 ]; then touch $router - cvs add -ko $router - echo "CVS added missing router $router" + if [ $RCSSYS = cvs ] ; then + cvs add -ko $router + else + svn add $router + fi + echo "$RCSSYS added missing router $router" fi done echo -# cvs delete configs for routers not listed in routers.up. -for router in `find . \( -name \*.new -prune -o -name CVS -prune \) -o -type f -print | sed -e 's/^.\///'` ; do +# delete configs from RCS for routers not listed in routers.up. +for router in `find . \( -name \*.new -prune -o -name CVS -prune -o -name .svn -prune \) -o -type f -print | sed -e 's/^.\///'` ; do grep -i "^$router:" ../router.db > /dev/null 2>&1 if [ $? -eq 1 ]; then rm -f $router - cvs delete $router - cvs commit -m 'deleted router' $router + $RCSSYS delete $router + $RCSSYS commit -m 'deleted router' $router echo "Deleted $router" fi done @@ -283,7 +336,7 @@ cd $DIR if [ ! -s routers.up ] then # commit router.db - cvs commit -m updates router.db > /dev/null + $RCSSYS commit -m updates router.db exit; fi @@ -311,7 +364,7 @@ par -q -n $PAR_COUNT -c "rancid-fe \{}" $devlistfile # This section will generate a list of missed routers # and try to grab them again. It will run through # $pass times. -pass=4 +pass=$MAX_ROUNDS round=1 if [ -f $DIR/routers.up.missed ]; then rm -f $DIR/routers.up.missed @@ -349,10 +402,10 @@ echo # 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 +do OFS=$IFS IFS=':' - set $router + set $router IFS=$OFS router=$1; @@ -371,8 +424,12 @@ done # Diff the directory and then checkin. trap 'rm -fr $TMP $TMP.diff $DIR/routers.single;' 1 2 15 cd $DIR -cvs -f @DIFF_CMD@ | sed -e '/^RCS file: /d' -e '/^--- /d' \ +if [ $RCSSYS = "cvs" ] ; then + cvs -f @DIFF_CMD@ -ko | sed -e '/^RCS file: /d' -e '/^--- /d' \ -e '/^+++ /d' -e 's/^\([-+ ]\)/\1 /' >$TMP.diff +else + svn diff | sed -e '/^+++ /d' -e 's/^\([-+ ]\)/\1 /' >$TMP.diff +fi if [ $alt_mailrcpt -eq 1 ] ; then subject="router config diffs - courtesy of $mailrcpt" @@ -380,22 +437,23 @@ else subject="router config diffs" fi if [ "X$device" != "X" ] ; then - cvs commit -m "updates - courtesy of $mailrcpt" + $RCSSYS commit -m "updates - courtesy of $mailrcpt" subject="$GROUP/$device $subject" else - cvs commit -m updates + $RCSSYS commit -m updates subject="$GROUP $subject" fi # Mail out the diffs (if there are any). -if [ -s $TMP.diff ]; then - sendmail -t <<EMAIL -To: $mailrcpt -Subject: $subject -Precedence: bulk - -`cat $TMP.diff` -EMAIL +if [ -s $TMP.diff ] +then + ( + echo "To: $mailrcpt" + echo "Subject: $subject" + echo "$MAILHEADERS" | awk '{L = "";LN = $0;while (LN ~ /\\n/) { I = index(LN,"\\n");L = L substr(LN,0,I-1) "\n";LN = substr(LN,I+2,length(LN)-I-1);}print L LN;}' + echo "" + cat $TMP.diff + ) | sendmail -t fi # If any machines have not been reached within the last $OLDTIME @@ -412,7 +470,7 @@ then ( echo "To: $adminmailrcpt" echo "Subject: config fetcher problems - $GROUP" - echo "Precedence: bulk" + echo "$MAILHEADERS" | awk '{L = "";LN = $0;while (LN ~ /\\n/) { I = index(LN,"\\n");L = L substr(LN,0,I-1) "\n";LN = substr(LN,I+2,length(LN)-I-1);}print L LN;}' echo "" echo "The following routers have not been successfully contacted for" echo "more than $OLDTIME hours." @@ -422,5 +480,5 @@ then fi # Cleanup -rm -f $TMP.diff $DIR/routers.single +rm -f $TMP.diff $DIR/routers.single $DIR/routers.failed trap '' 1 2 15 diff --git a/bin/cssrancid.in b/bin/cssrancid.in index 27049df..294f400 100644 --- a/bin/cssrancid.in +++ b/bin/cssrancid.in @@ -1,8 +1,9 @@ #! @PERLV_PATH@ ## -## $Id: cssrancid.in,v 1.4 2004/01/11 03:49:13 heas Exp $ +## $Id: cssrancid.in,v 1.13 2006/10/05 04:27:42 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -21,25 +22,30 @@ # # RANCID - Really Awesome New Cisco confIg Differ # -# usage: rancid [-d] [-l] [-f filename | $host] +# usage: rancid [-dV] [-l] [-f filename | hostname] # use Getopt::Std; -getopts('dfl'); +getopts('dflV'); +if ($opt_V) { + print "@PACKAGE@ @VERSION@\n"; + exit(0); +} $log = $opt_l; $debug = $opt_d; $file = $opt_f; $host = $ARGV[0]; $clean_run = 0; $found_end = 0; -$timeo = 90; # clogin timeout in seconds +$timeo = 90; # clogin timeout in seconds -my(%filter_pwds); # password filtering mode +my(@commandtable, %commands, @commands);# command lists +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) { + 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; } @@ -64,7 +70,7 @@ 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort numerically keys(%lines)) { @@ -77,7 +83,7 @@ sub keynsort { # 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort keys(%lines)) { @@ -90,7 +96,7 @@ sub keysort { # 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort values %lines) { @@ -102,7 +108,7 @@ sub valsort{ # This is a numerical sort routine (ascending). sub numsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $num (sort {$a <=> $b} keys %lines) { @@ -116,7 +122,7 @@ sub numsort { # ip address when the ip address is anywhere in # the strings. sub ipsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $addr (sort sortbyipaddr keys %lines) { @@ -129,7 +135,7 @@ sub ipsort { # 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])); + $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0])); } sub sortbyipaddr { &ipaddrval($a) <=> &ipaddrval($b); @@ -141,7 +147,6 @@ sub ShowVersion { while (<INPUT>) { tr/\015//d; - study; last if(/^$prompt/); next if(/^(\s*|\s*$cmd\s*)$/); return(-1) if (/command authorization failed/i); @@ -254,6 +259,8 @@ sub ShowVersion { sub TermLength { # Dummy subroutine.. need to set term length differently for CSS # boxes as term length 0 doesnt work correctly. POS. + print STDERR " In TermLength: $_" if ($debug); + $_ = <INPUT>; return(0); } @@ -264,6 +271,8 @@ sub CopyProfile { ## 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. + print STDERR " In CopyProfile: $_" if ($debug); + $_ = <INPUT>; return(0); } @@ -283,15 +292,16 @@ 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+:)/; + next if (/\*\* BOOT CONFIG /); 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: $_"); @@ -305,17 +315,18 @@ sub ShowBoot { # This routine processes a "show run" sub ShowRun { print STDERR " In ShowRun: $_" if ($debug); - my($lineauto) = 0; + my($lines) = 0; while (<INPUT>) { tr/\015//d; - study; - last if(/^$prompt/); + if(/^$prompt/) { + $found_end = 1 if ($lines > 4); + return(1); + } 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 (<INPUT>) { @@ -335,14 +346,14 @@ sub ShowRun { /^! (Last configuration|NVRAM config last)/ && next; ## CSS specific.... /Generated on/ && next; + $lines++; # 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 + /^ speed / && next; # kill speed on serial lines /^ clockrate / && next; # kill clockrate on serial interfaces if (/^(enable )?(password|passwd) / && $filter_pwds >= 1) { ProcessHistory("ENABLE","","","!$1$2 <removed>\n"); @@ -360,11 +371,9 @@ sub ShowRun { } next; } - if (/^username (\S+)(\s.*)? password ((\d) \S+|\S+)/) { - if ($filter_pwds == 2) { - ProcessHistory("USER","keysort","$1","!username $1$2 password <removed>\n"); - } elsif ($filter_pwds == 1 && $4 ne "5"){ - ProcessHistory("USER","keysort","$1","!username $1$2 password <removed>\n"); + if (/\s*username (\S+)(\s.*)? (des-password|password) (\S+|\S+)/) { + if ($filter_pwds >= 1) { + ProcessHistory("USER","keysort","$1","! username $1$2 $3 <removed>$'\n"); } else { ProcessHistory("USER","keysort","$1","$_"); } @@ -537,11 +546,6 @@ sub ShowRun { # 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); } @@ -550,25 +554,30 @@ sub ShowRun { 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" +@commandtable = ( + {'term length 65535' => 'TermLength'}, + {'copy profile user-profile' => 'CopyProfile'}, + {'show version' => 'ShowVersion'}, + {'show boot' => 'ShowBoot'}, + {'show run' => 'ShowRun'} ); +# Use an array to preserve the order of the commands and a hash for mapping +# commands to the subroutine and track commands that have been completed. +@commands = map(keys(%$_), @commandtable); +%commands = map(%$_, @commandtable); + $cisco_cmds=join(";",@commands); $cmds_regexp=join("|",@commands); +if (length($host) == 0) { + if ($file) { + print(STDERR "Too few arguments: file name required\n"); + exit(1); + } else { + print(STDERR "Too few arguments: host name required\n"); + exit(1); + } +} open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; select(OUTPUT); # make OUTPUT unbuffered if debugging @@ -590,7 +599,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; @@ -599,11 +608,12 @@ if ($ENV{"FILTER_PWDS"} =~ /no/i) { } ProcessHistory("","","","!RANCID-CONTENT-TYPE: cisco-css\n!\n"); -ProcessHistory("COMMENTS","keysort","B0","!\n"); -ProcessHistory("COMMENTS","keysort","F0","!\n"); -ProcessHistory("COMMENTS","keysort","G0","!\n"); +#ProcessHistory("COMMENTS","keysort","B0","!\n"); +#ProcessHistory("COMMENTS","keysort","F0","!\n"); +#ProcessHistory("COMMENTS","keysort","G0","!\n"); TOP: while(<INPUT>) { +NEXT: tr/\015//d; if (/\#\s?exit/) { $clean_run=1; @@ -615,23 +625,27 @@ TOP: while(<INPUT>) { $clean_run=0; last; } - while (/#\s*($cmds_regexp)\s*$/) { + if (/#\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"; - # $clean_run = 0; - # last TOP; - next TOP; - } else { - $rval = &{$commands{$cmd}}; - delete($commands{$cmd}); - if ($rval == -1) { - $clean_run = 0; - last TOP; - } + $clean_run = 0; + last TOP; + } + $rval = &{$commands{$cmd}}; + delete($commands{$cmd}); + if ($rval == -1) { + $clean_run = 0; + last TOP; } + # the function may have read the next prompt/cmd line + goto NEXT; } } print STDOUT "Done $logincmd: $_\n" if ($log); diff --git a/bin/elogin.in b/bin/elogin.in index 651d7fb..d581101 100644 --- a/bin/elogin.in +++ b/bin/elogin.in @@ -1,8 +1,9 @@ #! @EXPECT_PATH@ -- ## -## $Id: elogin.in,v 1.27 2004/01/11 05:39:15 heas Exp $ +## $Id: elogin.in,v 1.38 2006/12/05 16:50:52 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -40,7 +41,7 @@ set password_file $env(HOME)/.cloginrc set do_command 0 set do_script 0 # The default is to automatically enable -set enable 1 +set avenable 1 # The default is that you login non-enabled (tacacs can have you login already # enabled) set avautoenable 0 @@ -49,7 +50,7 @@ set avautoenable 0 set do_passwd 1 # Find the user in the ENV, or use the unix userid. -if {[ info exists env(CISCO_USER) ] } { +if {[ info exists env(CISCO_USER) ]} { set default_user $env(CISCO_USER) } elseif {[ info exists env(USER) ]} { set default_user $env(USER) @@ -62,9 +63,12 @@ if {[ info exists env(CISCO_USER) ] } { if [ catch {exec id} reason ] { send_error "\nError: could not exec id: $reason\n" exit 1 - } + } regexp {\(([^)]*)} "$reason" junk default_user -} +} +if {[ info exists env(CLOGINRC) ]} { + set password_file $env(CLOGINRC) +} # Sometimes routers take awhile to answer (the default is 10 sec) set timeout 45 @@ -90,13 +94,16 @@ for {set i 0} {$i < $argc} {incr i} { } set do_passwd 0 # VTY Password - } -v* - - -v* { + } -v* { if {! [ regexp .\[vV\](.+) $arg ignore passwd]} { incr i set passwd [ lindex $argv $i ] } set do_passwd 0 + # Version string + } -V* { + send_user "@PACKAGE@ @VERSION@\n" + exit 0 # Enable Username } -w* - -W* { @@ -268,31 +275,44 @@ proc source_password_file { password_file } { } # Log into the router. +# returns: 0 on success, 1 on failure 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 + set uprompt_seen 0 # try each of the connection methods in $cmethod until one is successful set progs [llength $cmethod] foreach prog [lrange $cmethod 0 end] { + incr progs -1 if [string match "telnet*" $prog] { regexp {telnet(:([^[:space:]]+))*} $prog command suffix port if {"$port" == ""} { - set retval [ catch {spawn telnet $router} reason ] - } else { + set retval [ catch {spawn telnet $router} reason ] + } else { set retval [ catch {spawn telnet $router $port} reason ] } if { $retval } { send_user "\nError: telnet failed: $reason\n" - exit 1 + return 1 } + } elseif ![string compare $prog "ssh"] { + send_error "\nError: unsupported method: ssh\n" + if { $progs == 0 } { + return 1 + } + continue + } elseif ![string compare $prog "rsh"] { + send_error "\nError: unsupported method: rsh\n" + if { $progs == 0 } { + return 1 + } + continue } else { - puts "\nError: unknown connection method: $prog" + send_user "\nError: unknown connection method: $prog\n" return 1 } - incr progs -1 sleep 0.3 # This helps cleanup each expect clause. @@ -394,9 +414,11 @@ proc run_commands { prompt command } { } send "exit\r" expect { - "\n" { exp_continue } - timeout { return 0 } - eof { return 0 } + "\n" { exp_continue } + timeout { catch {close}; wait + return 0 + } + eof { return 0 } } set in_proc 0 } diff --git a/bin/erancid.in b/bin/erancid.in index 20da43d..a95da84 100644 --- a/bin/erancid.in +++ b/bin/erancid.in @@ -1,8 +1,9 @@ #! @PERLV_PATH@ ## -## $Id: erancid.in,v 1.18 2004/01/11 03:49:13 heas Exp $ +## $Id: erancid.in,v 1.26 2006/10/05 04:27:42 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -21,25 +22,30 @@ # # RANCID - Really Awesome New Cisco confIg Differ # -# usage: rancid [-d] [-l] [-f filename | $host] +# usage: rancid [-dV] [-l] [-f filename | hostname] # use Getopt::Std; -getopts('dfl'); +getopts('dflV'); +if ($opt_V) { + print "@PACKAGE@ @VERSION@\n"; + exit(0); +} $log = $opt_l; $debug = $opt_d; $file = $opt_f; $host = $ARGV[0]; $clean_run = 0; $found_end = 0; -$timeo = 90; # clogin timeout in seconds +$timeo = 90; # elogin timeout in seconds -my(%filter_pwds); # password filtering mode +my(@commandtable, %commands, @commands);# command lists +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) { + 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; } @@ -61,10 +67,10 @@ sub ProcessHistory { sub numerically { $a <=> $b; } -# This is a sort routing that will sort numerically on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort numerically keys(%lines)) { @@ -74,10 +80,10 @@ sub keynsort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort keys(%lines)) { @@ -87,10 +93,10 @@ sub keysort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort values %lines) { @@ -100,9 +106,9 @@ sub valsort{ @sorted_lines; } -# This is a numerical sort routing (ascending). +# This is a numerical sort routine (ascending). sub numsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $num (sort {$a <=> $b} keys %lines) { @@ -116,7 +122,7 @@ sub numsort { # ip address when the ip address is anywhere in # the strings. sub ipsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $addr (sort sortbyipaddr keys %lines) { @@ -129,7 +135,7 @@ sub ipsort { # 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])); + $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0])); } sub sortbyipaddr { &ipaddrval($a) <=> &ipaddrval($b); @@ -168,8 +174,8 @@ sub ShowModule { # now just copy it verbatim to the history file while (<INPUT>) { - tr/\015//d; - last if(/Active\) >/); + tr/\015//d; + last if(/Active\) >/); last if(/^$/); chop; ProcessHistory("SLOT","","","-$_\n"); @@ -186,8 +192,8 @@ sub WriteTerm { # now just copy it verbatim to the history file while (<INPUT>) { - tr/\015//d; - last if(/Active\) >/); + tr/\015//d; + last if(/Active\) >/); chop; if (/^\s*snmp/ && defined($ENV{'NOCOMMSTR'})) { /snmp (getcomm|setcomm|trapcomm)(\s+)(\S*)/ && @@ -204,21 +210,28 @@ sub WriteTerm { sub DoNothing {print STDOUT;} # Main -%commands=( - 'version' => "ShowVersion", - 'equipment' => "ShowModule", - 'config' => "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=( - "version", - "equipment", - "config", +@commandtable = ( + {'version' => 'ShowVersion'}, + {'equipment' => 'ShowModule'}, + {'config' => 'WriteTerm'} ); +# Use an array to preserve the order of the commands and a hash for mapping +# commands to the subroutine and track commands that have been completed. +@commands = map(keys(%$_), @commandtable); +%commands = map(%$_, @commandtable); + $cisco_cmds=join(";",@commands); $cmds_regexp=join("|",@commands); +if (length($host) == 0) { + if ($file) { + print(STDERR "Too few arguments: file name required\n"); + exit(1); + } else { + print(STDERR "Too few arguments: host name required\n"); + exit(1); + } +} open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; select(OUTPUT); # make OUTPUT unbuffered if debugging @@ -241,7 +254,7 @@ if ($file) { # determine password filtering mode if ($ENV{"FILTER_PWDS"} =~ /no/i) { - $filter_pwds = 0; + $filter_pwds = 0; } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) { $filter_pwds = 2; } else { diff --git a/bin/f10rancid.in b/bin/f10rancid.in index 2c4e485..e61d215 100644 --- a/bin/f10rancid.in +++ b/bin/f10rancid.in @@ -1,8 +1,9 @@ #! @PERLV_PATH@ ## -## $Id: f10rancid.in,v 1.11 2004/01/11 03:49:13 heas Exp $ +## $Id: f10rancid.in,v 1.23 2006/10/05 04:27:42 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -23,25 +24,30 @@ # # RANCID - Really Awesome New Cisco confIg Differ # -# usage: rancid [-d] [-l] [-f filename | $host] +# usage: rancid [-dV] [-l] [-f filename | hostname] # use Getopt::Std; -getopts('dfl'); +getopts('dflV'); +if ($opt_V) { + print "@PACKAGE@ @VERSION@\n"; + exit(0); +} $log = $opt_l; $debug = $opt_d; $file = $opt_f; $host = $ARGV[0]; $clean_run = 0; $found_end = 0; -$timeo = 90; # clogin timeout in seconds +$timeo = 90; # clogin timeout in seconds -my(%filter_pwds); # password filtering mode +my(@commandtable, %commands, @commands);# command lists +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) { + 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; } @@ -63,10 +69,10 @@ sub ProcessHistory { sub numerically { $a <=> $b; } -# This is a sort routing that will sort numerically on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort numerically keys(%lines)) { @@ -76,10 +82,10 @@ sub keynsort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort keys(%lines)) { @@ -89,10 +95,10 @@ sub keysort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort values %lines) { @@ -102,9 +108,9 @@ sub valsort{ @sorted_lines; } -# This is a numerical sort routing (ascending). +# This is a numerical sort routine (ascending). sub numsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $num (sort {$a <=> $b} keys %lines) { @@ -118,7 +124,7 @@ sub numsort { # ip address when the ip address is anywhere in # the strings. sub ipsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $addr (sort sortbyipaddr keys %lines) { @@ -131,7 +137,7 @@ sub ipsort { # 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])); + $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0])); } sub sortbyipaddr { &ipaddrval($a) <=> &ipaddrval($b); @@ -360,41 +366,6 @@ sub ShowEnv { return(0); } -# This routine parses "show gsr chassis-info" for the gsr -# This will create arrays for hw info. -sub ShowGSR { - # Skip if this is not a 1200n. - print STDERR " In ShowGSR: $_" if ($debug); - - while (<INPUT>) { - 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]/); - /^$/ && next; - /^\s+Chassis: type (\S+) Fab Ver: (\S+)/ && - ProcessHistory("COMMENTS","keysort","D0","!\n") && - ProcessHistory("COMMENTS","keysort","D1", - "!GSR Chassis type: $1 Fab Ver: $2\n") && - next; - /^\s+Chassis S\/N: (.*)$/ && - ProcessHistory("COMMENTS","keysort","D2", - "!GSR Chassis S/N: $1\n") && - next; - /^\s+PCA: (\S+)\s*rev: (\S+)\s*dev: \S+\s*HW ver: (\S+)$/ && - ProcessHistory("COMMENTS","keysort","D3", - "!GSR Backplane PCA: $1, rev $2, ver $3\n") && - next; - /^\s+Backplane S\/N: (\S+)$/ && - ProcessHistory("COMMENTS","keysort","D4", - "!GSR Backplane S/N: $1\n") && - next; - } - ProcessHistory("COMMENTS","","","!\n"); - return(0); -} - # This routine parses "show boot" sub ShowBoot { # Pick up boot variables if 7000/7200/7500/12000/2900/3500; @@ -416,9 +387,9 @@ sub ShowBoot { } 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: $_"); @@ -800,41 +771,6 @@ sub ShowModule { return(0); } -# This routine parses "show c7200" for the 7200 -# This will create arrays for hw info. -sub ShowC7200 { - # Skip if this is not a 7200. - print STDERR " In ShowC7200: $_" if ($debug); - - while (<INPUT>) { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - #return(1) if ($type !~ /^72/); - return(-1) if (/command authorization failed/i); - /^$/ && next; - if (/C7200 Midplane EEPROM:/) { - $_ = <INPUT>; - /revision\s+(\S+).*revision\s+(\S+)/; - ProcessHistory("SLOT","","","!Slot Midplane: hvers $1 rev $2\n"); - $_ = <INPUT>; - /number\s+(\S+)\s+Part number\s+(\S+)/; - ProcessHistory("SLOT","","","!Slot Midplane: part $2, serial $1\n!\n"); - next; - } - if (/C720\d(VXR)? CPU EEPROM:/) { - $_ = <INPUT>; - /revision\s+(\S+).*revision\s+(\S+)/ && - ProcessHistory("SLOT","","","!Slot CPU: hvers $1 rev $2\n"); - $_ = <INPUT>; - /number\s+(\S+)\s+Part number\s+(\S+)/ && - ProcessHistory("SLOT","","","!Slot CPU: part $2, serial $1\n!\n"); - next; - } - } - return(0); -} - # This routine parses "show vtp status" sub ShowVTP { print STDERR " In ShowVTP: $_" if ($debug); @@ -890,7 +826,7 @@ sub WriteTerm { # skip the crap if (/^(##+$|(Building|Current) configuration)/i) { while (<INPUT>) { - next if (/^Current configuration\s*:/i); + next if (/^!?Current configuration\s*:/i); next if (/^:/); next if (/^([%!].*|\s*)$/); next if (/^ip add.*ipv4:/); # band-aid for 3620 12.0S @@ -1109,65 +1045,48 @@ sub WriteTerm { sub DoNothing {print STDOUT;} # Main -%commands=( - 'show version' => "ShowVersion", - 'show install active' => "ShowInstallActive", - 'show env all' => "ShowEnv", - 'show gsr chassis' => "ShowGSR", - 'show boot' => "ShowBoot", - 'show bootvar' => "ShowBoot", - 'show variables boot' => "ShowBoot", - 'show flash' => "ShowFlash", - 'dir /all nvram:' => "DirSlotN", - 'dir /all bootflash:' => "DirSlotN", - 'dir /all slot0:' => "DirSlotN", - 'dir /all disk0:' => "DirSlotN", - 'dir /all slot1:' => "DirSlotN", - 'dir /all disk1:' => "DirSlotN", - "dir /all sup-bootflash:"=> "DirSlotN", # cat 6500-ios - "dir /all sup-microcode:"=> "DirSlotN", # cat 6500-ios - 'show controllers' => "ShowContAll", - 'show controllers cbus' => "ShowContCbus", - 'show diagbus' => "ShowDiagbus", - 'show diag' => "ShowDiag", - 'show module' => "ShowModule", # cat 6500-ios - 'show c7200' => "ShowC7200", - 'show vtp status' => "ShowVTP", - 'show vlan' => "ShowVLAN", - 'show running' => "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 install active", - "show env all", - "show gsr chassis", - "show boot", - "show bootvar", - "show variables boot", - "show flash", - "dir /all nvram:", - "dir /all bootflash:", - "dir /all slot0:", - "dir /all disk0:", - "dir /all slot1:", - "dir /all disk1:", - "dir /all sup-bootflash:", - "dir /all sup-microcode:", - "show controllers", - "show controllers cbus", - "show diagbus", - "show diag", - "show module", - "show c7200", - "show vtp status", - "show vlan", - "show running" +@commandtable = ( + {'show version' => 'ShowVersion'}, + {'show install active' => 'ShowInstallActive'}, + {'show env all' => 'ShowEnv'}, + {'show boot' => 'ShowBoot'}, + {'show bootvar' => 'ShowBoot'}, + {'show variables boot' => 'ShowBoot'}, + {'show flash' => 'ShowFlash'}, + {'dir /all nvram:' => 'DirSlotN'}, + {'dir /all bootflash:' => 'DirSlotN'}, + {'dir /all slot0:' => 'DirSlotN'}, + {'dir /all disk0:' => 'DirSlotN'}, + {'dir /all slot1:' => 'DirSlotN'}, + {'dir /all disk1:' => 'DirSlotN'}, + {'dir /all sup-bootflash:' => 'DirSlotN'}, + {'dir /all sup-microcode:' => 'DirSlotN'}, + {'show controllers' => 'ShowContAll'}, + {'show controllers cbus' => 'ShowContCbus'}, + {'show diagbus' => 'ShowDiagbus'}, + {'show diag' => 'ShowDiag'}, + {'show module' => 'ShowModule'}, + {'show vtp status' => 'ShowVTP'}, + {'show vlan' => 'ShowVLAN'}, + {'show running' => 'WriteTerm'} ); +# Use an array to preserve the order of the commands and a hash for mapping +# commands to the subroutine and track commands that have been completed. +@commands = map(keys(%$_), @commandtable); +%commands = map(%$_, @commandtable); + $cisco_cmds=join(";",@commands); $cmds_regexp=join("|",@commands); +if (length($host) == 0) { + if ($file) { + print(STDERR "Too few arguments: file name required\n"); + exit(1); + } else { + print(STDERR "Too few arguments: host name required\n"); + exit(1); + } +} open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; select(OUTPUT); # make OUTPUT unbuffered if debugging @@ -1189,7 +1108,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; diff --git a/bin/flogin.in b/bin/flogin.in index 169e522..5c8813d 100644 --- a/bin/flogin.in +++ b/bin/flogin.in @@ -1,8 +1,9 @@ #! @EXPECT_PATH@ -- ## -## $Id: flogin.in,v 1.32 2004/01/11 05:39:15 heas Exp $ +## $Id: flogin.in,v 1.47 2006/12/08 21:28:26 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -50,7 +51,7 @@ set password_file $env(HOME)/.cloginrc set do_command 0 set do_script 0 # The default is to automatically enable -set enable 1 +set avenable 1 # The default is that you login non-enabled (tacacs can have you login already # enabled) set avautoenable 0 @@ -60,7 +61,7 @@ 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) ] } { +if {[ info exists env(CISCO_USER) ]} { set default_user $env(CISCO_USER) } elseif {[ info exists env(USER) ]} { set default_user $env(USER) @@ -73,9 +74,12 @@ if {[ info exists env(CISCO_USER) ] } { if [ catch {exec id} reason ] { send_error "\nError: could not exec id: $reason\n" exit 1 - } + } regexp {\(([^)]*)} "$reason" junk default_user -} +} +if {[ info exists env(CLOGINRC) ]} { + set password_file $env(CLOGINRC) +} # Sometimes routers take awhile to answer (the default is 10 sec) set timeout 45 @@ -101,13 +105,16 @@ for {set i 0} {$i < $argc} {incr i} { } set do_passwd 0 # VTY Password - } -v* - - -v* { + } -v* { if {! [ regexp .\[vV\](.+) $arg ignore passwd]} { incr i set passwd [ lindex $argv $i ] } set do_passwd 0 + # Version string + } -V* { + send_user "@PACKAGE@ @VERSION@\n" + exit 0 # Enable Username } -w* - -W* { @@ -186,11 +193,11 @@ for {set i 0} {$i < $argc} {incr i} { set do_command 1 # Do we enable? } -noenable { - set enable 0 + set avenable 0 # Does tacacs automatically enable us? } -autoenable { set avautoenable 1 - set enable 0 + set avenable 0 } -* { send_user "\nError: Unknown argument! $arg\n" send_user $usage @@ -244,9 +251,9 @@ proc include {args} { 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 @@ -264,7 +271,7 @@ proc find {var router} { # 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 +# 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] } { @@ -283,6 +290,7 @@ proc source_password_file { password_file } { } # Log into the router. +# returns: 0 on success, 1 on failure 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 @@ -292,6 +300,7 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype } { # try each of the connection methods in $cmethod until one is successful set progs [llength $cmethod] foreach prog [lrange $cmethod 0 end] { + incr progs -1 if [string match "telnet*" $prog] { regexp {telnet(:([^[:space:]]+))*} $prog command suffix port if {"$port" == ""} { @@ -301,23 +310,23 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype } { } if { $retval } { send_user "\nError: telnet failed: $reason\n" - exit 1 + return 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 + return 1 } } elseif ![string compare $prog "rsh"] { - if [ catch {spawn rsh -l $user $router} reason ] { - send_user "\nError: rsh failed: $reason\n" - exit 1 + send_error "\nError: unsupported method: rsh\n" + if { $progs == 0 } { + return 1 } + continue; } else { - puts "\nError: unknown connection method: $prog" + send_user "\nError: unknown connection method: $prog\n" return 1 } - incr progs -1 sleep 0.3 # This helps cleanup each expect clause. @@ -354,15 +363,15 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype } { 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 closed ($prog): $router\n" return 1 - } - } + } + } -re "Telnet server disabled" { catch {close}; wait if !$progs { @@ -500,12 +509,14 @@ proc run_commands { prompt command } { } send "exit\r" expect { - "\n" { exp_continue } - -re "^\[^ ]+>" { - send "exit\r" - exp_continue } - timeout { return 0 } - eof { return 0 } + "\n" { exp_continue } + -re "^\[^ ]+>" { send "exit\r" + exp_continue + } + timeout { catch {close}; wait + return 0 + } + eof { return 0 } } set in_proc 0 } @@ -535,6 +546,7 @@ foreach router [lrange $argv $i end] { set prompt "#" } else { set autoenable 0 + set enable $avenable set prompt ">" } } @@ -545,23 +557,26 @@ foreach router [lrange $argv $i end] { if { [llength $pswd] == 0 } { send_user "\nError: no password for $router in $password_file.\n" continue - } + } if { $enable && $do_enapasswd && $autoenable == 0 && [llength $pswd] < 2 } { send_user "\nError: no enable password for $router in $password_file.\n" continue } set passwd [join [lindex $pswd 0] ""] set enapasswd [join [lindex $pswd 1] ""] + } else { + set passwd $userpasswd + set enapasswd $enapasswd } # Figure out username - if {[info exists username]} { + 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]} { @@ -569,22 +584,22 @@ foreach router [lrange $argv $i end] { set userpswd $userpasswd } else { set userpswd [join [find userpassword $router] ""] - if { "$userpswd" == "" } { set userpswd $passwd } - } - + if { "$userpswd" == "" } { set userpswd $passwd } + } + # Figure out enable username - if {[info exists enausername]} { + if {[info exists enausername]} { # command line enausername set enauser $enausername } else { set enauser [join [find enauser $router] ""] - if { "$enauser" == "" } { set enauser $ruser } - } + if { "$enauser" == "" } { set enauser $ruser } + } # Figure out prompts set u_prompt [find userprompt $router] if { "$u_prompt" == "" } { - set u_prompt "(Username|login|Name|User Name):" + set u_prompt "(Username|login|Name|User Name) *:" } else { set u_prompt [join [lindex $u_prompt 0] ""] } @@ -614,18 +629,18 @@ 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} } + # 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 } - if { $enable } { + if { $enable } { if {[do_enable $enauser $enapasswd]} { if { $do_command || $do_script } { - close; wait + catch {close}; catch {wait} continue } } @@ -642,7 +657,7 @@ foreach router [lrange $argv $i end] { source $sfile close } else { - label $router + label $router log_user 1 interact } diff --git a/bin/fnrancid.in b/bin/fnrancid.in index 815227b..b14906a 100644 --- a/bin/fnrancid.in +++ b/bin/fnrancid.in @@ -1,8 +1,9 @@ #! @PERLV_PATH@ ## -## $Id: fnrancid.in,v 1.3 2004/01/11 03:49:13 heas Exp $ +## $Id: fnrancid.in,v 1.11 2006/10/05 04:27:42 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -20,29 +21,34 @@ ## # # A library built on Stephen Gill's Netscreen stuff to accomodate -# the Fortinet product line. [d_pfleger@juniper.net] +# the Fortinet product line. [d_pfleger@juniper.net] # # RANCID - Really Awesome New Cisco confIg Differ # -# usage: rancid [-d] [-l] [-f filename | $host] +# usage: rancid [-dV] [-l] [-f filename | hostname] # use Getopt::Std; -getopts('dfl'); +getopts('dflV'); +if ($opt_V) { + print "@PACKAGE@ @VERSION@\n"; + exit(0); +} $log = $opt_l; $debug = $opt_d; #$debug = 1; $file = $opt_f; $host = $ARGV[0]; $found_end = 0; -$timeo = 90; # nlogin timeout in seconds +$timeo = 90; # nlogin timeout in seconds -my(%filter_pwds); # password filtering mode +my(@commandtable, %commands, @commands);# command lists +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) { + 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; } @@ -64,10 +70,10 @@ sub ProcessHistory { sub numerically { $a <=> $b; } -# This is a sort routing that will sort numerically on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort numerically keys(%lines)) { @@ -77,10 +83,10 @@ sub keynsort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort keys(%lines)) { @@ -90,22 +96,22 @@ sub keysort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort values %lines) { - $sorted_lines[$i] = $key; - $i++; + $sorted_lines[$i] = $key; + $i++; } @sorted_lines; } -# This is a numerical sort routing (ascending). +# This is a numerical sort routine (ascending). sub numsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $num (sort {$a <=> $b} keys %lines) { @@ -119,7 +125,7 @@ sub numsort { # ip address when the ip address is anywhere in # the strings. sub ipsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $addr (sort sortbyipaddr keys %lines) { @@ -132,7 +138,7 @@ sub ipsort { # 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])); + $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0])); } sub sortbyipaddr { &ipaddrval($a) <=> &ipaddrval($b); @@ -146,7 +152,7 @@ sub GetSystem { tr/\015//d; next if /^\s*$/; last if(/$prompt/); - ProcessHistory("","","","$_"); + ProcessHistory("","","","$_"); #print STDOUT "$_"; } print STDOUT "Vendor: $vendor"; @@ -170,9 +176,9 @@ sub GetConf { next if /^\s*$/; last if(/$prompt/); if (/(^set.*)('Enc .*')(.*)/) { - ProcessHistory("ENC","","","!$1 'Enc **encoding removed**' $3\n"); - next; - } + ProcessHistory("ENC","","","!$1 'Enc **encoding removed**' $3\n"); + next; + } ProcessHistory("","","","$_"); #print STDOUT "$_"; } @@ -184,19 +190,27 @@ sub GetConf { 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" +@commandtable = ( + {'get system status' => 'GetSystem'}, + {'get conf' => 'GetConf'} ); +# Use an array to preserve the order of the commands and a hash for mapping +# commands to the subroutine and track commands that have been completed. +@commands = map(keys(%$_), @commandtable); +%commands = map(%$_, @commandtable); + $cisco_cmds=join(";",@commands); $cmds_regexp=join("|",@commands); +if (length($host) == 0) { + if ($file) { + print(STDERR "Too few arguments: file name required\n"); + exit(1); + } else { + print(STDERR "Too few arguments: host name required\n"); + exit(1); + } +} open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; select(OUTPUT); # make OUTPUT unbuffered if debugging @@ -218,7 +232,7 @@ if ($file) { # determine password filtering mode if ($ENV{"FILTER_PWDS"} =~ /no/i) { - $filter_pwds = 0; + $filter_pwds = 0; } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) { $filter_pwds = 2; } else { diff --git a/bin/francid.in b/bin/francid.in index e1fd284..2967a34 100644 --- a/bin/francid.in +++ b/bin/francid.in @@ -1,8 +1,9 @@ #! @PERLV_PATH@ ## -## $Id: francid.in,v 1.26 2004/01/11 03:49:13 heas Exp $ +## $Id: francid.in,v 1.42 2006/10/05 05:43:31 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -24,25 +25,30 @@ # # RANCID - Really Awesome New Cisco confIg Differ # -# usage: rancid [-d] [-l] [-f filename | $host] +# usage: rancid [-dV] [-l] [-f filename | hostname] # use Getopt::Std; -getopts('dfl'); +getopts('dflV'); +if ($opt_V) { + print "@PACKAGE@ @VERSION@\n"; + exit(0); +} $log = $opt_l; $debug = $opt_d; $file = $opt_f; $host = $ARGV[0]; $clean_run = 0; $found_end = 0; -$timeo = 90; # flogin timeout in seconds +$timeo = 90; # flogin timeout in seconds -my(%filter_pwds); # password filtering mode +my(@commandtable, %commands, @commands);# command lists +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) { + 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; } @@ -64,10 +70,10 @@ sub ProcessHistory { sub numerically { $a <=> $b; } -# This is a sort routing that will sort numerically on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort numerically keys(%lines)) { @@ -77,10 +83,10 @@ sub keynsort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort keys(%lines)) { @@ -90,22 +96,22 @@ sub keysort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort values %lines) { - $sorted_lines[$i] = $key; - $i++; + $sorted_lines[$i] = $key; + $i++; } @sorted_lines; } -# This is a numerical sort routing (ascending). +# This is a numerical sort routine (ascending). sub numsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $num (sort {$a <=> $b} keys %lines) { @@ -119,7 +125,7 @@ sub numsort { # ip address when the ip address is anywhere in # the strings. sub ipsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $addr (sort sortbyipaddr keys %lines) { @@ -132,7 +138,7 @@ sub ipsort { # 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])); + $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0])); } sub sortbyipaddr { &ipaddrval($a) <=> &ipaddrval($b); @@ -147,14 +153,17 @@ sub ShowVersion { while (<INPUT>) { tr/\015//d; next if /^\s*$/; - last if(/^$prompt/); + last if (/^$prompt/); next if (/^(The system |Crash time)/); + next if (/^((Active|Standby) Management|LP Slot \d+) uptime is/); s/^\s*(HW|SW)/$1/; s/^\s*(Compiled on)/SW: $1/; + s/^\s*(\(\d+ bytes\) from )/SW: $1/; + #s/^(HW.*)/$1\n/; - if (/^SL (\d)/) { + if (/^SL (\d+)/) { $slot = "Slot $1"; s/^SL \d+/$slot/; } @@ -172,6 +181,8 @@ sub ShowVersion { # This routine parses "show chassis" sub ShowChassis { + my($skip) = 0; + print STDERR " In ShowChassis: $_" if ($debug); while (<INPUT>) { @@ -179,6 +190,28 @@ sub ShowChassis { last if (/^$prompt/); next if (/ from /); next if (/current temperature/i); + + if (/^---/ || /^$/) { # next section reached + $skip = 0; + } + if (/(POWERS|TEMPERATURE READINGS)/) { + $skip = 1; + } + if (/fan controlled temperature:/i) { + $skip = 1; + } + if (/THERMAL PLANE/) { + $skip = 1; + } + if (/temperature:/i) { + $skip = 1; + } + s/(Fan \d+ \S+), speed .*/$1/; + if (/speed/i) { + $skip = 1; + } + next if $skip; + ProcessHistory("CHASSIS","","","! $_"); } ProcessHistory("CHASSIS","","","!\n"); @@ -191,8 +224,8 @@ sub ShowFlash { while (<INPUT>) { tr/\015//d; - last if(/^$prompt/); - next if /^\s*$/; + last if (/^$prompt/); + next if (/^\s*$/); ProcessHistory("FLASH","","","!Flash: $_"); } ProcessHistory("","","","!\n"); @@ -205,9 +238,10 @@ sub ShowModule { while (<INPUT>) { tr/\015//d; - last if(/^$prompt/); - next if /^\s*$/; - next if /:\s*$/; + last if (/^$prompt/); + return(1) if (/Invalid input ->/); + next if (/^\s*$/); + next if (/:\s*$/); ProcessHistory("MODULE","","","!Module: $_"); } ProcessHistory("","","","!\n"); @@ -220,17 +254,24 @@ sub WriteTerm { while (<INPUT>) { tr/\015//d; - last if(/^$prompt/); + last if (/^$prompt/); /Current configuration:/i && next; /^ver \d+\.\d+/ && next; /^module \d+ / && next; /^ntp clock-period / && next; # kill ntp clock-period - /^ length / && next; # kill length on serial lines - /^ width / && next; # kill width on serial lines + /^ length / && next; # kill length on serial lines + /^ width / && next; # kill width on serial lines # filter out any RCS/CVS tags to avoid confusing local CVS storage s/\$(Revision|Id):/ $1:/; + # sort secure-mac-addresses. Note: There is no way to determine which + # have been added dynamically vs statically. Thus, sort them? + /secure-mac-address (\S+)/ && + ProcessHistory("SECMAC","keysort","$1","$_") && next; + # OR filter them? XXX + #next if (/secure-mac-address/); + # order access-lists /^access-list\s+(\d+)\s+(perm|deny)\s+(\d\S+)(\/\d+)\s*$/ && ProcessHistory("PACL $1 $2","ipsort","$3","$_") @@ -301,6 +342,23 @@ sub WriteTerm { next; } + # reorder listing of ports in a vlan + if (/^ (?:un)?tagged ethe/) { + chomp; + s/^\s+//; + s/\s+$//; + + my @list = split /\s+ethe\s+/, $_; + my $tagtype = shift @list; + + while (@list) { + ProcessHistory("","","", + " $tagtype ethe " . (shift @list) . "\n"); + } + next; + } + + ProcessHistory("","","","$_"); # end of config if (/^end$/) { @@ -315,25 +373,30 @@ sub WriteTerm { sub DoNothing {print STDOUT;} # Main -%commands=( - 'show version' => "ShowVersion", - 'show chassis' => "ShowChassis", - 'show module' => "ShowModule", - 'show flash' => "ShowFlash", - 'write term' => "WriteTerm" -); -# keys() doesnt return things in the order entered and the order of the -# cmds is important. pita -@commands=( - "show version", - "show chassis", - "show module", - "show flash", - "write term" +@commandtable = ( + {'show version' => 'ShowVersion'}, + {'show chassis' => 'ShowChassis'}, + {'show module' => 'ShowModule'}, + {'show flash' => 'ShowFlash'}, + {'write term' => 'WriteTerm'} ); +# Use an array to preserve the order of the commands and a hash for mapping +# commands to the subroutine and track commands that have been completed. +@commands = map(keys(%$_), @commandtable); +%commands = map(%$_, @commandtable); + $cisco_cmds=join(";",@commands); $cmds_regexp=join("|",@commands); +if (length($host) == 0) { + if ($file) { + print(STDERR "Too few arguments: file name required\n"); + exit(1); + } else { + print(STDERR "Too few arguments: host name required\n"); + exit(1); + } +} open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; select(OUTPUT); # make OUTPUT unbuffered if debugging @@ -356,7 +419,7 @@ if ($file) { # determine password filtering mode if ($ENV{"FILTER_PWDS"} =~ /no/i) { - $filter_pwds = 0; + $filter_pwds = 0; } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) { $filter_pwds = 2; } else { diff --git a/bin/hlogin.in b/bin/hlogin.in index 6af11b4..8777021 100644 --- a/bin/hlogin.in +++ b/bin/hlogin.in @@ -1,8 +1,9 @@ #! @EXPECT_PATH@ -- ## -## $Id: hlogin.in,v 1.21 2004/01/11 05:39:15 heas Exp $ +## $Id: hlogin.in,v 1.40 2006/12/08 21:28:26 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -47,7 +48,7 @@ set password_file $env(HOME)/.cloginrc set do_command 0 set do_script 0 # The default is to automatically enable -set enable 1 +set avenable 1 # The default is that you login non-enabled (tacacs can have you login already # enabled) set avautoenable 0 @@ -57,9 +58,11 @@ set do_passwd 1 set do_enapasswd 1 # attempt at platform switching. set platform "" +# +set send_human {.4 .4 .7 .3 5} # Find the user in the ENV, or use the unix userid. -if {[ info exists env(CISCO_USER) ] } { +if {[ info exists env(CISCO_USER) ]} { set default_user $env(CISCO_USER) } elseif {[ info exists env(USER) ]} { set default_user $env(USER) @@ -75,6 +78,9 @@ if {[ info exists env(CISCO_USER) ] } { } regexp {\(([^)]*)} "$reason" junk default_user } +if {[ info exists env(CLOGINRC) ]} { + set password_file $env(CLOGINRC) +} # Sometimes routers take awhile to answer (the default is 10 sec) set timeout 45 @@ -100,13 +106,16 @@ for {set i 0} {$i < $argc} {incr i} { } set do_passwd 0 # VTY Password - } -v* - - -v* { + } -v* { if {! [ regexp .\[vV\](.+) $arg ignore passwd]} { incr i set passwd [ lindex $argv $i ] } set do_passwd 0 + # Version string + } -V* { + send_user "@PACKAGE@ @VERSION@\n" + exit 0 # Enable Username } -w* - -W* { @@ -181,20 +190,20 @@ for {set i 0} {$i < $argc} {incr i} { } if [ catch {set cmd_fd [open $cmd_file r]} reason ] { send_user "\nError: $reason\n" - exit 1 - } + 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 + set avenable 0 # Does tacacs automatically enable us? } -autoenable { # hp does not autoenable #set autoenable 1 - #set enable 0 + #set avenable 0 } -* { send_user "\nError: Unknown argument! $arg\n" send_user $usage @@ -244,25 +253,25 @@ proc label { host } { # add password * hanky-pie proc add {var args} { global int_$var ; lappend int_$var $args} proc include {args} { - global env - regsub -all "(^{|}$)" $args {} 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 + upvar int_$var list if { [info exists list] } { foreach line $list { if { [string match [lindex $line 0] $router ] } { return [lrange $line 1 end] - } - } - } - return {} -} + } + } + } + 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 @@ -287,6 +296,7 @@ proc source_password_file { password_file } { } # Log into the router. +# returns: 0 on success, 1 on failure 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 @@ -295,37 +305,38 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype } { # try each of the connection methods in $cmethod until one is successful set progs [llength $cmethod] foreach prog [lrange $cmethod 0 end] { + incr progs -1 regexp {(telnet|ssh)(:([^[:space:]]+))*} $prog command suffix junk port if [string match "telnet*" $prog] { if {"$port" == ""} { - set retval [ catch {spawn hpuifilter telnet $router} reason ] + set retval [ catch {spawn hpuifilter -- telnet $router} reason ] } else { - set retval [ catch {spawn hpuifilter telnet $router $port} reason ] + set retval [ catch {spawn hpuifilter -- telnet $router $port} reason ] } if { $retval } { send_user "\nError: telnet failed: $reason\n" - exit 1 + return 1 } } elseif [string match "ssh*" $prog] { if {"$port" == ""} { - set retval [ catch {spawn hpuifilter $sshcmd -c $cyphertype -x -l $user $router} reason ] + 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 ] + 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 + return 1 } } elseif ![string compare $prog "rsh"] { - if [ catch {spawn hpuifilter rsh -l $user $router} reason ] { - send_user "\nError: rsh failed: $reason\n" - exit 1 + send_error "\nError: unsupported method: rsh\n" + if { $progs == 0 } { + return 1 } + continue; } else { - puts "\nError: unknown connection method: $prog" + send_user "\nError: unknown connection method: $prog\n" return 1 } - incr progs -1 sleep 0.3 # This helps cleanup each expect clause. @@ -367,11 +378,6 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype } { 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 @@ -392,12 +398,21 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype } { send "no\r" send_user "\nError: host key mismatch for $router. Update the SSH known_hosts file accordingly.\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 + } -re "$u_prompt" { send "$user\r" expect { eof { send_user "\nError: Couldn't login\n"; wait; return 1 } "Login invalid" { send_user "\nError: Invalid login\n"; vatch {close}; wait; return 1 } -re "$p_prompt" { send "$userpswd\r" } "$prompt" { set in_proc 0; return 0 } + "Press any key to continue" { + send " " + exp_continue + } } exp_continue } @@ -408,9 +423,18 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype } { send "$passwd\r" } expect { - eof { send_user "\nError: Couldn't login\n"; wait; return 1 } + eof { send_user "\nError: Couldn't login\n"; + wait; + return 1 + } + "Press any key to continue" { + send " "; + exp_continue + } -re "$e_prompt" { send "$enapasswd\r" } - "$prompt" { set in_proc 0; return 0 } + "$prompt" { set in_proc 0; + return 0 + } } exp_continue } @@ -454,16 +478,14 @@ proc run_commands { prompt command } { global in_proc platform set in_proc 1 - # 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 and extreme. + # Turn off the pager and escape regex meta characters in the $prompt send "no page\r" regsub -all "\[)(]" $prompt {\\&} reprompt - expect { - -re $reprompt {} - -re "\[\n\r]+" { exp_continue } - } - # this is the only way i see to get rid for more prompts in o/p..grrrrr + expect { + -re $reprompt {} + -re "\[\n\r]+" { exp_continue } + } + # this is the only way i see to get rid of more prompts in o/p..grrrrr log_user 0 # Is this a multi-command? if [ string match "*\;*" "$command" ] { @@ -491,6 +513,10 @@ proc run_commands { prompt command } { } -re "^<-+ More -+>\[^\n\r]*" { send " " exp_continue } + -re "^-+ MORE -+\[^\n\r]*" { send " " + exp_continue } + -re "^-+More-+\[^\n\r]*" { send " " + exp_continue } -re "\b+" { exp_continue } } } @@ -516,11 +542,13 @@ proc run_commands { prompt command } { exp_continue } -re "^-+ MORE -+\[^\n\r]*" { send " " exp_continue } + -re "^-+More-+\[^\n\r]*" { send " " + exp_continue } -re "\b+" { exp_continue } } } log_user 1 - send "exit\r" + send -h "exit\r" expect { "Do you want to save current configuration" { send "n\r" @@ -536,10 +564,12 @@ proc run_commands { prompt command } { } -re "\[\r\n]+" { exp_continue } -re "^.+>" { - send "exit\r" + send -h "exit\r" exp_continue } - timeout { return 0 } + timeout { catch {close}; wait + return 0 + } eof { return 0 } } set in_proc 0 @@ -570,6 +600,7 @@ foreach router [lrange $argv $i end] { set prompt "#" } else { set autoenable 0 + set enable $avenable set prompt ">" } } @@ -592,6 +623,9 @@ foreach router [lrange $argv $i end] { } set passwd [join [lindex $pswd 0] ""] set enapasswd [join [lindex $pswd 1] ""] + } else { + set passwd $userpasswd + set enapasswd $enapasswd } # Figure out username @@ -654,9 +688,9 @@ 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} } + # 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 @@ -671,17 +705,17 @@ foreach router [lrange $argv $i end] { if { $enable } { if {[do_enable $enauser $enapasswd]} { if { $do_command || $do_script } { - close; wait + catch {close}; catch {wait} continue } } } # we are logged in, now figure out the full prompt - send "\r" - expect { + send "\r" + expect { -re "\[\r\n]+" { exp_continue; } -re "^.+$prompt" { set prompt $expect_out(0,string); } - } + } if { $do_command } { if {[run_commands $prompt $command]} { diff --git a/bin/hpuifilter.c b/bin/hpuifilter.c index 8f7005a..c278a3f 100644 --- a/bin/hpuifilter.c +++ b/bin/hpuifilter.c @@ -1,7 +1,7 @@ /* - * $Id: hpuifilter.c,v 1.17 2004/01/11 03:49:13 heas Exp $ + * $Id: hpuifilter.c,v 1.36 2006/11/29 01:02:27 heas Exp $ * - * Copyright (C) 1997-2004 by Terrapin Communications, Inc. + * Copyright (C) 1997-2006 by Terrapin Communications, Inc. * All rights reserved. * * This software may be freely copied, modified and redistributed @@ -21,51 +21,117 @@ * 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. + * + * Modified openpty() from NetBSD: + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ -#define DFLT_TO 60 /* default timeout */ -#include <config.h> -#include <version.h> +#include "config.h" +#include "version.h" + +#if HAVE_UNISTD_H +# include <unistd.h> +#endif #include <stdio.h> #include <limits.h> #include <fcntl.h> +#include <poll.h> +#if HAVE_PTY_H +# include <pty.h> +#endif +#include <regex.h> #include <signal.h> +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include <memory.h> +# endif +# include <string.h> +#endif +#if HAVE_STRINGS_H +# include <strings.h> +#endif +#if HAVE_PTMX && HAVE_STROPTS_H +# include <stropts.h> +#endif +#include <sys/ioctl.h> +#include <sys/stat.h> #include <sys/time.h> -#include <regex.h> - #include <termios.h> +#if HAVE_UTIL_H +# include <util.h> +#endif -char *progname; -int debug = 0; +#define BUFSZ (LINE_MAX * 2) + +char **environ, + *progname; +int child, + debug, + drain, + timeo = 5; /* default timeout */ int filter __P((char *, int)); +RETSIGTYPE reapchild __P((void)); +#if !HAVE_OPENPTY +int openpty(int *, int *, char *, struct termios *, + struct winsize *); +#endif +RETSIGTYPE sighdlr __P((int)); +#if !HAVE_UNSETENV +int unsetenv __P((const char *)); +#endif void usage __P((void)); void vers __P((void)); -RETSIGTYPE reapchild __P((void)); int -main(int argc, char **argv) +main(int argc, char **argv, char **ev) { extern char *optarg; extern int optind; char ch, - hbuf[LINE_MAX * 2], /* hlogin buffer */ - *hbufp, - tbuf[LINE_MAX * 2], /* telnet buffer */ + hbuf[BUFSZ], /* hlogin buffer */ + ptyname[FILENAME_MAX + 1], + tbuf[BUFSZ], /* telnet/ssh buffer */ *tbufp; int bytes, /* bytes read/written */ - child, - r[2], /* recv pipe */ - s[2]; /* send pipe */ + devnull, + rval = EX_OK, + ptym, /* master pty */ + ptys; /* slave pty */ ssize_t hlen = 0, /* len of hbuf */ tlen = 0; /* len of tbuf */ - struct timeval to = { DFLT_TO, 0 }; - fd_set rfds, /* select() */ - wfds; + struct pollfd pfds[3]; struct termios tios; + environ = ev; + /* get just the basename() of our exec() name and strip a .* off the end */ if ((progname = strrchr(argv[0], '/')) != NULL) progname += 1; @@ -74,11 +140,16 @@ main(int argc, char **argv) if (strrchr(progname, '.') != NULL) *(strrchr(progname, '.')) = '\0'; - while ((ch = getopt(argc, argv, "dhv")) != -1 ) + while ((ch = getopt(argc, argv, "dhvt:")) != -1 ) switch (ch) { case 'd': debug++; break; + case 't': + timeo = atoi(optarg); + if (timeo < 1) + timeo = 1; + break; case 'v': vers(); return(EX_OK); @@ -93,26 +164,41 @@ main(int argc, char **argv) return(EX_USAGE); } - /* reap our children */ - signal(SIGCHLD, (void *) reapchild); - signal(SIGHUP, (void *) reapchild); - signal(SIGINT, (void *) reapchild); - signal(SIGTERM, (void *) reapchild); + unsetenv("DISPLAY"); - /* 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, + + /* allocate pty for telnet/ssh, then fork and exec */ + if (openpty(&ptym, &ptys, ptyname, NULL, NULL)) { + fprintf(stderr, "%s: could not allocate pty: %s\n", progname, strerror(errno)); return(EX_TEMPFAIL); } + /* make the pty raw */ + if (tcgetattr(ptys, &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(ptys, TCSANOW, &tios)) { + fprintf(stderr, "%s: tcsetattr() failed: %s\n", progname, + strerror(errno)); + return(EX_OSERR); + } - /* if a tty, make it raw as the hp echos _everything_, including + /* + * if a tty, make it raw as the hp echos _everything_, including * passwords. */ - if (isatty(0)) { - if (tcgetattr(0, &tios)) { + if (isatty(fileno(stdin))) { + if (tcgetattr(fileno(stdin), &tios)) { fprintf(stderr, "%s: tcgetattr() failed: %s\n", progname, strerror(errno)); return(EX_OSERR); @@ -123,180 +209,272 @@ main(int argc, char **argv) tios.c_cc[VMIN] = 1; tios.c_cc[VTIME] = 0; #endif - if (tcsetattr(0, TCSANOW, &tios)) { + if (tcsetattr(fileno(stdin), TCSANOW, &tios)) { fprintf(stderr, "%s: tcsetattr() failed: %s\n", progname, strerror(errno)); return(EX_OSERR); } } + /* zero the buffers */ + memset(hbuf, 0, BUFSZ); + memset(tbuf, 0, BUFSZ); + + /* reap our children, must be set-up *after* openpty() */ + signal(SIGCHLD, (void *) reapchild); + if ((child = fork()) == -1) { - fprintf(stderr, "%s: fork() failed: %s\n", progname, - strerror(errno)); + 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]); + struct winsize ws; + + /* + * Make sure our terminal length and width are something greater + * than 1, for pagers on stupid boxes. + */ + ioctl(ptys, TIOCGWINSZ, &ws); + ws.ws_row = 24; + ws.ws_col = 132; + ioctl(ptys, TIOCSWINSZ, &ws); + + signal(SIGCHLD, SIG_DFL); + /* close the master pty & std* inherited from the parent */ + close(ptym); + if (ptys != 0) + close(0); + if (ptys != 1) + close(1); + if (ptys != 2) + close(2); +#ifdef TIOCSCTTY + setsid(); + if (ioctl(ptys, TIOCSCTTY, NULL) == -1) { + snprintf(ptyname, FILENAME_MAX, "%s: could not set controlling " + "tty: %s\n", progname, strerror(errno)); + write(0, ptyname, strlen(ptyname)); + return(EX_OSERR); + } +#endif + /* 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)); + if (dup2(ptys, 0) == -1 || dup2(ptys, 1) == -1 || dup2(ptys, 2) == -1) { + snprintf(ptyname, FILENAME_MAX, "%s: dup2() failed: %s\n", progname, + strerror(errno)); + write(0, ptyname, strlen(ptyname)); 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, + if (ptys > 2) + close(ptys); + + /* exec telnet/ssh */ + execvp(argv[optind], argv + optind); + snprintf(ptyname, FILENAME_MAX, "%s: execvp() failed: %s\n", progname, + strerror(errno)); + write(0, ptyname, strlen(ptyname)); + return(EX_TEMPFAIL); + /*NOTREACHED*/ + } + + /* parent */ + if (debug) + fprintf(stderr, "child %d\n", child); + + signal(SIGHUP, (void *) sighdlr); + + /* close the slave pty */ + close(ptys); + + devnull = open("/dev/null", O_RDWR); + + /* make FDs non-blocking */ + if (fcntl(ptym, F_SETFL, O_NONBLOCK) || + fcntl(fileno(stdin), F_SETFL, O_NONBLOCK) || + fcntl(fileno(stdout), F_SETFL, O_NONBLOCK)) { + fprintf(stderr, "%s: fcntl(NONBLOCK) failed: %s\n", progname, strerror(errno)); - return(EX_TEMPFAIL); + exit(EX_OSERR); + } + + /* loop to read on stdin and ptym */ +#define POLLEXP (POLLERR | POLLHUP | POLLNVAL) + pfds[0].fd = fileno(stdin); + pfds[0].events = POLLIN | POLLEXP; + pfds[1].fd = fileno(stdout); + pfds[2].fd = ptym; + pfds[2].events = POLLIN | POLLEXP; + + while (1) { + bytes = poll(pfds, 3, (timeo * 1000)); + if (bytes == 0) { + if (drain) + break; + /* timeout */ + continue; } - /* 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); + if (bytes == -1) { + switch (errno) { + case EAGAIN: + case EINTR: + break; + default: + rval = EX_IOERR; + break; + } + continue; } - /* loop to read on stdin and r[0] */ - FD_ZERO(&rfds); FD_ZERO(&wfds); - hbufp = hbuf; tbufp = tbuf; + /* + * write buffers first + * write hbuf (stdin) -> ptym + */ + if ((pfds[2].revents & POLLOUT) && hlen) { + if ((bytes = write(pfds[2].fd, hbuf, hlen)) < 0 && + errno != EINTR && errno != EAGAIN) { + fprintf(stderr, "%s: write() failed: %s\n", progname, + strerror(errno)); + hbuf[0] = '\0'; + hlen = 0; + drain = 1; + pfds[2].events &= ~POLLOUT; - 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); + break; + } else if (bytes > 0) { + strcpy(hbuf, hbuf + bytes); + hlen -= bytes; + if (hlen < 1) + pfds[2].events &= ~POLLOUT; } + } else if (pfds[2].revents & POLLEXP) { + hbuf[0] = '\0'; + hlen = 0; + pfds[2].events &= POLLIN; + break; + } - switch (select(r[1], &rfds, &wfds, NULL, &to)) { - case 0: - /* timeout */ - /* HEAS: what do i do here? */ + /* write tbuf -> stdout */ + if ((pfds[1].revents & POLLOUT) && tlen) { + /* + * if there is an escape char that didnt get filter()'d, + * we need to write only up to that point and wait for + * the bits that complete the escape sequence. if at least + * two bytes follow it, write it anyway as filter() didnt + * match it. + */ + bytes = tlen; + if ((tbufp = index(tbuf, 0x1b)) != NULL) + if (tlen - (tbufp - tbuf) < 2) + bytes = tbufp - tbuf; + + if ((bytes = write(pfds[1].fd, tbuf, bytes)) < 0 && + errno != EINTR && errno != EAGAIN) { + fprintf(stderr, "%s: write() failed: %s\n", progname, + strerror(errno)); break; - case -1: - switch (errno) { - case EINTR: /* interrupted syscall */ + tbuf[0] = '\0'; + tlen = 0; + drain = 1; + pfds[1].events = 0; + } else if (bytes > 0) { + strcpy(tbuf, tbuf + bytes); + tlen -= bytes; + if (tlen < 1) + pfds[1].events &= ~POLLOUT; + } + } else if (pfds[1].revents & POLLEXP) { + break; + tbuf[0] = '\0'; + tlen = 0; + pfds[1].fd = devnull; + pfds[1].events = 0; + } + + /* read stdin -> hbuf */ + if (pfds[0].revents & POLLIN) { + if (BUFSZ - hlen > 1) { + bytes = read(pfds[0].fd, hbuf + hlen, (BUFSZ - 1) - hlen); + if (bytes > 0) { + hlen += bytes; + hbuf[hlen] = '\0'; + pfds[2].events |= POLLOUT; + } else if (bytes == 0 && errno != EAGAIN && errno != EINTR) { break; - default: - exit(EX_IOERR); + /* EOF or read error */ + drain = 1; + pfds[0].fd = devnull; + pfds[0].events = 0; } - 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; } + } else if (pfds[0].revents & POLLEXP) { + break; + drain = 1; + pfds[0].fd = devnull; + pfds[0].events = 0; } - /* close */ - close(0); - close(1); - close(s[1]); - close(r[0]); + /* read telnet/ssh -> tbuf, then filter */ + if (pfds[2].revents & POLLIN) { + if (BUFSZ - tlen > 1) { + bytes = read(pfds[2].fd, tbuf + tlen, (BUFSZ - 1) - tlen); + if (bytes > 0) { + tlen += bytes; + tbuf[tlen] = '\0'; + tlen = filter(tbuf, tlen); + if (tlen > 0) + pfds[1].events |= POLLOUT; + } else if (bytes == 0 && errno != EAGAIN && errno != EINTR) { + /* EOF or read error */ + break; + drain = 1; + pfds[2].fd = devnull; + pfds[2].events = 0; + } + } + } else if (pfds[2].revents & POLLEXP) { + break; + drain = 1; + pfds[2].fd = devnull; + pfds[2].events = 0; + } + } + /* try to flush buffers */ + if (hlen) { + (void) write(pfds[2].fd, hbuf, hlen); + hlen = 0; } + if (tlen) { + (void) write(pfds[1].fd, tbuf, tlen); + tlen = 0; + } + if ((bytes = read(pfds[2].fd, tbuf, (BUFSZ - 1))) > 0) { + tbuf[bytes] = '\0'; + tlen = filter(tbuf, bytes); + (void) write(pfds[1].fd, tbuf, tlen); + } + tcdrain(pfds[1].fd); + if ((hlen = read(pfds[0].fd, hbuf, (BUFSZ - 1))) > 0) { + (void) write(pfds[2].fd, hbuf, hlen); + } + tcdrain(pfds[2].fd); - if (! kill(child, SIGQUIT)) + if (child && ! kill(child, SIGINT)) reapchild(); - return(EX_OK); + return(rval); } int -filter(buf, len) - char *buf; - int len; +filter(char *buf, int len) { static regmatch_t pmatch[1]; -#define N_REG 11 /* number of regexes in reg[][] */ +#define N_REG 14 /* 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 */ @@ -307,8 +485,12 @@ filter(buf, len) "\e\\[\\?7l", /* RA */ "\e\\[\\?25h", /* ve */ "\e\\[\\?25l", /* vi */ + "\e\\[K", /* ce */ + "\e\\[7m", /* mr - ansi */ - "\eE", /* replace w/ CR */ + /* replace these with CR */ + "\e\\[0m", /* me */ + "\eE", }; char ebuf[256]; size_t nmatch = 1; @@ -319,7 +501,7 @@ filter(buf, len) if (index(buf, 0x1b) == 0 || len == 0) return(len); - for (x = 0; x < N_REG - 1; x++) { + for (x = 0; x < N_REG - 2; x++) { if (! init) { if ((err = regcomp(&preg[x], reg[x], REG_EXTENDED))) { regerror(err, &preg[x], ebuf, 256); @@ -342,53 +524,89 @@ filter(buf, len) /* 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(); - } + for (x = N_REG - 2; x < N_REG; x++) + 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(); + } } - while (1) - if ((err = regexec(&preg[N_REG - 1], buf, nmatch, pmatch, 0))) { + for (x = N_REG - 2; x < N_REG; x++) { + if ((err = regexec(&preg[x], buf, nmatch, pmatch, 0))) { if (err != REG_NOMATCH) { - regerror(err, &preg[N_REG - 1], ebuf, 256); + regerror(err, &preg[x], 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; + *(buf + pmatch[0].rm_so) = '\r'; + *(buf + pmatch[0].rm_so + 1) = '\n'; + strcpy(buf + pmatch[0].rm_so + 2, buf + pmatch[0].rm_eo); + x = N_REG - 2; } - + } return(strlen(buf)); } -RETSIGTYPE +RETSIGTYPE reapchild(void) { int status; pid_t pid; - - /* HEAS: this needs to deal with/without wait3 via HAVE_WAIT3 */ + + /* XXX 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; + if (pid == child) + child = 0; - /* not reached */ -} + return; +} + +RETSIGTYPE +sighdlr(int sig) +{ + if (debug) + fprintf(stderr, "GOT SIGNAL %d\n", sig); + drain = 1; + return; +} + +#if !HAVE_UNSETENV +int +unsetenv(const char *name) +{ + char **victim, + **end; + int len; + if (environ == NULL) + return(0); + len = strlen(name); + victim = environ; + while (*victim != NULL) { + if (strncmp(name, *victim, len) == 0 && victim[0][len] == '=') + break; + victim++; + } + if (*victim == NULL) + return(0); + end = victim + 1; + while (*end != NULL) + end++; + end--; + *victim = *end; + *end = NULL; + return(0); +} +#endif void usage(void) { - fprintf(stderr, -"usage: %s [-hv] <telnet|ssh> [<ssh options>] <hostname> [<telnet_port>]\n", - progname); + fprintf(stderr, "usage: %s [-hv] [-t timeout] <telnet|ssh> [<ssh options>]" + " <hostname> [<telnet_port>]\n", progname); return; } @@ -398,3 +616,107 @@ vers(void) fprintf(stderr, "%s: %s version %s\n", progname, package, version); return; } + + +#if !HAVE_OPENPTY +#include <grp.h> +#define TTY_LETTERS "pqrstuvwxyzPQRST" +#define TTY_OLD_SUFFIX "0123456789abcdef" +#define TTY_NEW_SUFFIX "ghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + +int +openpty(int *amaster, int *aslave, char *name, struct termios *term, + struct winsize *winp) +{ + static char line[] = "/dev/XtyXX"; + const char *cp1, *cp2, *cp, *linep; + int master, slave; + gid_t ttygid; + mode_t mode; + struct group *gr; + +#if HAVE_PTMX + if ((master = +#if HAVE_PTMX_BSD + open("/dev/ptmx_bsd", O_RDWR)) +#else + open("/dev/ptmx", O_RDWR)) +#endif + != -1) { + linep = ptsname(master); + grantpt(master); + unlockpt(master); +#ifndef TIOCSCTTY + setsid(); +#endif + if ((slave = open(linep, O_RDWR)) < 0) { + slave = errno; + (void) close(master); + errno = slave; + return(-1); + } +#if HAVE_PTMX_OSF + { + char buf[10240]; + if (ioctl (slave, I_LOOK, buf) != 0) + if (ioctl (slave, I_PUSH, "ldterm")) { + close(slave); + close(master); + return(-1); + } + } +#elif HAVE_STROPTS_H + ioctl(slave, I_PUSH, "ptem"); + ioctl(slave, I_PUSH, "ldterm"); + ioctl(slave, I_PUSH, "ttcompat"); +#endif + goto gotit; + } + if (errno != ENOENT) + return(-1); +#endif + + if ((gr = getgrnam("tty")) != NULL) { + ttygid = gr->gr_gid; + mode = S_IRUSR|S_IWUSR|S_IWGRP; + } else { + ttygid = getgid(); + mode = S_IRUSR|S_IWUSR; + } + + for (cp1 = TTY_LETTERS; *cp1; cp1++) { + line[8] = *cp1; + for (cp = cp2 = TTY_OLD_SUFFIX TTY_NEW_SUFFIX; *cp2; cp2++) { + line[5] = 'p'; + line[9] = *cp2; + if ((master = open(line, O_RDWR, 0)) == -1) { + if (errno != ENOENT) + continue; /* busy */ + if (cp2 - cp + 1 < sizeof(TTY_OLD_SUFFIX)) + return -1; /* out of ptys */ + else + break; /* out of ptys in this group */ + } + line[5] = 't'; + linep = line; + if (chown(line, getuid(), ttygid) == 0 && + chmod(line, mode) == 0 && + (slave = open(line, O_RDWR, 0)) != -1) { +gotit: + *amaster = master; + *aslave = slave; + if (name) + (void)strcpy(name, linep); + if (term) + (void)tcsetattr(slave, TCSAFLUSH, term); + if (winp) + (void)ioctl(slave, TIOCSWINSZ, winp); + return 0; + } + (void)close(master); + } + } + errno = ENOENT; /* out of ptys */ + return -1; +} +#endif diff --git a/bin/hrancid.in b/bin/hrancid.in index fa048ce..0feefd0 100644 --- a/bin/hrancid.in +++ b/bin/hrancid.in @@ -1,8 +1,9 @@ #! @PERLV_PATH@ ## -## $Id: hrancid.in,v 1.17 2004/01/11 03:49:13 heas Exp $ +## $Id: hrancid.in,v 1.27 2006/10/05 04:27:42 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -24,25 +25,30 @@ # # RANCID - Really Awesome New Cisco confIg Differ # -# usage: rancid [-d] [-l] [-f filename | $host] +# usage: rancid [-dV] [-l] [-f filename | hostname] # use Getopt::Std; -getopts('dfl'); +getopts('dflV'); +if ($opt_V) { + print "@PACKAGE@ @VERSION@\n"; + exit(0); +} $log = $opt_l; $debug = $opt_d; $file = $opt_f; $host = $ARGV[0]; $clean_run = 0; -$found_end = 0; # unused - hp lacks an end-of-config tag. -$timeo = 90; # clogin timeout in seconds +$found_end = 0; # unused - hp lacks an end-of-config tag +$timeo = 90; # hlogin timeout in seconds -my(%filter_pwds); # password filtering mode +my(@commandtable, %commands, @commands);# command lists +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) { + 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; } @@ -64,10 +70,10 @@ sub ProcessHistory { sub numerically { $a <=> $b; } -# This is a sort routing that will sort numerically on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort numerically keys(%lines)) { @@ -77,10 +83,10 @@ sub keynsort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort keys(%lines)) { @@ -90,10 +96,10 @@ sub keysort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort values %lines) { @@ -103,9 +109,9 @@ sub valsort{ @sorted_lines; } -# This is a numerical sort routing (ascending). +# This is a numerical sort routine (ascending). sub numsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $num (sort {$a <=> $b} keys %lines) { @@ -119,7 +125,7 @@ sub numsort { # ip address when the ip address is anywhere in # the strings. sub ipsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $addr (sort sortbyipaddr keys %lines) { @@ -132,7 +138,7 @@ sub ipsort { # 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])); + $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0])); } sub sortbyipaddr { &ipaddrval($a) <=> &ipaddrval($b); @@ -159,8 +165,6 @@ sub ShowVersion { # This routine parses "show flash" sub ShowFlash { - # skip if this is 7000, 7200, 7500, or 12000; else we end up with - # redundant data from dir /all slot0: print STDERR " In ShowFlash: $_" if ($debug); while (<INPUT>) { @@ -188,8 +192,14 @@ sub ShowSystem { return(-1) if (/command authorization failed/i); return(-1) if /^(Invalid|Ambiguous) input:/i; - /memory\s+-\s+total\s+:\s+(\S+)/i && - ProcessHistory("COMMENTS","keysort","B0",";Memory: $1\n"); + if (/memory\s+-\s+total\s+:\s+(\S+)/i) { + my($mem) = $1; + $mem =~ s/,//g; + $mem /= (1024 * 1024); + ProcessHistory("COMMENTS","keysort","B0",";Memory: " . int($mem) . + "M\n"); + next; + } /serial\s+number\s+:\s+(\S+)/i && ProcessHistory("COMMENTS","keysort","A1",";Serial Number: $1\n"); /firmware\s+revision\s+:\s+(\S+)/i && @@ -230,7 +240,7 @@ sub ShowStack { last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); return(-1) if (/command authorization failed/i); - return(-1) if /^(Invalid|Ambiguous) input:/i; + return(1) if /^(Invalid|Ambiguous) input:/i; s/stacking - (Stacking Status).*/$1/i; s/\s*members unreachable .*$//i; @@ -426,27 +436,31 @@ sub WriteTerm { sub DoNothing {print STDOUT;} # Main -%commands=( - 'show version' => "ShowVersion", - 'show flash' => "ShowFlash", - 'show system-information' => "ShowSystem", - 'show module' => "ShowModule", - 'show stack' => "ShowStack", - '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 flash", - "show system-information", - "show module", - "show stack", - "write term" +@commandtable = ( + {'show version' => 'ShowVersion'}, + {'show flash' => 'ShowFlash'}, + {'show system-information' => 'ShowSystem'}, + {'show module' => 'ShowModule'}, + {'show stack' => 'ShowStack'}, + {'write term' => 'WriteTerm'} ); +# Use an array to preserve the order of the commands and a hash for mapping +# commands to the subroutine and track commands that have been completed. +@commands = map(keys(%$_), @commandtable); +%commands = map(%$_, @commandtable); + $cisco_cmds=join(";",@commands); $cmds_regexp=join("|",@commands); +if (length($host) == 0) { + if ($file) { + print(STDERR "Too few arguments: file name required\n"); + exit(1); + } else { + print(STDERR "Too few arguments: host name required\n"); + exit(1); + } +} open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; select(OUTPUT); # make OUTPUT unbuffered if debugging @@ -469,7 +483,7 @@ if ($file) { # determine password filtering mode if ($ENV{"FILTER_PWDS"} =~ /no/i) { - $filter_pwds = 0; + $filter_pwds = 0; } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) { $filter_pwds = 2; } else { diff --git a/bin/htlogin.in b/bin/htlogin.in index 8e9c5f5..213f028 100644 --- a/bin/htlogin.in +++ b/bin/htlogin.in @@ -1,8 +1,9 @@ #! @EXPECT_PATH@ -- ## -## $Id: htlogin.in,v 1.7 2004/01/11 05:39:15 heas Exp $ +## $Id: htlogin.in,v 1.18 2006/12/05 16:50:52 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -42,7 +43,7 @@ set password_file $env(HOME)/.cloginrc set do_command 0 set do_script 0 # The default is to automatically enable -set enable 1 +set avenable 1 # The default is that you login non-enabled (tacacs can have you login already # enabled) set avautoenable 0 @@ -51,7 +52,7 @@ set avautoenable 0 set do_passwd 1 # Find the user in the ENV, or use the unix userid. -if {[ info exists env(CISCO_USER) ] } { +if {[ info exists env(CISCO_USER) ]} { set default_user $env(CISCO_USER) } elseif {[ info exists env(USER) ]} { set default_user $env(USER) @@ -64,9 +65,12 @@ if {[ info exists env(CISCO_USER) ] } { if [ catch {exec id} reason ] { send_error "\nError: could not exec id: $reason\n" exit 1 - } + } regexp {\(([^)]*)} "$reason" junk default_user -} +} +if {[ info exists env(CLOGINRC) ]} { + set password_file $env(CLOGINRC) +} # Sometimes routers take awhile to answer (the default is 10 sec) set timeout 45 @@ -92,13 +96,16 @@ for {set i 0} {$i < $argc} {incr i} { } set do_passwd 0 # VTY Password - } -v* - - -v* { + } -v* { if {! [ regexp .\[vV\](.+) $arg ignore passwd]} { incr i set passwd [ lindex $argv $i ] } set do_passwd 0 + # Version string + } -V* { + send_user "@PACKAGE@ @VERSION@\n" + exit 0 # Enable Username } -w* - -W* { @@ -270,31 +277,44 @@ proc source_password_file { password_file } { } # Log into the router. +# returns: 0 on success, 1 on failure 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 + set uprompt_seen 0 # try each of the connection methods in $cmethod until one is successful set progs [llength $cmethod] foreach prog [lrange $cmethod 0 end] { + incr progs -1 if [string match "telnet*" $prog] { regexp {telnet(:([^[:space:]]+))*} $prog command suffix port if {"$port" == ""} { - set retval [ catch {spawn telnet $router} reason ] - } else { + set retval [ catch {spawn telnet $router} reason ] + } else { set retval [ catch {spawn telnet $router $port} reason ] } if { $retval } { send_user "\nError: telnet failed: $reason\n" - exit 1 + return 1 } + } elseif ![string compare $prog "ssh"] { + send_error "\nError: unsupported method: ssh\n" + if { $progs == 0 } { + return 1 + } + continue + } elseif ![string compare $prog "rsh"] { + send_error "\nError: unsupported method: rsh\n" + if { $progs == 0 } { + return 1 + } + continue } else { - puts "\nError: unknown connection method: $prog" + send_user "\nError: unknown connection method: $prog\n" return 1 } - incr progs -1 sleep 0.3 # This helps cleanup each expect clause. @@ -376,7 +396,7 @@ proc run_commands { prompt command } { 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 *]*$prompt" {} -re "\[\n\r]" { exp_continue } } @@ -384,16 +404,18 @@ proc run_commands { prompt command } { } else { send "$command\r" expect { - -re "^\[^\n\r]*$prompt" {} + -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 } + "\n" { exp_continue } + timeout { catch {close}; wait + return 0 + } + eof { return 0 } } set in_proc 0 } diff --git a/bin/htrancid.in b/bin/htrancid.in index 2b2eaaa..d15d569 100644 --- a/bin/htrancid.in +++ b/bin/htrancid.in @@ -1,8 +1,9 @@ #! @PERLV_PATH@ ## -## $Id: htrancid.in,v 1.5 2004/01/11 03:49:13 heas Exp $ +## $Id: htrancid.in,v 1.13 2006/10/05 04:27:43 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -23,25 +24,30 @@ # # RANCID - Really Awesome New Cisco confIg Differ # -# usage: htrancid [-d] [-l] [-f filename | $host] +# usage: htrancid [-dV] [-l] [-f filename | hostname] # use Getopt::Std; -getopts('dfl'); +getopts('dflV'); +if ($opt_V) { + print "@PACKAGE@ @VERSION@\n"; + exit(0); +} $log = $opt_l; $debug = $opt_d; $file = $opt_f; $host = $ARGV[0]; $clean_run = 0; $found_end = 0; -$timeo = 90; # blogin timeout in seconds +$timeo = 90; # htlogin timeout in seconds -my(%filter_pwds); # password filtering mode +my(@commandtable, %commands, @commands);# command lists +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) { + 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; } @@ -63,10 +69,10 @@ sub ProcessHistory { sub numerically { $a <=> $b; } -# This is a sort routing that will sort numerically on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort numerically keys(%lines)) { @@ -76,10 +82,10 @@ sub keynsort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort keys(%lines)) { @@ -89,10 +95,10 @@ sub keysort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort values %lines) { @@ -102,9 +108,9 @@ sub valsort{ @sorted_lines; } -# This is a numerical sort routing (ascending). +# This is a numerical sort routine (ascending). sub numsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $num (sort {$a <=> $b} keys %lines) { @@ -118,7 +124,7 @@ sub numsort { # ip address when the ip address is anywhere in # the strings. sub ipsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $addr (sort sortbyipaddr keys %lines) { @@ -131,7 +137,7 @@ sub ipsort { # 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])); + $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0])); } sub sortbyipaddr { &ipaddrval($a) <=> &ipaddrval($b); @@ -166,19 +172,27 @@ sub ShowVersion { 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" +@commandtable = ( + {'version -a' => 'ShowVersion'}, + {'cat /config/router.cnf' => 'ShowConfig'} ); +# Use an array to preserve the order of the commands and a hash for mapping +# commands to the subroutine and track commands that have been completed. +@commands = map(keys(%$_), @commandtable); +%commands = map(%$_, @commandtable); + $cisco_cmds=join(";",@commands); $cmds_regexp=join("|",@commands); +if (length($host) == 0) { + if ($file) { + print(STDERR "Too few arguments: file name required\n"); + exit(1); + } else { + print(STDERR "Too few arguments: host name required\n"); + exit(1); + } +} open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; select(OUTPUT); # make OUTPUT unbuffered if debugging @@ -201,7 +215,7 @@ if ($file) { # determine password filtering mode if ($ENV{"FILTER_PWDS"} =~ /no/i) { - $filter_pwds = 0; + $filter_pwds = 0; } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) { $filter_pwds = 2; } else { @@ -224,8 +238,8 @@ TOP: while(<INPUT>) { while (/command:\s*($cmds_regexp)\s*$/) { $cmd = $1; if (!defined($prompt)) { - $prompt = ($_ =~ /^([^:]+:)/)[0]; - } + $prompt = ($_ =~ /^([^:]+:)/)[0]; + } print STDERR ("HIT COMMAND:$_") if ($debug); if (! defined($commands{$cmd})) { print STDERR "$host: found unexpected command - \"$cmd\"\n"; diff --git a/bin/jerancid.in b/bin/jerancid.in index 1b72737..c0fb33e 100644 --- a/bin/jerancid.in +++ b/bin/jerancid.in @@ -1,8 +1,9 @@ #! @PERLV_PATH@ ## -## $Id: jerancid.in,v 1.25 2004/01/11 03:49:13 heas Exp $ +## $Id: jerancid.in,v 1.36 2006/10/05 04:27:43 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -23,25 +24,30 @@ # # RANCID - Really Awesome New Cisco confIg Differ # -# usage: rancid [-d] [-l] [-f filename | $host] +# usage: rancid [-dV] [-l] [-f filename | hostname] # use Getopt::Std; -getopts('dfl'); +getopts('dflV'); +if ($opt_V) { + print "@PACKAGE@ @VERSION@\n"; + exit(0); +} $log = $opt_l; $debug = $opt_d; $file = $opt_f; $host = $ARGV[0]; $clean_run = 0; $found_end = 0; -$timeo = 90; # clogin timeout in seconds +$timeo = 90; # clogin timeout in seconds -my(%filter_pwds); # password filtering mode +my(@commandtable, %commands, @commands);# command lists +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) { + 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; } @@ -63,10 +69,10 @@ sub ProcessHistory { sub numerically { $a <=> $b; } -# This is a sort routing that will sort numerically on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort numerically keys(%lines)) { @@ -76,10 +82,10 @@ sub keynsort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort keys(%lines)) { @@ -89,10 +95,10 @@ sub keysort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort values %lines) { @@ -102,9 +108,9 @@ sub valsort{ @sorted_lines; } -# This is a numerical sort routing (ascending). +# This is a numerical sort routine (ascending). sub numsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $num (sort {$a <=> $b} keys %lines) { @@ -118,7 +124,7 @@ sub numsort { # ip address when the ip address is anywhere in # the strings. sub ipsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $addr (sort sortbyipaddr keys %lines) { @@ -131,7 +137,7 @@ sub ipsort { # 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])); + $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0])); } sub sortbyipaddr { &ipaddrval($a) <=> &ipaddrval($b); @@ -203,6 +209,8 @@ sub ShowEnv { next if (/^(\s*|\s*$cmd\s*)$/); next if (/^Please wait/i); return(-1) if (/command authorization failed/i); + # fail if the RP is amid the auto-sync process + return(-1) if (/auto-sync enabled/ && !/in sync/); # skip the temperature goop if (/processor\s+processor/) { @@ -260,6 +268,8 @@ sub DirSlotN { next if (/^(\s*|\s*$cmd\s*)$/); next if (/^Please wait/i); next if (/^system\.log/); + # fail if the RP is amid the auto-sync process + return(-1) if (/active\/standby/i && /not sync/); ProcessHistory("FLASH","","","!Flash: $_"); } @@ -303,6 +313,8 @@ sub WriteTerm { # skip the crap /^! Configuration script /i && next; /^! Copyright /i && next; + /^Please wait/i && next; + /^(\.+)$/ && next; # Skip variable length pausing dot lines # Dog gone Cool matches to process the rest of the config /^ntp clock-period / && next; # kill ntp clock-period @@ -530,29 +542,32 @@ sub WriteTerm { 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" +@commandtable = ( + {'show version' => 'ShowVersion'}, + {'show redundancy' => 'ShowRedundancy'}, + {'show boot' => 'ShowBoot'}, + {'show environment all' => 'ShowEnv'}, + {'dir' => 'DirSlotN'}, + {'show hardware' => 'ShowHardware'}, + {'show configuration' => 'WriteTerm'} ); +# Use an array to preserve the order of the commands and a hash for mapping +# commands to the subroutine and track commands that have been completed. +@commands = map(keys(%$_), @commandtable); +%commands = map(%$_, @commandtable); + $jnxe_cmds=join(";",@commands); $cmds_regexp=join("|",@commands); +if (length($host) == 0) { + if ($file) { + print(STDERR "Too few arguments: file name required\n"); + exit(1); + } else { + print(STDERR "Too few arguments: host name required\n"); + exit(1); + } +} open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; select(OUTPUT); # make OUTPUT unbuffered if debugging diff --git a/bin/jlogin.in b/bin/jlogin.in index 31be4f6..729afa7 100644 --- a/bin/jlogin.in +++ b/bin/jlogin.in @@ -1,8 +1,9 @@ #! @EXPECT_PATH@ -- ## -## $Id: jlogin.in,v 1.41 2004/01/11 05:39:15 heas Exp $ +## $Id: jlogin.in,v 1.56 2006/12/05 16:50:52 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -42,15 +43,13 @@ set password_file $env(HOME)/.cloginrc set do_command 0 set do_script 0 # The default is to automatically enable -set enable 1 +set avenable 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 -# No passphrase by default -set passphrase "" # Find the user in the ENV, or use the unix userid. -if {[ info exists env(CISCO_USER) ] } { +if {[ info exists env(CISCO_USER) ]} { set default_user $env(CISCO_USER) } elseif {[ info exists env(USER) ]} { set default_user $env(USER) @@ -66,6 +65,9 @@ if {[ info exists env(CISCO_USER) ] } { } regexp {\(([^)]*)} "$reason" junk default_user } +if {[ info exists env(CLOGINRC) ]} { + set password_file $env(CLOGINRC) +} # Sometimes routers take awhile to answer (the default is 10 sec) set timeout 120 @@ -107,12 +109,16 @@ for {set i 0} {$i < $argc} {incr i} { set userpasswd [ lindex $argv $i ] } set do_passwd 0 + # Version string + } -V* { + send_user "@PACKAGE@ @VERSION@\n" + exit 0 # passphrase } -r* - -R* { if {! [ regexp .\[rR\](.+) $arg ignore passphrase]} { incr i - set passphrase [ lindex $argv $i ] + set avpassphrase [ lindex $argv $i ] } # Expect script to run. } -s* - @@ -254,6 +260,7 @@ proc source_password_file { password_file } { } # Log into the router. +# returns: 0 on success, 1 on failure proc login { router user passwd cmethod cyphertype identfile} { global spawn_id in_proc do_command do_script passphrase prompt global sshcmd @@ -262,6 +269,7 @@ proc login { router user passwd cmethod cyphertype identfile} { # try each of the connection methods in $cmethod until one is successful set progs [llength $cmethod] foreach prog [lrange $cmethod 0 end] { + incr progs -1 if [string match "telnet*" $prog] { regexp {telnet(:([^[:space:]]+))*} $prog command suffix port if {"$port" == ""} { @@ -271,7 +279,7 @@ proc login { router user passwd cmethod cyphertype identfile} { } if { $retval } { send_user "\nError: telnet failed: $reason\n" - exit 1 + return 1 } } elseif ![string compare $prog "ssh"] { # ssh to the router & try to login with or without an identfile. @@ -280,24 +288,24 @@ proc login { router user passwd cmethod cyphertype identfile} { if {$identfile != ""} { if [ catch {spawn $sshcmd -c $cyphertype -x -l $user -i $identfile $router} reason ] { send_user "\nError: failed to $sshcmd: $reason\n" - exit 1 + return 1 } } else { if [ catch {spawn $sshcmd -c $cyphertype -x -l $user $router} reason ] { send_user "\nError: failed to $sshcmd: $reason\n" - exit 1 + return 1 } } } elseif ![string compare $prog "rsh"] { - if [ catch {spawn rsh -l $user $router} reason ] { - send_user "\nError: rsh failed: $reason\n" - exit 1 + send_error "\nError: unsupported method: rsh\n" + if { $progs == 0 } { + return 1 } + continue } else { - puts "\nError: unknown connection method: $prog" + send_user "\nError: unknown connection method: $prog\n" return 1 } - incr progs -1 sleep 0.3 # This helps cleanup each expect clause. @@ -345,8 +353,12 @@ proc login { router user passwd cmethod cyphertype identfile} { catch {close}; send_user "\nError: Unknown host\n"; wait; return 1 } - -re "Enter passphrase for RSA key '\[^'\]*': " { - send_user "\nKey has passphrase!\n" + "Login incorrect" { + send_user "\nError: Check your password for $router\n" + catch {close}; wait; return 1 + } + -re "Enter passphrase.*: " { + # sleep briefly to allow time for stty -echo sleep 1 send "$passphrase\r" exp_continue } @@ -423,9 +435,11 @@ proc run_commands { prompt command } { } send "quit\r" expect { - "\n" { exp_continue } - timeout { return 0 } - eof { return 0 } + "\n" { exp_continue } + timeout { catch {close}; wait + return 0 + } + eof { return 0 } } set in_proc 0 } @@ -465,10 +479,17 @@ foreach router [lrange $argv $i end] { } } - # figure out identity file to use - set identfile "" - if {[info exists identity]} { - set identfile [join [lindex [find identity $router] 0] ""] + # Figure out identity file to use + set identfile [join [lindex [find identity $router] 0] ""] + + # Figure out passphrase to use + if {[info exists avpassphrase]} { + set passphrase $avpassphrase + } else { + set passphrase [join [lindex [find passphrase $router] 0] ""] + } + if { ! [string length "$passphrase"]} { + set passphrase $passwd } # Figure out ssh cypher type @@ -484,9 +505,9 @@ 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} } + # 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]} { diff --git a/bin/jrancid.in b/bin/jrancid.in index 2793446..252b1a3 100644 --- a/bin/jrancid.in +++ b/bin/jrancid.in @@ -1,8 +1,9 @@ #! @PERLV_PATH@ ## -## $Id: jrancid.in,v 1.58 2004/01/11 03:49:13 heas Exp $ +## $Id: jrancid.in,v 1.80 2006/12/05 17:14:27 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -24,10 +25,14 @@ # # RANCID - Really Awesome New Cisco confIg Differ # -# usage: jrancid [-d] [-l] [-f filename | $host] +# usage: jrancid [-dV] [-l] [-f filename | hostname] # use Getopt::Std; -getopts('dfl'); +getopts('dflV'); +if ($opt_V) { + print "@PACKAGE@ @VERSION@\n"; + exit(0); +} $debug = $opt_d; $log = $opt_l; $file = $opt_f; @@ -35,14 +40,17 @@ $host = $ARGV[0]; $clean_run = 0; $found_end = 0; +$timeo = 120; # clogin timeout in seconds -my(%filter_pwds); # password filtering mode +my(@commandtable, %commands, @commands);# command lists +my(%filter_pwds); # password filtering mode +my($ShowChassisSCB); # Only run ShowChassisSCB() once # 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) { + 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; } @@ -64,10 +72,10 @@ sub ProcessHistory { sub numerically { $a <=> $b; } -# This is a sort routing that will sort numerically on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort numerically keys(%lines)) { @@ -77,10 +85,10 @@ sub keynsort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort keys(%lines)) { @@ -90,22 +98,22 @@ sub keysort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort values %lines) { - $sorted_lines[$i] = $key; - $i++; + $sorted_lines[$i] = $key; + $i++; } @sorted_lines; } -# This is a numerical sort routing (ascending). +# This is a numerical sort routine (ascending). sub numsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $num (sort {$a <=> $b} keys %lines) { @@ -119,7 +127,7 @@ sub numsort { # ip address when the ip address is anywhere in # the strings. sub ipsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $addr (sort sortbyipaddr keys %lines) { @@ -132,7 +140,7 @@ sub ipsort { # 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])); + $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0])); } sub sortbyipaddr { &ipaddrval($a) <=> &ipaddrval($b); @@ -150,9 +158,9 @@ sub ShowChassisClocks { ProcessHistory("","","","# $_"); while (<INPUT>) { tr/\015//d; - last if(/^$prompt/); - next if(/^system (shutdown message from|going down )/i); - next if(/^\{(master|backup)}/); + 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; @@ -162,10 +170,20 @@ sub ShowChassisClocks { /syntax error/ && return; # filter decimal places of m160 measured clock MHz - /Measured frequency/ && s/\..*MHz/ MHz/; + if (/Measured frequency/) { + s/\..*MHz/ MHz/; + } elsif (/^.+\.[0-9]+ MHz$/) { + # filter for the m160 (newer format) + s/\.[0-9]+ MHz/ MHz/; + } elsif (/^(.+)(\.[0-9]+) MHz/) { + # filter for T series + my($leadlen) = length($1); + $x = sprintf(" MHz%".length($2)."s", " "); + substr($_, $leadlen, length($2)+4, $x); + } ProcessHistory("","","","# $_"); } - return; + return(0); } # This routine parses "show chassis environment" @@ -176,9 +194,9 @@ sub ShowChassisEnvironment { ProcessHistory("","","","# $_"); while (<INPUT>) { tr/\015//d; - last if(/^$prompt/); - next if(/^system (shutdown message from|going down )/i); - next if(/^\{(master|backup)}/); + 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; @@ -186,6 +204,7 @@ sub ShowChassisEnvironment { /command is not valid/ && return; /^\s+\^/ && return; /syntax error/ && return; + / backplane temperature/ && next; /(\s*Power supply.*), temperature/ && ProcessHistory("","","","# $1\n") && next; @@ -193,9 +212,11 @@ sub ShowChassisEnvironment { ProcessHistory("","","","# $1\n") && next; /(^.*\S)\s+ Spinning at .*$/ && ProcessHistory("","","","# $1\n") && next; + /(^.*\S)\s+Measurement/ && + ProcessHistory("","","","# $1\n") && next; ProcessHistory("","","","# $_"); } - return; + return(0); } # This routine parses "show chassis firmware" @@ -206,9 +227,9 @@ sub ShowChassisFirmware { ProcessHistory("","","","# $_"); while (<INPUT>) { tr/\015//d; - last if(/^$prompt/); - next if(/^system (shutdown message from|going down )/i); - next if(/^\{(master|backup)}/); + 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; @@ -216,9 +237,10 @@ sub ShowChassisFirmware { /command is not valid/ && return; /^\s+\^/ && return; /syntax error/ && return; + ProcessHistory("","","","# $_"); } - return; + return(0); } # This routine parses "show chassis fpc detail" @@ -229,9 +251,9 @@ sub ShowChassisFpcDetail { ProcessHistory("","","","# $_"); while (<INPUT>) { tr/\015//d; - last if(/^$prompt/); - next if(/^system (shutdown message from|going down )/i); - next if(/^\{(master|backup)}/); + 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; @@ -239,12 +261,13 @@ sub ShowChassisFpcDetail { /command is not valid/ && return; /^\s+\^/ && return; /syntax error/ && return; + / Temperature/ && next; / Start time/ && next; / Uptime/ && next; ProcessHistory("","","","# $_"); } - return; + return(0); } # This routine parses "show chassis hardware" @@ -255,9 +278,9 @@ sub ShowChassisHardware { ProcessHistory("","","","# $_"); while (<INPUT>) { tr/\015//d; - last if(/^$prompt/); - next if(/^system (shutdown message from|going down )/i); - next if(/^\{(master|backup)}/); + 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; @@ -265,9 +288,10 @@ sub ShowChassisHardware { /command is not valid/ && return; /^\s+\^/ && return; /syntax error/ && return; + ProcessHistory("","","","# $_"); } - return; + return(0); } # This routine parses "show chassis routing-engine" @@ -279,9 +303,9 @@ sub ShowChassisRoutingEngine { ProcessHistory("","","","# $_"); while (<INPUT>) { tr/\015//d; - last if(/^$prompt/); - next if(/^system (shutdown message from|going down )/i); - next if(/^\{(master|backup)}/); + 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; @@ -289,15 +313,17 @@ sub ShowChassisRoutingEngine { /command is not valid/ && return; /^\s+\^/ && return; /syntax error/ && return; + /^Routing Engine status:/ && ProcessHistory("","","","# $_") && next; / Slot / && ProcessHistory("","","","# $_") && next; / Current state/ && ProcessHistory("","","","# $_") && next; / Election priority/ && ProcessHistory("","","","# $_") && next; / DRAM/ && ProcessHistory("","","","# $_") && next; + / Model/ && ProcessHistory("","","","# $_") && next; / Serial ID/ && ProcessHistory("","","","# $_") && next; /^\s*$/ && ProcessHistory("","","","# $_") && next; } - return; + return(0); } # This routine parses "show chassis cfeb", "show chassis feb", "show @@ -310,9 +336,9 @@ sub ShowChassisSCB { ProcessHistory("","","","# $_"); while (<INPUT>) { tr/\015//d; - last if(/^$prompt/); - next if(/^system (shutdown message from|going down )/i); - next if(/^\{(master|backup)}/); + 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; @@ -321,7 +347,9 @@ sub ShowChassisSCB { /command is not valid/ && return; /^\s+\^/ && return; /syntax error/ && return; + / Temperature/ && next; + / temperature/ && next; / utilization/ && next; / Start time/ && next; / Uptime/ && next; @@ -330,26 +358,115 @@ sub ShowChassisSCB { ProcessHistory("","","","# $_"); } $ShowChassisSCB = 1; - return; + return(0); } -# This routine parses "show system boot-messages" +# This routine parses "show chassis alarms" sub ShowChassisAlarms { print STDERR " In ShowChassisAlarms: $_" if ($debug); + s/^[a-z]+@//; + ProcessHistory("","","","# $_"); + while (<INPUT>) { + tr/\015//d; + last if (/^$prompt/); + next if (/^system (shutdown message from|going down )/i); + next if (/^\{(master|backup)}/); + + /Unrecognized command/ && return; + /command is not valid/ && return; + /^\s+\^/ && return; + /syntax error/ && return; + + ProcessHistory("","","","# $_"); + } + return(0); +} + +# This routine parses "show system autoinstallation status" +sub ShowSystemAutoinstall { + print STDERR " In ShowSystemAutoinstall: $_" if ($debug); + + s/^[a-z]+@//; ProcessHistory("","","","# $_"); while (<INPUT>) { tr/\015//d; - last if(/^$prompt/); - next if(/^system (shutdown message from|going down )/i); - next if(/^\{(master|backup)}/); + last if (/^$prompt/); + next if (/^system (shutdown message from|going down )/i); + next if (/^\{(master|backup)}/); /Unrecognized command/ && return; + /command is not valid/ && return; /^\s+\^/ && return; /syntax error/ && return; + ProcessHistory("","","","# $_"); } - return; + return(0); +} + +sub ShowSystemCoreDumps { + print STDERR " In ShowSystemCoreDumps: $_" if ($debug); + + s/^[a-z]+@//; + ProcessHistory("","","","# $_"); + while (<INPUT>) { + tr/\015//d; + last if (/^$prompt/); + + /Unrecognized command/ && return(1); + /^\s+\^/ && return(1); + /syntax error/ && return(1); + /^JUNOS / && <INPUT> && next; + /No such file or directory$/ && next; + + ProcessHistory("","","","# $_"); + } + return(0); +} + +# This routine parses "show system license" +sub ShowSystemLicense { + print STDERR " In ShowSystemLicense: $_" if ($debug); + + s/^[a-z]+@//; + ProcessHistory("","","","# $_"); + while (<INPUT>) { + tr/\015//d; + last if (/^$prompt/); + next if (/^system (shutdown message from|going down )/i); + next if (/^\{(master|backup)}/); + + /Unrecognized command/ && return; + /command is not valid/ && return; + /^\s+\^/ && return; + /syntax error/ && return; + + ProcessHistory("","","","# $_"); + } + return(0); +} + +# This routine parses "show system license keys" +sub ShowSystemLicenseKeys { + print STDERR " In ShowSystemLicenseKeys: $_" if ($debug); + + s/^[a-z]+@//; + ProcessHistory("","","","# $_"); + while (<INPUT>) { + tr/\015//d; + last if (/^$prompt/); + next if (/^system (shutdown message from|going down )/i); + next if (/^\{(master|backup)}/); + + /Unrecognized command/ && return; + /command is not valid/ && return; + /^\s+\^/ && return; + /syntax error/ && return; + + ProcessHistory("","","","# $_"); + } + return(0); } # This routine parses "show system boot-messages" @@ -360,13 +477,15 @@ sub ShowSystemBootMessages { ProcessHistory("","","","# $_"); while (<INPUT>) { tr/\015//d; - last if(/^$prompt/); - next if(/^system (shutdown message from|going down )/i); - next if(/^\{(master|backup)}/); + last if (/^$prompt/); + next if (/^system (shutdown message from|going down )/i); + next if (/^\{(master|backup)}/); /Unrecognized command/ && return; + /command is not valid/ && return; /^\s+\^/ && return; /syntax error/ && return; + /^JUNOS / && <INPUT> && next; /^Timecounter "TSC" / && next; /^real memory / && next; @@ -374,7 +493,7 @@ sub ShowSystemBootMessages { /^\/dev\// && next; ProcessHistory("","","","# $_"); } - return; + return(0); } # This routine parses "show version" @@ -385,17 +504,17 @@ sub ShowVersion { ProcessHistory("","","","# $_"); while (<INPUT>) { tr/\015//d; - last if(/^$prompt/); - next if(/^\s*$/); - next if(/^system (shutdown message from|going down )/i); - next if(/^\{(master|backup)}/); + 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; + return(0); } # This routine parses "show configuration" @@ -409,20 +528,21 @@ sub ShowConfiguration { while (<INPUT>) { tr/\015//d; next if (/^\s*$/); - # end of config - hopefully. juniper does not have a reliable + # end of config - hopefully. juniper does not have a reliable # end-of-config tag. appears to end with "\nPROMPT>", but not sure. - if(/^$prompt/) { + if (/^$prompt/) { $found_end++; last; } - next if(/^system (shutdown message from|going down )/i); - next if(/^\{(master|backup)}/); + 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$//; + s/ ## SECRET-DATA$//; # filter snmp community, when in snmp { stanza } /^snmp/ && $snmp++; /^}/ && ($snmp = 0); @@ -435,6 +555,10 @@ sub ShowConfiguration { ProcessHistory("","","","#$1<removed>$'"); next; } + if (/(\s*md5 \d+ key )[^ ;]+/ && $filter_pwds >= 1) { + ProcessHistory("","","","#$1<removed>$'"); + next; + } if (/(\s*hello-authentication-key )[^ ;]+/ && $filter_pwds >= 1) { ProcessHistory("","","","#$1<removed>$'"); next; @@ -464,7 +588,7 @@ sub ShowConfiguration { return(-1); } - return; + return(0); } ### @@ -475,44 +599,45 @@ sub ShowConfiguration { sub DoNothing {print STDOUT;} # Main -%commands=( - "show chassis clocks" => "ShowChassisClocks", - "show chassis environment" => "ShowChassisEnvironment", - "show chassis firmware" => "ShowChassisFirmware", - "show chassis fpc detail" => "ShowChassisFpcDetail", - "show chassis hardware detail" => "ShowChassisHardware", - "show chassis routing-engine" => "ShowChassisRoutingEngine", - "show chassis scb" => "ShowChassisSCB", - "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 detail" => "ShowVersion", - "show configuration" => "ShowConfiguration" -); -@commands=( - "show chassis clocks", - "show chassis environment", - "show chassis firmware", - "show chassis fpc detail", - "show chassis hardware detail", - "show chassis routing-engine", - "show chassis scb", - "show chassis sfm detail", - "show chassis ssb", - "show chassis feb", - "show chassis cfeb", - "show chassis alarms", - "show system boot-messages", - "show version detail", - "show configuration" +@commandtable = ( + {'show chassis clocks' => 'ShowChassisClocks'}, + {'show chassis environment' => 'ShowChassisEnvironment'}, + {'show chassis firmware' => 'ShowChassisFirmware'}, + {'show chassis fpc detail' => 'ShowChassisFpcDetail'}, + {'show chassis hardware detail' => 'ShowChassisHardware'}, + {'show chassis routing-engine' => 'ShowChassisRoutingEngine'}, + {'show chassis scb' => 'ShowChassisSCB'}, + {'show chassis sfm detail' => 'ShowChassisSCB'}, + {'show chassis ssb' => 'ShowChassisSCB'}, + {'show chassis feb detail' => 'ShowChassisSCB'}, + {'show chassis feb' => 'ShowChassisSCB'}, + {'show chassis cfeb' => 'ShowChassisSCB'}, + {'show chassis alarms' => 'ShowChassisAlarms'}, +# {'show system autoinstallation status' => 'ShowSystemAutoinstall'}, + {'show system license' => 'ShowSystemLicense'}, +# {'show system license keys' => 'ShowSystemLicenseKeys'}, + {'show system boot-messages' => 'ShowSystemBootMessages'}, + {'show system core-dumps' => 'ShowSystemCoreDumps'}, + {'show version detail' => 'ShowVersion'}, + {'show configuration' => 'ShowConfiguration'} ); +# Use an array to preserve the order of the commands and a hash for mapping +# commands to the subroutine and track commands that have been completed. +@commands = map(keys(%$_), @commandtable); +%commands = map(%$_, @commandtable); $jnx_commands=join(";",@commands); $cmds_regexp=join("|",@commands); +if (length($host) == 0) { + if ($file) { + print(STDERR "Too few arguments: file name required\n"); + exit(1); + } else { + print(STDERR "Too few arguments: host name required\n"); + exit(1); + } +} open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; select(OUTPUT); # make OUTPUT unbuffered @@ -523,21 +648,21 @@ if ($file) { print STDOUT "opening file $host\n" if ($log); open(INPUT,"< $host") || die "open failed for $host: $!\n"; } else { - print(STDERR "executing echo jlogin -c\"$jnx_commands\" $host\n") if ($debug); - print(STDOUT "executing echo jlogin -c\"$jnx_commands\" $host\n") if ($debug); + print(STDERR "executing echo jlogin -t $timeo -c\"$jnx_commands\" $host\n") if ($debug); + print(STDOUT "executing echo jlogin -t $timeo -c\"$jnx_commands\" $host\n") if ($debug); if (defined($ENV{NOPIPE})) { - system "jlogin -c \"$jnx_commands\" $host </dev/null > $host.raw" || die "jlogin failed for $host: $!\n"; + system "jlogin -t $timeo -c \"$jnx_commands\" $host </dev/null > $host.raw" || die "jlogin failed for $host: $!\n"; open(INPUT, "< $host.raw") || die "jlogin failed for $host: $!\n"; } else { - open(INPUT,"jlogin -c \"$jnx_commands\" $host </dev/null |") || die "jlogin failed for $host: $!\n"; + open(INPUT,"jlogin -t $timeo -c \"$jnx_commands\" $host </dev/null |") || die "jlogin failed for $host: $!\n"; } } # determine password filtering mode if ($ENV{"FILTER_PWDS"} =~ /no/i) { - $filter_pwds = 0; + $filter_pwds = 0; } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) { $filter_pwds = 2; } else { @@ -545,7 +670,7 @@ if ($ENV{"FILTER_PWDS"} =~ /no/i) { } ProcessHistory("","","","# RANCID-CONTENT-TYPE: juniper\n#\n"); -TOP: while(<INPUT>) { +TOP: while (<INPUT>) { tr/\015//d; if (/^Error:/) { print STDOUT ("$host jlogin error: $_"); diff --git a/bin/lg.cgi.in b/bin/lg.cgi.in index ad08c68..4ad6fdd 100644 --- a/bin/lg.cgi.in +++ b/bin/lg.cgi.in @@ -1,8 +1,9 @@ #! @PERLV_PATH@ ## -## $Id: lg.cgi.in,v 1.47 2004/01/11 03:49:13 heas Exp $ +## $Id: lg.cgi.in,v 1.54 2006/10/05 04:27:43 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -27,8 +28,8 @@ # vars: query, router, args BEGIN { -$me = $0; -$me =~ s/.*\/(\S+)$/$1/; + $me = $0; + $me =~ s/.*\/(\S+)$/$1/; } use CGI qw/:standard escapeHTML/; @@ -38,6 +39,7 @@ use LockFile::Simple qw(lock trylock unlock); my($BASEDIR) = "@prefix@"; my($SYSCONFDIR) = "@sysconfdir@"; +my($LOCALSTATEDIR) = "@localstatedir@"; my($pingcmd) = "@LG_PING_CMD@"; my($query, $max_time_diff, $cache_dir, $cloginrc, @results); @@ -134,23 +136,24 @@ sub readrouters # 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"); + if (! opendir(DIR, $LOCALSTATEDIR)) { + dolog(LOG_ERR, "ERROR: couldn\'t read $LOCALSTATEDIR: $!\n"); } else { while ($dir = readdir(DIR)) { - next if ($dir =~ /^(\.|\.\.|CVS|bin|etc|logs|util)$/); - push(@dirs, $dir) if (-d "$BASEDIR/$dir"); + next if ($dir =~ /^(\.|\.\.|\.ssh|CVS|bin|etc|logs|util)$/); + push(@dirs, $dir) if (-d "$LOCALSTATEDIR/$dir"); } closedir(DIR); foreach $dir (@dirs) { - if (! opendir(DIR, "$BASEDIR/$dir")) { - dolog(LOG_ERR, "ERROR: couldn\'t read $BASEDIR/$dir: $!\n"); + if (! opendir(DIR, "$LOCALSTATEDIR/$dir")) { + dolog(LOG_ERR, + "ERROR: couldn\'t read $LOCALSTATEDIR/$dir: $!\n"); next; } closedir(DIR); - next if (! -f "$BASEDIR/$dir/router.db"); - if (open(RTR, "< $BASEDIR/$dir/router.db")) { + next if (! -f "$LOCALSTATEDIR/$dir/router.db"); + if (open(RTR, "< $LOCALSTATEDIR/$dir/router.db")) { while (<RTR>) { next if (/^\s*(#|$)/); # fqdn:mfg:state @@ -162,7 +165,7 @@ sub readrouters close(RTR); } else { dolog(LOG_ERR, "ERROR: couldn\'t open the router.db " . - "file: $BASEDIR/$dir/router.db: $!\n"); + "file: $LOCALSTATEDIR/$dir/router.db: $!\n"); } } } @@ -430,7 +433,7 @@ $max_lock_hold = 300; if (defined($LG_CLOGINRC)) { $cloginrc = $LG_CLOGINRC; } else { - $cloginrc = "$ENV(HOME)/.cloginrc"; + $cloginrc = $ENV{HOME} . "/.cloginrc"; } $query = new CGI; @@ -451,7 +454,7 @@ if (!defined($type) || !defined($router) || $router eq "") { "a clue.\n"); } -if ($arg !~ /^[-A-Za-z0-9|_\/ \.^\$]*$/) { +if ($arg !~ /^[-A-Za-z0-9|_\/: \.^\$]*$/) { &Error("Funny characters in argument; ignoring.\n"); } if (length($arg) >= 50) { @@ -678,7 +681,7 @@ if ($type eq "prefix" || $type eq "mbgp" || $type eq "route" ) { if ($mfg =~ /cisco/i) { $arg = " | include " . join(' ', @arg); } elsif ($mfg =~ /juniper/i) { - $arg = " | match \"" . join(' ', @arg) . "\""; + $arg = " | match \\\"" . join(' ', @arg) . "\\\""; } else { undef($arg); } @@ -736,7 +739,7 @@ if ($type eq "prefix" || $type eq "mbgp" || $type eq "route" ) { } else { $arg =~ s/[\$^]/ /g; } - $arg = "\"$arg\""; + $arg = "\\\"$arg\\\""; } # escape any ()s $arg =~ s/([\(\)])/\\$1/g; diff --git a/bin/lgform.cgi.in b/bin/lgform.cgi.in index 461ae68..774d104 100644 --- a/bin/lgform.cgi.in +++ b/bin/lgform.cgi.in @@ -1,8 +1,9 @@ #! @PERLV_PATH@ ## -## $Id: lgform.cgi.in,v 1.25 2004/01/11 03:49:13 heas Exp $ +## $Id: lgform.cgi.in,v 1.31 2006/10/05 04:27:43 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -26,11 +27,19 @@ # lgform.cgi - Looking glass front-end # produces html form for calling lg.cgi +BEGIN { + $me = $0; + $me =~ s/.*\/(\S+)$/$1/; +} + use CGI qw/:standard/; +use POSIX qw(strftime); +use Sys::Syslog; my(@rtrlist, %rtrlabels); my($BASEDIR) = "@prefix@"; my($SYSCONFDIR) = "@sysconfdir@"; +my($LOCALSTATEDIR) = "@localstatedir@"; # 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. @@ -118,23 +127,24 @@ sub readrouters # 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"); + if (! opendir(DIR, $LOCALSTATEDIR)) { + dolog(LOG_ERR, "ERROR: couldn\'t read $LOCALSTATEDIR: $!\n"); } else { while ($dir = readdir(DIR)) { - next if ($dir =~ /^(\.|\.\.|CVS|bin|etc|logs|util)$/); - push(@dirs, $dir) if (-d "$BASEDIR/$dir"); + next if ($dir =~ /^(\.|\.\.|\.ssh|CVS|bin|etc|logs|util)$/); + push(@dirs, $dir) if (-d "$LOCALSTATEDIR/$dir"); } closedir(DIR); foreach $dir (@dirs) { - if (! opendir(DIR, "$BASEDIR/$dir")) { - dolog(LOG_ERR, "ERROR: couldn\'t read $BASEDIR/$dir: $!\n"); + if (! opendir(DIR, "$LOCALSTATEDIR/$dir")) { + dolog(LOG_ERR, + "ERROR: couldn\'t read $LOCALSTATEDIR/$dir: $!\n"); next; } closedir(DIR); - next if (! -f "$BASEDIR/$dir/router.db"); - if (open(RTR, "< $BASEDIR/$dir/router.db")) { + next if (! -f "$LOCALSTATEDIR/$dir/router.db"); + if (open(RTR, "< $LOCALSTATEDIR/$dir/router.db")) { while (<RTR>) { next if (/^\s*(#|$)/); # fqdn:mfg:state @@ -146,7 +156,7 @@ sub readrouters close(RTR); } else { dolog(LOG_ERR, "ERROR: couldn\'t open the router.db " . - "file: $BASEDIR/$dir/router.db: $!\n"); + "file: $LOCALSTATEDIR/$dir/router.db: $!\n"); } } } diff --git a/bin/mrancid.in b/bin/mrancid.in index 8d52c27..f77779e 100644 --- a/bin/mrancid.in +++ b/bin/mrancid.in @@ -1,8 +1,9 @@ #! @PERLV_PATH@ ## -## $Id: mrancid.in,v 1.11 2004/01/11 03:49:13 heas Exp $ +## $Id: mrancid.in,v 1.19 2006/10/05 04:27:43 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -24,25 +25,30 @@ # # RANCID - Really Awesome New Cisco confIg Differ # -# usage: rancid [-d] [-l] [-f filename | $host] +# usage: rancid [-dV] [-l] [-f filename | hostname] # use Getopt::Std; -getopts('dfl'); +getopts('dflV'); +if ($opt_V) { + print "@PACKAGE@ @VERSION@\n"; + exit(0); +} $log = $opt_l; $debug = $opt_d; $file = $opt_f; $host = $ARGV[0]; $clean_run = 0; $found_end = 0; -$timeo = 90; # clogin timeout in seconds +$timeo = 90; # clogin timeout in seconds -my(%filter_pwds); # password filtering mode +my(@commandtable, %commands, @commands);# command lists +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) { + 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; } @@ -64,10 +70,10 @@ sub ProcessHistory { sub numerically { $a <=> $b; } -# This is a sort routing that will sort numerically on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort numerically keys(%lines)) { @@ -77,10 +83,10 @@ sub keynsort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort keys(%lines)) { @@ -90,10 +96,10 @@ sub keysort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort values %lines) { @@ -103,9 +109,9 @@ sub valsort{ @sorted_lines; } -# This is a numerical sort routing (ascending). +# This is a numerical sort routine (ascending). sub numsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $num (sort {$a <=> $b} keys %lines) { @@ -119,7 +125,7 @@ sub numsort { # ip address when the ip address is anywhere in # the strings. sub ipsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $addr (sort sortbyipaddr keys %lines) { @@ -132,7 +138,7 @@ sub ipsort { # 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])); + $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0])); } sub sortbyipaddr { &ipaddrval($a) <=> &ipaddrval($b); @@ -292,7 +298,6 @@ sub WriteTerm { ProcessHistory("IPHOST","numsort","$1","$_") && next; # end of config - #if (/^end(\n\[OK])?$/) { if (/^(: )?end$/) { $found_end = 1; return(1); @@ -305,19 +310,27 @@ sub WriteTerm { sub DoNothing {print STDOUT;} # Main -%commands=( - 'show version' => "ShowVersion", - 'show config' => "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 config" +@commandtable = ( + {'show version' => 'ShowVersion'}, + {'show config' => 'WriteTerm'} ); +# Use an array to preserve the order of the commands and a hash for mapping +# commands to the subroutine and track commands that have been completed. +@commands = map(keys(%$_), @commandtable); +%commands = map(%$_, @commandtable); + $cisco_cmds=join(";",@commands); $cmds_regexp=join("|",@commands); +if (length($host) == 0) { + if ($file) { + print(STDERR "Too few arguments: file name required\n"); + exit(1); + } else { + print(STDERR "Too few arguments: host name required\n"); + exit(1); + } +} open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; select(OUTPUT); # make OUTPUT unbuffered if debugging @@ -340,7 +353,7 @@ if ($file) { # determine password filtering mode if ($ENV{"FILTER_PWDS"} =~ /no/i) { - $filter_pwds = 0; + $filter_pwds = 0; } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) { $filter_pwds = 2; } else { diff --git a/bin/nlogin.in b/bin/nlogin.in index 685c759..53e8812 100644 --- a/bin/nlogin.in +++ b/bin/nlogin.in @@ -1,8 +1,9 @@ #! @EXPECT_PATH@ -- ## -## $Id: nlogin.in,v 1.14 2004/01/11 05:39:15 heas Exp $ +## $Id: nlogin.in,v 1.33 2006/12/08 21:28:26 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -20,16 +21,22 @@ ## # # The login expect scripts were based on Erik Sherk's gwtn, by permission. +# Netscreen hacks implemented by Stephen Gill <gillsr@yahoo.com>. # # nlogin - netscreen login # # Most options are intuitive for logging into a netscreen firewall. # +# Misc notes +# netscreen does not have the concept of "enable", once logged in, a +# users permissions can not change. # 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" +set usage "Usage: $argv0 \[-c command\] \[-Evar=x\] \[-f cloginrc-file\] \ +\[-p user-password\] \ +\[-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 @@ -39,18 +46,13 @@ 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) ] } { +if {[ info exists env(CISCO_USER) ]} { set default_user $env(CISCO_USER) } elseif {[ info exists env(USER) ]} { set default_user $env(USER) @@ -63,9 +65,12 @@ if {[ info exists env(CISCO_USER) ] } { if [ catch {exec id} reason ] { send_error "\nError: could not exec id: $reason\n" exit 1 - } + } regexp {\(([^)]*)} "$reason" junk default_user -} +} +if {[ info exists env(CLOGINRC) ]} { + set password_file $env(CLOGINRC) +} # Sometimes firewall take awhile to answer (the default is 10 sec) set timeout 45 @@ -154,7 +159,6 @@ for {set i 0} {$i < $argc} {incr i} { # Does tacacs automatically enable us? } -autoenable { # ignore autoenable - #set avautoenable 1 } -* { send_user "\nError: Unknown argument! $arg\n" send_user $usage @@ -208,9 +212,9 @@ proc include {args} { 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 @@ -228,7 +232,7 @@ proc find {var firewall} { # 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 +# 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] } { @@ -247,6 +251,7 @@ proc source_password_file { password_file } { } # Log into the firewall. +# returns: 0 on success, 1 on failure proc login { firewall user userpswd passwd enapasswd prompt cmethod cyphertype } { global spawn_id in_proc do_command do_script sshcmd @@ -256,6 +261,7 @@ cyphertype } { # Telnet to the firewall & try to login. set progs [llength $cmethod] foreach prog [lrange $cmethod 0 end] { + incr progs -1 if [string match "telnet*" $prog] { regexp {telnet(:([^[:space:]]+))*} $prog command suffix port if {"$port" == ""} { @@ -265,23 +271,23 @@ cyphertype } { } if { $retval } { send_user "\nError: telnet failed: $reason\n" - exit 1 + return 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 - } + return 1 + } } elseif ![string compare $prog "rsh"] { - if [ catch {spawn rsh -l $user $firewall} reason ] { - send_user "\nError: rsh failed: $reason\n" - exit 1 + send_error "\nError: unsupported method: rsh\n" + if { $progs == 0 } { + return 1 } + continue; } else { - puts "\nError: unknown connection method: $prog" + send_user "\nError: unknown connection method: $prog\n" return 1 } - incr progs -1 sleep 0.3 @@ -314,10 +320,10 @@ cyphertype } { # then it will just send the passwd. # if telnet fails with connection refused, try ssh expect { - "Connection refused" { + "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" { + } "Unknown host\r\n" { expect eof send_user "\nError: Unknown host\n"; wait; return 1 } "Host is unreachable" { @@ -343,17 +349,17 @@ cyphertype } { 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" + 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:)" { + -re "(login:)" { sleep 1; send "$user\r" set uprompt_seen 1 exp_continue } - "@\[^\r\n]+\[Pp]assword:" { + -re "@\[^\r\n]+\[Pp]assword:" { # ssh pwd prompt sleep 1 send "$userpswd\r" @@ -368,7 +374,7 @@ cyphertype } { } exp_continue } - "$prompt" { break; } + -- "$prompt" { break; } } } set in_proc 0 @@ -381,7 +387,7 @@ proc run_commands { prompt command } { set in_proc 1 send "set console page 0\r" - expect $prompt {} + expect -re $prompt {} # Is this a multi-command? if [ string match "*\;*" "$command" ] { @@ -391,26 +397,38 @@ proc run_commands { prompt command } { for {set i 0} {$i < $num_commands} { incr i} { send "[subst [lindex $commands $i]]\r" expect { - -re "$prompt" {} + -re "\[\n\r]+" { exp_continue } + -re "$prompt" {} + -gl "--- more ---" { send " " + exp_continue + } } } } else { send "[subst $command]\r" expect { - -re "$prompt" {} + -re "\[\n\r]+" { exp_continue } + -re "$prompt" {} + -gl "--- more ---" { send " " + exp_continue + } } } 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 } + -re "$prompt" { + send "exit\r" + exp_continue + } + -re "\[\n\r]+" { exp_continue } + -gl "Configuration modified, save?" { + send "n\r" + exp_continue + } + timeout { catch {close}; wait + return 0 + } + eof { return 0 } } set in_proc 0 } @@ -424,7 +442,7 @@ foreach firewall [lrange $argv $i end] { set firewall [string tolower $firewall] send_user "$firewall\n" - set prompt ">" + set prompt {-> } # Figure out passwords if { $do_passwd || $do_enapasswd } { @@ -432,19 +450,22 @@ foreach firewall [lrange $argv $i end] { if { [llength $pswd] == 0 } { send_user "\nError: no password for $firewall in $password_file.\n" continue - } - set passwd [join [lindex $pswd 0]""] + } + set passwd [join [lindex $pswd 0] ""] set enapasswd [join [lindex $pswd 1] ""] + } else { + set passwd $userpasswd + set enapasswd $enapasswd } # Figure out username - if {[info exists username]} { + 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]} { @@ -452,17 +473,9 @@ foreach firewall [lrange $argv $i end] { 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 } - } + if { "$userpswd" == "" } { set userpswd $passwd } + } + # Figure out cypher type if {[info exists cypher]} { @@ -477,28 +490,23 @@ foreach firewall [lrange $argv $i end] { 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} } + # Figure out the SSH executable name + set sshcmd [find sshcmd $firewall] + 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; + -re "^(.+$prompt)" { set junk $expect_out(0,string); + # if it has HA (high avail), the prompt will + # be "something-(.)->" + regsub -all "\[\]\)\(\[]" $junk {\\&} prompt; } } @@ -508,11 +516,11 @@ foreach firewall [lrange $argv $i end] { } } elseif { $do_script } { send "set console page 0\r" - expect $prompt {} + expect -re $prompt {} source $sfile close } else { - label $firewall + label $firewall log_user 1 interact } diff --git a/bin/nrancid.in b/bin/nrancid.in index 9b965a2..940bdc8 100644 --- a/bin/nrancid.in +++ b/bin/nrancid.in @@ -1,8 +1,9 @@ #! @PERLV_PATH@ ## -## $Id: nrancid.in,v 1.13 2004/01/11 03:49:13 heas Exp $ +## $Id: nrancid.in,v 1.28 2006/11/10 21:40:48 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -21,29 +22,34 @@ # # 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] +# usage: rancid [-dV] [-l] [-f filename | hostname] # use Getopt::Std; -getopts('dfl'); +getopts('dflV'); +if ($opt_V) { + print "@PACKAGE@ @VERSION@\n"; + exit(0); +} $log = $opt_l; $debug = $opt_d; $file = $opt_f; $host = $ARGV[0]; $found_end = 0; -$timeo = 90; # nlogin timeout in seconds +$timeo = 90; # nlogin timeout in seconds -my(%filter_pwds); # password filtering mode +my(@commandtable, %commands, @commands);# command lists +my(%filter_pwds); # password filtering mode -# This routine is used to print out the firewall configuration +# 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) { + 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; } @@ -65,10 +71,10 @@ sub ProcessHistory { sub numerically { $a <=> $b; } -# This is a sort routing that will sort numerically on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort numerically keys(%lines)) { @@ -78,10 +84,10 @@ sub keynsort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort keys(%lines)) { @@ -91,22 +97,22 @@ sub keysort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort values %lines) { - $sorted_lines[$i] = $key; - $i++; + $sorted_lines[$i] = $key; + $i++; } @sorted_lines; } -# This is a numerical sort routing (ascending). +# This is a numerical sort routine (ascending). sub numsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $num (sort {$a <=> $b} keys %lines) { @@ -120,7 +126,7 @@ sub numsort { # ip address when the ip address is anywhere in # the strings. sub ipsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $addr (sort sortbyipaddr keys %lines) { @@ -133,7 +139,7 @@ sub ipsort { # 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])); + $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0])); } sub sortbyipaddr { &ipaddrval($a) <=> &ipaddrval($b); @@ -147,24 +153,26 @@ sub GetSystem { tr/\015//d; next if /^\s*$/; last if(/$prompt/); + # throw away the pager lines + next if /^--- more ---/; - /^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; + /^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"); + ProcessHistory("SYSTEM","","","#\n"); return(0); } @@ -173,7 +181,7 @@ sub GetFile { while (<INPUT>) { last if(/$prompt/); } - ProcessHistory("FILE","","","!\n"); + ProcessHistory("FILE","","","#\n"); return(0); } @@ -182,21 +190,48 @@ sub GetConf { while (<INPUT>) { tr/\015//d; next if /^\s*$/; + next if /^Total Config.+$/i; last if(/$prompt/); + # throw away the pager lines + next if /^--- more ---/; if (/^set admin name "(\S+)"$/ && $filter_pwds >= 1) { - ProcessHistory("ADMIN","","","!set admin name <removed>\n"); - next; - } + ProcessHistory("ADMIN","","","#set admin name <removed>\n"); + next; + } if (/^set admin password (\S+)$/ && $filter_pwds >= 1) { - ProcessHistory("ADMIN","","","!set admin password <removed>\n"); - next; - } + ProcessHistory("ADMIN","","","#set admin password <removed>\n"); + next; + } if (/^set admin user (\S+) password (\S+) privilege (\S+)$/ && $filter_pwds >= 1) { - ProcessHistory("ADMIN","","", - "!set admin user $1 password <removed> privilege $3\n"); - next; + ProcessHistory("ADMIN","","", + "#set admin user $1 password <removed> privilege $3\n"); + next; + } + if (/^set auth-server (\S+) radius secret / && $filter_pwds >= 1 ) { + ProcessHistory("ADMIN","","", + "#set auth-server $1 radius secret <removed>\n"); + next; + } + if (/^set ike gateway (.*) username (\S+)(.*) password (\S+)(.*)$/ && + $filter_pwds >= 1) { + ProcessHistory("ADMIN","","", + "#set ike gateway $1 username <removed>$3 password <removed>$5\n"); + next; + } + if (/^set ike gateway (.*) preshare "(\S+)"(.*)$/ && + $filter_pwds >= 1) { + ProcessHistory("ADMIN","","", + "#set ike gateway $1 preshare <removed>$3\n"); + next; + } + if (/^set auth-server (.*) secret "(\S+)"(.*)$/ && + $filter_pwds >= 1) { + ProcessHistory("ADMIN","","", + "#set auth-server $1 secret <removed>$3\n"); + next; + } ProcessHistory("","","","$_"); } $found_end=1; @@ -207,19 +242,27 @@ sub GetConf { 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" +@commandtable = ( + {'get system' => 'GetSystem'}, + {'get conf' => 'GetConf'} ); +# Use an array to preserve the order of the commands and a hash for mapping +# commands to the subroutine and track commands that have been completed. +@commands = map(keys(%$_), @commandtable); +%commands = map(%$_, @commandtable); + $cisco_cmds=join(";",@commands); $cmds_regexp=join("|",@commands); +if (length($host) == 0) { + if ($file) { + print(STDERR "Too few arguments: file name required\n"); + exit(1); + } else { + print(STDERR "Too few arguments: host name required\n"); + exit(1); + } +} open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; select(OUTPUT); # make OUTPUT unbuffered if debugging @@ -242,14 +285,14 @@ if ($file) { # determine password filtering mode if ($ENV{"FILTER_PWDS"} =~ /no/i) { - $filter_pwds = 0; + $filter_pwds = 0; } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) { - $filter_pwds = 2; + $filter_pwds = 2; } else { - $filter_pwds = 1; + $filter_pwds = 1; } -ProcessHistory("","","","!RANCID-CONTENT-TYPE: netscreen\n!\n"); +ProcessHistory("","","","#RANCID-CONTENT-TYPE: netscreen\n#\n"); TOP: while(<INPUT>) { tr/\015//d; if (/^Error:/) { @@ -260,7 +303,8 @@ TOP: while(<INPUT>) { while (/>\s*($cmds_regexp)\s*$/) { $cmd = $1; if (!defined($prompt)) { - $prompt = "\-\>\s*"; + $prompt = ($_ =~ /^([^>]+->)/)[0]; + $prompt =~ s/([][}{)(\\])/\\$1/g; print STDERR ("PROMPT MATCH: $prompt\n") if ($debug); } print STDERR ("HIT COMMAND:$_") if ($debug); @@ -293,7 +337,6 @@ if (scalar(%commands) || !$found_end) { 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"); diff --git a/bin/nslogin.in b/bin/nslogin.in index 385f530..6cf4188 100644 --- a/bin/nslogin.in +++ b/bin/nslogin.in @@ -1,8 +1,9 @@ #! @EXPECT_PATH@ -- ## -## $Id: nslogin.in,v 1.10 2004/01/11 05:39:15 heas Exp $ +## $Id: nslogin.in,v 1.22 2006/12/08 21:28:26 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -49,7 +50,7 @@ set password_file $env(HOME)/.cloginrc set do_command 1 set do_script 0 # The default is to automatically enable -set enable 0 +set avenable 0 # The default is that you login non-enabled (tacacs can have you login already # enabled) set avautoenable 0 @@ -61,7 +62,7 @@ set do_enapasswd 1 set platform "" # Find the user in the ENV, or use the unix userid. -if {[ info exists env(CISCO_USER) ] } { +if {[ info exists env(CISCO_USER) ]} { set default_user $env(CISCO_USER) } elseif {[ info exists env(USER) ]} { set default_user $env(USER) @@ -77,6 +78,9 @@ if {[ info exists env(CISCO_USER) ] } { } regexp {\(([^)]*)} "$reason" junk default_user } +if {[ info exists env(CLOGINRC) ]} { + set password_file $env(CLOGINRC) +} # Sometimes routers take awhile to answer (the default is 10 sec) set timeout 45 @@ -191,11 +195,11 @@ for {set i 0} {$i < $argc} {incr i} { set do_command 1 # Do we enable? } -noenable { - set enable 0 + set avenable 0 # Does tacacs automatically enable us? } -autoenable { set avautoenable 1 - set enable 0 + set avenable 0 } -* { send_user "\nError: Unknown argument! $arg\n" send_user $usage @@ -288,6 +292,7 @@ proc source_password_file { password_file } { } # Log into the router. +# returns: 0 on success, 1 on failure 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 @@ -297,16 +302,28 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype } { # try each of the connection methods in $cmethod until one is successful set progs [llength $cmethod] foreach prog [lrange $cmethod 0 end] { + incr progs -1 if ![string compare $prog "ssh"] { if [ catch {spawn $sshcmd -c $cyphertype -x -l $user $router} reason ] { send_user "\nError: $sshcmd failed: $reason\n" - exit 1 + return 1 + } + } elseif ![string compare $prog "telnet"] { + send_error "\nError: unsupported method: telnet\n" + if { $progs == 0 } { + return 1 + } + continue + } elseif ![string compare $prog "rsh"] { + send_error "\nError: unsupported method: rsh\n" + if { $progs == 0 } { + return 1 } + continue } else { - puts "\nError: unknown connection method: $prog" + send_user "\nError: unknown connection method: $prog\n" return 1 } - incr progs -1 sleep 0.3 # This helps cleanup each expect clause. @@ -487,7 +504,9 @@ proc run_commands { prompt command } { exp_continue } "\n" { exp_continue } - timeout { return 0 } + timeout { catch {close}; wait + return 0 + } eof { return 0 } } set in_proc 0 @@ -510,6 +529,8 @@ foreach router [lrange $argv $i end] { # look for noenable option in .cloginrc if { [find noenable $router] != "" } { set enable 0 + } else { + set enable $avenable } # Figure out passwords @@ -525,6 +546,9 @@ foreach router [lrange $argv $i end] { } set passwd [join [lindex $pswd 0] ""] set enapasswd [join [lindex $pswd 1] ""] + } else { + set passwd $userpasswd + set enapasswd $enapasswd } # Figure out username @@ -587,9 +611,9 @@ 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} } + # 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]} { diff --git a/bin/nsrancid.in b/bin/nsrancid.in index 40a286f..a74cce6 100644 --- a/bin/nsrancid.in +++ b/bin/nsrancid.in @@ -1,8 +1,9 @@ #! @PERLV_PATH@ ## -## $Id: nsrancid.in,v 1.7 2004/01/11 03:49:13 heas Exp $ +## $Id: nsrancid.in,v 1.14 2006/10/05 04:27:43 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -24,30 +25,34 @@ # # RANCID - Really Awesome New Cisco confIg Differ # -# usage: rancid [-d] [-l] [-f filename | $host] +# usage: rancid [-dV] [-l] [-f filename | hostname] # use Getopt::Std; -getopts('dfl'); +getopts('dflV'); +if ($opt_V) { + print "@PACKAGE@ @VERSION@\n"; + exit(0); +} $log = $opt_l; $debug = $opt_d; $file = $opt_f; $host = $ARGV[0]; $clean_run = 0; $found_end = 0; -$timeo = 90; # nslogin timeout in seconds +$timeo = 90; # nslogin timeout in seconds +my(@commandtable, %commands, @commands);# command lists +my(%filter_pwds); # password filtering mode @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) { + 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; } @@ -69,10 +74,10 @@ sub ProcessHistory { sub numerically { $a <=> $b; } -# This is a sort routing that will sort numerically on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort numerically keys(%lines)) { @@ -82,10 +87,10 @@ sub keynsort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort keys(%lines)) { @@ -95,10 +100,10 @@ sub keysort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort values %lines) { @@ -108,9 +113,9 @@ sub valsort{ @sorted_lines; } -# This is a numerical sort routing (ascending). +# This is a numerical sort routine (ascending). sub numsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $num (sort {$a <=> $b} keys %lines) { @@ -124,7 +129,7 @@ sub numsort { # ip address when the ip address is anywhere in # the strings. sub ipsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $addr (sort sortbyipaddr keys %lines) { @@ -137,7 +142,7 @@ sub ipsort { # 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])); + $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0])); } sub sortbyipaddr { &ipaddrval($a) <=> &ipaddrval($b); @@ -165,9 +170,9 @@ sub ShowConfig { } if (/exit$/) { - $found_end = 1; - $clean_run = 1; - return(1); + $found_end = 1; + $clean_run = 1; + return(1); } return(0); } @@ -205,20 +210,27 @@ sub RunCommand { 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" +@commandtable = ( + {'cat /etc/ns.conf' => 'ShowConfig'}, + {'get log setting' => 'GetLogSet'} ); +# Use an array to preserve the order of the commands and a hash for mapping +# commands to the subroutine and track commands that have been completed. +@commands = map(keys(%$_), @commandtable); +%commands = map(%$_, @commandtable); + $cisco_cmds=join(";",@commands); $cmds_regexp=join("|",@commands); +if (length($host) == 0) { + if ($file) { + print(STDERR "Too few arguments: file name required\n"); + exit(1); + } else { + print(STDERR "Too few arguments: host name required\n"); + exit(1); + } +} open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; select(OUTPUT); # make OUTPUT unbuffered if debugging @@ -261,7 +273,7 @@ TOP: while(<INPUT>) { # if ( (/netscaler#/) || $found_end ) { #print STDOUT "\n\nhere1\n"; -# $clean_run=1; +# $clean_run=1; # last; # } @@ -1,8 +1,9 @@ #! @PERLV_PATH@ ## -## $Id: par.in,v 1.10 2004/01/11 03:49:13 heas Exp $ +## $Id: par.in,v 1.14 2006/11/28 21:21:28 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -44,7 +45,11 @@ # line is assumed to be a command to be run. # use Getopt::Std; -getopts('p:n:l:c:fixedq'); +getopts('p:n:l:c:fixedqV'); +if ($opt_V) { + print "@PACKAGE@ @VERSION@\n"; + exit(0); +} $procs=$opt_n; $procs=3 if(!$procs); $command=$opt_c; #$command="{}" if(!$command); $parlog=$opt_l; $parlog="par.log.".time() if(!$parlog); @@ -59,7 +64,7 @@ if ($opt_q && ($opt_x || $opt_l)) { $signalled=0; -sub handler { +sub handler { $signalled++; print STDERR "Received signal - ending run ($signalled).\n"; if($signalled>1) { @@ -145,4 +150,4 @@ $procs=$i if ($i<$procs); while($procs) { $procs-- if(finish); } -print STDERR "Complete\n" if ($debug); +print STDERR "Complete\n" if ($debug); diff --git a/bin/prancid.in b/bin/prancid.in index 7ded178..4777675 100755 --- a/bin/prancid.in +++ b/bin/prancid.in @@ -1,8 +1,9 @@ #! @PERLV_PATH@ ## -## $Id: prancid.in,v 1.29 2004/01/11 03:49:13 heas Exp $ +## $Id: prancid.in,v 1.35 2006/10/05 04:27:43 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -23,26 +24,31 @@ # # RANCID - Really Awesome New Cisco confIg Differ # -# usage: rancid [-d] [-l] [-f filename | $host] +# usage: rancid [-dV] [-l] [-f filename | hostname] # use Getopt::Std; -getopts('dfl'); +getopts('dflV'); +if ($opt_V) { + print "@PACKAGE@ @VERSION@\n"; + exit(0); +} $log = $opt_l; $debug = $opt_d; $file = $opt_f; $host = $ARGV[0]; $clean_run = 0; $found_end = 0; -$timeo = 90; # clogin timeout in seconds +$timeo = 90; # clogin timeout in seconds -my($platform); # platform/cpu type -my(%filter_pwds); # password filtering mode +my(@commandtable, %commands, @commands);# command lists +my(%filter_pwds); # password filtering mode +my($platform); # platform/cpu type # 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) { + 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; } @@ -64,10 +70,10 @@ sub ProcessHistory { sub numerically { $a <=> $b; } -# This is a sort routing that will sort numerically on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort numerically keys(%lines)) { @@ -77,10 +83,10 @@ sub keynsort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort keys(%lines)) { @@ -90,10 +96,10 @@ sub keysort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort values %lines) { @@ -103,9 +109,9 @@ sub valsort{ @sorted_lines; } -# This is a numerical sort routing (ascending). +# This is a numerical sort routine (ascending). sub numsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $num (sort {$a <=> $b} keys %lines) { @@ -119,7 +125,7 @@ sub numsort { # ip address when the ip address is anywhere in # the strings. sub ipsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $addr (sort sortbyipaddr keys %lines) { @@ -132,7 +138,7 @@ sub ipsort { # 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])); + $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0])); } sub sortbyipaddr { &ipaddrval($a) <=> &ipaddrval($b); @@ -460,25 +466,30 @@ sub WriteTerm { 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" +@commandtable = ( + {'show version all' => 'ShowVersion'}, + {'show package' => 'ShowPackage'}, + {'show hardware' => 'ShowHardware'}, + {'show inventory' => 'ShowInventory'}, + {'write term' => 'WriteTerm'} ); +# Use an array to preserve the order of the commands and a hash for mapping +# commands to the subroutine and track commands that have been completed. +@commands = map(keys(%$_), @commandtable); +%commands = map(%$_, @commandtable); + $cisco_cmds=join(";",@commands); $cmds_regexp=join("|",@commands); +if (length($host) == 0) { + if ($file) { + print(STDERR "Too few arguments: file name required\n"); + exit(1); + } else { + print(STDERR "Too few arguments: host name required\n"); + exit(1); + } +} open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; select(OUTPUT); # make OUTPUT unbuffered if debugging diff --git a/bin/rancid-cvs.in b/bin/rancid-cvs.in index 22d5fd2..24d555a 100644 --- a/bin/rancid-cvs.in +++ b/bin/rancid-cvs.in @@ -1,8 +1,9 @@ #! /bin/sh ## -## $Id: rancid-cvs.in,v 1.16 2004/01/11 03:49:13 heas Exp $ +## $Id: rancid-cvs.in,v 1.19 2006/10/05 04:27:43 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -20,7 +21,7 @@ ## # # Create all of the misc files & dirs needed for each group and import them -# into CVS. +# into CVS or Subversion. # # rancid-cvs # @@ -28,6 +29,32 @@ # Read in the environment ENVFILE="@sysconfdir@/rancid.conf" +# print a usage message to stderr +pr_usage() { + echo "usage: $0 [-V] [group [group ...]]" >&2; +} + +# command-line options +# -V print version string +if [ $# -ge 1 ] ; then + while [ 1 ] ; do + case $1 in + -V) + echo "@PACKAGE@ @VERSION@" + exit 0 + ;; + -*) + echo "unknown option: $1" >&2 + pr_usage + exit 1 + ;; + *) + break; + ;; + esac + done +fi + . $ENVFILE # Base dir @@ -38,9 +65,20 @@ fi cd $BASEDIR +# RCS system +RCSSYS=${RCSSYS:=cvs}; +if [ $RCSSYS != "cvs" -a $RCSSYS != "svn" ] ; then + echo "$RCSSYS is not a valid value for RCSSYS." + exit 1 +fi + # Top level CVS stuff if [ ! -d $CVSROOT ]; then - cvs init + if [ $RCSSYS = cvs ]; then + cvs -d $CVSROOT init + else + svnadmin create $CVSROOT + fi fi # Log dir @@ -65,15 +103,21 @@ do if [ ! -d $DIR ]; then mkdir -p $DIR cd $DIR - cvs import -m "$GROUP" $GROUP new rancid - cd $BASEDIR - cvs co $GROUP + if [ $RCSSYS = cvs ]; then + cvs import -m "$GROUP" $GROUP new rancid + cd $BASEDIR + cvs checkout $GROUP + else + svn import -m "$GROUP" . file://$CVSROOT/$GROUP + cd $BASEDIR + svn checkout file://$CVSROOT/$GROUP $GROUP + fi fi cd $DIR if [ ! -d configs ]; then mkdir configs - cvs add configs - cvs commit -m 'new' configs + $RCSSYS add configs + $RCSSYS commit -m 'new' configs fi # main files @@ -88,7 +132,7 @@ do fi if [ ! -f router.db ]; then touch router.db - cvs add router.db - cvs commit -m 'new' router.db + $RCSSYS add router.db + $RCSSYS commit -m 'new' router.db fi done diff --git a/bin/rancid-fe.in b/bin/rancid-fe.in index b80a194..bed4129 100644 --- a/bin/rancid-fe.in +++ b/bin/rancid-fe.in @@ -1,8 +1,9 @@ #! @PERLV_PATH@ ## -## $Id: rancid-fe.in,v 1.36 2004/01/11 03:49:13 heas Exp $ +## $Id: rancid-fe.in,v 1.45 2007/01/13 22:01:53 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -19,7 +20,7 @@ ## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. ## # -# rancid-FE - front-end to rancid/jrancid/etc. for use with par. +# rancid-FE - front-end to rancid/jrancid/etc. for use with par. # # usage: rancid-fe <router>:<vendor> # @@ -27,32 +28,40 @@ require 5; ($router, $vendor) = split('\:', $ARGV[0]); +$vendor =~ tr/[A-Z]/[a-z]/; - 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 { +%vendortable = ( + 'agm' => 'agmrancid', + 'alteon' => 'arancid', + 'baynet' => 'brancid', + 'cat5' => 'cat5rancid', + 'cisco' => 'rancid', + 'css' => 'cssrancid', + 'enterasys' => 'rivrancid', + 'erx' => 'jerancid', + 'extreme' => 'xrancid', + 'ezt3' => 'erancid', + 'force10' => 'f10rancid', + 'foundry' => 'francid', + 'hitachi' => 'htrancid', + 'hp' => 'hrancid', + 'juniper' => 'jrancid', + 'mrtd' => 'mrancid', + 'netscaler' => 'nsrancid', + 'netscreen' => 'nrancid', + 'procket' => 'prancid', + 'redback' => 'rrancid', + 'riverstone' => 'rivrancid', + 'smc' => 'srancid', + 'tnt' => 'tntrancid', + 'zebra' => 'zrancid' +); + +if ($vendortable{$vendor} eq "") { printf(STDERR "unknown router manufacturer for $router: $vendor\n"); exit(-1); +} else { + exec($vendortable{$vendor} . " $router"); } printf(STDERR "exec failed router manufacturer $vendor: $!\n"); diff --git a/bin/rancid-run.in b/bin/rancid-run.in index b59b026..42e387a 100644 --- a/bin/rancid-run.in +++ b/bin/rancid-run.in @@ -1,8 +1,9 @@ #! /bin/sh ## -## $Id: rancid-run.in,v 1.28 2004/01/11 06:11:23 hank Exp $ +## $Id: rancid-run.in,v 1.35 2006/10/05 04:27:43 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -23,10 +24,9 @@ # @sysconfdir@/rancid.conf or those specified on the command-line. # +# Default ENVFILE, overrideable with -f flag. ENVFILE="@sysconfdir@/rancid.conf" -. $ENVFILE - TMPDIR=${TMPDIR:=/tmp}; export TMPDIR # control_rancid argv @@ -34,19 +34,30 @@ 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; + echo "usage: $0 [-V] [-f config_file] [-r device_name] [-m mail rcpt] [group [group ...]]" >&2; } # command-line options +# -V +# -f <config file name> +# -m <mailto address> # -r <device name> if [ $# -ge 1 ] ; then while [ 1 ] ; do case $1 in - -r) + -V) + echo "@PACKAGE@ @VERSION@" + exit 0 + ;; + -f) shift - # next arg is the device name - CR_ARGV="$CR_ARGV -r $1"; export CR_ARGV + # next arg is the alternate config file name + ENVFILE="$1" + if [ -z $ENVFILE ]; then + pr_usage + exit 1 + fi shift ;; -m) @@ -55,6 +66,12 @@ if [ $# -ge 1 ] ; then CR_ARGV="$CR_ARGV -m $1"; export CR_ARGV shift ;; + -r) + shift + # next arg is the device name + CR_ARGV="$CR_ARGV -r $1"; export CR_ARGV + shift + ;; --) shift; break; ;; @@ -74,6 +91,9 @@ if [ $# -ge 1 ] ; then done fi +. $ENVFILE + + if [ $# -ge 1 ] ; then LIST_OF_GROUPS="$*"; export LIST_OF_GROUPS elif [ "$LIST_OF_GROUPS" = "" ] ; then @@ -88,49 +108,48 @@ 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 <<END + 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}${MAILDOMAIN}" + echo "Subject: rancid hung - $GROUP" + echo "Precedence: bulk" + echo "" + + cat <<END rancid $GROUP hung on `hostname`? Old lockfile still exists: `ls -l $LOCKFILE` END - ) | sendmail -t - fi - rm -f $TMPDIR/.$GROUP.old - - else - trap 'rm -fr $LOCKFILE;exit 1' 1 2 3 6 10 15 - touch $LOCKFILE - if [ $? -eq 0 ] ; then - control_rancid $CR_ARGV $GROUP - rm -f $LOCKFILE - fi - trap '' 1 2 3 6 10 15 - fi - - echo - echo ending: `date` - ) >$LOGDIR/$GROUP.`date +%Y%m%d.%H%M%S` 2>&1 + ) | sendmail -t + fi + rm -f $TMPDIR/.$GROUP.old + else + trap 'rm -fr $LOCKFILE;exit 1' 1 2 3 6 10 15 + touch $LOCKFILE + if [ $? -eq 0 ] ; then + control_rancid $CR_ARGV $GROUP + rm -f $LOCKFILE + fi + trap '' 1 2 3 6 10 15 + fi + + echo + echo ending: `date` + ) >$LOGDIR/$GROUP.`date +%Y%m%d.%H%M%S` 2>&1 done diff --git a/bin/rancid.in b/bin/rancid.in index 27a5a48..4b5b12a 100644 --- a/bin/rancid.in +++ b/bin/rancid.in @@ -1,8 +1,9 @@ #! @PERLV_PATH@ ## -## $Id: rancid.in,v 1.168 2004/01/12 00:52:47 asp Exp $ +## $Id: rancid.in,v 1.218 2006/10/05 04:27:43 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -21,25 +22,33 @@ # # RANCID - Really Awesome New Cisco confIg Differ # -# usage: rancid [-d] [-l] [-f filename | $host] +# usage: rancid [-dV] [-l] [-f filename | hostname] # use Getopt::Std; -getopts('dfl'); +getopts('dflV'); +if ($opt_V) { + print "@PACKAGE@ @VERSION@\n"; + exit(0); +} $log = $opt_l; $debug = $opt_d; $file = $opt_f; $host = $ARGV[0]; $clean_run = 0; $found_end = 0; -$timeo = 90; # clogin timeout in seconds +$found_version = 0; +$found_env = 0; +$found_diag = 0; +$timeo = 90; # clogin timeout in seconds -my(%filter_pwds); # password filtering mode +my(@commandtable, %commands, @commands);# command lists +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) { + 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; } @@ -61,10 +70,10 @@ sub ProcessHistory { sub numerically { $a <=> $b; } -# This is a sort routing that will sort numerically on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort numerically keys(%lines)) { @@ -74,10 +83,10 @@ sub keynsort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort keys(%lines)) { @@ -87,10 +96,10 @@ sub keysort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort values %lines) { @@ -100,9 +109,9 @@ sub valsort{ @sorted_lines; } -# This is a numerical sort routing (ascending). +# This is a numerical sort routine (ascending). sub numsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $num (sort {$a <=> $b} keys %lines) { @@ -116,7 +125,7 @@ sub numsort { # ip address when the ip address is anywhere in # the strings. sub ipsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $addr (sort sortbyipaddr keys %lines) { @@ -129,7 +138,7 @@ sub ipsort { # 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])); + $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0])); } sub sortbyipaddr { &ipaddrval($a) <=> &ipaddrval($b); @@ -142,11 +151,18 @@ sub ShowVersion { while (<INPUT>) { tr/\015//d; - last if(/^$prompt/); - next if(/^(\s*|\s*$cmd\s*)$/); + if (/^$prompt/) { $found_version=1; last}; + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; return(-1) if (/command authorization failed/i); + return(0) if ($found_version); # Only do this routine once # the pager can not be disabled per-session on the PIX - s/^<-+ More -+>\s*//; + if (/^(<-+ More -+>)/) { + my($len) = length($1); + s/^$1\s{$len}//; + } + if (/^Slave in slot (\d+) is running/) { $slave = " Slave:"; $slaveslot = ", slot $1"; @@ -157,10 +173,11 @@ sub ShowVersion { ProcessHistory("COMMENTS","keysort","F1", "!Image: $_") && next; /^Cisco Secure PIX /i && ProcessHistory("COMMENTS","keysort","F1", "!Image: $_") && next; - # PIX fail-over license - /^This PIX has an?\s+(.*)$/ && - ProcessHistory("COMMENTS","keysort","C1", "!$_") && next; - /^(Cisco )?IOS .* Software,? \(([A-Za-z-0-9]*)\), .*Version\s+(.*)$/ && + # PIX 6 fail-over license, as in "This PIX has an Unrestricted (UR) + # license." PIX 7 as "his platform has ..." + /^This (PIX|platform) has an?\s+(.*)$/ && + ProcessHistory("COMMENTS","keysort","D1", "!$_") && next; + /^(Cisco )?IOS .* Software,? \(([A-Za-z-0-9_]*)\), .*Version\s+(.*)$/ && ProcessHistory("COMMENTS","keysort","F1", "!Image:$slave Software: $2, $3\n") && next; /^([A-Za-z-0-9_]*) Synced to mainline version: (.*)$/ && @@ -181,6 +198,17 @@ sub ShowVersion { } /^Serial Number:\s+(.*)$/ && ProcessHistory("COMMENTS","keysort","C1", "!$_") && next; + # More PIX stuff + /^Encryption hardware device\s+:\s+(.*)/ && + ProcessHistory("COMMENTS","keysort","A3", "!Encryption: $1\n") && + next; + /^running activation key\s*:\s+(.*)/i && + ProcessHistory("COMMENTS","keysort","D2", "!Key: $1\n") && + next; + # Flash on the PIX or FWSM (FireWall Switch Module) + /^Flash(\s+\S+)+ \@ 0x\S+,\s+(\S+)/ && + ProcessHistory("COMMENTS","keysort","B2", "!Memory: Flash $2\n") && + next; # CatOS 3500xl stuff /^System serial number(:\s+.*)$/ && ProcessHistory("COMMENTS","keysort","C1", "!Serial Number$1\n") && @@ -211,7 +239,7 @@ sub ShowVersion { next; /^System image file is "([^\"]*)"$/ && ProcessHistory("COMMENTS","keysort","F5","!Image: $1\n") && next; - if (/(\S+)\s+\((\S+)\)\s+processor.*with (\S+[kK]) bytes/) { + if (/(\S+)\s+(?:\((\S+)\)\s+processor|\(revision[^)]+\)).*\s+with (\S+k) bytes/i) { my($proc) = $1; my($cpu) = $2; my($mem) = $3; @@ -225,7 +253,17 @@ sub ShowVersion { # incantations. for a slave, we dont get this info and its just a # blank line. $_ = <INPUT>; - $_ = <INPUT> if (/processor board id/i); + if (/processor board id/i) { + my($sn); + + if (/processor board id (\S+)/i) { + $sn = $1; + $sn =~ s/,$//; + ProcessHistory("COMMENTS","keysort","D9", + "!Processor ID: $sn\n"); + } + $_ = <INPUT>; + } $_ = "" if (! /(cpu at |processor: |$cpu processor,)/i); tr/\015//d; s/implementation/impl/i; @@ -234,53 +272,57 @@ sub ShowVersion { s/^/, /; } - if ( $proc eq "CSC") { + if ($proc eq "CSC") { $type = "AGS"; - } elsif ( $proc eq "CSC4") { + } elsif ($proc eq "CSC4") { $type = "AGS+"; - } elsif ( $proc =~ /^(AS)?25[12][12]/) { + } elsif ($proc =~ /^(AS)?25[12][12]/) { $type = "2500"; - } elsif ( $proc =~ /261[01]/ || $proc =~ /262[01]/ ) { + } elsif ($proc =~ /261[01]/ || $proc =~ /262[01]/ ) { $type = "2600"; - } elsif ( $proc =~ /^36[0246][0-9]/) { + } elsif ($proc =~ /^36[0246][0-9]/) { $type = "3600"; - } elsif ( $proc =~ /^37/) { + } elsif ($proc =~ /^37/) { $type = "3700"; - } elsif ( $proc eq "RSP7000") { + } elsif ($proc =~ /^38/) { + $type = "3800"; + } elsif ($proc eq "RSP7000") { $type = "7500"; - } elsif ( $proc =~ /RSP\d/) { + } elsif ($proc =~ /RSP\d/) { $type = "7500"; - } elsif ( $proc eq "RP1") { + } elsif ($proc eq "RP1") { $type = "7000"; - } elsif ( $proc eq "RP") { + } elsif ($proc eq "RP") { $type = "7000"; - } elsif ( $proc =~ /720[246]/) { + } elsif ($proc =~ /720[246]/) { $type = "7200"; - } elsif ( $proc =~ /1200[48]\/GRP/ || $proc =~ /1201[26]\/GRP/) { + } elsif ($proc =~ /1200[48]\/GRP/ || $proc =~ /1201[26]\/GRP/) { $type = "12000"; - } elsif ( $proc =~ /1201[26]-8R\/GRP/) { + } elsif ($proc =~ /1201[26]-8R\/GRP/) { $type = "12000"; - } elsif ( $proc =~ /WS-C29/) { + } elsif ($proc =~ /WS-C29/) { $type = "2900XL"; $device = "switch"; - } elsif ( $proc =~ /WS-C355/) { + } elsif ($proc =~ /WS-C355/) { $type = "3550"; $device = "switch"; - } elsif ( $proc =~ /WS-C35/) { + } elsif ($proc =~ /WS-C35/) { $type = "3500XL"; $device = "switch"; - } elsif ( $proc =~ /WS-C45/) { + } elsif ($proc =~ /WS-C45/) { $type = "4500"; $device = "switch"; - } elsif ( $proc =~ /6000/) { + } elsif ($proc =~ /6000/) { $type = "6000"; $device = "switch"; - } elsif ( $proc =~ /CISCO76/) { + } elsif ($proc =~ /CISCO76/) { $type = "7600"; $device = "router"; - } elsif ( $proc =~ /1900/) { + } elsif ($proc =~ /1900/) { $type = "1900"; $device = "switch"; + } elsif ( $proc =~ /^73/) { + $type = "7300"; } else { $type = $proc; } @@ -289,7 +331,10 @@ sub ShowVersion { "!Chassis type:$slave $proc - a $type $device\n"); ProcessHistory("COMMENTS","keysort","B1", "!Memory:$slave main $mem\n"); - ProcessHistory("COMMENTS","keysort","A3","!CPU:$slave $cpu$_$slaveslot\n"); + if (defined($cpu)) { + ProcessHistory("COMMENTS","keysort","A3", + "!CPU:$slave $cpu$_$slaveslot\n"); + } next; } if (/(\S+) Silicon\s*Switch Processor/) { @@ -316,12 +361,12 @@ sub ShowVersion { /^(\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) { + 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 (/^WARNING/) { if (!defined($I0)) { $I0=1; ProcessHistory("COMMENTS","keysort","I0","!\n"); @@ -332,6 +377,10 @@ sub ShowVersion { $config_register=$1; next; } + if (/^Configuration register on node \S+ is (.*)$/) { + $config_register=$1 if $config_register eq ""; + next; + } } return(0); } @@ -342,12 +391,17 @@ sub ShowRedundancy { while (<INPUT>) { tr/\015//d; - last if(/^$prompt/); - next if(/^(\s*|\s*$cmd\s*)$/); + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; # the pager can not be disabled per-session on the PIX - s/^<-+ More -+>\s*//; + if (/^(<-+ More -+>)/) { + my($len) = length($1); + s/^$1\s{$len}//; + } - /^IOS .* Software \(([A-Za-z-0-9]*)\), .*Version\s+(.*)$/ && + /^IOS .* Software \(([A-Za-z-0-9_]*)\), .*Version\s+(.*)$/ && ProcessHistory("COMMENTS","keysort","F1", "!Image:$slave Software: $1, $2\n") && next; /^Compiled (.*)$/ && @@ -365,14 +419,18 @@ sub ShowIDprom { while (<INPUT>) { tr/\015//d; - last if(/^$prompt/); - next if(/^(\s*|\s*$cmd\s*)$/); + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; # the pager can not be disabled per-session on the PIX - s/^<-+ More -+>\s*//; + if (/^(<-+ More -+>)/) { + my($len) = length($1); + s/^$1\s{$len}//; + } /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]+)/ && @@ -396,10 +454,15 @@ sub ShowInstallActive { last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); return(1) if /^\s*\^\s*$/; + return(1) if /Line has invalid autocommand /; 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*//; + if (/^(<-+ More -+>)/) { + my($len) = length($1); + s/^$1\s{$len}//; + } + ProcessHistory("COMMENTS","keysort","F5","!Image: $_") && next; } return(0); @@ -412,12 +475,19 @@ sub ShowEnv { while (<INPUT>) { tr/\015//d; - last if (/^$prompt/); + if (/^$prompt/) { $found_env=1; last}; next if (/^(\s*|\s*$cmd\s*)$/); #return(1) if ($type !~ /^7/); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; return(-1) if (/command authorization failed/i); + return(0) if ($found_env); # Only do this routine once # the pager can not be disabled per-session on the PIX - s/^<-+ More -+>\s*//; + if (/^(<-+ More -+>)/) { + my($len) = length($1); + s/^$1\s{$len}//; + } + if (!defined($E0)) { $E0=1; ProcessHistory("COMMENTS","keysort","E0","!\n"); @@ -432,6 +502,8 @@ sub ShowEnv { "!Chassis type: $2 backplane\n"); next; } + /^Power Supply Information$/ && next; + /^\s*Power Module\s+Voltage\s+Current$/ && next; /^\s*(Power [^:\n]+)$/ && ProcessHistory("COMMENTS","keysort","E1","!Power: $1\n") && next; /^\s*(Lower Power .*)/i && @@ -457,11 +529,13 @@ sub ShowRSP { 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*//; + if (/^(<-+ More -+>)/) { + my($len) = length($1); + s/^$1\s{$len}//; + } /^$/ && next; /^\s+Chassis model: (\S+)/ && - ProcessHistory("COMMENTS","keysort","D0","!\n") && ProcessHistory("COMMENTS","keysort","D1", "!RSP Chassis model: $1\n") && next; @@ -487,10 +561,13 @@ sub ShowGSR { 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*//; + if (/^(<-+ More -+>)/) { + my($len) = length($1); + s/^$1\s{$len}//; + } /^$/ && next; + /^\s+Chassis: type (\S+) Fab Ver: (\S+)/ && - ProcessHistory("COMMENTS","keysort","D0","!\n") && ProcessHistory("COMMENTS","keysort","D1", "!GSR Chassis type: $1 Fab Ver: $2\n") && next; @@ -522,12 +599,17 @@ sub ShowBoot { 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 /Line has invalid autocommand /; return(1) if /(Invalid input detected|Type help or )/; + return(1) if /Ambiguous command/i; return(1) if /(Open device \S+ failed|Error opening \S+:)/; + return(-1) if (/command authorization failed/i); # the pager can not be disabled per-session on the PIX - s/^<-+ More -+>\s*//; + if (/^(<-+ More -+>)/) { + my($len) = length($1); + s/^$1\s{$len}//; + } + next if /CONFGEN variable/; if (!defined($H0)) { $H0=1; ProcessHistory("COMMENTS","keysort","H0","!\n"); @@ -557,11 +639,17 @@ sub ShowFlash { last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); return(1) if ($type =~ /^(12[40]|7)/); - return(-1) if (/command authorization failed/i); return(1) if /^\s*\^\s*$/; + return(1) if /Line has invalid autocommand /; 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*//; + if (/^(<-+ More -+>)/) { + my($len) = length($1); + s/^$1\s{$len}//; + } + + /\s+(multiple-fs|nv_hdr|vlan\.dat)$/ && next; ProcessHistory("FLASH","","","!Flash: $_"); } ProcessHistory("","","","!\n"); @@ -581,6 +669,7 @@ sub DirSlotN { next if (/^(\s*|\s*$cmd\s*)$/); # return(1) if ($type !~ /^(12[40]|7|36)/); return(1) if /^\s*\^\s*$/; + return(1) if /Line has invalid autocommand /; return(1) if /(Invalid input detected|Type help or )/; return(1) if /(No such device|Error Sending Request)/i; return(1) if /\%Error: No such file or directory/; @@ -590,7 +679,11 @@ sub DirSlotN { 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*//; + if (/^(<-+ More -+>)/) { + my($len) = length($1); + s/^$1\s{$len}//; + } + ProcessHistory("FLASH","","","!Flash: $dev: $_"); } ProcessHistory("","","","!\n"); @@ -609,7 +702,11 @@ sub ShowContAll { # 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 (/^(<-+ More -+>)/) { + my($len) = length($1); + s/^$1\s{$len}//; + } + if (/^Interface ([^ \n(]*)/) { $INT = "$1, "; next; } /^(BRI unit \d)/ && ProcessHistory("INT","","","!Interface: $1\n") && next; @@ -669,7 +766,11 @@ sub ShowContCbus { #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 (/^(<-+ More -+>)/) { + my($len) = length($1); + s/^$1\s{$len}//; + } + if (/^\s*slot(\d+): ([^,]+), hw (\S+), sw (\S+), ccb/) { $slot = $1; $board{$slot} = $2; @@ -703,6 +804,34 @@ sub ShowContCbus { return(0); } +# This routine parses "show debug" +sub ShowDebug { + print STDERR " In ShowDebug: $_" if ($debug); + my($lines) = 0; + + while (<INPUT>) { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /Line has invalid autocommand /; + 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 + if (/^(<-+ More -+>)/) { + my($len) = length($1); + s/^$1\s{$len}//; + } + + /^No matching debug flags set$/ && next; + ProcessHistory("COMMENTS","keysort","J1","!DEBUG: $_"); + $lines++; + } + if ($lines) { + ProcessHistory("COMMENTS","keysort","J0","!\n"); + } + return(0); +} + # This routine parses "show diagbus" # This will create arrarys for hw info. sub ShowDiagbus { @@ -714,9 +843,15 @@ sub ShowDiagbus { last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); #return(1) if ($type !~ /^7[05]/); + return(1) if /Line has invalid autocommand /; + 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*//; + if (/^(<-+ More -+>)/) { + my($len) = length($1); + s/^$1\s{$len}//; + } + if (/^\s*Slot (\d+):/i) { $slot = $1; next; @@ -798,14 +933,20 @@ sub ShowDiag { print STDERR " In ShowDiag: $_" if ($debug); while (<INPUT>) { - tr/\015//d; - last if (/^$prompt/); +REDUX: tr/\015//d; + if (/^$prompt/) { $found_diag=1; last}; next if (/^(\s*|\s*$cmd\s*)$/); # return(1) if ($type !~ /^(12[40]|720|36|26)/); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; return(-1) if (/command authorization failed/i); + return(0) if ($found_diag); # Only do this routine once /^$/ && next; # the pager can not be disabled per-session on the PIX - s/^<-+ More -+>\s*//; + if (/^(<-+ More -+>)/) { + my($len) = length($1); + s/^$1\s{$len}//; + } s/Port Packet Over SONET/POS/; if (/^\s*SLOT\s+(\d+)\s+\((.*)\): (.*)/) { @@ -814,8 +955,59 @@ sub ShowDiag { ProcessHistory("SLOT","keysort","A","!Slot $slot: $3\n"); next; } - if (/^\s+MAIN:\s* type \d+,\s+(.*)/) { - ProcessHistory("SLOT","keysort","AM","!Slot $slot/MAIN: part $1\n"); + if (/^\s*NODE\s+(\S+) : (.*)/) { + $slot = $1; + ProcessHistory("SLOT","","","!\n"); + ProcessHistory("SLOT","keysort","A","!Slot $slot: $2\n"); + next; + } + if (/^\s*PLIM\s+(\S+) : (.*)/) { + $slot = $1 . " PLIM"; + ProcessHistory("SLOT","","","!\n"); + ProcessHistory("SLOT","keysort","A","!Slot $slot: $2\n"); + next; + } + if (/^\s*RACK\s+(\S+) : (.*)/) { + $slot = "Rack/" . $1; + ProcessHistory("SLOT","","","!\n"); + ProcessHistory("SLOT","keysort","A","!Slot $slot: $2\n"); + next; + } + if (/^\s+MAIN:\s* type \S+,\s+(.*)/) { + local($part) = $1; + $_ = <INPUT>; + if (/^\s+(HW version|Design Release) (\S+)\s+S\/N (\S+)/i) { + ProcessHistory("SLOT","keysort","AM","!Slot $slot/MAIN: part $part, serial $3\n"); + ProcessHistory("SLOT","keysort","AM","!Slot $slot/MAIN: hvers $2\n"); + } else { + ProcessHistory("SLOT","keysort","AM","!Slot $slot/MAIN: part $part\n"); + goto REDUX; + } + next; + } + if (/^\s+MAIN:\s* board type \S+$/) { + $_ = <INPUT>; + tr/\015//d; + if (/^\s+(.+)$/) { + local($part) = $1; + $_ = <INPUT>; + tr/\015//d; + if (/^\s+dev (.*)$/) { + local($dev) = $1; + $_ = <INPUT>; + if (/^\s+S\/N (\S+)/) { + ProcessHistory("SLOT","keysort","AM","!Slot $slot/MAIN: part $part, dev $dev, serial $1\n"); + } else { + ProcessHistory("SLOT","keysort","AM","!Slot $slot/MAIN: part $part, dev $dev\n"); + goto REDUX; + } + } else { + ProcessHistory("SLOT","keysort","AM","!Slot $slot/MAIN: part $part\n"); + goto REDUX; + } + } else { + goto REDUX; + } next; } if (/^c3700\s+(io-board|mid-plane)/i) { @@ -831,12 +1023,24 @@ sub ShowDiag { ProcessHistory("SLOT","keysort","AF","!Slot $slot/FRU: Linecard/Module: $1\n"); next; } + if (/\s+Processor Memory:\s+(\S+)/) { + ProcessHistory("SLOT","keysort","AF","!Slot $slot/FRU: Processor Memory: $1\n"); + next; + } + if (/\s+Packet Memory:\s+(\S+)/) { + ProcessHistory("SLOT","keysort","AF","!Slot $slot/FRU: Packet Memory: $1\n"); + next; + } if (/^\s+PCA:\s+(.*)/) { local($part) = $1; $_ = <INPUT>; - /^\s+(HW version|design release) (\S+)\s+S\/N (\S+)/i && - ProcessHistory("SLOT","keysort","C1","!Slot $slot/PCA: part $part, serial $3\n") && + if (/^\s+(HW version|design release) (\S+)\s+S\/N (\S+)/i) { + ProcessHistory("SLOT","keysort","C1","!Slot $slot/PCA: part $part, serial $3\n"); ProcessHistory("SLOT","keysort","C2","!Slot $slot/PCA: hvers $2\n"); + } else { + ProcessHistory("SLOT","keysort","C1","!Slot $slot/PCA: part $part\n"); + goto REDUX; + } next; } if (/^\s+MBUS: .*\)\s+(.*)/) { @@ -851,10 +1055,22 @@ sub ShowDiag { ProcessHistory("SLOT","keysort","MB3","!Slot $slot/MBUS: software $1\n"); next; } + if (/^\s+PLD: (.*)/) { + ProcessHistory("SLOT","keysort","P","!Slot $slot/PLD: $1\n"); + next; + } + if (/^\s+MONLIB: (.*)/) { + ProcessHistory("SLOT","keysort","Q","!Slot $slot/MONLIB: $1\n"); + next; + } if (/^\s+ROM Monitor version (.*)/) { ProcessHistory("SLOT","keysort","R","!Slot $slot/ROM Monitor: version $1\n"); next; } + if (/^\s+ROMMON: Version (.*)/) { + ProcessHistory("SLOT","keysort","R","!Slot $slot/ROMMON: version $1\n"); + next; + } if (/^\s+Fabric Downloader version used (.*)/) { ProcessHistory("SLOT","keysort","Z","!Slot $slot/Fabric Downloader: version $1\n"); next; @@ -867,6 +1083,7 @@ sub ShowDiag { . $1 / 1024 . " Kbytes SDRAM\n"); } else { ProcessHistory("SLOT","keysort","MB4","!Slot $slot/MBUS: $dram Mbytes DRAM\n"); + goto REDUX; } next; } @@ -880,6 +1097,8 @@ sub ShowDiag { $WIC = "/$2"; } elsif ($1 eq "WIC/VIC") { $WIC = "/$2"; + } elsif ($1 eq "DSP") { + $WIC = "/$2"; } elsif ($1 eq "Encryption AIM") { $slot = "$2"; undef($WIC); @@ -915,6 +1134,15 @@ sub ShowDiag { ProcessHistory("SLOT","keysort","B","!Slot $slot$WIC: type $_"); } next; + } elsif (/^\s+(.* (DSP) Module) Slot (\d):/) { + # The 1760 (at least) has yet another format...where it has two + # dedicated DSP slots, and thus two slot 0s. + my($TYPE) = $1; + $WIC = "/$3"; + ProcessHistory("SLOT","","","!\n"); + ProcessHistory("SLOT","keysort","B", + "!Slot $slot$WIC: type $TYPE\n"); + 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 @@ -929,7 +1157,7 @@ sub ShowDiag { while (<INPUT>) { tr/\015//d; - if (/0x..: /) { + if (/0x..: / || /^$/) { # no effing idea why break does not work there goto PerlSucks; } @@ -953,32 +1181,87 @@ PerlSucks: return(0); } +# This routine parses "show inventory". +sub ShowInventory { + print STDERR " In ShowInventory: $_" if ($debug); + + while (<INPUT>) { + tr/\015//d; + return if (/^\s*\^$/); + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /Line has invalid autocommand /; + 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 + if (/^(<-+ More -+>)/) { + my($len) = length($1); + s/^$1\s{$len}//; + } + + if (/^(NAME: "[^"]*",) (DESCR: "[^"]+")/) { + ProcessHistory("INVENTORY","","", sprintf("!%-30s %s\n", $1, $2)); + next; + } + # split PID/VID/SN line + if (/^PID: (\S*)\s*, VID: (\S*)\s*, SN: (\S*)\s*$/) { + my($entries) = ""; + $entries .= "!PID: $1\n" if ($1); + $entries .= "!VID: $2\n" if ($2); + $entries .= "!SN: $3\n" if ($3); + ProcessHistory("INVENTORY","","", "$entries"); + next; + } + ProcessHistory("INVENTORY","","","!$_"); + } + ProcessHistory("INVENTORY","","","!\n"); + + return(0); +} + # This routine parses "show module". sub ShowModule { print STDERR " In ShowModule: $_" if ($debug); my(@lines); - my($slot); + my($slot, $pa); while (<INPUT>) { tr/\015//d; return if (/^\s*\^$/); + last if (/online diag status/i); 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 (/^(<-+ More -+>)/) { + my($len) = length($1); + s/^$1\s{$len}//; + } # match slot/card info line if (/^ *(\d+)\s+(\d+)\s+(.*)\s+(\S+)\s+(\S+)\s*$/) { - $lines[$1] .= "!Slot $1: type $3, $2 ports\n!Slot $1: part $4, serial $5\n"; - $lines[$1] =~ s/\s+,/,/g; + $lines[$1 * 1000] .= "!Slot $1: type $3, $2 ports\n!Slot $1: part $4, serial $5\n"; + $lines[$1 * 1000] =~ s/\s+,/,/g; + next; } # now match the Revs in the second paragraph of o/p and stick it in # the array with the previous bits...grumble. if (/^ *(\d+)\s+\S+\s+to\s+\S+\s+(\S+)\s+(\S*)\s+(\S+)(\s+\S+)?\s*$/) { - $lines[$1] .= "!Slot $1: hvers $2, firmware $3, sw $4\n"; - $lines[$1] =~ s/\s+,/,/g; + $lines[$1 * 1000] .= "!Slot $1: hvers $2, firmware $3, sw $4\n"; + $lines[$1 * 1000] =~ s/\s+,/,/g; + next; + } + # grab the sub-modules, if any + if (/^\s+(\d+)\s(.*)\s+(\S+)\s+(\S+)\s+(\S+)\s+\S+\s*$/) { + my($idx); + $pa = 0 if ($1 != $slot); + $slot = $1; + $idx = $1 * 1000 + $1 * 10 + $pa; + $lines[$idx] .= "!Slot $1/$pa: type $2\n"; + $lines[$idx] .= "!Slot $slot/$pa: part $3, serial $4\n"; + $lines[$idx] .= "!Slot $slot/$pa: hvers $5\n"; + $pa++; } } foreach $slot (@lines) { @@ -998,6 +1281,7 @@ sub ShowSpeVersion { last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); return(1) if /^\s*\^\s*$/; + return(1) if /Line has invalid autocommand /; return(1) if /(Invalid input detected|Type help or )/; return(-1) if (/command authorization failed/i); @@ -1021,7 +1305,11 @@ sub ShowC7200 { return(-1) if (/command authorization failed/i); /^$/ && next; # the pager can not be disabled per-session on the PIX - s/^<-+ More -+>\s*//; + if (/^(<-+ More -+>)/) { + my($len) = length($1); + s/^$1\s{$len}//; + } + if (/^(C7200 )?Midplane EEPROM:/) { $_ = <INPUT>; /revision\s+(\S+).*revision\s+(\S+)/; @@ -1062,12 +1350,17 @@ sub ShowVTP { last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); return(1) if /^\s*\^\s*$/; + return(1) if /Line has invalid autocommand /; return(1) if /(Invalid input detected|Type help or )/; #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 (/^(<-+ More -+>)/) { + my($len) = length($1); + s/^$1\s{$len}//; + } + if (/^VTP Operating Mode\s+:\s+(Transparent|Server)/) { $DO_SHOW_VLAN = 1; } @@ -1087,14 +1380,21 @@ sub ShowVLAN { tr/\015//d; last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^\s*\^\s*$/; + return(1) if /Line has invalid autocommand /; return(1) if /(Invalid input detected|Type help or )/; + return(1) if /Ambiguous command/i; # 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*//; + if (/^(<-+ More -+>)/) { + my($len) = length($1); + s/^$1\s{$len}//; + } + ProcessHistory("COMMENTS","keysort","IO","!VLAN: $_"); } ProcessHistory("COMMENTS","keysort","IO","!\n"); @@ -1108,10 +1408,16 @@ sub WriteTerm { while (<INPUT>) { tr/\015//d; - last if(/^$prompt/); + last if (/^$prompt/); + return(1) if /Line has invalid autocommand /; + return(1) if (/(Invalid input detected|Type help or )/i); return(-1) if (/command authorization failed/i); # the pager can not be disabled per-session on the PIX - s/^<-+ More -+>\s*//; + if (/^(<-+ More -+>)/) { + my($len) = length($1); + s/^$1\s{$len}//; + } + /Non-Volatile memory is in use/ && return(-1); # NvRAM is locked return(0) if ($found_end); # Only do this routine once $linecnt++; @@ -1152,8 +1458,8 @@ sub WriteTerm { $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 <removed>\n"); + if (/^(enable )?(password|passwd)( level \d+)? / && $filter_pwds >= 1) { + ProcessHistory("ENABLE","","","!$1$2$3 <removed>\n"); next; } if (/^(enable secret) / && $filter_pwds >= 2) { @@ -1169,15 +1475,24 @@ sub WriteTerm { next; } if (/^username (\S+)(\s.*)? password ((\d) \S+|\S+)/) { - if ($filter_pwds == 2) { + if ($filter_pwds >= 2) { ProcessHistory("USER","keysort","$1","!username $1$2 password <removed>\n"); - } elsif ($filter_pwds == 1 && $4 ne "5"){ + } elsif ($filter_pwds >= 1 && $4 ne "5"){ ProcessHistory("USER","keysort","$1","!username $1$2 password <removed>\n"); } else { ProcessHistory("USER","keysort","$1","$_"); } next; } + # cisco AP w/ IOS + if (/^(wlccp \S+ username (\S+)(\s.*)? password) (\d \S+|\S+)/) { + if ($filter_pwds >= 1) { + ProcessHistory("USER","keysort","$2","!$1 <removed>\n"); + } else { + ProcessHistory("USER","keysort","$2","$_"); + } + next; + } if (/^( set session-key (in|out)bound ah \d+ )/ && $filter_pwds >= 1) { ProcessHistory("","","","!$1<removed>\n"); next; @@ -1190,6 +1505,10 @@ sub WriteTerm { ProcessHistory("LINE-PASS","","","!$1password <removed>\n"); next; } + if (/^(\s*)secret / && $filter_pwds >= 2) { + ProcessHistory("LINE-PASS","","","!$1secret <removed>\n"); + next; + } if (/^\s*neighbor (\S*) password / && $filter_pwds >= 1) { ProcessHistory("","","","! neighbor $1 password <removed>\n"); next; @@ -1215,11 +1534,15 @@ sub WriteTerm { if (/^( ip ospf message-digest-key \d+ md5) / && $filter_pwds >= 1) { ProcessHistory("","","","!$1 <removed>\n"); next; } + # this is also reversable, despite 'md5 encrypted' in the cmd + if (/^( message-digest-key \d+ md5 (7|encrypted)) / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 <removed>\n"); next; + } if (/^((crypto )?isakmp key) \S+ / && $filter_pwds >= 1) { ProcessHistory("","","","!$1 <removed> $'"); next; } # filter HSRP passwords - if (/^(\s+standby \d authentication) / && $filter_pwds >= 1) { + if (/^(\s+standby \d+ authentication) / && $filter_pwds >= 1) { ProcessHistory("","","","!$1 <removed>\n"); next; } # this appears in "measurement/sla" images @@ -1230,10 +1553,15 @@ sub WriteTerm { ProcessHistory("","","","!$1 <removed>\n"); next; } # i am told these are plain-text on the PIX - if (/^(vpdn username \S+ password)/ && $filter_pwds >= 1) { - ProcessHistory("","","","!$1 <removed>\n"); next; + if (/^(vpdn username (\S+) password)/) { + if ($filter_pwds >= 1) { + ProcessHistory("USER","keysort","$2","!$1 <removed>\n"); + } else { + ProcessHistory("USER","keysort","$2","$_"); + } + next; } - if (/^( cable shared-secret ) / && $filter_pwds >= 1) { + if (/^( cable shared-secret )/ && $filter_pwds >= 1) { ProcessHistory("","","","!$1 <removed>\n"); next; } @@ -1306,6 +1634,11 @@ sub WriteTerm { while ($token = shift(@tokens)) { if ($token eq 'version') { $line .= " " . join(' ', ($token, shift(@tokens))); + if ($token eq '3') { + $line .= " " . join(' ', ($token, shift(@tokens))); + } + } elsif ($token eq 'vrf') { + $line .= " " . join(' ', ($token, shift(@tokens))); } elsif ($token =~ /^(informs?|traps?|(no)?auth)$/) { $line .= " " . $token; } else { @@ -1327,12 +1660,9 @@ sub WriteTerm { } } # prune tacacs/radius server keys - if (/^(tacacs-server|radius-server) key / && $filter_pwds >= 1) { - ProcessHistory("","","","!$1 key <removed>\n"); next; - } - if (/^((tacacs-server|radius-server) host \S+ key) / && - $filter_pwds >= 1) { - ProcessHistory("","","","!$1 <removed>\n"); next; + if (/^((tacacs-server|radius-server)\s(\w*[-\s(\s\S+])*\s?key) \d \w+/ + && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 <removed>$'"); next; } # order clns host statements /^clns host \S+ (\S+)/ && @@ -1393,113 +1723,85 @@ sub WriteTerm { 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", - 'show variables boot' => "ShowBoot", - 'show flash' => "ShowFlash", - 'dir /all nvram:' => "DirSlotN", - 'dir /all bootflash:' => "DirSlotN", - 'dir /all slot0:' => "DirSlotN", - 'dir /all disk0:' => "DirSlotN", - 'dir /all slot1:' => "DirSlotN", - 'dir /all disk1:' => "DirSlotN", - 'dir /all slot2:' => "DirSlotN", - '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", - "show variables boot", - "show flash", - "dir /all nvram:", - "dir /all bootflash:", - "dir /all slot0:", - "dir /all disk0:", - "dir /all slot1:", - "dir /all disk1:", - "dir /all slot2:", - "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" +@commandtable = ( + {'admin show version' => 'ShowVersion'}, + {'show version' => 'ShowVersion'}, + {'show redundancy secondary' => 'ShowRedundancy'}, + {'show idprom backplane', => 'ShowIDprom'}, + {'show install active' => 'ShowInstallActive'}, + {'admin show env all' => 'ShowEnv'}, + {'show env all' => 'ShowEnv'}, + {'show rsp chassis-info', => 'ShowRSP'}, + {'show gsr chassis' => 'ShowGSR'}, + {'show diag chassis-info' => 'ShowGSR'}, + {'show boot' => 'ShowBoot'}, + {'show bootvar' => 'ShowBoot'}, + {'admin show variables boot' => 'ShowBoot'}, + {'show variables boot' => 'ShowBoot'}, + {'show flash' => 'ShowFlash'}, + {'dir /all nvram:' => 'DirSlotN'}, + {'dir /all bootflash:' => 'DirSlotN'}, + {'dir /all slot0:' => 'DirSlotN'}, + {'dir /all disk0:' => 'DirSlotN'}, + {'dir /all slot1:' => 'DirSlotN'}, + {'dir /all disk1:' => 'DirSlotN'}, + {'dir /all slot2:' => 'DirSlotN'}, + {'dir /all disk2:' => 'DirSlotN'}, + {'dir /all harddisk:' => 'DirSlotN'}, + {'dir /all harddiska:' => 'DirSlotN'}, + {'dir /all harddiskb:' => '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'}, + {'admin show diag' => 'ShowDiag'}, + {'show diag' => 'ShowDiag'}, + {'show module' => 'ShowModule'}, # cat 6500-ios + {'show spe version' => 'ShowSpeVersion'}, + {'show c7200' => 'ShowC7200'}, + {'show inventory raw' => 'ShowInventory'}, + {'show vtp status' => 'ShowVTP'}, + {'show vlan' => 'ShowVLAN'}, + {'show vlan-switch' => 'ShowVLAN'}, + {'show debug' => 'ShowDebug'}, + {'show running-config' => 'WriteTerm'}, + {'write term' => 'WriteTerm'}, ); +# Use an array to preserve the order of the commands and a hash for mapping +# commands to the subroutine and track commands that have been completed. +@commands = map(keys(%$_), @commandtable); +%commands = map(%$_, @commandtable); + $cisco_cmds=join(";",@commands); $cmds_regexp=join("|",@commands); +if (length($host) == 0) { + if ($file) { + print(STDERR "Too few arguments: file name required\n"); + exit(1); + } else { + print(STDERR "Too few arguments: host name required\n"); + exit(1); + } +} open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; select(OUTPUT); # make OUTPUT unbuffered if debugging @@ -1522,15 +1824,16 @@ if ($file) { # determine password filtering mode if ($ENV{"FILTER_PWDS"} =~ /no/i) { - $filter_pwds = 0; + $filter_pwds = 0; } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) { - $filter_pwds = 2; + $filter_pwds = 2; } else { - $filter_pwds = 1; + $filter_pwds = 1; } ProcessHistory("","","","!RANCID-CONTENT-TYPE: cisco\n!\n"); ProcessHistory("COMMENTS","keysort","B0","!\n"); +ProcessHistory("COMMENTS","keysort","D0","!\n"); ProcessHistory("COMMENTS","keysort","F0","!\n"); ProcessHistory("COMMENTS","keysort","G0","!\n"); TOP: while(<INPUT>) { diff --git a/bin/rivlogin.in b/bin/rivlogin.in index 12554d5..2d80217 100644 --- a/bin/rivlogin.in +++ b/bin/rivlogin.in @@ -1,8 +1,9 @@ #! @EXPECT_PATH@ -- ## -## $Id: rivlogin.in,v 1.15 2004/01/11 05:39:15 heas Exp $ +## $Id: rivlogin.in,v 1.26 2006/12/08 21:28:26 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -24,24 +25,28 @@ # rivlogin - Riverstone (and Enterasys SSR) login # # Based upon rscmd (see nmops.org) -# rscmd - Riverstone Networks Automated login -# by Mike MacFaden, Kiran Addepalli +# rscmd - Riverstone Networks Automated login +# by Mike MacFaden, Kiran Addepalli # Riverstone Networks, 2000 # # Returned to the RANCID crowd by andrew fort -# Global vars section +# Usage line +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" # 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 +# cli command prompt set my_prompt ">" set enable_prompt "\#" @@ -60,18 +65,35 @@ set do_script 0 set log_user 0 # The default CLI mode to login to is "enable" mode -set enable 1 +set avenable 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" +# +set send_human {.4 .4 .7 .3 5} + +# Find the user in the ENV, or use the unix userid. +if {[ info exists env(CISCO_USER) ]} { + set default_user $env(CISCO_USER) +} elseif {[ info exists env(USER) ]} { + set default_user $env(USER) +} elseif {[ info exists env(LOGNAME) ]} { + set default_user $env(LOGNAME) +} else { + # This uses "id" which I think is portable. At least it has existed + # (without options) on all machines/OSes I've been on recently - + # unlike whoami or id -nu. + if [ catch {exec id} reason ] { + send_error "\nError: could not exec id: $reason\n" + exit 1 + } + regexp {\(([^)]*)} "$reason" junk default_user +} +if {[ info exists env(CLOGINRC) ]} { + set password_file $env(CLOGINRC) +} # Procedures Section @@ -79,7 +101,6 @@ router \[router...\]\n" # # Sets Xterm title if interactive...if its an xterm and the user cares # - proc label { host } { global env @@ -97,35 +118,32 @@ proc label { host } { } } - # 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 } { +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 - +# 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] } { + if { [info exists read_password_file] } { return 1 } - if { [info exists password_file] == 0 } { + if { [info exists password_file] == 0 } { set password_file $env(HOME)/.cloginrc } @@ -142,15 +160,14 @@ proc 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] } { + upvar $var list + if { [info exists list] } { foreach line $list { if { [string match [lindex $line 0] $router ] } { return [lrange $line 1 end] @@ -160,13 +177,11 @@ proc find { var router } { return {} } - # pre: login completed ok # post: terminate login session by closing tcp connection - proc auto_exit { } { - global telnet_id + global telnet_id if { $verbose == 1 } { puts "DEBUG: auto_exit closing connection to pid $telnet_id\n" @@ -179,8 +194,7 @@ proc auto_exit { } { # 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 - +# and paging of cli output is disabled proc login { router user userpswd passwd enapasswd } { global login_array @@ -212,7 +226,7 @@ proc login { router user userpswd passwd enapasswd } { expect "*" send "\r" - # If password fails 3 times then expect again + # If password fails 3 times then expect again set pass_attempt 0 expect { @@ -220,7 +234,7 @@ proc login { router user userpswd passwd enapasswd } { -re ".*> " { } "Password:" { - incr pass_attempt + incr pass_attempt send "$passwd\r" exp_continue } @@ -232,13 +246,13 @@ proc login { router user userpswd passwd enapasswd } { send "$user\r" expect { - "Password: " { + "Password: " { incr pattempt if {$pattempt == 1} { - send "$userpswd\r"; - } else { - send "$enapasswd\r"; + send "$userpswd\r"; + } else { + send "$enapasswd\r"; } exp_continue } @@ -246,8 +260,8 @@ proc login { router user userpswd passwd enapasswd } { -re ".*> " { exp_continue;} } } - - "%TELNETD-W-BADPASSWD" { + + "%TELNETD-W-BADPASSWD" { puts "ERROR: bad userid or password to telnet." return 1 } @@ -266,7 +280,7 @@ proc login { router user userpswd passwd enapasswd } { return 1 } - "Connection closed *" { + "Connection closed *" { if {$pass_attempt == 3} { puts "ERROR: Maximum attempts for password reached. Check password. Exiting."; puts $expect_out(0,string); @@ -279,7 +293,7 @@ proc login { router user userpswd passwd enapasswd } { return 1 } - eof { + eof { puts "ERROR: device closed telnet connection during login" return 1 } @@ -298,7 +312,6 @@ proc login { router user userpswd passwd enapasswd } { # pre: login completed ok # post: turn off paging of commands - proc disable_cli_paging { } { global my_prompt @@ -313,7 +326,6 @@ proc disable_cli_paging { } { # 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 @@ -322,9 +334,9 @@ proc disable_cmd_autocomplete { } { $my_prompt { } - timeout { + timeout { puts "ERROR:disable_cmd_autocomplete(TIMEOUT)"; - return 0; + return 0; } } @@ -333,8 +345,7 @@ proc disable_cmd_autocomplete { } { } # pre: login returned 0, do_enable returned 0, cli is in enable or config mode -# post: issues logout cli to device, returns 0 - +# post: issues logout cli to device, returns 0 proc logout { prompt } { global config_mode enable_prompt @@ -342,7 +353,7 @@ proc logout { prompt } { # verify top level prompt state, move to it if necessary if { $config_mode == 1 } { - + send "exit\r" expect { @@ -370,7 +381,6 @@ proc logout { prompt } { # 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 @@ -380,19 +390,32 @@ proc do_enable { enauser enapasswd userpswd } { if { $verbose == 1 } { puts "DEBUG: do_enable: my_prompt = $my_prompt ena_prompt = $enable_prompt" } - + + set uses_username 0; + send "enable\r" expect { - Username: { send "$enauser\r"; exp_continue } - Password: { send "$userpswd\r"; exp_continue } + Username: { + set uses_username 1; + send "$enauser\r"; + exp_continue + } + Password: { + if {$uses_username == 1} { + send "$userpswd\r"; + } else { + send "$enapasswd\r"; + } + exp_continue + } "$my_prompt" { puts "ERROR: do_enable failed to gain enable mode." return 1 } - "CONS-W-AUTH_PASSWD" { send "$enapasswd\r"; } + "CONS-W-AUTH_PASSWD" { send "$enapasswd\r"; } "$enable_prompt " { } "%SYS-W-NOPASSWD*" { } @@ -402,14 +425,13 @@ proc do_enable { enauser enapasswd userpswd } { 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 @@ -419,7 +441,7 @@ proc do_configure { } { if { $verbose == 1 } { puts "DEBUG: do_config: my_prompt = $my_prompt cfg_prompt = $config_prompt" } - + send "configure\r" expect { "$config_prompt " { } @@ -438,15 +460,14 @@ proc do_configure { } { # 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 + global logging if { [ string length $output_file ] != 0 } { - set rc [ catch { + 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 @@ -458,7 +479,7 @@ proc start_logfile { output_file } { } proc run_commands { prompt cmdstring } { - global sendstring + global sendstring set commands [split $cmdstring \;] set num_commands [llength $cmdstring] @@ -474,13 +495,11 @@ proc run_commands { prompt cmdstring } { 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 @@ -498,7 +517,7 @@ proc run_single_command { prompt cmdstring } { set need_ays 1 set delay 1 if {$verbose == 1} { - puts "DEBUG: save startup cmd seen, set need_ays = 1" + puts "DEBUG: save startup cmd seen, set need_ays = 1" } } @@ -511,7 +530,7 @@ proc run_single_command { prompt cmdstring } { if { $delay == 1} { sleep 1 - } + } expect { @@ -542,7 +561,7 @@ proc run_single_command { prompt cmdstring } { "want to overwrite " { send "yes\r" if {$verbose == 1} { - puts "DEBUG: got overwrite question, set need_ays to 0" + puts "DEBUG: got overwrite question, set need_ays to 0" } set need_ays 0 } @@ -551,7 +570,7 @@ proc run_single_command { prompt cmdstring } { "%CONFIG-E-DUPLICATE,*" { } - "$prompt" { + "$prompt" { if { $seen_prompt == 0 } { set seen_prompt 1 } @@ -571,7 +590,7 @@ proc run_single_command { prompt cmdstring } { } - timeout { + timeout { if {$verbose == 1} { puts "DEBUG: timeout occured for the $seen_time time\n" } @@ -586,8 +605,8 @@ proc run_single_command { prompt cmdstring } { set rc 1 } - eof { - puts "ERROR:run_commands(connection closed by device)\n" + eof { + puts "ERROR:run_commands(connection closed by device)\n" set rc 1 } @@ -602,15 +621,14 @@ proc run_single_command { prompt cmdstring } { # 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 - + # 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 } @@ -631,14 +649,13 @@ proc source_script_file { filename } { # 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 rc [ catch { set ifile [ open $filename r] } errMsg ] @@ -650,16 +667,16 @@ proc process_script_file { filename } { set line_cnt 0 while { [eof $ifile] != 1 } { - + set bytes [ gets $ifile cmd ] incr line_cnt - if { $bytes < 0 } { - break + if { $bytes < 0 } { + break } elseif { $bytes == 0 } { continue } - + if { $verbose == 1 } { puts "DEBUG: line:$line_cnt cmd = $cmd\n" } @@ -693,12 +710,11 @@ proc process_script_file { filename } { # 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 rc [ catch { set ifile [ open $filename r] } errMsg ] @@ -706,7 +722,7 @@ proc strip_log { filename router } { puts "ERROR: strip_log: open script file $filename for read access failed. $errMsg\n" return 1 } - set rc [ catch { + set rc [ catch { set ofile [ open $tempfile w] } errMsg ] @@ -718,12 +734,11 @@ proc strip_log { filename router } { set nl 0 puts $ofile "rscmd: $router : [exec date]" - + while { [eof $ifile] != 1 } { - set bytes [ gets $ifile cmd ] - if { $bytes <= 0 } { - break + if { $bytes <= 0 } { + break } incr nl if { $nl <= 2 } { @@ -801,6 +816,10 @@ for {set idx 0} {$idx < $argc} {incr idx} { } set do_script 1 + # Version string + } -V* { + send_user "@PACKAGE@ @VERSION@\n" + exit 0 # Command file } -x* - -X { @@ -832,22 +851,21 @@ for {set idx 0} {$idx < $argc} {incr idx} { 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 + # Timeout + } -t* - + -T* { + incr idx + set timeout [ lindex $argv $idx ] + # Do we enable? + } -noenable { + set avenable 0 + } -* { + send_user "Error: Unkown argument! $arg\n" + send_user $usage exit 1 - - } default { + } default { break - } + } } } @@ -859,146 +877,139 @@ if { $idx == $argc } { } # 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 passwords + if {$verbose == 1} { + puts "DEBUG: do_passwd = $do_passwd\n" + puts "DEBUG: do_enablepasswd = $do_enapasswd\n" + } -# Figure out enable username + # look for noenable option in .cloginrc + if { [find noenable $router] != "" } { + set enable 0 + } else { + set enable $avenable + } -if {[info exists enausername]} { - # command line enausername - set enauser $enausername -} else { - set enauser [join [find enauser $router] ""] - if { "$enauser" == "" } { set enauser $user } -} + 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 + } -# Login to the router, set my_prompt to router's cmd prompt + set passwd [join [lindex $pswd 0] ""] + set enapasswd [join [lindex $pswd 1] ""] + } else { + set passwd $userpasswd + set enapasswd $enapasswd + } -if {[login $router $user $userpswd $passwd $enapasswd ]} { - if { $verbose == 1 } { - puts "DEBUG: login to $router failed\n" + # 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 } } - exit 1 -} -if {$verbose == 1 } { - puts "DEBUG: login completed ok\n" -} + # 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 } + } -if { $enable == 1 } { + # 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 } + } - if { [do_enable $enauser $enapasswd $userpswd] == 1} { + # Login to the router, set my_prompt to router's cmd prompt + if {[login $router $user $userpswd $passwd $enapasswd ]} { if { $verbose == 1 } { - puts "DEBUG: switch to enable mode on $router failed\n" + puts "DEBUG: login to $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 {$verbose == 1 } { + puts "DEBUG: login completed ok\n" } - if {[ run_commands $my_prompt $command ]} { - - log_file - exit 1 + 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 + } + } - } else { + # run in one of three modes + if { $do_command } { + disable_cmd_autocomplete + disable_cli_paging - logout $my_prompt + if { [start_logfile $output_file] != 0 } { + exit 1 + } - } - -} elseif { $do_script } { - - 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 { [process_script_file $sfile] == 1} { -# puts "DEBUG: logfile $output_file closed on error\n" -# logout $my_prompt -# exit 1 -# } + if {[ start_logfile $output_file] != 0 } { + exit 1 + } - source_script_file $sfile +# if { [process_script_file $sfile] == 1} { +# puts "DEBUG: logfile $output_file closed on error\n" +# logout $my_prompt +# exit 1 +# } - logout $my_prompt + source_script_file $sfile -} else { - - label $router - log_user 1 + logout $my_prompt + } else { + label $router + log_user 1 - if {[ start_logfile $output_file] != 0 } { - exit 1 + if {[ start_logfile $output_file] != 0 } { + exit 1 + } + interact + log_file } - interact - log_file -} -if { $verbose == 1 } { - puts "DEBUG: exiting normally.\n" -} + if { $verbose == 1 } { + puts "DEBUG: exiting normally.\n" + } -if { $logging == 1} { - log_file - strip_log $output_file $router -} + if { $logging == 1} { + log_file + strip_log $output_file $router + } } # puts "\n" diff --git a/bin/rivrancid.in b/bin/rivrancid.in index 8b9ae03..d6625b6 100644 --- a/bin/rivrancid.in +++ b/bin/rivrancid.in @@ -1,8 +1,9 @@ #! @PERLV_PATH@ ## -## $Id: rivrancid.in,v 1.9 2004/01/11 03:49:13 heas Exp $ +## $Id: rivrancid.in,v 1.17 2006/10/05 04:27:44 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -21,31 +22,36 @@ # # 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 +# Jim Meehan -- jmeehan@vpizza.org # # RANCID - Really Awesome New Cisco confIg Differ # -# usage: rivrancid [-d] [-l] [-f filename | $host] +# usage: rivrancid [-dV] [-l] [-f filename | hostname] # use Getopt::Std; -getopts('dfl'); +getopts('dflV'); +if ($opt_V) { + print "@PACKAGE@ @VERSION@\n"; + exit(0); +} $log = $opt_l; $debug = $opt_d; $file = $opt_f; $host = $ARGV[0]; $clean_run = 0; $found_end = 0; -$timeo = 90; # flogin timeout in seconds +$timeo = 90; # rivlogin timeout in seconds -my(%filter_pwds); # password filtering mode +my(@commandtable, %commands, @commands);# command lists +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) { + 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; } @@ -67,10 +73,10 @@ sub ProcessHistory { sub numerically { $a <=> $b; } -# This is a sort routing that will sort numerically on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort numerically keys(%lines)) { @@ -80,10 +86,10 @@ sub keynsort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort keys(%lines)) { @@ -93,22 +99,22 @@ sub keysort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort values %lines) { - $sorted_lines[$i] = $key; - $i++; + $sorted_lines[$i] = $key; + $i++; } @sorted_lines; } -# This is a numerical sort routing (ascending). +# This is a numerical sort routine (ascending). sub numsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $num (sort {$a <=> $b} keys %lines) { @@ -122,7 +128,7 @@ sub numsort { # ip address when the ip address is anywhere in # the strings. sub ipsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $addr (sort sortbyipaddr keys %lines) { @@ -135,7 +141,7 @@ sub ipsort { # 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])); + $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0])); } sub sortbyipaddr { &ipaddrval($a) <=> &ipaddrval($b); @@ -179,7 +185,7 @@ sub ShowUptime { tr/\015//d; last if(/^$prompt/); next if /^\s*$/; - next if /System up/; + next if /System up/; ProcessHistory("UPTIME","","","!UPTIME: $_"); } ProcessHistory("","","","!\n"); @@ -197,13 +203,13 @@ sub ShowActive { s/^\s*(\d+\D: )*//; # Riverstone/Cabletron doesn't have an "end" line, so - # we need to set $clean_run here + # we need to set $clean_run here if (/^$prompt/) { - $clean_run = 1; - last; - } + $clean_run = 1; + last; + } - next if (/Running system configuration/); + next if (/Running system configuration/); # filter out any RCS/CVS tags to avoid confusing local CVS storage s/\$(Revision|Id):/ $1:/; @@ -227,26 +233,29 @@ sub ShowActive { 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" +@commandtable = ( + {'system show uptime' => 'ShowUptime'}, + {'system show version' => 'ShowVersion'}, + {'system show hardware' => 'ShowHardware'}, + {'system show active-config' => 'ShowActive'} ); +# Use an array to preserve the order of the commands and a hash for mapping +# commands to the subroutine and track commands that have been completed. +@commands = map(keys(%$_), @commandtable); +%commands = map(%$_, @commandtable); $cisco_cmds=join(";",@commands); $cmds_regexp=join("|",@commands); +if (length($host) == 0) { + if ($file) { + print(STDERR "Too few arguments: file name required\n"); + exit(1); + } else { + print(STDERR "Too few arguments: host name required\n"); + exit(1); + } +} open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; select(OUTPUT); # make OUTPUT unbuffered if debugging @@ -269,7 +278,7 @@ if ($file) { # determine password filtering mode if ($ENV{"FILTER_PWDS"} =~ /no/i) { - $filter_pwds = 0; + $filter_pwds = 0; } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) { $filter_pwds = 2; } else { diff --git a/bin/rrancid.in b/bin/rrancid.in index 7674452..87ea7c4 100644 --- a/bin/rrancid.in +++ b/bin/rrancid.in @@ -1,8 +1,9 @@ #! @PERLV_PATH@ ## -## $Id: rrancid.in,v 1.18 2004/01/11 03:49:13 heas Exp $ +## $Id: rrancid.in,v 1.26 2006/10/05 04:27:44 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -23,25 +24,30 @@ # # RANCID - Really Awesome New Cisco confIg Differ # -# usage: rancid [-d] [-l] [-f filename | $host] +# usage: rancid [-dV] [-l] [-f filename | hostname] # use Getopt::Std; -getopts('dfl'); +getopts('dflV'); +if ($opt_V) { + print "@PACKAGE@ @VERSION@\n"; + exit(0); +} $log = $opt_l; $debug = $opt_d; $file = $opt_f; $host = $ARGV[0]; $clean_run = 0; $found_end = 0; -$timeo = 90; # clogin timeout in seconds +$timeo = 90; # clogin timeout in seconds -my(%filter_pwds); # password filtering mode +my(@commandtable, %commands, @commands);# command lists +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) { + 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; } @@ -63,10 +69,10 @@ sub ProcessHistory { sub numerically { $a <=> $b; } -# This is a sort routing that will sort numerically on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort numerically keys(%lines)) { @@ -76,10 +82,10 @@ sub keynsort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort keys(%lines)) { @@ -89,22 +95,22 @@ sub keysort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort values %lines) { - $sorted_lines[$i] = $key; - $i++; + $sorted_lines[$i] = $key; + $i++; } @sorted_lines; } -# This is a numerical sort routing (ascending). +# This is a numerical sort routine (ascending). sub numsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $num (sort {$a <=> $b} keys %lines) { @@ -118,7 +124,7 @@ sub numsort { # ip address when the ip address is anywhere in # the strings. sub ipsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $addr (sort sortbyipaddr keys %lines) { @@ -131,7 +137,7 @@ sub ipsort { # 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])); + $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0])); } sub sortbyipaddr { &ipaddrval($a) <=> &ipaddrval($b); @@ -245,7 +251,7 @@ sub WriteTerm { s/\$(Revision|Id):/ $1:/; # order access-lists /^access-list\s+(\d\d?)\s+(\S+)\s+(\S+)/ && - ProcessHistory("ACL $1 $2","ipsort","$3","$_") && next; + ProcessHistory("ACL $1 $2","ipsort","$3","$_") && next; # prune snmp community statements if (/^snmp (group|community) (\S+)/) { if (defined($ENV{'NOCOMMSTR'})) { @@ -255,7 +261,7 @@ sub WriteTerm { } } ProcessHistory("","","","$_"); - # end of config + # end of config if (/^end$/) { $found_end = 1; last; @@ -283,30 +289,33 @@ sub FlailHelplessly { } # Main -%commands=( - 'show version' => "ShowVersion", - "dir /flash" => "DirFlash", - "dir /pcmcia0" => "DirFlash", - "dir /pcmcia1" => "DirFlash", - 'show hardware' => "ShowHardware", - 'show chassis' => "ShowChassis", - 'show slot table' => "ShowSlotTable", - 'show config' => "WriteTerm" -); -@commands=( - "show version", - "dir /flash", - "dir /pcmcia0", - "dir /pcmcia1", - "show hardware", - "show chassis", - "show slot table", - "show config" +@commandtable = ( + {'show version' => 'ShowVersion'}, + {'dir /flash' => 'DirFlash'}, + {'dir /pcmcia0' => 'DirFlash'}, + {'dir /pcmcia1' => 'DirFlash'}, + {'show hardware' => 'ShowHardware'}, + {'show chassis' => 'ShowChassis'}, + {'show slot table' => 'ShowSlotTable'}, + {'show config' => 'WriteTerm'} ); +# Use an array to preserve the order of the commands and a hash for mapping +# commands to the subroutine and track commands that have been completed. +@commands = map(keys(%$_), @commandtable); +%commands = map(%$_, @commandtable); $redback_cmds=join(";",@commands); $cmds_regexp=join("|",@commands); +if (length($host) == 0) { + if ($file) { + print(STDERR "Too few arguments: file name required\n"); + exit(1); + } else { + print(STDERR "Too few arguments: host name required\n"); + exit(1); + } +} open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; select(OUTPUT); # make OUTPUT unbuffered @@ -330,7 +339,7 @@ if ($file) { # determine password filtering mode if ($ENV{"FILTER_PWDS"} =~ /no/i) { - $filter_pwds = 0; + $filter_pwds = 0; } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) { $filter_pwds = 2; } else { diff --git a/bin/srancid.in b/bin/srancid.in new file mode 100755 index 0000000..63c2e92 --- /dev/null +++ b/bin/srancid.in @@ -0,0 +1,404 @@ +#! @PERLV_PATH@ +## +## Pretty huge hack to take care of Dell Switch configs +## d_pfleger@juniper.net +## +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Henry Kilmer. +## All rights reserved. +## +## This software may be freely copied, modified and redistributed +## fee for non-commerical purposes provided that this copyright notice +## 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. +## +## +# +# RANCID - Really Awesome New Cisco confIg Differ +# +# usage: rancid [-dV] [-l] [-f filename | hostname] +# +use Getopt::Std; +getopts('dflV'); +if ($opt_V) { + print "@PACKAGE@ @VERSION@\n"; + exit(0); +} +$log = $opt_l; +$debug = $opt_d; +$file = $opt_f; +$host = $ARGV[0]; +$found_end = 0; +$timeo = 90; # hlogin timeout in seconds + +my(@commandtable, %commands, @commands);# command lists +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 "dir" +sub Dir { + print STDERR " In Dir: $_" if ($debug); + + while (<INPUT>) { + s/^\s+\015//g; + tr/\015//d; + next if /^\s*$/; + last if(/$prompt/); + # pager remnants like: ^H^H^H ^H^H^H content + s/[\b]+\s*[\b]*//g; + + ProcessHistory("COMMENTS","keysort","D1","! $_"); + } + return(0); +} + + +sub ShowVer { + print STDERR " In ShowVer: $_" if ($debug); + + while (<INPUT>) { + tr/\015//d; + next if /^\s*$/; + last if(/$prompt/); + # pager remnants like: ^H^H^H ^H^H^H content + s/[\b]+\s*[\b]*//g; + + ProcessHistory("COMMENTS","keysort","B1","! $_"); + } + return(0); +} + +sub ShowSys { + print STDERR " In ShowSys: $_" if ($debug); + + while (<INPUT>) { + s/^\s+\015//g; + tr/\015//d; + next if /^\s*$/; + last if(/$prompt/); + # pager remnants like: ^H^H^H ^H^H^H content + s/[\b]+\s*[\b]*//g; + + # Remove Uptime + / Up time/ && next; + + /system description: (.*)/i && + ProcessHistory("COMMENTS","keysort","A1", "!Chassis type: $1\n") && + next; + + ProcessHistory("COMMENTS","keysort","C1","! $_"); + } + return(0); +} + +sub ShowVlan { + print STDERR " In ShowVlan: $_" if ($debug); + + while (<INPUT>) { + s/^\s+\015//g; + tr/\015//d; + next if /^\s*$/; + last if(/$prompt/); + # pager remnants like: ^H^H^H ^H^H^H content + s/[\b]+\s*[\b]*//g; + + # Remove Uptime + / Up time/ && next; + ProcessHistory("COMMENTS","keysort","D1","! $_"); + } + return(0); +} + +# This routine processes a "write term" (aka show running-configuration) +sub WriteTerm { + my($comment) = (0); + print STDERR " In ShowRun: $_" if ($debug); + + while (<INPUT>) { + tr/\015//d; + next if /^\s*$/; + last if(/$prompt/); + # pager remnants like: ^H^H^H ^H^H^H content + s/[\b]+\s*[\b]*//g; + + # skip consecutive comment lines + if (/^!/) { + next if ($comment); + ProcessHistory("","","",$_); + $comment++; + next; + } + $comment = 0; + + /^building running-config/ && next; + /^------+/ && ProcessHistory("","","","!$_") && next; + /^router configuration/i && ProcessHistory("","","","!$_") && next; + /^oob host config/i && ProcessHistory("","","","!$_") && next; + /^empty configuration/i && ProcessHistory("","","","!$_") && next; + + if (/^password (\S+) encrypted/ && $filter_pwds > 1) { + ProcessHistory("","","","!password <removed> encrypted\n"); + next; + } + if (/^password (\S+)$/ && $filter_pwds >= 1) { + ProcessHistory("","","","!password <removed>\n"); + next; + } + + if (/^(enable password level \d+) (\S+) encrypted/ && $filter_pwds > 1){ + ProcessHistory("","","","!$1 <removed> encrypted\n"); + next; + } + if (/^(enable password level \d+) (\S+)$/ && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 <removed> $'\n"); + next; + } + + # order/prune snmp-server host statements + # we only prune lines of the form + # snmp-server host a.b.c.d <community> + if (/^(snmp-server host) (\d+\.\d+\.\d+\.\d+) (\S+)/) { + if (defined($ENV{'NOCOMMSTR'})) { + ProcessHistory("SNMPSERVERHOST","ipsort", + "$2","!$1 $2 <removed>$'"); + } else { + ProcessHistory("SNMPSERVERHOST","ipsort","$2","$_"); + } + next; + } + if (/^(snmp-server community) (\S+)/) { + if (defined($ENV{'NOCOMMSTR'})) { + ProcessHistory("SNMPSERVERCOMM","keysort", + "$_","!$1 <removed>$'") && next; + } else { + ProcessHistory("SNMPSERVERCOMM","keysort","$2","$_") && next; + } + } + + # prune tacacs/radius server keys + if (/^(tacacs-server|radius-server) key \w+/ && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 <removed>$'"); next; + } + + ProcessHistory("","","","$_"); + } + $found_end = 1; + return(1); +} + +# dummy function +sub DoNothing {print STDOUT;} + +# Main +@commandtable = ( + {'show system' => 'ShowSys'}, + {'show version' => 'ShowVer'}, + {'dir' => 'Dir'}, + {'show vlan' => 'ShowVlan'}, + {'show running-config' => 'WriteTerm'} +); +# Use an array to preserve the order of the commands and a hash for mapping +# commands to the subroutine and track commands that have been completed. +@commands = map(keys(%$_), @commandtable); +%commands = map(%$_, @commandtable); + +$cisco_cmds=join(";",@commands); +$cmds_regexp=join("|",@commands); + +if (length($host) == 0) { + if ($file) { + print(STDERR "Too few arguments: file name required\n"); + exit(1); + } else { + print(STDERR "Too few arguments: host name required\n"); + exit(1); + } +} +open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; +select(OUTPUT); +# make OUTPUT unbuffered if 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 hlogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($debug); + print STDOUT "executing hlogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($log); + if (defined($ENV{NOPIPE})) { + system "hlogin -t $timeo -c \"$cisco_cmds\" $host </dev/null > $host.raw 2>&1" || die "hlogin failed for $host: $!\n"; + open(INPUT, "< $host.raw") || die "hlogin failed for $host: $!\n"; + } else { + open(INPUT,"hlogin -t $timeo -c \"$cisco_cmds\" $host </dev/null |") || die "hlogin failed for $host: $!\n"; + } +} + +# determine password filtering mode +if ($ENV{"FILTER_PWDS"} =~ /no/i) { + $filter_pwds = 0; +} elsif ($ENV{"FILTER_PWDS"} =~ /all/i) { + $filter_pwds = 2; +} else { + $filter_pwds = 1; +} + +ProcessHistory("","","","!RANCID-CONTENT-TYPE: dell\n!\n"); +ProcessHistory("COMMENTS","keysort","A0","!\n"); +ProcessHistory("COMMENTS","keysort","B0","!\n"); +ProcessHistory("COMMENTS","keysort","C0","!\n"); +ProcessHistory("COMMENTS","keysort","D0","!\n"); +TOP: while(<INPUT>) { + tr/\015//d; + if (/^Error:/) { + print STDOUT ("$host dlogin error: $_"); + print STDERR ("$host dlogin error: $_") if ($debug); + 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"; + 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/tntlogin.in b/bin/tntlogin.in index 021f0d2..57fbfc0 100644 --- a/bin/tntlogin.in +++ b/bin/tntlogin.in @@ -1,8 +1,9 @@ #! @EXPECT_PATH@ -- ## -## $Id: tntlogin.in,v 1.11 2004/01/11 05:39:15 heas Exp $ +## $Id: tntlogin.in,v 1.22 2006/12/05 16:50:53 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -39,16 +40,16 @@ set password_file $env(HOME)/.cloginrc set do_command 0 set do_script 0 # The default is to automatically enable -set enable 0 +set avenable 0 # The default is that you login non-enabled (tacacs can have you login already # enabled) -set avautoenable 1 +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) ] } { +if {[ info exists env(CISCO_USER) ]} { set default_user $env(CISCO_USER) } elseif {[ info exists env(USER) ]} { set default_user $env(USER) @@ -61,9 +62,12 @@ if {[ info exists env(CISCO_USER) ] } { if [ catch {exec id} reason ] { send_error "\nError: could not exec id: $reason\n" exit 1 - } + } regexp {\(([^)]*)} "$reason" junk default_user -} +} +if {[ info exists env(CLOGINRC) ]} { + set password_file $env(CLOGINRC) +} # Sometimes routers take awhile to answer (the default is 10 sec) set timeout 45 @@ -81,13 +85,16 @@ for {set i 0} {$i < $argc} {incr i} { set username [ lindex $argv $i ] } # VTY Password - } -v* - - -v* { + } -v* { if {! [ regexp .\[vV\](.+) $arg ignore passwd]} { incr i set passwd [ lindex $argv $i ] } set do_passwd 0 + # Version string + } -V* { + send_user "@PACKAGE@ @VERSION@\n" + exit 0 # Enable Username } -w* - -W* { @@ -260,6 +267,7 @@ proc source_password_file { password_file } { } # Log into the router. +# returns: 0 on success, 1 on failure proc login { router user userpswd passwd prompt cmethod cyphertype } { global spawn_id in_proc do_command do_script global u_prompt p_prompt sshcmd @@ -269,6 +277,7 @@ proc login { router user userpswd passwd prompt cmethod cyphertype } { # try each of the connection methods in $cmethod until one is successful set progs [llength $cmethod] foreach prog [lrange $cmethod 0 end] { + incr progs -1 if [string match "telnet*" $prog] { regexp {telnet(:([^[:space:]]+))*} $prog command suffix port if {"$port" == ""} { @@ -278,24 +287,24 @@ proc login { router user userpswd passwd prompt cmethod cyphertype } { } if { $retval } { send_user "\nError: telnet failed: $reason\n" - exit 1 + return 1 } - } elseif ![string compare $prog "ssh"] { + } 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 + return 1 } - } else { - puts "\nError: unknown connection method: $prog" + } elseif ![string compare $prog "rsh"] { + send_error "\nError: unsupported method: rsh\n" + if { $progs == 0 } { + return 1 + } + continue; + } else { + send_user "\nError: unknown connection method: $prog\n" return 1 - } - incr progs -1 - sleep 0.3 + } + sleep 0.3 # This helps cleanup each expect clause. expect_after { @@ -387,7 +396,7 @@ proc run_commands { prompt command } { send "lines 0\r" expect -re $prompt {} regsub -all "\[)(]" $prompt {\\&} reprompt - + # Is this a multi-command? if [ string match "*\;*" "$command" ] { set commands [split $command \;] @@ -409,7 +418,7 @@ proc run_commands { prompt command } { -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]" @@ -417,10 +426,12 @@ proc run_commands { prompt command } { # send "y\r" exp_continue } - "\n" { exp_continue } - "\[^\n\r *]*Session terminated" { return 0 } - timeout { return 0 } - eof { return 0 } + "\n" { exp_continue } + "\[^\n\r *]*Session terminated" { return 0 } + timeout { catch {close}; wait + return 0 + } + eof { return 0 } } set in_proc 0 } @@ -496,9 +507,9 @@ 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} } + # 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]} { diff --git a/bin/tntrancid.in b/bin/tntrancid.in index 88520fd..e16d57b 100644 --- a/bin/tntrancid.in +++ b/bin/tntrancid.in @@ -1,8 +1,9 @@ #! @PERLV_PATH@ ## -## $Id: tntrancid.in,v 1.8 2004/01/11 03:49:13 heas Exp $ +## $Id: tntrancid.in,v 1.17 2006/10/05 04:27:44 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -24,29 +25,33 @@ # # RANCID - Really Awesome New Cisco confIg Differ # -# usage: tntrancid [-d] [-l] [-f filename | $host] +# usage: tntrancid [-dV] [-l] [-f filename | hostname] # use Getopt::Std; -getopts('dfl'); +getopts('dflV'); +if ($opt_V) { + print "@PACKAGE@ @VERSION@\n"; + exit(0); +} $log = $opt_l; $debug = $opt_d; $file = $opt_f; $host = $ARGV[0]; $clean_run = 0; $found_end = 0; -$timeo = 90; # tntlogin timeout in seconds +$timeo = 90; # tntlogin timeout in seconds $prompt = "admin> "; -$always_y = "y"; # cause its a pain. +$always_y = "y"; # cause its a pain. -my(%filter_pwds); # password filtering mode +my(@commandtable, %commands, @commands);# command lists +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) { + 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)) { @@ -67,10 +72,10 @@ sub ProcessHistory { sub numerically { $a <=> $b; } -# This is a sort routing that will sort numerically on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort numerically keys(%lines)) { @@ -80,10 +85,10 @@ sub keynsort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort keys(%lines)) { @@ -93,10 +98,10 @@ sub keysort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort values %lines) { @@ -106,9 +111,9 @@ sub valsort{ @sorted_lines; } -# This is a numerical sort routing (ascending). +# This is a numerical sort routine (ascending). sub numsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $num (sort {$a <=> $b} keys %lines) { @@ -122,7 +127,7 @@ sub numsort { # ip address when the ip address is anywhere in # the strings. sub ipsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $addr (sort sortbyipaddr keys %lines) { @@ -135,45 +140,40 @@ sub ipsort { # 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])); + $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 (<INPUT>) { 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 + # Leave software revision, but strip out saved date, + # which causes rancid to think it changes each poll if (/^; saved from /) { - ProcessHistory("","","","$_"); - next; + 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); + return(1); } - $found_end = 1; + # XXX what is the purpose of this? + $found_end = 1; #### print STDOUT "$found_end = found_end at test\n"; } $found_end = 1; @@ -189,18 +189,26 @@ print STDOUT "$found_end = found_end at end test\n"; 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" +@commandtable = ( + {'save con' => 'SaveConf'} ); +# Use an array to preserve the order of the commands and a hash for mapping +# commands to the subroutine and track commands that have been completed. +@commands = map(keys(%$_), @commandtable); +%commands = map(%$_, @commandtable); + $tnt_cmds=join(";",@commands); $cmds_regexp=join("|",@commands); -$tnt_cmds="save con"; +if (length($host) == 0) { + if ($file) { + print(STDERR "Too few arguments: file name required\n"); + exit(1); + } else { + print(STDERR "Too few arguments: host name required\n"); + exit(1); + } +} open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; select(OUTPUT); # make OUTPUT unbuffered if debugging @@ -223,7 +231,7 @@ if ($file) { # determine password filtering mode if ($ENV{"FILTER_PWDS"} =~ /no/i) { - $filter_pwds = 0; + $filter_pwds = 0; } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) { $filter_pwds = 2; } else { @@ -234,8 +242,8 @@ ProcessHistory("","","","#RANCID-CONTENT-TYPE: tnt\n#\n"); ProcessHistory("COMMENTS","keysort","X0",";\n"); TOP: while(<INPUT>) { tr/\015//d; - - if (/^Error:/) { + + if (/^Error:/) { print STDOUT ("$host tntlogin error: $_"); print STDERR ("$host tntlogin error: $_") if ($debug); $clean_run=0; diff --git a/bin/xrancid.in b/bin/xrancid.in index 4aeb1d3..96b99ef 100644 --- a/bin/xrancid.in +++ b/bin/xrancid.in @@ -1,8 +1,9 @@ #! @PERLV_PATH@ ## -## $Id: xrancid.in,v 1.32 2004/01/11 03:49:13 heas Exp $ +## $Id: xrancid.in,v 1.41 2006/10/05 04:27:44 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -21,25 +22,30 @@ # # RANCID - Really Awesome New Cisco confIg Differ # -# usage: rancid [-d] [-l] [-f filename | $host] +# usage: rancid [-dV] [-l] [-f filename | hostname] # use Getopt::Std; -getopts('dfl'); +getopts('dflV'); +if ($opt_V) { + print "@PACKAGE@ @VERSION@\n"; + exit(0); +} $log = $opt_l; $debug = $opt_d; $file = $opt_f; $host = $ARGV[0]; $clean_run = 0; $found_end = 0; -$timeo = 90; # clogin timeout in seconds +$timeo = 90; # clogin timeout in seconds -my(%filter_pwds); # password filtering mode +my(@commandtable, %commands, @commands);# command lists +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) { + 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; } @@ -61,10 +67,10 @@ sub ProcessHistory { sub numerically { $a <=> $b; } -# This is a sort routing that will sort numerically on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort numerically keys(%lines)) { @@ -74,10 +80,10 @@ sub keynsort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort keys(%lines)) { @@ -87,10 +93,10 @@ sub keysort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort values %lines) { @@ -100,9 +106,9 @@ sub valsort{ @sorted_lines; } -# This is a numerical sort routing (ascending). +# This is a numerical sort routine (ascending). sub numsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $num (sort {$a <=> $b} keys %lines) { @@ -116,7 +122,7 @@ sub numsort { # ip address when the ip address is anywhere in # the strings. sub ipsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $addr (sort sortbyipaddr keys %lines) { @@ -129,7 +135,7 @@ sub ipsort { # 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])); + $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0])); } sub sortbyipaddr { &ipaddrval($a) <=> &ipaddrval($b); @@ -180,7 +186,7 @@ sub ShowMemory { return(0); } -# This routine parses "show diagnostics" +# This routine parses "show diag" sub ShowDiag { print STDERR " In ShowDiag: $_" if ($debug); @@ -373,29 +379,32 @@ sub WriteTerm { sub DoNothing {print STDOUT;} # Main -%commands=( - '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 -@commands=( - "show version", - "show memory", - "show diagnostics", - "show switch", - "show slot", - "show configuration detail", - "show configuration" +@commandtable = ( + {'show version' => 'ShowVersion'}, + {'show memory' => 'ShowMemory'}, + {'show diag' => 'ShowDiag'}, + {'show switch' => 'ShowSwitch'}, + {'show slot' => 'ShowSlot'}, + {'show configuration detail' => 'WriteTerm'}, + {'show configuration' => 'WriteTerm'}, ); +# Use an array to preserve the order of the commands and a hash for mapping +# commands to the subroutine and track commands that have been completed. +@commands = map(keys(%$_), @commandtable); +%commands = map(%$_, @commandtable); + $cisco_cmds=join(";",@commands); $cmds_regexp=join("|",@commands); +if (length($host) == 0) { + if ($file) { + print(STDERR "Too few arguments: file name required\n"); + exit(1); + } else { + print(STDERR "Too few arguments: host name required\n"); + exit(1); + } +} open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; select(OUTPUT); # make OUTPUT unbuffered if debugging @@ -418,7 +427,7 @@ if ($file) { # determine password filtering mode if ($ENV{"FILTER_PWDS"} =~ /no/i) { - $filter_pwds = 0; + $filter_pwds = 0; } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) { $filter_pwds = 2; } else { @@ -453,7 +462,7 @@ TOP: while(<INPUT>) { if (!defined($prompt)) { $prompt = ($_ =~ /^([^#]+#)/)[0]; $prompt =~ s/([][}{)(\\])/\\$1/g; - $prompt =~ s/:(\d+ ?)#/:\\d+ ?#/; + $prompt =~ s/[:.](\d+ ?)#/:\\d+ ?#/; $prompt =~ s/\*/\\\*/; print STDERR ("PROMPT MATCH: $prompt\n") if ($debug); } diff --git a/bin/zrancid.in b/bin/zrancid.in index a969553..c8a926f 100755 --- a/bin/zrancid.in +++ b/bin/zrancid.in @@ -1,8 +1,9 @@ #! @PERLV_PATH@ ## -## $Id: zrancid.in,v 1.8 2004/01/11 03:49:13 heas Exp $ +## $Id: zrancid.in,v 1.14 2006/10/05 04:27:44 heas Exp $ ## -## Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (C) 1997-2006 by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -23,25 +24,30 @@ # # RANCID - Really Awesome New Cisco confIg Differ # -# usage: rancid [-d] [-l] [-f filename | $host] +# usage: rancid [-dV] [-l] [-f filename | hostname] # use Getopt::Std; -getopts('dfl'); +getopts('dflV'); +if ($opt_V) { + print "@PACKAGE@ @VERSION@\n"; + exit(0); +} $log = $opt_l; $debug = $opt_d; $file = $opt_f; $host = $ARGV[0]; $clean_run = 0; $found_end = 0; -$timeo = 90; # clogin timeout in seconds +$timeo = 90; # clogin timeout in seconds -my(%filter_pwds); # password filtering mode +my(@commandtable, %commands, @commands);# command lists +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) { + 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; } @@ -63,10 +69,10 @@ sub ProcessHistory { sub numerically { $a <=> $b; } -# This is a sort routing that will sort numerically on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort numerically keys(%lines)) { @@ -76,10 +82,10 @@ sub keynsort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort keys(%lines)) { @@ -89,10 +95,10 @@ sub keysort { @sorted_lines; } -# This is a sort routing that will sort on the +# 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(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $key (sort values %lines) { @@ -102,9 +108,9 @@ sub valsort{ @sorted_lines; } -# This is a numerical sort routing (ascending). +# This is a numerical sort routine (ascending). sub numsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $num (sort {$a <=> $b} keys %lines) { @@ -118,7 +124,7 @@ sub numsort { # ip address when the ip address is anywhere in # the strings. sub ipsort { - local(%lines)=@_; + local(%lines) = @_; local($i) = 0; local(@sorted_lines); foreach $addr (sort sortbyipaddr keys %lines) { @@ -131,7 +137,7 @@ sub ipsort { # 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])); + $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0])); } sub sortbyipaddr { &ipaddrval($a) <=> &ipaddrval($b); @@ -306,19 +312,27 @@ sub WriteTerm { 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" +@commandtable = ( + {'show version' => 'ShowVersion'}, + {'write term' => 'WriteTerm'} ); +# Use an array to preserve the order of the commands and a hash for mapping +# commands to the subroutine and track commands that have been completed. +@commands = map(keys(%$_), @commandtable); +%commands = map(%$_, @commandtable); + $cisco_cmds=join(";",@commands); $cmds_regexp=join("|",@commands); +if (length($host) == 0) { + if ($file) { + print(STDERR "Too few arguments: file name required\n"); + exit(1); + } else { + print(STDERR "Too few arguments: host name required\n"); + exit(1); + } +} open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; select(OUTPUT); # make OUTPUT unbuffered if debugging |