aboutsummaryrefslogtreecommitdiffstats
path: root/config/sarg
diff options
context:
space:
mode:
Diffstat (limited to 'config/sarg')
-rw-r--r--config/sarg/sarg.inc562
-rw-r--r--config/sarg/sarg.php50
-rw-r--r--config/sarg/sarg.priv.inc13
-rw-r--r--config/sarg/sarg.template811
-rw-r--r--config/sarg/sarg.xml371
-rwxr-xr-xconfig/sarg/sarg_about.php103
-rwxr-xr-xconfig/sarg/sarg_frame.php81
-rwxr-xr-xconfig/sarg/sarg_realtime.php258
-rwxr-xr-xconfig/sarg/sarg_reports.php93
-rw-r--r--config/sarg/sarg_schedule.xml224
-rw-r--r--config/sarg/sarg_sorttable.js493
-rwxr-xr-xconfig/sarg/sarg_sync.xml124
-rw-r--r--config/sarg/sarg_users.xml219
13 files changed, 3402 insertions, 0 deletions
diff --git a/config/sarg/sarg.inc b/config/sarg/sarg.inc
new file mode 100644
index 00000000..5d0a91a5
--- /dev/null
+++ b/config/sarg/sarg.inc
@@ -0,0 +1,562 @@
+<?php
+/* ========================================================================== */
+/*
+ sarg.inc
+ part of pfSense (http://www.pfSense.com)
+ Copyright (C) 2007 Joao Henrique F. Freitas
+ Copyright (C) 2012 Marcello Coutinho
+ 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.
+
+ THIS SOFTWARE IS PROVIDED ``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
+ AUTHOR 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.
+ */
+/* ========================================================================== */
+$pf_version=substr(trim(file_get_contents("/etc/version")),0,3);
+if ($pf_version > 2.0){
+ define('SARG_DIR', '/usr/pbi/sarg-' . php_uname("m"));
+ define('SQUID_DIR', '/usr/pbi/squid-' . php_uname("m"));
+ define('DANSG_DIR', '/usr/pbi/dansguardian-' . php_uname("m"));
+ }
+else{
+ define('SARG_DIR', '/usr/local');
+ define('SQUID_DIR', '/usr/local');
+ define('DANSG_DIR', '/usr/local');
+}
+
+$uname=posix_uname();
+if ($uname['machine']=='amd64')
+ ini_set('memory_limit', '250M');
+
+// STATIC VARS
+$sarg_proxy=array( 'squid_rc'=> SQUID_DIR . '/etc/rc.d/squid.sh',
+ 'squid_config'=> '/var/squid/logs/access.log',
+ 'squidguard_config'=> SARG_DIR . '/etc/squidGuard/squidGuard.conf',
+ 'squidguard_block_log'=>'/var/squidGuard/log/block.log',
+ 'dansguardian_config'=> DANSG_DIR . '/etc/dansguardian/dansguardian.conf',
+ 'dansguardian_log'=>'/var/log/dansguardian/access.log');
+
+// END STATIC VARS
+
+function sarg_start() {
+ global $g, $config;
+
+ // reserved
+}
+
+function sarg_text_area_decode($text){
+ return preg_replace('/\r\n/', "\n",base64_decode($text));
+}
+
+function sarg_resync() {
+ global $config;
+ if (($_POST['Submit'] == 'Save') || !isset($_POST['Submit']))
+ sync_package_sarg();
+ if ($_POST['Submit'] == 'Force update now')
+ run_sarg();
+
+}
+function log_rotate($log_file){
+ global $config, $g;
+
+ #remove .10 rotate log file
+ unlink_if_exists("$log_file".".10");
+ #rotate logs from 9 to 0
+ $i=9;
+ while ($i>=0){
+ if (file_exists($log_file.".".$i))
+ rename ($log_file.".".$i,$log_file.".".($i+1));
+ $i=$i-1;
+ }
+ #rotate current log
+ if (file_exists("$log_file"))
+ rename ($log_file,$log_file.".0");
+}
+function run_sarg($id=-1) {
+ global $config, $g,$sarg_proxy;
+ #mount filesystem writeable
+ conf_mount_rw();
+ $cmd = SARG_DIR . "/bin/sarg";
+ if ($id >= 0 && is_array($config['installedpackages']['sargschedule']['config'])){
+ $args=$config['installedpackages']['sargschedule']['config'][$id]['args'];
+ $action=$config['installedpackages']['sargschedule']['config'][$id]['action'];
+ $gzip=$config['installedpackages']['sargschedule']['config'][$id]['gzip'];
+ $find=$config['installedpackages']['sargschedule']['config'][$id]['find'];
+ $gziplevel=$config['installedpackages']['sargschedule']['config'][$id]['gziplevel'];
+ $daylimit=$config['installedpackages']['sargschedule']['config'][$id]['daylimit'];
+ }
+ else{
+ $args=$_POST['args'];
+ $action=$_POST['action'];
+ $gzip=$_POST['gzip'];
+ $find=$_POST['find'];
+ $gziplevel=$_POST['gziplevel'];
+ $daylimit="";
+ }
+ $find=(preg_match("/(\d+)/",$find,$find_matches) ? $find_matches[1] : "60");
+ log_error("Sarg: force refresh now with {$args} args, compress({$gzip}) and {$action} action after sarg finish.");
+ $gzip_script="#!/bin/sh\n";
+ if ($gzip=="on"){
+ #remove old file if exists
+ unlink_if_exists("/root/sarg_run_{$id}.sh");
+ $gzip_script.=<<<EOF
+for a in `/usr/bin/find /usr/local/sarg-reports -cmin -{$find} -type d -mindepth 1 -maxdepth 1`
+do
+echo \$a
+/usr/bin/find \$a -name "*html" | xargs gzip {$gziplevel}
+done
+
+EOF;
+
+ }
+ if (preg_match("/(\d+)/",$daylimit,$day_matches)){
+ $gzip_script.=<<<EOF
+for a in `/usr/bin/find /usr/local/sarg-reports -ctime +{$find} -type d -mindepth 1 -maxdepth 1`
+do
+echo \$a
+rm -rf \$a
+done
+
+EOF;
+ }
+ #create a new file to speedup find search
+ file_put_contents("/root/sarg_run_{$id}.sh",$gzip_script,LOCK_EX);
+ mwexec($cmd. " ".$args);
+ #check if there is a script to run after file save
+ if (is_array($config['installedpackages']['sarg']))
+ switch ($config['installedpackages']['sarg']['config'][0]['proxy_server']){
+ case "squidguard":
+ if ($action =="both" || $action=="rotate"){
+ log_error('executing squidguard log rotate after sarg.');
+ log_rotate($sarg_proxy['squidguard_block_log']);
+ file_put_contents($sarg_proxy['squidguard_block_log'],"",LOCK_EX);
+ chown($sarg_proxy['squidguard_block_log'],'proxy');
+ chgrp($sarg_proxy['squidguard_block_log'],'proxy');
+ mwexec(SQUID_DIR . '/sbin/squid -k reconfigure');
+ }
+ #leave this case without break to run squid rotate too.
+ case "squid":
+ if ($action =="both" || $action=="rotate"){
+ log_error('executing squid log rotate after sarg.');
+ mwexec(SQUID_DIR . '/sbin/squid -k rotate');
+ }
+ if ($action =="both" || $action=="restart"){
+ if (file_exists($sarg_proxy['squid_rc']))
+ mwexec_bg($sarg_proxy['squid_rc'].' restart');
+ }
+ break;
+ case "dansguardian":
+ if (preg_match('/\w+/',$action) && $action !="none"){
+ log_rotate($sarg_proxy['dansguardian_log']);
+ log_error('restarting dansguardian after sarg and log rotate.');
+ mwexec('/usr/bin/killall -HUP dansguardian');
+ }
+ break;
+ }
+ #check compress option
+ if ($gzip=="on")
+ mwexec_bg("/bin/sh /root/sarg_run_{$id}.sh");
+
+ #mount filesystem readonly
+ conf_mount_ro();
+}
+
+function sync_package_sarg() {
+ global $config, $g,$sarg_proxy;
+
+ # detect boot process
+ if (is_array($_POST)){
+ if (!preg_match("/\w+/",$_POST['__csrf_magic']))
+ return;
+ }
+ #check pkg.php sent a sync request
+
+
+ $update_conf=0;
+ #mount filesystem writeable
+ conf_mount_rw();
+ if (!is_array($config['installedpackages']['sarg']['config']))
+ $config['installedpackages']['sarg']['config'][0]=array('report_options'=>'use_graphs,remove_temp_files,main_index,use_comma,date_time_by_bytes',
+ 'report_type'=>'topusers,topsites,sites_users,users_sites,date_time,denied,auth_failures,site_user_time_date,downloads',
+ 'report_type'=>'u',
+ 'report_charset'=>'UTF-8',
+ 'topuser_num'=>'0',
+ 'authfail_report_limit'=>'0',
+ 'denied_report_limit'=>'0',
+ 'user_report_limit' =>'0',
+ 'lastlog'=> '0',
+ 'max_elapsed'=> '0');
+ $sarg=$config['installedpackages']['sarg']['config'][0];
+ if (!is_array($config['installedpackages']['sarguser']['config']))
+ $config['installedpackages']['sarguser']['config'][0]=array('user_sort_field'=>'BYTES',
+ 'exclude_userlist'=> $sarg['exclude_userlist'],
+ 'include_userlist'=> $sarg['include_userlist'],
+ 'usertab'=>$sarg['usertab'],
+ 'ldap_filter_search'=> '(uid=%s)',
+ 'ldap_target_attr'=> 'cn',
+ 'ldap_port'=> '389',
+ 'ntlm_user_format'=>'domainname+username');
+ $sarguser=$config['installedpackages']['sarguser']['config'][0];
+ $access_log=$sarg['proxy_server'];
+ switch ($sarg['proxy_server']){
+ case 'dansguardian':
+ $access_log= $sarg_proxy['dansguardian_log'];
+ $dansguardian_conf=$sarg_proxy['dansguardian_config'];
+ $dansguardian_filter_out_date="dansguardian_filter_out_date on";
+ $squidguard_conf='squidguard_conf none';
+ break;
+ case 'squidguard':
+ $squidguard_conf='squidguard_conf '.$sarg_proxy['squidguard_config'];
+ $redirector_log_format='redirector_log_format #year#-#mon#-#day# #hour# #tmp#/#list#/#tmp#/#tmp#/#url#/#tmp# #ip#/#tmp# #user# #end#';
+ #Leve this case without break to include squid log file on squidguard option
+ case 'squid':
+ $access_log= $sarg_proxy['squid_config'];
+ if (is_array($config['installedpackages']['squid']['config']))
+ if (file_exists($config['installedpackages']['squid']['config'][0]['log_dir']. '/access.log'))
+ $access_log = $config['installedpackages']['squid']['config'][0]['log_dir']. '/access.log';
+ break;
+ }
+ if (!file_exists($access_log) && $access_log !=""){
+ $error="Sarg config error: ".$sarg['proxy_server']." log file ($access_log) does not exists";
+ log_error($error);
+ file_notice("Sarg", $error, "Sarg Settings", "");
+ }
+
+ #general tab
+ $graphs=(preg_match('/use_graphs/',$sarg['report_options'])?"yes":"no");
+ $anonymous_output_files=(preg_match('/anonymous_output_files/',$sarg['report_options'])?"yes":"no");
+ $resolve_ip=(preg_match('/resolve_ip/',$sarg['report_options'])?"yes":"no");
+ $user_ip=(preg_match('/user_ip/',$sarg['report_options'])?"yes":"no");
+ $sort_order=(preg_match('/user_sort_field_order/',$sarg['report_options'])?"REVERSE":"NORMAL");
+ $remove_temp_files=(preg_match('/remove_temp_files/',$sarg['report_options'])?"yes":"no");
+ $main_index=(preg_match('/main_index/',$sarg['report_options'])?"yes":"no");
+ $index_tree=(preg_match('/index_tree/',$sarg['report_options'])?"file":"date");
+ $overwrite_report=(preg_match('/overwrite_report/',$sarg['report_options'])?"yes":"no");
+ $use_comma=(preg_match('/use_comma/',$sarg['report_options'])?"yes":"no");
+ $long_url=(preg_match('/long_url/',$sarg['report_options'])?"yes":"no");
+ $privacy=(preg_match('/privacy/',$sarg['report_options'])?"yes":"no");
+ $displayed_values=(preg_match('/displayed_values/',$sarg['report_options'])?"abbreviation":"bytes");
+ $bytes_in_sites_users_report=(preg_match('/bytes_in_sites_users_report/',$sarg['report_options'])?"yes":"no");
+ $date_time_by=(preg_match('/date_time_by_bytes/',$sarg['report_options'])?"bytes":"");
+ $date_time_by.=(preg_match('/date_time_by_elap/',$sarg['report_options'])?" elap":"");
+ $date_format=(empty($sarg['report_date_format'])?"u":$sarg['report_date_format']);
+ $report_type=preg_replace('/,/',' ',$sarg['report_type']);
+ $report_charset=(empty($sarg['report_charset'])?"UTF-8":$sarg['report_charset']);
+ $exclude_string=(empty($sarg['exclude_string'])?"":'exclude_string "'.$sarg['exclude_string'].'"');
+
+ #limits
+ $max_elapsed=(empty($sarg['max_elapsed'])?"0":$sarg['max_elapsed']);
+ $lastlog=(empty($sarg['lastlog'])?"0":$sarg['lastlog']);
+ $topuser_num=(empty($sarg['topuser_num'])?"0":$sarg['topuser_num']);
+ $authfail_report_limit=(empty($sarg['authfail_report_limit'])?"0":$sarg['authfail_report_limit']);
+ $denied_report_limit=(empty($sarg['denied_report_limit'])?"0":$sarg['denied_report_limit']);
+ $report_limit=(empty($sarg['user_report_limit'])?"0":$sarg['user_report_limit']);
+ $user_report_limit = "siteusers_report_limit ".$report_limit."\n";
+ $user_report_limit .= "user_report_limit ".$report_limit."\n";
+ if(preg_match("/(squidguard|dansguardian)/",$sarg['proxy_server'])){
+ $user_report_limit .= $sarg['proxy_server']."_report_limit ".$report_limit."\n";
+ }
+
+ #user tab
+ $ntlm_user_format=(empty($sarguser['ntlm_user_format'])?'domainname+username':$sarguser['ntlm_user_format']);
+ if(!empty($sarguser['include_userlist']))
+ $include_users="$include_users ".$sarguser['include_userlist'];
+
+ if(empty($sarguser['usertab'])){
+ $usertab="none";
+ }
+ else{
+ $usertab= SARG_DIR . "/etc/sarg/usertab.conf";
+ file_put_contents( SARG_DIR . '/etc/sarg/usertab.conf', sarg_text_area_decode($sarguser['usertab']),LOCK_EX);
+ }
+ if($sarguser['ldap_enable']){
+ $LDAPHost=(empty($sarguser['ldap_host'])?"":"LDAPHost ".$sarguser['ldap_host']);
+ $LDAPort=(empty($sarguser['ldap_port'])?"":"LDAPPort ".$sarguser['ldap_port']);
+ $LDAPBindDN=(empty($sarguser['ldap_bind_dn'])?"":"LDAPBindDN ".$sarguser['ldap_bind_dn']);
+ $LDAPBindPW=(empty($sarguser['ldap_bind_pw'])?"":"LDAPBindPW ".$sarguser['ldap_bind_pw']);
+ $LDAPBaseSearch=(empty($sarguser['ldap_base_search'])?"":"LDAPBaseSearch ".$sarguser['ldap_base_search']);
+ $LDAPTargetAttr=(empty($sarguser['ldap_target_Attr'])?"":"LDAPTargetAttr ".$sarguser['ldap_target_Attr']);
+ $LDAPFilterSearch=(empty($sarguser['ldap_filter_search'])?"":"LDAPFilterSearch ".$sarguser['ldap_filter_search']);
+ }
+
+
+ #move old reports
+ if (is_dir("/usr/local/www/sarg-reports") && !is_dir("/usr/local/sarg-reports"))
+ rename("/usr/local/www/sarg-reports","/usr/local/sarg-reports");
+
+ #check dirs
+ $dirs=array("/usr/local/sarg-reports","/usr/local/www/sarg-images","/usr/local/www/sarg-images/temp");
+ foreach ($dirs as $dir)
+ if (!is_dir($dir))
+ mkdir ($dir,0755,true);
+
+ #images
+ $simages=array("datetime.png","graph.png","sarg-squidguard-block.png","sarg.png");
+ $simgdir1="/usr/local/www/sarg-images";
+ $simgdir2= SARG_DIR . "/etc/sarg/images";
+ foreach ($simages as $simage){
+ if (!file_exists("{$simgdir1}/{$simage}"))
+ copy("{$simgdir2}/{$simage}","{$simgdir1}/{$simage}");
+ }
+
+ //log_error($_POST['__csrf_magic']." sarg log:". $access_log);
+ #create sarg config files
+ $sarg_dir= SARG_DIR;
+ include("/usr/local/pkg/sarg.template");
+ file_put_contents( SARG_DIR . "/etc/sarg/sarg.conf", $sg, LOCK_EX);
+ file_put_contents( SARG_DIR . '/etc/sarg/exclude_hosts.conf', sarg_text_area_decode($sarg['exclude_hostlist']),LOCK_EX);
+ file_put_contents( SARG_DIR . '/etc/sarg/exclude_codes', sarg_text_area_decode($sarg['exclude_codelist']),LOCK_EX);
+ file_put_contents( SARG_DIR . '/etc/sarg/hostalias',sarg_text_area_decode($sarg['hostalias']),LOCK_EX);
+ file_put_contents( SARG_DIR . '/etc/sarg/exclude_users.conf', sarg_text_area_decode($sarguser['exclude_userlist']),LOCK_EX);
+ #check cron_tab
+ $new_cron=array();
+ $cron_found=0;
+ if (is_array($config['cron']['item']))
+ foreach($config['cron']['item'] as $cron){
+ if (preg_match("/usr.local.www.sarg.php/",$cron["command"]))
+ $cron_found++;
+ else
+ $new_cron['item'][]=$cron;
+ }
+ $cron_cmd="/usr/local/bin/php /usr/local/www/sarg.php";
+ $sarg_schedule_id=0;
+ if (is_array($config['installedpackages']['sargschedule']['config']))
+ foreach ($config['installedpackages']['sargschedule']['config'] as $sarg_schedule){
+ if(preg_match('/(\d+)m/',$sarg_schedule['frequency'],$matches) && $sarg_schedule['enable']){
+ $new_cron['item'][]=array( "minute" => "*/".$matches[1],
+ "hour" => "*",
+ "mday" => "*",
+ "month" => "*",
+ "wday" => "*",
+ "who" => "root",
+ "command"=> $cron_cmd." ".$sarg_schedule_id);
+ $config['cron']=$new_cron;
+ $cron_found++;
+ }
+ if(preg_match('/(\d+)h/',$sarg_schedule['frequency'],$matches) && $sarg_schedule['enable']){
+ $new_cron['item'][]=array( "minute" => "0",
+ "hour" => "*/".$matches[1],
+ "mday" => "*",
+ "month" => "*",
+ "wday" => "*",
+ "who" => "root",
+ "command"=> $cron_cmd." ".$sarg_schedule_id);
+ $config['cron']=$new_cron;
+ $cron_found++;
+ }
+ if(preg_match('/(\d+)d/',$sarg_schedule['frequency'],$matches) && $sarg_schedule['enable']){
+ $new_cron['item'][]=array( "minute" => "0",
+ "hour" => "0",
+ "mday" => "*/".$matches[1],
+ "month" => "*",
+ "wday" => "*",
+ "who" => "root",
+ "command"=> $cron_cmd." ".$sarg_schedule_id);
+ $config['cron']=$new_cron;
+ $cron_found++;
+ }
+ $sarg_schedule_id++;
+ }
+
+ #update cron
+ if ($cron_found > 0){
+ $config['cron']=$new_cron;
+ write_config();
+ configure_cron();
+ }
+ #Write config if any file from filesystem was loaded
+ if ($update_conf > 0)
+ write_config();
+
+ #mount filesystem readonly
+ conf_mount_ro();
+
+ sarg_sync_on_changes();
+}
+
+function sarg_validate_input($post, &$input_errors) {
+ global $config,$g;
+ foreach ($post as $key => $value) {
+ if (empty($value))
+ continue;
+ # check dansguardian
+ if (substr($key, 0, 12) == "proxy_server" && $value == "dansguardian"){
+ if (is_array($config['installedpackages']['dansguardianlog'])){
+ if ($config['installedpackages']['dansguardianlog']['config'][0]['logfileformat']!=3){
+ $input_errors[]='Sarg is only compatible with dansguardian log squid mode';
+ $input_errors[]='Please change it on service -> dansguarian -> report and log -> log file format';
+ }
+ }
+ else
+ $input_errors[]='dansguardian package not detected';
+ }
+
+ # check squidguard
+ if (substr($key, 0, 10) == "proxy_server" && $value == "squidguard")
+ if (!is_array($config['installedpackages']['squidguardgeneral']))
+ $input_errors[]='squidguard package not detected';
+
+ # check squid
+ if (substr($key, 0, 5) == "proxy_server" && $value == "squid"){
+ if (is_array($config['installedpackages']['squid']))
+ if (!$config['installedpackages']['squid']['log_enabled'])
+ $input_errors[]='squidlogs not enabled';
+ else
+ $input_errors[]='squid package not installed';
+ }
+
+ if (substr($key, 0, 11) == "description" && !preg_match("@^[a-zA-Z0-9 _/.-]+$@", $value))
+ $input_errors[] = "Do not use special characters on description";
+ if (substr($key, 0, 8) == "fullfile" && !preg_match("@^[a-zA-Z0-9_/.-]+$@", $value))
+ $input_errors[] = "Do not use special characters on filename";
+ #check cron option
+ if($key == "frequency" && (!preg_match("/^\d+(h|m|d)$/",$value) || $value == 0))
+ $input_errors[] = "A valid number with a time reference is required for the field 'Update Frequency'";
+ }
+}
+
+
+/* Uses XMLRPC to synchronize the changes to a remote node */
+function sarg_sync_on_changes() {
+ global $config, $g;
+
+ log_error("[sarg] sarg_xmlrpc_sync.php is starting.");
+ $synconchanges = $config['installedpackages']['sargsync']['config'][0]['synconchanges'];
+ if(!$synconchanges)
+ return;
+ foreach ($config['installedpackages']['sargsync']['config'] as $rs ){
+ foreach($rs['row'] as $sh){
+ $sync_to_ip = $sh['ipaddress'];
+ $password = $sh['password'];
+ if($sh['username'])
+ $username = $sh['username'];
+ else
+ $username = 'admin';
+ if($password && $sync_to_ip)
+ sarg_do_xmlrpc_sync($sync_to_ip, $username, $password);
+ }
+ }
+ log_error("[sarg] sarg_xmlrpc_sync.php is ending.");
+}
+/* Do the actual XMLRPC sync */
+function sarg_do_xmlrpc_sync($sync_to_ip, $username, $password) {
+ global $config, $g;
+
+ if(!$username)
+ return;
+
+ if(!$password)
+ return;
+
+ if(!$sync_to_ip)
+ return;
+
+ $xmlrpc_sync_neighbor = $sync_to_ip;
+ if($config['system']['webgui']['protocol'] != "") {
+ $synchronizetoip = $config['system']['webgui']['protocol'];
+ $synchronizetoip .= "://";
+ }
+ $port = $config['system']['webgui']['port'];
+ /* if port is empty lets rely on the protocol selection */
+ if($port == "") {
+ if($config['system']['webgui']['protocol'] == "http")
+ $port = "80";
+ else
+ $port = "443";
+ }
+ $synchronizetoip .= $sync_to_ip;
+
+ /* xml will hold the sections to sync */
+ $xml = array();
+ $xml['sarg'] = $config['installedpackages']['sarg'];
+ $xml['sarguser'] = $config['installedpackages']['sarguser'];
+ /* assemble xmlrpc payload */
+ $params = array(
+ XML_RPC_encode($password),
+ XML_RPC_encode($xml)
+ );
+
+ /* set a few variables needed for sync code borrowed from filter.inc */
+ $url = $synchronizetoip;
+ log_error("Beginning sarg XMLRPC sync to {$url}:{$port}.");
+ $method = 'pfsense.merge_installedpackages_section_xmlrpc';
+ $msg = new XML_RPC_Message($method, $params);
+ $cli = new XML_RPC_Client('/xmlrpc.php', $url, $port);
+ $cli->setCredentials($username, $password);
+ if($g['debug'])
+ $cli->setDebug(1);
+ /* send our XMLRPC message and timeout after 250 seconds */
+ $resp = $cli->send($msg, "250");
+ if(!$resp) {
+ $error = "A communications error occurred while attempting sarg XMLRPC sync with {$url}:{$port}.";
+ log_error($error);
+ file_notice("sync_settings", $error, "sarg Settings Sync", "");
+ } elseif($resp->faultCode()) {
+ $cli->setDebug(1);
+ $resp = $cli->send($msg, "250");
+ $error = "An error code was received while attempting sarg XMLRPC sync with {$url}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString();
+ log_error($error);
+ file_notice("sync_settings", $error, "sarg Settings Sync", "");
+ } else {
+ log_error("sarg XMLRPC sync successfully completed with {$url}:{$port}.");
+ }
+
+ /* tell sarg to reload our settings on the destionation sync host. */
+ $method = 'pfsense.exec_php';
+ $execcmd = "require_once('/usr/local/pkg/sarg.inc');\n";
+ $execcmd .= "sync_package_sarg();";
+ /* assemble xmlrpc payload */
+ $params = array(
+ XML_RPC_encode($password),
+ XML_RPC_encode($execcmd)
+ );
+
+ log_error("sarg XMLRPC reload data {$url}:{$port}.");
+ $msg = new XML_RPC_Message($method, $params);
+ $cli = new XML_RPC_Client('/xmlrpc.php', $url, $port);
+ $cli->setCredentials($username, $password);
+ $resp = $cli->send($msg, "250");
+ if(!$resp) {
+ $error = "A communications error occurred while attempting sarg XMLRPC sync with {$url}:{$port} (pfsense.exec_php).";
+ log_error($error);
+ file_notice("sync_settings", $error, "sarg Settings Sync", "");
+ } elseif($resp->faultCode()) {
+ $cli->setDebug(1);
+ $resp = $cli->send($msg, "250");
+ $error = "An error code was received while attempting sarg XMLRPC sync with {$url}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString();
+ log_error($error);
+ file_notice("sync_settings", $error, "sarg Settings Sync", "");
+ } else {
+ log_error("sarg XMLRPC reload data success with {$url}:{$port} (pfsense.exec_php).");
+ }
+
+}
+
+function sarg_php_install_command() {
+ sync_package_sarg();
+}
+
+function sarg_php_deinstall_command() {
+ // reserved
+}
+
+?>
diff --git a/config/sarg/sarg.php b/config/sarg/sarg.php
new file mode 100644
index 00000000..98e6c426
--- /dev/null
+++ b/config/sarg/sarg.php
@@ -0,0 +1,50 @@
+<?php
+/* $Id$ */
+/* ========================================================================== */
+/*
+ sarg.php
+ part of pfSense (http://www.pfSense.com)
+ Copyright (C) 2012 Marcello Coutinho
+
+ 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.
+
+ THIS SOFTWARE IS PROVIDED ``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
+ AUTHOR 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.
+ */
+/* ========================================================================== */
+
+require_once("/etc/inc/util.inc");
+require_once("/etc/inc/functions.inc");
+require_once("/etc/inc/pkg-utils.inc");
+require_once("/etc/inc/globals.inc");
+require_once("/usr/local/pkg/sarg.inc");
+
+$uname=posix_uname();
+if ($uname['machine']=='amd64')
+ ini_set('memory_limit', '250M');
+
+if (preg_match ("/(\d+)/",$argv[1],$matches))
+ run_sarg($matches[1]);
+
+
+?> \ No newline at end of file
diff --git a/config/sarg/sarg.priv.inc b/config/sarg/sarg.priv.inc
new file mode 100644
index 00000000..4878c96e
--- /dev/null
+++ b/config/sarg/sarg.priv.inc
@@ -0,0 +1,13 @@
+<?php
+
+global $priv_list;
+
+$priv_list['page-status-sarg-reports'] = array();
+$priv_list['page-status-sarg-reports']['name'] = "WebCfg - Status: Sarg reports";
+$priv_list['page-status-sarg-reports']['descr'] = "Allow access to sarg reports page.";
+$priv_list['page-status-sarg-reports']['match'] = array();
+$priv_list['page-status-sarg-reports']['match'][] = "sarg_reports.php*";
+$priv_list['page-status-sarg-reports']['match'][] = "sarg_frame.php*";
+$priv_list['page-status-sarg-reports']['match'][] = "sarg_realtime.php*";
+
+?>
diff --git a/config/sarg/sarg.template b/config/sarg/sarg.template
new file mode 100644
index 00000000..abda925b
--- /dev/null
+++ b/config/sarg/sarg.template
@@ -0,0 +1,811 @@
+<?php
+/*
+ sag.template
+ part of the Dansguardian package for pfSense
+ Copyright (C) 2012 Marcello Coutinho
+ 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.
+
+ THIS SOFTWARE IS PROVIDED ``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
+ AUTHOR 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.
+
+*/
+
+#create sarg.conf
+ $sg=<<<EOF
+# sarg.conf
+#
+# TAG: access_log file
+# Where is the access.log
+# sarg -l file
+#
+access_log {$access_log}
+
+# TAG: graphs yes|no
+# Use graphics where is possible.
+# graph_days_bytes_bar_color blue|green|yellow|orange|brown|red
+#
+graphs {$graphs}
+#graph_days_bytes_bar_color orange
+
+# TAG: graph_font
+# The full path to the TTF font file to use to create the graphs. It is required
+# if graphs is set to yes.
+#
+#graph_font /usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf
+
+# TAG: title
+# Especify the title for html page.
+#
+#title "Squid User Access Reports"
+
+# TAG: font_face
+# Especify the font for html page.
+#
+#font_face Tahoma,Verdana,Arial
+
+# TAG: header_color
+# Especify the header color
+#
+#header_color darkblue
+
+# TAG: header_bgcolor
+# Especify the header bgcolor
+#
+#header_bgcolor blanchedalmond
+
+# TAG: font_size
+# Especify the text font size
+#
+#font_size 9px
+
+# TAG: header_font_size
+# Especify the header font size
+#
+#header_font_size 9px
+
+# TAG: title_font_size
+# Especify the title font size
+#
+#title_font_size 11px
+
+# TAG: background_color
+# TAG: background_color
+# Html page background color
+#
+# background_color white
+
+# TAG: text_color
+# Html page text color
+#
+#text_color #000000
+
+# TAG: text_bgcolor
+# Html page text background color
+#
+#text_bgcolor lavender
+
+# TAG: title_color
+# Html page title color
+#
+#title_color green
+
+# TAG: logo_image
+# Html page logo.
+#
+#logo_image none
+
+# TAG: logo_text
+# Html page logo text.
+#
+#logo_text ""
+
+# TAG: logo_text_color
+# Html page logo texti color.
+#
+#logo_text_color #000000
+
+# TAG: logo_image_size
+# Html page logo image size.
+# width height
+#
+#image_size 80 45
+
+# TAG: background_image
+# Html page background image
+#
+#background_image none
+
+# TAG: password
+# User password file used by Squid authentication scheme
+# If used, generate reports just for that users.
+#
+#password none
+
+# TAG: temporary_dir
+# Temporary directory name for work files
+# sarg -w dir
+#
+#temporary_dir /tmp
+
+# TAG: output_dir
+# The reports will be saved in that directory
+# sarg -o dir
+#
+output_dir /usr/local/sarg-reports
+
+# TAG: anonymous_output_files yes/no
+# Use anonymous file and directory names in the report. If it is set to
+# no (the default), the user id/ip/name is slightly mangled to create a
+# suitable file name to store the report of the user but the user's
+# identity can easily be guessed from the mangled name. If this option is
+# set, any file or directory belonging to the user is replaced by a short
+# number. The purpose is to hide the identity of the user when looking
+# at the report file names but it may serve to shorten the path too.
+#
+anonymous_output_files {$anonymous_output_files}
+
+# TAG: output_email
+# Email address to send the reports. If you use this tag, no html reports will be generated.
+# sarg -e email
+#
+#output_email none
+
+# TAG: resolve_ip yes/no
+# Convert ip address to dns name
+# sarg -n
+resolve_ip {$resolve_ip}
+
+# TAG: user_ip yes/no
+# Use Ip Address instead userid in reports.
+# sarg -p
+user_ip {$user_ip}
+
+# TAG: topuser_sort_field field normal/reverse
+# Sort field for the Topuser Report.
+# Allowed fields: USER CONNECT BYTES TIME
+#
+topuser_sort_field {$sarguser['user_sort_field']} {$sort_order}
+
+# TAG: user_sort_field field normal/reverse
+# Sort field for the User Report.
+# Allowed fields: SITE CONNECT BYTES TIME
+#
+user_sort_field {$sarguser['user_sort_field']} {$sort_order}
+
+# TAG: exclude_users file
+# users within the file will be excluded from reports.
+# you can use indexonly to have only index.html file.
+#
+exclude_users {$sarg_dir}/etc/sarg/exclude_users.conf
+
+# TAG: exclude_hosts file
+# Hosts, domains or subnets will be excluded from reports.
+#
+# Eg.: 192.168.10.10 - exclude ip address only
+# 192.168.10.0/24 - exclude full C class
+# s1.acme.foo - exclude hostname only
+# *.acme.foo - exclude full domain name
+#
+exclude_hosts {$sarg_dir}/etc/sarg/exclude_hosts.conf
+
+# TAG: useragent_log file
+# useragent.log file patch to generate useragent report.
+#
+#useragent_log none
+
+# TAG: date_format
+# Date format in reports: e (European=dd/mm/yy), u (American=mm/dd/yy), w (Weekly=yy.ww)
+#
+#date_format u
+date_format {$date_format}
+
+# TAG: per_user_limit file MB
+# Saves userid on file if download exceed n MB.
+# This option allow you to disable user access if user exceed a download limit.
+#
+#per_user_limit none
+
+# TAG: lastlog n
+# How many reports files must be kept in reports directory.
+# The oldest report file will be automatically removed.
+# 0 - no limit.
+#
+#lastlog 0
+lastlog {$lastlog}
+
+# TAG: remove_temp_files yes
+# Remove temporary files: geral, usuarios, top, periodo from root report directory.
+#
+remove_temp_files {$remove_temp_files}
+
+# TAG: index yes|no|only
+# Generate the main index.html.
+# only - generate only the main index.html
+#
+index {$main_index}
+
+# TAG: index_tree date|file
+# How to generate the index.
+#
+index_tree {$index_tree}
+
+# TAG: index_fields
+# The columns to show in the index of the reports
+# Columns are: dirsize
+#
+#index_fields dirsize
+
+# TAG: overwrite_report yes|no
+# yes - if report date already exist then will be overwrited.
+# no - if report date already exist then will be renamed to filename.n, filename.n+1
+#
+overwrite_report {$overwrite_report}
+
+# TAG: records_without_userid ignore|ip|everybody
+# What can I do with records without user id (no authentication) in access.log file ?
+#
+# ignore - This record will be ignored.
+# ip - Use ip address instead. (default)
+# everybody - Use "everybody" instead.
+#
+#records_without_userid ip
+
+# TAG: use_comma no|yes
+# Use comma instead point in reports.
+# Eg.: use_comma yes => 23,450,110
+# use_comma no => 23.450.110
+#
+use_comma {$use_comma}
+
+# TAG: mail_utility
+# Mail command to use to send reports via SMTP. Sarg calls it like this:
+# mail_utility -s "SARG report, date" "output_email" <"mail_content"
+#
+# Therefore, it is possible to add more arguments to the command by specifying them
+# here.
+#
+# If you need too, you can use a shell script to process the content of /dev/stdin
+# (/dev/stdin is the mail_content passed by sarg to the script) and call whatever
+# command you like. It is not limited to mailing the report via SMTP.
+#
+# Don't forget to quote the command if necessary (i.e. if the path contains
+# characters that must be quoted).
+#
+#mail_utility mailx
+
+# TAG: topsites_num n
+# How many sites in topsites report.
+#
+#topsites_num 100
+
+# TAG: topsites_sort_order CONNECT|BYTES|TIME A|D
+# Sort for topsites report, where A=Ascendent, D=Descendent
+#
+#topsites_sort_order CONNECT D
+
+# TAG: index_sort_order A/D
+# Sort for index.html, where A=Ascendent, D=Descendent
+#
+#index_sort_order D
+
+# TAG: exclude_codes file
+# Ignore records with these codes. Eg.: NONE/400
+# Write one code per line. Lines starting with a # are ignored.
+# Only codes matching exactly one of the line is rejected. The
+# comparison is not case sensitive.
+#
+exclude_codes {$sarg_dir}/etc/sarg/exclude_codes
+
+# TAG: replace_index string
+# Replace "index.html" in the main index file with this string
+# If null "index.html" is used
+#
+#replace_index <?php echo str_replace(".", "_", $REMOTE_ADDR); echo ".html"; ?>
+
+# TAG: max_elapsed milliseconds
+# If elapsed time is recorded in log is greater than max_elapsed use 0 for elapsed time.
+# Use 0 for no checking
+#
+#max_elapsed 28800000
+# 8 Hours
+max_elapsed {$max_elapsed}
+
+# TAG: report_type type
+# What kind of reports to generate.
+# topusers - users, sites, times, bytes, connects, links to accessed sites, etc
+# topsites - site, connect and bytes report
+# sites_users - users and sites report
+# users_sites - accessed sites by the user report
+# date_time - bytes used per day and hour report
+# denied - denied sites with full URL report
+# auth_failures - autentication failures report
+# site_user_time_date - sites, dates, times and bytes report
+# downloads - downloads per user report
+#
+# Eg.: report_type topsites denied
+#
+#report_type topusers topsites sites_users users_sites date_time denied auth_failures site_user_time_date downloads
+report_type {$report_type}
+
+# TAG: usertab filename
+# You can change the "userid" or the "ip address" to be a real user name on the reports.
+# If resolve_ip is active, the ip address is resolved before being looked up into this
+# file. That is, if you want to map the ip address, be sure to set resolv_ip to no or
+# the resolved name will be looked into the file instead of the ip address. Note that
+# it can be used to resolve any ip address known to the dns and then map the unresolved
+# ip addresses to a name found in the usertab file.
+# Table syntax:
+# userid name or ip address name
+# Eg:
+# SirIsaac Isaac Newton
+# vinci Leonardo da Vinci
+# 192.168.10.1 Karol Wojtyla
+#
+# Each line must be terminated with '\ n'
+# If usertab have value "ldap" (case ignoring), user names
+# will be taken from LDAP server. This method as approaches for reception
+# of usernames from Active Didectory
+#
+#usertab none
+usertab {$usertab}
+
+# TAG: LDAPHost hostname
+# FQDN or IP address of host with LDAP service or AD DC
+# default is '127.0.0.1'
+#LDAPHost 127.0.0.1
+{$LDAPHost}
+
+# TAG: LDAPPort port
+# LDAP service port number
+# default is '389'
+#LDAPPort 389
+{$LDAPPort}
+
+# TAG: LDAPBindDN CN=username,OU=group,DC=mydomain,DC=com
+# DN of LDAP user, who is authorized to read user's names from LDAP base
+# default is empty line
+#LDAPBindDN cn=proxy,dc=mydomain,dc=local
+{$LDAPBindDN}
+
+# TAG: LDAPBindPW secret
+# Password of DN, who is authorized to read user's names from LDAP base
+# default is empty line
+#LDAPBindPW secret
+{$LDAPBindPW}
+
+# TAG: LDAPBaseSearch OU=users,DC=mydomain,DC=com
+# LDAP search base
+# default is empty line
+#LDAPBaseSearch ou=users,dc=mydomain,dc=local
+{$LDAPBaseSearch}
+
+# TAG: LDAPFilterSearch (uid=%s)
+# User search filter by user's logins in LDAP
+# First founded record will be used
+# %s - will be changed to userlogins from access.log file
+# filter string can have up to 5 '%s' tags
+# default value is '(uid=%s)'
+#LDAPFilterSearch (uid=%s)
+{$LDAPFilterSearch}
+
+# TAG: LDAPTargetAttr attributename
+# Name of the attribute containing a name of the user
+# default value is 'cn'
+#LDAPTargetAttr cn
+{$LDAPTargetAttr}
+
+# TAG: long_url yes|no
+# If yes, the full url is showed in report.
+# If no, only the site will be showed
+#
+# YES option generate very big sort files and reports.
+#
+long_url {$long_url}
+
+# TAG: date_time_by bytes|elap
+# Date/Time reports show the downloaded volume or the elapsed time or both.
+#
+#date_time_by bytes
+date_time_by {$date_time_by}
+
+# TAG: charset name
+# ISO 8859 is a full series of 10 standardized multilingual single-byte coded (8bit)
+# graphic character sets for writing in alphabetic languages
+# You can use the following charsets:
+# Latin1 - West European
+# Latin2 - East European
+# Latin3 - South European
+# Latin4 - North European
+# Cyrillic
+# Arabic
+# Greek
+# Hebrew
+# Latin5 - Turkish
+# Latin6
+# Windows-1251
+# Japan
+# Koi8-r
+# UTF-8
+#
+#charset Latin1
+charset {$report_charset}
+
+# TAG: user_invalid_char "&/"
+# Records that contain invalid characters in userid will be ignored by Sarg.
+#
+#user_invalid_char "&/"
+
+# TAG: privacy yes|no
+# privacy_string "***.***.***.***"
+# privacy_string_color blue
+# In some countries the sysadm cannot see the visited sites by a restrictive law.
+# Using privacy yes the visited url will be changes by privacy_string and the link
+# will be removed from reports.
+#
+privacy {$privacy}
+#privacy_string "***.***.***.***"
+#privacy_string_color blue
+
+# TAG: include_users "user1:user2:...:usern"
+# Reports will be generated only for listed users.
+#
+#include_users none
+{$include_users}
+
+# TAG: exclude_string "string1:string2:...:stringn"
+# Records from access.log file that contain one of listed strings will be ignored.
+#
+#exclude_string none
+{$exclude_string}
+# TAG: show_successful_message yes|no
+# Shows "Successful report generated on dir" at end of process.
+#
+#show_successful_message yes
+
+# TAG: show_read_statistics yes|no
+# Shows some reading statistics.
+#
+#show_read_statistics yes
+
+# TAG: topuser_fields
+# Which fields must be in Topuser report.
+#
+#topuser_fields NUM DATE_TIME USERID CONNECT BYTES %BYTES IN-CACHE-OUT USED_TIME MILISEC %TIME TOTAL AVERAGE
+
+# TAG: user_report_fields
+# Which fields must be in User report.
+#
+#user_report_fields CONNECT BYTES %BYTES IN-CACHE-OUT USED_TIME MILISEC %TIME TOTAL AVERAGE
+
+# TAG: bytes_in_sites_users_report yes|no
+# Bytes field must be in Site & Users Report ?
+#
+#bytes_in_sites_users_report no
+bytes_in_sites_users_report {$bytes_in_sites_users_report}
+
+# TAG: topuser_num n
+# How many users in topsites report. 0 = no limit
+#
+#topuser_num 0
+topuser_num {$topuser_num}
+
+# TAG: datafile file
+# Save the report results in a file to populate some database
+#
+#datafile none
+
+# TAG: datafile_delimiter " "
+# ascii character to use as a field separator in datafile
+#
+#datafile_delimiter ""
+{$datafile_delimiter}
+# TAG: datafile_fields all
+# Which data fields must be in datafile
+# user;date;time;url;connect;bytes;in_cache;out_cache;elapsed
+#
+#datafile_fields user;date;time;url;connect;bytes;in_cache;out_cache;elapsed
+{$datafile_fields}
+
+# TAG: datafile_url ip|name
+# Saves the URL as ip or name in datafile
+#
+#datafile_url ip
+
+# TAG: weekdays
+# The weekdays to take into account ( Sunday->0, Saturday->6 )
+# Example:
+#weekdays 1-3,5
+# Default:
+#weekdays 0-6
+
+# TAG: hours
+# The hours to take into account
+# Example:
+#hours 7-12,14,16,18-20
+# Default:
+#hours 0-23
+
+# TAG: dansguardian_conf file
+# DansGuardian.conf file path
+# Generate reports from DansGuardian logs.
+# Use 'none' to disable it.
+# dansguardian_conf /usr/dansguardian/dansguardian.conf
+#
+dansguardian_conf {$dansguardian_conf}
+
+# TAG: dansguardian_filter_out_date on|off
+# This option replaces dansguardian_ignore_date whose name was not appropriate with respect to its action.
+# Note the change of parameter value compared with the old option.
+# 'off' use the record even if its date is outside of the range found in the input log file.
+# 'on' use the record only if its date is in the range found in the input log file.
+#
+{$dansguardian_filter_out_date}
+
+# TAG: squidguard_conf file
+# path to squidGuard.conf file
+# Generate reports from SquidGuard logs.
+# Use 'none' to disable.
+# You can use sarg -L filename to use an alternate squidGuard log.
+# squidguard_conf /usr/local/squidGuard/squidGuard.conf
+#
+{$squidguard_conf}
+
+# TAG: redirector_log file
+# the location of the web proxy redirector log such as one created by squidGuard or Rejik. The option
+# may be repeated up to 64 times to read multiple files.
+# If this option is specified, it takes precedence over squidguard_conf.
+# The command line option -L override this option.
+#
+#redirector_log /usr/local/squidGuard/var/logs/urls.log
+
+# TAG: redirector_filter_out_date on|off
+# This option replaces squidguard_ignore_date and redirector_ignore_date whose names were not
+# appropriate with respect to their action.
+# Note the change of parameter value compared with the old options.
+# 'off' use the record even if its date is outside of the range found in the input log file.
+# 'on' use the record only if its date is in the range found in the input log file.
+#
+#redirector_filter_out_date on
+
+# TAG: redirector_log_format
+# Format string for web proxy redirector logs.
+# This option was named squidguard_log_format before sarg 2.3.
+# REJIK #year#-#mon#-#day# #hour# #list#:#tmp# #ip# #user# #tmp#/#tmp#/#url#/#end#
+# SQUIDGUARD #year#-#mon#-#day# #hour# #tmp#/#list#/#tmp#/#tmp#/#url#/#tmp# #ip#/#tmp# #user# #end#
+#redirector_log_format #year#-#mon#-#day# #hour# #tmp#/#list#/#tmp#/#tmp#/#url#/#tmp# #ip#/#tmp# #user# #end#
+{$redirector_log_format}
+# TAG: show_sarg_info yes|no
+# shows sarg information and site path on each report bottom
+#
+show_sarg_info no
+
+# TAG: show_sarg_logo yes|no
+# shows sarg logo
+#
+show_sarg_logo no
+
+# TAG: parsed_output_log directory
+# Saves the processed log in a sarg format after parsing the squid log file.
+# This is a way to dump all of the data structures out, after parsing from
+# the logs (presumably this data will be much smaller than the log files themselves),
+# and pull them back in for later processing and merging with data from previous logs.
+#
+#parsed_output_log none
+
+# TAG: parsed_output_log_compress /bin/gzip|/usr/bin/bzip2|nocompress
+# Command to run to compress sarg parsed output log. It may contain
+# options (such as -f to overwrite existing target file). The name of
+# the file to compresse is provided at the end of this
+# command line. Don't forget to quote things appropriately.
+#
+#parsed_output_log_compress /bin/gzip
+
+# TAG: displayed_values bytes|abbreviation
+# how the values will be displayed in reports.
+# eg. bytes - 209.526
+# abbreviation - 210K
+#
+#displayed_values bytes
+displayed_values {$displayed_values}
+
+# Report limits
+# TAG: authfail_report_limit n
+# TAG: denied_report_limit n
+# TAG: siteusers_report_limit n
+# TAG: squidguard_report_limit n
+# TAG: user_report_limit n
+# TAG: dansguardian_report_limit n
+# TAG: download_report_limit n
+# report limits (lines).
+# '0' no limit
+#
+#authfail_report_limit 10
+authfail_report_limit {$authfail_report_limit}
+#denied_report_limit 10
+denied_report_limit {$denied_report_limit}
+#siteusers_report_limit 0
+#squidguard_report_limit 10
+#dansguardian_report_limit 10
+#user_report_limit 10
+#user_report_limit 50
+{$user_report_limit}
+
+# TAG: www_document_root dir
+# Where is your Web DocumentRoot
+# Sarg will create sarg-php directory with some PHP modules:
+# - sarg-squidguard-block.php - add urls from user reports to squidGuard DB
+#
+#www_document_root /var/www/html
+www_document_root /usr/local/www
+
+# TAG: block_it module_url
+# This tag allow you to pass urls from user reports to a cgi or php module,
+# to be blocked by some Squid acl
+#
+# Eg.: block_it /sarg-php/sarg-block-it.php
+# sarg-block-it is a php that will append a url to a flat file.
+# You must change /var/www/html/sarg-php/sarg-block-it to point to your file
+# in $filename variable, and chown to a httpd owner.
+#
+# sarg will pass http://module_url?url=url
+#
+#block_it none
+
+# TAG: external_css_file path
+# Provide the path to an external css file to link into the HTML reports instead of
+# the inline css written by sarg when this option is not set.
+#
+# In versions prior to 2.3, this used to be an absolute file name to
+# a file to include verbatim in each HTML page but, as it takes a lot of
+# space, version 2.3 switched to a link to an external css file.
+# Therefore, this option must contain the HTTP server path on which a client
+# browser may find the css file.
+#
+# Sarg use theses style classes:
+# .logo logo class
+# .info sarg information class, align=center
+# .title_c title class, align=center
+# .header_c header class, align:center
+# .header_l header class, align:left
+# .header_r header class, align:right
+# .text text class, align:right
+# .data table text class, align:right
+# .data2 table text class, align:left
+# .data3 table text class, align:center
+# .link link class
+#
+# Sarg can be instructed to output the internal css it inline
+# into the reports with this command:
+#
+# sarg --css
+#
+# You can redirect the output to a file of your choice and edit
+# it to your liking.
+#
+#external_css_file none
+# TAG: user_authentication yes|no
+# Allow user authentication in User Reports using .htaccess
+# Parameters:
+# AuthUserTemplateFile - The template to use to create the
+# .htaccess file. In the template, %u is replaced by the
+# user's ID for which the report is generated. The path of the
+# template is relative to the directory containing sarg
+# configuration file.
+#
+# user_authentication no
+# AuthUserTemplateFile sarg_htaccess
+
+# TAG: download_suffix "suffix,suffix,...,suffix"
+# file suffix to be considered as "download" in Download report.
+# Use 'none' to disable.
+#
+#download_suffix "zip,arj,bzip,gz,ace,doc,iso,adt,bin,cab,com,dot,drv$,lha,lzh,mdb,mso,ppt,rtf,src,shs,sys,exe,dll,mp3,avi,mpg,mpeg"
+
+# TAG: ulimit n
+# The maximum number of open file descriptors to avoid "Too many open files" error message.
+# You need to run sarg as root to use ulimit tag.
+# If you run sarg with a low privilege user, set to 'none' to disable ulimit
+#
+#ulimit 20000
+
+# TAG: ntlm_user_format username|domainname+username
+# NTLM users format.
+#
+#ntlm_user_format domainname+username
+ntlm_user_format {$ntlm_user_format}
+
+# TAG: realtime_refresh_time num sec
+# How many time to auto refresh the realtime report
+# 0 = disable
+#
+realtime_refresh_time 0
+
+# TAG: realtime_access_log_lines num
+# How many last lines to get from access.log file
+#
+# realtime_access_log_lines 1000
+
+# TAG: realtime_types: GET,PUT,CONNECT,ICP_QUERY,POST
+# Which records must be in realtime report.
+#
+realtime_types GET,PUT,CONNECT
+
+# TAG: realtime_unauthenticated_records: ignore|show
+# What to do with unauthenticated records in realtime report.
+#
+#
+realtime_unauthenticated_records show
+
+# TAG: byte_cost value no_cost_limit
+# Cost per byte.
+# Eg. byte_cost 0.01 100000000
+# per byte cost = 0.01
+# bytes with no cost = 100 Mb
+# 0 = disable
+#
+# byte_cost 0.01 50000000
+
+# TAG: squid24 on|off
+# Compatilibity with squid version <= 2.4 when using emulate_http_log on
+#
+# squid24 off
+
+# TAG: sorttable path
+# The path to a javascript script to dynamically sort the tables.
+# The path is the link a browser must follow to find the script. For instance,
+# it may be http://www.myproxy.org/sorttable.js or just /sorttable.js if the script
+# is at the root of your web site.
+#
+# If the path starts with "../" then it is assumed to be a relative
+# path and sarg adds as many "../" as necessary to locate the js script from
+# the output directory. Therefore, ../../sorttable.js links to the javascript
+# one level above output_dir.
+#
+# If this entry is set, each sortable table will have the "sortable" class set.
+# You may have a look at http://www.kryogenix.org/code/browser/sorttable/
+# for the implementation on which sarg is based.
+#
+sorttable /sarg_sorttable.js
+
+# TAG: hostalias
+# The name of a text file containing the host names one per line and the
+# optional alias to use in the report instead of that host name.
+# Host names may contain up to one wildcard denoted by a *. The wildcard
+# must not end the host name.
+# The host name may be followed by an optional alias but if no alias is
+# provided, the host name, including the wildcard, replaces any matching
+# host name found in the log.
+# Host names replaced by identical aliases are grouped together in the
+# reports.
+# IP addresses are supported and accept the CIDR notation both for IPv4 and
+# IPv6 addresses.
+#
+# Example:
+# *.gstatic.com
+# mt*.google.com
+# *.myphone.microsoft.com
+# *.myphone.microsoft.com:443 *.myphone.microsoft.com:secure
+# *.freeav.net antivirus:freeav
+# *.mail.live.com
+# 65.52.00.00/14 *.mail.live.com
+hostalias {$sarg_dir}/etc/sarg/hostalias
+EOF;
+?>
diff --git a/config/sarg/sarg.xml b/config/sarg/sarg.xml
new file mode 100644
index 00000000..bb345379
--- /dev/null
+++ b/config/sarg/sarg.xml
@@ -0,0 +1,371 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE packagegui SYSTEM "./schema/packages.dtd">
+<?xml-stylesheet type="text/xsl" href="./xsl/package.xsl"?>
+<packagegui>
+ <copyright>
+ <![CDATA[
+/* $Id$ */
+/* ========================================================================== */
+/*
+ sarg.xml
+ part of the sarg for pfSense
+ Copyright (C) 2012 Marcello Coutinho
+
+ 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.
+
+ THIS SOFTWARE IS PROVIDED ``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
+ AUTHOR 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.
+ */
+/* ========================================================================== */
+ ]]>
+ </copyright>
+ <description>Describe your package here</description>
+ <requirements>Describe your package requirements here</requirements>
+ <faq>Currently there are no FAQ items provided.</faq>
+ <name>sarg</name>
+ <version>1.0</version>
+ <title>Status: Sarg Settings</title>
+ <include_file>/usr/local/pkg/sarg.inc</include_file>
+ <menu>
+ <name>Sarg Reports</name>
+ <tooltiptext>Configure sarg</tooltiptext>
+ <section>Status</section>
+ <url>/pkg_edit.php?xml=sarg.xml</url>
+ </menu>
+ <additional_files_needed>
+ <item>http://www.pfsense.org/packages/config/sarg/sarg.inc</item>
+ <prefix>/usr/local/pkg/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.org/packages/config/sarg/sarg_schedule.xml</item>
+ <prefix>/usr/local/pkg/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.org/packages/config/sarg/sarg_sync.xml</item>
+ <prefix>/usr/local/pkg/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.org/packages/config/sarg/sarg_users.xml</item>
+ <prefix>/usr/local/pkg/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.org/packages/config/sarg/sarg_realtime.php</item>
+ <prefix>/usr/local/www/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.org/packages/config/sarg/sarg_about.php</item>
+ <prefix>/usr/local/www/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.org/packages/config/sarg/sarg.php</item>
+ <prefix>/usr/local/www/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.org/packages/config/sarg/sarg_reports.php</item>
+ <prefix>/usr/local/www/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.org/packages/config/sarg/sarg_frame.php</item>
+ <prefix>/usr/local/www/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.org/packages/config/sarg/sarg_sorttable.js</item>
+ <prefix>/usr/local/www/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.org/packages/config/sarg/sarg.template</item>
+ <prefix>/usr/local/pkg/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.org/packages/config/sarg/sarg.priv.inc</item>
+ <prefix>/etc/inc/priv/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <tabs>
+ <tab>
+ <text>General</text>
+ <url>/pkg_edit.php?xml=sarg.xml&amp;id=0</url>
+ <active/>
+ </tab>
+ <tab>
+ <text>Users</text>
+ <url>/pkg_edit.php?xml=sarg_users.xml&amp;id=0</url>
+ </tab>
+ <tab>
+ <text>Schedule</text>
+ <url>/pkg.php?xml=sarg_schedule.xml&amp;id=0</url>
+ </tab>
+ <tab>
+ <text>View Report</text>
+ <url>/sarg_reports.php</url>
+ </tab>
+ <tab>
+ <text>Realtime</text>
+ <url>/sarg_realtime.php</url>
+ </tab>
+ <tab>
+ <text>XMLRPC Sync</text>
+ <url>/pkg_edit.php?xml=sarg_sync.xml&amp;id=0</url>
+ </tab>
+ <tab>
+ <text>Help</text>
+ <url>/sarg_about.php</url>
+ </tab>
+</tabs>
+ <fields>
+ <field>
+ <name>Report Settings</name>
+ <type>listtopic</type>
+ </field>
+ <field>
+ <fielddescr>Proxy server</fielddescr>
+ <fieldname>proxy_server</fieldname>
+ <description><![CDATA[Select proxy server to read logs from]]></description>
+ <type>select</type>
+ <options>
+ <option><name>Dansguardian</name><value>dansguardian</value></option>
+ <option><name>Squidguard</name><value>squidguard</value></option>
+ <option><name>Squid</name><value>squid</value></option>
+ </options>
+ </field>
+ <field>
+ <fielddescr>Report Options</fielddescr>
+ <fieldname>report_options</fieldname>
+ <description><![CDATA[Sarg report options. Default values are in ( )<br>
+ If you select any option, it will be enabled on conf file.<br>
+ Use CTRL + click on this field]]></description>
+ <type>select</type>
+ <options>
+ <option><name>Use graphics where is possible. (yes)</name><value>use_graphs</value></option>
+ <option><name>Use anonymous file and directory names in the report. (no)</name><value>anonymous_output_files </value></option>
+ <option><name>Convert ip address to dns name (no)</name><value>resolve_ip</value></option>
+ <option><name>Use Ip Address instead userid in reports. (no)</name><value>user_ip</value></option>
+ <option><name>Sort Fields in Reverse order (no)</name><value>user_sort_field_order</value></option>
+ <option><name>Remove temporary files from root report directory (yes)</name><value>remove_temp_files</value></option>
+ <option><name>Generate the main index.html (yes)</name><value>main_index</value></option>
+ <option><name>Generate the index tree by file (yes)</name><value>index_tree</value></option>
+ <option><name>Overwrite report (no)</name><value>overwrite_report</value></option>
+ <option><name>Use comma instead point in reports (yes)</name><value>use_comma</value></option>
+ <option><name>Show full url in report (no)</name><value>long_url</value></option>
+ <option><name>Privacy (no)</name><value>privacy</value></option>
+ <option><name>Show Bytes in sites users reports(no)</name><value>bytes_in_sites_users_report</value></option>
+ <option><name>Show values in reports using abbreviation (no)</name><value>displayed_values</value></option>
+ <option><name>Show the downloaded volume on Date/Time reports (yes)</name><value>date_time_by_bytes</value></option>
+ <option><name>Show the downloaded elapsed time on Date/Time reports (no)</name><value>date_time_by_elap</value></option>
+ </options>
+ <multiple/>
+ <size>17</size>
+ </field>
+ <field>
+ <fielddescr>Report to generate</fielddescr>
+ <fieldname>report_type</fieldname>
+ <description><![CDATA[Sarg report type. All are enabled by default<br>
+ Use CTRL + click on this field]]></description>
+ <type>select</type>
+ <options>
+ <option><name>topusers - users, sites, times, bytes, connects, links to accessed sites, etc</name><value>topusers</value></option>
+ <option><name>topsites - site, connect and bytes report</name><value>topsites</value></option>
+ <option><name>sites_users - users and sites report</name><value>sites_users</value></option>
+ <option><name>users_sites - accessed sites by the user report</name><value>users_sites</value></option>
+ <option><name>date_time - bytes used per day and hour report</name><value>date_time</value></option>
+ <option><name>denied - denied sites with full URL report</name><value>denied</value></option>
+ <option><name>auth_failures - autentication failures report</name><value>auth_failures</value></option>
+ <option><name>site_user_time_date - sites, dates, times and bytes report</name><value>site_user_time_date</value></option>
+ <option><name>downloads - downloads per user report</name><value>downloads</value></option>
+ </options>
+ <multiple/>
+ <size>10</size>
+ </field>
+ <field>
+ <fielddescr>Date Format</fielddescr>
+ <fieldname>report_date_format</fieldname>
+ <description><![CDATA[Date format to use in reports.]]></description>
+ <type>select</type>
+ <options>
+ <option><name>American mm/dd/yy (default)</name><value>u</value></option>
+ <option><name>European dd/mm/yy</name><value>e</value></option>
+ <option><name>Weekly yy.ww</name><value>w</value></option>
+ </options>
+ </field>
+ <field>
+ <fielddescr>Report charset</fielddescr>
+ <fieldname>report_charset</fieldname>
+ <description><![CDATA[ISO 8859 is a full series of 10 standardized multilingual single-byte coded (8bit) graphic character sets for writing in alphabetic languages]]></description>
+ <type>select</type>
+ <options>
+ <option><name>UTF-8 (Default)</name><value>UTF-8</value></option>
+ <option><name>Latin1 - West European</name><value>Latin1</value></option>
+ <option><name>Latin2 - East European</name><value>Latin2</value></option>
+ <option><name>Latin3 - South European</name><value>Latin3</value></option>
+ <option><name>Latin4 - North European</name><value>Latin4</value></option>
+ <option><name>Latin5 - Turkish</name><value>Latin5</value></option>
+ <option><name>Latin6</name><value>Latin6</value></option>
+ <option><name>Cyrillic</name><value>Cyrillic</value></option>
+ <option><name>Arabic</name><value>Arabic</value></option>
+ <option><name>Greek</name><value>Greek</value></option>
+ <option><name>Hebrew</name><value>Hebrew</value></option>
+ <option><name>Windows-1251</name><value>Windows-1251</value></option>
+ <option><name>Japan</name><value>Japan</value></option>
+ <option><name>Koi8-r</name><value>Koi8-r</value></option>
+ </options>
+ </field>
+ <field>
+ <fielddescr>Host Aliases</fielddescr>
+ <fieldname>hostalias</fieldname>
+ <description><![CDATA[The name of a text file containing the host names one per line and the optional alias to use in the report instead of that host name.<br>
+ Host names may contain up to one wildcard denoted by a *. The wildcard must not end the host name.<br>
+ The host name may be followed by an optional alias but if no alias is provided, the host name, including the wildcard, replaces any matching host name found in the log.<br>
+ Host names replaced by identical aliases are grouped together in the reports.<br>
+ IP addresses are supported and accept the CIDR notation both for IPv4 and IPv6 addresses.<br>
+ Sample:<br>
+ *.gstatic.com<br>
+ mt*.google.com<br>
+ *.myphone.microsoft.com<br>
+ *.myphone.microsoft.com:443 *.myphone.microsoft.com:secure<br>
+ *.freeav.net antivirus:freeav<br>
+ *.mail.live.com<br>
+ 65.52.00.00/14 *.mail.live.com]]></description>
+ <type>textarea</type>
+ <cols>70</cols>
+ <rows>10</rows>
+ <encoding>base64</encoding>
+ </field>
+ <field>
+ <name>Limit Settings</name>
+ <type>listtopic</type>
+ </field>
+ <field>
+ <fielddescr>Max Elapsed</fielddescr>
+ <fieldname>max_elapsed</fieldname>
+ <description><![CDATA[If elapsed time is recorded in log is greater than max_elapsed use 0 for elapsed time.<br>
+ Samples: 0 means no checking<br>
+ 28800000 means 08 hours ]]></description>
+ <type>input</type>
+ <size>10</size>
+ </field>
+ <field>
+ <fielddescr>Reports list limits</fielddescr>
+ <fieldname>lastlog</fieldname>
+ <description><![CDATA[How many reports files must be kept in reports directory.<br>
+ The oldest report file will be automatically removed.0 means no limit.]]></description>
+ <type>input</type>
+ <size>10</size>
+ </field>
+ <field>
+ <fielddescr>Reports days limits</fielddescr>
+ <fieldname>daylimit</fieldname>
+ <description><![CDATA[How many days reports files must be kept in reports directory.<br>
+ Older report file will be automatically removed.<br>
+ Leave empty to do not remove old reports.]]></description>
+ <type>input</type>
+ <size>10</size>
+ </field>
+ <field>
+ <fielddescr>Top Users Limit</fielddescr>
+ <fieldname>topuser_num</fieldname>
+ <description><![CDATA[How many users in topsites report. 0 = no limit]]></description>
+ <type>input</type>
+ <size>10</size>
+ </field>
+ <field>
+ <fielddescr>Denied Limit</fielddescr>
+ <fieldname>denied_report_limit</fieldname>
+ <description><![CDATA[0 means no limit.]]></description>
+ <type>input</type>
+ <size>10</size>
+ </field>
+ <field>
+ <fielddescr>AuthFail Limit</fielddescr>
+ <fieldname>authfail_report_limit</fieldname>
+ <description><![CDATA[0 means no limit.]]></description>
+ <type>input</type>
+ <size>10</size>
+ </field>
+ <field>
+ <fielddescr>User_report_limit</fielddescr>
+ <fieldname>user_report_limit</fieldname>
+ <description><![CDATA[0 means no limit.]]></description>
+ <type>input</type>
+ <size>10</size>
+ </field>
+ <field>
+ <name>Exclude Settings</name>
+ <type>listtopic</type>
+ </field>
+ <field>
+ <fielddescr>Exclude string</fielddescr>
+ <fieldname>exclude_string</fieldname>
+ <description><![CDATA[Records from access.log file that contain one of listed strings will be ignored.<br>
+ <strong>Format: string1:string2:...:stringn</strong>]]></description>
+ <type>input</type>
+ <size>70</size>
+ </field>
+ <field>
+ <fielddescr>Exclude hosts</fielddescr>
+ <fieldname>exclude_hostlist</fieldname>
+ <description><![CDATA[Hosts, domains or subnets will be excluded from reports.<br>
+ Eg.: 192.168.10.10 - exclude ip address only<br>
+ 192.168.10.0/24 - exclude full C class<br>
+ s1.acme.foo - exclude hostname only<br>
+ *.acme.foo - exclude full domain name]]></description>
+ <type>textarea</type>
+ <cols>70</cols>
+ <rows>10</rows>
+ <encoding>base64</encoding>
+ </field>
+ <field>
+ <fielddescr>Exclude codes</fielddescr>
+ <fieldname>exclude_codelist</fieldname>
+ <description><![CDATA[Ignore records with these codes. Eg.: NONE/400<br>
+ Write one code per line. Lines starting with a # are ignored.<br>
+ Only codes matching exactly one of the line is rejected. The comparison is not case sensitive.]]></description>
+ <type>textarea</type>
+ <cols>70</cols>
+ <rows>10</rows>
+ <encoding>base64</encoding>
+ </field>
+ </fields>
+ <custom_php_install_command>
+ sarg_php_install_command();
+ </custom_php_install_command>
+ <custom_php_deinstall_command>
+ sarg_php_deinstall_command();
+ </custom_php_deinstall_command>
+ <custom_php_validation_command>
+ sarg_validate_input($_POST, &amp;$input_errors);
+ </custom_php_validation_command>
+ <custom_php_resync_config_command>
+ sync_package_sarg();
+ </custom_php_resync_config_command>
+</packagegui>
diff --git a/config/sarg/sarg_about.php b/config/sarg/sarg_about.php
new file mode 100755
index 00000000..1321adf6
--- /dev/null
+++ b/config/sarg/sarg_about.php
@@ -0,0 +1,103 @@
+<?php
+/*
+ sarg_about.php
+ part of pfSense (http://www.pfsense.com/)
+ Copyright (C) 2012 Marcello Coutinho <marcellocoutinho@gmail.com>
+ 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.
+
+ THIS SOFTWARE IS PROVIDED ``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
+ AUTHOR 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.
+*/
+
+require("guiconfig.inc");
+
+$pfSversion = str_replace("\n", "", file_get_contents("/etc/version"));
+if(strstr($pfSversion, "1.2"))
+ $one_two = true;
+
+$pgtitle = "About: Sarg Package";
+include("head.inc");
+
+?>
+<body link="#0000CC" vlink="#0000CC" alink="#0000CC">
+<?php include("fbegin.inc"); ?>
+
+<?php if($one_two): ?>
+<p class="pgtitle"><?=$pgtitle?></font></p>
+<?php endif; ?>
+<?php if ($input_errors) print_input_errors($input_errors); ?>
+<?php if ($savemsg) print_info_box($savemsg); ?>
+
+
+<div id="mainlevel">
+ <table width="100%" border="0" cellpadding="0" cellspacing="0">
+ <tr><td>
+ <?php
+ $tab_array = array();
+ $tab_array[] = array(gettext("General"), false, "/pkg_edit.php?xml=sarg.xml&id=0");
+ $tab_array[] = array(gettext("Users"), false, "/pkg_edit.php?xml=sarg_users.xml&id=0");
+ $tab_array[] = array(gettext("Schedule"), false, "/pkg.php?xml=sarg_schedule.xml");
+ $tab_array[] = array(gettext("View Report"), false, "/sarg_reports.php");
+ $tab_array[] = array(gettext("Realtime"), false, "/sarg_realtime.php");
+ $tab_array[] = array(gettext("XMLRPC Sync"), false, "/pkg_edit.php?xml=sarg_sync.xml&id=0");
+ $tab_array[] = array(gettext("Help"), true, "/sarg_about.php");
+ display_top_tabs($tab_array);
+?>
+ </td></tr>
+ <tr>
+
+ <td>
+ <div id="mainarea">
+ <table class="tabcont" width="100%" border="0" cellpadding="8" cellspacing="0">
+ <tr><td></td></tr>
+ <tr>
+ <td colspan="2" valign="top" class="listtopic"><?=gettext("Help docs"); ?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?=gettext("Sarg Site");?></td>
+ <td width="78%" class="vtable"><?=gettext("<a target=_new href='http://sarg.sourceforge.net/welcome.php'>Squid Analysis Report Generator</a><br><br>");?>
+ </tr>
+ <tr>
+ <td colspan="2" valign="top" class="listtopic"><?=gettext("About sarg package"); ?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?=gettext("Credits ");?></td>
+ <td width="78%" class="vtable"><?=gettext("Package Created by <a target=_new href='http://forum.pfsense.org/index.php?action=profile;u=4710'>Marcello Coutinho</a><br><br>");?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?=gettext("Donatios ");?></td>
+ <td width="78%" class="vtable"><?=gettext("If you like this package, please <a target=_new href='http://www.pfsense.org/index.php?option=com_content&task=view&id=47&Itemid=77'>donate to pfSense project</a>.<br><br>
+ If you want that your donation goes to this package developer, make a note on donation forwarding it to me.<br><br>");?></td>
+ </tr>
+ </table>
+
+ </div>
+ </td>
+ </tr>
+
+
+ </table>
+ <br>
+ <div id="search_results"></div>
+</div>
+<?php include("fend.inc"); ?>
+</body>
+</html>
diff --git a/config/sarg/sarg_frame.php b/config/sarg/sarg_frame.php
new file mode 100755
index 00000000..4d3421ab
--- /dev/null
+++ b/config/sarg/sarg_frame.php
@@ -0,0 +1,81 @@
+<?php
+/*
+ sarg_frame.php
+ part of pfSense (http://www.pfsense.com/)
+ Copyright (C) 2012 Marcello Coutinho <marcellocoutinho@gmail.com>
+ based on varnish_view_config.
+ 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.
+
+ THIS SOFTWARE IS PROVIDED ``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
+ AUTHOR 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.
+*/
+require_once("authgui.inc");
+
+$uname=posix_uname();
+if ($uname['machine']=='amd64')
+ ini_set('memory_limit', '250M');
+
+if(preg_match("/(\S+)\W(\w+.html)/",$_REQUEST['file'],$matches)){
+ #https://192.168.1.1/sarg_reports.php?file=2012Mar30-2012Mar30/index.html
+ $url=$matches[2];
+ $prefix=$matches[1];
+ }
+else{
+ $url="index.html";
+ $prefix="";
+ }
+$url=($_REQUEST['file'] == ""?"index.html":$_REQUEST['file']);
+$dir="/usr/local/sarg-reports";
+$rand=rand(100000000000,999999999999);
+$report="";
+if (file_exists("{$dir}/{$url}"))
+ $report=file_get_contents("{$dir}/{$url}");
+else if (file_exists("{$dir}/{$url}.gz")) {
+ $data = gzfile("{$dir}/{$url}.gz");
+ $report = implode($data);
+ unset ($data);
+ }
+if ($report != "" )
+ {
+ $pattern[0]="/href=\W(\S+html)\W/";
+ $replace[0]="href=/sarg_frame.php?prevent=".$rand."&file=$prefix/$1";
+ $pattern[1]='/img src="\S+\W([a-zA-Z0-9.-]+.png)/';
+ $replace[1]='img src="/sarg-images/$1';
+ $pattern[2]='@img src="([.a-z/]+)/(\w+\.\w+)@';
+ $replace[2]='img src="/sarg-images'.$prefix.'/$1/$2';
+ $pattern[3]='/img src="([a-zA-Z0-9.-_]+).png/';
+ $replace[3]='img src="/sarg-images/temp/$1.'.$rand.'.png';
+ $pattern[4]='/<head>/';
+ $replace[4]='<head><META HTTP-EQUIV="CACHE-CONTROL" CONTENT="NO-CACHE"><META HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE">';
+
+ #look for graph files inside reports.
+ if (preg_match_all('/img src="([a-zA-Z0-9._-]+).png/',$report,$images)){
+ for ($x=0;$x<count($images[1]);$x++){
+ copy("{$dir}/{$prefix}/{$images[1][$x]}.png","/usr/local/www/sarg-images/temp/{$images[1][$x]}.{$rand}.png");
+ }
+ }
+ print preg_replace($pattern,$replace,$report);
+ }
+else{
+ print "<pre>Error: Could not find report index file.<br>Check and save sarg settings and try to force sarg schedule.";
+ }
+
+?> \ No newline at end of file
diff --git a/config/sarg/sarg_realtime.php b/config/sarg/sarg_realtime.php
new file mode 100755
index 00000000..76e89769
--- /dev/null
+++ b/config/sarg/sarg_realtime.php
@@ -0,0 +1,258 @@
+<?php
+/*
+ sarg_realtime.php
+ part of pfSense (http://www.pfsense.com/)
+ Copyright (C) 2012 Marcello Coutinho <marcellocoutinho@gmail.com>
+ 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.
+
+ THIS SOFTWARE IS PROVIDED ``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
+ AUTHOR 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.
+*/
+
+$pf_version=substr(trim(file_get_contents("/etc/version")),0,3);
+if ($pf_version > 2.0)
+ define('SARG_DIR', '/usr/pbi/sarg-' . php_uname("m"));
+else
+ define('SARG_DIR', '/usr/local');
+
+$uname=posix_uname();
+if ($uname['machine']=='amd64')
+ ini_set('memory_limit', '250M');
+
+
+function get_cmd(){
+ global $config,$g;
+ #print $_REQUEST['type'];
+ if ($_REQUEST['cmd'] =='sarg'){
+ $update_config=0;
+ #Check report xml info
+ if (!is_array($config['installedpackages']['sargrealtime'])){
+ $config['installedpackages']['sargrealtime']['config'][0]['realtime_types']= "";
+ $config['installedpackages']['sargrealtime']['config'][0]['realtime_users']= "";
+ }
+ #Check report http actions to show
+ if ($config['installedpackages']['sargrealtime']['config'][0]['realtime_types'] != $_REQUEST['qshape']){
+ $config['installedpackages']['sargrealtime']['config'][0]['realtime_types']= $_REQUEST['qshape'];
+ $update_config++;
+ }
+
+ #Check report users show
+ if ($config['installedpackages']['sargrealtime']['config'][0]['realtime_users'] != $_REQUEST['type']){
+ $config['installedpackages']['sargrealtime']['config'][0]['realtime_users']= $_REQUEST['type'];
+ $update_config++;
+ }
+
+ if($update_config > 0){
+ write_config();
+ #write changes to sarg_file
+ $sarg_config=file_get_contents(SARG_DIR . '/etc/sarg/sarg.conf');
+ $pattern[0]='/realtime_types\s+[A-Z,,]+/';
+ $replace[0]="realtime_types ".$_REQUEST['qshape'];
+ $pattern[1]='/realtime_unauthenticated_records\s+\w+/';
+ $replace[1]="realtime_unauthenticated_records ".$_REQUEST['type'];
+ file_put_contents(SARG_DIR . '/etc/sarg/sarg.conf', preg_replace($pattern,$replace,$sarg_config),LOCK_EX);
+ }
+ exec(SARG_DIR ."/bin/sarg -r",$sarg);
+ $pattern[0]="/<?(html|head|style)>/";
+ $replace[0]="";
+ $pattern[1]="/header_\w/";
+ $replace[1]="listtopic";
+ $pattern[2]="/class=.data./";
+ $replace[2]='class="listlr"';
+ $pattern[3]="/cellpadding=.\d./";
+ $replace[3]='cellpadding="0"';
+ $pattern[4]="/cellspacing=.\d./";
+ $replace[4]='cellspacing="0"';
+ $pattern[5]="/sarg/";
+ $replace[5]='cellspacing="0"';
+ foreach ($sarg as $line){
+ if (preg_match("/<.head>/",$line))
+ $print ="ok";
+ if ($print =="ok" && !preg_match("/(sarg realtime|Auto Refresh)/i",$line))
+ print preg_replace($pattern,$replace,$line);
+ }
+ }
+}
+
+if ($_REQUEST['cmd']!=""){
+ require_once("authgui.inc");
+ require_once("functions.inc");
+ get_cmd();
+ }
+else{
+ require("guiconfig.inc");
+ $pfSversion = str_replace("\n", "", file_get_contents("/etc/version"));
+ if(strstr($pfSversion, "1.2"))
+ $one_two = true;
+
+ $pgtitle = "Status: Sarg Realtime";
+ include("head.inc");
+
+ ?>
+ <body link="#0000CC" vlink="#0000CC" alink="#0000CC">
+ <?php include("fbegin.inc"); ?>
+
+ <?php if($one_two): ?>
+ <p class="pgtitle"><?=$pgtitle?></font></p>
+ <?php endif; ?>
+
+ <?php if ($savemsg) print_info_box($savemsg); ?>
+
+ <form action="sarg_realtime.php" method="post">
+
+ <div id="mainlevel">
+ <table width="100%" border="0" cellpadding="0" cellspacing="0">
+ <tr><td>
+ <?php
+ $tab_array = array();
+ $tab_array[] = array(gettext("General"), false, "/pkg_edit.php?xml=sarg.xml&id=0");
+ $tab_array[] = array(gettext("Users"), false, "/pkg_edit.php?xml=sarg_users.xml&id=0");
+ $tab_array[] = array(gettext("Schedule"), false, "/pkg.php?xml=sarg_schedule.xml");
+ $tab_array[] = array(gettext("View Report"), false, "/sarg_reports.php");
+ $tab_array[] = array(gettext("Realtime"), true, "/sarg_realtime.php");
+ $tab_array[] = array(gettext("XMLRPC Sync"), false, "/pkg_edit.php?xml=sarg_sync.xml&id=0");
+ $tab_array[] = array(gettext("Help"), false, "/sarg_about.php");
+ display_top_tabs($tab_array);
+ ?>
+ </td></tr>
+ <tr>
+ <td>
+ <div id="mainarea">
+ <table class="tabcont" width="100%" border="0" cellpadding="8" cellspacing="0">
+ <tr><td></td></tr>
+ <tr>
+ <td colspan="2" valign="top" class="listtopic"><?=gettext("Sarg Realtime"); ?></td></tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?=gettext("Log command: ");?></td>
+ <td width="78%" class="vtable">
+ <select name="drop3" id="cmd">
+ <option value="sarg" selected="selected">Sarg Realtime</option>
+ </select><br><?=gettext("Select report command to run.");?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?=gettext("update frequency: ");?></td>
+ <td width="78%" class="vtable">
+ <select name="drop3" id="updatef">
+ <option value="1">01 second</option>
+ <option value="3" selected="selected">03 seconds</option>
+ <option value="5">05 seconds</option>
+ <option value="15">15 Seconds</option>
+ <option value="30">30 Seconds</option>
+ <option value="60">One minute</option>
+ <option value="1">Never</option>
+ </select><br><?=gettext("Select how often report will run.");?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?=gettext("Report Types: ");?></td>
+ <td width="78%" class="vtable">
+ <select name="drop3" id="qshape" multiple="multiple" size="5">
+ <option value="GET" selected="selected">GET</option>
+ <option value="PUT" selected="selected">PUT</option>
+ <option value="CONNECT" selected="selected">CONNECT</option>
+ <option value="ICP_QUERY">ICP_QUERY</option>
+ <option value="POST">POST</option>
+ </select><br><?=gettext("Which records must be in realtime report.");?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?=gettext("unauthenticated_records: ");?></td>
+ <td width="78%" class="vtable">
+ <select name="drop3" id="qtype">
+ <option value="show" selected>show</option>
+ <option value="hide">hide</option>
+ </select><br><?=gettext("What to do with unauthenticated records in realtime report.");?></td>
+ </tr>
+
+ <tr>
+ <td width="22%" valign="top"></td>
+ <td width="78%"><input name="Submit" type="button" class="formbtn" id="run" value="<?=gettext("show log");?>" onclick="get_queue('mailq')"><div id="search_help"></div></td>
+ </table>
+ </div>
+ </td>
+ </tr>
+ </table>
+ <br>
+ <div>
+ <table class="tabcont" width="100%" border="0" cellpadding="8" cellspacing="0">
+ <tr>
+ <td class="tabcont" >
+ <div id="file_div"></div>
+
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </form>
+ <script type="text/javascript">
+ function loopSelected(id)
+ {
+ var selectedArray = new Array();
+ var selObj = document.getElementById(id);
+ var i;
+ var count = 0;
+ for (i=0; i<selObj.options.length; i++) {
+ if (selObj.options[i].selected) {
+ selectedArray[count] = selObj.options[i].value;
+ count++;
+ }
+ }
+ return(selectedArray);
+ }
+ function get_queue(loop) {
+ //prevent multiple instances
+ if ($('run').value=="show log" || loop== 'running'){
+ $('run').value="running...";
+ $('search_help').innerHTML ="<br><strong>You can change options while running.<br>To Stop seach, change update frequency to Never.</strong>";
+ var axel = Math.random() + "";
+ var num = axel * 1000000000000000000;
+ var q_args=loopSelected('qshape');
+ var pars = 'cmd='+$('cmd').options[$('cmd').selectedIndex].value;
+ var pars = pars + '&qshape='+q_args;
+ var pars = pars + '&prevent='+num;
+ var pars = pars + '&type='+$('qtype').options[$('qtype').selectedIndex].value;
+ var url = "/sarg_realtime.php";
+ var myAjax = new Ajax.Request(
+ url,
+ {
+ method: 'post',
+ parameters: pars,
+ onComplete: activitycallback_queue_file
+ });
+ }
+ }
+ function activitycallback_queue_file(transport) {
+ $('file_div').innerHTML = transport.responseText;
+ var update=$('updatef').options[$('updatef').selectedIndex].value * 1000;
+ if (update > 999){
+ setTimeout('get_queue("running")', update);
+ }
+ else{
+ $('run').value="show log";
+ $('search_help').innerHTML ="";
+ }
+ }
+ </script>
+ <?php
+ include("fend.inc");
+ }
+ ?>
+ </body>
+ </html>
diff --git a/config/sarg/sarg_reports.php b/config/sarg/sarg_reports.php
new file mode 100755
index 00000000..b1792312
--- /dev/null
+++ b/config/sarg/sarg_reports.php
@@ -0,0 +1,93 @@
+<?php
+/*
+ sarg_reports.php
+ part of pfSense (http://www.pfsense.com/)
+ Copyright (C) 2012 Marcello Coutinho <marcellocoutinho@gmail.com>
+ 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.
+
+ THIS SOFTWARE IS PROVIDED ``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
+ AUTHOR 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.
+*/
+
+require("guiconfig.inc");
+
+ $pfSversion = str_replace("\n", "", file_get_contents("/etc/version"));
+ if(strstr($pfSversion, "1.2"))
+ $one_two = true;
+
+ $pgtitle = "Status: Sarg Reports";
+ include("head.inc");
+
+ ?>
+ <body link="#0000CC" vlink="#0000CC" alink="#0000CC">
+ <?php include("fbegin.inc"); ?>
+
+ <?php if($one_two): ?>
+ <p class="pgtitle"><?=$pgtitle?></font></p>
+ <?php endif; ?>
+
+ <?php if ($savemsg) print_info_box($savemsg); ?>
+
+ <form>
+
+ <div id="mainlevel">
+ <table width="100%" border="0" cellpadding="0" cellspacing="0">
+ <tr><td>
+ <?php
+ $tab_array = array();
+ $tab_array[] = array(gettext("General"), false, "/pkg_edit.php?xml=sarg.xml&id=0");
+ $tab_array[] = array(gettext("Users"), false, "/pkg_edit.php?xml=sarg_users.xml&id=0");
+ $tab_array[] = array(gettext("Schedule"), false, "/pkg.php?xml=sarg_schedule.xml");
+ $tab_array[] = array(gettext("View Report"), true, "/sarg_reports.php");
+ $tab_array[] = array(gettext("Realtime"), false, "/sarg_realtime.php");
+ $tab_array[] = array(gettext("XMLRPC Sync"), false, "/pkg_edit.php?xml=sarg_sync.xml&id=0");
+ $tab_array[] = array(gettext("Help"), false, "/pkg_edit.php?xml=sarg_about.php");
+ display_top_tabs($tab_array);
+ exec('rm -f /usr/local/www/sarg-images/temp/*');
+ ?>
+ </td></tr>
+ <tr>
+ <td>
+ <div id="mainarea">
+ <table class="tabcont" width="100%" border="0" cellpadding="8" cellspacing="0">
+ <tr><td></td></tr>
+ <tr>
+ <td colspan="2" valign="top" class="listtopic"><?=gettext("Sarg Reports"); ?></td></tr>
+ </table>
+ </div>
+ <br>
+ <script language="JavaScript">
+ var axel = Math.random() + "";
+ var num = axel * 1000000000000000000;
+ document.writeln('<IFRAME SRC="/sarg_frame.php?prevent='+ num +'?" frameborder=0 width="100%" height="600"></IFRAME>');
+ </script>
+ <div id="file_div"></div>
+
+ </td>
+ </tr>
+ </table>
+ </div>
+ </form>
+ <?php
+ include("fend.inc");
+ ?>
+ </body>
+ </html>
diff --git a/config/sarg/sarg_schedule.xml b/config/sarg/sarg_schedule.xml
new file mode 100644
index 00000000..0c452335
--- /dev/null
+++ b/config/sarg/sarg_schedule.xml
@@ -0,0 +1,224 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE packagegui SYSTEM "./schema/packages.dtd">
+<?xml-stylesheet type="text/xsl" href="./xsl/package.xsl"?>
+<packagegui>
+ <copyright>
+ <![CDATA[
+/* ========================================================================== */
+/*
+ sarg_schedule.xml
+ part of pfSense (http://www.pfSense.com)
+ Copyright (C) 2012 Marcello Coutinho
+ 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.
+
+ THIS SOFTWARE IS PROVIDED ``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
+ AUTHOR 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.
+ */
+/* ========================================================================== */
+ ]]>
+ </copyright>
+ <description>Describe your package here</description>
+ <requirements>Describe your package requirements here</requirements>
+ <faq>Currently there are no FAQ items provided.</faq>
+ <name>sargschedule</name>
+ <version>0.5</version>
+ <title>Status: Sarg Schedules</title>
+ <include_file>/usr/local/pkg/sarg.inc</include_file>
+ <additional_files_needed>
+ <prefix>/usr/local/pkg/</prefix>
+ <chmod>0755</chmod>
+ <item>http://www.pfsense.com/packages/config/sarg/sarg.inc</item>
+ </additional_files_needed>
+ <additional_files_needed>
+ <prefix>/usr/local/pkg/</prefix>
+ <chmod>0755</chmod>
+ <item>http://www.pfsense.com/packages/config/sarg/sarg_sync.xml</item>
+ </additional_files_needed>
+ <menu>
+ <name>sarg</name>
+ <tooltiptext>sarg</tooltiptext>
+ <section>Diagnostics</section>
+ <configfile>sarg.xml</configfile>
+ </menu>
+ <tabs>
+ <tab>
+ <text>General</text>
+ <url>/pkg_edit.php?xml=sarg.xml&amp;id=0</url>
+ </tab>
+ <tab>
+ <text>Users</text>
+ <url>/pkg_edit.php?xml=sarg_users.xml&amp;id=0</url>
+ </tab>
+ <tab>
+ <text>Schedule</text>
+ <url>/pkg.php?xml=sarg_schedule.xml&amp;id=0</url>
+ <active/>
+ </tab>
+ <tab>
+ <text>View Report</text>
+ <url>/sarg_reports.php</url>
+ </tab>
+ <tab>
+ <text>Realtime</text>
+ <url>/sarg_realtime.php</url>
+ </tab>
+ <tab>
+ <text>XMLRPC Sync</text>
+ <url>/pkg_edit.php?xml=sarg_sync.xml&amp;id=0</url>
+ </tab>
+ <tab>
+ <text>Help</text>
+ <url>/sarg_about.php</url>
+ </tab>
+ </tabs>
+ <adddeleteeditpagefields>
+ <columnitem>
+ <fielddescr>Status</fielddescr>
+ <fieldname>enable</fieldname>
+ </columnitem>
+ <columnitem>
+ <fielddescr>Update Frequency</fielddescr>
+ <fieldname>frequency</fieldname>
+ </columnitem>
+ <columnitem>
+ <fielddescr>Aditional Args</fielddescr>
+ <fieldname>args</fieldname>
+ </columnitem>
+ <columnitem>
+ <fielddescr>Gzip</fielddescr>
+ <fieldname>gzip</fieldname>
+ </columnitem>
+ <columnitem>
+ <fielddescr>Post Action</fielddescr>
+ <fieldname>action</fieldname>
+ </columnitem>
+ <columnitem>
+ <fielddescr>Description</fielddescr>
+ <fieldname>description</fieldname>
+ </columnitem>
+ <movable>arrow</movable>
+ </adddeleteeditpagefields>
+ <fields>
+ <field>
+ <type>listtopic</type>
+ <fieldname>temp</fieldname>
+ <name>Schedule Options</name>
+ </field>
+ <field>
+ <fielddescr>Enable</fielddescr>
+ <fieldname>enable</fieldname>
+ <type>checkbox</type>
+ <description>Enable this schedule</description>
+ </field>
+ <field>
+ <fielddescr>Description</fielddescr>
+ <fieldname>description</fieldname>
+ <description>Enter a description for this file.</description>
+ <type>input</type>
+ <size>50</size>
+ </field>
+ <field>
+ <fielddescr>Sarg args</fielddescr>
+ <fieldname>args</fieldname>
+ <description><![CDATA[Enter sarg extra args to run on this schedule.<br>
+ To force sarg to create a report only from current day, use:<br>
+ <strong>-d `date +%d/%m/%Y`-`date +%d/%m/%Y`</strong>]]></description>
+ <type>input</type>
+ <size>50</size>
+ </field>
+ <field>
+ <fielddescr>frequency</fielddescr>
+ <fieldname>frequency</fieldname>
+ <type>input</type>
+ <size>5</size>
+ <description><![CDATA[How often extract users from active directory and verify changes<br>
+ Valid options are minutes(m), hours(h), days(d)<br>
+ Sample: To update every hour, use 1h<br><br>]]>&lt;input type=&quot;submit&quot; name=&quot;Submit&quot; value=&quot;Force update now&quot;&gt;&lt;br&gt;</description>
+ <required/>
+ </field>
+ <field>
+ <fielddescr>Action after sarg</fielddescr>
+ <fieldname>action</fieldname>
+ <type>select</type>
+ <options>
+ <option><name>None(default)</name><value>none</value></option>
+ <option><name>rotate logs</name><value>rotate</value></option>
+ <option><name>Restart proxy daemon</name><value>restart</value></option>
+ <option><name>Rotate log and restart proxy daemon</name><value>both</value></option>
+ </options>
+ <description>Choose an action after sarg finishes</description>
+ </field>
+ <field>
+ <type>listtopic</type>
+ <fieldname>temp</fieldname>
+ <name>Compress Options</name>
+ </field>
+ <field>
+ <fielddescr>Enable Compression</fielddescr>
+ <fieldname>gzip</fieldname>
+ <description><![CDATA[Enable this option to compress sarg report html files using gzip and reduce 4 times sarg reports data.]]></description>
+ <type>checkbox</type>
+ </field>
+ <field>
+ <fielddescr>Compression level</fielddescr>
+ <fieldname>gziplevel</fieldname>
+ <type>select</type>
+ <options>
+ <option><name>Default gzip compression (Recommended)</name><value></value></option>
+ <option><name>1 (fast)</name><value>--fast</value></option>
+ <option><name>2</name><value>-2</value></option>
+ <option><name>3</name><value>-3</value></option>
+ <option><name>4</name><value>-4</value></option>
+ <option><name>5</name><value>-5</value></option>
+ <option><name>6</name><value>-6</value></option>
+ <option><name>7</name><value>-7</value></option>
+ <option><name>8</name><value>-8</value></option>
+ <option><name>9 (best)</name><value>--best</value></option>
+ </options>
+ <description>Choose gzip compression level.</description>
+ </field>
+ <field>
+ <fielddescr>Find Limit</fielddescr>
+ <fieldname>find</fieldname>
+ <type>input</type>
+ <default_value>60</default_value>
+ <size>5</size>
+ <description><![CDATA[To speed up find process, restrict find search to report files created/changed n minutes ago.<br>
+ Default is to 60 minutes. If your reports take longer to be created, increase this value.]]></description>
+ </field>
+ </fields>
+ <custom_php_install_command>
+ sarg_php_install_command();
+ </custom_php_install_command>
+ <custom_php_command_before_form>
+ </custom_php_command_before_form>
+ <custom_php_validation_command>
+ sarg_validate_input($_POST, &amp;$input_errors);
+ </custom_php_validation_command>
+ <custom_delete_php_command>
+ sync_package_sarg();
+ </custom_delete_php_command>
+ <custom_php_resync_config_command>
+ sarg_resync();
+ </custom_php_resync_config_command>
+</packagegui>
diff --git a/config/sarg/sarg_sorttable.js b/config/sarg/sarg_sorttable.js
new file mode 100644
index 00000000..25bccb2b
--- /dev/null
+++ b/config/sarg/sarg_sorttable.js
@@ -0,0 +1,493 @@
+/*
+ SortTable
+ version 2
+ 7th April 2007
+ Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/
+
+ Instructions:
+ Download this file
+ Add <script src="sorttable.js"></script> to your HTML
+ Add class="sortable" to any table you'd like to make sortable
+ Click on the headers to sort
+
+ Thanks to many, many people for contributions and suggestions.
+ Licenced as X11: http://www.kryogenix.org/code/browser/licence.html
+ This basically means: do what you want with it.
+*/
+
+
+var stIsIE = /*@cc_on!@*/false;
+
+sorttable = {
+ init: function() {
+ // quit if this function has already been called
+ if (arguments.callee.done) return;
+ // flag this function so we don't do the same thing twice
+ arguments.callee.done = true;
+ // kill the timer
+ if (_timer) clearInterval(_timer);
+
+ if (!document.createElement || !document.getElementsByTagName) return;
+
+ sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/;
+
+ forEach(document.getElementsByTagName('table'), function(table) {
+ if (table.className.search(/\bsortable\b/) != -1) {
+ sorttable.makeSortable(table);
+ }
+ });
+
+ },
+
+ makeSortable: function(table) {
+ if (table.getElementsByTagName('thead').length == 0) {
+ // table doesn't have a tHead. Since it should have, create one and
+ // put the first table row in it.
+ the = document.createElement('thead');
+ the.appendChild(table.rows[0]);
+ table.insertBefore(the,table.firstChild);
+ }
+ // Safari doesn't support table.tHead, sigh
+ if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0];
+
+ if (table.tHead.rows.length != 1) return; // can't cope with two header rows
+
+ // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as
+ // "total" rows, for example). This is B&R, since what you're supposed
+ // to do is put them in a tfoot. So, if there are sortbottom rows,
+ // for backwards compatibility, move them to tfoot (creating it if needed).
+ sortbottomrows = [];
+ for (var i=0; i<table.rows.length; i++) {
+ if (table.rows[i].className.search(/\bsortbottom\b/) != -1) {
+ sortbottomrows[sortbottomrows.length] = table.rows[i];
+ }
+ }
+ if (sortbottomrows) {
+ if (table.tFoot == null) {
+ // table doesn't have a tfoot. Create one.
+ tfo = document.createElement('tfoot');
+ table.appendChild(tfo);
+ }
+ for (var i=0; i<sortbottomrows.length; i++) {
+ tfo.appendChild(sortbottomrows[i]);
+ }
+ delete sortbottomrows;
+ }
+
+ // work through each column and calculate its type
+ headrow = table.tHead.rows[0].cells;
+ for (var i=0; i<headrow.length; i++) {
+ // manually override the type with a sorttable_type attribute
+ if (!headrow[i].className.match(/\bsorttable_nosort\b/)) { // skip this col
+ mtch = headrow[i].className.match(/\bsorttable_([a-z0-9]+)\b/);
+ if (mtch) { override = mtch[1]; }
+ if (mtch && typeof sorttable["sort_"+override] == 'function') {
+ headrow[i].sorttable_sortfunction = sorttable["sort_"+override];
+ } else {
+ headrow[i].sorttable_sortfunction = sorttable.guessType(table,i);
+ }
+ // make it clickable to sort
+ headrow[i].sorttable_columnindex = i;
+ headrow[i].sorttable_tbody = table.tBodies[0];
+ dean_addEvent(headrow[i],"click", function(e) {
+
+ if (this.className.search(/\bsorttable_sorted\b/) != -1) {
+ // if we're already sorted by this column, just
+ // reverse the table, which is quicker
+ sorttable.reverse(this.sorttable_tbody);
+ this.className = this.className.replace('sorttable_sorted',
+ 'sorttable_sorted_reverse');
+ this.removeChild(document.getElementById('sorttable_sortfwdind'));
+ sortrevind = document.createElement('span');
+ sortrevind.id = "sorttable_sortrevind";
+ sortrevind.innerHTML = stIsIE ? '&nbsp<font face="webdings">5</font>' : '&nbsp;&#x25B4;';
+ this.appendChild(sortrevind);
+ return;
+ }
+ if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) {
+ // if we're already sorted by this column in reverse, just
+ // re-reverse the table, which is quicker
+ sorttable.reverse(this.sorttable_tbody);
+ this.className = this.className.replace('sorttable_sorted_reverse',
+ 'sorttable_sorted');
+ this.removeChild(document.getElementById('sorttable_sortrevind'));
+ sortfwdind = document.createElement('span');
+ sortfwdind.id = "sorttable_sortfwdind";
+ sortfwdind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25BE;';
+ this.appendChild(sortfwdind);
+ return;
+ }
+
+ // remove sorttable_sorted classes
+ theadrow = this.parentNode;
+ forEach(theadrow.childNodes, function(cell) {
+ if (cell.nodeType == 1) { // an element
+ cell.className = cell.className.replace('sorttable_sorted_reverse','');
+ cell.className = cell.className.replace('sorttable_sorted','');
+ }
+ });
+ sortfwdind = document.getElementById('sorttable_sortfwdind');
+ if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); }
+ sortrevind = document.getElementById('sorttable_sortrevind');
+ if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); }
+
+ this.className += ' sorttable_sorted';
+ sortfwdind = document.createElement('span');
+ sortfwdind.id = "sorttable_sortfwdind";
+ sortfwdind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25BE;';
+ this.appendChild(sortfwdind);
+
+ // build an array to sort. This is a Schwartzian transform thing,
+ // i.e., we "decorate" each row with the actual sort key,
+ // sort based on the sort keys, and then put the rows back in order
+ // which is a lot faster because you only do getInnerText once per row
+ row_array = [];
+ col = this.sorttable_columnindex;
+ rows = this.sorttable_tbody.rows;
+ for (var j=0; j<rows.length; j++) {
+ row_array[row_array.length] = [sorttable.getInnerText(rows[j].cells[col]), rows[j]];
+ }
+ /* If you want a stable sort, uncomment the following line */
+ //sorttable.shaker_sort(row_array, this.sorttable_sortfunction);
+ /* and comment out this one */
+ row_array.sort(this.sorttable_sortfunction);
+
+ tb = this.sorttable_tbody;
+ for (var j=0; j<row_array.length; j++) {
+ tb.appendChild(row_array[j][1]);
+ }
+
+ delete row_array;
+ });
+ }
+ }
+ },
+
+ guessType: function(table, column) {
+ // guess the type of a column based on its first non-blank row
+ sortfn = sorttable.sort_alpha;
+ for (var i=0; i<table.tBodies[0].rows.length; i++) {
+ text = sorttable.getInnerText(table.tBodies[0].rows[i].cells[column]);
+ if (text != '') {
+ if (text.match(/^-?[£$¤]?[\d,.]+%?$/)) {
+ return sorttable.sort_numeric;
+ }
+ // check for a date: dd/mm/yyyy or dd/mm/yy
+ // can have / or . or - as separator
+ // can be mm/dd as well
+ possdate = text.match(sorttable.DATE_RE)
+ if (possdate) {
+ // looks like a date
+ first = parseInt(possdate[1]);
+ second = parseInt(possdate[2]);
+ if (first > 12) {
+ // definitely dd/mm
+ return sorttable.sort_ddmm;
+ } else if (second > 12) {
+ return sorttable.sort_mmdd;
+ } else {
+ // looks like a date, but we can't tell which, so assume
+ // that it's dd/mm (English imperialism!) and keep looking
+ sortfn = sorttable.sort_ddmm;
+ }
+ }
+ }
+ }
+ return sortfn;
+ },
+
+ getInnerText: function(node) {
+ // gets the text we want to use for sorting for a cell.
+ // strips leading and trailing whitespace.
+ // this is *not* a generic getInnerText function; it's special to sorttable.
+ // for example, you can override the cell text with a customkey attribute.
+ // it also gets .value for <input> fields.
+
+ hasInputs = (typeof node.getElementsByTagName == 'function') &&
+ node.getElementsByTagName('input').length;
+
+ if (node.getAttribute("sorttable_customkey") != null) {
+ return node.getAttribute("sorttable_customkey");
+ }
+ else if (typeof node.textContent != 'undefined' && !hasInputs) {
+ return node.textContent.replace(/^\s+|\s+$/g, '');
+ }
+ else if (typeof node.innerText != 'undefined' && !hasInputs) {
+ return node.innerText.replace(/^\s+|\s+$/g, '');
+ }
+ else if (typeof node.text != 'undefined' && !hasInputs) {
+ return node.text.replace(/^\s+|\s+$/g, '');
+ }
+ else {
+ switch (node.nodeType) {
+ case 3:
+ if (node.nodeName.toLowerCase() == 'input') {
+ return node.value.replace(/^\s+|\s+$/g, '');
+ }
+ case 4:
+ return node.nodeValue.replace(/^\s+|\s+$/g, '');
+ break;
+ case 1:
+ case 11:
+ var innerText = '';
+ for (var i = 0; i < node.childNodes.length; i++) {
+ innerText += sorttable.getInnerText(node.childNodes[i]);
+ }
+ return innerText.replace(/^\s+|\s+$/g, '');
+ break;
+ default:
+ return '';
+ }
+ }
+ },
+
+ reverse: function(tbody) {
+ // reverse the rows in a tbody
+ newrows = [];
+ for (var i=0; i<tbody.rows.length; i++) {
+ newrows[newrows.length] = tbody.rows[i];
+ }
+ for (var i=newrows.length-1; i>=0; i--) {
+ tbody.appendChild(newrows[i]);
+ }
+ delete newrows;
+ },
+
+ /* sort functions
+ each sort function takes two parameters, a and b
+ you are comparing a[0] and b[0] */
+ sort_numeric: function(a,b) {
+ aa = parseFloat(a[0].replace(/[^0-9.-]/g,''));
+ if (isNaN(aa)) aa = 0;
+ bb = parseFloat(b[0].replace(/[^0-9.-]/g,''));
+ if (isNaN(bb)) bb = 0;
+ return aa-bb;
+ },
+ sort_alpha: function(a,b) {
+ if (a[0]==b[0]) return 0;
+ if (a[0]<b[0]) return -1;
+ return 1;
+ },
+ sort_ddmm: function(a,b) {
+ mtch = a[0].match(sorttable.DATE_RE);
+ y = mtch[3]; m = mtch[2]; d = mtch[1];
+ if (m.length == 1) m = '0'+m;
+ if (d.length == 1) d = '0'+d;
+ dt1 = y+m+d;
+ mtch = b[0].match(sorttable.DATE_RE);
+ y = mtch[3]; m = mtch[2]; d = mtch[1];
+ if (m.length == 1) m = '0'+m;
+ if (d.length == 1) d = '0'+d;
+ dt2 = y+m+d;
+ if (dt1==dt2) return 0;
+ if (dt1<dt2) return -1;
+ return 1;
+ },
+ sort_mmdd: function(a,b) {
+ mtch = a[0].match(sorttable.DATE_RE);
+ y = mtch[3]; d = mtch[2]; m = mtch[1];
+ if (m.length == 1) m = '0'+m;
+ if (d.length == 1) d = '0'+d;
+ dt1 = y+m+d;
+ mtch = b[0].match(sorttable.DATE_RE);
+ y = mtch[3]; d = mtch[2]; m = mtch[1];
+ if (m.length == 1) m = '0'+m;
+ if (d.length == 1) d = '0'+d;
+ dt2 = y+m+d;
+ if (dt1==dt2) return 0;
+ if (dt1<dt2) return -1;
+ return 1;
+ },
+
+ shaker_sort: function(list, comp_func) {
+ // A stable sort function to allow multi-level sorting of data
+ // see: http://en.wikipedia.org/wiki/Cocktail_sort
+ // thanks to Joseph Nahmias
+ var b = 0;
+ var t = list.length - 1;
+ var swap = true;
+
+ while(swap) {
+ swap = false;
+ for(var i = b; i < t; ++i) {
+ if ( comp_func(list[i], list[i+1]) > 0 ) {
+ var q = list[i]; list[i] = list[i+1]; list[i+1] = q;
+ swap = true;
+ }
+ } // for
+ t--;
+
+ if (!swap) break;
+
+ for(var i = t; i > b; --i) {
+ if ( comp_func(list[i], list[i-1]) < 0 ) {
+ var q = list[i]; list[i] = list[i-1]; list[i-1] = q;
+ swap = true;
+ }
+ } // for
+ b++;
+
+ } // while(swap)
+ }
+}
+
+/* ******************************************************************
+ Supporting functions: bundled here to avoid depending on a library
+ ****************************************************************** */
+
+// Dean Edwards/Matthias Miller/John Resig
+
+/* for Mozilla/Opera9 */
+if (document.addEventListener) {
+ document.addEventListener("DOMContentLoaded", sorttable.init, false);
+}
+
+/* for Internet Explorer */
+/*@cc_on @*/
+/*@if (@_win32)
+ document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
+ var script = document.getElementById("__ie_onload");
+ script.onreadystatechange = function() {
+ if (this.readyState == "complete") {
+ sorttable.init(); // call the onload handler
+ }
+ };
+/*@end @*/
+
+/* for Safari */
+if (/WebKit/i.test(navigator.userAgent)) { // sniff
+ var _timer = setInterval(function() {
+ if (/loaded|complete/.test(document.readyState)) {
+ sorttable.init(); // call the onload handler
+ }
+ }, 10);
+}
+
+/* for other browsers */
+window.onload = sorttable.init;
+
+// written by Dean Edwards, 2005
+// with input from Tino Zijdel, Matthias Miller, Diego Perini
+
+// http://dean.edwards.name/weblog/2005/10/add-event/
+
+function dean_addEvent(element, type, handler) {
+ if (element.addEventListener) {
+ element.addEventListener(type, handler, false);
+ } else {
+ // assign each event handler a unique ID
+ if (!handler.$$guid) handler.$$guid = dean_addEvent.guid++;
+ // create a hash table of event types for the element
+ if (!element.events) element.events = {};
+ // create a hash table of event handlers for each element/event pair
+ var handlers = element.events[type];
+ if (!handlers) {
+ handlers = element.events[type] = {};
+ // store the existing event handler (if there is one)
+ if (element["on" + type]) {
+ handlers[0] = element["on" + type];
+ }
+ }
+ // store the event handler in the hash table
+ handlers[handler.$$guid] = handler;
+ // assign a global event handler to do all the work
+ element["on" + type] = handleEvent;
+ }
+};
+// a counter used to create unique IDs
+dean_addEvent.guid = 1;
+
+function removeEvent(element, type, handler) {
+ if (element.removeEventListener) {
+ element.removeEventListener(type, handler, false);
+ } else {
+ // delete the event handler from the hash table
+ if (element.events && element.events[type]) {
+ delete element.events[type][handler.$$guid];
+ }
+ }
+};
+
+function handleEvent(event) {
+ var returnValue = true;
+ // grab the event object (IE uses a global event object)
+ event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event);
+ // get a reference to the hash table of event handlers
+ var handlers = this.events[event.type];
+ // execute each event handler
+ for (var i in handlers) {
+ this.$$handleEvent = handlers[i];
+ if (this.$$handleEvent(event) === false) {
+ returnValue = false;
+ }
+ }
+ return returnValue;
+};
+
+function fixEvent(event) {
+ // add W3C standard event methods
+ event.preventDefault = fixEvent.preventDefault;
+ event.stopPropagation = fixEvent.stopPropagation;
+ return event;
+};
+fixEvent.preventDefault = function() {
+ this.returnValue = false;
+};
+fixEvent.stopPropagation = function() {
+ this.cancelBubble = true;
+}
+
+// Dean's forEach: http://dean.edwards.name/base/forEach.js
+/*
+ forEach, version 1.0
+ Copyright 2006, Dean Edwards
+ License: http://www.opensource.org/licenses/mit-license.php
+*/
+
+// array-like enumeration
+if (!Array.forEach) { // mozilla already supports this
+ Array.forEach = function(array, block, context) {
+ for (var i = 0; i < array.length; i++) {
+ block.call(context, array[i], i, array);
+ }
+ };
+}
+
+// generic enumeration
+Function.prototype.forEach = function(object, block, context) {
+ for (var key in object) {
+ if (typeof this.prototype[key] == "undefined") {
+ block.call(context, object[key], key, object);
+ }
+ }
+};
+
+// character enumeration
+String.forEach = function(string, block, context) {
+ Array.forEach(string.split(""), function(chr, index) {
+ block.call(context, chr, index, string);
+ });
+};
+
+// globally resolve forEach enumeration
+var forEach = function(object, block, context) {
+ if (object) {
+ var resolve = Object; // default
+ if (object instanceof Function) {
+ // functions have a "length" property
+ resolve = Function;
+ } else if (object.forEach instanceof Function) {
+ // the object implements a custom forEach method so use that
+ object.forEach(block, context);
+ return;
+ } else if (typeof object == "string") {
+ // the object is a string
+ resolve = String;
+ } else if (typeof object.length == "number") {
+ // the object is array-like
+ resolve = Array;
+ }
+ resolve.forEach(object, block, context);
+ }
+};
+
diff --git a/config/sarg/sarg_sync.xml b/config/sarg/sarg_sync.xml
new file mode 100755
index 00000000..6c81b3f8
--- /dev/null
+++ b/config/sarg/sarg_sync.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE packagegui SYSTEM "./schema/packages.dtd">
+<?xml-stylesheet type="text/xsl" href="./xsl/package.xsl"?>
+<packagegui>
+ <copyright>
+ <![CDATA[
+/* $Id$ */
+/* ========================================================================== */
+/*
+ sarg_sync.xml
+ part of the sarg package for pfSense
+ Copyright (C) 2012 Marcello Coutinho
+ 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.
+
+ THIS SOFTWARE IS PROVIDED ``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
+ AUTHOR 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.
+ */
+/* ========================================================================== */
+ ]]>
+ </copyright>
+ <description>Describe your package here</description>
+ <requirements>Describe your package requirements here</requirements>
+ <faq>Currently there are no FAQ items provided.</faq>
+ <name>sargsync</name>
+ <version>1.0</version>
+ <title>Status: Sarg Sync</title>
+ <include_file>/usr/local/pkg/sarg.inc</include_file>
+ <tabs>
+ <tab>
+ <text>General</text>
+ <url>/pkg_edit.php?xml=sarg.xml&amp;id=0</url>
+ </tab>
+ <tab>
+ <text>Users</text>
+ <url>/pkg_edit.php?xml=sarg_users.xml&amp;id=0</url>
+ </tab>
+ <tab>
+ <text>Schedule</text>
+ <url>/pkg.php?xml=sarg_schedule.xml&amp;id=0</url>
+ </tab>
+ <tab>
+ <text>View Report</text>
+ <url>/sarg_reports.php</url>
+ </tab>
+ <tab>
+ <text>Realtime</text>
+ <url>/sarg_realtime.php</url>
+ </tab>
+ <tab>
+ <text>XMLRPC Sync</text>
+ <url>/pkg_edit.php?xml=sarg_sync.xml&amp;id=0</url>
+ <active/>
+ </tab>
+ <tab>
+ <text>Help</text>
+ <url>/sarg_about.php</url>
+ </tab>
+</tabs>
+ <fields>
+ <field>
+ <name>XMLRPC Sync</name>
+ <type>listtopic</type>
+ </field>
+ <field>
+ <fielddescr>Automatically sync sarg configuration changes</fielddescr>
+ <fieldname>synconchanges</fieldname>
+ <description>pfSense will automatically sync changes to the hosts defined below.</description>
+ <type>checkbox</type>
+ </field>
+ <field>
+ <fielddescr>Remote Server</fielddescr>
+ <fieldname>none</fieldname>
+ <type>rowhelper</type>
+ <rowhelper>
+ <rowhelperfield>
+ <fielddescr>IP Address</fielddescr>
+ <fieldname>ipaddress</fieldname>
+ <description>IP Address of remote server</description>
+ <type>input</type>
+ <size>20</size>
+ </rowhelperfield>
+ <rowhelperfield>
+ <fielddescr>Password</fielddescr>
+ <fieldname>password</fieldname>
+ <description>Password for remote server.</description>
+ <type>password</type>
+ <size>20</size>
+ </rowhelperfield>
+ </rowhelper>
+ </field>
+ </fields>
+ <custom_php_install_command>
+ sarg_php_install_command();
+ </custom_php_install_command>
+ <custom_php_deinstall_command>
+ sarg_php_deinstall_command();
+ </custom_php_deinstall_command>
+ <custom_php_validation_command>
+ sarg_validate_input($_POST, &amp;$input_errors);
+ </custom_php_validation_command>
+ <custom_php_resync_config_command>
+ sarg_resync();
+ </custom_php_resync_config_command>
+</packagegui>
diff --git a/config/sarg/sarg_users.xml b/config/sarg/sarg_users.xml
new file mode 100644
index 00000000..d038e5b3
--- /dev/null
+++ b/config/sarg/sarg_users.xml
@@ -0,0 +1,219 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE packagegui SYSTEM "./schema/packages.dtd">
+<?xml-stylesheet type="text/xsl" href="./xsl/package.xsl"?>
+<packagegui>
+ <copyright>
+ <![CDATA[
+/* $Id$ */
+/* ========================================================================== */
+/*
+ sarg_users.xml
+ part of the sarg for pfSense
+ Copyright (C) 2012 Marcello Coutinho
+
+ 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.
+
+ THIS SOFTWARE IS PROVIDED ``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
+ AUTHOR 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.
+ */
+/* ========================================================================== */
+ ]]>
+ </copyright>
+ <description>Describe your package here</description>
+ <requirements>Describe your package requirements here</requirements>
+ <faq>Currently there are no FAQ items provided.</faq>
+ <name>sarguser</name>
+ <version>1.0</version>
+ <title>Status: Sarg User Settings</title>
+ <include_file>/usr/local/pkg/sarg.inc</include_file>
+ <tabs>
+ <tab>
+ <text>General</text>
+ <url>/pkg_edit.php?xml=sarg.xml&amp;id=0</url>
+ </tab>
+ <tab>
+ <text>Users</text>
+ <url>/pkg_edit.php?xml=sarg_users.xml&amp;id=0</url>
+ <active/>
+ </tab>
+ <tab>
+ <text>Schedule</text>
+ <url>/pkg.php?xml=sarg_schedule.xml&amp;id=0</url>
+ </tab>
+ <tab>
+ <text>View Report</text>
+ <url>/sarg_reports.php</url>
+ </tab>
+ <tab>
+ <text>Realtime</text>
+ <url>/sarg_realtime.php</url>
+ </tab>
+ <tab>
+ <text>XMLRPC Sync</text>
+ <url>/pkg_edit.php?xml=sarg_sync.xml&amp;id=0</url>
+ </tab>
+ <tab>
+ <text>Help</text>
+ <url>/sarg_about.php</url>
+ </tab>
+</tabs>
+ <fields>
+ <field>
+ <name>User Settings</name>
+ <type>listtopic</type>
+ </field>
+ <field>
+ <fielddescr>User Sort Field</fielddescr>
+ <fieldname>user_sort_field</fieldname>
+ <description><![CDATA[Sort field for the User Report.]]></description>
+ <type>select</type>
+ <options>
+ <option><name>BYTES(default)</name><value>BYTES</value></option>
+ <option><name>SITE normal</name><value>SITE</value></option>
+ <option><name>CONNECT</name><value>CONNECT</value></option>
+ <option><name>TIME</name><value>TIME</value></option>
+ </options>
+ </field>
+ <field>
+ <fielddescr>Ntlm User Format</fielddescr>
+ <fieldname>ntlm_user_format</fieldname>
+ <description><![CDATA[NTLM users format]]></description>
+ <type>select</type>
+ <options>
+ <option><name>domainname+username (default)</name><value>domainname+username</value></option>
+ <option><name>username</name><value>user</value></option>
+ </options>
+ </field>
+ <field>
+ <fielddescr>Exclude users</fielddescr>
+ <fieldname>exclude_userlist</fieldname>
+ <description><![CDATA[Users within the file will be excluded from reports.<br>
+ You can use indexonly to have only index.html file.<br>
+ <strong>Format: one user per line.</strong>]]></description>
+ <type>textarea</type>
+ <cols>70</cols>
+ <rows>10</rows>
+ <encoding>base64</encoding>
+ </field>
+ <field>
+ <fielddescr>Include users</fielddescr>
+ <fieldname>include_userlist</fieldname>
+ <description><![CDATA[Reports will be generated only for listed users.<br>
+ <strong>Format: user1:user2:...:usern</strong>]]></description>
+ <type>input</type>
+ <size>70</size>
+ </field>
+ <field>
+ <fielddescr>Users association</fielddescr>
+ <fieldname>usertab</fieldname>
+ <description><![CDATA[You can change the "userid" or the "ip address" to be a real user name on the reports.<br>
+ If resolve_ip is active, the ip address is resolved before being looked up into this file.<br>
+ That is, if you want to map the ip address, be sure to set resolv_ip to no or the resolved name will be looked into the file instead of the ip address.<br>
+ Note that it can be used to resolve any ip address known to the dns and then map the unresolved ip addresses to a name found in the usertab file.<br>
+ <strong>Table syntax: userid name or ip address name</strong><br>
+ Eg:<br>SirIsaac Isaac Newton<br>
+ vinci Leonardo da Vinci<br>
+ 192.168.10.1 Karol Wojtyla]]></description>
+ <type>textarea</type>
+ <cols>70</cols>
+ <rows>10</rows>
+ <encoding>base64</encoding>
+ </field>
+ <field>
+ <name>Ldap Settings</name>
+ <type>listtopic</type>
+ </field>
+ <field>
+ <fielddescr>Enable LDAP search</fielddescr>
+ <fieldname>ldap_enable</fieldname>
+ <description><![CDATA[Enable LDAP search for username replacement based on active directory info.<br>
+ This option is usefull to show full usernames in sarg reports instead of user logins.]]></description>
+ <type>checkbox</type>
+ </field>
+ <field>
+ <fielddescr>LDAP Hostname</fielddescr>
+ <fieldname>ldap_host</fieldname>
+ <description><![CDATA[FQDN or IP address of host with LDAP service or AD DC]]></description>
+ <type>input</type>
+ <size>60</size>
+ </field>
+ <field>
+ <fielddescr>LDAP Port</fielddescr>
+ <fieldname>ldap_port</fieldname>
+ <description><![CDATA[LDAP service port number.<br>Default is 389]]></description>
+ <type>input</type>
+ <size>10</size>
+ </field>
+ <field>
+ <fielddescr>LDAP Bind DN</fielddescr>
+ <fieldname>ldap_bind_dn</fieldname>
+ <description><![CDATA[DN of LDAP user, who is authorized to read user's names from LDAP base.<br>
+ Sample: CN=username,OU=group,DC=mydomain,DC=com<br>]]></description>
+ <type>input</type>
+ <size>60</size>
+ </field>
+ <field>
+ <fielddescr>LDAP Bind Password</fielddescr>
+ <fieldname>ldap_bind_pw</fieldname>
+ <description><![CDATA[LDAPBindPW secret Password of DN, who is authorized to read user's names from LDAP base.]]></description>
+ <type>password</type>
+ <size>10</size>
+ </field>
+ <field>
+ <fielddescr>LDAP Base Search</fielddescr>
+ <fieldname>ldap_base_search</fieldname>
+ <description><![CDATA[LDAP search base.<br>
+ Sample: OU=users,DC=mydomain,DC=com]]></description>
+ <type>input</type>
+ <size>60</size>
+ </field>
+ <field>
+ <fielddescr>LDAP filter Search</fielddescr>
+ <fieldname>ldap_filter_search</fieldname>
+ <description><![CDATA[LDAPFilterSearch (uid=%s)<br>
+ User search filter by user's logins in LDAP. First founded record will be used.<br>
+ %s - will be changed to userlogins from access.log file filter string can have up to 5 '%s' tags.<br>
+ Default value is '(uid=%s)']]></description>
+ <type>input</type>
+ <size>60</size>
+ </field>
+ <field>
+ <fielddescr>LDAP Target Attribute</fielddescr>
+ <fieldname>ldap_target_attr</fieldname>
+ <description><![CDATA[Name of the attribute containing a name of the user<br>
+ Default value is 'cn']]></description>
+ <type>input</type>
+ <size>60</size>
+ </field>
+ </fields>
+ <custom_php_install_command>
+ </custom_php_install_command>
+ <custom_php_deinstall_command>
+ </custom_php_deinstall_command>
+ <custom_php_validation_command>
+ sarg_validate_input($_POST, &amp;$input_errors);
+ </custom_php_validation_command>
+ <custom_php_resync_config_command>
+ sync_package_sarg();
+ </custom_php_resync_config_command>
+</packagegui>