#!/usr/bin/perl
#
# $Id: updateplugins.pl,v 1.4 2004/11/24 02:53:26 greg_k Exp $
#

################################################################################
#			      Last update: 09.10.2004			      #
#-----------------------------------------------------------------------------#
#				     Inprotect				      #
#-----------------------------------------------------------------------------#
# Copyright (C) 2002 - 2004 Inprotect.com				      #
#									      #
# This program is free software; you can redistribute it and/or modify it     #
# under the terms of version 2 of the GNU General Public License as published #
# by the Free Software Foundation.					      #
#									      #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    #
# more details.								      #
#									      #
# You should have received a copy of the GNU General Public License along     #
# with this program; if not, write to the Free Software Foundation, Inc.,     #
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA			      #
#									      #
# Contact Information:							      #
# Alex Zimin (alex@inprotect.com)					      #
# http://www.inprotect.com						      #
###############################################################################
# See the README.txt and/or help files for more information on how to use &   #
# configuration.							      #
# See the LICENSE.txt file for more information on the License this software  #
# is distributed under.							      #
#									      #
# This program is intended for use in an authorized manner only, and the      #
# author can not be held liable for anything done with this program, code, or #
# items discovered with this program's use.				      #
###############################################################################

use DBI;

use vars qw/%CONFIG/;

&load_configs;

#Redirect output to the log file
my $updatepluginslog = "$CONFIG{'UPDATEPLUGINSLOG'}";
my $updateplugins="$CONFIG{'UPDATEPLUGINSTABLE'}";
open(LOG,">>$updatepluginslog") or die "Failed to create $updatepluginslog: $!\n";
*STDERR=*LOG;
*STDOUT=*LOG;

my($nessususer, $nessuspassw, $nessussvr, $nessusport, $nessusdb, $nessustable, $tempfile, $sid, $sautoenable, $status, $statusvalue, $serverid);

#Update these variables:
$serverid = "$CONFIG{'SERVERID'}";			#Nessus server id 
$nessustable = "nessus_plugins";			#Final table with Nessus plugins
$dbusername = "$CONFIG{'DATABASEUSER'}"; 		#Username to connect to database
$dbpass = "$CONFIG{'DATABASEPASSWORD'}";		#Password to connect to database
$dbdsn = "$CONFIG{'DATABASEDSN'}";			#Database DSN
$tempfile = "$CONFIG{'OUTDIR'}/plugins.sql";		#Temp Nessus plugins file

my ($risk, $dbh, $sth_ins, $sth_upd, $sth_sel2, $sth_sel3, $sth_selc, $sth_self, $sth_insc, $sth_insf, $catid, $setid, $plugincount, $pid, $pname, $pfamily, $pcategory, $pcopyright, $psummary, $pdescription, $pversion, $pcve_id,$pluginversion, $pbugtraq_id);

my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst);
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);

$year+=1900;
my $now;
$mon++;
if ($mon<10){ $mon="0".$mon;};
if ($mday<10) { $mday="0".$mday;};
if ($hour<10){ $hour="0".$hour;};
if ($min<10){ $min="0".$min;};
if ($sec<10){ $sec="0".$sec;}; $now=$year.$mon.$mday.$hour.$min.$sec;

main();
close LOG;
exit(0);

