176ce1169SAndreas Gohr<?php 276ce1169SAndreas Gohr/** 376ce1169SAndreas Gohr * PHP LDAP CLASS FOR MANIPULATING ACTIVE DIRECTORY 476ce1169SAndreas Gohr * Version 4.0.4 576ce1169SAndreas Gohr * 676ce1169SAndreas Gohr * PHP Version 5 with SSL and LDAP support 776ce1169SAndreas Gohr * 876ce1169SAndreas Gohr * Written by Scott Barnett, Richard Hyland 976ce1169SAndreas Gohr * email: scott@wiggumworld.com, adldap@richardhyland.com 1076ce1169SAndreas Gohr * http://adldap.sourceforge.net/ 1176ce1169SAndreas Gohr * 1276ce1169SAndreas Gohr * Copyright (c) 2006-2012 Scott Barnett, Richard Hyland 1376ce1169SAndreas Gohr * 1476ce1169SAndreas Gohr * We'd appreciate any improvements or additions to be submitted back 1576ce1169SAndreas Gohr * to benefit the entire community :) 1676ce1169SAndreas Gohr * 1776ce1169SAndreas Gohr * This library is free software; you can redistribute it and/or 1876ce1169SAndreas Gohr * modify it under the terms of the GNU Lesser General Public 1976ce1169SAndreas Gohr * License as published by the Free Software Foundation; either 2076ce1169SAndreas Gohr * version 2.1 of the License. 2176ce1169SAndreas Gohr * 2276ce1169SAndreas Gohr * This library is distributed in the hope that it will be useful, 2376ce1169SAndreas Gohr * but WITHOUT ANY WARRANTY; without even the implied warranty of 2476ce1169SAndreas Gohr * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 2576ce1169SAndreas Gohr * Lesser General Public License for more details. 2676ce1169SAndreas Gohr * 2776ce1169SAndreas Gohr * @category ToolsAndUtilities 2876ce1169SAndreas Gohr * @package adLDAP 2976ce1169SAndreas Gohr * @author Scott Barnett, Richard Hyland 3076ce1169SAndreas Gohr * @copyright (c) 2006-2012 Scott Barnett, Richard Hyland 3176ce1169SAndreas Gohr * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html LGPLv2.1 3276ce1169SAndreas Gohr * @revision $Revision: 169 $ 3376ce1169SAndreas Gohr * @version 4.0.4 3476ce1169SAndreas Gohr * @link http://adldap.sourceforge.net/ 3576ce1169SAndreas Gohr */ 3676ce1169SAndreas Gohr 3776ce1169SAndreas Gohr/** 3876ce1169SAndreas Gohr* Main adLDAP class 3976ce1169SAndreas Gohr* 4076ce1169SAndreas Gohr* Can be initialised using $adldap = new adLDAP(); 4176ce1169SAndreas Gohr* 4276ce1169SAndreas Gohr* Something to keep in mind is that Active Directory is a permissions 4376ce1169SAndreas Gohr* based directory. If you bind as a domain user, you can't fetch as 4476ce1169SAndreas Gohr* much information on other users as you could as a domain admin. 4576ce1169SAndreas Gohr* 4676ce1169SAndreas Gohr* Before asking questions, please read the Documentation at 4776ce1169SAndreas Gohr* http://adldap.sourceforge.net/wiki/doku.php?id=api 4876ce1169SAndreas Gohr*/ 4976ce1169SAndreas Gohrrequire_once(dirname(__FILE__) . '/collections/adLDAPCollection.php'); 5076ce1169SAndreas Gohrrequire_once(dirname(__FILE__) . '/classes/adLDAPGroups.php'); 5176ce1169SAndreas Gohrrequire_once(dirname(__FILE__) . '/classes/adLDAPUsers.php'); 5276ce1169SAndreas Gohrrequire_once(dirname(__FILE__) . '/classes/adLDAPFolders.php'); 5376ce1169SAndreas Gohrrequire_once(dirname(__FILE__) . '/classes/adLDAPUtils.php'); 5476ce1169SAndreas Gohrrequire_once(dirname(__FILE__) . '/classes/adLDAPContacts.php'); 5576ce1169SAndreas Gohrrequire_once(dirname(__FILE__) . '/classes/adLDAPExchange.php'); 5676ce1169SAndreas Gohrrequire_once(dirname(__FILE__) . '/classes/adLDAPComputers.php'); 5776ce1169SAndreas Gohr 5876ce1169SAndreas Gohrclass adLDAP { 5976ce1169SAndreas Gohr 6076ce1169SAndreas Gohr /** 6176ce1169SAndreas Gohr * Define the different types of account in AD 6276ce1169SAndreas Gohr */ 6376ce1169SAndreas Gohr const ADLDAP_NORMAL_ACCOUNT = 805306368; 6476ce1169SAndreas Gohr const ADLDAP_WORKSTATION_TRUST = 805306369; 6576ce1169SAndreas Gohr const ADLDAP_INTERDOMAIN_TRUST = 805306370; 6676ce1169SAndreas Gohr const ADLDAP_SECURITY_GLOBAL_GROUP = 268435456; 6776ce1169SAndreas Gohr const ADLDAP_DISTRIBUTION_GROUP = 268435457; 6876ce1169SAndreas Gohr const ADLDAP_SECURITY_LOCAL_GROUP = 536870912; 6976ce1169SAndreas Gohr const ADLDAP_DISTRIBUTION_LOCAL_GROUP = 536870913; 7076ce1169SAndreas Gohr const ADLDAP_FOLDER = 'OU'; 7176ce1169SAndreas Gohr const ADLDAP_CONTAINER = 'CN'; 7276ce1169SAndreas Gohr 7376ce1169SAndreas Gohr /** 7476ce1169SAndreas Gohr * The default port for LDAP non-SSL connections 7576ce1169SAndreas Gohr */ 7676ce1169SAndreas Gohr const ADLDAP_LDAP_PORT = '389'; 7776ce1169SAndreas Gohr /** 7876ce1169SAndreas Gohr * The default port for LDAPS SSL connections 7976ce1169SAndreas Gohr */ 8076ce1169SAndreas Gohr const ADLDAP_LDAPS_PORT = '636'; 8176ce1169SAndreas Gohr 8276ce1169SAndreas Gohr /** 8376ce1169SAndreas Gohr * The account suffix for your domain, can be set when the class is invoked 8476ce1169SAndreas Gohr * 8576ce1169SAndreas Gohr * @var string 8676ce1169SAndreas Gohr */ 8776ce1169SAndreas Gohr protected $accountSuffix = "@mydomain.local"; 8876ce1169SAndreas Gohr 8976ce1169SAndreas Gohr /** 9076ce1169SAndreas Gohr * The base dn for your domain 9176ce1169SAndreas Gohr * 9276ce1169SAndreas Gohr * If this is set to null then adLDAP will attempt to obtain this automatically from the rootDSE 9376ce1169SAndreas Gohr * 9476ce1169SAndreas Gohr * @var string 9576ce1169SAndreas Gohr */ 9676ce1169SAndreas Gohr protected $baseDn = "DC=mydomain,DC=local"; 9776ce1169SAndreas Gohr 9876ce1169SAndreas Gohr /** 9976ce1169SAndreas Gohr * Port used to talk to the domain controllers. 10076ce1169SAndreas Gohr * 10176ce1169SAndreas Gohr * @var int 10276ce1169SAndreas Gohr */ 10376ce1169SAndreas Gohr protected $adPort = self::ADLDAP_LDAP_PORT; 10476ce1169SAndreas Gohr 10576ce1169SAndreas Gohr /** 10676ce1169SAndreas Gohr * Array of domain controllers. Specifiy multiple controllers if you 10776ce1169SAndreas Gohr * would like the class to balance the LDAP queries amongst multiple servers 10876ce1169SAndreas Gohr * 10976ce1169SAndreas Gohr * @var array 11076ce1169SAndreas Gohr */ 11176ce1169SAndreas Gohr protected $domainControllers = array("dc01.mydomain.local"); 11276ce1169SAndreas Gohr 11376ce1169SAndreas Gohr /** 11476ce1169SAndreas Gohr * Optional account with higher privileges for searching 11576ce1169SAndreas Gohr * This should be set to a domain admin account 11676ce1169SAndreas Gohr * 11776ce1169SAndreas Gohr * @var string 11876ce1169SAndreas Gohr * @var string 11976ce1169SAndreas Gohr */ 12076ce1169SAndreas Gohr protected $adminUsername = NULL; 12176ce1169SAndreas Gohr protected $adminPassword = NULL; 12276ce1169SAndreas Gohr 12376ce1169SAndreas Gohr /** 12476ce1169SAndreas Gohr * AD does not return the primary group. http://support.microsoft.com/?kbid=321360 12576ce1169SAndreas Gohr * This tweak will resolve the real primary group. 12676ce1169SAndreas Gohr * Setting to false will fudge "Domain Users" and is much faster. Keep in mind though that if 12776ce1169SAndreas Gohr * someone's primary group is NOT domain users, this is obviously going to mess up the results 12876ce1169SAndreas Gohr * 12976ce1169SAndreas Gohr * @var bool 13076ce1169SAndreas Gohr */ 13176ce1169SAndreas Gohr protected $realPrimaryGroup = true; 13276ce1169SAndreas Gohr 13376ce1169SAndreas Gohr /** 13476ce1169SAndreas Gohr * Use SSL (LDAPS), your server needs to be setup, please see 13576ce1169SAndreas Gohr * http://adldap.sourceforge.net/wiki/doku.php?id=ldap_over_ssl 13676ce1169SAndreas Gohr * 13776ce1169SAndreas Gohr * @var bool 13876ce1169SAndreas Gohr */ 13976ce1169SAndreas Gohr protected $useSSL = false; 14076ce1169SAndreas Gohr 14176ce1169SAndreas Gohr /** 14276ce1169SAndreas Gohr * Use TLS 14376ce1169SAndreas Gohr * If you wish to use TLS you should ensure that $useSSL is set to false and vice-versa 14476ce1169SAndreas Gohr * 14576ce1169SAndreas Gohr * @var bool 14676ce1169SAndreas Gohr */ 14776ce1169SAndreas Gohr protected $useTLS = false; 14876ce1169SAndreas Gohr 14976ce1169SAndreas Gohr /** 15076ce1169SAndreas Gohr * Use SSO 15176ce1169SAndreas Gohr * To indicate to adLDAP to reuse password set by the brower through NTLM or Kerberos 15276ce1169SAndreas Gohr * 15376ce1169SAndreas Gohr * @var bool 15476ce1169SAndreas Gohr */ 15576ce1169SAndreas Gohr protected $useSSO = false; 15676ce1169SAndreas Gohr 15776ce1169SAndreas Gohr /** 15876ce1169SAndreas Gohr * When querying group memberships, do it recursively 15976ce1169SAndreas Gohr * eg. User Fred is a member of Group A, which is a member of Group B, which is a member of Group C 16076ce1169SAndreas Gohr * user_ingroup("Fred","C") will returns true with this option turned on, false if turned off 16176ce1169SAndreas Gohr * 16276ce1169SAndreas Gohr * @var bool 16376ce1169SAndreas Gohr */ 16476ce1169SAndreas Gohr protected $recursiveGroups = true; 16576ce1169SAndreas Gohr 16676ce1169SAndreas Gohr // You should not need to edit anything below this line 16776ce1169SAndreas Gohr //****************************************************************************************** 16876ce1169SAndreas Gohr 16976ce1169SAndreas Gohr /** 17076ce1169SAndreas Gohr * Connection and bind default variables 17176ce1169SAndreas Gohr * 17276ce1169SAndreas Gohr * @var mixed 17376ce1169SAndreas Gohr * @var mixed 17476ce1169SAndreas Gohr */ 17576ce1169SAndreas Gohr protected $ldapConnection; 17676ce1169SAndreas Gohr protected $ldapBind; 17776ce1169SAndreas Gohr 17876ce1169SAndreas Gohr /** 17976ce1169SAndreas Gohr * Get the active LDAP Connection 18076ce1169SAndreas Gohr * 18176ce1169SAndreas Gohr * @return resource 18276ce1169SAndreas Gohr */ 18376ce1169SAndreas Gohr public function getLdapConnection() { 18476ce1169SAndreas Gohr if ($this->ldapConnection) { 18576ce1169SAndreas Gohr return $this->ldapConnection; 18676ce1169SAndreas Gohr } 18776ce1169SAndreas Gohr return false; 18876ce1169SAndreas Gohr } 18976ce1169SAndreas Gohr 19076ce1169SAndreas Gohr /** 19176ce1169SAndreas Gohr * Get the bind status 19276ce1169SAndreas Gohr * 19376ce1169SAndreas Gohr * @return bool 19476ce1169SAndreas Gohr */ 19576ce1169SAndreas Gohr public function getLdapBind() { 19676ce1169SAndreas Gohr return $this->ldapBind; 19776ce1169SAndreas Gohr } 19876ce1169SAndreas Gohr 19976ce1169SAndreas Gohr /** 20076ce1169SAndreas Gohr * Get the current base DN 20176ce1169SAndreas Gohr * 20276ce1169SAndreas Gohr * @return string 20376ce1169SAndreas Gohr */ 20476ce1169SAndreas Gohr public function getBaseDn() { 20576ce1169SAndreas Gohr return $this->baseDn; 20676ce1169SAndreas Gohr } 20776ce1169SAndreas Gohr 20876ce1169SAndreas Gohr /** 20976ce1169SAndreas Gohr * The group class 21076ce1169SAndreas Gohr * 21176ce1169SAndreas Gohr * @var adLDAPGroups 21276ce1169SAndreas Gohr */ 21376ce1169SAndreas Gohr protected $groupClass; 21476ce1169SAndreas Gohr 21576ce1169SAndreas Gohr /** 21676ce1169SAndreas Gohr * Get the group class interface 21776ce1169SAndreas Gohr * 21876ce1169SAndreas Gohr * @return adLDAPGroups 21976ce1169SAndreas Gohr */ 22076ce1169SAndreas Gohr public function group() { 22176ce1169SAndreas Gohr if (!$this->groupClass) { 22276ce1169SAndreas Gohr $this->groupClass = new adLDAPGroups($this); 22376ce1169SAndreas Gohr } 22476ce1169SAndreas Gohr return $this->groupClass; 22576ce1169SAndreas Gohr } 22676ce1169SAndreas Gohr 22776ce1169SAndreas Gohr /** 22876ce1169SAndreas Gohr * The user class 22976ce1169SAndreas Gohr * 23076ce1169SAndreas Gohr * @var adLDAPUsers 23176ce1169SAndreas Gohr */ 23276ce1169SAndreas Gohr protected $userClass; 23376ce1169SAndreas Gohr 23476ce1169SAndreas Gohr /** 23576ce1169SAndreas Gohr * Get the userclass interface 23676ce1169SAndreas Gohr * 23776ce1169SAndreas Gohr * @return adLDAPUsers 23876ce1169SAndreas Gohr */ 23976ce1169SAndreas Gohr public function user() { 24076ce1169SAndreas Gohr if (!$this->userClass) { 24176ce1169SAndreas Gohr $this->userClass = new adLDAPUsers($this); 24276ce1169SAndreas Gohr } 24376ce1169SAndreas Gohr return $this->userClass; 24476ce1169SAndreas Gohr } 24576ce1169SAndreas Gohr 24676ce1169SAndreas Gohr /** 24776ce1169SAndreas Gohr * The folders class 24876ce1169SAndreas Gohr * 24976ce1169SAndreas Gohr * @var adLDAPFolders 25076ce1169SAndreas Gohr */ 25176ce1169SAndreas Gohr protected $folderClass; 25276ce1169SAndreas Gohr 25376ce1169SAndreas Gohr /** 25476ce1169SAndreas Gohr * Get the folder class interface 25576ce1169SAndreas Gohr * 25676ce1169SAndreas Gohr * @return adLDAPFolders 25776ce1169SAndreas Gohr */ 25876ce1169SAndreas Gohr public function folder() { 25976ce1169SAndreas Gohr if (!$this->folderClass) { 26076ce1169SAndreas Gohr $this->folderClass = new adLDAPFolders($this); 26176ce1169SAndreas Gohr } 26276ce1169SAndreas Gohr return $this->folderClass; 26376ce1169SAndreas Gohr } 26476ce1169SAndreas Gohr 26576ce1169SAndreas Gohr /** 26676ce1169SAndreas Gohr * The utils class 26776ce1169SAndreas Gohr * 26876ce1169SAndreas Gohr * @var adLDAPUtils 26976ce1169SAndreas Gohr */ 27076ce1169SAndreas Gohr protected $utilClass; 27176ce1169SAndreas Gohr 27276ce1169SAndreas Gohr /** 27376ce1169SAndreas Gohr * Get the utils class interface 27476ce1169SAndreas Gohr * 27576ce1169SAndreas Gohr * @return adLDAPUtils 27676ce1169SAndreas Gohr */ 27776ce1169SAndreas Gohr public function utilities() { 27876ce1169SAndreas Gohr if (!$this->utilClass) { 27976ce1169SAndreas Gohr $this->utilClass = new adLDAPUtils($this); 28076ce1169SAndreas Gohr } 28176ce1169SAndreas Gohr return $this->utilClass; 28276ce1169SAndreas Gohr } 28376ce1169SAndreas Gohr 28476ce1169SAndreas Gohr /** 28576ce1169SAndreas Gohr * The contacts class 28676ce1169SAndreas Gohr * 28776ce1169SAndreas Gohr * @var adLDAPContacts 28876ce1169SAndreas Gohr */ 28976ce1169SAndreas Gohr protected $contactClass; 29076ce1169SAndreas Gohr 29176ce1169SAndreas Gohr /** 29276ce1169SAndreas Gohr * Get the contacts class interface 29376ce1169SAndreas Gohr * 29476ce1169SAndreas Gohr * @return adLDAPContacts 29576ce1169SAndreas Gohr */ 29676ce1169SAndreas Gohr public function contact() { 29776ce1169SAndreas Gohr if (!$this->contactClass) { 29876ce1169SAndreas Gohr $this->contactClass = new adLDAPContacts($this); 29976ce1169SAndreas Gohr } 30076ce1169SAndreas Gohr return $this->contactClass; 30176ce1169SAndreas Gohr } 30276ce1169SAndreas Gohr 30376ce1169SAndreas Gohr /** 30476ce1169SAndreas Gohr * The exchange class 30576ce1169SAndreas Gohr * 30676ce1169SAndreas Gohr * @var adLDAPExchange 30776ce1169SAndreas Gohr */ 30876ce1169SAndreas Gohr protected $exchangeClass; 30976ce1169SAndreas Gohr 31076ce1169SAndreas Gohr /** 31176ce1169SAndreas Gohr * Get the exchange class interface 31276ce1169SAndreas Gohr * 31376ce1169SAndreas Gohr * @return adLDAPExchange 31476ce1169SAndreas Gohr */ 31576ce1169SAndreas Gohr public function exchange() { 31676ce1169SAndreas Gohr if (!$this->exchangeClass) { 31776ce1169SAndreas Gohr $this->exchangeClass = new adLDAPExchange($this); 31876ce1169SAndreas Gohr } 31976ce1169SAndreas Gohr return $this->exchangeClass; 32076ce1169SAndreas Gohr } 32176ce1169SAndreas Gohr 32276ce1169SAndreas Gohr /** 32376ce1169SAndreas Gohr * The computers class 32476ce1169SAndreas Gohr * 32576ce1169SAndreas Gohr * @var adLDAPComputers 32676ce1169SAndreas Gohr */ 32776ce1169SAndreas Gohr protected $computersClass; 32876ce1169SAndreas Gohr 32976ce1169SAndreas Gohr /** 33076ce1169SAndreas Gohr * Get the computers class interface 33176ce1169SAndreas Gohr * 33276ce1169SAndreas Gohr * @return adLDAPComputers 33376ce1169SAndreas Gohr */ 33476ce1169SAndreas Gohr public function computer() { 33576ce1169SAndreas Gohr if (!$this->computerClass) { 33676ce1169SAndreas Gohr $this->computerClass = new adLDAPComputers($this); 33776ce1169SAndreas Gohr } 33876ce1169SAndreas Gohr return $this->computerClass; 33976ce1169SAndreas Gohr } 34076ce1169SAndreas Gohr 34176ce1169SAndreas Gohr /** 34276ce1169SAndreas Gohr * Getters and Setters 34376ce1169SAndreas Gohr */ 34476ce1169SAndreas Gohr 34576ce1169SAndreas Gohr /** 34676ce1169SAndreas Gohr * Set the account suffix 34776ce1169SAndreas Gohr * 34876ce1169SAndreas Gohr * @param string $accountSuffix 34976ce1169SAndreas Gohr * @return void 35076ce1169SAndreas Gohr */ 35176ce1169SAndreas Gohr public function setAccountSuffix($accountSuffix) 35276ce1169SAndreas Gohr { 35376ce1169SAndreas Gohr $this->accountSuffix = $accountSuffix; 35476ce1169SAndreas Gohr } 35576ce1169SAndreas Gohr 35676ce1169SAndreas Gohr /** 35776ce1169SAndreas Gohr * Get the account suffix 35876ce1169SAndreas Gohr * 35976ce1169SAndreas Gohr * @return string 36076ce1169SAndreas Gohr */ 36176ce1169SAndreas Gohr public function getAccountSuffix() 36276ce1169SAndreas Gohr { 36376ce1169SAndreas Gohr return $this->accountSuffix; 36476ce1169SAndreas Gohr } 36576ce1169SAndreas Gohr 36676ce1169SAndreas Gohr /** 36776ce1169SAndreas Gohr * Set the domain controllers array 36876ce1169SAndreas Gohr * 36976ce1169SAndreas Gohr * @param array $domainControllers 37076ce1169SAndreas Gohr * @return void 37176ce1169SAndreas Gohr */ 37276ce1169SAndreas Gohr public function setDomainControllers(array $domainControllers) 37376ce1169SAndreas Gohr { 37476ce1169SAndreas Gohr $this->domainControllers = $domainControllers; 37576ce1169SAndreas Gohr } 37676ce1169SAndreas Gohr 37776ce1169SAndreas Gohr /** 37876ce1169SAndreas Gohr * Get the list of domain controllers 37976ce1169SAndreas Gohr * 38076ce1169SAndreas Gohr * @return void 38176ce1169SAndreas Gohr */ 38276ce1169SAndreas Gohr public function getDomainControllers() 38376ce1169SAndreas Gohr { 38476ce1169SAndreas Gohr return $this->domainControllers; 38576ce1169SAndreas Gohr } 38676ce1169SAndreas Gohr 38776ce1169SAndreas Gohr /** 38876ce1169SAndreas Gohr * Sets the port number your domain controller communicates over 38976ce1169SAndreas Gohr * 39076ce1169SAndreas Gohr * @param int $adPort 39176ce1169SAndreas Gohr */ 39276ce1169SAndreas Gohr public function setPort($adPort) 39376ce1169SAndreas Gohr { 39476ce1169SAndreas Gohr $this->adPort = $adPort; 39576ce1169SAndreas Gohr } 39676ce1169SAndreas Gohr 39776ce1169SAndreas Gohr /** 39876ce1169SAndreas Gohr * Gets the port number your domain controller communicates over 39976ce1169SAndreas Gohr * 40076ce1169SAndreas Gohr * @return int 40176ce1169SAndreas Gohr */ 40276ce1169SAndreas Gohr public function getPort() 40376ce1169SAndreas Gohr { 40476ce1169SAndreas Gohr return $this->adPort; 40576ce1169SAndreas Gohr } 40676ce1169SAndreas Gohr 40776ce1169SAndreas Gohr /** 40876ce1169SAndreas Gohr * Set the username of an account with higher priviledges 40976ce1169SAndreas Gohr * 41076ce1169SAndreas Gohr * @param string $adminUsername 41176ce1169SAndreas Gohr * @return void 41276ce1169SAndreas Gohr */ 41376ce1169SAndreas Gohr public function setAdminUsername($adminUsername) 41476ce1169SAndreas Gohr { 41576ce1169SAndreas Gohr $this->adminUsername = $adminUsername; 41676ce1169SAndreas Gohr } 41776ce1169SAndreas Gohr 41876ce1169SAndreas Gohr /** 41976ce1169SAndreas Gohr * Get the username of the account with higher priviledges 42076ce1169SAndreas Gohr * 42176ce1169SAndreas Gohr * This will throw an exception for security reasons 42276ce1169SAndreas Gohr */ 42376ce1169SAndreas Gohr public function getAdminUsername() 42476ce1169SAndreas Gohr { 42576ce1169SAndreas Gohr throw new adLDAPException('For security reasons you cannot access the domain administrator account details'); 42676ce1169SAndreas Gohr } 42776ce1169SAndreas Gohr 42876ce1169SAndreas Gohr /** 42976ce1169SAndreas Gohr * Set the password of an account with higher priviledges 43076ce1169SAndreas Gohr * 43176ce1169SAndreas Gohr * @param string $adminPassword 43276ce1169SAndreas Gohr * @return void 43376ce1169SAndreas Gohr */ 43476ce1169SAndreas Gohr public function setAdminPassword($adminPassword) 43576ce1169SAndreas Gohr { 43676ce1169SAndreas Gohr $this->adminPassword = $adminPassword; 43776ce1169SAndreas Gohr } 43876ce1169SAndreas Gohr 43976ce1169SAndreas Gohr /** 44076ce1169SAndreas Gohr * Get the password of the account with higher priviledges 44176ce1169SAndreas Gohr * 44276ce1169SAndreas Gohr * This will throw an exception for security reasons 44376ce1169SAndreas Gohr */ 44476ce1169SAndreas Gohr public function getAdminPassword() 44576ce1169SAndreas Gohr { 44676ce1169SAndreas Gohr throw new adLDAPException('For security reasons you cannot access the domain administrator account details'); 44776ce1169SAndreas Gohr } 44876ce1169SAndreas Gohr 44976ce1169SAndreas Gohr /** 45076ce1169SAndreas Gohr * Set whether to detect the true primary group 45176ce1169SAndreas Gohr * 45276ce1169SAndreas Gohr * @param bool $realPrimaryGroup 45376ce1169SAndreas Gohr * @return void 45476ce1169SAndreas Gohr */ 45576ce1169SAndreas Gohr public function setRealPrimaryGroup($realPrimaryGroup) 45676ce1169SAndreas Gohr { 45776ce1169SAndreas Gohr $this->realPrimaryGroup = $realPrimaryGroup; 45876ce1169SAndreas Gohr } 45976ce1169SAndreas Gohr 46076ce1169SAndreas Gohr /** 46176ce1169SAndreas Gohr * Get the real primary group setting 46276ce1169SAndreas Gohr * 46376ce1169SAndreas Gohr * @return bool 46476ce1169SAndreas Gohr */ 46576ce1169SAndreas Gohr public function getRealPrimaryGroup() 46676ce1169SAndreas Gohr { 46776ce1169SAndreas Gohr return $this->realPrimaryGroup; 46876ce1169SAndreas Gohr } 46976ce1169SAndreas Gohr 47076ce1169SAndreas Gohr /** 47176ce1169SAndreas Gohr * Set whether to use SSL 47276ce1169SAndreas Gohr * 47376ce1169SAndreas Gohr * @param bool $useSSL 47476ce1169SAndreas Gohr * @return void 47576ce1169SAndreas Gohr */ 47676ce1169SAndreas Gohr public function setUseSSL($useSSL) 47776ce1169SAndreas Gohr { 47876ce1169SAndreas Gohr $this->useSSL = $useSSL; 47976ce1169SAndreas Gohr // Set the default port correctly 48076ce1169SAndreas Gohr if($this->useSSL) { 48176ce1169SAndreas Gohr $this->setPort(self::ADLDAP_LDAPS_PORT); 48276ce1169SAndreas Gohr } 48376ce1169SAndreas Gohr else { 48476ce1169SAndreas Gohr $this->setPort(self::ADLDAP_LDAP_PORT); 48576ce1169SAndreas Gohr } 48676ce1169SAndreas Gohr } 48776ce1169SAndreas Gohr 48876ce1169SAndreas Gohr /** 48976ce1169SAndreas Gohr * Get the SSL setting 49076ce1169SAndreas Gohr * 49176ce1169SAndreas Gohr * @return bool 49276ce1169SAndreas Gohr */ 49376ce1169SAndreas Gohr public function getUseSSL() 49476ce1169SAndreas Gohr { 49576ce1169SAndreas Gohr return $this->useSSL; 49676ce1169SAndreas Gohr } 49776ce1169SAndreas Gohr 49876ce1169SAndreas Gohr /** 49976ce1169SAndreas Gohr * Set whether to use TLS 50076ce1169SAndreas Gohr * 50176ce1169SAndreas Gohr * @param bool $useTLS 50276ce1169SAndreas Gohr * @return void 50376ce1169SAndreas Gohr */ 50476ce1169SAndreas Gohr public function setUseTLS($useTLS) 50576ce1169SAndreas Gohr { 50676ce1169SAndreas Gohr $this->useTLS = $useTLS; 50776ce1169SAndreas Gohr } 50876ce1169SAndreas Gohr 50976ce1169SAndreas Gohr /** 51076ce1169SAndreas Gohr * Get the TLS setting 51176ce1169SAndreas Gohr * 51276ce1169SAndreas Gohr * @return bool 51376ce1169SAndreas Gohr */ 51476ce1169SAndreas Gohr public function getUseTLS() 51576ce1169SAndreas Gohr { 51676ce1169SAndreas Gohr return $this->useTLS; 51776ce1169SAndreas Gohr } 51876ce1169SAndreas Gohr 51976ce1169SAndreas Gohr /** 52076ce1169SAndreas Gohr * Set whether to use SSO 52176ce1169SAndreas Gohr * Requires ldap_sasl_bind support. Be sure --with-ldap-sasl is used when configuring PHP otherwise this function will be undefined. 52276ce1169SAndreas Gohr * 52376ce1169SAndreas Gohr * @param bool $useSSO 52476ce1169SAndreas Gohr * @return void 52576ce1169SAndreas Gohr */ 52676ce1169SAndreas Gohr public function setUseSSO($useSSO) 52776ce1169SAndreas Gohr { 52876ce1169SAndreas Gohr if ($useSSO === true && !$this->ldapSaslSupported()) { 529*59752844SAnders Sandblad throw new adLDAPException('No LDAP SASL support for PHP. See: http://php.net/ldap_sasl_bind'); 53076ce1169SAndreas Gohr } 53176ce1169SAndreas Gohr $this->useSSO = $useSSO; 53276ce1169SAndreas Gohr } 53376ce1169SAndreas Gohr 53476ce1169SAndreas Gohr /** 53576ce1169SAndreas Gohr * Get the SSO setting 53676ce1169SAndreas Gohr * 53776ce1169SAndreas Gohr * @return bool 53876ce1169SAndreas Gohr */ 53976ce1169SAndreas Gohr public function getUseSSO() 54076ce1169SAndreas Gohr { 54176ce1169SAndreas Gohr return $this->useSSO; 54276ce1169SAndreas Gohr } 54376ce1169SAndreas Gohr 54476ce1169SAndreas Gohr /** 54576ce1169SAndreas Gohr * Set whether to lookup recursive groups 54676ce1169SAndreas Gohr * 54776ce1169SAndreas Gohr * @param bool $recursiveGroups 54876ce1169SAndreas Gohr * @return void 54976ce1169SAndreas Gohr */ 55076ce1169SAndreas Gohr public function setRecursiveGroups($recursiveGroups) 55176ce1169SAndreas Gohr { 55276ce1169SAndreas Gohr $this->recursiveGroups = $recursiveGroups; 55376ce1169SAndreas Gohr } 55476ce1169SAndreas Gohr 55576ce1169SAndreas Gohr /** 55676ce1169SAndreas Gohr * Get the recursive groups setting 55776ce1169SAndreas Gohr * 55876ce1169SAndreas Gohr * @return bool 55976ce1169SAndreas Gohr */ 56076ce1169SAndreas Gohr public function getRecursiveGroups() 56176ce1169SAndreas Gohr { 56276ce1169SAndreas Gohr return $this->recursiveGroups; 56376ce1169SAndreas Gohr } 56476ce1169SAndreas Gohr 56576ce1169SAndreas Gohr /** 56676ce1169SAndreas Gohr * Default Constructor 56776ce1169SAndreas Gohr * 56876ce1169SAndreas Gohr * Tries to bind to the AD domain over LDAP or LDAPs 56976ce1169SAndreas Gohr * 57076ce1169SAndreas Gohr * @param array $options Array of options to pass to the constructor 57176ce1169SAndreas Gohr * @throws Exception - if unable to bind to Domain Controller 57276ce1169SAndreas Gohr * @return bool 57376ce1169SAndreas Gohr */ 57476ce1169SAndreas Gohr function __construct($options = array()) { 57576ce1169SAndreas Gohr // You can specifically overide any of the default configuration options setup above 57676ce1169SAndreas Gohr if (count($options) > 0) { 57776ce1169SAndreas Gohr if (array_key_exists("account_suffix",$options)){ $this->accountSuffix = $options["account_suffix"]; } 57876ce1169SAndreas Gohr if (array_key_exists("base_dn",$options)){ $this->baseDn = $options["base_dn"]; } 57976ce1169SAndreas Gohr if (array_key_exists("domain_controllers",$options)){ 58076ce1169SAndreas Gohr if (!is_array($options["domain_controllers"])) { 58176ce1169SAndreas Gohr throw new adLDAPException('[domain_controllers] option must be an array'); 58276ce1169SAndreas Gohr } 58376ce1169SAndreas Gohr $this->domainControllers = $options["domain_controllers"]; 58476ce1169SAndreas Gohr } 58576ce1169SAndreas Gohr if (array_key_exists("admin_username",$options)){ $this->adminUsername = $options["admin_username"]; } 58676ce1169SAndreas Gohr if (array_key_exists("admin_password",$options)){ $this->adminPassword = $options["admin_password"]; } 58776ce1169SAndreas Gohr if (array_key_exists("real_primarygroup",$options)){ $this->realPrimaryGroup = $options["real_primarygroup"]; } 58876ce1169SAndreas Gohr if (array_key_exists("use_ssl",$options)){ $this->setUseSSL($options["use_ssl"]); } 58976ce1169SAndreas Gohr if (array_key_exists("use_tls",$options)){ $this->useTLS = $options["use_tls"]; } 59076ce1169SAndreas Gohr if (array_key_exists("recursive_groups",$options)){ $this->recursiveGroups = $options["recursive_groups"]; } 59176ce1169SAndreas Gohr if (array_key_exists("ad_port",$options)){ $this->setPort($options["ad_port"]); } 59276ce1169SAndreas Gohr if (array_key_exists("sso",$options)) { 59376ce1169SAndreas Gohr $this->setUseSSO($options["sso"]); 59476ce1169SAndreas Gohr if (!$this->ldapSaslSupported()) { 59576ce1169SAndreas Gohr $this->setUseSSO(false); 59676ce1169SAndreas Gohr } 59776ce1169SAndreas Gohr } 59876ce1169SAndreas Gohr } 59976ce1169SAndreas Gohr 60076ce1169SAndreas Gohr if ($this->ldapSupported() === false) { 601*59752844SAnders Sandblad throw new adLDAPException('No LDAP support for PHP. See: http://php.net/ldap'); 60276ce1169SAndreas Gohr } 60376ce1169SAndreas Gohr 60476ce1169SAndreas Gohr return $this->connect(); 60576ce1169SAndreas Gohr } 60676ce1169SAndreas Gohr 60776ce1169SAndreas Gohr /** 60876ce1169SAndreas Gohr * Default Destructor 60976ce1169SAndreas Gohr * 61076ce1169SAndreas Gohr * Closes the LDAP connection 61176ce1169SAndreas Gohr * 61276ce1169SAndreas Gohr * @return void 61376ce1169SAndreas Gohr */ 61476ce1169SAndreas Gohr function __destruct() { 61576ce1169SAndreas Gohr $this->close(); 61676ce1169SAndreas Gohr } 61776ce1169SAndreas Gohr 61876ce1169SAndreas Gohr /** 61976ce1169SAndreas Gohr * Connects and Binds to the Domain Controller 62076ce1169SAndreas Gohr * 62176ce1169SAndreas Gohr * @return bool 62276ce1169SAndreas Gohr */ 62376ce1169SAndreas Gohr public function connect() 62476ce1169SAndreas Gohr { 62576ce1169SAndreas Gohr // Connect to the AD/LDAP server as the username/password 62676ce1169SAndreas Gohr $domainController = $this->randomController(); 62776ce1169SAndreas Gohr if ($this->useSSL) { 62876ce1169SAndreas Gohr $this->ldapConnection = ldap_connect("ldaps://" . $domainController, $this->adPort); 62976ce1169SAndreas Gohr } else { 63076ce1169SAndreas Gohr $this->ldapConnection = ldap_connect($domainController, $this->adPort); 63176ce1169SAndreas Gohr } 63276ce1169SAndreas Gohr 63376ce1169SAndreas Gohr // Set some ldap options for talking to AD 63476ce1169SAndreas Gohr ldap_set_option($this->ldapConnection, LDAP_OPT_PROTOCOL_VERSION, 3); 63576ce1169SAndreas Gohr ldap_set_option($this->ldapConnection, LDAP_OPT_REFERRALS, 0); 63676ce1169SAndreas Gohr 63776ce1169SAndreas Gohr if ($this->useTLS) { 63876ce1169SAndreas Gohr ldap_start_tls($this->ldapConnection); 63976ce1169SAndreas Gohr } 64076ce1169SAndreas Gohr 64176ce1169SAndreas Gohr // Bind as a domain admin if they've set it up 64276ce1169SAndreas Gohr if ($this->adminUsername !== NULL && $this->adminPassword !== NULL) { 64376ce1169SAndreas Gohr $this->ldapBind = @ldap_bind($this->ldapConnection, $this->adminUsername . $this->accountSuffix, $this->adminPassword); 64476ce1169SAndreas Gohr if (!$this->ldapBind) { 64576ce1169SAndreas Gohr if ($this->useSSL && !$this->useTLS) { 64676ce1169SAndreas Gohr // If you have problems troubleshooting, remove the @ character from the ldapldapBind command above to get the actual error message 64776ce1169SAndreas Gohr throw new adLDAPException('Bind to Active Directory failed. Either the LDAPs connection failed or the login credentials are incorrect. AD said: ' . $this->getLastError()); 64876ce1169SAndreas Gohr } 64976ce1169SAndreas Gohr else { 65076ce1169SAndreas Gohr throw new adLDAPException('Bind to Active Directory failed. Check the login credentials and/or server details. AD said: ' . $this->getLastError()); 65176ce1169SAndreas Gohr } 65276ce1169SAndreas Gohr } 65376ce1169SAndreas Gohr } 65476ce1169SAndreas Gohr if ($this->useSSO && $_SERVER['REMOTE_USER'] && $this->adminUsername === null && $_SERVER['KRB5CCNAME']) { 65576ce1169SAndreas Gohr putenv("KRB5CCNAME=" . $_SERVER['KRB5CCNAME']); 65676ce1169SAndreas Gohr $this->ldapBind = @ldap_sasl_bind($this->ldapConnection, NULL, NULL, "GSSAPI"); 65776ce1169SAndreas Gohr if (!$this->ldapBind){ 65876ce1169SAndreas Gohr throw new adLDAPException('Rebind to Active Directory failed. AD said: ' . $this->getLastError()); 65976ce1169SAndreas Gohr } 66076ce1169SAndreas Gohr else { 66176ce1169SAndreas Gohr return true; 66276ce1169SAndreas Gohr } 66376ce1169SAndreas Gohr } 66476ce1169SAndreas Gohr 66576ce1169SAndreas Gohr 66676ce1169SAndreas Gohr if ($this->baseDn == NULL) { 66776ce1169SAndreas Gohr $this->baseDn = $this->findBaseDn(); 66876ce1169SAndreas Gohr } 66976ce1169SAndreas Gohr 67076ce1169SAndreas Gohr return true; 67176ce1169SAndreas Gohr } 67276ce1169SAndreas Gohr 67376ce1169SAndreas Gohr /** 67476ce1169SAndreas Gohr * Closes the LDAP connection 67576ce1169SAndreas Gohr * 67676ce1169SAndreas Gohr * @return void 67776ce1169SAndreas Gohr */ 67876ce1169SAndreas Gohr public function close() { 67976ce1169SAndreas Gohr if ($this->ldapConnection) { 68076ce1169SAndreas Gohr @ldap_close($this->ldapConnection); 68176ce1169SAndreas Gohr } 68276ce1169SAndreas Gohr } 68376ce1169SAndreas Gohr 68476ce1169SAndreas Gohr /** 68576ce1169SAndreas Gohr * Validate a user's login credentials 68676ce1169SAndreas Gohr * 68776ce1169SAndreas Gohr * @param string $username A user's AD username 68876ce1169SAndreas Gohr * @param string $password A user's AD password 68976ce1169SAndreas Gohr * @param bool optional $preventRebind 69076ce1169SAndreas Gohr * @return bool 69176ce1169SAndreas Gohr */ 69276ce1169SAndreas Gohr public function authenticate($username, $password, $preventRebind = false) { 69376ce1169SAndreas Gohr // Prevent null binding 69476ce1169SAndreas Gohr if ($username === NULL || $password === NULL) { return false; } 69576ce1169SAndreas Gohr if (empty($username) || empty($password)) { return false; } 69676ce1169SAndreas Gohr 69776ce1169SAndreas Gohr // Allow binding over SSO for Kerberos 69876ce1169SAndreas Gohr if ($this->useSSO && $_SERVER['REMOTE_USER'] && $_SERVER['REMOTE_USER'] == $username && $this->adminUsername === NULL && $_SERVER['KRB5CCNAME']) { 69976ce1169SAndreas Gohr putenv("KRB5CCNAME=" . $_SERVER['KRB5CCNAME']); 70076ce1169SAndreas Gohr $this->ldapBind = @ldap_sasl_bind($this->ldapConnection, NULL, NULL, "GSSAPI"); 70176ce1169SAndreas Gohr if (!$this->ldapBind) { 70276ce1169SAndreas Gohr throw new adLDAPException('Rebind to Active Directory failed. AD said: ' . $this->getLastError()); 70376ce1169SAndreas Gohr } 70476ce1169SAndreas Gohr else { 70576ce1169SAndreas Gohr return true; 70676ce1169SAndreas Gohr } 70776ce1169SAndreas Gohr } 70876ce1169SAndreas Gohr 70976ce1169SAndreas Gohr // Bind as the user 71076ce1169SAndreas Gohr $ret = true; 71176ce1169SAndreas Gohr $this->ldapBind = @ldap_bind($this->ldapConnection, $username . $this->accountSuffix, $password); 71276ce1169SAndreas Gohr if (!$this->ldapBind){ 71376ce1169SAndreas Gohr $ret = false; 71476ce1169SAndreas Gohr } 71576ce1169SAndreas Gohr 71676ce1169SAndreas Gohr // Cnce we've checked their details, kick back into admin mode if we have it 71776ce1169SAndreas Gohr if ($this->adminUsername !== NULL && !$preventRebind) { 71876ce1169SAndreas Gohr $this->ldapBind = @ldap_bind($this->ldapConnection, $this->adminUsername . $this->accountSuffix , $this->adminPassword); 71976ce1169SAndreas Gohr if (!$this->ldapBind){ 72076ce1169SAndreas Gohr // This should never happen in theory 72176ce1169SAndreas Gohr throw new adLDAPException('Rebind to Active Directory failed. AD said: ' . $this->getLastError()); 72276ce1169SAndreas Gohr } 72376ce1169SAndreas Gohr } 72476ce1169SAndreas Gohr 72576ce1169SAndreas Gohr return $ret; 72676ce1169SAndreas Gohr } 72776ce1169SAndreas Gohr 72876ce1169SAndreas Gohr /** 72976ce1169SAndreas Gohr * Find the Base DN of your domain controller 73076ce1169SAndreas Gohr * 73176ce1169SAndreas Gohr * @return string 73276ce1169SAndreas Gohr */ 73376ce1169SAndreas Gohr public function findBaseDn() 73476ce1169SAndreas Gohr { 73576ce1169SAndreas Gohr $namingContext = $this->getRootDse(array('defaultnamingcontext')); 73676ce1169SAndreas Gohr return $namingContext[0]['defaultnamingcontext'][0]; 73776ce1169SAndreas Gohr } 73876ce1169SAndreas Gohr 73976ce1169SAndreas Gohr /** 74076ce1169SAndreas Gohr * Get the RootDSE properties from a domain controller 74176ce1169SAndreas Gohr * 74276ce1169SAndreas Gohr * @param array $attributes The attributes you wish to query e.g. defaultnamingcontext 74376ce1169SAndreas Gohr * @return array 74476ce1169SAndreas Gohr */ 74576ce1169SAndreas Gohr public function getRootDse($attributes = array("*", "+")) { 74676ce1169SAndreas Gohr if (!$this->ldapBind){ return (false); } 74776ce1169SAndreas Gohr 74876ce1169SAndreas Gohr $sr = @ldap_read($this->ldapConnection, NULL, 'objectClass=*', $attributes); 74976ce1169SAndreas Gohr $entries = @ldap_get_entries($this->ldapConnection, $sr); 75076ce1169SAndreas Gohr return $entries; 75176ce1169SAndreas Gohr } 75276ce1169SAndreas Gohr 75376ce1169SAndreas Gohr /** 75476ce1169SAndreas Gohr * Get last error from Active Directory 75576ce1169SAndreas Gohr * 75676ce1169SAndreas Gohr * This function gets the last message from Active Directory 75776ce1169SAndreas Gohr * This may indeed be a 'Success' message but if you get an unknown error 75876ce1169SAndreas Gohr * it might be worth calling this function to see what errors were raised 75976ce1169SAndreas Gohr * 76076ce1169SAndreas Gohr * return string 76176ce1169SAndreas Gohr */ 76276ce1169SAndreas Gohr public function getLastError() { 76376ce1169SAndreas Gohr return @ldap_error($this->ldapConnection); 76476ce1169SAndreas Gohr } 76576ce1169SAndreas Gohr 76676ce1169SAndreas Gohr /** 76776ce1169SAndreas Gohr * Detect LDAP support in php 76876ce1169SAndreas Gohr * 76976ce1169SAndreas Gohr * @return bool 77076ce1169SAndreas Gohr */ 77176ce1169SAndreas Gohr protected function ldapSupported() 77276ce1169SAndreas Gohr { 77376ce1169SAndreas Gohr if (!function_exists('ldap_connect')) { 77476ce1169SAndreas Gohr return false; 77576ce1169SAndreas Gohr } 77676ce1169SAndreas Gohr return true; 77776ce1169SAndreas Gohr } 77876ce1169SAndreas Gohr 77976ce1169SAndreas Gohr /** 78076ce1169SAndreas Gohr * Detect ldap_sasl_bind support in PHP 78176ce1169SAndreas Gohr * 78276ce1169SAndreas Gohr * @return bool 78376ce1169SAndreas Gohr */ 78476ce1169SAndreas Gohr protected function ldapSaslSupported() 78576ce1169SAndreas Gohr { 78676ce1169SAndreas Gohr if (!function_exists('ldap_sasl_bind')) { 78776ce1169SAndreas Gohr return false; 78876ce1169SAndreas Gohr } 78976ce1169SAndreas Gohr return true; 79076ce1169SAndreas Gohr } 79176ce1169SAndreas Gohr 79276ce1169SAndreas Gohr /** 79376ce1169SAndreas Gohr * Schema 79476ce1169SAndreas Gohr * 79576ce1169SAndreas Gohr * @param array $attributes Attributes to be queried 79676ce1169SAndreas Gohr * @return array 79776ce1169SAndreas Gohr */ 79876ce1169SAndreas Gohr public function adldap_schema($attributes){ 79976ce1169SAndreas Gohr 80076ce1169SAndreas Gohr // LDAP doesn't like NULL attributes, only set them if they have values 80176ce1169SAndreas Gohr // If you wish to remove an attribute you should set it to a space 80276ce1169SAndreas Gohr // TO DO: Adapt user_modify to use ldap_mod_delete to remove a NULL attribute 80376ce1169SAndreas Gohr $mod=array(); 80476ce1169SAndreas Gohr 80576ce1169SAndreas Gohr // Check every attribute to see if it contains 8bit characters and then UTF8 encode them 80676ce1169SAndreas Gohr array_walk($attributes, array($this, 'encode8bit')); 80776ce1169SAndreas Gohr 80876ce1169SAndreas Gohr if ($attributes["address_city"]){ $mod["l"][0]=$attributes["address_city"]; } 80976ce1169SAndreas Gohr if ($attributes["address_code"]){ $mod["postalCode"][0]=$attributes["address_code"]; } 81076ce1169SAndreas Gohr //if ($attributes["address_country"]){ $mod["countryCode"][0]=$attributes["address_country"]; } // use country codes? 81176ce1169SAndreas Gohr if ($attributes["address_country"]){ $mod["c"][0]=$attributes["address_country"]; } 81276ce1169SAndreas Gohr if ($attributes["address_pobox"]){ $mod["postOfficeBox"][0]=$attributes["address_pobox"]; } 81376ce1169SAndreas Gohr if ($attributes["address_state"]){ $mod["st"][0]=$attributes["address_state"]; } 81476ce1169SAndreas Gohr if ($attributes["address_street"]){ $mod["streetAddress"][0]=$attributes["address_street"]; } 81576ce1169SAndreas Gohr if ($attributes["company"]){ $mod["company"][0]=$attributes["company"]; } 81676ce1169SAndreas Gohr if ($attributes["change_password"]){ $mod["pwdLastSet"][0]=0; } 81776ce1169SAndreas Gohr if ($attributes["department"]){ $mod["department"][0]=$attributes["department"]; } 81876ce1169SAndreas Gohr if ($attributes["description"]){ $mod["description"][0]=$attributes["description"]; } 81976ce1169SAndreas Gohr if ($attributes["display_name"]){ $mod["displayName"][0]=$attributes["display_name"]; } 82076ce1169SAndreas Gohr if ($attributes["email"]){ $mod["mail"][0]=$attributes["email"]; } 82176ce1169SAndreas Gohr if ($attributes["expires"]){ $mod["accountExpires"][0]=$attributes["expires"]; } //unix epoch format? 82276ce1169SAndreas Gohr if ($attributes["firstname"]){ $mod["givenName"][0]=$attributes["firstname"]; } 82376ce1169SAndreas Gohr if ($attributes["home_directory"]){ $mod["homeDirectory"][0]=$attributes["home_directory"]; } 82476ce1169SAndreas Gohr if ($attributes["home_drive"]){ $mod["homeDrive"][0]=$attributes["home_drive"]; } 82576ce1169SAndreas Gohr if ($attributes["initials"]){ $mod["initials"][0]=$attributes["initials"]; } 82676ce1169SAndreas Gohr if ($attributes["logon_name"]){ $mod["userPrincipalName"][0]=$attributes["logon_name"]; } 82776ce1169SAndreas Gohr if ($attributes["manager"]){ $mod["manager"][0]=$attributes["manager"]; } //UNTESTED ***Use DistinguishedName*** 82876ce1169SAndreas Gohr if ($attributes["office"]){ $mod["physicalDeliveryOfficeName"][0]=$attributes["office"]; } 82976ce1169SAndreas Gohr if ($attributes["password"]){ $mod["unicodePwd"][0]=$this->user()->encodePassword($attributes["password"]); } 83076ce1169SAndreas Gohr if ($attributes["profile_path"]){ $mod["profilepath"][0]=$attributes["profile_path"]; } 83176ce1169SAndreas Gohr if ($attributes["script_path"]){ $mod["scriptPath"][0]=$attributes["script_path"]; } 83276ce1169SAndreas Gohr if ($attributes["surname"]){ $mod["sn"][0]=$attributes["surname"]; } 83376ce1169SAndreas Gohr if ($attributes["title"]){ $mod["title"][0]=$attributes["title"]; } 83476ce1169SAndreas Gohr if ($attributes["telephone"]){ $mod["telephoneNumber"][0]=$attributes["telephone"]; } 83576ce1169SAndreas Gohr if ($attributes["mobile"]){ $mod["mobile"][0]=$attributes["mobile"]; } 83676ce1169SAndreas Gohr if ($attributes["pager"]){ $mod["pager"][0]=$attributes["pager"]; } 83776ce1169SAndreas Gohr if ($attributes["ipphone"]){ $mod["ipphone"][0]=$attributes["ipphone"]; } 83876ce1169SAndreas Gohr if ($attributes["web_page"]){ $mod["wWWHomePage"][0]=$attributes["web_page"]; } 83976ce1169SAndreas Gohr if ($attributes["fax"]){ $mod["facsimileTelephoneNumber"][0]=$attributes["fax"]; } 84076ce1169SAndreas Gohr if ($attributes["enabled"]){ $mod["userAccountControl"][0]=$attributes["enabled"]; } 84176ce1169SAndreas Gohr if ($attributes["homephone"]){ $mod["homephone"][0]=$attributes["homephone"]; } 84276ce1169SAndreas Gohr 84376ce1169SAndreas Gohr // Distribution List specific schema 84476ce1169SAndreas Gohr if ($attributes["group_sendpermission"]){ $mod["dlMemSubmitPerms"][0]=$attributes["group_sendpermission"]; } 84576ce1169SAndreas Gohr if ($attributes["group_rejectpermission"]){ $mod["dlMemRejectPerms"][0]=$attributes["group_rejectpermission"]; } 84676ce1169SAndreas Gohr 84776ce1169SAndreas Gohr // Exchange Schema 84876ce1169SAndreas Gohr if ($attributes["exchange_homemdb"]){ $mod["homeMDB"][0]=$attributes["exchange_homemdb"]; } 84976ce1169SAndreas Gohr if ($attributes["exchange_mailnickname"]){ $mod["mailNickname"][0]=$attributes["exchange_mailnickname"]; } 85076ce1169SAndreas Gohr if ($attributes["exchange_proxyaddress"]){ $mod["proxyAddresses"][0]=$attributes["exchange_proxyaddress"]; } 85176ce1169SAndreas Gohr if ($attributes["exchange_usedefaults"]){ $mod["mDBUseDefaults"][0]=$attributes["exchange_usedefaults"]; } 85276ce1169SAndreas Gohr if ($attributes["exchange_policyexclude"]){ $mod["msExchPoliciesExcluded"][0]=$attributes["exchange_policyexclude"]; } 85376ce1169SAndreas Gohr if ($attributes["exchange_policyinclude"]){ $mod["msExchPoliciesIncluded"][0]=$attributes["exchange_policyinclude"]; } 85476ce1169SAndreas Gohr if ($attributes["exchange_addressbook"]){ $mod["showInAddressBook"][0]=$attributes["exchange_addressbook"]; } 85576ce1169SAndreas Gohr if ($attributes["exchange_altrecipient"]){ $mod["altRecipient"][0]=$attributes["exchange_altrecipient"]; } 85676ce1169SAndreas Gohr if ($attributes["exchange_deliverandredirect"]){ $mod["deliverAndRedirect"][0]=$attributes["exchange_deliverandredirect"]; } 85776ce1169SAndreas Gohr 85876ce1169SAndreas Gohr // This schema is designed for contacts 85976ce1169SAndreas Gohr if ($attributes["exchange_hidefromlists"]){ $mod["msExchHideFromAddressLists"][0]=$attributes["exchange_hidefromlists"]; } 86076ce1169SAndreas Gohr if ($attributes["contact_email"]){ $mod["targetAddress"][0]=$attributes["contact_email"]; } 86176ce1169SAndreas Gohr 86276ce1169SAndreas Gohr //echo ("<pre>"); print_r($mod); 86376ce1169SAndreas Gohr /* 86476ce1169SAndreas Gohr // modifying a name is a bit fiddly 86576ce1169SAndreas Gohr if ($attributes["firstname"] && $attributes["surname"]){ 86676ce1169SAndreas Gohr $mod["cn"][0]=$attributes["firstname"]." ".$attributes["surname"]; 86776ce1169SAndreas Gohr $mod["displayname"][0]=$attributes["firstname"]." ".$attributes["surname"]; 86876ce1169SAndreas Gohr $mod["name"][0]=$attributes["firstname"]." ".$attributes["surname"]; 86976ce1169SAndreas Gohr } 87076ce1169SAndreas Gohr */ 87176ce1169SAndreas Gohr 87276ce1169SAndreas Gohr if (count($mod)==0){ return (false); } 87376ce1169SAndreas Gohr return ($mod); 87476ce1169SAndreas Gohr } 87576ce1169SAndreas Gohr 87676ce1169SAndreas Gohr /** 87776ce1169SAndreas Gohr * Convert 8bit characters e.g. accented characters to UTF8 encoded characters 87876ce1169SAndreas Gohr */ 87976ce1169SAndreas Gohr protected function encode8Bit(&$item, $key) { 88076ce1169SAndreas Gohr $encode = false; 88176ce1169SAndreas Gohr if (is_string($item)) { 88276ce1169SAndreas Gohr for ($i=0; $i<strlen($item); $i++) { 88376ce1169SAndreas Gohr if (ord($item[$i]) >> 7) { 88476ce1169SAndreas Gohr $encode = true; 88576ce1169SAndreas Gohr } 88676ce1169SAndreas Gohr } 88776ce1169SAndreas Gohr } 88876ce1169SAndreas Gohr if ($encode === true && $key != 'password') { 88976ce1169SAndreas Gohr $item = utf8_encode($item); 89076ce1169SAndreas Gohr } 89176ce1169SAndreas Gohr } 89276ce1169SAndreas Gohr 89376ce1169SAndreas Gohr /** 89476ce1169SAndreas Gohr * Select a random domain controller from your domain controller array 89576ce1169SAndreas Gohr * 89676ce1169SAndreas Gohr * @return string 89776ce1169SAndreas Gohr */ 89876ce1169SAndreas Gohr protected function randomController() 89976ce1169SAndreas Gohr { 90076ce1169SAndreas Gohr mt_srand(doubleval(microtime()) * 100000000); // For older PHP versions 90176ce1169SAndreas Gohr /*if (sizeof($this->domainControllers) > 1) { 90276ce1169SAndreas Gohr $adController = $this->domainControllers[array_rand($this->domainControllers)]; 90376ce1169SAndreas Gohr // Test if the controller is responding to pings 90476ce1169SAndreas Gohr $ping = $this->pingController($adController); 90576ce1169SAndreas Gohr if ($ping === false) { 90676ce1169SAndreas Gohr // Find the current key in the domain controllers array 90776ce1169SAndreas Gohr $key = array_search($adController, $this->domainControllers); 90876ce1169SAndreas Gohr // Remove it so that we don't end up in a recursive loop 90976ce1169SAndreas Gohr unset($this->domainControllers[$key]); 91076ce1169SAndreas Gohr // Select a new controller 91176ce1169SAndreas Gohr return $this->randomController(); 91276ce1169SAndreas Gohr } 91376ce1169SAndreas Gohr else { 91476ce1169SAndreas Gohr return ($adController); 91576ce1169SAndreas Gohr } 91676ce1169SAndreas Gohr } */ 91776ce1169SAndreas Gohr return $this->domainControllers[array_rand($this->domainControllers)]; 91876ce1169SAndreas Gohr } 91976ce1169SAndreas Gohr 92076ce1169SAndreas Gohr /** 92176ce1169SAndreas Gohr * Test basic connectivity to controller 92276ce1169SAndreas Gohr * 92376ce1169SAndreas Gohr * @return bool 92476ce1169SAndreas Gohr */ 92576ce1169SAndreas Gohr protected function pingController($host) { 92676ce1169SAndreas Gohr $port = $this->adPort; 92776ce1169SAndreas Gohr fsockopen($host, $port, $errno, $errstr, 10); 92876ce1169SAndreas Gohr if ($errno > 0) { 92976ce1169SAndreas Gohr return false; 93076ce1169SAndreas Gohr } 93176ce1169SAndreas Gohr return true; 93276ce1169SAndreas Gohr } 93376ce1169SAndreas Gohr 93476ce1169SAndreas Gohr} 93576ce1169SAndreas Gohr 93676ce1169SAndreas Gohr/** 93776ce1169SAndreas Gohr* adLDAP Exception Handler 93876ce1169SAndreas Gohr* 93976ce1169SAndreas Gohr* Exceptions of this type are thrown on bind failure or when SSL is required but not configured 94076ce1169SAndreas Gohr* Example: 94176ce1169SAndreas Gohr* try { 94276ce1169SAndreas Gohr* $adldap = new adLDAP(); 94376ce1169SAndreas Gohr* } 94476ce1169SAndreas Gohr* catch (adLDAPException $e) { 94576ce1169SAndreas Gohr* echo $e; 94676ce1169SAndreas Gohr* exit(); 94776ce1169SAndreas Gohr* } 94876ce1169SAndreas Gohr*/ 94976ce1169SAndreas Gohrclass adLDAPException extends Exception {} 950