2 rcs_id('$Id: PagePerm.php,v 1.19 2004-06-06 17:12:28 rurban Exp $');
4 Copyright 2004 $ThePhpWikiProgrammingTeam
6 This file is part of PhpWiki.
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.
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.
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
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)
29 Permissions may be inherited from its parent pages, a optional the
30 optional master page ("."), and predefined default permissions, if "."
32 Pagenames starting with "." have special default permissions.
33 For Authentication see WikiUserNew.php, WikiGroup.php and main.php
34 Page Permssions are in PhpWiki since v1.3.9 and enabled since v1.4.0
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,
43 Request::getDisallowedActionDescription($action)
44 helper to localize the _notAuthorized message per action,
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
53 The defined main.php actions map to simplier access types:
56 create => edit or create
60 list in PageList => list
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');
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) {
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());
86 return array('inherited',pagePermissions(getParentPage($pagename)));
88 } elseif ($perm = getPagePermissions($page)) {
89 return array('page',$perm);
90 // or no permissions defined; returned inherited permissions, to be displayed in gray
92 return array('inherited',pagePermissions(getParentPage($pagename)));
96 function pagePermissionsSimpleFormat($perm_tree,$owner,$group=false) {
97 list($type,$perm) = pagePermissionsAcl($perm_tree[0], $perm_tree);
99 $type = $perm_tree[0];
100 $perm = pagePermissionsAcl($perm_tree);
101 if (is_object($perm_tree[1]))
102 $perm = $perm_tree[1];
103 elseif (is_array($perm_tree[1])) {
104 $perm_tree = pagePermissionsSimpleFormat($perm_tree[1],$owner,$group);
105 if (isa($perm_tree[1],'pagepermission'))
106 $perm = $perm_tree[1];
107 elseif (isa($perm_tree,'htmlelement'))
112 return HTML::tt(HTML::bold($perm->asRwxString($owner,$group).'+'));
113 elseif ($type == 'default')
114 return HTML::tt($perm->asRwxString($owner,$group));
115 elseif ($type == 'inherited') {
116 return HTML::tt(array('class'=>'inherited','style'=>'color:#aaa;'),
117 $perm->asRwxString($owner,$group));
121 function pagePermissionsAcl($type,$perm_tree) {
122 $perm = $perm_tree[1];
123 while (!is_object($perm)) {
124 $perm_tree = pagePermissionsAcl($type, $perm);
125 $perm = $perm_tree[1];
127 return array($type,$perm);
132 function pagePermissionsAclFormat($perm_tree, $editable=false) {
133 list($type,$perm) = pagePermissionsAcl($perm_tree[0], $perm_tree);
135 return $perm->asEditableTable($type);
137 return $perm->asTable($type);
141 * Check permission per page.
142 * Returns true or false.
144 function mayAccessPage ($access, $pagename) {
146 return _requiredAuthorityForPagename($access, $pagename);
151 /** Check the permissions for the current action.
152 * Walk down the inheritance tree. Collect all permissions until
153 * the minimum required level is gained, which is not
154 * overruled by more specific forbid rules.
155 * Todo: cache result per access and page in session?
157 function requiredAuthorityForPage ($action) {
158 $auth = _requiredAuthorityForPagename(action2access($action),
159 $GLOBALS['request']->getArg('pagename'));
160 assert($auth !== -1);
162 return $GLOBALS['request']->_user->_level;
164 return WIKIAUTH_UNOBTAINABLE;
167 // Translate action or plugin to the simplier access types:
168 function action2access ($action) {
187 $page = $request->getPage();
188 $current = $page->getCurrentRevision();
189 if ($current->hasDefaultContents())
196 // probably create/edit but we cannot check all page permissions, can we?
203 //Todo: Plugins should be able to override its access type
204 if (isWikiWord($action))
212 // Recursive helper to do the real work
213 function _requiredAuthorityForPagename($access, $pagename) {
215 $page = $request->getPage($pagename);
216 // Page not found; check against default permissions
217 if (! $page->exists() ) {
218 $perm = new PagePermission();
219 return ($perm->isAuthorized($access, $request->_user) === true);
221 // no ACL defined; check for special dotfile or walk down
222 if (! ($perm = getPagePermissions($page))) {
223 if ($pagename[0] == '.') {
224 $perm = new PagePermission(PagePermission::dotPerms());
225 return ($perm->isAuthorized($access, $request->_user) === true);
227 return _requiredAuthorityForPagename($access, getParentPage($pagename));
229 // ACL defined; check if isAuthorized returns true or false or undecided
230 $authorized = $perm->isAuthorized($access, $request->_user);
231 if ($authorized != -1) // -1 for undecided
234 return _requiredAuthorityForPagename($access, getParentPage($pagename));
238 * @param string $pagename page from which the parent page is searched.
239 * @return string parent pagename or the (possibly pseudo) dot-pagename.
241 function getParentPage($pagename) {
242 if (isSubPage($pagename)) {
243 return subPageSlice($pagename,0);
249 // Read the ACL from the page
250 // Done: Not existing pages should NOT be queried.
251 // Check the parent page instead and don't take the default ACL's
252 function getPagePermissions ($page) {
253 if ($hash = $page->get('perm')) // hash => object
254 return new PagePermission(unserialize($hash));
259 // Store the ACL in the page
260 function setPagePermissions ($page,$perm) {
264 function getAccessDescription($access) {
265 static $accessDescriptions;
266 if (! $accessDescriptions) {
267 $accessDescriptions = array(
268 'list' => _("List this page and all subpages"),
269 'view' => _("View this page and all subpages"),
270 'edit' => _("Edit this page and all subpages"),
271 'create' => _("Create a new (sub)page"),
272 'dump' => _("Download the page contents"),
273 'change' => _("Change page attributes"),
274 'remove' => _("Remove this page"),
277 if (in_array($access, array_keys($accessDescriptions)))
278 return $accessDescriptions[$access];
284 function array_diff_assoc_recursive($array1, $array2) {
285 foreach ($array1 as $key => $value) {
286 if (is_array($value)) {
287 if (!is_array($array2[$key])) {
288 $difference[$key] = $value;
290 $new_diff = array_diff_assoc_recursive($value, $array2[$key]);
291 if ($new_diff != false) {
292 $difference[$key] = $new_diff;
295 } elseif(!isset($array2[$key]) || $array2[$key] != $value) {
296 $difference[$key] = $value;
299 return !isset($difference) ? 0 : $difference;
303 * The ACL object per page. It is stored in a page, but can also
304 * be merged with ACL's from other pages or taken from the master (pseudo) dot-file.
306 * A hash of "access" => "requires" pairs.
307 * "access" is a shortcut for common actions, which map to main.php actions
308 * "requires" required username or groupname or any special group => true or false
310 * Define any special rules here, like don't list dot-pages.
312 class PagePermission {
315 function PagePermission($hash = array()) {
316 $this->_group = &WikiGroup::getGroup($GLOBALS['request']);
317 if (is_array($hash) and !empty($hash)) {
318 $accessTypes = $this->accessTypes();
319 foreach ($hash as $access => $requires) {
320 if (in_array($access, $accessTypes))
321 $this->perm[$access] = $requires;
323 trigger_error(sprintf(_("Unsupported ACL access type %s ignored."), $access),
327 // set default permissions, the so called dot-file acl's
328 $this->perm = $this->defaultPerms();
334 * The workhorse to check the user against the current ACL pairs.
335 * Must translate the various special groups to the actual users settings
336 * (userid, group membership).
338 function isAuthorized($access,$user) {
339 if (!empty($this->perm{$access})) {
340 foreach ($this->perm[$access] as $group => $bool) {
341 if ($this->isMember($user,$group)) {
346 return -1; // undecided
350 * Translate the various special groups to the actual users settings
351 * (userid, group membership).
353 function isMember($user, $group) {
355 if ($group === ACL_EVERY) return true;
356 if (!isset($this->_group)) $member =& WikiGroup::getGroup($request);
357 else $member =& $this->_group;
358 //$user = & $request->_user;
359 if ($group === ACL_ADMIN) // WIKI_ADMIN or member of _("Administrators")
360 return $user->isAdmin() or
361 ($user->isAuthenticated() and
362 $member->isMember(GROUP_ADMIN));
363 if ($group === ACL_ANONYMOUS)
364 return ! $user->isSignedIn();
365 if ($group === ACL_BOGOUSER)
367 return isa($user,'_BogoUser') or
368 (isWikiWord($user->_userid) and $user->_level >= WIKIAUTH_BOGO);
369 else return isWikiWord($user->UserName());
370 if ($group === ACL_HASHOMEPAGE)
371 return $user->hasHomePage();
372 if ($group === ACL_SIGNED)
373 return $user->isSignedIn();
374 if ($group === ACL_AUTHENTICATED)
375 return $user->isAuthenticated();
376 if ($group === ACL_OWNER) {
377 $page = $request->getPage();
378 return ($user->isAuthenticated() and
379 $page->getOwner() === $user->UserName());
381 if ($group === ACL_CREATOR) {
382 $page = $request->getPage();
383 return ($user->isAuthenticated() and
384 $page->getCreator() === $user->UserName());
386 /* Or named groups or usernames.
387 Note: We don't seperate groups and users here.
388 Users overrides groups with the same name.
390 return $user->UserName() === $group or
391 $member->isMember($group);
395 * returns hash of default permissions.
396 * check if the page '.' exists and returns this instead.
398 function defaultPerms() {
399 //Todo: check for the existance of '.' and take this instead.
400 //Todo: honor more config.ini auth settings here
401 $perm = array('view' => array(ACL_EVERY => true),
402 'edit' => array(ACL_EVERY => true),
403 'create' => array(ACL_EVERY => true),
404 'list' => array(ACL_EVERY => true),
405 'remove' => array(ACL_ADMIN => true,
407 'change' => array(ACL_ADMIN => true,
410 $perm['dump'] = array(ACL_ADMIN => true,
413 $perm['dump'] = array(ACL_EVERY => true);
415 if (!ALLOW_ANON_USER) {
416 if (!ALLOW_USER_PASSWORDS)
417 $perm['view'] = array(ACL_SIGNED => true);
419 $perm['view'] = array(ACL_AUTHENTICATED => true);
420 $perm['view'][ACL_BOGOUSER] = ALLOW_BOGO_LOGIN ? true : false;
423 if (!ALLOW_ANON_EDIT) {
424 if (!ALLOW_USER_PASSWORDS)
425 $perm['edit'] = array(ACL_SIGNED => true);
427 $perm['edit'] = array(ACL_AUTHENTICATED => true);
428 $perm['edit'][ACL_BOGOUSER] = ALLOW_BOGO_LOGIN ? true : false;
429 $perm['create'] = $perm['edit'];
435 foreach ($this->perm as $access => $groups) {
436 foreach ($groups as $group => $bool) {
437 $this->perm[$access][$group] = (boolean) $bool;
443 * do a recursive comparison
445 function equal($otherperm) {
446 $diff = array_diff_assoc_recursive($this->perm, $otherperm);
451 * returns list of all supported access types.
453 function accessTypes() {
454 return array_keys(PagePermission::defaultPerms());
458 * special permissions for dot-files, beginning with '.'
459 * maybe also for '_' files?
461 function dotPerms() {
462 $def = array(ACL_ADMIN => true,
465 foreach (PagePermission::accessTypes() as $access) {
466 $perm[$access] = $def;
472 * dead code. not needed inside the object. see getPagePermissions($page)
474 function retrieve($page) {
475 $hash = $page->get('perm');
476 if ($hash) // hash => object
477 $perm = new PagePermission(unserialize($hash));
479 $perm = new PagePermission();
484 function store($page) {
487 return $page->set('perm',serialize($this->perm));
490 function groupName ($group) {
491 if ($group[0] == '_') return constant("GROUP".$group);
495 /* type: page, default, inherited */
496 function asTable($type) {
497 $table = HTML::table();
498 foreach ($this->perm as $access => $perms) {
499 $td = HTML::table(array('class' => 'cal','valign' => 'top'));
500 foreach ($perms as $group => $bool) {
501 $td->pushContent(HTML::tr(HTML::td(array('align'=>'right'),$group),
502 HTML::td($bool ? '[X]' : '[ ]')));
504 $table->pushContent(HTML::tr(array('valign' => 'top'),
505 HTML::td($access),HTML::td($td)));
507 if ($type == 'default')
508 $table->setAttr('style','border: dotted thin black; background-color:#eee;');
509 elseif ($type == 'inherited')
510 $table->setAttr('style','border: dotted thin black; background-color:#ddd;');
511 elseif ($type == 'page')
512 $table->setAttr('style','border: solid thin black; font-weight: bold;');
516 /* type: page, default, inherited */
517 function asEditableTable($type) {
519 if (!isset($this->_group)) {
520 $this->_group =& WikiGroup::getGroup($GLOBALS['request']);
522 $table = HTML::table();
523 $table->pushContent(HTML::tr(
524 HTML::th(array('align' => 'left'),
526 HTML::th(array('align'=>'right'),
528 HTML::th(_("Grant")),
529 HTML::th(_("Del/+")),
530 HTML::th(_("Description"))));
532 $allGroups = $this->_group->_specialGroups();
533 foreach ($this->_group->getAllGroupsIn() as $group) {
534 if (!in_array($group,$this->_group->specialGroups()))
535 $allGroups[] = $group;
537 //array_unique(array_merge($this->_group->getAllGroupsIn(),
538 $deletesrc = $Theme->_findData('images/delete.png');
539 $addsrc = $Theme->_findData('images/add.png');
540 $nbsp = HTML::raw(' ');
541 foreach ($this->perm as $access => $groups) {
542 //$permlist = HTML::table(array('class' => 'cal','valign' => 'top'));
544 $newperm = HTML::input(array('type' => 'checkbox',
545 'name' => "acl[_new_perm][$access]",
547 $addbutton = HTML::input(array('type' => 'checkbox',
548 'name' => "acl[_add_group][$access]",
551 'title' => _("Add this ACL"),
553 $newgroup = HTML::select(array('name' => "acl[_new_group][$access]",
554 'style'=> 'text-align: right;',
556 foreach ($allGroups as $groupname) {
557 if (!isset($groups[$groupname]))
558 $newgroup->pushContent(HTML::option(array('value' => $groupname),
559 $this->groupName($groupname)));
561 if (empty($groups)) {
562 $addbutton->setAttr('checked','checked');
563 $newperm->setAttr('checked','checked');
565 HTML::tr(array('valign' => 'top'),
566 HTML::td(HTML::strong($access.":")),
568 HTML::td($nbsp,$newperm),
569 HTML::td($nbsp,$addbutton),
570 HTML::td(HTML::em(getAccessDescription($access)))));
572 foreach ($groups as $group => $bool) {
573 $checkbox = HTML::input(array('type' => 'checkbox',
574 'name' => "acl[$access][$group]",
575 'title' => _("Allow / Deny"),
577 if ($bool) $checkbox->setAttr('checked','checked');
578 $checkbox = HTML(HTML::input(array('type' => 'hidden',
579 'name' => "acl[$access][$group]",
582 $deletebutton = HTML::input(array('type' => 'checkbox',
583 'name' => "acl[_del_group][$access][$group]",
584 'style' => 'background: #aaa url('.$deletesrc.')',
585 //'src' => $deletesrc,
587 'title' => _("Delete this ACL"),
592 HTML::td(HTML::strong($access.":")),
593 HTML::td(array('class' => 'cal-today','align'=>'right'),
594 HTML::strong($this->groupName($group))),
595 HTML::td(array('align'=>'center'),$nbsp,$checkbox),
596 HTML::td(array('align'=>'right','style' => 'background: #aaa url('.$deletesrc.') no-repeat'),$deletebutton),
597 HTML::td(HTML::em(getAccessDescription($access)))));
603 HTML::td(array('class' => 'cal-today','align'=>'right'),
604 HTML::strong($this->groupName($group))),
605 HTML::td(array('align'=>'center'),$nbsp,$checkbox),
606 HTML::td(array('align'=>'right','style' => 'background: #aaa url('.$deletesrc.') no-repeat'),$deletebutton),
612 HTML::tr(array('valign' => 'top'),
613 HTML::td(array('align'=>'right'),_("add ")),
615 HTML::td(array('align'=>'center'),$nbsp,$newperm),
616 HTML::td(array('align'=>'right','style' => 'background: #ccc url('.$addsrc.') no-repeat'),$addbutton),
617 HTML::td(HTML::small(_("Check to add this Acl")))));
619 if ($type == 'default')
620 $table->setAttr('style','border: dotted thin black; background-color:#eee;');
621 elseif ($type == 'inherited')
622 $table->setAttr('style','border: dotted thin black; background-color:#ddd;');
623 elseif ($type == 'page')
624 $table->setAttr('style','border: solid thin black; font-weight: bold;');
628 // this is just a bad hack for testing
629 // simplify the ACL to a unix-like "rwx------" string
630 function asRwxString($owner,$group=false) {
632 // simplify object => rwxrw---x+ string as in cygwin (+ denotes additional ACLs)
633 $perm =& $this->perm;
634 // get effective user and group
636 if (isset($perm['view'][$owner]) or
637 (isset($perm['view'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
639 if (isset($perm['edit'][$owner]) or
640 (isset($perm['edit'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
642 if (isset($perm['change'][$owner]) or
643 (isset($perm['change'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
645 if (!empty($group)) {
646 if (isset($perm['view'][$group]) or
647 (isset($perm['view'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
649 if (isset($perm['edit'][$group]) or
650 (isset($perm['edit'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
652 if (isset($perm['change'][$group]) or
653 (isset($perm['change'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
656 if (isset($perm['view'][ACL_EVERY]) or
657 (isset($perm['view'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
659 if (isset($perm['edit'][ACL_EVERY]) or
660 (isset($perm['edit'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
662 if (isset($perm['change'][ACL_EVERY]) or
663 (isset($perm['change'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
669 // $Log: not supported by cvs2svn $
670 // Revision 1.18 2004/05/27 17:49:05 rurban
671 // renamed DB_Session to DbSession (in CVS also)
672 // added WikiDB->getParam and WikiDB->getAuthParam method to get rid of globals
673 // remove leading slash in error message
674 // added force_unlock parameter to File_Passwd (no return on stale locks)
675 // fixed adodb session AffectedRows
676 // added FileFinder helpers to unify local filenames and DATA_PATH names
677 // editpage.php: new edit toolbar javascript on ENABLE_EDIT_TOOLBAR
679 // Revision 1.17 2004/05/16 23:10:44 rurban
680 // update_locale wrongly resetted LANG, which broke japanese.
681 // japanese now correctly uses EUC_JP, not utf-8.
682 // more charset and lang headers to help the browser.
684 // Revision 1.16 2004/05/16 22:32:53 rurban
687 // Revision 1.15 2004/05/16 22:07:35 rurban
688 // check more config-default and predefined constants
689 // various PagePerm fixes:
690 // fix default PagePerms, esp. edit and view for Bogo and Password users
691 // implemented Creator and Owner
692 // BOGOUSERS renamed to BOGOUSER
693 // fixed syntax errors in signin.tmpl
695 // Revision 1.14 2004/05/15 22:54:49 rurban
696 // fixed important WikiDB bug with DEBUG > 0: wrong assertion
697 // improved SetAcl (works) and PagePerms, some WikiGroup helpers.
699 // Revision 1.13 2004/05/15 19:48:33 rurban
700 // fix some too loose PagePerms for signed, but not authenticated users
701 // (admin, owner, creator)
702 // no double login page header, better login msg.
703 // moved action_pdf to lib/pdf.php
705 // Revision 1.12 2004/05/04 22:34:25 rurban
708 // Revision 1.11 2004/05/02 21:26:38 rurban
709 // limit user session data (HomePageHandle and auth_dbi have to invalidated anyway)
710 // because they will not survive db sessions, if too large.
711 // extended action=upgrade
712 // some WikiTranslation button work
713 // revert WIKIAUTH_UNOBTAINABLE (need it for main.php)
714 // some temp. session debug statements
716 // Revision 1.10 2004/04/29 22:32:56 zorloc
717 // Slightly more elegant fix. Instead of WIKIAUTH_FORBIDDEN, the current user's level + 1 is returned on a false.
719 // Revision 1.9 2004/04/29 17:18:19 zorloc
720 // 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.
722 // Revision 1.8 2004/03/14 16:24:35 rurban
723 // authenti(fi)cation spelling
725 // Revision 1.7 2004/02/28 22:25:07 rurban
726 // First PagePerm implementation:
728 // $Theme->setAnonEditUnknownLinks(false);
730 // Layout improvement with dangling links for mostly closed wiki's:
731 // If false, only users with edit permissions will be presented the
732 // special wikiunknown class with "?" and Tooltip.
733 // If true (default), any user will see the ?, but will be presented
734 // the PrintLoginForm on a click.
736 // Revision 1.6 2004/02/24 15:20:05 rurban
737 // fixed minor warnings: unchecked args, POST => Get urls for sortby e.g.
739 // Revision 1.5 2004/02/23 21:30:25 rurban
740 // more PagePerm stuff: (working against 1.4.0)
741 // ACL editing and simplification of ACL's to simple rwx------ string
744 // Revision 1.4 2004/02/12 13:05:36 rurban
745 // Rename functional for PearDB backend
746 // some other minor changes
747 // SiteMap comes with a not yet functional feature request: includepages (tbd)
749 // Revision 1.3 2004/02/09 03:58:12 rurban
750 // for now default DB_SESSION to false
752 // * not existing perms will now query the parent, and not
753 // return the default perm
754 // * added pagePermissions func which returns the object per page
755 // * added getAccessDescription
757 // * added global ->prepare (not yet used) with smart user/pref/member table prefixing.
758 // * force init of authdbh in the 2 db classes
760 // * fixed session handling (not triple auth request anymore)
761 // * don't store cookie prefs with sessions
762 // stdlib: global obj2hash helper from _AuthInfo, also needed for PagePerm
764 // Revision 1.2 2004/02/08 13:17:48 rurban
765 // This should be the functionality. Needs testing and some minor todos.
767 // Revision 1.1 2004/02/08 12:29:30 rurban
768 // initial version, not yet hooked into lib/main.php
776 // c-hanging-comment-ender-p: nil
777 // indent-tabs-mode: nil