2 rcs_id('$Id: WikiGroup.php,v 1.37 2004-06-25 14:29:18 rurban Exp $');
4 Copyright (C) 2003, 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
23 if (!defined('GROUP_METHOD') or
24 !in_array(GROUP_METHOD,
25 array('NONE','WIKIPAGE','DB','FILE','LDAP')))
26 trigger_error(_("No or unsupported GROUP_METHOD defined"), E_USER_WARNING);
28 /* Special group names for ACL */
29 define('GROUP_EVERY', _("Every"));
30 define('GROUP_ANONYMOUS', _("Anonymous Users"));
31 define('GROUP_BOGOUSER', _("Bogo Users"));
32 define('GROUP_HASHOMEPAGE', _("HasHomePage"));
33 define('GROUP_SIGNED', _("Signed Users"));
34 define('GROUP_AUTHENTICATED', _("Authenticated Users"));
35 define('GROUP_ADMIN', _("Administrators"));
36 define('GROUP_OWNER', _("Owner"));
37 define('GROUP_CREATOR', _("Creator"));
40 * WikiGroup is an abstract class to provide the base functions for determining
41 * group membership for a specific user. Some functions are user independent.
43 * Limitation: For the current user only. This must be fixed to be able to query
44 * for membership of any user.
46 * WikiGroup is an abstract class with three functions:
47 * <ol><li />Provide the static method getGroup with will return the proper
49 * <li />Provide an interface for subclasses to implement.
50 * <li />Provide fallover methods (with error msgs) if not impemented in subclass.
52 * Do not ever instantiate this class. Use: $group = &WikiGroup::getGroup();
53 * This will instantiate the proper subclass.
55 * @author Joby Walker <zorloc@imperium.org>
61 /** User object if different from current user */
63 /** The global WikiRequest object */
65 /** Array of groups $username is confirmed to belong to */
67 /** boolean if not the current user */
71 * Initializes a WikiGroup object which should never happen. Use:
72 * $group = &WikiGroup::getGroup();
73 * @param object $request The global WikiRequest object -- ignored.
75 function WikiGroup($not_current = false) {
76 $this->not_current = $not_current;
77 $this->request =& $GLOBALS['request'];
81 * Gets the current username from the internal user object
82 * and erases $this->membership if is different than
83 * the stored $this->username
84 * @return string Current username.
86 function _getUserName(){
87 $user = (!empty($this->user)) ? $this->user : $this->request->getUser();
88 $username = $user->getID();
89 if ($username != $this->username) {
90 $this->membership = array();
91 $this->username = $username;
93 if (!$this->not_current)
99 * Static method to return the WikiGroup subclass used in this wiki. Controlled
100 * by the constant GROUP_METHOD.
101 * @param object $request The global WikiRequest object.
102 * @return object Subclass of WikiGroup selected via GROUP_METHOD.
104 function getGroup($not_current = false){
105 switch (GROUP_METHOD){
107 return new GroupNone($not_current);
110 return new GroupWikiPage($not_current);
113 if ($GLOBALS['DBParams']['dbtype'] == 'ADODB') {
114 return new GroupDB_ADODB($not_current);
115 } elseif ($GLOBALS['DBParams']['dbtype'] == 'SQL') {
116 return new GroupDb_PearDB($not_current);
118 trigger_error("GROUP_METHOD = DB: Unsupported dbtype "
119 . $GLOBALS['DBParams']['dbtype'],
124 return new GroupFile($not_current);
127 return new GroupLDAP($not_current);
130 trigger_error(_("No or unsupported GROUP_METHOD defined"), E_USER_WARNING);
131 return new WikiGroup($not_current);
135 /** ACL PagePermissions will need those special groups based on the User status only.
138 function specialGroup($group){
139 return in_array($group,$this->specialGroups());
142 function _specialGroup($group){
143 return in_array($group,$this->_specialGroups());
146 function specialGroups(){
156 function _specialGroups(){
167 * Determines if the current user is a member of a group.
169 * This method is an abstraction. The group is ignored, an error is sent, and
170 * false (not a member of the group) is returned.
171 * @param string $group Name of the group to check for membership (ignored).
172 * @return boolean True if user is a member, else false (always false).
174 function isMember($group){
175 if (isset($this->membership[$group]))
176 return $this->membership[$group];
177 if ($this->specialGroup($group)) {
178 return $this->isSpecialMember($group);
180 trigger_error(__sprintf("Method '%s' not implemented in this GROUP_METHOD %s",
181 'isMember', GROUP_METHOD),
187 function isSpecialMember($group){
188 if (isset($this->membership[$group]))
189 return $this->membership[$group];
190 $user = (!empty($this->user)) ? $this->user : $this->request->getUser();
193 return $this->membership[$group] = true;
194 case GROUP_ANONYMOUS:
195 return $this->membership[$group] = ! $user->isSignedIn();
197 return $this->membership[$group] = (isa($user,'_BogoUser') and
198 $user->_level >= WIKIAUTH_BOGO);
200 return $this->membership[$group] = $user->isSignedIn();
201 case GROUP_AUTHENTICATED:
202 return $this->membership[$group] = $user->isAuthenticated();
204 return $this->membership[$group] = $user->isAdmin();
206 trigger_error(__sprintf("Undefined method %s for special group %s",
214 * Determines all of the groups of which the current user is a member.
216 * This method is an abstraction. An error is sent and an empty
218 * @return array Array of groups to which the user belongs (always empty).
220 function getAllGroupsIn(){
221 trigger_error(__sprintf("Method '%s' not implemented in this GROUP_METHOD %s",
222 'getAllGroupsIn', GROUP_METHOD),
227 function _allUsers() {
228 static $result = array();
232 /* WikiPage users: */
233 $dbh = $this->request->getDbh();
234 $page_iter = $dbh->getAllPages();
236 while ($page = $page_iter->next()) {
237 if ($page->isUserPage())
238 $users[] = $page->_pagename;
241 /* WikiDB users from prefs (not from users): */
242 $dbi = _PassUser::getAuthDbh();
243 if ($dbi and !empty($GLOBALS['DBAuthParams']['pref_select'])) {
245 $sql = preg_replace('/SELECT .+ FROM/i','SELECT userid FROM',
246 $GLOBALS['DBAuthParams']['pref_select']);
247 //don't strip WHERE, only the userid stuff.
248 $sql = preg_replace('/(WHERE.*?)\s+\w+\s*=\s*["\']\$userid[\'"]/i','\\1 AND 1',$sql);
249 $sql = str_replace('WHERE AND 1','',$sql);
250 if ($GLOBALS['DBParams']['dbtype'] == 'ADODB') {
251 $db_result = $dbi->Execute($sql);
252 foreach ($db_result->GetArray() as $u) {
253 $users = array_merge($users,array_values($u));
255 } elseif ($GLOBALS['DBParams']['dbtype'] == 'SQL') {
256 $users = array_merge($users,$dbi->getCol($sql));
260 /* WikiDB users from users: */
261 // Fixme: don't strip WHERE, only the userid stuff.
262 if ($dbi and !empty($GLOBALS['DBAuthParams']['auth_user_exists'])) {
263 //don't strip WHERE, only the userid stuff.
264 $sql = preg_replace('/(WHERE.*?)\s+\w+\s*=\s*["\']\$userid[\'"]/i','\\1 AND 1',
265 $GLOBALS['DBAuthParams']['auth_user_exists']);
266 $sql = str_replace('WHERE AND 1','',$sql);
267 if ($GLOBALS['DBParams']['dbtype'] == 'ADODB') {
268 $db_result = $dbi->Execute($sql);
269 foreach ($db_result->GetArray() as $u) {
270 $users = array_merge($users,array_values($u));
272 } elseif ($GLOBALS['DBParams']['dbtype'] == 'SQL') {
273 $users = array_merge($users,$dbi->getCol($sql));
277 // remove empty and duplicate users
279 foreach ($users as $u) {
280 if (empty($u) or in_array($u,$result)) continue;
287 * Determines all of the members of a particular group.
289 * This method is an abstraction. The group is ignored, an error is sent,
290 * and an empty array is returned
291 * @param string $group Name of the group to get the full membership list of.
292 * @return array Array of usernames that have joined the group (always empty).
294 function getMembersOf($group){
295 if ($this->specialGroup($group)) {
296 return getSpecialMembersOf($group);
298 trigger_error(__sprintf("Method '%s' not implemented in this GROUP_METHOD %s",
299 'getMembersOf', GROUP_METHOD),
304 function getSpecialMembersOf($group) {
305 //$request = &$this->request;
306 $all = $this->_allUsers();
311 case GROUP_ANONYMOUS:
314 foreach ($all as $u) {
315 if (isWikiWord($user)) $users[] = $u;
319 foreach ($all as $u) {
320 $user = WikiUser($u);
321 if ($user->isSignedIn()) $users[] = $u;
324 case GROUP_AUTHENTICATED:
325 foreach ($all as $u) {
326 $user = WikiUser($u);
327 if ($user->isAuthenticated()) $users[] = $u;
331 foreach ($all as $u) {
332 $user = WikiUser($u);
333 if ($user->isAdmin()) $users[] = $u;
337 trigger_error(__sprintf("Unknown special group '%s'", $group),
343 * Add the current or specified user to a group.
345 * This method is an abstraction. The group and user are ignored, an error
346 * is sent, and false (not added) is always returned.
347 * @param string $group User added to this group.
348 * @param string $user Username to add to the group (default = current user).
349 * @return bool On true user was added, false if not.
351 function setMemberOf($group, $user = false){
352 trigger_error(__sprintf("Method '%s' not implemented in this GROUP_METHOD %s",
353 'setMemberOf', GROUP_METHOD),
359 * Remove the current or specified user to a group.
361 * This method is an abstraction. The group and user are ignored, and error
362 * is sent, and false (not removed) is always returned.
363 * @param string $group User removed from this group.
364 * @param string $user Username to remove from the group (default = current user).
365 * @return bool On true user was removed, false if not.
367 function removeMemberOf($group, $user = false){
368 trigger_error(__sprintf("Method '%s' not implemented in this GROUP_METHOD %s",
369 'removeMemberOf', GROUP_METHOD),
376 * GroupNone disables all Group funtionality
378 * All of the GroupNone functions return false or empty values to indicate failure or
379 * no results. Use GroupNone if group controls are not desired.
380 * @author Joby Walker <zorloc@imperium.org>
382 class GroupNone extends WikiGroup{
387 * Ignores the parameter provided.
388 * @param object $request The global WikiRequest object - ignored.
390 function GroupNone() {
391 $this->request = &$GLOBALS['request'];
396 * Determines if the current user is a member of a group.
398 * The group is ignored and false (not a member of the group) is returned.
399 * @param string $group Name of the group to check for membership (ignored).
400 * @return boolean True if user is a member, else false (always false).
402 function isMember($group){
403 if ($this->specialGroup($group)) {
404 return $this->isSpecialMember($group);
411 * Determines all of the groups of which the current user is a member.
413 * The group is ignored and an empty array (a member of no groups) is returned.
414 * @param string $group Name of the group to check for membership (ignored).
415 * @return array Array of groups to which the user belongs (always empty).
417 function getAllGroupsIn(){
422 * Determines all of the members of a particular group.
424 * The group is ignored and an empty array (a member of no groups) is returned.
425 * @param string $group Name of the group to check for membership (ignored).
426 * @return array Array of groups user belongs to (always empty).
428 function getMembersOf($group){
435 * GroupWikiPage provides group functionality via pages within the Wiki.
437 * GroupWikiPage is the Wiki way of managing a group. Every group will have
438 * a page. To modify the membership of the group, one only needs to edit the
439 * membership list on the page.
440 * @author Joby Walker <zorloc@imperium.org>
442 class GroupWikiPage extends WikiGroup{
447 * Initializes the three superclass instance variables
448 * @param object $request The global WikiRequest object.
450 function GroupWikiPage() {
451 $this->request = &$GLOBALS['request'];
452 $this->username = $this->_getUserName();
453 //$this->username = null;
454 $this->membership = array();
458 * Determines if the current user is a member of a group.
460 * To determine membership in a particular group, this method checks the
461 * superclass instance variable $membership to see if membership has
462 * already been determined. If not, then the group page is parsed to
463 * determine membership.
464 * @param string $group Name of the group to check for membership.
465 * @return boolean True if user is a member, else false.
467 function isMember($group){
468 if (isset($this->membership[$group])) {
469 return $this->membership[$group];
471 $group_page = $this->request->getPage($group);
472 if ($this->_inGroupPage($group_page)) {
473 $this->membership[$group] = true;
476 $this->membership[$group] = false;
477 // Let grouppages override certain defaults, such as members of admin
478 if ($this->specialGroup($group)) {
479 return $this->isSpecialMember($group);
485 * Private method to take a WikiDB_Page and parse to determine if the
486 * current_user is a member of the group.
487 * @param object $group_page WikiDB_Page object for the group's page
488 * @return boolean True if user is a member, else false.
491 function _inGroupPage($group_page, $strict=false){
492 $group_revision = $group_page->getCurrentRevision();
493 if ($group_revision->hasDefaultContents()) {
494 $group = $group_page->getName();
495 if ($strict) trigger_error(sprintf(_("Group page '%s' does not exist"), $group),
499 $contents = $group_revision->getContent();
500 $match = '/^\s*[\*\#]+\s*' . $this->username . '\s*$/';
501 foreach ($contents as $line){
502 if (preg_match($match, $line)) {
510 * Determines all of the groups of which the current user is a member.
512 * Checks the root Group page ('CategoryGroup') for the list of all groups,
513 * then checks each group to see if the current user is a member.
514 * @param string $group Name of the group to check for membership.
515 * @return array Array of groups to which the user belongs.
517 function getAllGroupsIn(){
518 $membership = array();
520 $specialgroups = $this->specialGroups();
521 foreach ($specialgroups as $group) {
522 $this->membership[$group] = $this->isSpecialMember($group);
525 $dbh = &$this->request->getDbh();
526 $master_page = $this->request->getPage(_("CategoryGroup"));
527 $master_list = $master_page->getLinks(true);
528 while ($group_page = $master_list->next()){
529 $group = $group_page->getName();
530 $this->membership[$group] = $this->_inGroupPage($group_page);
532 foreach ($this->membership as $g => $bool) {
533 if ($bool) $membership[] = $g;
539 * Determines all of the members of a particular group.
541 * Checks a group's page to return all the current members. Currently this
542 * method is disabled and triggers an error and returns an empty array.
543 * @param string $group Name of the group to get the full membership list of.
544 * @return array Array of usernames that have joined the group (always empty).
546 function getMembersOf($group){
547 if ($this->specialGroup($group))
548 return $this->getSpecialMembersOf($group);
550 trigger_error("GroupWikiPage::getMembersOf is not yet implimented",
554 * Waiting for a reliable way to check if a string is a username.
555 $request = $this->request;
557 $group_page = $request->getPage($group);
558 $group_revision = $group_page->getCurrentRevision();
559 if ($group_revision->hasDefaultContents()) {
560 trigger_error("Group $group does not exist", E_USER_WARNING);
563 $contents = $group_revision->getContent();
564 $match = '/^(\s*[\*\#]+\s*)(\w+)(\s*)$/';
566 foreach($contents as $line){
568 if(preg_match($match, $line, $matches)){
569 $members[] = $matches[2];
578 * GroupDb is configured by $DbAuthParams[] statements
583 class GroupDb extends WikiGroup {
585 var $_is_member, $_group_members, $_user_groups;
590 * @param object $request The global WikiRequest object. ignored
593 global $DBAuthParams, $DBParams;
594 $this->request = &$GLOBALS['request'];
595 $this->username = $this->_getUserName();
596 $this->membership = array();
598 if (empty($DBAuthParams['group_members']) or
599 empty($DBAuthParams['user_groups']) or
600 empty($DBAuthParams['is_member'])) {
601 trigger_error(_("No or not enough GROUP_DB SQL statements defined"),
603 return new GroupNone();
605 if (empty($this->user)) {
606 // use _PassUser::prepare instead
607 if (isa($this->request->getUser(),'_PassUser'))
608 $user =& $this->request->getUser();
610 $user = new _PassUser($this->username);
612 $user =& $this->user;
614 $this->_is_member = $user->prepare($DBAuthParams['is_member'],
615 array('userid','groupname'));
616 $this->_group_members = $user->prepare($DBAuthParams['group_members'],'groupname');
617 $this->_user_groups = $user->prepare($DBAuthParams['user_groups'],'userid');
618 $this->dbh = $user->_auth_dbi;
627 class GroupDb_PearDB extends GroupDb {
630 * Determines if the current user is a member of a database group.
632 * @param string $group Name of the group to check for membership.
633 * @return boolean True if user is a member, else false.
635 function isMember($group) {
636 if (isset($this->membership[$group])) {
637 return $this->membership[$group];
640 $db_result = $dbh->query(sprintf($this->_is_member,$dbh->quote($this->username),
641 $dbh->quote($group)));
642 if ($db_result->numRows() > 0) {
643 $this->membership[$group] = true;
646 $this->membership[$group] = false;
647 // Let override certain defaults, such as members of admin
648 if ($this->specialGroup($group))
649 return $this->isSpecialMember($group);
654 * Determines all of the groups of which the current user is a member.
656 * then checks each group to see if the current user is a member.
657 * @param string $group Name of the group to check for membership.
658 * @return array Array of groups to which the user belongs.
660 function getAllGroupsIn(){
661 $membership = array();
663 $specialgroups = $this->specialGroups();
664 foreach ($specialgroups as $group) {
665 if ($this->isMember($group)) {
666 $membership[] = $group;
670 $db_result = $dbh->query(sprintf($this->_user_groups,$dbh->quote($this->username)));
671 if ($db_result->numRows() > 0) {
672 while (list($group) = $db_result->fetchRow(DB_FETCHMODE_ORDERED)) {
673 $membership[] = $group;
674 $this->membership[$group] = true;
681 * Determines all of the members of a particular group.
683 * Checks a group's page to return all the current members. Currently this
684 * method is disabled and triggers an error and returns an empty array.
685 * @param string $group Name of the group to get the full membership list of.
686 * @return array Array of usernames that have joined the group.
688 function getMembersOf($group){
692 $db_result = $dbh->query(sprintf($this->_group_members,$dbh->quote($group)));
693 if ($db_result->numRows() > 0) {
694 while (list($userid) = $db_result->fetchRow(DB_FETCHMODE_ORDERED)) {
695 $members[] = $userid;
698 // add certain defaults, such as members of admin
699 if ($this->specialGroup($group))
700 $members = array_merge($members, $this->getSpecialMembersOf($group));
710 class GroupDb_ADODB extends GroupDb {
713 * Determines if the current user is a member of a database group.
715 * @param string $group Name of the group to check for membership.
716 * @return boolean True if user is a member, else false.
718 function isMember($group) {
719 if (isset($this->membership[$group])) {
720 return $this->membership[$group];
723 $rs = $dbh->Execute(sprintf($this->_is_member,$dbh->qstr($this->username),
724 $dbh->qstr($group)));
728 if ($rs->numRows() > 0) {
729 $this->membership[$group] = true;
734 $this->membership[$group] = false;
735 if ($this->specialGroup($group))
736 return $this->isSpecialMember($group);
742 * Determines all of the groups of which the current user is a member.
743 * then checks each group to see if the current user is a member.
745 * @param string $group Name of the group to check for membership.
746 * @return array Array of groups to which the user belongs.
748 function getAllGroupsIn(){
749 $membership = array();
751 $specialgroups = $this->specialGroups();
752 foreach ($specialgroups as $group) {
753 if ($this->isMember($group)) {
754 $membership[] = $group;
758 $rs = $dbh->Execute(sprintf($this->_user_groups, $dbh->qstr($this->username)));
759 if (!$rs->EOF and $rs->numRows() > 0) {
761 $group = reset($rs->fields);
762 $membership[] = $group;
763 $this->membership[$group] = true;
772 * Determines all of the members of a particular group.
774 * @param string $group Name of the group to get the full membership list of.
775 * @return array Array of usernames that have joined the group.
777 function getMembersOf($group){
780 $rs = $dbh->Execute(sprintf($this->_group_members,$dbh->qstr($group)));
781 if (!$rs->EOF and $rs->numRows() > 0) {
783 $members[] = reset($rs->fields);
788 // add certain defaults, such as members of admin
789 if ($this->specialGroup($group))
790 $members = array_merge($members, $this->getSpecialMembersOf($group));
796 * GroupFile is configured by AUTH_GROUP_FILE
797 * groupname: user1 user2 ...
801 class GroupFile extends WikiGroup {
806 * @param object $request The global WikiRequest object.
808 function GroupFile(){
809 $this->request = &$GLOBALS['request'];
810 $this->username = $this->_getUserName();
811 //$this->username = null;
812 $this->membership = array();
814 if (!defined('AUTH_GROUP_FILE')) {
815 trigger_error(_("AUTH_GROUP_FILE not defined"), E_USER_WARNING);
818 if (!file_exists(AUTH_GROUP_FILE)) {
819 trigger_error(sprintf(_("Cannot open AUTH_GROUP_FILE %s"), AUTH_GROUP_FILE),
823 require_once('lib/pear/File_Passwd.php');
824 $this->_file = new File_Passwd(AUTH_GROUP_FILE,false,AUTH_GROUP_FILE.".lock");
828 * Determines if the current user is a member of a group.
830 * To determine membership in a particular group, this method checks the
831 * superclass instance variable $membership to see if membership has
832 * already been determined. If not, then the group file is parsed to
833 * determine membership.
834 * @param string $group Name of the group to check for membership.
835 * @return boolean True if user is a member, else false.
837 function isMember($group) {
838 //$request = $this->request;
839 //$username = $this->username;
840 if (isset($this->membership[$group])) {
841 return $this->membership[$group];
844 if (is_array($this->_file->users)) {
845 foreach ($this->_file->users as $g => $u) {
846 $users = explode(' ',$u);
847 if (in_array($this->username,$users)) {
848 $this->membership[$group] = true;
853 $this->membership[$group] = false;
854 if ($this->specialGroup($group))
855 return $this->isSpecialMember($group);
860 * Determines all of the groups of which the current user is a member.
862 * then checks each group to see if the current user is a member.
863 * @param string $group Name of the group to check for membership.
864 * @return array Array of groups to which the user belongs.
866 function getAllGroupsIn(){
867 //$username = $this->_getUserName();
868 $membership = array();
870 $specialgroups = $this->specialGroups();
871 foreach ($specialgroups as $group) {
872 if ($this->isMember($group)) {
873 $this->membership[$group] = true;
874 $membership[] = $group;
877 if (is_array($this->_file->users)) {
878 foreach ($this->_file->users as $group => $u) {
879 $users = explode(' ',$u);
880 if (in_array($this->username,$users)) {
881 $this->membership[$group] = true;
882 $membership[] = $group;
890 * Determines all of the members of a particular group.
892 * Return all the current members.
893 * @param string $group Name of the group to get the full membership list of.
894 * @return array Array of usernames that have joined the group.
896 function getMembersOf($group){
898 if (!empty($this->_file->users[$group])) {
899 $members = explode(' ',$this->_file->users[$group]);
901 if ($this->specialGroup($group)) {
902 $members = array_merge($members, $this->getSpecialMembersOf($group));
909 * Ldap is configured in index.php
913 class GroupLdap extends WikiGroup {
918 * @param object $request The global WikiRequest object.
920 function GroupLdap(){
921 $this->request = &$GLOBALS['request'];
922 $this->username = $this->_getUserName();
923 $this->membership = array();
925 if (!defined("LDAP_AUTH_HOST")) {
926 trigger_error(_("LDAP_AUTH_HOST not defined"), E_USER_WARNING);
929 // We should ignore multithreaded environments, not generally windows.
931 if (! function_exists('ldap_connect') and (!isWindows() or isCGI())) {
932 // on MacOSX >= 4.3 you'll need PHP_SHLIB_SUFFIX instead.
933 dl("ldap".defined('PHP_SHLIB_SUFFIX') ? PHP_SHLIB_SUFFIX : DLL_EXT);
934 if (! function_exists('ldap_connect')) {
935 trigger_error(_("No LDAP in this PHP version"), E_USER_WARNING);
939 if (!defined("LDAP_BASE_DN"))
940 define("LDAP_BASE_DN",'');
941 $this->base_dn = LDAP_BASE_DN;
942 if (strstr("ou=",LDAP_BASE_DN))
943 $this->base_dn = preg_replace("/(ou=\w+,)?()/","\$2", LDAP_BASE_DN);
947 * Determines if the current user is a member of a group.
950 * @param string $group Name of the group to check for membership.
951 * @return boolean True if user is a member, else false.
953 function isMember($group) {
954 if ($this->specialGroup($group))
955 return $this->isSpecialMember($group);
957 if (isset($this->membership[$group])) {
958 return $this->membership[$group];
960 //$request = $this->request;
961 //$username = $this->_getUserName();
963 $this->membership[$group] = in_array($this->username,$this->getMembersOf($group));
964 return $this->membership[$group];
968 * Determines all of the groups of which the current user is a member.
970 * @param string $group Name of the group to check for membership.
971 * @return array Array of groups to which the user belongs.
973 function getAllGroupsIn(){
974 //$request = &$this->request;
975 //$username = $this->_getUserName();
976 $membership = array();
978 $specialgroups = $this->specialGroups();
979 foreach ($specialgroups as $group) {
980 if ($this->isMember($group)) {
981 $this->membership[$group] = true;
982 $membership[] = $group;
985 // must be a valid LDAP server, and username must not contain a wildcard
986 if ($ldap = ldap_connect(LDAP_AUTH_HOST) and !strstr($this->username,'*')) {
987 if (!empty($LDAP_SET_OPTION)) {
988 foreach ($LDAP_SET_OPTION as $key => $value) {
989 if (is_string($key) and defined($key))
990 $key = constant($key);
991 ldap_set_option($ldap,$key,$value);
995 if (defined('LDAP_AUTH_USER'))
996 if (defined('LDAP_AUTH_PASSWORD'))
997 // Windows Active Directory Server is strict
998 $r = @ldap_bind($ldap, LDAP_AUTH_USER, LDAP_AUTH_PASSWORD);
1000 $r = @ldap_bind($ldap, LDAP_AUTH_USER);
1002 $r = @ldap_bind($ldap); // this is an anonymous bind
1005 trigger_error(fmt("Unable to bind LDAP server %s", LDAP_AUTH_HOST),
1007 return $this->membership;
1010 $st_search = defined('LDAP_SEARCH_FIELD')
1011 ? LDAP_SEARCH_FIELD."=".$this->username
1012 : "uid=".$this->username;
1014 $sr = ldap_search($ldap, "ou=Users".($this->base_dn ? ",".$this->base_dn : ''), $st_search);
1017 return $this->membership;
1019 $info = ldap_get_entries($ldap, $sr);
1020 if (empty($info["count"])) {
1022 return $this->membership;
1024 for ($i = 0; $i < $info["count"]; $i++) {
1025 if ($info[$i]["gidnumber"]["count"]) {
1026 $gid = $info[$i]["gidnumber"][0];
1027 $sr2 = ldap_search($ldap, "ou=Groups".($this->base_dn ? ",".$this->base_dn : ''),"gidNumber=$gid");
1029 $info2 = ldap_get_entries($ldap, $sr2);
1030 if (!empty($info2["count"]))
1031 $membership[] = $info2[0]["cn"][0];
1036 trigger_error(fmt("Unable to connect to LDAP server %s", LDAP_AUTH_HOST),
1040 $this->membership = $membership;
1045 * Determines all of the members of a particular group.
1047 * Return all the members of the given group. LDAP just returns the gid of each user
1048 * @param string $group Name of the group to get the full membership list of.
1049 * @return array Array of usernames that have joined the group.
1051 function getMembersOf($group){
1052 if ($this->specialGroup($group))
1053 return $this->getSpecialMembersOf($group);
1056 if ($ldap = ldap_connect(LDAP_AUTH_HOST)) { // must be a valid LDAP server!
1057 $r = @ldap_bind($ldap); // this is an anonymous bind
1058 $sr = ldap_search($ldap, "ou=Groups,".$this->base_dn,"cn=$group");
1059 $info = ldap_get_entries($ldap, $sr);
1060 for ($i = 0; $i < $info["count"]; $i++) {
1061 $gid = $info[$i]["gidnumber"][0];
1062 //uid=* would be better probably
1063 $sr2 = ldap_search($ldap, "ou=Users,".$this->base_dn,"gidNumber=$gid");
1064 $info2 = ldap_get_entries($ldap, $sr2);
1065 for ($j = 0; $j < $info2["count"]; $j++) {
1066 $members[] = $info2[$j]["cn"][0];
1075 // $Log: not supported by cvs2svn $
1076 // Revision 1.36 2004/06/16 13:21:05 rurban
1077 // stabilize on failing ldap queries or bind
1079 // Revision 1.35 2004/06/16 12:08:25 rurban
1082 // Revision 1.34 2004/06/16 11:51:35 rurban
1083 // catch dl error on Windows
1085 // Revision 1.33 2004/06/15 10:40:35 rurban
1086 // minor WikiGroup cleanup: no request param, start of current user independency
1088 // Revision 1.32 2004/06/15 09:15:52 rurban
1089 // IMPORTANT: fixed passwd handling for passwords stored in prefs:
1090 // fix encrypted usage, actually store and retrieve them from db
1091 // fix bogologin with passwd set.
1092 // fix php crashes with call-time pass-by-reference (references wrongly used
1093 // in declaration AND call). This affected mainly Apache2 and IIS.
1094 // (Thanks to John Cole to detect this!)
1096 // Revision 1.31 2004/06/03 18:06:29 rurban
1097 // fix file locking issues (only needed on write)
1098 // fixed immediate LANG and THEME in-session updates if not stored in prefs
1099 // advanced editpage toolbars (search & replace broken)
1101 // Revision 1.30 2004/06/03 09:39:51 rurban
1102 // fix LDAP injection (wildcard in username) detected by Steve Christey, MITRE
1104 // Revision 1.29 2004/05/16 22:07:35 rurban
1105 // check more config-default and predefined constants
1106 // various PagePerm fixes:
1107 // fix default PagePerms, esp. edit and view for Bogo and Password users
1108 // implemented Creator and Owner
1109 // BOGOUSERS renamed to BOGOUSER
1110 // fixed syntax errors in signin.tmpl
1112 // Revision 1.28 2004/05/15 22:54:49 rurban
1113 // fixed important WikiDB bug with DEBUG > 0: wrong assertion
1114 // improved SetAcl (works) and PagePerms, some WikiGroup helpers.
1116 // Revision 1.27 2004/05/06 13:56:40 rurban
1117 // Enable the Administrators group, and add the WIKIPAGE group default root page.
1119 // Revision 1.26 2004/04/07 23:13:18 rurban
1120 // fixed pear/File_Passwd for Windows
1121 // fixed FilePassUser sessions (filehandle revive) and password update
1123 // Revision 1.25 2004/03/29 10:40:36 rurban
1124 // GroupDb_PearDB fetchmode fix
1126 // Revision 1.24 2004/03/14 16:26:22 rurban
1129 // Revision 1.23 2004/03/12 23:20:58 rurban
1130 // pref fixes (base64)
1132 // Revision 1.22 2004/03/12 15:48:07 rurban
1133 // fixed explodePageList: wrong sortby argument order in UnfoldSubpages
1134 // simplified lib/stdlib.php:explodePageList
1136 // Revision 1.21 2004/03/12 11:18:24 rurban
1137 // fixed ->membership chache
1139 // Revision 1.20 2004/03/12 10:47:30 rurban
1140 // fixed GroupDB for ADODB
1142 // Revision 1.19 2004/03/11 16:27:30 rurban
1143 // fixed GroupFile::getMembersOf for special groups
1144 // added authenticated bind for GroupLdap (Windows AD) as in WikiUserNew
1146 // Revision 1.18 2004/03/11 13:30:47 rurban
1147 // fixed File Auth for user and group
1148 // missing only getMembersOf(Authenticated Users),getMembersOf(Every),getMembersOf(Signed Users)
1150 // Revision 1.17 2004/03/10 15:38:48 rurban
1151 // store current user->page and ->action in session for WhoIsOnline
1152 // better WhoIsOnline icon
1153 // fixed WhoIsOnline warnings
1155 // Revision 1.15 2004/03/09 12:11:57 rurban
1156 // prevent from undefined DBAuthParams warning
1158 // Revision 1.14 2004/03/08 19:30:01 rurban
1159 // fixed Theme->getButtonURL
1160 // AllUsers uses now WikiGroup (also DB User and DB Pref users)
1161 // PageList fix for empty pagenames
1163 // Revision 1.13 2004/03/08 18:17:09 rurban
1164 // added more WikiGroup::getMembersOf methods, esp. for special groups
1165 // fixed $LDAP_SET_OPTIONS
1166 // fixed _AuthInfo group methods
1168 // Revision 1.12 2004/02/23 21:30:25 rurban
1169 // more PagePerm stuff: (working against 1.4.0)
1170 // ACL editing and simplification of ACL's to simple rwx------ string
1173 // Revision 1.11 2004/02/07 10:41:25 rurban
1174 // fixed auth from session (still double code but works)
1176 // fixed DbPassUser upgrade and policy=old
1179 // Revision 1.10 2004/02/03 09:45:39 rurban
1180 // LDAP cleanup, start of new Pref classes
1182 // Revision 1.9 2004/02/01 09:14:11 rurban
1183 // Started with Group_Ldap (not yet ready)
1184 // added new _AuthInfo plugin to help in auth problems (warning: may display passwords)
1185 // fixed some configurator vars
1186 // renamed LDAP_AUTH_SEARCH to LDAP_BASE_DN
1187 // changed PHPWIKI_VERSION from 1.3.8a to 1.3.8pre
1188 // USE_DB_SESSION defaults to true on SQL
1189 // changed GROUP_METHOD definition to string, not constants
1190 // changed sample user DBAuthParams from UPDATE to REPLACE to be able to
1191 // create users. (Not to be used with external databases generally, but
1192 // with the default internal user table)
1194 // fixed the IndexAsConfigProblem logic. this was flawed:
1195 // scripts which are the same virtual path defined their own lib/main call
1196 // (hmm, have to test this better, phpwiki.sf.net/demo works again)
1198 // Revision 1.8 2004/01/27 23:23:39 rurban
1199 // renamed ->Username => _userid for consistency
1200 // renamed mayCheckPassword => mayCheckPass
1201 // fixed recursion problem in WikiUserNew
1202 // fixed bogo login (but not quite 100% ready yet, password storage)
1204 // Revision 1.7 2004/01/26 16:52:40 rurban
1205 // added GroupDB and GroupFile classes
1207 // Revision 1.6 2003/12/07 19:29:11 carstenklapp
1208 // Code Housecleaning: fixed syntax errors. (php -l *.php)
1210 // Revision 1.5 2003/02/22 20:49:55 dairiki
1211 // Fixes for "Call-time pass by reference has been deprecated" errors.
1213 // Revision 1.4 2003/01/21 04:02:39 zorloc
1214 // Added Log entry and page footer.
1220 // c-basic-offset: 4
1221 // c-hanging-comment-ender-p: nil
1222 // indent-tabs-mode: nil