[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/lib/plugins/authad/adLDAP/classes/ -> adLDAPUsers.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 User
  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/adLDAPUserCollection.php');
  39  
  40  /**
  41  * USER FUNCTIONS
  42  */
  43  class adLDAPUsers {
  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      * Validate a user's login credentials
  57      * 
  58      * @param string $username A user's AD username
  59      * @param string $password A user's AD password
  60      * @param bool optional $prevent_rebind
  61      * @return bool
  62      */
  63      public function authenticate($username, $password, $preventRebind = false) {
  64          return $this->adldap->authenticate($username, $password, $preventRebind);
  65      }
  66      
  67      /**
  68      * Create a user
  69      * 
  70      * If you specify a password here, this can only be performed over SSL
  71      * 
  72      * @param array $attributes The attributes to set to the user account
  73      * @return bool
  74      */
  75      public function create($attributes)
  76      {
  77          // Check for compulsory fields
  78          if (!array_key_exists("username", $attributes)){ return "Missing compulsory field [username]"; }
  79          if (!array_key_exists("firstname", $attributes)){ return "Missing compulsory field [firstname]"; }
  80          if (!array_key_exists("surname", $attributes)){ return "Missing compulsory field [surname]"; }
  81          if (!array_key_exists("email", $attributes)){ return "Missing compulsory field [email]"; }
  82          if (!array_key_exists("container", $attributes)){ return "Missing compulsory field [container]"; }
  83          if (!is_array($attributes["container"])){ return "Container attribute must be an array."; }
  84  
  85          if (array_key_exists("password",$attributes) && (!$this->adldap->getUseSSL() && !$this->adldap->getUseTLS())){ 
  86              throw new adLDAPException('SSL must be configured on your webserver and enabled in the class to set passwords.');
  87          }
  88  
  89          if (!array_key_exists("display_name", $attributes)) { 
  90              $attributes["display_name"] = $attributes["firstname"] . " " . $attributes["surname"]; 
  91          }
  92  
  93          // Translate the schema
  94          $add = $this->adldap->adldap_schema($attributes);
  95          
  96          // Additional stuff only used for adding accounts
  97          $add["cn"][0] = $attributes["display_name"];
  98          $add["samaccountname"][0] = $attributes["username"];
  99          $add["objectclass"][0] = "top";
 100          $add["objectclass"][1] = "person";
 101          $add["objectclass"][2] = "organizationalPerson";
 102          $add["objectclass"][3] = "user"; //person?
 103          //$add["name"][0]=$attributes["firstname"]." ".$attributes["surname"];
 104  
 105          // Set the account control attribute
 106          $control_options = array("NORMAL_ACCOUNT");
 107          if (!$attributes["enabled"]) { 
 108              $control_options[] = "ACCOUNTDISABLE"; 
 109          }
 110          $add["userAccountControl"][0] = $this->accountControl($control_options);
 111          
 112          // Determine the container
 113          $attributes["container"] = array_reverse($attributes["container"]);
 114          $container = "OU=" . implode(", OU=",$attributes["container"]);
 115  
 116          // Add the entry
 117          $result = @ldap_add($this->adldap->getLdapConnection(), "CN=" . $add["cn"][0] . ", " . $container . "," . $this->adldap->getBaseDn(), $add);
 118          if ($result != true) { 
 119              return false; 
 120          }
 121          
 122          return true;
 123      }
 124      
 125      /**
 126      * Account control options
 127      *
 128      * @param array $options The options to convert to int 
 129      * @return int
 130      */
 131      protected function accountControl($options)
 132      {
 133          $val=0;
 134  
 135          if (is_array($options)) {
 136              if (in_array("SCRIPT",$options)){ $val=$val+1; }
 137              if (in_array("ACCOUNTDISABLE",$options)){ $val=$val+2; }
 138              if (in_array("HOMEDIR_REQUIRED",$options)){ $val=$val+8; }
 139              if (in_array("LOCKOUT",$options)){ $val=$val+16; }
 140              if (in_array("PASSWD_NOTREQD",$options)){ $val=$val+32; }
 141              //PASSWD_CANT_CHANGE Note You cannot assign this permission by directly modifying the UserAccountControl attribute.
 142              //For information about how to set the permission programmatically, see the "Property flag descriptions" section.
 143              if (in_array("ENCRYPTED_TEXT_PWD_ALLOWED",$options)){ $val=$val+128; }
 144              if (in_array("TEMP_DUPLICATE_ACCOUNT",$options)){ $val=$val+256; }
 145              if (in_array("NORMAL_ACCOUNT",$options)){ $val=$val+512; }
 146              if (in_array("INTERDOMAIN_TRUST_ACCOUNT",$options)){ $val=$val+2048; }
 147              if (in_array("WORKSTATION_TRUST_ACCOUNT",$options)){ $val=$val+4096; }
 148              if (in_array("SERVER_TRUST_ACCOUNT",$options)){ $val=$val+8192; }
 149              if (in_array("DONT_EXPIRE_PASSWORD",$options)){ $val=$val+65536; }
 150              if (in_array("MNS_LOGON_ACCOUNT",$options)){ $val=$val+131072; }
 151              if (in_array("SMARTCARD_REQUIRED",$options)){ $val=$val+262144; }
 152              if (in_array("TRUSTED_FOR_DELEGATION",$options)){ $val=$val+524288; }
 153              if (in_array("NOT_DELEGATED",$options)){ $val=$val+1048576; }
 154              if (in_array("USE_DES_KEY_ONLY",$options)){ $val=$val+2097152; }
 155              if (in_array("DONT_REQ_PREAUTH",$options)){ $val=$val+4194304; } 
 156              if (in_array("PASSWORD_EXPIRED",$options)){ $val=$val+8388608; }
 157              if (in_array("TRUSTED_TO_AUTH_FOR_DELEGATION",$options)){ $val=$val+16777216; }
 158          }
 159          return $val;
 160      }
 161      
 162      /**
 163      * Delete a user account
 164      * 
 165      * @param string $username The username to delete (please be careful here!)
 166      * @param bool $isGUID Is the username a GUID or a samAccountName
 167      * @return array
 168      */
 169      public function delete($username, $isGUID = false) 
 170      {      
 171          $userinfo = $this->info($username, array("*"), $isGUID);
 172          $dn = $userinfo[0]['distinguishedname'][0];
 173          $result = $this->adldap->folder()->delete($dn);
 174          if ($result != true) { 
 175              return false;
 176          }        
 177          return true;
 178      }
 179      
 180      /**
 181      * Groups the user is a member of
 182      * 
 183      * @param string $username The username to query
 184      * @param bool $recursive Recursive list of groups
 185      * @param bool $isGUID Is the username passed a GUID or a samAccountName
 186      * @return array
 187      */
 188      public function groups($username, $recursive = NULL, $isGUID = false)
 189      {
 190          if ($username === NULL) { return false; }
 191          if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it
 192          if (!$this->adldap->getLdapBind()) { return false; }
 193          
 194          // Search the directory for their information
 195          $info = @$this->info($username, array("memberof", "primarygroupid"), $isGUID);
 196          $groups = $this->adldap->utilities()->niceNames($info[0]["memberof"]); // Presuming the entry returned is our guy (unique usernames)
 197  
 198          if ($recursive === true){
 199              foreach ($groups as $id => $groupName){
 200                  $extraGroups = $this->adldap->group()->recursiveGroups($groupName);
 201                  $groups = array_merge($groups, $extraGroups);
 202              }
 203          }
 204          
 205          return $groups;
 206      }
 207      
 208      /**
 209      * Find information about the users. Returned in a raw array format from AD
 210      * 
 211      * @param string $username The username to query
 212      * @param array $fields Array of parameters to query
 213      * @param bool $isGUID Is the username passed a GUID or a samAccountName
 214      * @return array
 215      */
 216      public function info($username, $fields = NULL, $isGUID = false)
 217      {
 218          if ($username === NULL) { return false; }
 219          if (!$this->adldap->getLdapBind()) { return false; }
 220  
 221          if ($isGUID === true) {
 222              $username = $this->adldap->utilities()->strGuidToHex($username);
 223              $filter = "objectguid=" . $username;
 224          }
 225          else if (strstr($username, "@")) {
 226               $filter = "userPrincipalName=" . $username;
 227          }
 228          else {
 229               $filter = "samaccountname=" . $username;
 230          }
 231          $filter = "(&(objectCategory=person)({$filter}))";
 232          if ($fields === NULL) { 
 233              $fields = array("samaccountname","mail","memberof","department","displayname","telephonenumber","primarygroupid","objectsid"); 
 234          }
 235          if (!in_array("objectsid", $fields)) {
 236              $fields[] = "objectsid";
 237          }
 238          $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
 239          $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
 240          
 241          if (isset($entries[0])) {
 242              if ($entries[0]['count'] >= 1) {
 243                  if (in_array("memberof", $fields)) {
 244                      // AD does not return the primary group in the ldap query, we may need to fudge it
 245                      if ($this->adldap->getRealPrimaryGroup() && isset($entries[0]["primarygroupid"][0]) && isset($entries[0]["objectsid"][0])){
 246                          //$entries[0]["memberof"][]=$this->group_cn($entries[0]["primarygroupid"][0]);
 247                          $entries[0]["memberof"][] = $this->adldap->group()->getPrimaryGroup($entries[0]["primarygroupid"][0], $entries[0]["objectsid"][0]);
 248                      } else {
 249                          $entries[0]["memberof"][] = "CN=Domain Users,CN=Users," . $this->adldap->getBaseDn();
 250                      }
 251                      if (!isset($entries[0]["memberof"]["count"])) {
 252                          $entries[0]["memberof"]["count"] = 0;
 253                      }
 254                      $entries[0]["memberof"]["count"]++;
 255                  }
 256              }
 257              
 258              return $entries;
 259          }
 260          return false;
 261      }
 262      
 263      /**
 264      * Find information about the users. Returned in a raw array format from AD
 265      * 
 266      * @param string $username The username to query
 267      * @param array $fields Array of parameters to query
 268      * @param bool $isGUID Is the username passed a GUID or a samAccountName
 269      * @return mixed
 270      */
 271      public function infoCollection($username, $fields = NULL, $isGUID = false)
 272      {
 273          if ($username === NULL) { return false; }
 274          if (!$this->adldap->getLdapBind()) { return false; }
 275          
 276          $info = $this->info($username, $fields, $isGUID);
 277          
 278          if ($info !== false) {
 279              $collection = new adLDAPUserCollection($info, $this->adldap);
 280              return $collection;
 281          }
 282          return false;
 283      }
 284      
 285      /**
 286      * Determine if a user is in a specific group
 287      * 
 288      * @param string $username The username to query
 289      * @param string $group The name of the group to check against
 290      * @param bool $recursive Check groups recursively
 291      * @param bool $isGUID Is the username passed a GUID or a samAccountName
 292      * @return bool
 293      */
 294      public function inGroup($username, $group, $recursive = NULL, $isGUID = false)
 295      {
 296          if ($username === NULL) { return false; }
 297          if ($group === NULL) { return false; }
 298          if (!$this->adldap->getLdapBind()) { return false; }
 299          if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it
 300          
 301          // Get a list of the groups
 302          $groups = $this->groups($username, $recursive, $isGUID);
 303          
 304          // Return true if the specified group is in the group list
 305          if (in_array($group, $groups)) { 
 306              return true; 
 307          }
 308  
 309          return false;
 310      }
 311      
 312      /**
 313      * Determine a user's password expiry date
 314      * 
 315      * @param string $username The username to query
 316      * @param book $isGUID Is the username passed a GUID or a samAccountName
 317      * @requires bcmath http://php.net/manual/en/book.bc.php
 318      * @return array
 319      */
 320      public function passwordExpiry($username, $isGUID = false) 
 321      {
 322          if ($username === NULL) { return "Missing compulsory field [username]"; }
 323          if (!$this->adldap->getLdapBind()) { return false; }
 324          if (!function_exists('bcmod')) { throw new adLDAPException("Missing function support [bcmod] http://php.net/manual/en/book.bc.php"); };
 325          
 326          $userInfo = $this->info($username, array("pwdlastset", "useraccountcontrol"), $isGUID);
 327          $pwdLastSet = $userInfo[0]['pwdlastset'][0];
 328          $status = array();
 329          
 330          if ($userInfo[0]['useraccountcontrol'][0] == '66048') {
 331              // Password does not expire
 332              return "Does not expire";
 333          }
 334          if ($pwdLastSet === '0') {
 335              // Password has already expired
 336              return "Password has expired";
 337          }
 338          
 339           // Password expiry in AD can be calculated from TWO values:
 340           //   - User's own pwdLastSet attribute: stores the last time the password was changed
 341           //   - Domain's maxPwdAge attribute: how long passwords last in the domain
 342           //
 343           // Although Microsoft chose to use a different base and unit for time measurements.
 344           // This function will convert them to Unix timestamps
 345           $sr = ldap_read($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), 'objectclass=*', array('maxPwdAge'));
 346           if (!$sr) {
 347               return false;
 348           }
 349           $info = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
 350           $maxPwdAge = $info[0]['maxpwdage'][0];
 351           
 352  
 353           // See MSDN: http://msdn.microsoft.com/en-us/library/ms974598.aspx
 354           //
 355           // pwdLastSet contains the number of 100 nanosecond intervals since January 1, 1601 (UTC), 
 356           // stored in a 64 bit integer. 
 357           //
 358           // The number of seconds between this date and Unix epoch is 11644473600.
 359           //
 360           // maxPwdAge is stored as a large integer that represents the number of 100 nanosecond
 361           // intervals from the time the password was set before the password expires.
 362           //
 363           // We also need to scale this to seconds but also this value is a _negative_ quantity!
 364           //
 365           // If the low 32 bits of maxPwdAge are equal to 0 passwords do not expire
 366           //
 367           // Unfortunately the maths involved are too big for PHP integers, so I've had to require
 368           // BCMath functions to work with arbitrary precision numbers.
 369           if (bcmod($maxPwdAge, 4294967296) === '0') {
 370              return "Domain does not expire passwords";
 371          }
 372          
 373          // Add maxpwdage and pwdlastset and we get password expiration time in Microsoft's
 374          // time units.  Because maxpwd age is negative we need to subtract it.
 375          $pwdExpire = bcsub($pwdLastSet, $maxPwdAge);
 376      
 377          // Convert MS's time to Unix time
 378          $status['expiryts'] = bcsub(bcdiv($pwdExpire, '10000000'), '11644473600');
 379          $status['expiryformat'] = date('Y-m-d H:i:s', bcsub(bcdiv($pwdExpire, '10000000'), '11644473600'));
 380          
 381          return $status;
 382      }
 383      
 384      /**
 385      * Modify a user
 386      * 
 387      * @param string $username The username to query
 388      * @param array $attributes The attributes to modify.  Note if you set the enabled attribute you must not specify any other attributes
 389      * @param bool $isGUID Is the username passed a GUID or a samAccountName
 390      * @return bool
 391      */
 392      public function modify($username, $attributes, $isGUID = false)
 393      {
 394          if ($username === NULL) { return "Missing compulsory field [username]"; }
 395          if (array_key_exists("password", $attributes) && !$this->adldap->getUseSSL() && !$this->adldap->getUseTLS()) { 
 396              throw new adLDAPException('SSL/TLS must be configured on your webserver and enabled in the class to set passwords.');
 397          }
 398  
 399          // Find the dn of the user
 400          $userDn = $this->dn($username, $isGUID);
 401          if ($userDn === false) { 
 402              return false; 
 403          }
 404          
 405          // Translate the update to the LDAP schema                
 406          $mod = $this->adldap->adldap_schema($attributes);
 407          
 408          // Check to see if this is an enabled status update
 409          if (!$mod && !array_key_exists("enabled", $attributes)){ 
 410              return false; 
 411          }
 412          
 413          // Set the account control attribute (only if specified)
 414          if (array_key_exists("enabled", $attributes)){
 415              if ($attributes["enabled"]){ 
 416                  $controlOptions = array("NORMAL_ACCOUNT"); 
 417              }
 418              else { 
 419                  $controlOptions = array("NORMAL_ACCOUNT", "ACCOUNTDISABLE"); 
 420              }
 421              $mod["userAccountControl"][0] = $this->accountControl($controlOptions);
 422          }
 423  
 424          // Do the update
 425          $result = @ldap_modify($this->adldap->getLdapConnection(), $userDn, $mod);
 426          if ($result == false) { 
 427              return false; 
 428          }
 429          
 430          return true;
 431      }
 432      
 433      /**
 434      * Disable a user account
 435      * 
 436      * @param string $username The username to disable
 437      * @param bool $isGUID Is the username passed a GUID or a samAccountName
 438      * @return bool
 439      */
 440      public function disable($username, $isGUID = false)
 441      {
 442          if ($username === NULL) { return "Missing compulsory field [username]"; }
 443          $attributes = array("enabled" => 0);
 444          $result = $this->modify($username, $attributes, $isGUID);
 445          if ($result == false) { return false; }
 446          
 447          return true;
 448      }
 449      
 450      /**
 451      * Enable a user account
 452      * 
 453      * @param string $username The username to enable
 454      * @param bool $isGUID Is the username passed a GUID or a samAccountName
 455      * @return bool
 456      */
 457      public function enable($username, $isGUID = false)
 458      {
 459          if ($username === NULL) { return "Missing compulsory field [username]"; }
 460          $attributes = array("enabled" => 1);
 461          $result = $this->modify($username, $attributes, $isGUID);
 462          if ($result == false) { return false; }
 463          
 464          return true;
 465      }
 466      
 467      /**
 468      * Set the password of a user - This must be performed over SSL
 469      * 
 470      * @param string $username The username to modify
 471      * @param string $password The new password
 472      * @param bool $isGUID Is the username passed a GUID or a samAccountName
 473      * @return bool
 474      */
 475      public function password($username, $password, $isGUID = false)
 476      {
 477          if ($username === NULL) { return false; }
 478          if ($password === NULL) { return false; }
 479          if (!$this->adldap->getLdapBind()) { return false; }
 480          if (!$this->adldap->getUseSSL() && !$this->adldap->getUseTLS()) { 
 481              throw new adLDAPException('SSL must be configured on your webserver and enabled in the class to set passwords.');
 482          }
 483          
 484          $userDn = $this->dn($username, $isGUID);
 485          if ($userDn === false) { 
 486              return false; 
 487          }
 488                  
 489          $add=array();
 490          $add["unicodePwd"][0] = $this->encodePassword($password);
 491          
 492          $result = @ldap_mod_replace($this->adldap->getLdapConnection(), $userDn, $add);
 493          if ($result === false){
 494              $err = ldap_errno($this->adldap->getLdapConnection());
 495              if ($err) {
 496                  $msg = 'Error ' . $err . ': ' . ldap_err2str($err) . '.';
 497                  if($err == 53) {
 498                      $msg .= ' Your password might not match the password policy.';
 499                  }
 500                  throw new adLDAPException($msg);
 501              }
 502              else {
 503                  return false;
 504              }
 505          }
 506          
 507          return true;
 508      }
 509      
 510      /**
 511      * Encode a password for transmission over LDAP
 512      *
 513      * @param string $password The password to encode
 514      * @return string
 515      */
 516      public function encodePassword($password)
 517      {
 518          $password="\"".$password."\"";
 519          $encoded="";
 520          for ($i=0; $i <strlen($password); $i++){ $encoded.="{$password{$i}}\000"; }
 521          return $encoded;
 522      }
 523       
 524      /**
 525      * Obtain the user's distinguished name based on their userid 
 526      * 
 527      * 
 528      * @param string $username The username
 529      * @param bool $isGUID Is the username passed a GUID or a samAccountName
 530      * @return string
 531      */
 532      public function dn($username, $isGUID=false)
 533      {
 534          $user = $this->info($username, array("cn"), $isGUID);
 535          if ($user[0]["dn"] === NULL) { 
 536              return false; 
 537          }
 538          $userDn = $user[0]["dn"];
 539          return $userDn;
 540      }
 541      
 542      /**
 543      * Return a list of all users in AD
 544      * 
 545      * @param bool $includeDescription Return a description of the user
 546      * @param string $search Search parameter
 547      * @param bool $sorted Sort the user accounts
 548      * @return array
 549      */
 550      public function all($includeDescription = false, $search = "*", $sorted = true)
 551      {
 552          if (!$this->adldap->getLdapBind()) { return false; }
 553          
 554          // Perform the search and grab all their details
 555          $filter = "(&(objectClass=user)(samaccounttype=" . adLDAP::ADLDAP_NORMAL_ACCOUNT .")(objectCategory=person)(cn=" . $search . "))";
 556          $fields = array("samaccountname","displayname");
 557          $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
 558          $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
 559  
 560          $usersArray = array();
 561          for ($i=0; $i<$entries["count"]; $i++){
 562              if ($includeDescription && strlen($entries[$i]["displayname"][0])>0){
 563                  $usersArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["displayname"][0];
 564              } elseif ($includeDescription){
 565                  $usersArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["samaccountname"][0];
 566              } else {
 567                  array_push($usersArray, $entries[$i]["samaccountname"][0]);
 568              }
 569          }
 570          if ($sorted) { 
 571              asort($usersArray); 
 572          }
 573          return $usersArray;
 574      }
 575      
 576      /**
 577      * Converts a username (samAccountName) to a GUID
 578      * 
 579      * @param string $username The username to query
 580      * @return string
 581      */
 582      public function usernameToGuid($username) 
 583      {
 584          if (!$this->adldap->getLdapBind()){ return false; }
 585          if ($username === null){ return "Missing compulsory field [username]"; }
 586          
 587          $filter = "samaccountname=" . $username; 
 588          $fields = array("objectGUID"); 
 589          $sr = @ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields); 
 590          if (ldap_count_entries($this->adldap->getLdapConnection(), $sr) > 0) { 
 591              $entry = @ldap_first_entry($this->adldap->getLdapConnection(), $sr); 
 592              $guid = @ldap_get_values_len($this->adldap->getLdapConnection(), $entry, 'objectGUID'); 
 593              $strGUID = $this->adldap->utilities()->binaryToText($guid[0]);          
 594              return $strGUID; 
 595          }
 596          return false; 
 597      }
 598      
 599      /**
 600      * Return a list of all users in AD that have a specific value in a field
 601      *
 602      * @param bool $includeDescription Return a description of the user
 603      * @param string $searchField Field to search search for
 604      * @param string $searchFilter Value to search for in the specified field
 605      * @param bool $sorted Sort the user accounts
 606      * @return array
 607      */
 608      public function find($includeDescription = false, $searchField = false, $searchFilter = false, $sorted = true){
 609          if (!$this->adldap->getLdapBind()){ return false; }
 610            
 611          // Perform the search and grab all their details
 612          $searchParams = "";
 613          if ($searchField) {
 614              $searchParams = "(" . $searchField . "=" . $searchFilter . ")";
 615          }                           
 616          $filter = "(&(objectClass=user)(samaccounttype=" . adLDAP::ADLDAP_NORMAL_ACCOUNT .")(objectCategory=person)" . $searchParams . ")";
 617          $fields = array("samaccountname","displayname");
 618          $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
 619          $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
 620  
 621          $usersArray = array();
 622          for ($i=0; $i < $entries["count"]; $i++) {
 623              if ($includeDescription && strlen($entries[$i]["displayname"][0]) > 0) {
 624                  $usersArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["displayname"][0];
 625              }
 626              else if ($includeDescription) {
 627                  $usersArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["samaccountname"][0];
 628              }
 629              else {
 630                  array_push($usersArray, $entries[$i]["samaccountname"][0]);
 631              }
 632          }
 633          if ($sorted){ 
 634            asort($usersArray); 
 635          }
 636          return ($usersArray);
 637      }
 638      
 639      /**
 640      * Move a user account to a different OU
 641      *
 642      * @param string $username The username to move (please be careful here!)
 643      * @param array $container The container or containers to move the user to (please be careful here!).
 644      * accepts containers in 1. parent 2. child order
 645      * @return array
 646      */
 647      public function move($username, $container) 
 648      {
 649          if (!$this->adldap->getLdapBind()) { return false; }
 650          if ($username === null) { return "Missing compulsory field [username]"; }
 651          if ($container === null) { return "Missing compulsory field [container]"; }
 652          if (!is_array($container)) { return "Container must be an array"; }
 653          
 654          $userInfo = $this->info($username, array("*"));
 655          $dn = $userInfo[0]['distinguishedname'][0];
 656          $newRDn = "cn=" . $username;
 657          $container = array_reverse($container);
 658          $newContainer = "ou=" . implode(",ou=",$container);
 659          $newBaseDn = strtolower($newContainer) . "," . $this->adldap->getBaseDn();
 660          $result = @ldap_rename($this->adldap->getLdapConnection(), $dn, $newRDn, $newBaseDn, true);
 661          if ($result !== true) {
 662              return false;
 663          }
 664          return true;
 665      }
 666      
 667      /**
 668      * Get the last logon time of any user as a Unix timestamp
 669      * 
 670      * @param string $username
 671      * @return long $unixTimestamp
 672      */
 673      public function getLastLogon($username) {
 674          if (!$this->adldap->getLdapBind()) { return false; }
 675          if ($username === null) { return "Missing compulsory field [username]"; }
 676          $userInfo = $this->info($username, array("lastLogonTimestamp"));
 677          $lastLogon = adLDAPUtils::convertWindowsTimeToUnixTime($userInfo[0]['lastLogonTimestamp'][0]);
 678          return $lastLogon;
 679      }
 680      
 681  }
 682  ?>