5 * Class to interact with the system
8 * @author Christian Bayle
11 * This file is part of GForge.
12 * It's OO version of ancient ldap.php
14 * GForge is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * GForge is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with GForge; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 require_once('common/include/account.php');
29 require_once('common/include/system/UNIX.class.php');
31 class LDAP extends UNIX {
46 * asciize() - Replace non-ascii characters with question marks
48 * LDAP expects utf-8 encoded character string. Since we cannot
49 * know which encoding 8-bit characters in database use, we
50 * just replace them with question marks.
52 * @param string UTF-8 encoded character string.
53 * @return string which contains only ascii characters
55 function asciize($str) {
57 // LDAP don't allow empty strings for some attributes
61 return ereg_replace("[\x80-\xff]","?",$str);
65 * Wrappers for PHP LDAP functions
69 * gfLdapConnect() - Connect to the LDAP server
71 * @returns true on success/false on error
74 function gfLdapConnect() {
75 global $sys_ldap_host,$sys_ldap_port;
76 global $sys_ldap_bind_dn,$sys_ldap_passwd,$ldap_conn,$sys_ldap_version;
80 $ldap_conn = @ldap_connect($sys_ldap_host,$sys_ldap_port);
82 $this->setError('ERROR: Cannot connect to LDAP server<br />');
85 if ($sys_ldap_version) {
86 ldap_set_option($ldap_conn, LDAP_OPT_PROTOCOL_VERSION, $sys_ldap_version);
88 ldap_bind($ldap_conn,$sys_ldap_bind_dn,$sys_ldap_passwd);
94 * gfLdapAdd() - Wrapper for ldap_add()
100 function gfLdapAdd($dn, $entry) {
102 return @ldap_add($ldap_conn,$dn,$entry);
106 * gfLdapDelete() - Wrapper for ldap_delete()
111 function gfLdapDelete($dn) {
113 return @ldap_delete($ldap_conn,$dn);
117 * gfLdapModify() - Wrapper for ldap_modify()
120 * @param string entry
123 function gfLdapModify($dn,$entry) {
125 return @ldap_modify($ldap_conn,$dn,$entry);
129 * gfLdapModifyIfExists() - Wrapper for ldap_modify()
130 * works like gfLdapModify, but returns true if the LDAP entry does not exist
133 * @param string entry
136 function gfLdapModifyIfExists($dn,$entry) {
137 $res = $this->gfLdapModify($dn,$entry);
141 $err = ldap_errno ($ldap_conn) ;
151 * gfLdapModAdd() - Wrapper for ldap_mod_add()
154 * @param string entry
157 function gfLdapModAdd($dn,$entry) {
159 return @ldap_mod_add($ldap_conn,$dn,$entry);
163 * gfLdapModDel() - Wrapper for ldap_mod_del()
166 * @param string entry
169 function gfLdapModDel($dn,$entry) {
171 return @ldap_mod_del($ldap_conn,$dn,$entry);
175 * gfLdapRead() - Wrapper for ldap_read()
178 * @param string filter
182 function gfLdapRead($dn,$filter,$attrs=0) {
184 return @ldap_read($ldap_conn,$dn,$filter,$attrs);
188 * gfLdapError() - Wrapper for ldap_error()
193 function gfLdapError() {
195 return ldap_error($ldap_conn);
199 * gfLdapErrno() - Wrapper for ldap_errno()
204 function gfLdapErrno() {
206 return ldap_errno($ldap_conn);
210 * gfLdapAlreadyExists()
212 function gfLdapAlreadyExists() {
214 return ldap_errno($ldap_conn)==20;
218 * gfLdapDoesNotExist()
220 function gfLdapDoesNotExist() {
222 return ldap_errno($ldap_conn)==16;
226 * User management functions
230 * sysCheckUser() - Check for the existence of a user
232 * @param int The user ID of the user to check
233 * @returns true on success/false on error
236 function sysCheckUser($user_id) {
237 $user =& user_get_object($user_id);
241 return $this->gfLdapcheck_user_by_name($user->getUnixName());
245 * gfLdapcheck_user_by_name() - Check for a user by the username
247 * @param string The username
248 * @returns true on success/false on error
251 function gfLdapcheck_user_by_name($user_name) {
253 global $sys_ldap_base_dn;
255 if (!$this->gfLdapConnect()) {
259 $dn = 'uid='.$user_name.',ou=People,'.$sys_ldap_base_dn;
260 $res = $this->gfLdapRead($dn,"objectClass=*",array("uid"));
262 ldap_free_result($res);
270 * sysCreateUser() - Create a user
272 * @param int The user ID of the user to create
273 * @returns The return status of gfLdapcreate_user_from_object()
276 function sysCreateUser($user_id) {
277 // Check even if the user shouldn't exist
278 // It can be created by a cron
279 if (!$this->sysCheckUser($user_id)){
280 $user = &user_get_object($user_id);
281 return $this->gfLdapcreate_user_from_object($user);
287 * sysCheckCreateUser() - Check that a user has been created
289 * @param int The ID of the user to check
290 * @returns true on success/false on error
293 function sysCheckCreateUser($user_id) {
294 if (!$this->sysCheckUser($user_id)){
295 $user = &user_get_object($user_id);
296 return $this->gfLdapcreate_user_from_object($user);
302 * gfLdapcreate_user_from_object() - Create a user from information contained within an object
304 * @param object The user object
305 * @returns true on success/false on error
308 function gfLdapcreate_user_from_object(&$user) {
309 global $sys_ldap_base_dn;
310 if (!$this->gfLdapConnect()) {
313 $dn = 'uid='.$user->getUnixName().',ou=People,'.$sys_ldap_base_dn;
314 $entry['objectClass'][0]='top';
315 $entry['objectClass'][1]='account';
316 $entry['objectClass'][2]='posixAccount';
317 $entry['objectClass'][3]='shadowAccount';
318 $entry['objectClass'][4]='debGforgeAccount';
319 $entry['uid']=$user->getUnixName();
320 $entry['cn']=$this->asciize($user->getRealName());
321 $entry['gecos']=$this->asciize($user->getRealName());
322 $entry['userPassword']='{crypt}'.$user->getUnixPasswd();
323 $entry['homeDirectory'] = account_user_homedir($user->getUnixName());
324 $entry['loginShell']=$user->getShell();
325 $entry['debGforgeCvsShell']="/bin/cvssh"; // unless explicitly set otherwise, developer has write access
326 $entry['debGforgeForwardEmail']=$user->getEmail();
327 $entry['uidNumber']=$this->getUnixUID();
328 $entry['gidNumber']=$this->getUnixGID(); // users as in debian backend
329 $entry['shadowLastChange']=1; // We don't have expiration, so any non-0
330 $entry['shadowMax']=99999;
331 $entry['shadowWarning']=7;
333 if (!$this->gfLdapAdd($dn,$entry)) {
334 $this->setError("ERROR: cannot add LDAP user entry '".
335 $user->getUnixName()."': ".$this->gfLdapError()."<br />");
342 * gfLdapCreateUserFromProps() - Creates an LDAP user from
344 * @param string The username
346 * @param string The encrypted password
347 * @returns true on success/false on error
350 function gfLdapCreateUserFromProps($username, $cn, $crypt_pw,
351 $shell, $cvsshell, $uid, $gid, $email) {
352 global $sys_ldap_base_dn;
353 if (!$this->gfLdapConnect()) {
356 $dn = 'uid='.$username.',ou=People,'.$sys_ldap_base_dn;
357 $entry['objectClass'][0]='top';
358 $entry['objectClass'][1]='account';
359 $entry['objectClass'][2]='posixAccount';
360 $entry['objectClass'][3]='shadowAccount';
361 $entry['objectClass'][4]='debGforgeAccount';
362 $entry['uid']=$username;
363 $entry['cn']=$this->asciize($cn);
364 $entry['gecos']=$this->asciize($cn);
365 $entry['userPassword']='{crypt}'.$crypt_pw;
366 $entry['homeDirectory'] = account_user_homedir($username);
367 $entry['loginShell']=$shell;
368 $entry['debGforgeCvsShell']=$cvsshell;
369 $entry['debGforgeForwardEmail']=$email;
370 $entry['uidNumber']=$uid;
371 $entry['gidNumber']=$gid;
372 $entry['shadowLastChange']=1;
373 $entry['shadowMax']=99999;
374 $entry['shadowWarning']=7;
376 if (!$this->gfLdapAdd($dn,$entry)) {
377 $this->setError("ERROR: cannot add LDAP user entry '".
378 $username."': ".$this->gfLdapError()."<br />");
385 * sysRemoveUser() - Remove an LDAP user
387 * @param int The user ID of the user to remove
388 * @returns true on success/false on failure
391 function sysRemoveUser($user_id) {
392 global $sys_ldap_base_dn;
394 $user = &user_get_object($user_id);
395 if (!$this->gfLdapConnect()) {
398 $dn = 'uid='.$user->getUnixName().',ou=People,'.$sys_ldap_base_dn;
400 if (!$this->gfLdapDelete($dn)) {
401 $this->setError("ERROR: cannot delete LDAP user entry '".
402 $user->getUnixName()."': ".$this->gfLdapError()."<br />");
409 * sysUserSetAttribute() - Set an attribute for a user
411 * @param int The user ID
412 * @param string The attribute to set
413 * @param string The new value of the attribute
414 * @returns true on success/false on error
417 function sysUserSetAttribute($user_id,$attr,$value) {
418 global $sys_ldap_base_dn;
420 $user = &user_get_object($user_id);
421 if (!$this->gfLdapConnect()) {
424 $dn = 'uid='.$user->getUnixName().',ou=People,'.$sys_ldap_base_dn;
425 $entry[$attr]=$value;
427 if (!$this->gfLdapModifyIfExists($dn, $entry)) {
428 $this->setError("ERROR: cannot change LDAP attribute '$attr' for user '".
429 $user->getUnixName()."': ".$this->gfLdapError()."<br />");
436 * Group management functions
440 * sysCheckGroup() - Check for the existence of a group
442 * @param int The ID of the group to check
443 * @returns true on success/false on error
446 function sysCheckGroup($group_id) {
448 global $sys_ldap_base_dn;
450 $group = &group_get_object($group_id);
452 $this->setError("ERROR: Cannot find group [$group_id]<br />");
455 if (!$this->gfLdapConnect()) {
458 $dn = 'cn='.$group->getUnixName().',ou=Group,'.$sys_ldap_base_dn;
459 $res=$this->gfLdapRead($dn, "objectClass=*", array("cn"));
461 ldap_free_result($res);
468 * sysCreateGroup() - Create a group
470 * @param int The ID of the group to create
471 * @returns true on success/false on error
474 function sysCreateGroup($group_id) {
475 global $sys_ldap_base_dn;
477 $group = &group_get_object($group_id);
478 if (!$this->gfLdapConnect()) {
481 $dn = 'cn='.$group->getUnixName().',ou=Group,'.$sys_ldap_base_dn;
482 $entry['objectClass'][0]='top';
483 $entry['objectClass'][1]='posixGroup';
484 $entry['cn']=$group->getUnixName();
485 $entry['userPassword']='{crypt}x';
486 $entry['gidNumber']=$this->getUnixGID();
492 if (!$this->gfLdapAdd($dn,$entry)) {
493 $this->setError("ERROR: cannot add LDAP group entry '".
494 $group->getUnixName()."': ".$this->gfLdapError()."<br />");
495 // If there's error, that's bad. But don't stop.
500 // Now create CVS group
503 // Add virtual anoncvs user to CVS group
504 $cvs_member_list[$i_cvs++] = 'anoncvs_'.$group->getUnixName();
506 $dn = 'cn='.$group->getUnixName().',ou=cvsGroup,'.$sys_ldap_base_dn;
508 if ($cvs_member_list) {
509 $entry['memberUid']=$cvs_member_list;
511 unset($entry['memberUid']);
514 if (!$this->gfLdapAdd($dn,$entry)) {
515 $this->setError("ERROR: cannot add LDAP CVS group entry '"
516 .$group->getUnixName()."': ".$this->gfLdapError()."<br />");
521 // Finally, setup AnonCVS virtual user
524 if (!$this->gfLdapcheck_user_by_name('anoncvs_'.$group->getUnixName())
525 && !$this->gfLdapCreateUserFromProps('scm_'.$group->getUnixName(),
527 '/bin/false', '/bin/false',
529 $this->getUnixGID(), "/dev/null")) {
530 $this->setError("ERROR: cannot add LDAP AnonCVS user entry '"
531 .$group->getUnixName()."': ".$this->gfLdapError()."<br />");
539 * sysRemoveGroup() - Remove a group
541 * @param int The ID of the group to remove
542 * @returns true on success/false on error
545 function sysRemoveGroup($group_id) {
546 global $sys_ldap_base_dn;
548 $group = &group_get_object($group_id);
549 if (!$this->gfLdapConnect()) {
554 // Remove shell LDAP group
558 $dn = 'cn='.$group->getUnixName().',ou=Group,'.$sys_ldap_base_dn;
560 if (!$this->gfLdapDelete($dn)) {
561 $this->setError("ERROR: cannot delete LDAP group entry '".
562 $group->getUnixName()."': ".$this->gfLdapError()."<br />");
567 // Remove CVS LDAP group
570 $dn = 'cn='.$group->getUnixName().',ou=cvsGroup,'.$sys_ldap_base_dn;
572 if (!$this->gfLdapDelete($dn)) {
573 $this->setError("ERROR: cannot delete LDAP CVS group entry '".
574 $group->getUnixName()."': ".$this->gfLdapError()."<br />");
579 // Remove AnonCVS virtual user
582 $dn = 'uid=anoncvs_'.$group->getUnixName().',ou=People,'.$sys_ldap_base_dn;
583 if (!$this->gfLdapDelete($dn)) {
584 $this->setError("ERROR: cannot delete LDAP AnonCVS user entry '".
585 $group->getUnixName()."': ".$this->gfLdapError()."<br />");
593 * sysGroupAddUser() - Add a user to an LDAP group
595 * @param int The ID of the group two which the user will be added
596 * @param int The ID of the user to add
597 * @param bool Only add this user to CVS
598 * @returns true on success/false on error
601 function sysGroupAddUser($group_id,$user_id,$cvs_only=0) {
603 global $sys_ldap_base_dn;
605 $group = &group_get_object($group_id);
606 $user = &user_get_object($user_id);
607 if (!$this->gfLdapConnect()) {
610 $dn = 'cn='.$group->getUnixName().',ou=Group,'.$sys_ldap_base_dn;
611 $cvs_dn = 'cn='.$group->getUnixName().',ou=cvsGroup,'.$sys_ldap_base_dn;
612 $entry['memberUid'] = $user->getUnixName();
615 // Check if user already a member of CVS group
618 $res=$this->gfLdapRead($cvs_dn,"memberUid=".$user->getUnixName(),array("cn"));
619 if ($res && ldap_count_entries($ldap_conn,$res)>0) {
620 //echo "already a member of CVS<br />";
626 if (!$this->gfLdapModAdd($cvs_dn,$entry)) {
627 $this->setError("ERROR: cannot add member to LDAP CVS group entry '".
628 $group->getUnixName()."': ".$this->gfLdapError()."<br />");
633 ldap_free_result($res);
640 // Check if user already a member of shell group
642 $res = $this->gfLdapRead($dn, "memberUid=".$user->getUnixName(), array("cn"));
644 if ($res && ldap_count_entries($ldap_conn,$res)>0) {
645 //echo "already a member<br />";
651 if (!$this->gfLdapModAdd($dn,$entry)) {
652 $this->setError("ERROR: cannot add member to LDAP group entry '".
653 $group->getUnixName()."': ".$this->gfLdapError()."<br />");
658 ldap_free_result($res);
664 * sysGroupRemoveUser() - Remove a user from an LDAP group
666 * @param int The ID of the group from which to remove the user
667 * @param int The ID of the user to remove
668 * @param bool Only remove user from CVS group
669 * @returns true on success/false on error
672 function sysGroupRemoveUser($group_id,$user_id,$cvs_only=0) {
673 global $sys_ldap_base_dn;
675 $group = &group_get_object($group_id);
676 $user = &user_get_object($user_id);
677 if (!$this->gfLdapConnect()) {
681 $dn = 'cn='.$group->getUnixName().',ou=Group,'.$sys_ldap_base_dn;
682 $cvs_dn = 'cn='.$group->getUnixName().',ou=cvsGroup,'.$sys_ldap_base_dn;
683 $entry['memberUid'] = $user->getUnixName();
687 if (!$this->gfLdapModDel($cvs_dn,$entry) && !$this->gfLdapDoesNotExist()) {
688 $this->setError("ERROR: cannot remove member from LDAP CVS group entry '".
689 $group->getUnixName()."': ".$this->gfLdapError()."(".$this->gfLdapErrno().")"."<br />");
697 if (!$this->gfLdapModDel($dn,$entry) && !$this->gfLdapDoesNotExist()) {
698 $this->setError("ERROR: cannot remove member from LDAP group entry '".
699 $group->getUnixName()."': ".$this->gfLdapError()."(".$this->gfLdapErrno().")"."<br />");
709 // c-file-style: "bsd"