[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/lib/plugins/authad/adLDAP/classes/ -> adLDAPGroups.php (source)

   1  <?php
   2  /**
   3   * PHP LDAP CLASS FOR MANIPULATING ACTIVE DIRECTORY 
   4   * Version 4.0.4
   5   * 
   6   * PHP Version 5 with SSL and LDAP support
   7   * 
   8   * Written by Scott Barnett, Richard Hyland
   9   *   email: scott@wiggumworld.com, adldap@richardhyland.com
  10   *   http://adldap.sourceforge.net/
  11   * 
  12   * Copyright (c) 2006-2012 Scott Barnett, Richard Hyland
  13   * 
  14   * We'd appreciate any improvements or additions to be submitted back
  15   * to benefit the entire community :)
  16   * 
  17   * This library is free software; you can redistribute it and/or
  18   * modify it under the terms of the GNU Lesser General Public
  19   * License as published by the Free Software Foundation; either
  20   * version 2.1 of the License.
  21   * 
  22   * This library is distributed in the hope that it will be useful,
  23   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  25   * Lesser General Public License for more details.
  26   * 
  27   * @category ToolsAndUtilities
  28   * @package adLDAP
  29   * @subpackage Groups
  30   * @author Scott Barnett, Richard Hyland
  31   * @copyright (c) 2006-2012 Scott Barnett, Richard Hyland
  32   * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html LGPLv2.1
  33   * @revision $Revision: 97 $
  34   * @version 4.0.4
  35   * @link http://adldap.sourceforge.net/
  36   */
  37  require_once(dirname(__FILE__) . '/../adLDAP.php');
  38  require_once(dirname(__FILE__) . '/../collections/adLDAPGroupCollection.php');
  39  
  40  /**
  41  * GROUP FUNCTIONS
  42  */
  43  class adLDAPGroups {
  44      /**
  45      * The current adLDAP connection via dependency injection
  46      * 
  47      * @var adLDAP
  48      */
  49      protected $adldap;
  50      
  51      public function __construct(adLDAP $adldap) {
  52          $this->adldap = $adldap;
  53      }
  54      
  55      /**
  56      * Add a group to a group
  57      * 
  58      * @param string $parent The parent group name
  59      * @param string $child The child group name
  60      * @return bool
  61      */
  62      public function addGroup($parent,$child){
  63  
  64          // Find the parent group's dn
  65          $parentGroup = $this->ginfo($parent, array("cn"));
  66          if ($parentGroup[0]["dn"] === NULL){
  67              return false; 
  68          }
  69          $parentDn = $parentGroup[0]["dn"];
  70          
  71          // Find the child group's dn
  72          $childGroup = $this->info($child, array("cn"));
  73          if ($childGroup[0]["dn"] === NULL){ 
  74              return false; 
  75          }
  76          $childDn = $childGroup[0]["dn"];
  77                  
  78          $add = array();
  79          $add["member"] = $childDn;
  80          
  81          $result = @ldap_mod_add($this->adldap->getLdapConnection(), $parentDn, $add);
  82          if ($result == false) { 
  83              return false; 
  84          }
  85          return true;
  86      }
  87      
  88      /**
  89      * Add a user to a group
  90      * 
  91      * @param string $group The group to add the user to
  92      * @param string $user The user to add to the group
  93      * @param bool $isGUID Is the username passed a GUID or a samAccountName
  94      * @return bool
  95      */
  96      public function addUser($group, $user, $isGUID = false)
  97      {
  98          // Adding a user is a bit fiddly, we need to get the full DN of the user
  99          // and add it using the full DN of the group
 100          
 101          // Find the user's dn
 102          $userDn = $this->adldap->user()->dn($user, $isGUID);
 103          if ($userDn === false) { 
 104              return false; 
 105          }
 106          
 107          // Find the group's dn
 108          $groupInfo = $this->info($group, array("cn"));
 109          if ($groupInfo[0]["dn"] === NULL) { 
 110              return false; 
 111          }
 112          $groupDn = $groupInfo[0]["dn"];
 113          
 114          $add = array();
 115          $add["member"] = $userDn;
 116          
 117          $result = @ldap_mod_add($this->adldap->getLdapConnection(), $groupDn, $add);
 118          if ($result == false) { 
 119              return false; 
 120          }
 121          return true;
 122      }
 123      
 124      /**
 125      * Add a contact to a group
 126      * 
 127      * @param string $group The group to add the contact to
 128      * @param string $contactDn The DN of the contact to add
 129      * @return bool
 130      */
 131      public function addContact($group, $contactDn)
 132      {
 133          // To add a contact we take the contact's DN
 134          // and add it using the full DN of the group
 135          
 136          // Find the group's dn
 137          $groupInfo = $this->info($group, array("cn"));
 138          if ($groupInfo[0]["dn"] === NULL) { 
 139              return false; 
 140          }
 141          $groupDn = $groupInfo[0]["dn"];
 142          
 143          $add = array();
 144          $add["member"] = $contactDn;
 145          
 146          $result = @ldap_mod_add($this->adldap->getLdapConnection(), $groupDn, $add);
 147          if ($result == false) { 
 148              return false; 
 149          }
 150          return true;
 151      }
 152  
 153      /**
 154      * Create a group
 155      * 
 156      * @param array $attributes Default attributes of the group
 157      * @return bool
 158      */
 159      public function create($attributes)
 160      {
 161          if (!is_array($attributes)){ return "Attributes must be an array"; }
 162          if (!array_key_exists("group_name", $attributes)){ return "Missing compulsory field [group_name]"; }
 163          if (!array_key_exists("container", $attributes)){ return "Missing compulsory field [container]"; }
 164          if (!array_key_exists("description", $attributes)){ return "Missing compulsory field [description]"; }
 165          if (!is_array($attributes["container"])){ return "Container attribute must be an array."; }
 166          $attributes["container"] = array_reverse($attributes["container"]);
 167  
 168          //$member_array = array();
 169          //$member_array[0] = "cn=user1,cn=Users,dc=yourdomain,dc=com";
 170          //$member_array[1] = "cn=administrator,cn=Users,dc=yourdomain,dc=com";
 171          
 172          $add = array();
 173          $add["cn"] = $attributes["group_name"];
 174          $add["samaccountname"] = $attributes["group_name"];
 175          $add["objectClass"] = "Group";
 176          $add["description"] = $attributes["description"];
 177          //$add["member"] = $member_array; UNTESTED
 178  
 179          $container = "OU=" . implode(",OU=", $attributes["container"]);
 180          $result = ldap_add($this->adldap->getLdapConnection(), "CN=" . $add["cn"] . ", " . $container . "," . $this->adldap->getBaseDn(), $add);
 181          if ($result != true) { 
 182              return false; 
 183          }
 184          return true;
 185      }
 186      
 187      /**
 188      * Delete a group account 
 189      * 
 190      * @param string $group The group to delete (please be careful here!) 
 191      * 
 192      * @return array 
 193      */
 194      public function delete($group) {
 195          if (!$this->adldap->getLdapBind()){ return false; }
 196          if ($group === null){ return "Missing compulsory field [group]"; }
 197          
 198          $groupInfo = $this->info($group, array("*"));
 199          $dn = $groupInfo[0]['distinguishedname'][0]; 
 200          $result = $this->adldap->folder()->delete($dn); 
 201          if ($result !== true) { 
 202              return false; 
 203          } return true;   
 204      }
 205  
 206      /**
 207      * Remove a group from a group
 208      * 
 209      * @param string $parent The parent group name
 210      * @param string $child The child group name
 211      * @return bool
 212      */
 213      public function removeGroup($parent , $child)
 214      {
 215      
 216          // Find the parent dn
 217          $parentGroup = $this->info($parent, array("cn"));
 218          if ($parentGroup[0]["dn"] === NULL) { 
 219              return false; 
 220          }
 221          $parentDn = $parentGroup[0]["dn"];
 222          
 223          // Find the child dn
 224          $childGroup = $this->info($child, array("cn"));
 225          if ($childGroup[0]["dn"] === NULL) { 
 226              return false; 
 227          }
 228          $childDn = $childGroup[0]["dn"];
 229          
 230          $del = array();
 231          $del["member"] = $childDn;
 232          
 233          $result = @ldap_mod_del($this->adldap->getLdapConnection(), $parentDn, $del);
 234          if ($result == false) { 
 235              return false; 
 236          }
 237          return true;
 238      }
 239      
 240      /**
 241      * Remove a user from a group
 242      * 
 243      * @param string $group The group to remove a user from
 244      * @param string $user The AD user to remove from the group
 245      * @param bool $isGUID Is the username passed a GUID or a samAccountName
 246      * @return bool
 247      */
 248      public function removeUser($group, $user, $isGUID = false)
 249      {
 250      
 251          // Find the parent dn
 252          $groupInfo = $this->info($group, array("cn"));
 253          if ($groupInfo[0]["dn"] === NULL){ 
 254              return false; 
 255          }
 256          $groupDn = $groupInfo[0]["dn"];
 257          
 258          // Find the users dn
 259          $userDn = $this->adldap->user()->dn($user, $isGUID);
 260          if ($userDn === false) {
 261              return false; 
 262          }
 263  
 264          $del = array();
 265          $del["member"] = $userDn;
 266          
 267          $result = @ldap_mod_del($this->adldap->getLdapConnection(), $groupDn, $del);
 268          if ($result == false) {
 269              return false; 
 270          }
 271          return true;
 272      }
 273      
 274      /**
 275      * Remove a contact from a group
 276      * 
 277      * @param string $group The group to remove a user from
 278      * @param string $contactDn The DN of a contact to remove from the group
 279      * @return bool
 280      */
 281      public function removeContact($group, $contactDn)
 282      {
 283      
 284          // Find the parent dn
 285          $groupInfo = $this->info($group, array("cn"));
 286          if ($groupInfo[0]["dn"] === NULL) { 
 287              return false; 
 288          }
 289          $groupDn = $groupInfo[0]["dn"];
 290      
 291          $del = array();
 292          $del["member"] = $contactDn;
 293          
 294          $result = @ldap_mod_del($this->adldap->getLdapConnection(), $groupDn, $del);
 295          if ($result == false) { 
 296              return false; 
 297          }
 298          return true;
 299      }
 300      
 301      /**
 302      * Return a list of groups in a group
 303      * 
 304      * @param string $group The group to query
 305      * @param bool $recursive Recursively get groups
 306      * @return array
 307      */
 308      public function inGroup($group, $recursive = NULL)
 309      {
 310          if (!$this->adldap->getLdapBind()){ return false; }
 311          if ($recursive === NULL){ $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it 
 312          
 313          // Search the directory for the members of a group
 314          $info = $this->info($group, array("member","cn"));
 315          $groups = $info[0]["member"];
 316          if (!is_array($groups)) {
 317              return false;   
 318          }
 319   
 320          $groupArray = array();
 321  
 322          for ($i=0; $i<$groups["count"]; $i++){ 
 323               $filter = "(&(objectCategory=group)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($groups[$i]) . "))";
 324               $fields = array("samaccountname", "distinguishedname", "objectClass");
 325               $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
 326               $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
 327  
 328               // not a person, look for a group  
 329               if ($entries['count'] == 0 && $recursive == true) {  
 330                  $filter = "(&(objectCategory=group)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($groups[$i]) . "))";  
 331                  $fields = array("distinguishedname");  
 332                  $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);  
 333                  $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);  
 334                  if (!isset($entries[0]['distinguishedname'][0])) {
 335                      continue;  
 336                  }
 337                  $subGroups = $this->inGroup($entries[0]['distinguishedname'][0], $recursive);  
 338                  if (is_array($subGroups)) {
 339                      $groupArray = array_merge($groupArray, $subGroups); 
 340                      $groupArray = array_unique($groupArray);  
 341                  }
 342                  continue;  
 343               } 
 344  
 345               $groupArray[] = $entries[0]['distinguishedname'][0];
 346          }
 347          return $groupArray;
 348      }
 349      
 350      /**
 351      * Return a list of members in a group
 352      * 
 353      * @param string $group The group to query
 354      * @param bool $recursive Recursively get group members
 355      * @return array
 356      */
 357      public function members($group, $recursive = NULL)
 358      {
 359          if (!$this->adldap->getLdapBind()){ return false; }
 360          if ($recursive === NULL){ $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it 
 361          // Search the directory for the members of a group
 362          $info = $this->info($group, array("member","cn"));
 363          $users = $info[0]["member"];
 364          if (!is_array($users)) {
 365              return false;   
 366          }
 367   
 368          $userArray = array();
 369  
 370          for ($i=0; $i<$users["count"]; $i++){ 
 371               $filter = "(&(objectCategory=person)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($users[$i]) . "))";
 372               $fields = array("samaccountname", "distinguishedname", "objectClass");
 373               $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
 374               $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
 375  
 376               // not a person, look for a group  
 377               if ($entries['count'] == 0 && $recursive == true) {  
 378                  $filter = "(&(objectCategory=group)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($users[$i]) . "))";  
 379                  $fields = array("samaccountname");  
 380                  $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);  
 381                  $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);  
 382                  if (!isset($entries[0]['samaccountname'][0])) {
 383                      continue;  
 384                  }
 385                  $subUsers = $this->members($entries[0]['samaccountname'][0], $recursive);  
 386                  if (is_array($subUsers)) {
 387                      $userArray = array_merge($userArray, $subUsers); 
 388                      $userArray = array_unique($userArray);  
 389                  }
 390                  continue;  
 391               } 
 392               else if ($entries['count'] == 0) {   
 393                  continue; 
 394               } 
 395  
 396               if ((!isset($entries[0]['samaccountname'][0]) || $entries[0]['samaccountname'][0] === NULL) && $entries[0]['distinguishedname'][0] !== NULL) {
 397                   $userArray[] = $entries[0]['distinguishedname'][0];
 398               }
 399               else if ($entries[0]['samaccountname'][0] !== NULL) {
 400                  $userArray[] = $entries[0]['samaccountname'][0];
 401               }
 402          }
 403          return $userArray;
 404      }
 405      
 406      /**
 407      * Group Information.  Returns an array of raw information about a group.
 408      * The group name is case sensitive
 409      * 
 410      * @param string $groupName The group name to retrieve info about
 411      * @param array $fields Fields to retrieve
 412      * @return array
 413      */
 414      public function info($groupName, $fields = NULL)
 415      {
 416          if ($groupName === NULL) { return false; }
 417          if (!$this->adldap->getLdapBind()) { return false; }
 418          
 419          if (stristr($groupName, '+')) {
 420              $groupName = stripslashes($groupName);   
 421          }
 422          
 423          $filter = "(&(objectCategory=group)(name=" . $this->adldap->utilities()->ldapSlashes($groupName) . "))";
 424          if ($fields === NULL) { 
 425              $fields = array("member","memberof","cn","description","distinguishedname","objectcategory","samaccountname"); 
 426          }
 427          $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
 428          $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
 429  
 430          return $entries;
 431      }
 432      
 433      /**
 434      * Group Information.  Returns an collection
 435      * The group name is case sensitive
 436      * 
 437      * @param string $groupName The group name to retrieve info about
 438      * @param array $fields Fields to retrieve
 439      * @return adLDAPGroupCollection
 440      */
 441      public function infoCollection($groupName, $fields = NULL)
 442      {
 443          if ($groupName === NULL) { return false; }
 444          if (!$this->adldap->getLdapBind()) { return false; }
 445          
 446          $info = $this->info($groupName, $fields);
 447          if ($info !== false) {
 448              $collection = new adLDAPGroupCollection($info, $this->adldap);
 449              return $collection;
 450          }
 451          return false;
 452      }
 453      
 454      /**
 455      * Return a complete list of "groups in groups"
 456      * 
 457      * @param string $group The group to get the list from
 458      * @return array
 459      */
 460      public function recursiveGroups($group)
 461      {
 462          if ($group === NULL) { return false; }
 463  
 464          $stack = array(); 
 465          $processed = array(); 
 466          $retGroups = array(); 
 467       
 468          array_push($stack, $group); // Initial Group to Start with 
 469          while (count($stack) > 0) {
 470              $parent = array_pop($stack);
 471              array_push($processed, $parent);
 472              
 473              $info = $this->info($parent, array("memberof"));
 474              
 475              if (isset($info[0]["memberof"]) && is_array($info[0]["memberof"])) {
 476                  $groups = $info[0]["memberof"]; 
 477                  if ($groups) {
 478                      $groupNames = $this->adldap->utilities()->niceNames($groups);  
 479                      $retGroups = array_merge($retGroups, $groupNames); //final groups to return
 480                      foreach ($groupNames as $id => $groupName) { 
 481                          if (!in_array($groupName, $processed)) {
 482                              array_push($stack, $groupName);
 483                          }
 484                      }
 485                  }
 486              }
 487          }
 488          
 489          return $retGroups;
 490      }
 491      
 492      /**
 493      * Returns a complete list of the groups in AD based on a SAM Account Type  
 494      * 
 495      * @param string $sAMAaccountType The account type to return
 496      * @param bool $includeDescription Whether to return a description
 497      * @param string $search Search parameters
 498      * @param bool $sorted Whether to sort the results
 499      * @return array
 500      */
 501      public function search($sAMAaccountType = adLDAP::ADLDAP_SECURITY_GLOBAL_GROUP, $includeDescription = false, $search = "*", $sorted = true) {
 502          if (!$this->adldap->getLdapBind()) { return false; }
 503          
 504          $filter = '(&(objectCategory=group)';
 505          if ($sAMAaccountType !== null) {
 506              $filter .= '(samaccounttype='. $sAMAaccountType .')';
 507          }
 508          $filter .= '(cn=' . $search . '))';
 509          // Perform the search and grab all their details
 510          $fields = array("samaccountname", "description");
 511          $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
 512          $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
 513  
 514          $groupsArray = array();        
 515          for ($i=0; $i<$entries["count"]; $i++){
 516              if ($includeDescription && strlen($entries[$i]["description"][0]) > 0 ) {
 517                  $groupsArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["description"][0];
 518              }
 519              else if ($includeDescription){
 520                  $groupsArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["samaccountname"][0];
 521              }
 522              else {
 523                  array_push($groupsArray, $entries[$i]["samaccountname"][0]);
 524              }
 525          }
 526          if ($sorted) { 
 527              asort($groupsArray); 
 528          }
 529          return $groupsArray;
 530      }
 531      
 532      /**
 533      * Returns a complete list of all groups in AD
 534      * 
 535      * @param bool $includeDescription Whether to return a description
 536      * @param string $search Search parameters
 537      * @param bool $sorted Whether to sort the results
 538      * @return array
 539      */
 540      public function all($includeDescription = false, $search = "*", $sorted = true){
 541          $groupsArray = $this->search(null, $includeDescription, $search, $sorted);
 542          return $groupsArray;
 543      }
 544      
 545      /**
 546      * Returns a complete list of security groups in AD
 547      * 
 548      * @param bool $includeDescription Whether to return a description
 549      * @param string $search Search parameters
 550      * @param bool $sorted Whether to sort the results
 551      * @return array
 552      */
 553      public function allSecurity($includeDescription = false, $search = "*", $sorted = true){
 554          $groupsArray = $this->search(adLDAP::ADLDAP_SECURITY_GLOBAL_GROUP, $includeDescription, $search, $sorted);
 555          return $groupsArray;
 556      }
 557      
 558      /**
 559      * Returns a complete list of distribution lists in AD
 560      * 
 561      * @param bool $includeDescription Whether to return a description
 562      * @param string $search Search parameters
 563      * @param bool $sorted Whether to sort the results
 564      * @return array
 565      */
 566      public function allDistribution($includeDescription = false, $search = "*", $sorted = true){
 567          $groupsArray = $this->search(adLDAP::ADLDAP_DISTRIBUTION_GROUP, $includeDescription, $search, $sorted);
 568          return $groupsArray;
 569      }
 570      
 571      /**
 572      * Coping with AD not returning the primary group
 573      * http://support.microsoft.com/?kbid=321360 
 574      * 
 575      * This is a re-write based on code submitted by Bruce which prevents the 
 576      * need to search each security group to find the true primary group
 577      * 
 578      * @param string $gid Group ID
 579      * @param string $usersid User's Object SID
 580      * @return mixed
 581      */
 582      public function getPrimaryGroup($gid, $usersid)
 583      {
 584          if ($gid === NULL || $usersid === NULL) { return false; }
 585          $sr = false;
 586  
 587          $gsid = substr_replace($usersid, pack('V',$gid), strlen($usersid)-4,4);
 588          $filter = '(objectsid=' . $this->adldap->utilities()->getTextSID($gsid).')';
 589          $fields = array("samaccountname","distinguishedname");
 590          $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
 591          $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
 592  
 593          if (isset($entries[0]['distinguishedname'][0])) {
 594              return $entries[0]['distinguishedname'][0];
 595          }
 596          return false;
 597       }
 598       
 599       /**
 600      * Coping with AD not returning the primary group
 601      * http://support.microsoft.com/?kbid=321360 
 602      * 
 603      * For some reason it's not possible to search on primarygrouptoken=XXX
 604      * If someone can show otherwise, I'd like to know about it :)
 605      * this way is resource intensive and generally a pain in the @#%^
 606      * 
 607      * @deprecated deprecated since version 3.1, see get get_primary_group
 608      * @param string $gid Group ID
 609      * @return string
 610      */
 611      public function cn($gid){    
 612          if ($gid === NULL) { return false; }
 613          $sr = false;
 614          $r = '';
 615          
 616          $filter = "(&(objectCategory=group)(samaccounttype=" . adLDAP::ADLDAP_SECURITY_GLOBAL_GROUP . "))";
 617          $fields = array("primarygrouptoken", "samaccountname", "distinguishedname");
 618          $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
 619          $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
 620          
 621          for ($i=0; $i<$entries["count"]; $i++){
 622              if ($entries[$i]["primarygrouptoken"][0] == $gid) {
 623                  $r = $entries[$i]["distinguishedname"][0];
 624                  $i = $entries["count"];
 625              }
 626          }
 627  
 628          return $r;
 629      }
 630  }
 631  ?>