]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/PagePerm.php
just aesthetics
[SourceForge/phpwiki.git] / lib / PagePerm.php
1 <?php // -*-php-*-
2 rcs_id('$Id: PagePerm.php,v 1.37 2004-11-23 13:06:30 rurban Exp $');
3 /*
4  Copyright 2004 $ThePhpWikiProgrammingTeam
5
6  This file is part of PhpWiki.
7
8  PhpWiki is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12
13  PhpWiki is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  GNU General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with PhpWiki; if not, write to the Free Software
20  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 /**
24    Permissions per page and action based on current user, 
25    ownership and group membership implemented with ACL's (Access Control Lists),
26    opposed to the simplier unix like ugo:rwx system.
27    The previous system was only based on action and current user. (lib/main.php)
28
29    Permissions may be inherited from its parent pages, a optional the 
30    optional master page ("."), and predefined default permissions, if "." 
31    is not defined.
32    Pagenames starting with "." have special default permissions.
33    For Authentication see WikiUserNew.php, WikiGroup.php and main.php
34    Page Permissions are in PhpWiki since v1.3.9 and enabled since v1.4.0
35
36    This file might replace the following functions from main.php:
37      Request::_notAuthorized($require_level)
38        display the denied message and optionally a login form 
39        to gain higher privileges
40      Request::getActionDescription($action)
41        helper to localize the _notAuthorized message per action, 
42        when login is tried.
43      Request::getDisallowedActionDescription($action)
44        helper to localize the _notAuthorized message per action, 
45        when it aborts
46      Request::requiredAuthority($action)
47        returns the needed user level
48        has a hook for plugins on POST
49      Request::requiredAuthorityForAction($action)
50        just returns the level per action, will be replaced with the 
51        action + page pair
52
53      The defined main.php actions map to simplier access types:
54        browse => view
55        edit   => edit
56        create => edit or create
57        remove => remove
58        rename => change
59        store prefs => change
60        list in PageList => list
61 */
62
63 /* Symbolic special ACL groups. Untranslated to be stored in page metadata*/
64 define('ACL_EVERY',        '_EVERY');
65 define('ACL_ANONYMOUS',    '_ANONYMOUS');
66 define('ACL_BOGOUSER',     '_BOGOUSER');
67 define('ACL_HASHOMEPAGE',  '_HASHOMEPAGE');
68 define('ACL_SIGNED',       '_SIGNED');
69 define('ACL_AUTHENTICATED','_AUTHENTICATED');
70 define('ACL_ADMIN',        '_ADMIN');
71 define('ACL_OWNER',        '_OWNER');
72 define('ACL_CREATOR',      '_CREATOR');
73
74 // Return an page permissions array for this page.
75 // To provide ui helpers to view and change page permissions:
76 //   <tr><th>Group</th><th>Access</th><th>Allow or Forbid</th></tr>
77 //   <tr><td>$group</td><td>_($access)</td><td> [ ] </td></tr>
78 function pagePermissions($pagename) {
79     global $request;
80     $page = $request->getPage($pagename);
81     // Page not found (new page); returned inherited permissions, to be displayed in gray
82     if (! $page->exists() ) {
83         if ($pagename == '.') // stop recursion
84             return array('default', new PagePermission());
85         else {
86             return array('inherited', pagePermissions(getParentPage($pagename)));
87         }
88     } elseif ($perm = getPagePermissions($page)) {
89         return array('page',$perm);
90     // or no permissions defined; returned inherited permissions, to be displayed in gray
91     } elseif ($pagename == '.') { // stop recursion in pathological case. 
92         // "." defined, without any acl
93         return array('default', new PagePermission());
94     } else {
95         return array('inherited', pagePermissions(getParentPage($pagename)));
96     }
97 }
98
99 function pagePermissionsSimpleFormat($perm_tree, $owner, $group=false) {
100     list($type,$perm) = pagePermissionsAcl($perm_tree[0], $perm_tree);
101     /*
102     $type = $perm_tree[0];
103     $perm = pagePermissionsAcl($perm_tree);
104     if (is_object($perm_tree[1]))
105         $perm = $perm_tree[1];
106     elseif (is_array($perm_tree[1])) {
107         $perm_tree = pagePermissionsSimpleFormat($perm_tree[1],$owner,$group);
108         if (isa($perm_tree[1],'pagepermission'))
109             $perm = $perm_tree[1];
110         elseif (isa($perm_tree,'htmlelement'))
111             return $perm_tree;
112     }
113     */
114     if ($type == 'page')
115         return HTML::tt(HTML::strong($perm->asRwxString($owner, $group)));
116     elseif ($type == 'default')
117         return HTML::tt($perm->asRwxString($owner, $group));
118     elseif ($type == 'inherited') {
119         return HTML::tt(array('class'=>'inherited', 'style'=>'color:#aaa;'),
120                         $perm->asRwxString($owner, $group));
121     }
122 }
123
124 function pagePermissionsAcl($type,$perm_tree) {
125     $perm = $perm_tree[1];
126     while (!is_object($perm)) {
127         $perm_tree = pagePermissionsAcl($type, $perm);
128         $perm = $perm_tree[1];
129     }
130     return array($type,$perm);
131 }
132
133 // view => who
134 // edit => who
135 function pagePermissionsAclFormat($perm_tree, $editable=false) {
136     list($type,$perm) = pagePermissionsAcl($perm_tree[0], $perm_tree);
137     if ($editable)
138         return $perm->asEditableTable($type);
139     else
140         return $perm->asTable($type);
141 }
142
143 /** 
144  * Check the permissions for the current action.
145  * Walk down the inheritance tree. Collect all permissions until 
146  * the minimum required level is gained, which is not 
147  * overruled by more specific forbid rules.
148  * Todo: cache result per access and page in session?
149  */
150 function requiredAuthorityForPage ($action) {
151     global $request;
152     $auth = _requiredAuthorityForPagename(action2access($action),
153                                           $request->getArg('pagename'));
154     assert($auth !== -1);
155     if ($auth)
156         return $request->_user->_level;
157     else
158         return WIKIAUTH_UNOBTAINABLE;
159 }
160
161 // Translate action or plugin to the simplier access types:
162 function action2access ($action) {
163     global $request;
164     switch ($action) {
165     case 'browse':
166     case 'viewsource':
167     case 'diff':
168     case 'select':
169     case 'xmlrpc':
170     case 'search':
171     case 'pdf':
172         return 'view';
173     case 'zip':
174     case 'ziphtml':
175     case 'dumpserial':
176     case 'dumphtml':
177         return 'dump';
178     case 'revert':
179     case 'edit':
180         return 'edit';
181     case 'create':
182         $page = $request->getPage();
183         if (!$page->exists())
184             return 'create';
185         else
186             return 'view'; 
187         break;
188     case 'upload':
189     case 'loadfile': 
190         // probably create/edit but we cannot check all page permissions, can we?
191     case 'remove':
192     case 'lock':
193     case 'unlock':
194     case 'upgrade':
195     case 'chown':
196     case 'setacl':
197     case 'rename':
198             return 'change';
199     default:
200         //Todo: Plugins should be able to override its access type
201         if (isWikiWord($action))
202             return 'view';
203         else
204             return 'change';
205         break;
206     }
207 }
208
209 // Recursive helper to do the real work
210 // TODO: check if a perm cache for page-(current+edit+change?)action pairs will help
211 function _requiredAuthorityForPagename($access, $pagename) {
212     static $permcache = array();
213     
214     if (array_key_exists($pagename, $permcache)
215         and array_key_exists($access, $permcache[$pagename]))
216         return $permcache[$pagename][$access];
217         
218     global $request;
219     $page = $request->getPage($pagename);
220     // Page not found; check against default permissions
221     if (! $page->exists() ) {
222         $perm = new PagePermission();
223         $result = ($perm->isAuthorized($access, $request->_user) === true);
224         $permcache[$pagename][$access] = $result;
225         return $result;
226     }
227     // no ACL defined; check for special dotfile or walk down
228     if (! ($perm = getPagePermissions($page))) { 
229         if ($pagename == '.') {
230             $perm = new PagePermission();
231             if ($perm->isAuthorized('change', $request->_user)) {
232                 // warn the user to set ACL of ".", if he has permissions to do so.
233                 trigger_error(". (dotpage == rootpage for inheriting pageperm ACLs) exists without any ACL!\n".
234                               "Please do ?action=setacl&pagename=.", E_USER_WARNING);
235             }
236             $result = ($perm->isAuthorized($access, $request->_user) === true);
237             $permcache[$pagename][$access] = $result;
238             return $result;
239         } elseif ($pagename[0] == '.') {
240             $perm = new PagePermission(PagePermission::dotPerms());
241             $result = ($perm->isAuthorized($access, $request->_user) === true);
242             $permcache[$pagename][$access] = $result;
243             return $result;
244         }
245         return _requiredAuthorityForPagename($access, getParentPage($pagename));
246     }
247     // ACL defined; check if isAuthorized returns true or false or undecided
248     $authorized = $perm->isAuthorized($access, $request->_user);
249     if ($authorized !== -1) { // interestingly true is also -1
250         $permcache[$pagename][$access] = $authorized;
251         return $authorized;
252     } elseif ($pagename == '.') {
253         return false;
254     } else {    
255         return _requiredAuthorityForPagename($access, getParentPage($pagename));
256     }
257 }
258
259 /**
260  * @param  string $pagename   page from which the parent page is searched.
261  * @return string parent      pagename or the (possibly pseudo) dot-pagename.
262  */
263 function getParentPage($pagename) {
264     if (isSubPage($pagename)) {
265         return subPageSlice($pagename,0);
266     } else {
267         return '.';
268     }
269 }
270
271 // Read the ACL from the page
272 // Done: Not existing pages should NOT be queried. 
273 // Check the parent page instead and don't take the default ACL's
274 function getPagePermissions ($page) {
275     if ($hash = $page->get('perm'))  // hash => object
276         return new PagePermission(unserialize($hash));
277     else 
278         return false;
279 }
280
281 // Store the ACL in the page
282 function setPagePermissions ($page,$perm) {
283     $perm->store($page);
284 }
285
286 function getAccessDescription($access) {
287     static $accessDescriptions;
288     if (! $accessDescriptions) {
289         $accessDescriptions = array(
290                                     'list'     => _("List this page and all subpages"),
291                                     'view'     => _("View this page and all subpages"),
292                                     'edit'     => _("Edit this page and all subpages"),
293                                     'create'   => _("Create a new (sub)page"),
294                                     'dump'     => _("Download the page contents"),
295                                     'change'   => _("Change page attributes"),
296                                     'remove'   => _("Remove this page"),
297                                     );
298     }
299     if (in_array($access, array_keys($accessDescriptions)))
300         return $accessDescriptions[$access];
301     else
302         return $access;
303 }
304
305 // from php.net docs
306 function array_diff_assoc_recursive($array1, $array2) {
307     foreach ($array1 as $key => $value) {
308          if (is_array($value)) {
309              if (!is_array($array2[$key])) {
310                  $difference[$key] = $value;
311              } else {
312                  $new_diff = array_diff_assoc_recursive($value, $array2[$key]);
313                  if ($new_diff != false) {
314                      $difference[$key] = $new_diff;
315                  } 
316              }
317          } elseif(!isset($array2[$key]) || $array2[$key] != $value) {
318              $difference[$key] = $value;
319          }
320     }
321     return !isset($difference) ? 0 : $difference;
322 }
323
324 /**
325  * The ACL object per page. It is stored in a page, but can also 
326  * be merged with ACL's from other pages or taken from the master (pseudo) dot-file.
327  *
328  * A hash of "access" => "requires" pairs.
329  *   "access"   is a shortcut for common actions, which map to main.php actions
330  *   "requires" required username or groupname or any special group => true or false
331  *
332  * Define any special rules here, like don't list dot-pages.
333  */ 
334 class PagePermission {
335     var $perm;
336
337     function PagePermission($hash = array()) {
338         $this->_group = &$GLOBALS['request']->getGroup();
339         if (is_array($hash) and !empty($hash)) {
340             $accessTypes = $this->accessTypes();
341             foreach ($hash as $access => $requires) {
342                 if (in_array($access, $accessTypes))
343                     $this->perm[$access] = $requires;
344                 else
345                     trigger_error(sprintf(_("Unsupported ACL access type %s ignored."), $access),
346                                   E_USER_WARNING);
347             }
348         } else {
349             // set default permissions, the so called dot-file acl's
350             $this->perm = $this->defaultPerms();
351         }
352         return $this;
353     }
354
355     /**
356      * The workhorse to check the user against the current ACL pairs.
357      * Must translate the various special groups to the actual users settings 
358      * (userid, group membership).
359      */
360     function isAuthorized($access,$user) {
361         if (!empty($this->perm{$access})) {
362             foreach ($this->perm[$access] as $group => $bool) {
363                 if ($this->isMember($user,$group)) {
364                     return $bool;
365                 }
366             }
367         }
368         return -1; // undecided
369     }
370
371     /**
372      * Translate the various special groups to the actual users settings 
373      * (userid, group membership).
374      */
375     function isMember($user, $group) {
376         global $request;
377         if ($group === ACL_EVERY) return true;
378         if (!isset($this->_group)) $member =& $request->getGroup();
379         else $member =& $this->_group;
380         //$user = & $request->_user;
381         if ($group === ACL_ADMIN)   // WIKI_ADMIN or member of _("Administrators")
382             return $user->isAdmin() or 
383                    ($user->isAuthenticated() and 
384                    $member->isMember(GROUP_ADMIN));
385         if ($group === ACL_ANONYMOUS) 
386             return ! $user->isSignedIn();
387         if ($group === ACL_BOGOUSER)
388             if (ENABLE_USER_NEW)
389                 return isa($user,'_BogoUser') or 
390                       (isWikiWord($user->_userid) and $user->_level >= WIKIAUTH_BOGO);
391             else return isWikiWord($user->UserName());
392         if ($group === ACL_HASHOMEPAGE)
393             return $user->hasHomePage();
394         if ($group === ACL_SIGNED)
395             return $user->isSignedIn();
396         if ($group === ACL_AUTHENTICATED)
397             return $user->isAuthenticated();
398         if ($group === ACL_OWNER) {
399             if (!$user->isAuthenticated()) return false;
400             $page = $request->getPage();
401             $owner = $page->getOwner();
402             return ($owner === $user->UserName() 
403                     or $member->isMember($owner));
404         }
405         if ($group === ACL_CREATOR) {
406             if (!$user->isAuthenticated()) return false;
407             $page = $request->getPage();
408             $creator = $page->getCreator();
409             return ($creator === $user->UserName() 
410                     or $member->isMember($creator));
411         }
412         /* Or named groups or usernames.
413            Note: We don't seperate groups and users here. 
414            Users overrides groups with the same name. 
415         */
416         return $user->UserName() === $group or
417                $member->isMember($group);
418     }
419
420     /**
421      * returns hash of default permissions.
422      * check if the page '.' exists and returns this instead.
423      */
424     function defaultPerms() {
425         //Todo: check for the existance of '.' and take this instead.
426         //Todo: honor more config.ini auth settings here
427         $perm = array('view'   => array(ACL_EVERY => true),
428                       'edit'   => array(ACL_EVERY => true),
429                       'create' => array(ACL_EVERY => true),
430                       'list'   => array(ACL_EVERY => true),
431                       'remove' => array(ACL_ADMIN => true,
432                                         ACL_OWNER => true),
433                       'change' => array(ACL_ADMIN => true,
434                                         ACL_OWNER => true));
435         if (ZIPDUMP_AUTH)
436             $perm['dump'] = array(ACL_ADMIN => true,
437                                   ACL_OWNER => true);
438         else
439             $perm['dump'] = array(ACL_EVERY => true);
440         if (defined('REQUIRE_SIGNIN_BEFORE_EDIT') && REQUIRE_SIGNIN_BEFORE_EDIT)
441             $perm['edit'] = array(ACL_SIGNED => true);
442         // view:
443         if (!ALLOW_ANON_USER) {
444             if (!ALLOW_USER_PASSWORDS) 
445                 $perm['view'] = array(ACL_SIGNED => true);
446             else                
447                 $perm['view'] = array(ACL_AUTHENTICATED => true);
448             $perm['view'][ACL_BOGOUSER] = ALLOW_BOGO_LOGIN ? true : false;
449         }
450         // edit:
451         if (!ALLOW_ANON_EDIT) {
452             if (!ALLOW_USER_PASSWORDS) 
453                 $perm['edit'] = array(ACL_SIGNED => true);
454             else                
455                 $perm['edit'] = array(ACL_AUTHENTICATED => true);
456             $perm['edit'][ACL_BOGOUSER] = ALLOW_BOGO_LOGIN ? true : false;
457             $perm['create'] = $perm['edit'];
458         }
459         return $perm;
460     }
461
462     /**
463      * FIXME: check valid groups and access
464      */
465     function sanify() {
466         foreach ($this->perm as $access => $groups) {
467             foreach ($groups as $group => $bool) {
468                 $this->perm[$access][$group] = (boolean) $bool;
469             }
470         }
471     }
472
473     /**
474      * do a recursive comparison
475      */
476     function equal($otherperm) {
477         $diff = array_diff_assoc_recursive($this->perm, $otherperm);
478         return empty($diff);
479     }
480     
481     /**
482      * returns list of all supported access types.
483      */
484     function accessTypes() {
485         return array_keys(PagePermission::defaultPerms());
486     }
487
488     /**
489      * special permissions for dot-files, beginning with '.'
490      * maybe also for '_' files?
491      */
492     function dotPerms() {
493         $def = array(ACL_ADMIN => true,
494                      ACL_OWNER => true);
495         $perm = array();
496         foreach (PagePermission::accessTypes() as $access) {
497             $perm[$access] = $def;
498         }
499         return $perm;
500     }
501
502     /**
503      *  dead code. not needed inside the object. see getPagePermissions($page)
504      */
505     function retrieve($page) {
506         $hash = $page->get('perm');
507         if ($hash)  // hash => object
508             $perm = new PagePermission(unserialize($hash));
509         else 
510             $perm = new PagePermission();
511         $perm->sanify();
512         return $perm;
513     }
514
515     function store($page) {
516         // object => hash
517         $this->sanify();
518         return $page->set('perm',serialize($this->perm));
519     }
520
521     function groupName ($group) {
522         if ($group[0] == '_') return constant("GROUP".$group);
523         else return $group;
524     }
525     
526     /* type: page, default, inherited */
527     function asTable($type) {
528         $table = HTML::table();
529         foreach ($this->perm as $access => $perms) {
530             $td = HTML::table(array('class' => 'cal','valign' => 'top'));
531             foreach ($perms as $group => $bool) {
532                 $td->pushContent(HTML::tr(HTML::td(array('align'=>'right'),$group),
533                                                    HTML::td($bool ? '[X]' : '[ ]')));
534             }
535             $table->pushContent(HTML::tr(array('valign' => 'top'),
536                                          HTML::td($access),HTML::td($td)));
537         }
538         if ($type == 'default')
539             $table->setAttr('style','border: dotted thin black; background-color:#eee;');
540         elseif ($type == 'inherited')
541             $table->setAttr('style','border: dotted thin black; background-color:#ddd;');
542         elseif ($type == 'page')
543             $table->setAttr('style','border: solid thin black; font-weight: bold;');
544         return $table;
545     }
546     
547     /* type: page, default, inherited */
548     function asEditableTable($type) {
549         global $WikiTheme;
550         if (!isset($this->_group)) { 
551             $this->_group =& $GLOBALS['request']->getGroup();
552         }
553         $table = HTML::table();
554         $table->pushContent(HTML::tr(
555                                      HTML::th(array('align' => 'left'),
556                                               _("Access")),
557                                      HTML::th(array('align'=>'right'),
558                                               _("Group/User")),
559                                      HTML::th(_("Grant")),
560                                      HTML::th(_("Del/+")),
561                                      HTML::th(_("Description"))));
562         
563         $allGroups = $this->_group->_specialGroups();
564         foreach ($this->_group->getAllGroupsIn() as $group) {
565             if (!in_array($group,$this->_group->specialGroups()))
566                 $allGroups[] = $group;
567         }
568         //array_unique(array_merge($this->_group->getAllGroupsIn(),
569         $deletesrc = $WikiTheme->_findData('images/delete.png');
570         $addsrc = $WikiTheme->_findData('images/add.png');
571         $nbsp = HTML::raw('&nbsp;');
572         foreach ($this->perm as $access => $groups) {
573             //$permlist = HTML::table(array('class' => 'cal','valign' => 'top'));
574             $first_only = true;
575             $newperm = HTML::input(array('type' => 'checkbox',
576                                          'name' => "acl[_new_perm][$access]",
577                                          'value' => 1));
578             $addbutton = HTML::input(array('type' => 'checkbox',
579                                            'name' => "acl[_add_group][$access]",
580                                            //'src'  => $addsrc,
581                                            //'alt'   => "Add",
582                                            'title' => _("Add this ACL"),
583                                            'value' => 1));
584             $newgroup = HTML::select(array('name' => "acl[_new_group][$access]",
585                                            'style'=> 'text-align: right;',
586                                            'size' => 1));
587             foreach ($allGroups as $groupname) {
588                 if (!isset($groups[$groupname]))
589                     $newgroup->pushContent(HTML::option(array('value' => $groupname),
590                                                         $this->groupName($groupname)));
591             }
592             if (empty($groups)) {
593                 $addbutton->setAttr('checked','checked');
594                 $newperm->setAttr('checked','checked');
595                 $table->pushContent(
596                     HTML::tr(array('valign' => 'top'),
597                              HTML::td(HTML::strong($access.":")),
598                              HTML::td($newgroup),
599                              HTML::td($nbsp,$newperm),
600                              HTML::td($nbsp,$addbutton),
601                              HTML::td(HTML::em(getAccessDescription($access)))));
602             }
603             foreach ($groups as $group => $bool) {
604                 $checkbox = HTML::input(array('type' => 'checkbox',
605                                               'name' => "acl[$access][$group]",
606                                               'title' => _("Allow / Deny"),
607                                               'value' => 1));
608                 if ($bool) $checkbox->setAttr('checked','checked');
609                 $checkbox = HTML(HTML::input(array('type' => 'hidden',
610                                                    'name' => "acl[$access][$group]",
611                                                    'value' => 0)),
612                                  $checkbox);
613                 $deletebutton = HTML::input(array('type' => 'checkbox',
614                                                   'name' => "acl[_del_group][$access][$group]",
615                                                   'style' => 'background: #aaa url('.$deletesrc.')',
616                                                   //'src'  => $deletesrc,
617                                                   //'alt'   => "Del",
618                                                   'title' => _("Delete this ACL"),
619                                                   'value' => 1));
620                 if ($first_only) {
621                     $table->pushContent(
622                         HTML::tr(
623                                  HTML::td(HTML::strong($access.":")),
624                                  HTML::td(array('class' => 'cal-today','align'=>'right'),
625                                           HTML::strong($this->groupName($group))),
626                                  HTML::td(array('align'=>'center'),$nbsp,$checkbox),
627                                  HTML::td(array('align'=>'right','style' => 'background: #aaa url('.$deletesrc.') no-repeat'),$deletebutton),
628                                  HTML::td(HTML::em(getAccessDescription($access)))));
629                     $first_only = false;
630                 } else {
631                     $table->pushContent(
632                         HTML::tr(
633                                  HTML::td(),
634                                  HTML::td(array('class' => 'cal-today','align'=>'right'),
635                                           HTML::strong($this->groupName($group))),
636                                  HTML::td(array('align'=>'center'),$nbsp,$checkbox),
637                                  HTML::td(array('align'=>'right','style' => 'background: #aaa url('.$deletesrc.') no-repeat'),$deletebutton),
638                                  HTML::td()));
639                 }
640             }
641             if (!empty($groups))
642                 $table->pushContent(
643                     HTML::tr(array('valign' => 'top'),
644                              HTML::td(array('align'=>'right'),_("add ")),
645                              HTML::td($newgroup),
646                              HTML::td(array('align'=>'center'),$nbsp,$newperm),
647                              HTML::td(array('align'=>'right','style' => 'background: #ccc url('.$addsrc.') no-repeat'),$addbutton),
648                              HTML::td(HTML::small(_("Check to add this Acl")))));
649         }
650         if ($type == 'default')
651             $table->setAttr('style','border: dotted thin black; background-color:#eee;');
652         elseif ($type == 'inherited')
653             $table->setAttr('style','border: dotted thin black; background-color:#ddd;');
654         elseif ($type == 'page')
655             $table->setAttr('style','border: solid thin black; font-weight: bold;');
656         return $table;
657     }
658
659     // Print ACL as lines of [+-]user[,group,...]:access[,access...]
660     // Seperate acl's by "; " or whitespace
661     // See http://opag.ca/wiki/HelpOnAccessControlLists
662     // As used by WikiAdminSetAclSimple
663     function asAclLines() {
664         $s = ''; $line = '';
665         $this->sanify();
666         foreach ($this->perm as $access => $groups) {
667             // unify groups for same access+bool
668             //    view:CREATOR,-OWNER,
669             $line = $access.':';
670             foreach ($groups as $group => $bool) {
671                 $line .= ($bool?'':'-').$group.",";
672             }
673             if (substr($line,-1) == ',')
674                 $s .= substr($line,0,-1)."; ";
675         }
676         if (substr($s,-2) == '; ')
677             $s = substr($s,0,-2);
678         return $s;
679     }
680
681
682     // This is just a bad hack for testing.
683     // Simplify the ACL to a unix-like "rwx------+" string
684     // See getfacl(8)
685     function asRwxString($owner,$group=false) {
686         global $request;
687         // simplify object => rwxrw---x+ string as in cygwin (+ denotes additional ACLs)
688         $perm =& $this->perm;
689         // get effective user and group
690         $s = '---------+';
691         if (isset($perm['view'][$owner]) or 
692             (isset($perm['view'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
693             $s[0] = 'r';
694         if (isset($perm['edit'][$owner]) or 
695             (isset($perm['edit'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
696             $s[1] = 'w';
697         if (isset($perm['change'][$owner]) or 
698             (isset($perm['change'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
699             $s[2] = 'x';
700         if (!empty($group)) {
701             if (isset($perm['view'][$group]) or 
702                 (isset($perm['view'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
703                 $s[3] = 'r';
704             if (isset($perm['edit'][$group]) or 
705                 (isset($perm['edit'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
706                 $s[4] = 'w';
707             if (isset($perm['change'][$group]) or 
708                 (isset($perm['change'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
709                 $s[5] = 'x';
710         }
711         if (isset($perm['view'][ACL_EVERY]) or 
712             (isset($perm['view'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
713             $s[6] = 'r';
714         if (isset($perm['edit'][ACL_EVERY]) or 
715             (isset($perm['edit'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
716             $s[7] = 'w';
717         if (isset($perm['change'][ACL_EVERY]) or 
718             (isset($perm['change'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
719             $s[8] = 'x';
720         return $s;
721     }
722 }
723
724 // $Log: not supported by cvs2svn $
725 // Revision 1.36  2004/11/21 11:59:16  rurban
726 // remove final \n to be ob_cache independent
727 //
728 // Revision 1.35  2004/11/15 15:56:40  rurban
729 // don't load PagePerm on ENABLE_PAGEPERM = false to save memory. Move mayAccessPage() to main.php
730 //
731 // Revision 1.34  2004/11/01 10:43:55  rurban
732 // seperate PassUser methods into seperate dir (memory usage)
733 // fix WikiUser (old) overlarge data session
734 // remove wikidb arg from various page class methods, use global ->_dbi instead
735 // ...
736 //
737 // Revision 1.33  2004/09/26 11:47:52  rurban
738 // fix another reecursion loop when . exists: deny if ACL not defined; implement pageperm cache
739 //
740 // Revision 1.32  2004/09/25 18:56:09  rurban
741 // avoid recursion bug on setacl for "."
742 //
743 // Revision 1.31  2004/09/25 18:34:45  rurban
744 // fix and warn on too restrictive ACL handling without ACL in existing . (dotpage)
745 //
746 // Revision 1.30  2004/09/25 16:24:02  rurban
747 // fix interesting PagePerm problem: -1 == true
748 //
749 // Revision 1.29  2004/07/03 08:04:19  rurban
750 // fixed implicit PersonalPage login (e.g. on edit), fixed to check against create ACL on create, not edit
751 //
752 // Revision 1.28  2004/06/25 14:29:17  rurban
753 // WikiGroup refactoring:
754 //   global group attached to user, code for not_current user.
755 //   improved helpers for special groups (avoid double invocations)
756 // new experimental config option ENABLE_XHTML_XML (fails with IE, and document.write())
757 // fixed a XHTML validation error on userprefs.tmpl
758 //
759 // Revision 1.27  2004/06/16 10:38:58  rurban
760 // Disallow refernces in calls if the declaration is a reference
761 // ("allow_call_time_pass_reference clean").
762 //   PhpWiki is now allow_call_time_pass_reference = Off clean,
763 //   but several external libraries may not.
764 //   In detail these libs look to be affected (not tested):
765 //   * Pear_DB odbc
766 //   * adodb oracle
767 //
768 // Revision 1.26  2004/06/14 11:31:36  rurban
769 // renamed global $Theme to $WikiTheme (gforge nameclash)
770 // inherit PageList default options from PageList
771 //   default sortby=pagename
772 // use options in PageList_Selectable (limit, sortby, ...)
773 // added action revert, with button at action=diff
774 // added option regex to WikiAdminSearchReplace
775 //
776 // Revision 1.25  2004/06/08 13:51:57  rurban
777 // some comments only
778 //
779 // Revision 1.24  2004/06/08 10:54:46  rurban
780 // better acl dump representation, read back acl and owner
781 //
782 // Revision 1.23  2004/06/08 10:05:11  rurban
783 // simplified admin action shortcuts
784 //
785 // Revision 1.22  2004/06/07 22:44:14  rurban
786 // added simplified chown, setacl actions
787 //
788 // Revision 1.21  2004/06/07 22:28:03  rurban
789 // add acl field to mimified dump
790 //
791 // Revision 1.20  2004/06/07 18:39:03  rurban
792 // support for SetAclSimple
793 //
794 // Revision 1.19  2004/06/06 17:12:28  rurban
795 // fixed PagePerm non-object problem (mayAccessPage), also bug #967150
796 //
797 // Revision 1.18  2004/05/27 17:49:05  rurban
798 // renamed DB_Session to DbSession (in CVS also)
799 // added WikiDB->getParam and WikiDB->getAuthParam method to get rid of globals
800 // remove leading slash in error message
801 // added force_unlock parameter to File_Passwd (no return on stale locks)
802 // fixed adodb session AffectedRows
803 // added FileFinder helpers to unify local filenames and DATA_PATH names
804 // editpage.php: new edit toolbar javascript on ENABLE_EDIT_TOOLBAR
805 //
806 // Revision 1.17  2004/05/16 23:10:44  rurban
807 // update_locale wrongly resetted LANG, which broke japanese.
808 // japanese now correctly uses EUC_JP, not utf-8.
809 // more charset and lang headers to help the browser.
810 //
811 // Revision 1.16  2004/05/16 22:32:53  rurban
812 // setacl icons
813 //
814 // Revision 1.15  2004/05/16 22:07:35  rurban
815 // check more config-default and predefined constants
816 // various PagePerm fixes:
817 //   fix default PagePerms, esp. edit and view for Bogo and Password users
818 //   implemented Creator and Owner
819 //   BOGOUSERS renamed to BOGOUSER
820 // fixed syntax errors in signin.tmpl
821 //
822 // Revision 1.14  2004/05/15 22:54:49  rurban
823 // fixed important WikiDB bug with DEBUG > 0: wrong assertion
824 // improved SetAcl (works) and PagePerms, some WikiGroup helpers.
825 //
826 // Revision 1.13  2004/05/15 19:48:33  rurban
827 // fix some too loose PagePerms for signed, but not authenticated users
828 //  (admin, owner, creator)
829 // no double login page header, better login msg.
830 // moved action_pdf to lib/pdf.php
831 //
832 // Revision 1.12  2004/05/04 22:34:25  rurban
833 // more pdf support
834 //
835 // Revision 1.11  2004/05/02 21:26:38  rurban
836 // limit user session data (HomePageHandle and auth_dbi have to invalidated anyway)
837 //   because they will not survive db sessions, if too large.
838 // extended action=upgrade
839 // some WikiTranslation button work
840 // revert WIKIAUTH_UNOBTAINABLE (need it for main.php)
841 // some temp. session debug statements
842 //
843 // Revision 1.10  2004/04/29 22:32:56  zorloc
844 // Slightly more elegant fix.  Instead of WIKIAUTH_FORBIDDEN, the current user's level + 1 is returned on a false.
845 //
846 // Revision 1.9  2004/04/29 17:18:19  zorloc
847 // Fixes permission failure issues.  With PagePermissions and Disabled Actions when user did not have permission WIKIAUTH_FORBIDDEN was returned.  In WikiUser this was ok because WIKIAUTH_FORBIDDEN had a value of 11 -- thus no user could perform that action.  But WikiUserNew has a WIKIAUTH_FORBIDDEN value of -1 -- thus a user without sufficent permission to do anything.  The solution is a new high value permission level (WIKIAUTH_UNOBTAINABLE) to be the default level for access failure.
848 //
849 // Revision 1.8  2004/03/14 16:24:35  rurban
850 // authenti(fi)cation spelling
851 //
852 // Revision 1.7  2004/02/28 22:25:07  rurban
853 // First PagePerm implementation:
854 //
855 // $WikiTheme->setAnonEditUnknownLinks(false);
856 //
857 // Layout improvement with dangling links for mostly closed wiki's:
858 // If false, only users with edit permissions will be presented the
859 // special wikiunknown class with "?" and Tooltip.
860 // If true (default), any user will see the ?, but will be presented
861 // the PrintLoginForm on a click.
862 //
863 // Revision 1.6  2004/02/24 15:20:05  rurban
864 // fixed minor warnings: unchecked args, POST => Get urls for sortby e.g.
865 //
866 // Revision 1.5  2004/02/23 21:30:25  rurban
867 // more PagePerm stuff: (working against 1.4.0)
868 //   ACL editing and simplification of ACL's to simple rwx------ string
869 //   not yet working.
870 //
871 // Revision 1.4  2004/02/12 13:05:36  rurban
872 // Rename functional for PearDB backend
873 // some other minor changes
874 // SiteMap comes with a not yet functional feature request: includepages (tbd)
875 //
876 // Revision 1.3  2004/02/09 03:58:12  rurban
877 // for now default DB_SESSION to false
878 // PagePerm:
879 //   * not existing perms will now query the parent, and not
880 //     return the default perm
881 //   * added pagePermissions func which returns the object per page
882 //   * added getAccessDescription
883 // WikiUserNew:
884 //   * added global ->prepare (not yet used) with smart user/pref/member table prefixing.
885 //   * force init of authdbh in the 2 db classes
886 // main:
887 //   * fixed session handling (not triple auth request anymore)
888 //   * don't store cookie prefs with sessions
889 // stdlib: global obj2hash helper from _AuthInfo, also needed for PagePerm
890 //
891 // Revision 1.2  2004/02/08 13:17:48  rurban
892 // This should be the functionality. Needs testing and some minor todos.
893 //
894 // Revision 1.1  2004/02/08 12:29:30  rurban
895 // initial version, not yet hooked into lib/main.php
896 //
897 //
898
899 // Local Variables:
900 // mode: php
901 // tab-width: 8
902 // c-basic-offset: 4
903 // c-hanging-comment-ender-p: nil
904 // indent-tabs-mode: nil
905 // End:
906 ?>