<?php # Copyright(C) 2004-2006 INL # Written by Eric Leblond <regit@inl.fr> # Vincent Deffontaines <gryzor@inl.fr> # Jean Gillaux <jean@inl.fr> # Damien Boucard <damien.boucard AT inl.fr> # # $Id: index_func.php 17927 2009-02-16 13:16:09Z haypo $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, version 3 of the License. # # 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, see <http://www.gnu.org/licenses/>. require_once('desc.class.php'); require_once('ruleset.class.php'); require_once('bichain.php'); function generate_firewall_rules($ruleset_filename) { global $nuface_dir, $network_desc_file, $datadir, $support_duplication; if (!check_filename($ruleset_filename)) { log_error(sprintf(_('Invalid filename: "%s".'), $ruleset_filename)); return null; } $desc_mtime = filemtime("$nuface_dir/$network_desc_file"); $ruleset_mtime = filemtime("$datadir/$ruleset_filename"); if ($desc_mtime > $ruleset_mtime) { log_error(sprintf( _('The networks definition is more recent than the ruleset: try to load and then save the ruleset "%s"!'), filenameWithoutXml($ruleset_filename))); return null; } // Load ruleset to make sure that it's consistent $ruleset = read_ruleset_file($ruleset_filename); if (!$ruleset) return null; // Check that networks definition exists in the ruleset $used_desc = find_build_desc($ruleset, false); if (is_null($used_desc)) { log_error(sprintf( _('Error: unable to find used networks definition: try to load and then save the ruleset "%s"!'), $ruleset->name)); return null; } // Execute nupyf, nuperiod and nulayer7 $ok = execute_nupyf_and_friends($ruleset_filename, $used_desc); if (!$ok) { log_error(_('Firewall rules were not updated!')); return null; } rename_firewall_files(); return $ruleset; } function execute_nupyf_and_friends($ruleset_filename, $used_desc) { global $l7_firewall; $ok = execute_nupyf($ruleset_filename, $used_desc); if (!$ok) return false; $ok = execute_nuperiod($ruleset_filename); if (!$ok) return false; $l7_filename = remove_layer7_rules(); if ($l7_firewall) { $ok = execute_nulayer7($ruleset_filename, $l7_filename); if (!$ok) return false; } return true; } function execute_nupyf($file, $used_desc) { global $nufw_firewall; global $etc_dir, $datadir, $nuface_dir, $rules_dir, $std_rules_dir, $nufw_rules_dir; global $nupyf_command, $nupyf_conf_file, $nupyf_ldap_file, $network_desc_file; $desc_file = "$nuface_dir/$network_desc_file"; $input_rules = 'input_rules.tmp'; $output_rules = 'output_rules.tmp'; $nat_rules = 'nat_rules.tmp'; $mangle_rules = 'mangle_rules.tmp'; $nupyf_args = gen_nupyf_args($nufw_rules_dir, 'dispatch_targets.tmp', 'default_estrel_invalid.tmp','dispatch_rules.tmp', 'forward_rules.tmp', $input_rules, $output_rules, $nat_rules, false, $mangle_rules); $nupyf_args.= " --sortid $used_desc"; if ($nufw_firewall) { $nufw_cmd = $nupyf_command . $nupyf_args; $nufw_cmd .= " --conf ".$etc_dir."/".$nupyf_conf_file; $nufw_cmd .= " --dumpldap ".$rules_dir."/".$nupyf_ldap_file; $nufw_cmd .= " ".$desc_file; $nufw_cmd .= " ".$datadir."/".$file; if (!nupyf($nufw_cmd)) return false; } //generate rescue rules $nupyf_args = gen_nupyf_args($std_rules_dir, 'dispatch_targets.tmp', 'default_estrel_invalid.tmp', 'dispatch_rules.tmp', 'forward_rules.tmp', $input_rules, $output_rules, $nat_rules, true, $mangle_rules); $nupyf_args.= " --sortid $used_desc"; $nupyf_cmd = $nupyf_command.$nupyf_args." $desc_file $datadir/$file"; if (!nupyf($nupyf_cmd)) return false; return true; } function nupyf($command) { global $debug_nuface; $stdout = report_execute($command, $exit_code); if ($exit_code!=0) { /* display specific error messages */ log_error(_('Error of nupyf program:')); add_log_pre($stdout); return false; } else if ($debug_nuface and $stdout) { add_log(_('Output of nupyf program:')); add_log_pre($stdout); } return true; } function remove_layer7_rules() { global $rules_dir; $l7_rules = $rules_dir."/".'l7_rules'; if (file_exists($l7_rules) and (!unlink($l7_rules))) { add_log(sprintf(_('Warning: could not delete file "%s".'), $l7_rules)); } $l7_rules_tmp = $l7_rules.'.tmp'; if (file_exists($l7_rules_tmp) and (!unlink($l7_rules_tmp))) { add_log(sprintf(_('Warning: could not delete file "%s".'), $l7_rules_tmp)); } return $l7_rules_tmp; } function execute_nulayer7($file, $output_filename) { global $l7_command, $datadir; $l7_cmd = $l7_command." --output=$output_filename $datadir/$file"; $l7_res = report_execute ($l7_cmd, $result0); if ($result0 != 0) { /* display specific error messages */ log_error(_('Error of nulayer7 program:')); add_log_pre($l7_res); return false; } return true; } function execute_nuperiod($file) { global $rules_dir, $datadir, $nuperiod_command; global $periods_file; # FIXME: Remove this global variable! /* run nuperiod to generate nuauth xml periods file */ $periods_file = $rules_dir.'/periods.xml.tmp'; $nuperiod_cmd = "$nuperiod_command -f $datadir/$file -o $periods_file"; $nuperiod_res = report_execute($nuperiod_cmd, $result_periods); if ($result_periods != 0) { log_error(_('Error of nuperiod program:')); add_log_pre($nuperiod_res); return false; } return true; } function rename_firewall_files() { global $rules_dir, $nufw_rules_dir, $std_rules_dir, $support_duplication; rename_if_exists("$rules_dir/l7_rules.tmp","$rules_dir/l7_rules"); foreach(array($nufw_rules_dir,$std_rules_dir) as $the_dir){ rename_if_exists("$the_dir/nat_rules.tmp","$the_dir/nat_rules"); rename_if_exists("$the_dir/dispatch_targets.tmp","$the_dir/dispatch_targets"); rename_if_exists("$the_dir/default_estrel_invalid.tmp","$the_dir/default_estrel_invalid"); rename_if_exists("$the_dir/dispatch_rules.tmp","$the_dir/dispatch_rules"); rename_if_exists("$the_dir/forward_rules.tmp","$the_dir/forward_rules"); rename_if_exists("$the_dir/input_rules.tmp","$the_dir/input_rules"); rename_if_exists("$the_dir/output_rules.tmp","$the_dir/output_rules"); rename_if_exists("$the_dir/mangle_rules.tmp","$the_dir/mangle_rules"); } rename_if_exists("$rules_dir/periods.xml.tmp","$rules_dir/periods.xml"); } function apply_firewall_rules($ruleset, $with_nufw) { global $nufw_firewall; global $rules_dir; global $sudo_command; global $firewall_script; global $sync_enabled; global $debug_nuface; if ($nufw_firewall and $with_nufw) { $farg = 'nufw'; } else { $farg = 'nonufw'; } if ($sync_enabled) { if( sync_firewall_rules($ruleset, $farg)) { add_log(sprintf( _('The firewall rules "%s" were successfully propagated.'), $ruleset->name)); }else{ log_error(sprintf( _('The firewall rules "%s" could not be propagated!'), $ruleset->name)); add_log_pre($ret); return; } } $cmd = "$sudo_command $firewall_script $farg"; if ($debug_nuface) $cmd .= ' --debug'; $ret = report_execute($cmd,$result); if ($result!=0) { log_error(sprintf( _('The firewall rules "%s" could not be applied!'), $ruleset->name)); add_log_pre($ret); return; } if ($nufw_firewall and !$with_nufw) { add_log(sprintf( _('The firewall rules "%s" (without NuFW authentication) were successfully applied.'), $ruleset->name)); } else { add_log(sprintf( _('The firewall rules "%s" were successfully applied.'), $ruleset->name)); } } function sync_firewall_rules($ruleset, $farg) { global $rules_dir; global $sudo_command; global $sync_user; global $sync_script; global $sync_remote_rules_dir; global $sync_remote_sudo_command; global $sync_remote_firewall_script; global $sync_stop_apply_on_fail; global $sync_hosts; foreach ($sync_hosts as $index=>$host) { // Check host name $hostname = array_get($host, 'hostname'); if (!$hostname) { log_error(sprintf( _('Hostname is not set in $host number %s!'), $index)); if ($sync_stop_apply_on_fail) return false; else continue; } // Set default values $host = array_merge(Array( 'user' => $sync_user, 'remote_rules_dir' => $rules_dir, 'remote_sudo_command' => $sudo_command, 'remote_firewall_script' => $sync_remote_firewall_script, ), $host); // Create the command line $cmd = array_map('escapeshellarg', Array( $rules_dir, $host['user'], $hostname, $host['remote_rules_dir'], $host['remote_sudo_command'], $host['remote_firewall_script'], $farg )); $cmd = escapeshellcmd($sync_script).' '.implode(' ', $cmd); // Run remote command $stdout = report_execute($cmd, $result); if ($result != 0) { log_error(sprintf( _('The firewall rules "%s" on host "%s" could not be propagated!'), $ruleset->name, $hostname)); add_log_pre($stdout); if ($sync_stop_apply_on_fail) return false; else continue; } add_log(sprintf( _('The firewall rules "%s" on host "%s" were successfully propagated.'), $ruleset->name, $hostname)); } return true; } function firewall_rules($ruleset_filename) { global $apply_firewall_rules; if (getHttp('save_ruleset') == 1) { // Load ruleset $ruleset = getSession('document'); if (!$ruleset) { log_error(_("Unable to retrieve active ruleset! Your session may have expired.")); return; } // Save ruleset $filename = basename($ruleset->filename); $result = write_ruleset_file($ruleset, $filename); if (!$result) return; } $with_nufw = getHttpCheckbox('with_nufw'); $ruleset = generate_firewall_rules($ruleset_filename); if (!$ruleset) { return; } if ($apply_firewall_rules) { apply_firewall_rules($ruleset, $with_nufw); } else { log_error(_("Warning: Don't apply firewall rules (disabled in NuFace configuration).")); } } function copyUserXML($file) { global $datadir; $basename = basename($file['name']); if (!check_filename($basename)) { log_error(sprintf(_('Invalid filename: "%s".'), $basename)); return false; } $dest = $datadir . "/" . $basename; if (file_exists($dest)) { $name = filenameWithoutXml($basename); log_error (sprintf(_('Sorry, a ruleset called "%s" already exists.'), $name)); return false; } $ok = @move_uploaded_file($file['tmp_name'], $dest); if (!$ok) { log_error(sprintf(_('Unable to copy uploaded file "%s"!'), $basename)); return false; } return true; } function validateUserXML($file) { if (basename($file['name'],'.xml') == $file['name']) { add_log(_('The file is not in an XML document!')); return false; } if ($file['type'] != '' && $file['type'] != 'text/xml') { add_log(_('The file is not in an XML document!')); return false; } try { $policy = new policy($file['tmp_name'], false, $file['name']); } catch (Exception $err) { log_exception($err); return false; } return true; } function uploadUserXML() { global $tmpdir; $file = getFile('userfile'); if (!$file) { // no file uploaded, just exit return; } if (validateUserXML($file)) { $ok = copyUserXML($file); if ($ok) { $name = basename($file['name']); $name = filenameWithoutXml($name); add_log(sprintf(_('The ruleset "%s" was correctly uploaded.'), $name)); } } if(file_exists($file['tmp_name'])) unlink($file['tmp_name']); } function loadNewRuleset() { global $datadir; $filename = "$datadir/fixed/empty.xml"; try { $policy = new policy($filename); $policy->name = sprintf("[%s]", _("template")); $policy->filename = null; handleLoadedDocument($policy); } catch (Exception $err) { $msg = sprintf(_("Unable to load ruleset file %s: %s"), $filename, $err->getMessage()); log_error($msg, $err->getTrace()); } } function loadUserXML($input) { try { return _loadUserXML($input); } catch (Exception $err) { log_exception($err); return false; } } function _loadUserXML($input) { if (!check_filename($input)) { log_error(sprintf(_('Invalid filename: "%s".'), $input)); return false; } $_SESSION['modified'] = 0; // read file includes checking on filename $document=read_ruleset_file($input); if (!$document) { log_error(sprintf(_('An error occured when reading the ruleset "%s"!'), filenameWithoutXml($input))); return false; } return handleLoadedDocument($document); } function handleLoadedDocument($document) { $descs= &$document->descs; $used_desc = find_build_desc($document); if (is_null($used_desc)) { return false; } $desc = $descs->elts[$used_desc]; $bichains = build_bichains($desc); $bichains = populate_bichains_max($bichains, $document->acls); $resources=&$document->resources; check_objects_from_desc($resources, $desc); $_SESSION['used_desc']=$used_desc; sessionSaveRuleset($document); $_SESSION['bichains']=serialize($bichains); check_acls_order_scheme($document->acls); recompute_all_descsorts($document, $desc); // Let us check at least one group exists. If not, let us create it $groups = &$document->groups; if ((!isset($groups)) or ($groups->elts == array())) { $new_group = array(); $new_group{'name'} = 'default'; $new_group{'enabled'} = 1; $new_group{'comment'} = ''; $group=new group($new_group,'data',$groups->new_id()); $groups->add_elt($group); } if (! $document){ display_openfile_menu(); }else{ sessionSaveRuleset($document); if ($document->name) { add_log(sprintf(_('The ruleset "%s" was successfully loaded.'), $document->name)); } else { add_log(sprintf(_('The new ruleset was successfully created.'))); } } if (complete_resources_from_desc($document,$used_desc)) { saveRuleset($document); } return true; } function writeUserXML($output) { global $datadir; $ruleset = getSession('document'); if (!$ruleset) { return; } if (!$output) { if ($ruleset->filename) { $filename = basename($ruleset->filename); } else { $filename = 'ruleset.xml'; } $GLOBALS['USE_EXIT_NUFACE'] = false; header('Content-type: binary/data'); header('Content-Disposition: attachment; filename='.$filename); write_ruleset_file($ruleset, $output, false, false); exit(0); }else{ if (!check_filename($output)) { log_error(sprintf(_('Invalid filename: "%s".'), $output)); return; } $name = filenameWithoutXml($output); $filename = "$datadir/$output"; $save_copy = basename($ruleset->filename) != $output; if ($save_copy and file_exists($filename)) { log_error (sprintf(_('Sorry, the ruleset "%s" already exists.'), $name)); return; } if (!$ruleset->filename) { $ruleset->name = $name; $ruleset->filename = $filename; sessionSaveRuleset($ruleset); $_SESSION['modified'] = 0; } write_ruleset_file($ruleset, $output, true, !$save_copy); } } function complete_resources_from_desc(&$document,$used_desc) { $result = false; $resources = &$document->resources; $seen_nets = array(); foreach($resources->elts as $resource) { foreach ($resource->elts as $sub) { if ((isset($sub->datas['type'])) and ($sub->datas['type'] == 'ipv4') and (isset($sub->datas['net']))) { array_push($seen_nets,$sub->datas['net']); } } } $descs = $document->descs; $desc = $descs->elts[$used_desc]; $c_desc = clone($desc); $special_internet->datas['addr'] = "0.0.0.0/0"; $special_internet->datas['name'] = "INTERNET"; $special_internet->datas['dftroute'] = 0; array_push($c_desc->networks->elts, $special_internet); foreach ($c_desc->networks->elts as $desc_network) { if (!isset($desc_network->datas['addr'])) continue; // Check if this network is already defined. $seen_this = 0; foreach($seen_nets as $already_net) { if (Net_IPv4::compare($already_net, $desc_network->datas['addr'])) { $seen_this++; break; } } if ($seen_this != 0) continue; // Add the network try { $myres = array(); $myres['name'] = $desc_network->datas['name']; if ($desc_network->datas['dftroute'] == 1) { $myres['name'] .= '_interco_'.$desc_network->datas['addr']; } $new_res = new resource($myres,'toto',$resources->get_max_id()+1); $myelt = array(); $myelt['name']='ip'; $myelt['net'] = $desc_network->datas['addr']; $myelt['type'] = 'ipv4'; $new_elt = new elt($myelt,'toto',$resources->get_max_elt_id()+1); $new_res->add_elt($new_elt); $count = 1; $format = $new_res->name."-%s"; do { $found = $resources->getByName($new_res->name); if ($found) { $count += 1; $new_res->name = sprintf($format, $count); } } while ($found); add_log(sprintf(_('Create the new resource "%s" (%s) from the network description.'), $new_res->name, $myelt['net'])); $resources->add_elt($new_res); $result = true; } catch (Exception $err) { log_exception($err); $result = false; } } array_pop($c_desc->networks->elts); return($result); } ?>