if ($cgiparams{'RULESET'}) {
## Grab all available rules and store them in the idsrules hash.
#
+
+ # Get enabled providers.
+ my @enabled_providers = &IDS::get_enabled_providers();
+
# Open rules directory and do a directory listing.
opendir(DIR, $IDS::rulespath) or die $!;
# Loop through the direcory.
# Skip whitelist rules file.
next if( $file eq "whitelist.rules");
+ # Splitt vendor from filename.
+ my @filename_parts = split(/-/, $file);
+
+ # Assign vendor name for easy processing.
+ my $vendor = @filename_parts[0];
+
+ # Skip rulefile if the provider is disabled.
+ next unless ($vendor ~~ @enabled_providers);
+
# Call subfunction to read-in rulefile and add rules to
# the idsrules hash.
&readrulesfile("$file");
closedir(DIR);
- # Gather used rulefiles.
- #
- # Check if the file for activated rulefiles is not empty.
- if(-f $IDS::used_rulefiles_file) {
- # Open the file for used rulefile and read-in content.
- open(FILE, $IDS::used_rulefiles_file) or die "Could not open $IDS::used_rulefiles_file. $!\n";
-
- # Read-in content.
- my @lines = <FILE>;
-
- # Close file.
- close(FILE);
-
- # Loop through the array.
- foreach my $line (@lines) {
- # Remove newlines.
- chomp($line);
-
- # Skip comments.
- next if ($line =~ /\#/);
-
- # Skip blank lines.
- next if ($line =~ /^\s*$/);
-
- # Gather rule sid and message from the ruleline.
- if ($line =~ /.*- (.*)/) {
- my $rulefile = $1;
-
- # Check if the current rulefile exists in the %idsrules hash.
- # If not, the file probably does not exist anymore or contains
- # no rules.
- if($idsrules{$rulefile}) {
- # Add the rulefile state to the %idsrules hash.
- $idsrules{$rulefile}{'Rulefile'}{'State'} = "on";
- }
+ # Loop through the array of used providers.
+ foreach my $provider (@enabled_providers) {
+ # Gather used rulefiles.
+ my @used_rulesfiles = &IDS::read_used_provider_rulesfiles($provider);
+
+ # Loop through the array of used rulesfiles.
+ foreach my $rulefile (@used_rulesfiles) {
+ # Check if the current rulefile exists in the %idsrules hash.
+ # If not, the file probably does not exist anymore or contains
+ # no rules.
+ if($idsrules{$rulefile}) {
+ # Add the rulefile state to the %idsrules hash.
+ $idsrules{$rulefile}{'Rulefile'}{'State'} = "on";
}
}
}
}
-# Save ruleset configuration.
-if ($cgiparams{'RULESET'} eq $Lang::tr{'save'}) {
- my %oldsettings;
-
- # Read-in current (old) IDS settings.
- &General::readhash("$IDS::rules_settings_file", \%oldsettings);
-
- # Prevent form name from been stored in conf file.
- delete $cgiparams{'RULESET'};
-
- # Check if the choosen vendor (URL) requires an subscription/oinkcode.
- if ($IDS::Ruleset::Providers{$cgiparams{'RULES'}}{'requires_subscription'} eq "True") {
- # Check if an subscription/oinkcode has been provided.
- if ($cgiparams{'OINKCODE'}) {
- # Check if the oinkcode contains unallowed chars.
- unless ($cgiparams{'OINKCODE'} =~ /^[a-z0-9]+$/) {
- $errormessage = $Lang::tr{'invalid input for oink code'};
- }
- } else {
- # Print an error message, that an subsription/oinkcode is required for this
- # vendor.
- $errormessage = $Lang::tr{'ids oinkcode required'};
- }
- }
-
- # Go on if there are no error messages.
- if (!$errormessage) {
- # Store settings into settings file.
- &General::writehash("$IDS::rules_settings_file", \%cgiparams);
-
- # Check if a ruleset is present - if not or the source has been changed download it.
- if((! %idsrules) || ($oldsettings{'RULES'} ne $cgiparams{'RULES'})) {
- # Check if the red device is active.
- unless (-e "${General::swroot}/red/active") {
- $errormessage = "$Lang::tr{'could not download latest updates'} - $Lang::tr{'system is offline'}";
- }
-
- # Check if enough free disk space is availabe.
- if(&IDS::checkdiskspace()) {
- $errormessage = "$Lang::tr{'not enough disk space'}";
- }
-
- # Check if any errors happend.
- unless ($errormessage) {
- # Lock the webpage and print notice about downloading
- # a new ruleset.
- &working_notice("$Lang::tr{'ids working'}");
-
- # Write the modify sid's file and pass the taken ruleaction.
- &IDS::write_modify_sids_file();
-
- # Call subfunction to download the ruleset.
- if(&IDS::downloadruleset()) {
- $errormessage = $Lang::tr{'could not download latest updates'};
-
- # Call function to store the errormessage.
- &IDS::_store_error_message($errormessage);
- } else {
- # Call subfunction to launch oinkmaster.
- &IDS::oinkmaster();
- }
-
- # Check if the IDS is running.
- if(&IDS::ids_is_running()) {
- # Call suricatactrl to stop the IDS - because of the changed
- # ruleset - the use has to configure it before suricata can be
- # used again.
- &IDS::call_suricatactrl("stop");
- }
-
- # Perform a reload of the page.
- &reload();
- }
- }
- }
-
# Save ruleset.
-} elsif ($cgiparams{'RULESET'} eq $Lang::tr{'ids apply'}) {
+if ($cgiparams{'RULESET'} eq $Lang::tr{'ids apply'}) {
# Arrays to store which rulefiles have been enabled and will be used.
my @enabled_rulefiles;
- # Hash to store the user-enabled and disabled sids.
- my %enabled_disabled_sids;
-
# Store if a restart of suricata is required.
my $suricata_restart_required;
}
}
- # Read-in the files for enabled/disabled sids.
- # This will be done by calling the read_enabled_disabled_sids_file function two times
- # and merge the returned hashes together into the enabled_disabled_sids hash.
- %enabled_disabled_sids = (
- &read_enabled_disabled_sids_file($IDS::disabled_sids_file),
- &read_enabled_disabled_sids_file($IDS::enabled_sids_file));
+ # Open oinkmaster main include file for provider modifications.
+ open(OINKM_INCL_FILE, ">", "$IDS::oinkmaster_provider_includes_file") or die "Could not open $IDS::oinkmaster_provider_includes_file. $!\n";
- # Loop through the hash of idsrules.
- foreach my $rulefile (keys %idsrules) {
- # Loop through the single rules of the rulefile.
- foreach my $sid (keys %{$idsrules{$rulefile}}) {
- # Skip the current sid if it is not numeric.
- next unless ($sid =~ /\d+/ );
-
- # Check if there exists a key in the cgiparams hash for this sid.
- if (exists($cgiparams{$sid})) {
- # Look if the rule is disabled.
- if ($idsrules{$rulefile}{$sid}{'State'} eq "off") {
- # Check if the state has been set to 'on'.
- if ($cgiparams{$sid} eq "on") {
- # Add/Modify the sid to/in the enabled_disabled_sids hash.
- $enabled_disabled_sids{$sid} = "enabled";
+ # Print file header and notice about autogenerated file.
+ print OINKM_INCL_FILE "#Autogenerated file. Any custom changes will be overwritten!\n";
+
+ # Get enabled providers.
+ my @enabled_providers = &IDS::get_enabled_providers();
+
+ # Loop through the array of enabled providers.
+ foreach my $provider (@enabled_providers) {
+ # Hash to store the used-enabled and disabled sids.
+ my %enabled_disabled_sids;
+
+ # Generate modified sids file name for the current processed provider.
+ my $providers_modified_sids_file = "$IDS::settingsdir/oinkmaster-$provider-modified-sids.conf";
+
+ # Check if a modified sids file for this provider exists.
+ if (-f $providers_modified_sids_file) {
+ # Read-in the file for enabled/disabled sids.
+ %enabled_disabled_sids = &read_enabled_disabled_sids_file($providers_modified_sids_file);
+ }
+
+ # Loop through the hash of idsrules.
+ foreach my $rulefile (keys %idsrules) {
+ # Split the rulefile to get the vendor.
+ my @filename_parts = split(/-/, $rulefile);
+
+ # Assign rulefile vendor.
+ my $rulefile_vendor = @filename_parts[0];
+
+ # Skip the rulefile if the vendor is not our current processed provider.
+ next unless ($rulefile_vendor eq $provider);
+
+ # Loop through the single rules of the rulefile.
+ foreach my $sid (keys %{$idsrules{$rulefile}}) {
+ # Skip the current sid if it is not numeric.
+ next unless ($sid =~ /\d+/ );
+
+ # Check if there exists a key in the cgiparams hash for this sid.
+ if (exists($cgiparams{$sid})) {
+ # Look if the rule is disabled.
+ if ($idsrules{$rulefile}{$sid}{'State'} eq "off") {
+ # Check if the state has been set to 'on'.
+ if ($cgiparams{$sid} eq "on") {
+ # Add/Modify the sid to/in the enabled_disabled_sids hash.
+ $enabled_disabled_sids{$sid} = "enabled";
+
+ # Drop item from cgiparams hash.
+ delete $cgiparams{$rulefile}{$sid};
+ }
+ }
+ } else {
+ # Look if the rule is enabled.
+ if ($idsrules{$rulefile}{$sid}{'State'} eq "on") {
+ # Check if the state is 'on' and should be disabled.
+ # In this case there is no entry
+ # for the sid in the cgiparams hash.
+ # Add/Modify it to/in the enabled_disabled_sids hash.
+ $enabled_disabled_sids{$sid} = "disabled";
# Drop item from cgiparams hash.
delete $cgiparams{$rulefile}{$sid};
}
}
- } else {
- # Look if the rule is enabled.
- if ($idsrules{$rulefile}{$sid}{'State'} eq "on") {
- # Check if the state is 'on' and should be disabled.
- # In this case there is no entry
- # for the sid in the cgiparams hash.
- # Add/Modify it to/in the enabled_disabled_sids hash.
- $enabled_disabled_sids{$sid} = "disabled";
-
- # Drop item from cgiparams hash.
- delete $cgiparams{$rulefile}{$sid};
- }
}
}
- }
- # Open enabled sid's file for writing.
- open(ENABLED_FILE, ">$IDS::enabled_sids_file") or die "Could not write to $IDS::enabled_sids_file. $!\n";
-
- # Open disabled sid's file for writing.
- open(DISABLED_FILE, ">$IDS::disabled_sids_file") or die "Could not write to $IDS::disabled_sids_file. $!\n";
-
- # Write header to the files.
- print ENABLED_FILE "#Autogenerated file. Any custom changes will be overwritten!\n";
- print DISABLED_FILE "#Autogenerated file. Any custom changes will be overwritten!\n";
-
- # Check if the hash for enabled/disabled files contains any entries.
- if (%enabled_disabled_sids) {
- # Loop through the hash.
- foreach my $sid (keys %enabled_disabled_sids) {
- # Check if the sid is enabled.
- if ($enabled_disabled_sids{$sid} eq "enabled") {
- # Print the sid to the enabled_sids file.
- print ENABLED_FILE "enablesid $sid\n";
- # Check if the sid is disabled.
- } elsif ($enabled_disabled_sids{$sid} eq "disabled") {
- # Print the sid to the disabled_sids file.
- print DISABLED_FILE "disablesid $sid\n";
- # Something strange happende - skip the current sid.
- } else {
- next;
+ # Check if the hash for enabled/disabled sids contains any entries.
+ if (%enabled_disabled_sids) {
+ # Open providers modified sids file for writing.
+ open(PROVIDER_MOD_FILE, ">$providers_modified_sids_file") or die "Could not write to $providers_modified_sids_file. $!\n";
+
+ # Write header to the files.
+ print PROVIDER_MOD_FILE "#Autogenerated file. Any custom changes will be overwritten!\n";
+
+ # Loop through the hash.
+ foreach my $sid (keys %enabled_disabled_sids) {
+ # Check if the sid is enabled.
+ if ($enabled_disabled_sids{$sid} eq "enabled") {
+ # Print the sid to the enabled_sids file.
+ print PROVIDER_MOD_FILE "enablesid $sid\n";
+ # Check if the sid is disabled.
+ } elsif ($enabled_disabled_sids{$sid} eq "disabled") {
+ # Print the sid to the disabled_sids file.
+ print PROVIDER_MOD_FILE "disablesid $sid\n";
+ # Something strange happende - skip the current sid.
+ } else {
+ next;
+ }
}
+
+ # Close file handle for the providers modified sids file.
+ close(PROVIDER_MOD_FILE);
+
+ # Add the file to the oinkmasters include file.
+ print OINKM_INCL_FILE "include $providers_modified_sids_file\n";
}
}
- # Close file for enabled_sids after writing.
- close(ENABLED_FILE);
+ # Close the file handle after writing.
+ close(OINKM_INCL_FILE);
+
+ # Handle enabled / disabled rulefiles.
+ #
+
+ # Loop through the array of enabled providers.
+ foreach my $provider(@enabled_providers) {
+ # Array to store the rulefiles which belong to the current processed provider.
+ my @provider_rulefiles = ();
+
+ # Loop through the array of enabled rulefiles.
+ foreach my $rulesfile (@enabled_rulefiles) {
+ # Split the rulefile name.
+ my @filename_parts = split(/-/, "$rulesfile");
- # Close file for disabled_sids after writing.
- close(DISABLED_FILE);
+ # Assign vendor name for easy processings.
+ my $vendor = @filename_parts[0];
+
+ # Check if the rulesvendor is our current processed enabled provider.
+ if ("$vendor" eq "$provider") {
+ # Add the rulesfile to the array of provider rulesfiles.
+ push(@provider_rulefiles, $rulesfile);
+ }
+
+ # Check if any rulesfiles have been found for this provider.
+ if (@provider_rulefiles) {
+ # Call function and write the providers used rulesfile file.
+ &IDS::write_used_provider_rulefiles_file($provider, @provider_rulefiles);
+ }
+ }
+ }
# Call function to generate and write the used rulefiles file.
- &IDS::write_used_rulefiles_file(@enabled_rulefiles);
+ &IDS::write_main_used_rulefiles_file(@enabled_providers);
# Lock the webpage and print message.
&working_notice("$Lang::tr{'ids apply ruleset changes'}");
# Check if the IDS should be enabled.
if ($cgiparams{'ENABLE_IDS'} eq "on") {
+ # Get enabled providers.
+ my @enabled_providers = &IDS::get_enabled_providers();
+
# Check if any ruleset is available. Otherwise abort and display an error.
- unless(%used_providers) {
- $errormessage = $Lang::tr{'ids no ruleset available'};
+ unless(@enabled_providers) {
+ $errormessage = $Lang::tr{'ids no enabled ruleset provider'};
}
# Loop through the array of available interfaces.
foreach my $id ( keys %used_providers) {
# Check if the choosen provider is already in use.
if ($used_providers{$id}[0] eq "$provider") {
- # XXX - add to language file.
# Assign error message.
- $errormessage = "The choosen provider is already in use.";
+ $errormessage = "$Lang::tr{'ids the choosen provider is already in use'}";
}
}
}
# Write the changed hash to the providers settings file.
&General::writehasharray($IDS::providers_settings_file, \%used_providers);
+ # Check if a new provider will be added.
+ if ($cgiparams{'PROVIDERS'} eq $Lang::tr{'add'}) {
+ # Lock the webpage and print notice about downloading
+ # a new ruleset.
+ &working_notice("$Lang::tr{'ids working'}");
+
+ # Download the ruleset.
+ &IDS::downloadruleset($provider);
+
+ # Extract the ruleset
+ &IDS::extractruleset($provider);
+
+ # Move the ruleset.
+ &IDS::move_tmp_ruleset();
+
+ # Cleanup temporary directory.
+ &IDS::cleanup_tmp_directory();
+
+ # Create new empty file for used rulefiles
+ # for this provider.
+ &IDS::write_used_provider_rulefiles_file($provider);
+
+ # Perform a reload of the page.
+ &reload();
+ }
+
# Undefine providers flag.
undef($cgiparams{'PROVIDERS'});
}
# Write the changed hash to the providers settings file.
&General::writehasharray($IDS::providers_settings_file, \%used_providers);
- # XXX - The ruleset needs to be regenerated
- # XXX - Suricata requires a reload or if the last provider
- # has been disabled suricata needs to be stopped.
+ # Get all enabled providers.
+ my @enabled_providers = &IDS::get_enabled_providers();
+
+ # Write the main providers include file.
+ &IDS::write_main_used_rulefiles_file(@enabled_providers);
+
# Check if the IDS is running.
- #if(&IDS::ids_is_running()) {
- # # Call suricatactrl to perform a reload.
- # &IDS::call_suricatactrl("reload");
- #}
+ if(&IDS::ids_is_running()) {
+ # Gather the amount of enabled providers (elements in the array).
+ my $amount = @enabled_providers;
+
+ # Check if there are still enabled ruleset providers.
+ if ($amount >= 1) {
+ # Call suricatactrl to perform a restart.
+ &IDS::call_suricatactrl("restart");
+
+ # No active ruleset provider, suricata has to be stopped.
+ } else {
+ # Stop suricata.
+ &IDS::call_suricatactrl("stop");
+ }
+ }
# Undefine providers flag.
undef($cgiparams{'PROVIDERS'});
# Read-in provider settings file.
&General::readhasharray($IDS::providers_settings_file, \%used_providers);
+ # Grab the provider name bevore deleting it from hash.
+ my $provider = $used_providers{$cgiparams{'ID'}}[0];
+
# Drop entry from the hash.
delete($used_providers{$cgiparams{'ID'}});
# Write the changed hash to the provide settings file.
&General::writehasharray($IDS::providers_settings_file, \%used_providers);
- # XXX - The ruleset of the provider needs to be dropped.
- # XXX - The remain rulest of suricata needs to be regenerated.
- # XXX - Suricata requires a reload or if the last provider has
- # been removed it has to be stopped.
+ # Lock the webpage and print message.
+ &working_notice("$Lang::tr{'ids apply ruleset changes'}");
+
+ # Drop the stored ruleset file.
+ &IDS::drop_dl_rulesfile($provider);
+
+ # Get the name of the provider rulessets include file.
+ my $provider_used_rulefile = &get_used_provider_rulesfile_file($provider);
+
+ # Drop the file, it is not longer needed.
+ unlink("$provider_used_rulefile");
+
+ # Regenerate ruleset.
+ &IDS::oinkmaster();
+
+ # Gather all enabled providers.
+ my @enabled_providers = &IDS::get_enabled_providers();
+
+ # Regenerate main providers include file.
+ &IDS::write_main_used_rulefiles_file(@enabled_providers);
+
# Check if the IDS is running.
- #if(&IDS::ids_is_running()) {
- # Call suricatactrl to perform a reload.
- # &IDS::call_suricatactrl("reload");
- #}
+ if(&IDS::ids_is_running()) {
+ # Get amount of enabled providers.
+ my $amount = @enabled_providers;
+
+ # Check if at least one enabled provider remains.
+ if ($amount >= 1) {
+ # Call suricatactrl to perform a reload.
+ &IDS::call_suricatactrl("restart");
+
+ # Stop suricata if no enabled provider remains.
+ } else {
+ # Call suricatactrel to perform the stop.
+ &IDS::call_suricatactrl("stop");
+ }
+ }
# Undefine providers flag.
undef($cgiparams{'PROVIDERS'});
+
+ # Reload page.
+ &reload();
}
&Header::openpage($Lang::tr{'intrusion detection system'}, 1, '');
# Assign data array positions to some nice variable names.
my $provider = $used_providers{$id}[0];
my $provider_name = &get_provider_name($provider);
-
- #XXX my $rulesdate = &IDS::get_ruleset_date($provider);
- my $rulesdate;
+ my $rulesetdate = &IDS::get_ruleset_date($provider);
my $subscription_code = $used_providers{$id}[1];
my $autoupdate_status = $used_providers{$id}[2];
print <<END;
<tr>
<td width='33%' class='base' $col>$provider_name</td>
- <td width='30%' class='base' $col>$rulesdate</td>
+ <td width='30%' class='base' $col>$rulesetdate</td>
<td align='center' $col>
<form method='post' action='$ENV{'SCRIPT_NAME'}'>
<tr>
<td width='40%'>
<input type='hidden' name='ID' value='$cgiparams{'ID'}'>
- <select name='PROVIDER' id='PROVIDER'>
END
;
+ # Value to allow disabling the dropdown menu.
+ my $disabled;
+
+ # Check if we are in edit mode.
+ if ($cgiparams{'PROVIDERS'} eq "$Lang::tr{'edit'}") {
+ $disabled = "disabled";
+
+ # Add hidden input with the provider because the disable select does not provider
+ # this.
+ print "<input type='hidden' name='PROVIDER' value='$used_providers{$cgiparams{'ID'}}[0]'>\n";
+ }
+
+ print "<select name='PROVIDER' id='PROVIDER' $disabled>\n";
# Loop through the array of ruleset providers.
foreach my $provider (@ruleset_providers) {
# Get the provider name.