]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/WikiGroup.php
Remove ENABLE_USER_NEW (always true), remove lib/WikiUser.php
[SourceForge/phpwiki.git] / lib / WikiGroup.php
1 <?php
2
3 /*
4  * Copyright (C) 2003, 2004 $ThePhpWikiProgrammingTeam
5  * Copyright (C) 2010 Marc-Etienne Vargenau, Alcatel-Lucent
6  *
7  * This file is part of PhpWiki.
8  *
9  * PhpWiki is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * PhpWiki is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with PhpWiki; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23
24 if (!defined('GROUP_METHOD') or
25     !in_array(GROUP_METHOD,
26         array('NONE', 'WIKIPAGE', 'DB', 'FILE', 'LDAP'))
27 )
28     trigger_error(_("No or unsupported GROUP_METHOD defined"), E_USER_WARNING);
29
30 /* Special group names for ACL */
31 define('GROUP_EVERY', _("Every"));
32 define('GROUP_ANONYMOUS', _("Anonymous Users"));
33 define('GROUP_BOGOUSER', _("Bogo Users"));
34 define('GROUP_SIGNED', _("Signed Users"));
35 define('GROUP_AUTHENTICATED', _("Authenticated Users"));
36 define('GROUP_ADMIN', _("Administrators"));
37 define('GROUP_OWNER', _("Owner"));
38 define('GROUP_CREATOR', _("Creator"));
39
40 /**
41  * WikiGroup is an abstract class to provide the base functions for determining
42  * group membership for a specific user. Some functions are user independent.
43  *
44  * Limitation: For the current user only. This must be fixed to be able to query
45  * for membership of any user.
46  *
47  * WikiGroup is an abstract class with three functions:
48  * <ol><li />Provide the static method getGroup with will return the proper
49  *         subclass.
50  *     <li />Provide an interface for subclasses to implement.
51  *     <li />Provide fallover methods (with error msgs) if not impemented in subclass.
52  * </ol>
53  * Do not ever instantiate this class. Use: $group = &WikiGroup::getGroup();
54  * This will instantiate the proper subclass.
55  *
56  * @author Joby Walker <zorloc@imperium.org>
57  * @author Reini Urban
58  */
59 class WikiGroup
60 {
61     /** User name */
62     public $username = '';
63     /** User object if different from current user */
64     public $user;
65     /** The global WikiRequest object */
66     //public $request;
67     /** Array of groups $username is confirmed to belong to */
68     public $membership;
69     /** boolean if not the current user */
70     public $not_current = false;
71
72     /**
73      * Initializes a WikiGroup object which should never happen.  Use:
74      * $group = &WikiGroup::getGroup();
75      * @param bool $not_current
76      */
77     function WikiGroup($not_current = false)
78     {
79         $this->not_current = $not_current;
80         //$this->request =& $GLOBALS['request'];
81     }
82
83     /**
84      * Gets the current username from the internal user object
85      * and erases $this->membership if is different than
86      * the stored $this->username
87      * @return string Current username.
88      */
89     function _getUserName()
90     {
91         global $request;
92         $user = (!empty($this->user)) ? $this->user : $request->getUser();
93         $username = $user->getID();
94         if ($username != $this->username) {
95             $this->membership = array();
96             $this->username = $username;
97         }
98         if (!$this->not_current)
99             $this->user = $user;
100         return $username;
101     }
102
103     /**
104      * Static method to return the WikiGroup subclass used in this wiki.  Controlled
105      * by the constant GROUP_METHOD.
106      * @param  bool $not_current The global WikiRequest object.
107      * @return object Subclass of WikiGroup selected via GROUP_METHOD.
108      */
109     function getGroup($not_current = false)
110     {
111         switch (GROUP_METHOD) {
112             case "NONE":
113                 return new GroupNone($not_current);
114                 break;
115             case "WIKIPAGE":
116                 return new GroupWikiPage($not_current);
117                 break;
118             case "DB":
119                 if ($GLOBALS['DBParams']['dbtype'] == 'ADODB') {
120                     return new GroupDB_ADODB($not_current);
121                 } elseif ($GLOBALS['DBParams']['dbtype'] == 'SQL') {
122                     return new GroupDb_PearDB($not_current);
123                 } else {
124                     trigger_error("GROUP_METHOD = DB: Unsupported dbtype "
125                             . $GLOBALS['DBParams']['dbtype'],
126                         E_USER_ERROR);
127                 }
128                 break;
129             case "FILE":
130                 return new GroupFile($not_current);
131                 break;
132             case "LDAP":
133                 return new GroupLDAP($not_current);
134                 break;
135             default:
136                 trigger_error(_("No or unsupported GROUP_METHOD defined"), E_USER_WARNING);
137                 return new WikiGroup($not_current);
138         }
139     }
140
141     /** ACL PagePermissions will need those special groups based on the User status only.
142      *  translated
143      */
144     function specialGroup($group)
145     {
146         return in_array($group, $this->specialGroups());
147     }
148
149     /** untranslated */
150     function _specialGroup($group)
151     {
152         return in_array($group, $this->_specialGroups());
153     }
154
155     /** translated */
156     function specialGroups()
157     {
158         return array(
159             GROUP_EVERY,
160             GROUP_ANONYMOUS,
161             GROUP_BOGOUSER,
162             GROUP_SIGNED,
163             GROUP_AUTHENTICATED,
164             GROUP_ADMIN,
165             GROUP_OWNER,
166             GROUP_CREATOR);
167     }
168
169     /** untranslated */
170     function _specialGroups()
171     {
172         return array(
173             "_EVERY",
174             "_ANONYMOUS",
175             "_BOGOUSER",
176             "_SIGNED",
177             "_AUTHENTICATED",
178             "_ADMIN",
179             "_OWNER",
180             "_CREATOR");
181     }
182
183     /**
184      * Determines if the current user is a member of a group.
185      *
186      * This method is an abstraction.  The group is ignored, an error is sent, and
187      * false (not a member of the group) is returned.
188      * @param  string  $group Name of the group to check for membership (ignored).
189      * @return boolean True if user is a member, else false (always false).
190      */
191     function isMember($group)
192     {
193         if (isset($this->membership[$group]))
194             return $this->membership[$group];
195         if ($this->specialGroup($group)) {
196             return $this->isSpecialMember($group);
197         } else {
198             trigger_error(__sprintf("Method ā€œ%sā€ not implemented in this GROUP_METHOD %s",
199                     'isMember', GROUP_METHOD),
200                 E_USER_WARNING);
201         }
202         return false;
203     }
204
205     function isSpecialMember($group)
206     {
207         global $request;
208
209         if (isset($this->membership[$group]))
210             return $this->membership[$group];
211         $user = (!empty($this->user)) ? $this->user : $request->getUser();
212         switch ($group) {
213             case GROUP_EVERY:
214                 return $this->membership[$group] = true;
215             case GROUP_ANONYMOUS:
216                 return $this->membership[$group] = !$user->isSignedIn();
217             case GROUP_BOGOUSER:
218                 return $this->membership[$group] = (isa($user, '_BogoUser')
219                     and $user->_level >= WIKIAUTH_BOGO);
220             case GROUP_SIGNED:
221                 return $this->membership[$group] = $user->isSignedIn();
222             case GROUP_AUTHENTICATED:
223                 return $this->membership[$group] = $user->isAuthenticated();
224             case GROUP_ADMIN:
225                 return $this->membership[$group] = (isset($user->_level)
226                     and $user->_level == WIKIAUTH_ADMIN);
227             case GROUP_OWNER:
228             case GROUP_CREATOR:
229                 return false;
230             default:
231                 trigger_error(__sprintf("Undefined method %s for special group %s",
232                         'isMember', $group),
233                     E_USER_WARNING);
234         }
235         return false;
236     }
237
238     /**
239      * Determines all of the groups of which the current user is a member.
240      *
241      * This method is an abstraction.  An error is sent and an empty
242      * array is returned.
243      * @return array Array of groups to which the user belongs (always empty).
244      */
245     function getAllGroupsIn()
246     {
247         trigger_error(__sprintf("Method ā€œ%sā€ not implemented in this GROUP_METHOD %s",
248                 'getAllGroupsIn', GROUP_METHOD),
249             E_USER_WARNING);
250         return array();
251     }
252
253     function _allUsers()
254     {
255         static $result = array();
256         if (!empty($result))
257             return $result;
258
259         global $request;
260         /* WikiPage users: */
261         $dbh =& $request->_dbi;
262         $page_iter = $dbh->getAllPages();
263         $users = array();
264         while ($page = $page_iter->next()) {
265             if ($page->isUserPage())
266                 $users[] = $page->_pagename;
267         }
268
269         /* WikiDB users from prefs (not from users): */
270         $dbi = _PassUser::getAuthDbh();
271
272         if ($dbi and $dbh->getAuthParam('pref_select')) {
273             //get prefs table
274             $sql = preg_replace('/SELECT .+ FROM/i', 'SELECT userid FROM',
275                 $dbh->getAuthParam('pref_select'));
276             //don't strip WHERE, only the userid stuff.
277             $sql = preg_replace('/(WHERE.*?)\s+\w+\s*=\s*["\']\$userid[\'"]/i', '\\1 AND 1', $sql);
278             $sql = str_replace('WHERE AND 1', '', $sql);
279             if (isa($dbi, 'ADOConnection')) {
280                 $db_result = $dbi->Execute($sql);
281                 foreach ($db_result->GetArray() as $u) {
282                     $users = array_merge($users, array_values($u));
283                 }
284             } elseif (isa($dbi, 'DB_common')) { // PearDB
285                 $users = array_merge($users, $dbi->getCol($sql));
286             }
287         }
288
289         /* WikiDB users from users: */
290         // Fixme: don't strip WHERE, only the userid stuff.
291         if ($dbi and $dbh->getAuthParam('auth_user_exists')) {
292             //don't strip WHERE, only the userid stuff.
293             $sql = preg_replace('/(WHERE.*?)\s+\w+\s*=\s*["\']\$userid[\'"]/i', '\\1 AND 1',
294                 $dbh->getAuthParam('auth_user_exists'));
295             $sql = str_replace('WHERE AND 1', '', $sql);
296             if (isa($dbi, 'ADOConnection')) {
297                 $db_result = $dbi->Execute($sql);
298                 foreach ($db_result->GetArray() as $u) {
299                     $users = array_merge($users, array_values($u));
300                 }
301             } elseif (isa($dbi, 'DB_common')) {
302                 $users = array_merge($users, $dbi->getCol($sql));
303             }
304         }
305
306         // remove empty and duplicate users
307         $result = array();
308         foreach ($users as $u) {
309             if (empty($u) or in_array($u, $result)) continue;
310             $result[] = $u;
311         }
312         return $result;
313     }
314
315     /**
316      * Determines all of the members of a particular group.
317      *
318      * This method is an abstraction.  The group is ignored, an error is sent,
319      * and an empty array is returned
320      * @param  string $group Name of the group to get the full membership list of.
321      * @return array  Array of usernames that have joined the group (always empty).
322      */
323     function getMembersOf($group)
324     {
325         if ($this->specialGroup($group)) {
326             return $this->getSpecialMembersOf($group);
327         }
328         trigger_error(__sprintf("Method ā€œ%sā€ not implemented in this GROUP_METHOD %s",
329                 'getMembersOf', GROUP_METHOD),
330             E_USER_WARNING);
331         return array();
332     }
333
334     function getSpecialMembersOf($group)
335     {
336         //$request = &$this->request;
337         $all = $this->_allUsers();
338         $users = array();
339         switch ($group) {
340             case GROUP_EVERY:
341                 return $all;
342             case GROUP_ANONYMOUS:
343                 return $users;
344             case GROUP_BOGOUSER:
345                 foreach ($all as $u) {
346                     if (isWikiWord($u)) $users[] = $u;
347                 }
348                 return $users;
349             case GROUP_SIGNED:
350                 foreach ($all as $u) {
351                     $user = WikiUser($u);
352                     if ($user->isSignedIn()) $users[] = $u;
353                 }
354                 return $users;
355             case GROUP_AUTHENTICATED:
356                 foreach ($all as $u) {
357                     $user = WikiUser($u);
358                     if ($user->isAuthenticated()) $users[] = $u;
359                 }
360                 return $users;
361             case GROUP_ADMIN:
362                 foreach ($all as $u) {
363                     $user = WikiUser($u);
364                     if (isset($user->_level) and $user->_level == WIKIAUTH_ADMIN)
365                         $users[] = $u;
366                 }
367                 return $users;
368             case GROUP_OWNER:
369             case GROUP_CREATOR:
370                 // this could get complex so just return an empty array
371                 return false;
372             default:
373                 trigger_error(__sprintf("Unknown special group ā€œ%sā€", $group),
374                     E_USER_WARNING);
375         }
376     }
377
378     /**
379      * Add the current or specified user to a group.
380      *
381      * This method is an abstraction.  The group and user are ignored, an error
382      * is sent, and false (not added) is always returned.
383      * @param  string $group User added to this group.
384      * @param  string $user  Username to add to the group (default = current user).
385      * @return bool   On true user was added, false if not.
386      */
387     function setMemberOf($group, $user = '')
388     {
389         trigger_error(__sprintf("Method ā€œ%sā€ not implemented in this GROUP_METHOD %s",
390                 'setMemberOf', GROUP_METHOD),
391             E_USER_WARNING);
392         return false;
393     }
394
395     /**
396      * Remove the current or specified user to a group.
397      *
398      * This method is an abstraction.  The group and user are ignored, and error
399      * is sent, and false (not removed) is always returned.
400      * @param  string $group User removed from this group.
401      * @param  string $user  Username to remove from the group (default = current user).
402      * @return bool   On true user was removed, false if not.
403      */
404     function removeMemberOf($group, $user = '')
405     {
406         trigger_error(__sprintf("Method ā€œ%sā€ not implemented in this GROUP_METHOD %s",
407                 'removeMemberOf', GROUP_METHOD),
408             E_USER_WARNING);
409         return false;
410     }
411 }
412
413 /**
414  * GroupNone disables all Group funtionality
415  *
416  * All of the GroupNone functions return false or empty values to indicate failure or
417  * no results.  Use GroupNone if group controls are not desired.
418  * @author Joby Walker <zorloc@imperium.org>
419  */
420 class GroupNone extends WikiGroup
421 {
422     function __construct()
423     {
424         return;
425     }
426
427     /**
428      * Determines if the current user is a member of a group.
429      *
430      * The group is ignored and false (not a member of the group) is returned.
431      * @param  string  $group Name of the group to check for membership (ignored).
432      * @return boolean True if user is a member, else false (always false).
433      */
434     function isMember($group)
435     {
436         if ($this->specialGroup($group)) {
437             return $this->isSpecialMember($group);
438         } else {
439             return false;
440         }
441     }
442
443     /**
444      * Determines all of the groups of which the current user is a member.
445      *
446      * The group is ignored and an empty array (a member of no groups) is returned.
447      * @return array  Array of groups to which the user belongs (always empty).
448      */
449     function getAllGroupsIn()
450     {
451         return array();
452     }
453
454     /**
455      * Determines all of the members of a particular group.
456      *
457      * The group is ignored and an empty array (a member of no groups) is returned.
458      * @param  string $group Name of the group to check for membership (ignored).
459      * @return array  Array of groups user belongs to (always empty).
460      */
461     function getMembersOf($group)
462     {
463         return array();
464     }
465
466 }
467
468 /**
469  * GroupWikiPage provides group functionality via pages within the Wiki.
470  *
471  * GroupWikiPage is the Wiki way of managing a group.  Every group will have
472  * a page. To modify the membership of the group, one only needs to edit the
473  * membership list on the page.
474  * @author Joby Walker <zorloc@imperium.org>
475  */
476 class GroupWikiPage extends WikiGroup
477 {
478     /**
479      * Initializes the three superclass instance variables
480      */
481     function __construct()
482     {
483         //$this->request = &$GLOBALS['request'];
484         $this->username = $this->_getUserName();
485         //$this->username = null;
486         $this->membership = array();
487     }
488
489     /**
490      * Determines if the current user is a member of a group.
491      *
492      * To determine membership in a particular group, this method checks the
493      * superclass instance variable $membership to see if membership has
494      * already been determined.  If not, then the group page is parsed to
495      * determine membership.
496      * @param  string  $group Name of the group to check for membership.
497      * @return boolean True if user is a member, else false.
498      */
499     function isMember($group)
500     {
501         if (isset($this->membership[$group])) {
502             return $this->membership[$group];
503         }
504         global $request;
505         $group_page = $request->getPage($group);
506         if ($this->_inGroupPage($group_page)) {
507             $this->membership[$group] = true;
508             return true;
509         }
510         $this->membership[$group] = false;
511         // Let grouppages override certain defaults, such as members of admin
512         if ($this->specialGroup($group)) {
513             return $this->isSpecialMember($group);
514         }
515         return false;
516     }
517
518     /**
519      * Private method to take a WikiDB_Page and parse to determine if the
520      * current_user is a member of the group.
521      * @param object $group_page WikiDB_Page object for the group's page
522      * @param bool $strict
523      * @return boolean True if user is a member, else false.
524      */
525     private function _inGroupPage($group_page, $strict = false)
526     {
527         $group_revision = $group_page->getCurrentRevision();
528         if ($group_revision->hasDefaultContents()) {
529             $group = $group_page->getName();
530             if ($strict) trigger_error(sprintf(_("Group page ā€œ%sā€ does not exist"), $group),
531                 E_USER_WARNING);
532             return false;
533         }
534         $contents = $group_revision->getContent();
535         $match = '/^\s*[\*\#]+\s*\[?' . $this->username . '\]?(\s|$)/';
536         foreach ($contents as $line) {
537             if (preg_match($match, $line)) {
538                 return true;
539             }
540         }
541         return false;
542     }
543
544     /**
545      * Determines all of the groups of which the current user is a member.
546      *
547      * Checks the root Group page ('CategoryGroup') for the list of all groups,
548      * then checks each group to see if the current user is a member.
549      * @return array  Array of groups to which the user belongs.
550      */
551     function getAllGroupsIn()
552     {
553         $membership = array();
554
555         $specialgroups = $this->specialGroups();
556         foreach ($specialgroups as $group) {
557             $this->membership[$group] = $this->isSpecialMember($group);
558         }
559
560         global $request;
561         $dbh = &$request->_dbi;
562         $master_page = $request->getPage(CATEGORY_GROUP_PAGE);
563         $master_list = $master_page->getLinks(true);
564         while ($group_page = $master_list->next()) {
565             $group = $group_page->getName();
566             $this->membership[$group] = $this->_inGroupPage($group_page);
567         }
568         foreach ($this->membership as $g => $bool) {
569             if ($bool) $membership[] = $g;
570         }
571         return $membership;
572     }
573
574     /**
575      * Determines all of the members of a particular group.
576      *
577      * Checks a group's page to return all the current members.  Currently this
578      * method is disabled and triggers an error and returns an empty array.
579      * @param  string $group Name of the group to get the full membership list of.
580      * @return array  Array of usernames that have joined the group (always empty).
581      */
582     function getMembersOf($group)
583     {
584         if ($this->specialGroup($group))
585             return $this->getSpecialMembersOf($group);
586
587         $group_page = $GLOBALS['request']->getPage($group);
588         $group_revision = $group_page->getCurrentRevision();
589         if ($group_revision->hasDefaultContents()) {
590             trigger_error(sprintf(_("Group %s does not exist"), $group), E_USER_WARNING);
591             return array();
592         }
593         $contents = $group_revision->getContent();
594         // This is not really a reliable way to check if a string is a username. But better than nothing.
595         $match = '/^(\s*[\*\#]+\s*\[?)(\w+)(\]?\s*)$/';
596         $members = array();
597         foreach ($contents as $line) {
598             if (preg_match($match, $line, $matches)) {
599                 $members[] = $matches[2];
600             }
601         }
602         return $members;
603     }
604 }
605
606 /**
607  * GroupDb is configured by $DbAuthParams[] statements
608  *
609  * Fixme: adodb
610  * @author ReiniUrban
611  */
612 class GroupDb extends WikiGroup
613 {
614
615     public $_is_member, $_group_members, $_user_groups;
616
617     function __construct()
618     {
619         global $DBAuthParams, $DBParams;
620         //$this->request = &$GLOBALS['request'];
621         $this->username = $this->_getUserName();
622         $this->membership = array();
623
624         if (empty($DBAuthParams['group_members']) or
625             empty($DBAuthParams['user_groups']) or
626             empty($DBAuthParams['is_member'])
627         ) {
628             trigger_error(_("No or not enough GROUP_DB SQL statements defined"),
629                 E_USER_WARNING);
630             return new GroupNone();
631         }
632         if (empty($this->user)) {
633             // use _PassUser::prepare instead
634             if (isa($request->getUser(), '_PassUser'))
635                 $user = $request->getUser();
636             else
637                 $user = new _PassUser($this->username);
638         } elseif (!isa($this->user, '_PassUser')) {
639             $user = new _PassUser($this->username);
640         } else {
641             $user =& $this->user;
642         }
643         if (isa($this->user, '_PassUser')) { // TODO: safety by Charles Corrigan
644             $this->_is_member = $user->prepare($DBAuthParams['is_member'],
645                 array('userid', 'groupname'));
646             $this->_group_members = $user->prepare($DBAuthParams['group_members'], 'groupname');
647             $this->_user_groups = $user->prepare($DBAuthParams['user_groups'], 'userid');
648             $this->dbh = $user->_auth_dbi;
649         }
650     }
651 }
652
653 /**
654  * PearDB methods
655  *
656  * @author ReiniUrban
657  */
658 class GroupDb_PearDB extends GroupDb
659 {
660
661     /**
662      * Determines if the current user is a member of a database group.
663      *
664      * @param  string  $group Name of the group to check for membership.
665      * @return boolean True if user is a member, else false.
666      */
667     function isMember($group)
668     {
669         if (isset($this->membership[$group])) {
670             return $this->membership[$group];
671         }
672         $dbh = & $this->dbh;
673         $db_result = $dbh->query(sprintf($this->_is_member,
674             $dbh->quote($this->username),
675             $dbh->quote($group)));
676         if ($db_result->numRows() > 0) {
677             $this->membership[$group] = true;
678             return true;
679         }
680         $this->membership[$group] = false;
681         // Let override certain defaults, such as members of admin
682         if ($this->specialGroup($group))
683             return $this->isSpecialMember($group);
684         return false;
685     }
686
687     /**
688      * Determines all of the groups of which the current user is a member.
689      *
690      * then checks each group to see if the current user is a member.
691      * @return array  Array of groups to which the user belongs.
692      */
693     function getAllGroupsIn()
694     {
695         $membership = array();
696
697         $dbh = & $this->dbh;
698         $db_result = $dbh->query(sprintf($this->_user_groups, $dbh->quote($this->username)));
699         if ($db_result->numRows() > 0) {
700             while (list($group) = $db_result->fetchRow(DB_FETCHMODE_ORDERED)) {
701                 $membership[] = $group;
702                 $this->membership[$group] = true;
703             }
704         }
705
706         $specialgroups = $this->specialGroups();
707         foreach ($specialgroups as $group) {
708             if ($this->isMember($group)) {
709                 $membership[] = $group;
710             }
711         }
712         return $membership;
713     }
714
715     /**
716      * Determines all of the members of a particular group.
717      *
718      * Checks a group's page to return all the current members.  Currently this
719      * method is disabled and triggers an error and returns an empty array.
720      * @param  string $group Name of the group to get the full membership list of.
721      * @return array  Array of usernames that have joined the group.
722      */
723     function getMembersOf($group)
724     {
725
726         $members = array();
727         $dbh = & $this->dbh;
728         $db_result = $dbh->query(sprintf($this->_group_members, $dbh->quote($group)));
729         if ($db_result->numRows() > 0) {
730             while (list($userid) = $db_result->fetchRow(DB_FETCHMODE_ORDERED)) {
731                 $members[] = $userid;
732             }
733         }
734         // add certain defaults, such as members of admin
735         if ($this->specialGroup($group))
736             $members = array_merge($members, $this->getSpecialMembersOf($group));
737         return $members;
738     }
739 }
740
741 /**
742  * ADODB methods
743  *
744  * @author ReiniUrban
745  */
746 class GroupDb_ADODB extends GroupDb
747 {
748
749     /**
750      * Determines if the current user is a member of a database group.
751      *
752      * @param  string  $group Name of the group to check for membership.
753      * @return boolean True if user is a member, else false.
754      */
755     function isMember($group)
756     {
757         if (isset($this->membership[$group])) {
758             return $this->membership[$group];
759         }
760         $dbh = & $this->dbh;
761         $rs = $dbh->Execute(sprintf($this->_is_member, $dbh->qstr($this->username),
762             $dbh->qstr($group)));
763         if ($rs->EOF) {
764             $rs->Close();
765         } else {
766             if ($rs->numRows() > 0) {
767                 $this->membership[$group] = true;
768                 $rs->Close();
769                 return true;
770             }
771         }
772         $this->membership[$group] = false;
773         if ($this->specialGroup($group))
774             return $this->isSpecialMember($group);
775
776         return false;
777     }
778
779     /**
780      * Determines all of the groups of which the current user is a member.
781      * then checks each group to see if the current user is a member.
782      *
783      * @return array  Array of groups to which the user belongs.
784      */
785     function getAllGroupsIn()
786     {
787         $membership = array();
788
789         $dbh = & $this->dbh;
790         $rs = $dbh->Execute(sprintf($this->_user_groups, $dbh->qstr($this->username)));
791         if (!$rs->EOF and $rs->numRows() > 0) {
792             while (!$rs->EOF) {
793                 $group = reset($rs->fields);
794                 $membership[] = $group;
795                 $this->membership[$group] = true;
796                 $rs->MoveNext();
797             }
798         }
799         $rs->Close();
800
801         $specialgroups = $this->specialGroups();
802         foreach ($specialgroups as $group) {
803             if ($this->isMember($group)) {
804                 $membership[] = $group;
805             }
806         }
807         return $membership;
808     }
809
810     /**
811      * Determines all of the members of a particular group.
812      *
813      * @param  string $group Name of the group to get the full membership list of.
814      * @return array  Array of usernames that have joined the group.
815      */
816     function getMembersOf($group)
817     {
818         $members = array();
819         $dbh = & $this->dbh;
820         $rs = $dbh->Execute(sprintf($this->_group_members, $dbh->qstr($group)));
821         if (!$rs->EOF and $rs->numRows() > 0) {
822             while (!$rs->EOF) {
823                 $members[] = reset($rs->fields);
824                 $rs->MoveNext();
825             }
826         }
827         $rs->Close();
828         // add certain defaults, such as members of admin
829         if ($this->specialGroup($group))
830             $members = array_merge($members, $this->getSpecialMembersOf($group));
831         return $members;
832     }
833 }
834
835 /**
836  * GroupFile is configured by AUTH_GROUP_FILE
837  * groupname: user1 user2 ...
838  *
839  * @author ReiniUrban
840  */
841 class GroupFile extends WikiGroup
842 {
843     function __construct()
844     {
845         //$this->request = &$GLOBALS['request'];
846         $this->username = $this->_getUserName();
847         //$this->username = null;
848         $this->membership = array();
849
850         if (!defined('AUTH_GROUP_FILE')) {
851             trigger_error(sprintf(_("%s: not defined"), "AUTH_GROUP_FILE"),
852                 E_USER_WARNING);
853             return false;
854         }
855         if (!file_exists(AUTH_GROUP_FILE)) {
856             trigger_error(sprintf(_("Cannot open AUTH_GROUP_FILE %s"), AUTH_GROUP_FILE),
857                 E_USER_WARNING);
858             return false;
859         }
860         require_once 'lib/pear/File_Passwd.php';
861         $this->_file = new File_Passwd(AUTH_GROUP_FILE, false, AUTH_GROUP_FILE . ".lock");
862     }
863
864     /**
865      * Determines if the current user is a member of a group.
866      *
867      * To determine membership in a particular group, this method checks the
868      * superclass instance variable $membership to see if membership has
869      * already been determined.  If not, then the group file is parsed to
870      * determine membership.
871      * @param  string  $group Name of the group to check for membership.
872      * @return boolean True if user is a member, else false.
873      */
874     function isMember($group)
875     {
876         //$request = $this->request;
877         //$username = $this->username;
878         if (isset($this->membership[$group])) {
879             return $this->membership[$group];
880         }
881
882         if (is_array($this->_file->users)) {
883             foreach ($this->_file->users as $g => $u) {
884                 $users = explode(' ', $u);
885                 if (in_array($this->username, $users)) {
886                     $this->membership[$group] = true;
887                     return true;
888                 }
889             }
890         }
891         $this->membership[$group] = false;
892         if ($this->specialGroup($group))
893             return $this->isSpecialMember($group);
894         return false;
895     }
896
897     /**
898      * Determines all of the groups of which the current user is a member.
899      *
900      * then checks each group to see if the current user is a member.
901      * @return array  Array of groups to which the user belongs.
902      */
903     function getAllGroupsIn()
904     {
905         //$username = $this->_getUserName();
906         $membership = array();
907
908         if (is_array($this->_file->users)) {
909             foreach ($this->_file->users as $group => $u) {
910                 $users = explode(' ', $u);
911                 if (in_array($this->username, $users)) {
912                     $this->membership[$group] = true;
913                     $membership[] = $group;
914                 }
915             }
916         }
917
918         $specialgroups = $this->specialGroups();
919         foreach ($specialgroups as $group) {
920             if ($this->isMember($group)) {
921                 $this->membership[$group] = true;
922                 $membership[] = $group;
923             }
924         }
925         return $membership;
926     }
927
928     /**
929      * Determines all of the members of a particular group.
930      *
931      * Return all the current members.
932      * @param  string $group Name of the group to get the full membership list of.
933      * @return array  Array of usernames that have joined the group.
934      */
935     function getMembersOf($group)
936     {
937         $members = array();
938         if (!empty($this->_file->users[$group])) {
939             $members = explode(' ', $this->_file->users[$group]);
940         }
941         if ($this->specialGroup($group)) {
942             $members = array_merge($members, $this->getSpecialMembersOf($group));
943         }
944         return $members;
945     }
946 }
947
948 /**
949  * Ldap is configured in index.php
950  *
951  * @author ReiniUrban
952  */
953 class GroupLdap extends WikiGroup
954 {
955     function __construct()
956     {
957         //$this->request = &$GLOBALS['request'];
958         $this->username = $this->_getUserName();
959         $this->membership = array();
960
961         if (!defined("LDAP_AUTH_HOST")) {
962             trigger_error(sprintf(_("%s not defined"), "LDAP_AUTH_HOST"),
963                 E_USER_WARNING);
964             return;
965         }
966         // We should ignore multithreaded environments, not generally windows.
967         // CGI does work.
968         if (!function_exists('ldap_connect') and (!isWindows() or isCGI())) {
969             // on MacOSX >= 4.3 you'll need PHP_SHLIB_SUFFIX instead.
970             dl("ldap" . defined('PHP_SHLIB_SUFFIX') ? PHP_SHLIB_SUFFIX : DLL_EXT);
971             if (!function_exists('ldap_connect')) {
972                 trigger_error(_("No LDAP in this PHP version"), E_USER_WARNING);
973                 return;
974             }
975         }
976         if (!defined("LDAP_BASE_DN"))
977             define("LDAP_BASE_DN", '');
978         $this->base_dn = LDAP_BASE_DN;
979         // if no users ou (organizational unit) is defined,
980         // then take out the ou= from the base_dn (if exists) and append a default
981         // from users and group
982         if (!LDAP_OU_USERS)
983             if (strstr(LDAP_BASE_DN, "ou="))
984                 $this->base_dn = preg_replace("/(ou=\w+,)?()/", "\$2", LDAP_BASE_DN);
985
986         if (!isset($this->user) or !isa($this->user, '_LDAPPassUser'))
987             $this->_user = new _LDAPPassUser('LdapGroupTest'); // to have a valid username
988         else
989             $this->_user =& $this->user;
990     }
991
992     /**
993      * Determines if the current user is a member of a group.
994      * Not ready yet!
995      *
996      * @param  string  $group Name of the group to check for membership.
997      * @return boolean True if user is a member, else false.
998      */
999     function isMember($group)
1000     {
1001         if (isset($this->membership[$group])) {
1002             return $this->membership[$group];
1003         }
1004         //$request = $this->request;
1005         //$username = $this->_getUserName();
1006         $this->membership[$group] = in_array($this->username, $this->getMembersOf($group));
1007         if ($this->membership[$group])
1008             return true;
1009         if ($this->specialGroup($group))
1010             return $this->isSpecialMember($group);
1011     }
1012
1013     /**
1014      * Determines all of the groups of which the current user is a member.
1015      *
1016      * @return array  Array of groups to which the user belongs.
1017      */
1018     function getAllGroupsIn()
1019     {
1020         $membership = array();
1021
1022         $specialgroups = $this->specialGroups();
1023         foreach ($specialgroups as $group) {
1024             if ($this->isMember($group)) {
1025                 $this->membership[$group] = true;
1026                 $membership[] = $group;
1027             }
1028         }
1029
1030         // must be a valid LDAP server, and username must not contain a wildcard
1031         if ($ldap = $this->_user->_init()) {
1032             $st_search = LDAP_SEARCH_FIELD ? LDAP_SEARCH_FIELD . "=" . $this->username
1033                 : "uid=" . $this->username;
1034             $sr = ldap_search($ldap, (LDAP_OU_USERS ? LDAP_OU_USERS : "ou=Users")
1035                 . ($this->base_dn ? "," . $this->base_dn : ''),
1036                 $st_search);
1037             if (!$sr) {
1038                 $this->_user->_free();
1039                 return $this->membership;
1040             }
1041             $info = ldap_get_entries($ldap, $sr);
1042             if (empty($info["count"])) {
1043                 $this->_user->_free();
1044                 return $this->membership;
1045             }
1046             for ($i = 0; $i < $info["count"]; $i++) {
1047                 if ($info[$i]["gidNumber"]["count"]) {
1048                     $gid = $info[$i]["gidnumber"][0];
1049                     $sr2 = ldap_search($ldap, (LDAP_OU_GROUP ? LDAP_OU_GROUP : "ou=Groups")
1050                         . ($this->base_dn ? "," . $this->base_dn : ''),
1051                         "gidNumber=$gid");
1052                     if ($sr2) {
1053                         $info2 = ldap_get_entries($ldap, $sr2);
1054                         if (!empty($info2["count"]))
1055                             $membership[] = $info2[0]["cn"][0];
1056                     }
1057                 }
1058             }
1059         } else {
1060             trigger_error(fmt("Unable to connect to LDAP server %s", LDAP_AUTH_HOST),
1061                 E_USER_WARNING);
1062         }
1063         $this->_user->_free();
1064         //ldap_close($ldap);
1065         $this->membership = $membership;
1066         return $membership;
1067     }
1068
1069     /**
1070      * Determines all of the members of a particular group.
1071      *
1072      * Return all the members of the given group. LDAP just returns the gid of each user
1073      * @param  string $group Name of the group to get the full membership list of.
1074      * @return array  Array of usernames that have joined the group.
1075      */
1076     function getMembersOf($group)
1077     {
1078         $members = array();
1079         if ($ldap = $this->_user->_init()) {
1080             $base_dn = (LDAP_OU_GROUP ? LDAP_OU_GROUP : "ou=Groups")
1081                 . ($this->base_dn ? "," . $this->base_dn : '');
1082             $sr = ldap_search($ldap, $base_dn, "cn=$group");
1083             if ($sr)
1084                 $info = ldap_get_entries($ldap, $sr);
1085             else {
1086                 $info = array('count' => 0);
1087                 trigger_error("LDAP_SEARCH: base=\"$base_dn\" \"(cn=$group)\" failed", E_USER_NOTICE);
1088             }
1089             $base_dn = (LDAP_OU_USERS ? LDAP_OU_USERS : "ou=Users")
1090                 . ($this->base_dn ? "," . $this->base_dn : '');
1091             for ($i = 0; $i < $info["count"]; $i++) {
1092                 $gid = $info[$i]["gidNumber"][0];
1093                 //uid=* would be better probably
1094                 $sr2 = ldap_search($ldap, $base_dn, "gidNumber=$gid");
1095                 if ($sr2) {
1096                     $info2 = ldap_get_entries($ldap, $sr2);
1097                     for ($j = 0; $j < $info2["count"]; $j++) {
1098                         $members[] = $info2[$j]["cn"][0];
1099                     }
1100                 } else {
1101                     trigger_error("LDAP_SEARCH: base=\"$base_dn\" \"(gidNumber=$gid)\" failed", E_USER_NOTICE);
1102                 }
1103             }
1104         }
1105         $this->_user->_free();
1106         //ldap_close($ldap);
1107
1108         if ($this->specialGroup($group)) {
1109             $members = array_merge($members, $this->getSpecialMembersOf($group));
1110         }
1111         return $members;
1112     }
1113 }
1114
1115 // Local Variables:
1116 // mode: php
1117 // tab-width: 8
1118 // c-basic-offset: 4
1119 // c-hanging-comment-ender-p: nil
1120 // indent-tabs-mode: nil
1121 // End: