xref: /dokuwiki/lib/plugins/acl/admin.php (revision 2a3623da3390f0118660d541928ae8c635631b3d)
111e2ce22Schris<?php
211e2ce22Schris/**
311e2ce22Schris * ACL administration functions
411e2ce22Schris *
511e2ce22Schris * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6*2a3623daSAndreas Gohr * @author     Andreas Gohr <andi@splitbrain.org>
7*2a3623daSAndreas Gohr * @author     Anika Henke <a.c.henke@arcor.de> (concepts)
8*2a3623daSAndreas Gohr * @author     Frank Schubert <frank@schokilade.de> (old version)
911e2ce22Schris */
10e04f1f16Schris// must be run within Dokuwiki
11e04f1f16Schrisif(!defined('DOKU_INC')) die();
12e04f1f16Schris
1311e2ce22Schrisif(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
1411e2ce22Schrisrequire_once(DOKU_PLUGIN.'admin.php');
1511e2ce22Schris
1611e2ce22Schris/**
1711e2ce22Schris * All DokuWiki plugins to extend the admin function
1811e2ce22Schris * need to inherit from this class
1911e2ce22Schris */
2011e2ce22Schrisclass admin_plugin_acl extends DokuWiki_Admin_Plugin {
21*2a3623daSAndreas Gohr    var $acl = null;
22*2a3623daSAndreas Gohr    var $ns  = null;
23*2a3623daSAndreas Gohr    var $who = '';
24*2a3623daSAndreas Gohr    var $usersgroups = array();
251d3e0272SAndreas Gohr
261d3e0272SAndreas Gohr
2711e2ce22Schris    /**
2811e2ce22Schris     * return some info
2911e2ce22Schris     */
3011e2ce22Schris    function getInfo(){
3111e2ce22Schris        return array(
32*2a3623daSAndreas Gohr            'author' => 'Andreas Gohr',
33*2a3623daSAndreas Gohr            'email'  => 'andi@splitbrain.org',
34*2a3623daSAndreas Gohr            'date'   => '2007-11-17',
3511e2ce22Schris            'name'   => 'ACL',
3611e2ce22Schris            'desc'   => 'Manage Page Access Control Lists',
3711e2ce22Schris            'url'    => 'http://wiki.splitbrain.org/wiki:acl',
3811e2ce22Schris        );
3911e2ce22Schris    }
4011e2ce22Schris
4111e2ce22Schris    /**
4211e2ce22Schris     * return prompt for admin menu
4311e2ce22Schris     */
4411e2ce22Schris    function getMenuText($language) {
45*2a3623daSAndreas Gohr        return $this->getLang('admin_acl');
4611e2ce22Schris    }
4711e2ce22Schris
4811e2ce22Schris    /**
4911e2ce22Schris     * return sort order for position in admin menu
5011e2ce22Schris     */
5111e2ce22Schris    function getMenuSort() {
5211e2ce22Schris        return 1;
5311e2ce22Schris    }
5411e2ce22Schris
5511e2ce22Schris    /**
5611e2ce22Schris     * handle user request
57*2a3623daSAndreas Gohr     *
58*2a3623daSAndreas Gohr     * Initializes internal vars and handles modifications
59*2a3623daSAndreas Gohr     *
60*2a3623daSAndreas Gohr     * @author Andreas Gohr <andi@splitbrain.org>
6111e2ce22Schris     */
6211e2ce22Schris    function handle() {
6311e2ce22Schris        global $AUTH_ACL;
64*2a3623daSAndreas Gohr        global $ID;
6511e2ce22Schris
66*2a3623daSAndreas Gohr        // namespace given?
67*2a3623daSAndreas Gohr        if($_REQUEST['ns'] == '*'){
68*2a3623daSAndreas Gohr            $this->ns = '*';
6911e2ce22Schris        }else{
70*2a3623daSAndreas Gohr            $this->ns = cleanID($_REQUEST['ns']);
7111e2ce22Schris        }
7211e2ce22Schris
73*2a3623daSAndreas Gohr        // user or group choosen?
74*2a3623daSAndreas Gohr        $who = trim($_REQUEST['acl_w']);
75*2a3623daSAndreas Gohr        if($_REQUEST['acl_t'] == '__g__' && $who){
76*2a3623daSAndreas Gohr            $this->who = '@'.ltrim($who,'@');
77*2a3623daSAndreas Gohr        }elseif($_REQUEST['acl_t'] == '__u__' && $who){
78*2a3623daSAndreas Gohr            $this->who = ltrim($who,'@');
79*2a3623daSAndreas Gohr        }elseif($_REQUEST['acl_t'] &&
80*2a3623daSAndreas Gohr                $_REQUEST['acl_t'] != '__u__' &&
81*2a3623daSAndreas Gohr                $_REQUEST['acl_t'] != '__g__'){
82*2a3623daSAndreas Gohr            $this->who = $_REQUEST['acl_t'];
83*2a3623daSAndreas Gohr        }elseif($who){
84*2a3623daSAndreas Gohr            $this->who = $who;
85*2a3623daSAndreas Gohr        }
86634d7150SAndreas Gohr
87*2a3623daSAndreas Gohr        // handle modifications
88*2a3623daSAndreas Gohr        if(isset($_REQUEST['cmd'])){
89*2a3623daSAndreas Gohr            // scope for modifications
90*2a3623daSAndreas Gohr            if($this->ns){
91*2a3623daSAndreas Gohr                if($this->ns == '*'){
92*2a3623daSAndreas Gohr                    $scope = '*';
93*2a3623daSAndreas Gohr                }else{
94*2a3623daSAndreas Gohr                    $scope = $this->ns.':*';
95*2a3623daSAndreas Gohr                }
96*2a3623daSAndreas Gohr            }else{
97*2a3623daSAndreas Gohr                $scope = $ID;
98*2a3623daSAndreas Gohr            }
9911e2ce22Schris
100*2a3623daSAndreas Gohr            if(isset($_REQUEST['cmd']['save']) && $scope && $this->who && isset($_REQUEST['acl'])){
101*2a3623daSAndreas Gohr                // handle additions or single modifications
102*2a3623daSAndreas Gohr                $this->_acl_del($scope, $this->who);
103*2a3623daSAndreas Gohr                $this->_acl_add($scope, $this->who, (int) $_REQUEST['acl']);
104*2a3623daSAndreas Gohr            }elseif(isset($_REQUEST['cmd']['del']) && $scope && $this->who){
105*2a3623daSAndreas Gohr                // handle single deletions
106*2a3623daSAndreas Gohr                $this->_acl_del($scope, $this->who);
107*2a3623daSAndreas Gohr            }elseif(isset($_REQUEST['cmd']['update'])){
108*2a3623daSAndreas Gohr                // handle update of the whole file
109*2a3623daSAndreas Gohr                foreach((array) $_REQUEST['del'] as $where => $who){
110*2a3623daSAndreas Gohr                    // remove all rules marked for deletion
111*2a3623daSAndreas Gohr                    unset($_REQUEST['acl'][$where][$who]);
112*2a3623daSAndreas Gohr                }
113*2a3623daSAndreas Gohr                // prepare lines
114*2a3623daSAndreas Gohr                $lines = array();
115*2a3623daSAndreas Gohr                // keep header
116*2a3623daSAndreas Gohr                foreach($AUTH_ACL as $line){
117*2a3623daSAndreas Gohr                    if($line{0} == '#'){
118*2a3623daSAndreas Gohr                        $lines[] = $line;
119*2a3623daSAndreas Gohr                    }else{
120*2a3623daSAndreas Gohr                        break;
121*2a3623daSAndreas Gohr                    }
122*2a3623daSAndreas Gohr                }
123*2a3623daSAndreas Gohr                // re-add all rules
124*2a3623daSAndreas Gohr                foreach((array) $_REQUEST['acl'] as $where => $opt){
125*2a3623daSAndreas Gohr                    foreach($opt as $who => $perm){
126*2a3623daSAndreas Gohr                        $who = auth_nameencode($who,true);
127*2a3623daSAndreas Gohr                        $lines[] = "$where\t$who\t$perm\n";
128*2a3623daSAndreas Gohr                    }
129*2a3623daSAndreas Gohr                }
130*2a3623daSAndreas Gohr                // save it
131*2a3623daSAndreas Gohr                io_saveFile(DOKU_CONF.'acl.auth.php', join('',$lines));
13211e2ce22Schris            }
13311e2ce22Schris
13411e2ce22Schris            // reload ACL config
13511e2ce22Schris            $AUTH_ACL = file(DOKU_CONF.'acl.auth.php');
13611e2ce22Schris        }
13711e2ce22Schris
138*2a3623daSAndreas Gohr        // initialize ACL array
139*2a3623daSAndreas Gohr        $this->_init_acl_config();
140*2a3623daSAndreas Gohr    }
141*2a3623daSAndreas Gohr
14211e2ce22Schris    /**
14311e2ce22Schris     * ACL Output function
14411e2ce22Schris     *
14511e2ce22Schris     * print a table with all significant permissions for the
14611e2ce22Schris     * current id
14711e2ce22Schris     *
14811e2ce22Schris     * @author  Frank Schubert <frank@schokilade.de>
14911e2ce22Schris     * @author  Andreas Gohr <andi@splitbrain.org>
15011e2ce22Schris     */
15111e2ce22Schris    function html() {
15211e2ce22Schris        global $ID;
15311e2ce22Schris
154*2a3623daSAndreas Gohr        echo '<div id="acl_manager">'.NL;
155*2a3623daSAndreas Gohr        echo '<h1>'.$this->getLang('admin_acl').'</h1>'.NL;
156*2a3623daSAndreas Gohr        echo '<div class="level1">'.NL;
15711e2ce22Schris
158*2a3623daSAndreas Gohr        echo '<div id="acl__tree">'.NL;
159*2a3623daSAndreas Gohr        $this->_html_explorer($_REQUEST['ns']);
160*2a3623daSAndreas Gohr        echo '</div>'.NL;
16111e2ce22Schris
162*2a3623daSAndreas Gohr        echo '<div id="acl__detail">'.NL;
163*2a3623daSAndreas Gohr        $this->_html_detail();
164*2a3623daSAndreas Gohr        echo '</div>'.NL;
165*2a3623daSAndreas Gohr        echo '</div>'.NL;
16611e2ce22Schris
167*2a3623daSAndreas Gohr        echo '<div class="clearer"></div>';
168*2a3623daSAndreas Gohr        echo '<h2>'.$this->getLang('current').'</h2>'.NL;
169*2a3623daSAndreas Gohr        echo '<div class="level2">'.NL;
170*2a3623daSAndreas Gohr        $this->_html_table();
171*2a3623daSAndreas Gohr        echo '</div>'.NL;
172*2a3623daSAndreas Gohr
173*2a3623daSAndreas Gohr        echo '</div>'.NL;
17411e2ce22Schris    }
17511e2ce22Schris
176*2a3623daSAndreas Gohr    /**
177*2a3623daSAndreas Gohr     * returns array with set options for building links
178*2a3623daSAndreas Gohr     *
179*2a3623daSAndreas Gohr     * @author Andreas Gohr <andi@splitbrain.org>
180*2a3623daSAndreas Gohr     */
181*2a3623daSAndreas Gohr    function _get_opts($addopts=null){
182*2a3623daSAndreas Gohr        global $ID;
183*2a3623daSAndreas Gohr        $opts = array(
184*2a3623daSAndreas Gohr                    'do'=>'admin',
185*2a3623daSAndreas Gohr                    'page'=>'acl',
186*2a3623daSAndreas Gohr                );
187*2a3623daSAndreas Gohr        if($this->ns) $opts['ns'] = $this->ns;
188*2a3623daSAndreas Gohr        if($this->who) $opts['acl_w'] = $this->who;
189*2a3623daSAndreas Gohr
190*2a3623daSAndreas Gohr        if(is_null($addopts)) return $opts;
191*2a3623daSAndreas Gohr        return array_merge($opts, $addopts);
192*2a3623daSAndreas Gohr    }
193*2a3623daSAndreas Gohr
194*2a3623daSAndreas Gohr    /**
195*2a3623daSAndreas Gohr     * Display a tree menu to select a page or namespace
196*2a3623daSAndreas Gohr     *
197*2a3623daSAndreas Gohr     * @author Andreas Gohr <andi@splitbrain.org>
198*2a3623daSAndreas Gohr     */
199*2a3623daSAndreas Gohr    function _html_explorer(){
200*2a3623daSAndreas Gohr        require_once(DOKU_INC.'inc/search.php');
201*2a3623daSAndreas Gohr        global $conf;
202*2a3623daSAndreas Gohr        global $ID;
203*2a3623daSAndreas Gohr        global $lang;
204*2a3623daSAndreas Gohr
205*2a3623daSAndreas Gohr        $dir = $conf['datadir'];
206*2a3623daSAndreas Gohr        $ns  = $this->ns;
207*2a3623daSAndreas Gohr        if(empty($ns)){
208*2a3623daSAndreas Gohr            $ns = dirname(str_replace(':','/',$ID));
209*2a3623daSAndreas Gohr            if($ns == '.') $ns ='';
210*2a3623daSAndreas Gohr        }elseif($ns == '*'){
211*2a3623daSAndreas Gohr            $ns ='';
212*2a3623daSAndreas Gohr        }
213*2a3623daSAndreas Gohr        $ns  = utf8_encodeFN(str_replace(':','/',$ns));
214*2a3623daSAndreas Gohr
215*2a3623daSAndreas Gohr
216*2a3623daSAndreas Gohr        $data = array();
217*2a3623daSAndreas Gohr        search($data,$conf['datadir'],'search_index',array('ns' => $ns));
218*2a3623daSAndreas Gohr
219*2a3623daSAndreas Gohr
220*2a3623daSAndreas Gohr        // wrap a list with the root level around the other namespaces
221*2a3623daSAndreas Gohr        $item = array( 'level' => 0, 'id' => '*', 'type' => 'd',
222*2a3623daSAndreas Gohr                   'open' =>'true', 'label' => '['.$lang['mediaroot'].']');
223*2a3623daSAndreas Gohr
224*2a3623daSAndreas Gohr        echo '<ul class="acltree">';
225*2a3623daSAndreas Gohr        echo $this->_html_li_acl($item);
226*2a3623daSAndreas Gohr        echo '<div class="li">';
227*2a3623daSAndreas Gohr        echo $this->_html_list_acl($item);
228*2a3623daSAndreas Gohr        echo '</div>';
229*2a3623daSAndreas Gohr        echo html_buildlist($data,'acl',
230*2a3623daSAndreas Gohr                            array($this,'_html_list_acl'),
231*2a3623daSAndreas Gohr                            array($this,'_html_li_acl'));
232*2a3623daSAndreas Gohr        echo '</li>';
233*2a3623daSAndreas Gohr        echo '</ul>';
234*2a3623daSAndreas Gohr
235*2a3623daSAndreas Gohr    }
236*2a3623daSAndreas Gohr
237*2a3623daSAndreas Gohr    /**
238*2a3623daSAndreas Gohr     * Display the current ACL for selected where/who combination with
239*2a3623daSAndreas Gohr     * selectors and modification form
240*2a3623daSAndreas Gohr     *
241*2a3623daSAndreas Gohr     * @author Andreas Gohr <andi@splitbrain.org>
242*2a3623daSAndreas Gohr     */
243*2a3623daSAndreas Gohr    function _html_detail(){
244*2a3623daSAndreas Gohr        global $conf;
245*2a3623daSAndreas Gohr        global $ID;
246*2a3623daSAndreas Gohr
247*2a3623daSAndreas Gohr        echo '<form action="'.wl().'" method="post" accept-charset="utf-8">'.NL;
248*2a3623daSAndreas Gohr
249*2a3623daSAndreas Gohr        echo '<div id="acl__user">';
250*2a3623daSAndreas Gohr        echo $this->getLang('acl_perms').' ';
251*2a3623daSAndreas Gohr        $inl =  $this->_html_select();
252*2a3623daSAndreas Gohr        echo '<input type="text" name="acl_w" class="edit" value="'.(($inl)?'':hsc(ltrim($this->who,'@'))).'" />'.NL;
253*2a3623daSAndreas Gohr        echo '<input type="submit" value="Select" class="button" />'.NL;
254*2a3623daSAndreas Gohr        echo '</div>'.NL;
255*2a3623daSAndreas Gohr
256*2a3623daSAndreas Gohr        echo '<div id="acl__info">';
257*2a3623daSAndreas Gohr        $this->_html_info();
258*2a3623daSAndreas Gohr        echo '</div>';
259*2a3623daSAndreas Gohr
260*2a3623daSAndreas Gohr        echo '<input type="hidden" name="ns" value="'.hsc($this->ns).'" />'.NL;
261*2a3623daSAndreas Gohr        echo '<input type="hidden" name="id" value="'.hsc($ID).'" />'.NL;
262*2a3623daSAndreas Gohr        echo '<input type="hidden" name="do" value="admin" />'.NL;
263*2a3623daSAndreas Gohr        echo '<input type="hidden" name="page" value="acl" />'.NL;
264*2a3623daSAndreas Gohr        echo '</form>'.NL;
265*2a3623daSAndreas Gohr    }
266*2a3623daSAndreas Gohr
267*2a3623daSAndreas Gohr    /**
268*2a3623daSAndreas Gohr     * Print infos and editor
269*2a3623daSAndreas Gohr     */
270*2a3623daSAndreas Gohr    function _html_info(){
271*2a3623daSAndreas Gohr        global $ID;
272*2a3623daSAndreas Gohr
273*2a3623daSAndreas Gohr        if($this->who){
274*2a3623daSAndreas Gohr            $current = $this->_get_exact_perm();
275*2a3623daSAndreas Gohr
276*2a3623daSAndreas Gohr            // explain current permissions
277*2a3623daSAndreas Gohr            $this->_html_explain($current);
278*2a3623daSAndreas Gohr            // load editor
279*2a3623daSAndreas Gohr            $this->_html_acleditor($current);
280*2a3623daSAndreas Gohr        }else{
281*2a3623daSAndreas Gohr            echo '<p>';
282*2a3623daSAndreas Gohr            if($this->ns){
283*2a3623daSAndreas Gohr                printf($this->getLang('p_choose_ns'),hsc($this->ns));
284*2a3623daSAndreas Gohr            }else{
285*2a3623daSAndreas Gohr                printf($this->getLang('p_choose_id'),hsc($ID));
286*2a3623daSAndreas Gohr            }
287*2a3623daSAndreas Gohr            echo '</p>';
288*2a3623daSAndreas Gohr
289*2a3623daSAndreas Gohr            echo $this->locale_xhtml('help');
290*2a3623daSAndreas Gohr        }
291*2a3623daSAndreas Gohr    }
292*2a3623daSAndreas Gohr
293*2a3623daSAndreas Gohr    /**
294*2a3623daSAndreas Gohr     * Display the ACL editor
295*2a3623daSAndreas Gohr     *
296*2a3623daSAndreas Gohr     * @author Andreas Gohr <andi@splitbrain.org>
297*2a3623daSAndreas Gohr     */
298*2a3623daSAndreas Gohr    function _html_acleditor($current){
299*2a3623daSAndreas Gohr        global $lang;
300*2a3623daSAndreas Gohr
301*2a3623daSAndreas Gohr        echo '<fieldset>';
302*2a3623daSAndreas Gohr        if(is_null($current)){
303*2a3623daSAndreas Gohr            echo '<legend>'.$this->getLang('acl_new').'</legend>';
304*2a3623daSAndreas Gohr        }else{
305*2a3623daSAndreas Gohr            echo '<legend>'.$this->getLang('acl_mod').'</legend>';
306*2a3623daSAndreas Gohr        }
307*2a3623daSAndreas Gohr
308*2a3623daSAndreas Gohr
309*2a3623daSAndreas Gohr        echo $this->_html_checkboxes($current,empty($this->ns),'acl');
310*2a3623daSAndreas Gohr
311*2a3623daSAndreas Gohr        if(is_null($current)){
312*2a3623daSAndreas Gohr            echo '<input type="submit" name="cmd[save]" class="button" value="'.$lang['btn_save'].'" />'.NL;
313*2a3623daSAndreas Gohr        }else{
314*2a3623daSAndreas Gohr            echo '<input type="submit" name="cmd[save]" class="button" value="'.$lang['btn_update'].'" />'.NL;
315*2a3623daSAndreas Gohr            echo '<input type="submit" name="cmd[del]" class="button" value="'.$lang['btn_delete'].'" />'.NL;
316*2a3623daSAndreas Gohr        }
317*2a3623daSAndreas Gohr
318*2a3623daSAndreas Gohr        echo '</fieldset>';
319*2a3623daSAndreas Gohr    }
320*2a3623daSAndreas Gohr
321*2a3623daSAndreas Gohr    /**
322*2a3623daSAndreas Gohr     * Explain the currently set permissions in plain english/$lang
323*2a3623daSAndreas Gohr     *
324*2a3623daSAndreas Gohr     * @author Andreas Gohr <andi@splitbrain.org>
325*2a3623daSAndreas Gohr     */
326*2a3623daSAndreas Gohr    function _html_explain($current){
327*2a3623daSAndreas Gohr        global $ID;
328*2a3623daSAndreas Gohr        global $auth;
329*2a3623daSAndreas Gohr
330*2a3623daSAndreas Gohr        $who = $this->who;
331*2a3623daSAndreas Gohr        $ns  = $this->ns;
332*2a3623daSAndreas Gohr
333*2a3623daSAndreas Gohr        // prepare where to check
334*2a3623daSAndreas Gohr        if($ns){
335*2a3623daSAndreas Gohr            if($ns == '*'){
336*2a3623daSAndreas Gohr                $check='*';
337*2a3623daSAndreas Gohr            }else{
338*2a3623daSAndreas Gohr                $check=$ns.':*';
339*2a3623daSAndreas Gohr            }
340*2a3623daSAndreas Gohr        }else{
341*2a3623daSAndreas Gohr            $check = $ID;
342*2a3623daSAndreas Gohr        }
343*2a3623daSAndreas Gohr
344*2a3623daSAndreas Gohr        // prepare who to check
345*2a3623daSAndreas Gohr        if($who{0} == '@'){
346*2a3623daSAndreas Gohr            $user   = '';
347*2a3623daSAndreas Gohr            $groups = array(ltrim($who,'@'));
348*2a3623daSAndreas Gohr        }else{
349*2a3623daSAndreas Gohr            $user = auth_nameencode($who);
350*2a3623daSAndreas Gohr            $info = $auth->getUserData($user);
351*2a3623daSAndreas Gohr            $groups = $info['groups'];
352*2a3623daSAndreas Gohr        }
353*2a3623daSAndreas Gohr
354*2a3623daSAndreas Gohr        // check the permissions
355*2a3623daSAndreas Gohr        $perm = auth_aclcheck($check,$user,$groups);
356*2a3623daSAndreas Gohr
357*2a3623daSAndreas Gohr        // build array of named permissions
358*2a3623daSAndreas Gohr        $names = array();
359*2a3623daSAndreas Gohr        if($perm){
360*2a3623daSAndreas Gohr            if($ns){
361*2a3623daSAndreas Gohr                if($perm >= AUTH_DELETE) $names[] = $this->getLang('acl_perm16');
362*2a3623daSAndreas Gohr                if($perm >= AUTH_UPLOAD) $names[] = $this->getLang('acl_perm8');
363*2a3623daSAndreas Gohr                if($perm >= AUTH_CREATE) $names[] = $this->getLang('acl_perm4');
364*2a3623daSAndreas Gohr            }
365*2a3623daSAndreas Gohr            if($perm >= AUTH_EDIT) $names[] = $this->getLang('acl_perm2');
366*2a3623daSAndreas Gohr            if($perm >= AUTH_READ) $names[] = $this->getLang('acl_perm1');
367*2a3623daSAndreas Gohr            $names = array_reverse($names);
368*2a3623daSAndreas Gohr        }else{
369*2a3623daSAndreas Gohr            $names[] = $this->getLang('acl_perm0');
370*2a3623daSAndreas Gohr        }
371*2a3623daSAndreas Gohr
372*2a3623daSAndreas Gohr        // print permission explanation
373*2a3623daSAndreas Gohr        echo '<p>';
374*2a3623daSAndreas Gohr        if($user){
375*2a3623daSAndreas Gohr            if($ns){
376*2a3623daSAndreas Gohr                printf($this->getLang('p_user_ns'),hsc($who),hsc($ns),join(', ',$names));
377*2a3623daSAndreas Gohr            }else{
378*2a3623daSAndreas Gohr                printf($this->getLang('p_user_id'),hsc($who),hsc($ID),join(', ',$names));
379*2a3623daSAndreas Gohr            }
380*2a3623daSAndreas Gohr        }else{
381*2a3623daSAndreas Gohr            if($ns){
382*2a3623daSAndreas Gohr                printf($this->getLang('p_group_ns'),hsc(ltrim($who,'@')),hsc($ns),join(', ',$names));
383*2a3623daSAndreas Gohr            }else{
384*2a3623daSAndreas Gohr                printf($this->getLang('p_group_id'),hsc(ltrim($who,'@')),hsc($ID),join(', ',$names));
385*2a3623daSAndreas Gohr            }
386*2a3623daSAndreas Gohr        }
387*2a3623daSAndreas Gohr        echo '</p>';
388*2a3623daSAndreas Gohr
389*2a3623daSAndreas Gohr        // add note if admin
390*2a3623daSAndreas Gohr        if($perm == AUTH_ADMIN){
391*2a3623daSAndreas Gohr            echo '<p>'.$this->getLang('p_isadmin').'</p>';
392*2a3623daSAndreas Gohr        }elseif(is_null($current)){
393*2a3623daSAndreas Gohr            echo '<p>'.$this->getLang('p_inherited').'</p>';
394*2a3623daSAndreas Gohr        }
39511e2ce22Schris    }
39611e2ce22Schris
39711e2ce22Schris
39811e2ce22Schris    /**
399*2a3623daSAndreas Gohr     * Item formatter for the tree view
40011e2ce22Schris     *
401*2a3623daSAndreas Gohr     * User function for html_buildlist()
40211e2ce22Schris     *
403*2a3623daSAndreas Gohr     * @author Andreas Gohr <andi@splitbrain.org>
40411e2ce22Schris     */
405*2a3623daSAndreas Gohr    function _html_list_acl($item){
406*2a3623daSAndreas Gohr        global $ID;
407*2a3623daSAndreas Gohr        $ret = '';
408*2a3623daSAndreas Gohr        // what to display
409*2a3623daSAndreas Gohr        if($item['label']){
410*2a3623daSAndreas Gohr            $base = $item['label'];
411*2a3623daSAndreas Gohr        }else{
412*2a3623daSAndreas Gohr            $base = ':'.$item['id'];
413*2a3623daSAndreas Gohr            $base = substr($base,strrpos($base,':')+1);
414*2a3623daSAndreas Gohr        }
415*2a3623daSAndreas Gohr
416*2a3623daSAndreas Gohr        // highlight?
417*2a3623daSAndreas Gohr        if(($item['type']=='d' &&
418*2a3623daSAndreas Gohr            $item['id'] == $this->ns) ||
419*2a3623daSAndreas Gohr            $item['id'] == $ID) $cl = ' cur';
420*2a3623daSAndreas Gohr
421*2a3623daSAndreas Gohr        // namespace or page?
422*2a3623daSAndreas Gohr        if($item['type']=='d'){
423*2a3623daSAndreas Gohr            if($item['open']){
424*2a3623daSAndreas Gohr                $img   = DOKU_BASE.'lib/images/minus.gif';
425*2a3623daSAndreas Gohr                $alt   = '&minus;';
426*2a3623daSAndreas Gohr            }else{
427*2a3623daSAndreas Gohr                $img   = DOKU_BASE.'lib/images/plus.gif';
428*2a3623daSAndreas Gohr                $alt   = '+';
429*2a3623daSAndreas Gohr            }
430*2a3623daSAndreas Gohr            $ret .= '<img src="'.$img.'" alt="'.$alt.'" />';
431*2a3623daSAndreas Gohr            $ret .= '<a href="'.wl('',$this->_get_opts(array('ns'=>$item['id']))).'" class="idx_dir'.$cl.'">';
432*2a3623daSAndreas Gohr            $ret .= $base;
433*2a3623daSAndreas Gohr            $ret .= '</a>';
434*2a3623daSAndreas Gohr        }else{
435*2a3623daSAndreas Gohr            $ret .= '<a href="'.wl('',$this->_get_opts(array('id'=>$item['id'],'ns'=>''))).'" class="wikilink1'.$cl.'">';
436*2a3623daSAndreas Gohr            $ret .= noNS($item['id']);
437*2a3623daSAndreas Gohr            $ret .= '</a>';
438*2a3623daSAndreas Gohr        }
439*2a3623daSAndreas Gohr        return $ret;
440*2a3623daSAndreas Gohr    }
441*2a3623daSAndreas Gohr
442*2a3623daSAndreas Gohr
443*2a3623daSAndreas Gohr    function _html_li_acl($item){
444*2a3623daSAndreas Gohr            return '<li class="level'.$item['level'].'">';
445*2a3623daSAndreas Gohr    }
446*2a3623daSAndreas Gohr
447*2a3623daSAndreas Gohr
448*2a3623daSAndreas Gohr    /**
449*2a3623daSAndreas Gohr     * Get current ACL settings as multidim array
450*2a3623daSAndreas Gohr     *
451*2a3623daSAndreas Gohr     * @author Andreas Gohr <andi@splitbrain.org>
452*2a3623daSAndreas Gohr     */
453*2a3623daSAndreas Gohr    function _init_acl_config(){
45411e2ce22Schris        global $AUTH_ACL;
455*2a3623daSAndreas Gohr        global $conf;
45611e2ce22Schris        $acl_config=array();
457*2a3623daSAndreas Gohr        $usersgroups = array();
45811e2ce22Schris
459*2a3623daSAndreas Gohr        foreach($AUTH_ACL as $line){
460*2a3623daSAndreas Gohr            $line = trim(preg_replace('/#.*$/','',$line)); //ignore comments
461*2a3623daSAndreas Gohr            if(!$line) continue;
462*2a3623daSAndreas Gohr
463*2a3623daSAndreas Gohr            $acl = preg_split('/\s+/',$line);
46411e2ce22Schris            //0 is pagename, 1 is user, 2 is acl
465*2a3623daSAndreas Gohr
466*2a3623daSAndreas Gohr            $acl[1] = rawurldecode($acl[1]);
467*2a3623daSAndreas Gohr            $acl_config[$acl[0]][$acl[1]] = $acl[2];
468*2a3623daSAndreas Gohr
469*2a3623daSAndreas Gohr            // store non-special users and groups for later selection dialog
470*2a3623daSAndreas Gohr            $ug = $acl[1];
471*2a3623daSAndreas Gohr            if($ug == '@ALL') continue;
472*2a3623daSAndreas Gohr            if($ug == $conf['superuser']) continue;
473*2a3623daSAndreas Gohr            if($ug == $conf['manager']) continue;
474*2a3623daSAndreas Gohr            $usersgroups[] = $ug;
475*2a3623daSAndreas Gohr        }
476*2a3623daSAndreas Gohr
477*2a3623daSAndreas Gohr        $usersgroups = array_unique($usersgroups);
478*2a3623daSAndreas Gohr        sort($usersgroups);
479*2a3623daSAndreas Gohr        uksort($acl_config,array($this,'_sort_names'));
480*2a3623daSAndreas Gohr
481*2a3623daSAndreas Gohr        $this->acl = $acl_config;
482*2a3623daSAndreas Gohr        $this->usersgroups = $usersgroups;
483*2a3623daSAndreas Gohr    }
484*2a3623daSAndreas Gohr
485*2a3623daSAndreas Gohr    /**
486*2a3623daSAndreas Gohr     * Custom function to sort the ACLs by namespace names
487*2a3623daSAndreas Gohr     *
488*2a3623daSAndreas Gohr     * @todo This maybe could be improved to resemble the real tree structure?
489*2a3623daSAndreas Gohr     */
490*2a3623daSAndreas Gohr    function _sort_names($a,$b){
491*2a3623daSAndreas Gohr        $ca = substr_count($a,':');
492*2a3623daSAndreas Gohr        $cb = substr_count($b,':');
493*2a3623daSAndreas Gohr        if($ca < $cb){
494*2a3623daSAndreas Gohr            return -1;
495*2a3623daSAndreas Gohr        }elseif($ca > $cb){
496*2a3623daSAndreas Gohr            return 1;
497*2a3623daSAndreas Gohr        }else{
498*2a3623daSAndreas Gohr            return strcmp($a,$b);
49911e2ce22Schris        }
50011e2ce22Schris    }
50111e2ce22Schris
502*2a3623daSAndreas Gohr    /**
503*2a3623daSAndreas Gohr     * Display all currently set permissions in a table
504*2a3623daSAndreas Gohr     *
505*2a3623daSAndreas Gohr     * @author Andreas Gohr <andi@splitbrain.org>
506*2a3623daSAndreas Gohr     */
507*2a3623daSAndreas Gohr    function _html_table(){
508*2a3623daSAndreas Gohr        global $lang;
509*2a3623daSAndreas Gohr        global $ID;
510*2a3623daSAndreas Gohr
511*2a3623daSAndreas Gohr        echo '<form action="'.wl().'" method="post" accept-charset="utf-8">'.NL;
512*2a3623daSAndreas Gohr        if($this->ns){
513*2a3623daSAndreas Gohr            echo '<input type="hidden" name="ns" value="'.hsc($this->ns).'" />'.NL;
514*2a3623daSAndreas Gohr        }else{
515*2a3623daSAndreas Gohr            echo '<input type="hidden" name="id" value="'.hsc($ID).'" />'.NL;
51611e2ce22Schris        }
517*2a3623daSAndreas Gohr        echo '<input type="hidden" name="acl_w" value="'.hsc($this->who).'" />'.NL;
518*2a3623daSAndreas Gohr        echo '<input type="hidden" name="do" value="admin" />'.NL;
519*2a3623daSAndreas Gohr        echo '<input type="hidden" name="page" value="acl" />'.NL;
520*2a3623daSAndreas Gohr        echo '<table class="inline">';
521*2a3623daSAndreas Gohr        echo '<tr>';
522*2a3623daSAndreas Gohr        echo '<th>'.$this->getLang('where').'</th>';
523*2a3623daSAndreas Gohr        echo '<th>'.$this->getLang('who').'</th>';
524*2a3623daSAndreas Gohr        echo '<th>'.$this->getLang('perm').'</th>';
525*2a3623daSAndreas Gohr        echo '<th>'.$lang['btn_delete'].'</th>';
526*2a3623daSAndreas Gohr        echo '</tr>';
527*2a3623daSAndreas Gohr        foreach($this->acl as $where => $set){
528*2a3623daSAndreas Gohr            foreach($set as $who => $perm){
529*2a3623daSAndreas Gohr                echo '<tr>';
530*2a3623daSAndreas Gohr                echo '<td>';
531*2a3623daSAndreas Gohr                if(substr($where,-1) == '*'){
532*2a3623daSAndreas Gohr                    echo '<span class="aclns">'.hsc($where).'</span>';
533*2a3623daSAndreas Gohr                    $ispage = false;
534*2a3623daSAndreas Gohr                }else{
535*2a3623daSAndreas Gohr                    echo '<span class="aclpage">'.hsc($where).'</span>';
536*2a3623daSAndreas Gohr                    $ispage = true;
537*2a3623daSAndreas Gohr                }
538*2a3623daSAndreas Gohr                echo '</td>';
539*2a3623daSAndreas Gohr
540*2a3623daSAndreas Gohr                echo '<td>';
541*2a3623daSAndreas Gohr                if($who{0} == '@'){
542*2a3623daSAndreas Gohr                    echo '<span class="aclgroup">'.hsc($who).'</span>';
543*2a3623daSAndreas Gohr                }else{
544*2a3623daSAndreas Gohr                    echo '<span class="acluser">'.hsc($who).'</span>';
545*2a3623daSAndreas Gohr                }
546*2a3623daSAndreas Gohr                echo '</td>';
547*2a3623daSAndreas Gohr
548*2a3623daSAndreas Gohr                echo '<td>';
549*2a3623daSAndreas Gohr                echo $this->_html_checkboxes($perm,$ispage,'acl['.hsc($where).']['.hsc($who).']');
550*2a3623daSAndreas Gohr                echo '</td>';
551*2a3623daSAndreas Gohr
552*2a3623daSAndreas Gohr                echo '<td align="center">';
553*2a3623daSAndreas Gohr                echo '<input type="checkbox" name="del['.hsc($where).']" value="'.hsc($who).'" class="edit" />';
554*2a3623daSAndreas Gohr                echo '</td>';
555*2a3623daSAndreas Gohr                echo '</tr>';
55611e2ce22Schris            }
55711e2ce22Schris        }
55811e2ce22Schris
559*2a3623daSAndreas Gohr        echo '<tr>';
560*2a3623daSAndreas Gohr        echo '<th align="right" colspan="4">';
561*2a3623daSAndreas Gohr        echo '<input type="submit" value="'.$lang['btn_update'].'" name="cmd[update]" class="button" />';
562*2a3623daSAndreas Gohr        echo '</th>';
563*2a3623daSAndreas Gohr        echo '</tr>';
564*2a3623daSAndreas Gohr        echo '</table>';
565*2a3623daSAndreas Gohr        echo '</form>'.NL;
56611e2ce22Schris    }
56711e2ce22Schris
56811e2ce22Schris
569*2a3623daSAndreas Gohr    /**
570*2a3623daSAndreas Gohr     * Returns the permission which were set for exactly the given user/group
571*2a3623daSAndreas Gohr     * and page/namespace. Returns null if no exact match is available
572*2a3623daSAndreas Gohr     *
573*2a3623daSAndreas Gohr     * @author Andreas Gohr <andi@splitbrain.org>
574*2a3623daSAndreas Gohr     */
575*2a3623daSAndreas Gohr    function _get_exact_perm(){
576*2a3623daSAndreas Gohr        global $ID;
577*2a3623daSAndreas Gohr        if($this->ns){
578*2a3623daSAndreas Gohr            if($this->ns == '*'){
579*2a3623daSAndreas Gohr                $check = '*';
580*2a3623daSAndreas Gohr            }else{
581*2a3623daSAndreas Gohr                $check = $this->ns.':*';
582*2a3623daSAndreas Gohr            }
583*2a3623daSAndreas Gohr        }else{
584*2a3623daSAndreas Gohr            $check = $ID;
58511e2ce22Schris        }
58611e2ce22Schris
587*2a3623daSAndreas Gohr        if(isset($this->acl[$check][auth_nameencode($this->who,true)])){
588*2a3623daSAndreas Gohr            return $this->acl[$check][auth_nameencode($this->who,true)];
589*2a3623daSAndreas Gohr        }else{
590*2a3623daSAndreas Gohr            return null;
591*2a3623daSAndreas Gohr        }
592*2a3623daSAndreas Gohr    }
59311e2ce22Schris
59411e2ce22Schris    /**
59511e2ce22Schris     * adds new acl-entry to conf/acl.auth.php
59611e2ce22Schris     *
59711e2ce22Schris     * @author  Frank Schubert <frank@schokilade.de>
59811e2ce22Schris     */
599*2a3623daSAndreas Gohr    function _acl_add($acl_scope, $acl_user, $acl_level){
600*2a3623daSAndreas Gohr        $acl_config = file_get_contents(DOKU_CONF.'acl.auth.php');
601*2a3623daSAndreas Gohr        $acl_user = auth_nameencode($acl_user,true);
60211e2ce22Schris
60311e2ce22Schris        // max level for pagenames is edit
60411e2ce22Schris        if(strpos($acl_scope,'*') === false) {
60511e2ce22Schris            if($acl_level > AUTH_EDIT) $acl_level = AUTH_EDIT;
60611e2ce22Schris        }
60711e2ce22Schris
608*2a3623daSAndreas Gohr
60911e2ce22Schris        $new_acl = "$acl_scope\t$acl_user\t$acl_level\n";
61011e2ce22Schris
61111e2ce22Schris        $new_config = $acl_config.$new_acl;
61211e2ce22Schris
61311e2ce22Schris        return io_saveFile(DOKU_CONF.'acl.auth.php', $new_config);
61411e2ce22Schris    }
61511e2ce22Schris
61611e2ce22Schris    /**
61711e2ce22Schris     * remove acl-entry from conf/acl.auth.php
61811e2ce22Schris     *
61911e2ce22Schris     * @author  Frank Schubert <frank@schokilade.de>
62011e2ce22Schris     */
621*2a3623daSAndreas Gohr    function _acl_del($acl_scope, $acl_user){
62211e2ce22Schris        $acl_config = file(DOKU_CONF.'acl.auth.php');
623*2a3623daSAndreas Gohr        $acl_user = auth_nameencode($acl_user,true);
62411e2ce22Schris
62511e2ce22Schris        $acl_pattern = '^'.preg_quote($acl_scope,'/').'\s+'.$acl_user.'\s+[0-8].*$';
62611e2ce22Schris
627*2a3623daSAndreas Gohr        // save all non!-matching
62811e2ce22Schris        $new_config = preg_grep("/$acl_pattern/", $acl_config, PREG_GREP_INVERT);
62911e2ce22Schris
63011e2ce22Schris        return io_saveFile(DOKU_CONF.'acl.auth.php', join('',$new_config));
63111e2ce22Schris    }
63211e2ce22Schris
63311e2ce22Schris    /**
634*2a3623daSAndreas Gohr     * print the permission radio boxes
63511e2ce22Schris     *
63611e2ce22Schris     * @author  Frank Schubert <frank@schokilade.de>
63711e2ce22Schris     * @author  Andreas Gohr <andi@splitbrain.org>
63811e2ce22Schris     */
639*2a3623daSAndreas Gohr    function _html_checkboxes($setperm,$ispage,$name){
64011e2ce22Schris        global $lang;
64111e2ce22Schris
64211e2ce22Schris        static $label = 0; //number labels
64311e2ce22Schris        $ret = '';
64411e2ce22Schris
645*2a3623daSAndreas Gohr        if($ispage && $setperm > AUTH_EDIT) $perm = AUTH_EDIT;
646*2a3623daSAndreas Gohr
647*2a3623daSAndreas Gohr        foreach(array(AUTH_NONE,AUTH_READ,AUTH_EDIT,AUTH_CREATE,AUTH_UPLOAD,AUTH_DELETE) as $perm){
64811e2ce22Schris            $label += 1;
64911e2ce22Schris
65011e2ce22Schris            //general checkbox attributes
651*2a3623daSAndreas Gohr            $atts = array( 'type'  => 'radio',
65211e2ce22Schris                           'id'    => 'pbox'.$label,
653*2a3623daSAndreas Gohr                           'name'  => $name,
65411e2ce22Schris                           'value' => $perm );
65511e2ce22Schris            //dynamic attributes
656*2a3623daSAndreas Gohr            if(!is_null($setperm) && $setperm == $perm) $atts['checked']  = 'checked';
657*2a3623daSAndreas Gohr            if($ispage && $perm > AUTH_EDIT){
658*2a3623daSAndreas Gohr                $atts['disabled'] = 'disabled';
659*2a3623daSAndreas Gohr                $class = ' class="disabled"';
660*2a3623daSAndreas Gohr            }else{
661*2a3623daSAndreas Gohr                $class = '';
662*2a3623daSAndreas Gohr            }
66311e2ce22Schris
66411e2ce22Schris            //build code
665*2a3623daSAndreas Gohr            $ret .= '<label for="pbox'.$label.'" title="'.$this->getLang('acl_perm'.$perm).'"'.$class.'>';
666*2a3623daSAndreas Gohr            $ret .= '<input '.html_attbuild($atts).' />&nbsp;';
667*2a3623daSAndreas Gohr            $ret .= $this->getLang('acl_perm'.$perm);
668*2a3623daSAndreas Gohr            $ret .= '</label>'.NL;
66911e2ce22Schris        }
67011e2ce22Schris        return $ret;
67111e2ce22Schris    }
67211e2ce22Schris
673*2a3623daSAndreas Gohr    /**
674*2a3623daSAndreas Gohr     * Print a user/group selector (reusing already used users and groups)
675*2a3623daSAndreas Gohr     *
676*2a3623daSAndreas Gohr     * @author  Andreas Gohr <andi@splitbrain.org>
677*2a3623daSAndreas Gohr     */
678*2a3623daSAndreas Gohr    function _html_select(){
679*2a3623daSAndreas Gohr        global $conf;
680*2a3623daSAndreas Gohr        $inlist = false;
681*2a3623daSAndreas Gohr
682*2a3623daSAndreas Gohr        $specials = array('@ALL','@'.$conf['defaultgroup']);
683*2a3623daSAndreas Gohr        if($conf['manager'] && $conf['manager'] != '!!not set!!') $specials[] = $conf['manager'];
684*2a3623daSAndreas Gohr
685*2a3623daSAndreas Gohr
686*2a3623daSAndreas Gohr        if($this->who &&
687*2a3623daSAndreas Gohr           !in_array($this->who,$this->usersgroups) &&
688*2a3623daSAndreas Gohr           !in_array($this->who,$specials)){
689*2a3623daSAndreas Gohr
690*2a3623daSAndreas Gohr            if($this->who{0} == '@'){
691*2a3623daSAndreas Gohr                $gsel = ' selected="selected"';
692*2a3623daSAndreas Gohr            }else{
693*2a3623daSAndreas Gohr                $usel   = ' selected="selected"';
694*2a3623daSAndreas Gohr            }
695*2a3623daSAndreas Gohr        }else{
696*2a3623daSAndreas Gohr            $usel = '';
697*2a3623daSAndreas Gohr            $gsel = '';
698*2a3623daSAndreas Gohr            $inlist = true;
699*2a3623daSAndreas Gohr        }
700*2a3623daSAndreas Gohr
701*2a3623daSAndreas Gohr
702*2a3623daSAndreas Gohr        echo '<select name="acl_t" class="edit">'.NL;
703*2a3623daSAndreas Gohr        echo '  <option value="__g__" class="aclgroup"'.$gsel.'>'.$this->getLang('acl_group').':</option>'.NL;
704*2a3623daSAndreas Gohr        echo '  <option value="__u__"  class="acluser"'.$usel.'>'.$this->getLang('acl_user').':</option>'.NL;
705*2a3623daSAndreas Gohr        echo '  <optgroup label="&nbsp;">'.NL;
706*2a3623daSAndreas Gohr        foreach($specials as $ug){
707*2a3623daSAndreas Gohr            if($ug == $this->who){
708*2a3623daSAndreas Gohr                $sel    = ' selected="selected"';
709*2a3623daSAndreas Gohr                $inlist = true;
710*2a3623daSAndreas Gohr            }else{
711*2a3623daSAndreas Gohr                $sel = '';
712*2a3623daSAndreas Gohr            }
713*2a3623daSAndreas Gohr
714*2a3623daSAndreas Gohr            if($ug{0} == '@'){
715*2a3623daSAndreas Gohr                    echo '  <option value="'.hsc($ug).'" class="aclgroup"'.$sel.'>'.hsc($ug).'</option>'.NL;
716*2a3623daSAndreas Gohr            }else{
717*2a3623daSAndreas Gohr                    echo '  <option value="'.hsc($ug).'" class="acluser"'.$sel.'>'.hsc($ug).'</option>'.NL;
718*2a3623daSAndreas Gohr            }
719*2a3623daSAndreas Gohr        }
720*2a3623daSAndreas Gohr        echo '  </optgroup>'.NL;
721*2a3623daSAndreas Gohr        echo '  <optgroup label="&nbsp;">'.NL;
722*2a3623daSAndreas Gohr        foreach($this->usersgroups as $ug){
723*2a3623daSAndreas Gohr            if($ug == $this->who){
724*2a3623daSAndreas Gohr                $sel    = ' selected="selected"';
725*2a3623daSAndreas Gohr                $inlist = true;
726*2a3623daSAndreas Gohr            }else{
727*2a3623daSAndreas Gohr                $sel = '';
728*2a3623daSAndreas Gohr            }
729*2a3623daSAndreas Gohr
730*2a3623daSAndreas Gohr            if($ug{0} == '@'){
731*2a3623daSAndreas Gohr                    echo '  <option value="'.hsc($ug).'" class="aclgroup"'.$sel.'>'.hsc($ug).'</option>'.NL;
732*2a3623daSAndreas Gohr            }else{
733*2a3623daSAndreas Gohr                    echo '  <option value="'.hsc($ug).'" class="acluser"'.$sel.'>'.hsc($ug).'</option>'.NL;
734*2a3623daSAndreas Gohr            }
735*2a3623daSAndreas Gohr        }
736*2a3623daSAndreas Gohr        echo '  </optgroup>'.NL;
737*2a3623daSAndreas Gohr        echo '</select>'.NL;
738*2a3623daSAndreas Gohr        return $inlist;
739*2a3623daSAndreas Gohr    }
74011e2ce22Schris}
741