#!/usr/bin/perl -Tw
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
# John Chambers' SNMP script.  This can be put into your web server's cgi-bin #
# directory, and will return as much of the data for SNMP MIB-I and MIB-II as #
# it can find on your system.  This script is useful for two things:          #
#                                                                             #
# 1. Do you need to test your SNMP agent, and verify that it is returning the #
# correct data? This script returns the data in a form that a perl script can #
# easily parse, making it easy to verify the results of snmpget, snmpnext  or #
# snmpwalk.                                                                   #
#                                                                             #
# 2. Do you want to avoid the long development time that SNMP always entails? #
# You can take part in the effort to wipe out SNMP  in  our  lifetime.   This #
# script  lets  you  dispense with SNMP on any machine that has a web server. #
# (And who doesn't have one nowadays?) Adding new variables  here  is  a  lot #
# easier than futzing with ASN.1 MIB files.                                   #
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
# After dropping this script into your server's directory, you can invoke  it #
# from  a  web browser by appending variables to the script's name, separated #
# by a slashes, commas, or the ?___+___+___ notation:                         #
#                                                                             #
# Return the entire interfaces group:                                         #
#   http://foo.bar.com/cgi/snmpInfo/interfaces                                #
#   http://foo.bar.com/cgi/snmpInfo?interfaces                                #
#                                                                             #
# Return the system and tcp group:                                            #
#   http://foo.bar.com/cgi/snmpInfo/system,tcp                                #
#   http://foo.bar.com/cgi/snmpInfo?system+tcp                                #
#                                                                             #
# Return sysName.0, sysDescr.0, ifNumber.0 and the ifTable group:             #
#   http://foo.bar.com/cgi/snmpInfo/sysName/sysDescr/ifNumber/ifTable         #
#   http://foo.bar.com/cgi/snmpInfo/sysName?sysDescr+ifNumber+ifTable         #
#   http://foo.bar.com/cgi/snmpInfo/sysName,sysDescr,ifNumber,ifTable         #
#                                                                             #
# Note the various syntaxes that may be used to  pass  in  the  list  of  MIB #
# groups  or  variables.   The  HTTP  protocol  has several different ways of #
# passing parameters to a CGI script such as this one.  I've  tried  to  make #
# sure  that  all  the syntaxes work, and that you may use commas with any of #
# them in the usual manner.                                                   #
#                                                                             #
# Author: John Chambers <jc@trillian.mit.edu>                                 #
# Tested-On: Linux 1.2.13 and 2.2.13, FreeBSD 4.1 and 4.2                     #
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
# This script requires a number of other modules, which should be in the same
# directory:

#   Vopt.pm       Our verbose/log output package.
#   cgi-lib.pm    The usual CGI library for perl, in any CPAN archive.
#   snmpList.pm   The HTML list-producing routines.
#   snmpTable.pm  The HTML table-producing routines.
#   snmpData.pm   Routines to get data from the system.
#   oidorder.pm   Routine for sorting dotted-decimal strings.
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #

$| = 1;
$V = 1;		# Verbose level.

($me = $0) =~ s'.*/'';
push @INC, '.', 'sh';
require 'cgi-lib.pm';	# CGI library.
require 'cgilocal.pm';	# Our local paths.
require 'Vopt.pm';		# Verbose/log output.

# Here's how we set up a verbose/log file:

&HTMLhdr() if !$HTMLhdrs;			# Boilerplate HTML headers.
$logfile  = "$tmpdir/snmp$$.log";	# Where to put logfile.
$Vstr = $ENV{"V_$me"} || $ENV{"D_$me"} || $ENV{"T_$me"} || "1$logfile";
print "<br>Vstr=\"$Vstr\"<br>\n" if $V>1;
&Vopt($Vstr);
print "<br>Vopt=\"$Vopt\" V='$V' Vfil='$Vfil'\n" if $V>1;
print V "$me: Started.\n" if $V>1;

sub HTMLhdr {
	print &PrintHeader;
	print "<html>\n";
	print "<title>SNMP Report V=$V</title>\n";
	print "<body>\n";
	++$HTMLhdrs;
}
sub Vhdr {
	print "<br>Vopt='$Vopt' V='$V' <br>\n" if $V>1;
	++$Vhdrs;
}

# Some things to satisfy taintperl:
$ENV{'PATH'} = '/bin:/sbin:/usr/bin:/usr/ucb';
#print "INC: @INC\n";
@INC = ('.');

#($pwd = `pwd`) =~ s/\s+$//;

require "snmpData.pm";	# Data-fetching routines.
&format($me);
&getname(0);
print "<p><center><B>Web SNMP Report from $sysName V=$V </B></center>\n";
print "<hr>\n";

$, = '.';
print "<br>#	PATH_INFO=\"$ENV{'PATH_INFO'}\"\n" if $V>2;
($vars = $ENV{'PATH_INFO'}) =~ s"/","g;
print "<br>#	vars=\"$vars\"\n" if $V>2;
for $arg (@ARGV) {
	$vars .= ',' . $arg;
	print "<br>#	vars=\"$vars\"\n" if $V>2;
}
if (&ReadParse(*in)) {
	print "<br>#	ReadParse succeeded.\n" if $V>2;
} else {
	print "<br>#	ReadParse failed.\n" if $V>2;
}
print "<br>#	\$in=(", $in, ")\n" if $V>2;
print "<br>#	\@in=(", @in, ")\n" if $V>2;
if (@in) {
	for $xxx (@in) {
		print "<br>#	xxx: \"$xxx\"\n" if $V>2;
		if ($xxx =~ /^table=(.*)/) {
			$vars .= ',' . $1;
			print "<br>#   vars=\"$vars\"\n" if $V>2;
		} elsif ($xxx =~ /^var=(.*)/) {
			$vars .= ',' . $1;
			print "<br>#   vars=\"$vars\"\n" if $V>2;
		} elsif ($xxx =~ /^format=(.*)/) {
			print "<br>#   format=\"$1\"\n" if $V>1;
			&format($1);
		}
	}
} else {
	print "<br>#	\@in is empty.\n" if $V>2;
}

if ($fmt eq 'T') {
	print "<br>#	Before snmpTable.pm ...\n" if $V>2;
	require "snmpTable.pm";
	print "<br>#	After snmpTable.pm ...\n" if $V>2;
} else {
	print "<br>#	Before snmpList.pm ...\n" if $V>2;
	require "snmpList.pm";
	print "<br>#	After snmpList.pm ...\n" if $V>2;
}
print "<br>#	\$vars=(", $vars, ")\n" if $V>2;

for (split(/[^\w.]+/,$vars)) {
	push(@vars,$1) if (/([\w.]+)/);
	print "<br>#	\@vars=(", @vars, ")\n" if $V>2;
}
print "<dl compact>\n" if $fmt eq 'L';
@vars = ('system') if !@vars;
&proc_snmp;

for $var (@vars) {
	print "<br>#	var=\"$var\"\n" if $V>2;
	$var =~ s/^\.+//;
	if (@flds  = split(/\./,$var)) {
		print "<br>#	flds=(@flds)\n" if $V>2;
		if ($#flds < 1) {
			$flds[1] = 0;
			print "<br>#	flds=(@flds)\n" if $V>2;
		}
		&get(@flds);
	}
}
print "</dl>\n" if $fmt eq 'L';
print "</body>\n";
print "</html>\n";

exit 0;
