3 * FusionForge system users integration
5 * Copyright 2004, Christian Bayle
7 * This file is part of FusionForge.
9 * FusionForge is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published
11 * by the Free Software Foundation; either version 2 of the License,
12 * or (at your option) any later version.
14 * FusionForge is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with FusionForge; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
25 require_once $gfcommon.'include/account.php';
26 require_once $gfcommon.'include/system/UNIX.class.php';
28 class LDAP extends UNIX {
43 * asciize() - Replace non-ascii characters with question marks
45 * LDAP expects utf-8 encoded character string. Since we cannot
46 * know which encoding 8-bit characters in database use, we
47 * just replace them with question marks.
49 * @param string UTF-8 encoded character string.
50 * @return string which contains only ascii characters
52 function asciize($str) {
54 // LDAP don't allow empty strings for some attributes
58 return ereg_replace("[\x80-\xff]","?",$str);
62 * Wrappers for PHP LDAP functions
66 * gfLdapConnect() - Connect to the LDAP server
68 * @returns true on success/false on error
71 function gfLdapConnect() {
72 global $sys_ldap_host,$sys_ldap_port;
73 global $sys_ldap_bind_dn,$sys_ldap_passwd,$ldap_conn,$sys_ldap_version;
77 $ldap_conn = @ldap_connect($sys_ldap_host,$sys_ldap_port);
79 $this->setError('ERROR: Cannot connect to LDAP server<br />');
82 if ($sys_ldap_version) {
83 ldap_set_option($ldap_conn, LDAP_OPT_PROTOCOL_VERSION, $sys_ldap_version);
85 ldap_bind($ldap_conn,$sys_ldap_bind_dn,$sys_ldap_passwd);
91 * gfLdapAdd() - Wrapper for ldap_add()
97 function gfLdapAdd($dn, $entry) {
99 return @ldap_add($ldap_conn,$dn,$entry);
103 * gfLdapDelete() - Wrapper for ldap_delete()
108 function gfLdapDelete($dn) {
110 return @ldap_delete($ldap_conn,$dn);
114 * gfLdapModify() - Wrapper for ldap_modify()
117 * @param string entry
120 function gfLdapModify($dn,$entry) {
122 return @ldap_modify($ldap_conn,$dn,$entry);
126 * gfLdapModifyIfExists() - Wrapper for ldap_modify()
127 * works like gfLdapModify, but returns true if the LDAP entry does not exist
130 * @param string entry
133 function gfLdapModifyIfExists($dn,$entry) {
134 $res = $this->gfLdapModify($dn,$entry);
138 $err = ldap_errno ($ldap_conn) ;
148 * gfLdapModAdd() - Wrapper for ldap_mod_add()
151 * @param string entry
154 function gfLdapModAdd($dn,$entry) {
156 return @ldap_mod_add($ldap_conn,$dn,$entry);
160 * gfLdapModDel() - Wrapper for ldap_mod_del()
163 * @param string entry
166 function gfLdapModDel($dn,$entry) {
168 return @ldap_mod_del($ldap_conn,$dn,$entry);
172 * gfLdapRead() - Wrapper for ldap_read()
175 * @param string filter
179 function gfLdapRead($dn,$filter,$attrs=0) {
181 return @ldap_read($ldap_conn,$dn,$filter,$attrs);
185 * gfLdapError() - Wrapper for ldap_error()
190 function gfLdapError() {
192 return ldap_error($ldap_conn);
196 * gfLdapErrno() - Wrapper for ldap_errno()
201 function gfLdapErrno() {
203 return ldap_errno($ldap_conn);
207 * gfLdapAlreadyExists()
209 function gfLdapAlreadyExists() {
211 return ldap_errno($ldap_conn)==20;
215 * gfLdapDoesNotExist()
217 function gfLdapDoesNotExist() {
219 return ldap_errno($ldap_conn)==16;
223 * User management functions
227 * sysCheckUser() - Check for the existence of a user
229 * @param int The user ID of the user to check
230 * @returns true on success/false on error
233 function sysCheckUser($user_id) {
234 $user =& user_get_object($user_id);
238 return $this->gfLdapcheck_user_by_name($user->getUnixName());
242 * gfLdapcheck_user_by_name() - Check for a user by the username
244 * @param string The username
245 * @returns true on success/false on error
248 function gfLdapcheck_user_by_name($user_name) {
250 global $sys_ldap_base_dn;
252 if (!$this->gfLdapConnect()) {
256 $dn = 'uid='.$user_name.',ou=People,'.$sys_ldap_base_dn;
257 $res = $this->gfLdapRead($dn,"objectClass=*",array("uid"));
259 ldap_free_result($res);
267 * sysCreateUser() - Create a user
269 * @param int The user ID of the user to create
270 * @returns The return status of gfLdapcreate_user_from_object()
273 function sysCreateUser($user_id) {
274 // Check even if the user shouldn't exist
275 // It can be created by a cron
276 if (!$this->sysCheckUser($user_id)){
277 $user = &user_get_object($user_id);
278 return $this->gfLdapcreate_user_from_object($user);
284 * sysCheckCreateUser() - Check that a user has been created
286 * @param int The ID of the user to check
287 * @returns true on success/false on error
290 function sysCheckCreateUser($user_id) {
291 if (!$this->sysCheckUser($user_id)){
292 $user = &user_get_object($user_id);
293 return $this->gfLdapcreate_user_from_object($user);
299 * gfLdapcreate_user_from_object() - Create a user from information contained within an object
301 * @param object The user object
302 * @returns true on success/false on error
305 function gfLdapcreate_user_from_object(&$user) {
306 global $sys_ldap_base_dn;
307 if (!$this->gfLdapConnect()) {
310 $dn = 'uid='.$user->getUnixName().',ou=People,'.$sys_ldap_base_dn;
311 $entry['objectClass'][0]='top';
312 $entry['objectClass'][1]='account';
313 $entry['objectClass'][2]='posixAccount';
314 $entry['objectClass'][3]='shadowAccount';
315 $entry['objectClass'][4]='debGforgeAccount';
316 $entry['uid']=$user->getUnixName();
317 $entry['cn']=$this->asciize($user->getRealName());
318 $entry['gecos']=$this->asciize($user->getRealName());
319 $entry['userPassword']='{crypt}'.$user->getUnixPasswd();
320 $entry['homeDirectory'] = account_user_homedir($user->getUnixName());
321 $entry['loginShell']=$user->getShell();
322 $entry['debGforgeCvsShell']="/bin/cvssh"; // unless explicitly set otherwise, developer has write access
323 $entry['debGforgeForwardEmail']=$user->getEmail();
324 $entry['uidNumber']=$this->getUnixUID();
325 $entry['gidNumber']=$this->getUnixGID(); // users as in debian backend
326 $entry['shadowLastChange']=1; // We don't have expiration, so any non-0
327 $entry['shadowMax']=99999;
328 $entry['shadowWarning']=7;
330 if (!$this->gfLdapAdd($dn,$entry)) {
331 $this->setError("ERROR: cannot add LDAP user entry '".
332 $user->getUnixName()."': ".$this->gfLdapError()."<br />");
339 * gfLdapCreateUserFromProps() - Creates an LDAP user from
341 * @param string The username
343 * @param string The encrypted password
344 * @returns true on success/false on error
347 function gfLdapCreateUserFromProps($username, $cn, $crypt_pw,
348 $shell, $cvsshell, $uid, $gid, $email) {
349 global $sys_ldap_base_dn;
350 if (!$this->gfLdapConnect()) {
353 $dn = 'uid='.$username.',ou=People,'.$sys_ldap_base_dn;
354 $entry['objectClass'][0]='top';
355 $entry['objectClass'][1]='account';
356 $entry['objectClass'][2]='posixAccount';
357 $entry['objectClass'][3]='shadowAccount';
358 $entry['objectClass'][4]='debGforgeAccount';
359 $entry['uid']=$username;
360 $entry['cn']=$this->asciize($cn);
361 $entry['gecos']=$this->asciize($cn);
362 $entry['userPassword']='{crypt}'.$crypt_pw;
363 $entry['homeDirectory'] = account_user_homedir($username);
364 $entry['loginShell']=$shell;
365 $entry['debGforgeCvsShell']=$cvsshell;
366 $entry['debGforgeForwardEmail']=$email;
367 $entry['uidNumber']=$uid;
368 $entry['gidNumber']=$gid;
369 $entry['shadowLastChange']=1;
370 $entry['shadowMax']=99999;
371 $entry['shadowWarning']=7;
373 if (!$this->gfLdapAdd($dn,$entry)) {
374 $this->setError("ERROR: cannot add LDAP user entry '".
375 $username."': ".$this->gfLdapError()."<br />");
382 * sysRemoveUser() - Remove an LDAP user
384 * @param int The user ID of the user to remove
385 * @returns true on success/false on failure
388 function sysRemoveUser($user_id) {
389 global $sys_ldap_base_dn;
391 $user = &user_get_object($user_id);
392 if (!$this->gfLdapConnect()) {
395 $dn = 'uid='.$user->getUnixName().',ou=People,'.$sys_ldap_base_dn;
397 if (!$this->gfLdapDelete($dn)) {
398 $this->setError("ERROR: cannot delete LDAP user entry '".
399 $user->getUnixName()."': ".$this->gfLdapError()."<br />");
406 * sysUserSetAttribute() - Set an attribute for a user
408 * @param int The user ID
409 * @param string The attribute to set
410 * @param string The new value of the attribute
411 * @returns true on success/false on error
414 function sysUserSetAttribute($user_id,$attr,$value) {
415 global $sys_ldap_base_dn;
417 $user = &user_get_object($user_id);
418 if (!$this->gfLdapConnect()) {
421 $dn = 'uid='.$user->getUnixName().',ou=People,'.$sys_ldap_base_dn;
422 $entry[$attr]=$value;
424 if (!$this->gfLdapModifyIfExists($dn, $entry)) {
425 $this->setError("ERROR: cannot change LDAP attribute '$attr' for user '".
426 $user->getUnixName()."': ".$this->gfLdapError()."<br />");
433 * Group management functions
437 * sysCheckGroup() - Check for the existence of a group
439 * @param int The ID of the group to check
440 * @returns true on success/false on error
443 function sysCheckGroup($group_id) {
445 global $sys_ldap_base_dn;
447 $group = &group_get_object($group_id);
449 $this->setError("ERROR: Cannot find group [$group_id]<br />");
452 if (!$this->gfLdapConnect()) {
455 $dn = 'cn='.$group->getUnixName().',ou=Group,'.$sys_ldap_base_dn;
456 $res=$this->gfLdapRead($dn, "objectClass=*", array("cn"));
458 ldap_free_result($res);
465 * sysCreateGroup() - Create a group
467 * @param int The ID of the group to create
468 * @returns true on success/false on error
471 function sysCreateGroup($group_id) {
472 global $sys_ldap_base_dn;
474 $group = &group_get_object($group_id);
475 if (!$this->gfLdapConnect()) {
478 $dn = 'cn='.$group->getUnixName().',ou=Group,'.$sys_ldap_base_dn;
479 $entry['objectClass'][0]='top';
480 $entry['objectClass'][1]='posixGroup';
481 $entry['cn']=$group->getUnixName();
482 $entry['userPassword']='{crypt}x';
483 $entry['gidNumber']=$this->getUnixGID();
489 if (!$this->gfLdapAdd($dn,$entry)) {
490 $this->setError("ERROR: cannot add LDAP group entry '".
491 $group->getUnixName()."': ".$this->gfLdapError()."<br />");
492 // If there's error, that's bad. But don't stop.
497 // Now create CVS group
500 // Add virtual anoncvs user to CVS group
501 $cvs_member_list[$i_cvs++] = 'anoncvs_'.$group->getUnixName();
503 $dn = 'cn='.$group->getUnixName().',ou=cvsGroup,'.$sys_ldap_base_dn;
505 if ($cvs_member_list) {
506 $entry['memberUid']=$cvs_member_list;
508 unset($entry['memberUid']);
511 if (!$this->gfLdapAdd($dn,$entry)) {
512 $this->setError("ERROR: cannot add LDAP CVS group entry '"
513 .$group->getUnixName()."': ".$this->gfLdapError()."<br />");
518 // Finally, setup AnonCVS virtual user
521 if (!$this->gfLdapcheck_user_by_name('anoncvs_'.$group->getUnixName())
522 && !$this->gfLdapCreateUserFromProps('scm_'.$group->getUnixName(),
524 '/bin/false', '/bin/false',
526 $this->getUnixGID(), "/dev/null")) {
527 $this->setError("ERROR: cannot add LDAP AnonCVS user entry '"
528 .$group->getUnixName()."': ".$this->gfLdapError()."<br />");
536 * sysRemoveGroup() - Remove a group
538 * @param int The ID of the group to remove
539 * @returns true on success/false on error
542 function sysRemoveGroup($group_id) {
543 global $sys_ldap_base_dn;
545 $group = &group_get_object($group_id);
546 if (!$this->gfLdapConnect()) {
551 // Remove shell LDAP group
555 $dn = 'cn='.$group->getUnixName().',ou=Group,'.$sys_ldap_base_dn;
557 if (!$this->gfLdapDelete($dn)) {
558 $this->setError("ERROR: cannot delete LDAP group entry '".
559 $group->getUnixName()."': ".$this->gfLdapError()."<br />");
564 // Remove CVS LDAP group
567 $dn = 'cn='.$group->getUnixName().',ou=cvsGroup,'.$sys_ldap_base_dn;
569 if (!$this->gfLdapDelete($dn)) {
570 $this->setError("ERROR: cannot delete LDAP CVS group entry '".
571 $group->getUnixName()."': ".$this->gfLdapError()."<br />");
576 // Remove AnonCVS virtual user
579 $dn = 'uid=anoncvs_'.$group->getUnixName().',ou=People,'.$sys_ldap_base_dn;
580 if (!$this->gfLdapDelete($dn)) {
581 $this->setError("ERROR: cannot delete LDAP AnonCVS user entry '".
582 $group->getUnixName()."': ".$this->gfLdapError()."<br />");
590 * sysGroupAddUser() - Add a user to an LDAP group
592 * @param int The ID of the group two which the user will be added
593 * @param int The ID of the user to add
594 * @param bool Only add this user to CVS
595 * @returns true on success/false on error
598 function sysGroupAddUser($group_id,$user_id,$cvs_only=0) {
600 global $sys_ldap_base_dn;
602 $group = &group_get_object($group_id);
603 $user = &user_get_object($user_id);
604 if (!$this->gfLdapConnect()) {
607 $dn = 'cn='.$group->getUnixName().',ou=Group,'.$sys_ldap_base_dn;
608 $cvs_dn = 'cn='.$group->getUnixName().',ou=cvsGroup,'.$sys_ldap_base_dn;
609 $entry['memberUid'] = $user->getUnixName();
612 // Check if user already a member of CVS group
615 $res=$this->gfLdapRead($cvs_dn,"memberUid=".$user->getUnixName(),array("cn"));
616 if ($res && ldap_count_entries($ldap_conn,$res)>0) {
617 //echo "already a member of CVS<br />";
623 if (!$this->gfLdapModAdd($cvs_dn,$entry)) {
624 $this->setError("ERROR: cannot add member to LDAP CVS group entry '".
625 $group->getUnixName()."': ".$this->gfLdapError()."<br />");
630 ldap_free_result($res);
637 // Check if user already a member of shell group
639 $res = $this->gfLdapRead($dn, "memberUid=".$user->getUnixName(), array("cn"));
641 if ($res && ldap_count_entries($ldap_conn,$res)>0) {
642 //echo "already a member<br />";
648 if (!$this->gfLdapModAdd($dn,$entry)) {
649 $this->setError("ERROR: cannot add member to LDAP group entry '".
650 $group->getUnixName()."': ".$this->gfLdapError()."<br />");
655 ldap_free_result($res);
661 * sysGroupRemoveUser() - Remove a user from an LDAP group
663 * @param int The ID of the group from which to remove the user
664 * @param int The ID of the user to remove
665 * @param bool Only remove user from CVS group
666 * @returns true on success/false on error
669 function sysGroupRemoveUser($group_id,$user_id,$cvs_only=0) {
670 global $sys_ldap_base_dn;
672 $group = &group_get_object($group_id);
673 $user = &user_get_object($user_id);
674 if (!$this->gfLdapConnect()) {
678 $dn = 'cn='.$group->getUnixName().',ou=Group,'.$sys_ldap_base_dn;
679 $cvs_dn = 'cn='.$group->getUnixName().',ou=cvsGroup,'.$sys_ldap_base_dn;
680 $entry['memberUid'] = $user->getUnixName();
684 if (!$this->gfLdapModDel($cvs_dn,$entry) && !$this->gfLdapDoesNotExist()) {
685 $this->setError("ERROR: cannot remove member from LDAP CVS group entry '".
686 $group->getUnixName()."': ".$this->gfLdapError()."(".$this->gfLdapErrno().")"."<br />");
694 if (!$this->gfLdapModDel($dn,$entry) && !$this->gfLdapDoesNotExist()) {
695 $this->setError("ERROR: cannot remove member from LDAP group entry '".
696 $group->getUnixName()."': ".$this->gfLdapError()."(".$this->gfLdapErrno().")"."<br />");
706 // c-file-style: "bsd"