diff --git a/composer.json b/composer.json index 672316b..73a7e77 100644 --- a/composer.json +++ b/composer.json @@ -1,10 +1,10 @@ { - "name": "adldap/adldap", + "name": "suqld/adldap", "type": "library", "description": "adLDAP, low-level library to query Active directory", "keywords": ["active directory","ldap","windows"], - "homepage": "http://adldap.sourceforge.net", - "license": "GNU", + "homepage": "https://github.com/suqld/adLDAP/", + "license": "LGPL", "authors": [ { "name": "Richard Hyland" diff --git a/lib/adLDAP/adLDAP.php b/lib/adLDAP/adLDAP.php index a692ead..8101d11 100644 --- a/lib/adLDAP/adLDAP.php +++ b/lib/adLDAP/adLDAP.php @@ -85,7 +85,7 @@ class adLDAP { * * @var string */ - protected $accountSuffix = "@mydomain.local"; + protected $accountSuffix = "@mydomain.local"; /** * The base dn for your domain @@ -94,7 +94,7 @@ class adLDAP { * * @var string */ - protected $baseDn = "DC=mydomain,DC=local"; + protected $baseDn = "DC=mydomain,DC=local"; /** * Port used to talk to the domain controllers. @@ -102,7 +102,7 @@ class adLDAP { * @var int */ protected $adPort = self::ADLDAP_LDAP_PORT; - + /** * Array of domain controllers. Specifiy multiple controllers if you * would like the class to balance the LDAP queries amongst multiple servers @@ -110,7 +110,7 @@ class adLDAP { * @var array */ protected $domainControllers = array("dc01.mydomain.local"); - + /** * Optional account with higher privileges for searching * This should be set to a domain admin account @@ -118,7 +118,7 @@ class adLDAP { * @var string * @var string */ - protected $adminUsername = null; + protected $adminUsername = null; protected $adminPassword = null; /** @@ -129,15 +129,15 @@ class adLDAP { * * @var bool */ - protected $realPrimaryGroup = true; - + protected $realPrimaryGroup = true; + /** * Use SSL (LDAPS), your server needs to be setup, please see * http://adldap.sourceforge.net/wiki/doku.php?id=ldap_over_ssl * * @var bool */ - protected $useSSL = false; + protected $useSSL = false; /** * Use TLS @@ -162,19 +162,19 @@ class adLDAP { * * @var bool */ - protected $recursiveGroups = true; - - // You should not need to edit anything below this line - //****************************************************************************************** - - /** + protected $recursiveGroups = true; + + // You should not need to edit anything below this line + //****************************************************************************************** + + /** * Connection and bind default variables * * @var mixed * @var mixed */ - protected $ldapConnection; - protected $ldapBind; + protected $ldapConnection; + protected $ldapBind; /** * Get the active LDAP Connection @@ -799,66 +799,64 @@ protected function ldapSaslSupported() public function adldap_schema($attributes){ // LDAP doesn't like NULL attributes, only set them if they have values - // If you wish to remove an attribute you should set it to a space - // TO DO: Adapt user_modify to use ldap_mod_delete to remove a NULL attribute $mod=array(); // Check every attribute to see if it contains 8bit characters and then UTF8 encode them array_walk($attributes, array($this, 'encode8bit')); - if ($attributes["address_city"]){ $mod["l"][0]=$attributes["address_city"]; } - if ($attributes["address_code"]){ $mod["postalCode"][0]=$attributes["address_code"]; } - //if ($attributes["address_country"]){ $mod["countryCode"][0]=$attributes["address_country"]; } // use country codes? - if ($attributes["address_country"]){ $mod["c"][0]=$attributes["address_country"]; } - if ($attributes["address_pobox"]){ $mod["postOfficeBox"][0]=$attributes["address_pobox"]; } - if ($attributes["address_state"]){ $mod["st"][0]=$attributes["address_state"]; } - if ($attributes["address_street"]){ $mod["streetAddress"][0]=$attributes["address_street"]; } - if ($attributes["company"]){ $mod["company"][0]=$attributes["company"]; } - if ($attributes["change_password"]){ $mod["pwdLastSet"][0]=0; } - if ($attributes["department"]){ $mod["department"][0]=$attributes["department"]; } - if ($attributes["description"]){ $mod["description"][0]=$attributes["description"]; } - if ($attributes["display_name"]){ $mod["displayName"][0]=$attributes["display_name"]; } - if ($attributes["email"]){ $mod["mail"][0]=$attributes["email"]; } - if ($attributes["expires"]){ $mod["accountExpires"][0]=$attributes["expires"]; } //unix epoch format? - if ($attributes["firstname"]){ $mod["givenName"][0]=$attributes["firstname"]; } - if ($attributes["home_directory"]){ $mod["homeDirectory"][0]=$attributes["home_directory"]; } - if ($attributes["home_drive"]){ $mod["homeDrive"][0]=$attributes["home_drive"]; } - if ($attributes["initials"]){ $mod["initials"][0]=$attributes["initials"]; } - if ($attributes["logon_name"]){ $mod["userPrincipalName"][0]=$attributes["logon_name"]; } - if ($attributes["manager"]){ $mod["manager"][0]=$attributes["manager"]; } //UNTESTED ***Use DistinguishedName*** - if ($attributes["office"]){ $mod["physicalDeliveryOfficeName"][0]=$attributes["office"]; } - if ($attributes["password"]){ $mod["unicodePwd"][0]=$this->user()->encodePassword($attributes["password"]); } - if ($attributes["profile_path"]){ $mod["profilepath"][0]=$attributes["profile_path"]; } - if ($attributes["script_path"]){ $mod["scriptPath"][0]=$attributes["script_path"]; } - if ($attributes["surname"]){ $mod["sn"][0]=$attributes["surname"]; } - if ($attributes["title"]){ $mod["title"][0]=$attributes["title"]; } - if ($attributes["telephone"]){ $mod["telephoneNumber"][0]=$attributes["telephone"]; } - if ($attributes["mobile"]){ $mod["mobile"][0]=$attributes["mobile"]; } - if ($attributes["pager"]){ $mod["pager"][0]=$attributes["pager"]; } - if ($attributes["ipphone"]){ $mod["ipphone"][0]=$attributes["ipphone"]; } - if ($attributes["web_page"]){ $mod["wWWHomePage"][0]=$attributes["web_page"]; } - if ($attributes["fax"]){ $mod["facsimileTelephoneNumber"][0]=$attributes["fax"]; } - if ($attributes["enabled"]){ $mod["userAccountControl"][0]=$attributes["enabled"]; } - if ($attributes["homephone"]){ $mod["homephone"][0]=$attributes["homephone"]; } + if (array_key_exists("address_city", $attributes)){ $mod["l"][0]=$attributes["address_city"]; } + if (array_key_exists("address_code", $attributes)){ $mod["postalCode"][0]=$attributes["address_code"]; } + //if (array_key_exists("address_country", $attributes)){ $mod["countryCode"][0]=$attributes["address_country"]; } // use country codes? + if (array_key_exists("address_country", $attributes)){ $mod["c"][0]=$attributes["address_country"]; } + if (array_key_exists("address_pobox", $attributes)){ $mod["postOfficeBox"][0]=$attributes["address_pobox"]; } + if (array_key_exists("address_state", $attributes)){ $mod["st"][0]=$attributes["address_state"]; } + if (array_key_exists("address_street", $attributes)){ $mod["streetAddress"][0]=$attributes["address_street"]; } + if (array_key_exists("company", $attributes)){ $mod["company"][0]=$attributes["company"]; } + if (array_key_exists("change_password", $attributes)){ $mod["pwdLastSet"][0]=0; } + if (array_key_exists("department", $attributes)){ $mod["department"][0]=$attributes["department"]; } + if (array_key_exists("description", $attributes)){ $mod["description"][0]=$attributes["description"]; } + if (array_key_exists("display_name", $attributes)){ $mod["displayName"][0]=$attributes["display_name"]; } + if (array_key_exists("email", $attributes)){ $mod["mail"][0]=$attributes["email"]; } + if (array_key_exists("expires", $attributes)){ $mod["accountExpires"][0]=$attributes["expires"]; } //unix epoch format? + if (array_key_exists("firstname", $attributes)){ $mod["givenName"][0]=$attributes["firstname"]; } + if (array_key_exists("home_directory", $attributes)){ $mod["homeDirectory"][0]=$attributes["home_directory"]; } + if (array_key_exists("home_drive", $attributes)){ $mod["homeDrive"][0]=$attributes["home_drive"]; } + if (array_key_exists("initials", $attributes)){ $mod["initials"][0]=$attributes["initials"]; } + if (array_key_exists("logon_name", $attributes)){ $mod["userPrincipalName"][0]=$attributes["logon_name"]; } + if (array_key_exists("manager", $attributes)){ $mod["manager"][0]=$attributes["manager"]; } //UNTESTED ***Use DistinguishedName*** + if (array_key_exists("office", $attributes)){ $mod["physicalDeliveryOfficeName"][0]=$attributes["office"]; } + if (array_key_exists("password", $attributes)){ $mod["unicodePwd"][0]=$this->user()->encodePassword($attributes["password"]); } + if (array_key_exists("profile_path", $attributes)){ $mod["profilepath"][0]=$attributes["profile_path"]; } + if (array_key_exists("script_path", $attributes)){ $mod["scriptPath"][0]=$attributes["script_path"]; } + if (array_key_exists("surname", $attributes)){ $mod["sn"][0]=$attributes["surname"]; } + if (array_key_exists("title", $attributes)){ $mod["title"][0]=$attributes["title"]; } + if (array_key_exists("telephone", $attributes)){ $mod["telephoneNumber"][0]=$attributes["telephone"]; } + if (array_key_exists("mobile", $attributes)){ $mod["mobile"][0]=$attributes["mobile"]; } + if (array_key_exists("pager", $attributes)){ $mod["pager"][0]=$attributes["pager"]; } + if (array_key_exists("ipphone", $attributes)){ $mod["ipphone"][0]=$attributes["ipphone"]; } + if (array_key_exists("web_page", $attributes)){ $mod["wWWHomePage"][0]=$attributes["web_page"]; } + if (array_key_exists("fax", $attributes)){ $mod["facsimileTelephoneNumber"][0]=$attributes["fax"]; } + if (array_key_exists("enabled", $attributes)){ $mod["userAccountControl"][0]=$attributes["enabled"]; } + if (array_key_exists("homephone", $attributes)){ $mod["homephone"][0]=$attributes["homephone"]; } // Distribution List specific schema - if ($attributes["group_sendpermission"]){ $mod["dlMemSubmitPerms"][0]=$attributes["group_sendpermission"]; } - if ($attributes["group_rejectpermission"]){ $mod["dlMemRejectPerms"][0]=$attributes["group_rejectpermission"]; } + if (array_key_exists("group_sendpermission", $attributes)){ $mod["dlMemSubmitPerms"][0]=$attributes["group_sendpermission"]; } + if (array_key_exists("group_rejectpermission", $attributes)){ $mod["dlMemRejectPerms"][0]=$attributes["group_rejectpermission"]; } // Exchange Schema - if ($attributes["exchange_homemdb"]){ $mod["homeMDB"][0]=$attributes["exchange_homemdb"]; } - if ($attributes["exchange_mailnickname"]){ $mod["mailNickname"][0]=$attributes["exchange_mailnickname"]; } - if ($attributes["exchange_proxyaddress"]){ $mod["proxyAddresses"][0]=$attributes["exchange_proxyaddress"]; } - if ($attributes["exchange_usedefaults"]){ $mod["mDBUseDefaults"][0]=$attributes["exchange_usedefaults"]; } - if ($attributes["exchange_policyexclude"]){ $mod["msExchPoliciesExcluded"][0]=$attributes["exchange_policyexclude"]; } - if ($attributes["exchange_policyinclude"]){ $mod["msExchPoliciesIncluded"][0]=$attributes["exchange_policyinclude"]; } - if ($attributes["exchange_addressbook"]){ $mod["showInAddressBook"][0]=$attributes["exchange_addressbook"]; } - if ($attributes["exchange_altrecipient"]){ $mod["altRecipient"][0]=$attributes["exchange_altrecipient"]; } - if ($attributes["exchange_deliverandredirect"]){ $mod["deliverAndRedirect"][0]=$attributes["exchange_deliverandredirect"]; } + if (array_key_exists("exchange_homemdb", $attributes)){ $mod["homeMDB"][0]=$attributes["exchange_homemdb"]; } + if (array_key_exists("exchange_mailnickname", $attributes)){ $mod["mailNickname"][0]=$attributes["exchange_mailnickname"]; } + if (array_key_exists("exchange_proxyaddress", $attributes)){ $mod["proxyAddresses"][0]=$attributes["exchange_proxyaddress"]; } + if (array_key_exists("exchange_usedefaults", $attributes)){ $mod["mDBUseDefaults"][0]=$attributes["exchange_usedefaults"]; } + if (array_key_exists("exchange_policyexclude", $attributes)){ $mod["msExchPoliciesExcluded"][0]=$attributes["exchange_policyexclude"]; } + if (array_key_exists("exchange_policyinclude", $attributes)){ $mod["msExchPoliciesIncluded"][0]=$attributes["exchange_policyinclude"]; } + if (array_key_exists("exchange_addressbook", $attributes)){ $mod["showInAddressBook"][0]=$attributes["exchange_addressbook"]; } + if (array_key_exists("exchange_altrecipient", $attributes)){ $mod["altRecipient"][0]=$attributes["exchange_altrecipient"]; } + if (array_key_exists("exchange_deliverandredirect", $attributes)){ $mod["deliverAndRedirect"][0]=$attributes["exchange_deliverandredirect"]; } // This schema is designed for contacts - if ($attributes["exchange_hidefromlists"]){ $mod["msExchHideFromAddressLists"][0]=$attributes["exchange_hidefromlists"]; } - if ($attributes["contact_email"]){ $mod["targetAddress"][0]=$attributes["contact_email"]; } + if (array_key_exists("exchange_hidefromlists", $attributes)){ $mod["msExchHideFromAddressLists"][0]=$attributes["exchange_hidefromlists"]; } + if (array_key_exists("contact_email", $attributes)){ $mod["targetAddress"][0]=$attributes["contact_email"]; } //echo ("
"); print_r($mod);
         /*
@@ -870,8 +868,19 @@ public function adldap_schema($attributes){
         }
         */
 
-        if (count($mod)==0){ return (false); }
-        return ($mod);
+        // Filter out attributes that are NULL so we can ldap_mod_del them 
+        // instead
+        $del = array();
+        foreach ($mod as $attribute => $value) {
+            if ($value[0] == '') {
+                $del[$attribute] = array();
+                unset($mod[$attribute]);
+            }
+        }
+
+        if (count($mod)==0){ $mod = false; }
+        if (count($del)==0){ $del = false; }
+        return (array($mod, $del));
     }
     
     /**
@@ -949,4 +958,4 @@ protected function pingController($host) {
 */
 class adLDAPException extends \Exception {}
 
-?>
\ No newline at end of file
+?>
diff --git a/lib/adLDAP/classes/adLDAPContacts.php b/lib/adLDAP/classes/adLDAPContacts.php
index ccf2356..c56a745 100644
--- a/lib/adLDAP/classes/adLDAPContacts.php
+++ b/lib/adLDAP/classes/adLDAPContacts.php
@@ -71,7 +71,7 @@ public function create($attributes)
         if (!is_array($attributes["container"])) { return "Container attribute must be an array."; }
 
         // Translate the schema
-        $add = $this->adldap->adldap_schema($attributes);
+        list($add, ) = $this->adldap->adldap_schema($attributes);
         
         // Additional stuff only used for adding contacts
         $add["cn"][0] = $attributes["display_name"];
@@ -217,14 +217,24 @@ public function modify($distinguishedName, $attributes) {
         $mod = $this->adldap->adldap_schema($attributes);
         
         // Check to see if this is an enabled status update
-        if (!$mod) { 
+        if (!$mod && !$del) { 
             return false;
         }
+
+        // Do the Delete updates
+        if ($del) {
+            $result = @ldap_mod_del($this->adldap->getLdapConnection(), $distinguishedName, $del);
+            if ($result == false) {
+                return false;
+            }    
+        }
         
         // Do the update
-        $result = ldap_modify($this->adldap->getLdapConnection(), $distinguishedName, $mod);
-        if ($result == false) {
-            return false;
+        if ($mod) {
+            $result = ldap_modify($this->adldap->getLdapConnection(), $distinguishedName, $mod);
+            if ($result == false) {
+                return false;
+            }
         }
         
         return true;
diff --git a/lib/adLDAP/classes/adLDAPExchange.php b/lib/adLDAP/classes/adLDAPExchange.php
index b36813f..7476e4c 100644
--- a/lib/adLDAP/classes/adLDAPExchange.php
+++ b/lib/adLDAP/classes/adLDAPExchange.php
@@ -127,7 +127,7 @@ public function addX400($username, $country, $admd, $pdmd, $org, $surname, $give
         $attributes['exchange_proxyaddress'] = $proxyValue . 'c=' . $country . ';a=' . $admd . ';p=' . $pdmd . ';o=' . $org . ';s=' . $surname . ';g=' . $givenName . ';';
        
         // Translate the update to the LDAP schema                
-        $add = $this->adldap->adldap_schema($attributes);
+        list ($add,) = $this->adldap->adldap_schema($attributes);
         
         if (!$add) { return false; }
         
@@ -191,7 +191,7 @@ public function addAddress($username, $emailAddress, $default = FALSE, $isGUID =
             $attributes['exchange_proxyaddress'] = $proxyValue . $emailAddress;
             
             // Translate the update to the LDAP schema                
-            $add = $this->adldap->adldap_schema($attributes);
+            list ($add,) = $this->adldap->adldap_schema($attributes);
             
             if (!$add) { 
                 return false; 
@@ -317,14 +317,24 @@ public function contactMailEnable($distinguishedName, $emailAddress, $mailNickna
         $attributes = array("email"=>$emailAddress,"contact_email"=>"SMTP:" . $emailAddress,"exchange_proxyaddress"=>"SMTP:" . $emailAddress,"exchange_mailnickname" => $mailNickname);
          
         // Translate the update to the LDAP schema                
-        $mod = $this->adldap->adldap_schema($attributes);
+        list($mod, $del) = $this->adldap->adldap_schema($attributes);
         
         // Check to see if this is an enabled status update
-        if (!$mod) { return false; }
+        if (!$mod && !$del) { return false; }
+
+        // Do the Delete updates
+        if ($del){
+            $result = @ldap_mod_del($this->adldap->getLdapConnection(), $userDn, $del);
+            if ($result == false) {
+                return false;
+            }
+        }
         
         // Do the update
-        $result = ldap_modify($this->adldap->getLdapConnection(), $distinguishedName, $mod);
-        if ($result == false) { return false; }
+        if ($mod) {
+            $result = ldap_modify($this->adldap->getLdapConnection(), $distinguishedName, $mod);
+            if ($result == false) { return false; }
+        }
         
         return true;
     }
@@ -389,4 +399,4 @@ public function storageDatabases($storageGroup, $attributes = array('cn','distin
         return $entries;
     }
 }
-?>
\ No newline at end of file
+?>
diff --git a/lib/adLDAP/classes/adLDAPGroups.php b/lib/adLDAP/classes/adLDAPGroups.php
index 1aea568..feb1e97 100644
--- a/lib/adLDAP/classes/adLDAPGroups.php
+++ b/lib/adLDAP/classes/adLDAPGroups.php
@@ -362,6 +362,12 @@ public function members($group, $recursive = null)
         if ($recursive === null){ $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it
         // Search the directory for the members of a group
         $info = $this->info($group, array("member","cn"));
+
+        if(!array_key_exists("member", $info[0]))
+        {
+            return false;
+        }
+
         $users = $info[0]["member"];
         if (!is_array($users)) {
             return false;
@@ -422,7 +428,9 @@ public function info($groupName, $fields = null)
             $groupName = stripslashes($groupName);   
         }
         
-        $filter = "(&(objectCategory=group)(name=" . $this->adldap->utilities()->ldapSlashes($groupName) . "))";
+        $filter = "(&(objectCategory=group)";
+        $filter .= "(|(samaccountname=".$this->adldap->utilities()->ldapSlashes($groupName).")";
+        $filter .= "(name=".$this->adldap->utilities()->ldapSlashes($groupName).")))";
         if ($fields === null) {
             $fields = array("member","memberof","cn","description","distinguishedname","objectcategory","samaccountname"); 
         }
@@ -513,9 +521,9 @@ public function search($sAMAaccountType = adLDAP::ADLDAP_SECURITY_GLOBAL_GROUP,
         $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
         $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
 
-        $groupsArray = array();        
+        $groupsArray = array();
         for ($i=0; $i<$entries["count"]; $i++){
-            if ($includeDescription && strlen($entries[$i]["description"][0]) > 0 ) {
+            if ($includeDescription && array_key_exists("description", $entries[$i]) && ($entries[$i]["description"][0]) > 0 ) {
                 $groupsArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["description"][0];
             }
             else if ($includeDescription){
diff --git a/lib/adLDAP/classes/adLDAPUsers.php b/lib/adLDAP/classes/adLDAPUsers.php
index 12d765e..0fed359 100644
--- a/lib/adLDAP/classes/adLDAPUsers.php
+++ b/lib/adLDAP/classes/adLDAPUsers.php
@@ -93,7 +93,7 @@ public function create($attributes)
         }
 
         // Translate the schema
-        $add = $this->adldap->adldap_schema($attributes);
+        list($add, ) = $this->adldap->adldap_schema($attributes);
         
         // Additional stuff only used for adding accounts
         $add["cn"][0] = $attributes["display_name"];
@@ -405,10 +405,10 @@ public function modify($username, $attributes, $isGUID = false)
         }
         
         // Translate the update to the LDAP schema                
-        $mod = $this->adldap->adldap_schema($attributes);
+        list ($mod, $del) = $this->adldap->adldap_schema($attributes);
         
         // Check to see if this is an enabled status update
-        if (!$mod && !array_key_exists("enabled", $attributes)){ 
+        if (!$mod && !$del && !array_key_exists("enabled", $attributes)){ 
             return false;
         }
         
@@ -423,10 +423,20 @@ public function modify($username, $attributes, $isGUID = false)
             $mod["userAccountControl"][0] = $this->accountControl($controlOptions);
         }
 
+        // Do the Delete updates
+        if ($del) {
+            $result = @ldap_mod_del($this->adldap->getLdapConnection(), $userDn, $del);
+            if ($result == false) {
+                return false;
+            }
+        }
+
         // Do the update
-        $result = @ldap_modify($this->adldap->getLdapConnection(), $userDn, $mod);
-        if ($result == false) {
-            return false;
+        if ($mod) {
+            $result = @ldap_modify($this->adldap->getLdapConnection(), $userDn, $mod);
+            if ($result == false) {
+                return false;
+            }
         }
         
         return true;
diff --git a/lib/adLDAP/classes/adLDAPUtils.php b/lib/adLDAP/classes/adLDAPUtils.php
index 3d0290c..d2fc287 100644
--- a/lib/adLDAP/classes/adLDAPUtils.php
+++ b/lib/adLDAP/classes/adLDAPUtils.php
@@ -68,16 +68,21 @@ public function niceNames($groups)
         $groupArray = array();
         for ($i=0; $i<$groups["count"]; $i++){ // For each group
             $line = $groups[$i];
-            
+
             if (strlen($line)>0) { 
-                // More presumptions, they're all prefixed with CN=
-                // so we ditch the first three characters and the group
-                // name goes up to the first comma
-                $bits=explode(",", $line);
-                $groupArray[] = substr($bits[0], 3, (strlen($bits[0])-3));
+                $fields = array("samaccountname");
+                $filter = "(&(objectCategory=group)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($groups[$i]) . "))";
+                $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+                $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+                if (!isset($entries[0]['samaccountname'][0])) {
+                    continue;  
+                }
+
+                $groupArray[] = $entries[0]['samaccountname'][0];
             }
         }
-        return $groupArray;    
+        return $groupArray;
     }
     
     /**
@@ -263,4 +268,4 @@ public static function convertWindowsTimeToUnixTime($windowsTime) {
     }
 }
 
-?>
\ No newline at end of file
+?>