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