sub main {

	#Establish db connection
	$dbh=conn_db();

	#Select server attributes
	$sth = $dbh->prepare(qq{
		SELECT hostname, port, user, password
		FROM nessus_servers
		WHERE id=$serverid
		} );
	$sth->execute;
	($nessussvr, $nessusport, $nessususer, $nessuspassw)=$sth->fetchrow_array;

	#Select Nessus plugins download location
	$sth = $dbh->prepare(qq{
		SELECT inprotect_url
		FROM inprotect_settings
		} );
	$sth->execute;
	my($inprotect_url)=$sth->fetchrow_array;

	#execute nessus-update-plugins
	#system ("nessus-update-plugins") == 0 or print localtime(time)." updateplugins: No new plugins installed";
	#If used patch for nessus-update-plugins, we may pass parameter on the command line.
	system ("nessus-update-plugins.141 -u $inprotect_url/nessus") == 0 or die localtime(time)." updateplugins: No new plugins installed";

	#Sleep 30 sec, allow nessusd to restart
	sleep 30;

	if ($updateplugins==1) {

		#Dump Nessus plugins info into a file
		system("$CONFIG{'NESSUSPATH'} -qxpS $nessussvr $nessusport $nessususer $nessuspassw > $tempfile");

		#Insert Nessus plugins info into db
		system ("mysql --force --user=$CONFIG{'DATABASEUSER'} --password=$CONFIG{'DATABASEPASSWORD'} --host=$CONFIG{'DATABASEHOST'} $CONFIG{'DATABASENAME'} < $tempfile");

		#Delete temporary file
		unlink $tempfile if -e $tempfile;

		#Updating family and category tables
		$sth_sel = $dbh->prepare(q{
			select distinct plugins.category
			from plugins left join nessus_category on plugins.category = nessus_category.name
			where nessus_category.id is null
			order by category
			} );
		$sth_sel->execute;

		while (my ($categoryname) = $sth_sel->fetchrow_array ) {
			$sth_ins=$dbh->prepare(qq{
				insert into nessus_category (name) values('$categoryname')
				} );
			$sth_ins->execute;

			$sth_selc=$dbh->prepare(qq{
				select id from nessus_category
				where name='$categoryname'
				} );
			$sth_selc->execute;
			($catid)=$sth_selc->fetchrow_array;

			$sth_selc=$dbh->prepare(qq{
				select distinct sid from nessus_settings_category
				} );
			$sth_selc->execute;
			while (($setid) =$sth_selc->fetchrow_array ) {
				$sth_insc=$dbh->prepare(qq{
				insert into nessus_settings_category (sid, cid, status)
				values ($setid, $catid, 1)
				} );
				$sth_insc->execute;
			}
		}
		$sth_sel = $dbh->prepare(q{
			select distinct plugins.family
			from plugins left join nessus_family on plugins.family = nessus_family.name
			where nessus_family.id is null
			order by family
			} );
		$sth_sel->execute;

		while (my ($familyname) = $sth_sel->fetchrow_array ) {
			$sth_ins=$dbh->prepare(qq{
				insert into nessus_family (name) values('$familyname')
				} );
			$sth_ins->execute;

			$sth_self=$dbh->prepare(qq{
				select id from nessus_family
				where name='$familyname'
				} );
			$sth_self->execute;

			($famid)=$sth_self->fetchrow_array;

			$sth_self=$dbh->prepare(qq{
				select distinct sid from nessus_settings_family
				} );
			$sth_self->execute;
			while (($setid) =$sth_self->fetchrow_array ) {
				$sth_insf=$dbh->prepare(qq{
				insert into nessus_settings_family (sid, fid, status)
				values ($setid, $famid, 1)
				} );
				$sth_insf->execute;
			}
		}

		#Select all plugin ids from the database
		$sth_sel = $dbh->prepare(q{
			SELECT id
			FROM plugins
			} );
		$sth_sel->execute;

		while ( my ($id) = $sth_sel->fetchrow_array ) {

			$sth_sel2 = $dbh->prepare(qq{
				SELECT count(*)
				FROM $nessustable
				WHERE id=$id
			} );
			$sth_sel2->execute;

			$sth_sel3 = $dbh->prepare(qq{
				SELECT t1.id, t1.name, t2.id, t3.id, t1.copyright, t1.summary, t1.description, t1.version, t1.cve_id, t1.bugtraq_id
				FROM plugins as t1, nessus_family as t2, nessus_category as t3
				WHERE t1.id=$id and t1.family = t2.name and t1.category=t3.name
				});
			$sth_sel3->execute;

			($pid, $pname, $pfamily, $pcategory, $pcopyright, $psummary, $pdescription, $pversion, $pcve_id, $pbugtraq_id) = $sth_sel3->fetchrow_array;

			($plugincount)= $sth_sel2->fetchrow_array;
			if ($plugincount==0) {
				#INSERT new plugins into db

				$risk=7;
				$risk=1 if ($pdescription =~ "Risk factor : Serious");
				$risk=2 if ($pdescription =~ "Risk factor : High");
				$risk=3 if ($pdescription =~ "Risk factor : Medium");
				$risk=4 if ($pdescription =~ "Risk factor : Medium/Low");
				$risk=5 if ($pdescription =~ "Risk factor : Low/Medium");
				$risk=6 if ($pdescription =~ "Risk factor : Low");

				$sth_ins = $dbh->prepare("
					INSERT into $nessustable
					VALUES ($pid, 'Y','$pversion', '$now', null, null, $pcategory, $pfamily, $risk)
					");
				$sth_ins->execute;

				$sth_sel2 = $dbh->prepare(qq{
					select id, autoenable from nessus_settings
					} );
				$sth_sel2->execute;

				while (($sid, $sautoenable)=$sth_sel2->fetchrow_array) {
					$statusvalue="Y";
					if ($sautoenable eq "C") {
						$sth_sel3=$dbh->prepare(qq{
						select status from nessus_settings_category
						where sid=$sid and cid=$pcategory
						} );
						$sth_sel3->execute;
						($status)=$sth_sel3->fetchrow_array;
						if ($status ==3 or $status==4) {
							$statusvalue="N";
						}
					}
					elsif ($sautoenable eq "F") {
						$sth_sel3=$dbh->prepare(qq{
							select status from nessus_settings_family
							where sid=$sid and fid=$pfamily
							} );
						$sth_sel3->execute;
						($status)=$sth_sel3->fetchrow_array;
						if ($status ==3 or $status==4) {
							$statusvalue="N";
						}
					}
					$sth_ins=$dbh->prepare(qq{
						insert into nessus_settings_plugins
						values ($pid, $sid, '$statusvalue', $pcategory, $pfamily)
						} );
					$sth_ins->execute;
				}
			}
			#Update changed plugins info in the db
			else {
				$sth_sel2 = $dbh->prepare(qq{
					SELECT version
					FROM $nessustable
					WHERE id=$id
					} );
				$sth_sel2->execute;
				($pluginversion) = $sth_sel2->fetchrow_array;
				if ($pluginversion ne $pversion) {
					$sth_ins = $dbh->prepare("
						UPDATE $nessustable
						set version='$pversion', modified='$now' where id=$id
						");
					$sth_ins->execute;
				}
			}
		}
		#Mark obsolete plugins deleted
		$sth_sel = $dbh->prepare(qq{
			SELECT id
			FROM $nessustable
			WHERE deleted is null
			} );
		$sth_sel->execute;

		while ( ($id) = $sth_sel->fetchrow_array ) {
			$sth_sel2 = $dbh->prepare(qq{
				SELECT count(*)
				FROM plugins
				WHERE id=$id
			} );
			$sth_sel2->execute;
			($plugincount)= $sth_sel2->fetchrow_array;
			if ($plugincount==0) {
				$sth_ins = $dbh->prepare("
					UPDATE $nessustable
					set enabled='N', deleted='$now' where id=$id
					");
				$sth_ins->execute;
				$sth_ins = $dbh->prepare(qq{
					DELETE
					FROM nessus_settings_plugins
					WHERE id=$id
					});
				$sth_ins->execute;
			}
		}
		#Updating risk level info
		$sth_sel = $dbh->prepare (q{
			select id
			from nessus_plugins
			where risk=0
			});
		$sth_sel->execute;

		while (my ($pluginid) = $sth_sel->fetchrow_array ) {
			$sth_sel2=$dbh->prepare(qq{
				select description
				from plugins
				where id=$pluginid
				});
			$sth_sel2->execute;
			$pdescription=$sth_sel2->fetchrow_array;

			$risk=7;
			$risk=1 if ($pdescription =~ "Risk factor : Serious");
			$risk=2 if ($pdescription =~ "Risk factor : High");
			$risk=3 if ($pdescription =~ "Risk factor : Medium");
			$risk=4 if ($pdescription =~ "Risk factor : Medium/Low");
			$risk=5 if ($pdescription =~ "Risk factor : Low/Medium");
			$risk=6 if ($pdescription =~ "Risk factor : Low");

			$sth_upd=$dbh->prepare(qq{
				update nessus_plugins set risk=$risk
				where id=$pluginid
				});
			$sth_upd->execute;
		}
		$sth_sel->finish();
	} #end of if - do not update database

	# Cleanup statement handles
	#$sth_sel2->finish();
	$sth_sel3->finish();

	disconn_db($dbh);

	#end of main
}

sub conn_db {
	my($dbh);
	$dbh = DBI->connect("$CONFIG{'DATABASEDSN'}:$CONFIG{'DATABASENAME'}:$CONFIG{'DATABASEHOST'}","$CONFIG{'DATABASEUSER'}","$CONFIG{'DATABASEPASSWORD'}", {
	PrintError => 0,
	RaiseError => 1,
	AutoCommit => 1 } ) or die("Failed to connect : $DBI::errstr\n");
	return $dbh;
}

sub disconn_db {
	my ($dbh) = @_;
	$dbh->disconnect or die "Failed to disconnect : $DBI::errstr\n";
}

sub load_configs
{
	my $configfile="/usr/local/etc/inprotect.cfg";
	my $noconfig=0;
	open(CONF,"<$configfile") || $noconfig++;
	my @CONFILE=<CONF>;
	close(CONF);

	if ($noconfig) { print localtime(time)." updateplugins: No inprotect.cfg file found.\n"; }

	foreach my $line (@CONFILE)
	{
		$line =~ s/\#.*$//;
		chomp($line);
		$line =~ s/\s+$//;
		$line =~ s/^\s+//;
		if ($line eq "") { next; }
		my @temp=split(/=/,$line,2);
		if ($temp[0] ne "") { $CONFIG{$temp[0]}=$temp[1]; }
	}
	return;
}
