*/
// must be run within Dokuwiki
if(!defined('DOKU_INC')) die();
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC.'lib/plugins/');
require_once(DOKU_PLUGIN.'admin.php');
define('ACLAUDITOR_SCENARIODIR', DOKU_CONF.'aclauditor_scenarios');
class admin_plugin_aclauditor extends DokuWiki_Admin_Plugin {
var $mode = 'single';
var $data = null;
var $error = '';
var $test = null;
var $who = null;
var $what = null;
var $scenario = '';
var $scenariofn = '';
var $scenarios = array();
function getInfo() {
return array(
'author' => 'Etienne MELEARD',
'email' => 'etienne.meleard@free.fr',
'date' => @file_get_contents(DOKU_PLUGIN.'aclauditor/VERSION'),
'name' => 'ACL Auditor Admin Plugin',
'desc' => 'Functions to get info about user /group ACLs of a wiki page',
'url' => 'http://dokuwiki.org/plugin:aclauditor',
);
}
function getMenuSort() { return 200; }
function getMenuText($language) { return $this->getLang('menu'); }
function forAdminOnly() { return false; }
function handle() {
global $ID;
$helper = $this->loadHelper('aclauditor', true);
if(!$helper) return null;
$this->mode = (isset($_GET['aclaudit_mode']) && in_array($_GET['aclaudit_mode'], array('single', 'scenario'))) ? $_GET['aclaudit_mode'] : 'single';
if($this->mode != 'scenario') {
$what = (isset($_REQUEST['aclaudit_what']) && !empty($_REQUEST['aclaudit_what'])) ? $_REQUEST['aclaudit_what'] : null;
$this->what = preg_match('`^(.*[^:])(\:\*)$`', $what, $m) ? cleanID($m[1]).$m[2] : $what;
if(substr($this->what, -1) == ':') $this->what .= '*';
$this->who = (isset($_REQUEST['aclaudit_who']) && !empty($_REQUEST['aclaudit_who'])) ? $_REQUEST['aclaudit_who'] : null;
if(isset($_REQUEST['aclaudit_testwho'])) {
$this->test = 'who';
$this->data = $helper->getACL($this->who ? $this->who : $_SERVER['REMOTE_USER']);
}elseif(isset($_REQUEST['aclaudit_testwhat'])) {
$this->test = 'what';
$this->data = $helper->resourceACLs($this->what ? $this->what : $ID);
}elseif(isset($_REQUEST['aclaudit_testboth'])) {
$this->test = 'both';
$this->data = $helper->getACLon($this->who ? $this->who : $_SERVER['REMOTE_USER'], $this->what ? $this->what : $ID);
}
}else{
if(!@is_dir(ACLAUDITOR_SCENARIODIR)) mkdir(ACLAUDITOR_SCENARIODIR);
foreach(scandir(ACLAUDITOR_SCENARIODIR) as $i) {
if(!preg_match('`^[^\.].*\.csv$`', $i)) continue;
$desc = '';
if($fp = fopen(ACLAUDITOR_SCENARIODIR.'/'.$i, 'r')) {
$l = fgets($fp);
if(preg_match('`^\s*"?\s*#\s*(.+)\s*"?,,,\s*$`', $l, $m)) $desc = str_replace('""', '"', $m[1]);
fclose($fp);
}
$this->scenarios[$i] = trim($desc, '"');
}
$this->scenario = isset($_POST['aclaudit_scenario_content']) ? trim($_POST['aclaudit_scenario_content']) : null;
$fn = isset($_POST['aclaudit_scenario_save_filename']) ? trim($_POST['aclaudit_scenario_save_filename']) : null;
if(preg_match('`^[^/\.]+(\.csv)?$`', $fn, $m)) $this->scenariofn = $fn.($m[1] ? '' : '.csv');
if(isset($_POST['aclaudit_scenario_load'])) {
$fn = isset($_POST['aclaudit_scenario_load_filename']) ? trim($_POST['aclaudit_scenario_load_filename']) : null;
if($fn && array_key_exists($fn, $this->scenarios)) $this->scenariofn = $fn;
if($this->scenariofn && @file_exists(ACLAUDITOR_SCENARIODIR.'/'.$this->scenariofn)) {
$this->scenario = @file_get_contents(ACLAUDITOR_SCENARIODIR.'/'.$this->scenariofn);
msg($this->getLang('scenario_load_success'), 1);
}else msg($this->getLang('scenario_load_badfile_error'), -1);
}elseif(isset($_POST['aclaudit_scenario_upload'])) {
if(isset($_FILES['aclaudit_scenario_upload_file']) && @is_uploaded_file($_FILES['aclaudit_scenario_upload_file']['tmp_name'])) {
$this->scenariofn = '';
$this->scenario = @file_get_contents($_FILES['aclaudit_scenario_upload_file']['tmp_name']);
msg($this->getLang('scenario_upload_success'), 1);
}else msg($this->getLang('scenario_upload_error'), -1);
}elseif(isset($_POST['aclaudit_scenario_save'])) {
if($this->scenariofn) {
if($this->scenario) {
if($fp = fopen(ACLAUDITOR_SCENARIODIR.'/'.$this->scenariofn, 'w')) {
fwrite($fp, $this->scenario);
fclose($fp);
msg($this->getLang('scenario_save_success'), 1);
}else msg($this->getLang('scenario_save_failed_error'), -1);
}elseif(@file_exists(ACLAUDITOR_SCENARIODIR.'/'.$this->scenariofn)) {
if(unlink(ACLAUDITOR_SCENARIODIR.'/'.$this->scenariofn)) {
msg($this->getLang('scenario_rm_success'), 1);
$this->scenario = '';
$this->scenariofn = '';
}else msg($this->getLang('scenario_save_rmfailed_error'), -1);
}
}else msg($this->getLang('scenario_save_badfile_error'), -1);
}elseif(isset($_POST['aclaudit_scenario_download'])) {
if($this->scenario) {
header('Content-type: application/force-download');
header('Content-Disposition: attachment; filename="'.($this->scenariofn ? $this->scenariofn : 'scenario_'.date('Ymd_His').'.csv').'"');
header('Content-Length: '.strlen($this->scenario));
echo $this->scenario;
exit();
}else msg($this->getLang('scenario_download_nodata_error'), -1);
}
if(isset($_POST['aclaudit_scenario_run'])) {
if($this->scenario) {
$this->test = true;
$this->data = array();
foreach(preg_split('`\s*\n\s*`', $this->scenario) as $l) {
if(preg_match('`^\s*"?\s*#`', $l)) continue;
list($id, $user, $group, $reqlvl) = array_map(create_function('$i', 'return trim(preg_match("`^\"(.+)\"$`", $i, $m) ? $m[1] : $i);'), preg_split('`\s*[,;]\s*`', $l));
$this->data[$l] = array('valid' => false);
if(!$user && !$group) continue;
if(!$id) $id = '*';
$this->data[$l]['id'] = $id;
$u = $user ? $user : 'dummy_aclauditor_user_'.uniqid().'_'.time();
$this->data[$l]['user'] = $user;
$grps = array_filter(explode('|', (string)$group), create_function('$g', 'return (bool)strlen($g);'));
if($grps[0] == '*') {
global $auth;
if($auth && ($u = reset($auth->retrieveUsers(0, 1, array('user' => $u))))) {
$grps = $u['grps'];
}else $grps = array();
}
if(!count($grps)) $grps[] = 'ALL';
$this->data[$l]['group'] = $grps;
$law = '==';
if(preg_match('`^(\=\=?|\<\=?|\>\=?|\!\=?)\s*([0-9]+)$`', $reqlvl, $m)) {
$law = $m[1];
$reqlvl = (int)$m[2];
}else $reqlvl = (int)$reqlvl;
if(!preg_match('`^[0-9]+$`', $reqlvl)) continue;
$this->data[$l]['law'] = $law;
$this->data[$l]['reqlvl'] = $reqlvl;
$this->data[$l]['required'] = ((($law != '==') && ($law != '=')) ? $law : '').$reqlvl;
$syslvl = auth_aclcheck($id, $u, $grps);
if(auth_isadmin($u, $grps)) $syslvl = 255;
$this->data[$l]['found'] = $syslvl;
$ok = false;
switch($law) {
case '<' : if($syslvl < $reqlvl) $ok = true; break;
case '<=' : if($syslvl <= $reqlvl) $ok = true; break;
case '>' : if($syslvl > $reqlvl) $ok = true; break;
case '>=' : if($syslvl >= $reqlvl) $ok = true; break;
case '!' :
case '!=' : if($syslvl != $reqlvl) $ok = true; break;
case '=' :
case '==' :
default : if($syslvl == $reqlvl) $ok = true; $law = '';
}
$this->data[$l]['valid'] = true;
$this->data[$l]['pass'] = $ok;
$this->data[$l]['explanations'] = $ok ? null : $helper->resourceACLs($id);
if(!$ok) $this->test = false;
}
}else msg($this->getLang('scenario_download_nodata_error'), -1);
}
}
}
function html() {
global $ID;
if($this->mode != 'scenario') {
ptln('
'.$this->getLang('listform').'
');
ptln(''.$this->getLang('toscenario').'
');
ptln('');
if($this->test) {
ptln(''.$this->getLang('list').'
');
ptln('');
switch($this->test) {
case 'who' :
ptln('
'.$this->getLang('listwho').' : "'.($this->who ? $this->who : $_SERVER['REMOTE_USER']).'"'.'
');
foreach($this->data as $id => $list) {
ptln('
');
ptln(' '.$this->getLang('permwhat').' "'.$id.'" :');
ptln(' '.$this->getLang('who').' | '.$this->getLang('what').' | '.$this->getLang('perm').' |
');
foreach($list as $rule => $dfn) {
if($rule == '_lvl') continue;
ptln(' '.$dfn['who'].' | '.$dfn['what'].' | '.$this->getLang('perm'.$dfn['lvl']).' |
');
}
ptln(' '.$this->getLang('resource_final_perm').' : | '.$this->getLang('perm'.$list['_lvl']).' | ');
ptln('
');
}
break;
case 'what' :
ptln('
'.$this->getLang('listwhat').' : "'.($this->what ? $this->what : $ID).'"'.'
');
foreach($this->data as $who => $list) {
ptln('
');
ptln(' '.$this->getLang('permwho').' "'.$who.'" :');
ptln(' '.$this->getLang('who').' | '.$this->getLang('what').' | '.$this->getLang('perm').' |
');
foreach($list as $rule => $dfn) {
if($rule == '_lvl') continue;
ptln(' '.$dfn['who'].' | '.$dfn['what'].' | '.$this->getLang('perm'.$dfn['lvl']).' |
');
}
ptln(' '.$this->getLang('resource_final_perm').' : | '.$this->getLang('perm'.$list['_lvl']).' | ');
ptln('
');
}
break;
case 'both' :
ptln('
'.$this->getLang('listbothwho').' "'.($this->who ? $this->who : $_SERVER['REMOTE_USER']).'" '.$this->getLang('listbothwhat').' "'.($this->what ? $this->what : $ID).'"'.'
');
foreach($this->data as $id => $list) {
if($id == '_lvl') continue;
if($id == '_specificlvl') continue;
ptln('
');
ptln('
'.$this->getLang('permbothwhat').' "'.$id.'" :
');
ptln('
');
ptln(' '.$this->getLang('who').' | '.$this->getLang('what').' | '.$this->getLang('perm').' |
');
$data = $this->data;
foreach($data as $tid => $tlist) {
foreach($tlist as $who => $slist) {
if($who == '_lvl') continue;
if($who == '_specificlvl') continue;
foreach($slist as $rule => $dfn) {
if($rule == '_lvl') continue;
if($rule == '_specificlvl') continue;
ptln(' '.$dfn['who'].' | '.$dfn['what'].' | '.$this->getLang('perm'.$dfn['lvl']).' |
');
}
}
if($tid == $id) break;
}
if(count($list) <= 2) ptln('
');
$perm = ($list['_specificlvl'] >= 0) ? $list['_specificlvl'] : $list['_lvl'];
ptln(' '.$this->getLang('bothresource_final_perm').' '.((($list['_specificlvl'] >= 0) && ($id != '*')) ? '('.$this->getLang('specific').') ' : '').': | '.$this->getLang('perm'.$perm).' | ');
ptln('
');
ptln('
');
}
$perm = ($this->data['_specificlvl'] >= 0) ? $this->data['_specificlvl'] : $this->data['_lvl'];
ptln('
'.$this->getLang('resource_final_perm').' '.(($this->data['_specificlvl'] >= 0) ? '('.$this->getLang('specific').') ' : '').': '.$this->getLang('perm'.$perm).'
');
break;
}
ptln('
');
}
}else{
ptln(''.$this->getLang('scenarioform').'
');
ptln(''.$this->getLang('tosingle').'
');
ptln('');
if(!is_null($this->data)) {
ptln(''.$this->getLang('scenario_results').'
');
ptln(''.$this->getLang($this->test ? 'scenario_passed' : 'scenario_failed').'
');
if(!$this->test) {
ptln('');
ptln(' ');
ptln(' '.$this->getLang('scenario_rule').' | ');
ptln(' '.$this->getLang('scenario_testid').' | ');
ptln(' '.$this->getLang('scenario_teston').' | ');
ptln(' '.$this->getLang('scenario_required').' | ');
ptln(' '.$this->getLang('scenario_found').' | ');
ptln('
');
foreach($this->data as $rule => $r) {
if($r['pass']) continue;
if(!$r['valid']) {
ptln(' ');
ptln(' '.$rule.' | ');
ptln(' '.$this->getLang('invalid_rule').' | ');
ptln('
');
continue;
}
$on = $r['user'] ? $r['user'] : '';
if($on && $r['group']) $on .= '
';
$on .= $r['group'] ? implode(', ', array_map(create_function('$g', 'return "@".$g;'), $r['group'])) : '';
ptln(' ');
ptln(' '.$rule.' | ');
ptln(' '.$r['id'].' | ');
ptln(' '.$on.' | ');
$lvlstr = $this->getLang('perm'.$r['reqlvl']);
switch($r['law']) {
case '<' : $l = 'lt'; break;
case '<=' : $l = 'lte'; break;
case '>' : $l = 'gt'; break;
case '>=' : $l = 'gte'; break;
case '!' :
case '!=' : $l = 'ne'; break;
case '=' :
case '==' :
default : $l = 'eq'; break;
}
ptln(' '.$r['required'].($lvlstr ? ' ('.$this->getLang('req_'.$l).' '.$lvlstr.')' : '').' | ');
ptln(' '.$r['found'].' ('.$this->getLang('perm'.$r['found']).') | ');
ptln('
');
ptln(' ');
ptln(' ');
foreach($r['explanations'] as $who => $list) {
if(substr($who, 0, 1) == '_') continue;
$rules = array();
foreach($list as $crule => $parts) {
if(substr($id, 0, 1) == '_') continue;
if(($r['user'] && $parts['who'] == $r['user']) || ($r['group'] && in_array($parts['who'], array_map(create_function('$g', 'return "@".$g;'), $r['group'])))) {
$rules[] = ' '.$crule.' => '.$parts['lvl'];
}
}
if(count($rules)) {
ptln($this->getLang('permwho').' : '.$who);
foreach($rules as $d) ptln($d);
}
}
ptln(' '.$this->getLang('more_details').' | ');
ptln('
');
}
ptln('
');
}
}
}
}
}