diff options
Diffstat (limited to 'lib/Auth/LDAP.php')
-rw-r--r-- | lib/Auth/LDAP.php | 690 |
1 files changed, 512 insertions, 178 deletions
diff --git a/lib/Auth/LDAP.php b/lib/Auth/LDAP.php index bcd3491..7146f71 100644 --- a/lib/Auth/LDAP.php +++ b/lib/Auth/LDAP.php @@ -72,7 +72,7 @@ class LDAP $domain = $_SESSION['user']->get_domain(); } catch (Exception $e) { // TODO: Debug logging - error_log("Warning, user not authenticated yet"); + //console("Warning, user not authenticated yet"); } } } @@ -128,7 +128,7 @@ class LDAP */ public function authenticate($username, $password) { - error_log("LDAP authentication request for $username"); + //console("LDAP authentication request for $username"); if (!$this->_connect()) { return false; @@ -189,17 +189,17 @@ class LDAP $_SESSION['user']->user_root_dn = $root_dn; $_SESSION['user']->user_bind_dn = $subject_dn; $_SESSION['user']->user_bind_pw = $password; - error_log("Successfully bound with User DN: " . $_SESSION['user']->user_bind_dn); + //console("Successfully bound with User DN: " . $_SESSION['user']->user_bind_dn); } else { - error_log("Successfully bound with User DN: " . $subject_dn . " but not saving it to the session"); + //console("Successfully bound with User DN: " . $subject_dn . " but not saving it to the session"); } // @TODO: return unique attribute return $subject_dn; } else { - error_log("LDAP Error: " . $this->_errstr()); + //console("LDAP Error: " . $this->_errstr()); return false; } } @@ -236,7 +236,7 @@ class LDAP } } } else { - error_log("No schema details exist for attribute $attribute (which is strange)"); + //console("No schema details exist for attribute $attribute (which is strange)"); } // The relevant parts only, please @@ -292,17 +292,71 @@ class LDAP } - public function domain_add($domain, $domain_alias = false, $prepopulate = true) + public function domain_add($domain, $parent_domain = false, $prepopulate = true) { // Apply some routines for access control to this function here. - if ($domain_alias) { - return $this->_domain_add_alias($domain, $domain_alias); + if (!empty($parent_domain)) { + return $this->_domain_add_alias($domain, $parent_domain); } else { return $this->_domain_add_new($domain, $prepopulate); } } + public function domain_edit($domain, $attributes, $typeid = null) + { + // Domain identifier + $unique_attr = $this->unique_attribute(); + $attributes[$unique_attr] = $domain; + + // Now that values have been re-generated where necessary, compare + // the new domain attributes to the original domain attributes. + $_domain = $this->domain_find_by_attribute(array($unique_attr => $attributes[$unique_attr])); + + if (!$_domain) { + //console("Could not find domain"); + return false; + } + + $_domain_dn = key($_domain); + $_domain = $this->domain_info($_domain_dn, array_keys($attributes)); + + // We should start throwing stuff over the fence here. + return $this->modify_entry($_domain_dn, $_domain[$_domain_dn], $attributes); + } + + public function domain_find_by_attribute($attribute) + { + $conf = Conf::get_instance(); + $base_dn = $conf->get('ldap', 'domain_base_dn'); + return $this->entry_find_by_attribute($attribute, $base_dn); + } + + public function domain_info($domain, $attributes = array('*')) + { + $conf = Conf::get_instance(); + + $domain_dn = $this->entry_dn($domain); + + if (!$domain_dn) { + $domain_base_dn = $conf->get('ldap', 'domain_base_dn'); + $domain_filter = $conf->get('ldap', 'domain_filter'); + $domain_name_attribute = $conf->get('ldap', 'domain_name_attribute'); + $domain_filter = "(&$domain_filter($domain_name_attribute=$domain))"; + $result = self::normalize_result($this->_search($domain_base_dn, $domain_filter, $attributes)); + } else { + $result = self::normalize_result($this->_search($domain_dn, '(objectclass=*)', $attributes)); + } + + if (!$result) { + return false; + } + + //console("domain_info() result:", $result); + + return $result; + } + public function effective_rights($subject) { $effective_rights_control_oid = "1.3.6.1.4.1.42.2.27.9.5.2"; @@ -310,7 +364,7 @@ class LDAP $supported_controls = $this->supported_controls(); if (!in_array($effective_rights_control_oid, $supported_controls)) { - error_log("No getEffectiveRights control in supportedControls"); + //console("No getEffectiveRights control in supportedControls"); return $this->legacy_rights($subject); } @@ -333,16 +387,20 @@ class LDAP //console("effective_rights for $subject resolves to $entry_dn"); + $moz_ldapsearch = "/usr/lib64/mozldap/ldapsearch"; + if (!is_file($moz_ldapsearch)) { + $moz_ldapsearch = "/usr/lib/mozldap/ldapsearch"; + } + $command = array( - // TODO: Very 64-bit specific - '/usr/lib64/mozldap/ldapsearch', + $moz_ldapsearch, '-x', '-h', $this->_ldap_server, '-p', $this->_ldap_port, '-b', - $conf->get('base_dn'), + '"' . $entry_dn . '"', '-D', '"' . $_SESSION['user']->user_bind_dn . '"', '-w', @@ -356,7 +414,9 @@ class LDAP 'dn:' . $_SESSION['user']->user_bind_dn // User DN ) ) . '"', - '"(entrydn=' . $entry_dn . ')"', + '-s', + 'base', + '"(objectclass=*)"', '"*"', ); @@ -399,6 +459,28 @@ class LDAP return $attributes; } + public function find_user_groups($member_dn) + { + //console(__FILE__ . "(" . __LINE__ . "): " . $member_dn); + + $groups = array(); + + $root_dn = $this->domain_root_dn($this->domain); + + // TODO: Do not query for both, it's either one or the other + $entries = $this->_search($root_dn, "(|" . + "(&(objectclass=groupofnames)(member=$member_dn))" . + "(&(objectclass=groupofuniquenames)(uniquemember=$member_dn))" . + ")"); + + $entries = self::normalize_result($entries); + + foreach ($entries as $entry_dn => $entry_attributes) { + $groups[] = $entry_dn; + } + + return $groups; + } public function get_attribute($subject_dn, $attribute) { @@ -422,6 +504,101 @@ class LDAP return false; } + public function group_add($attrs, $typeid = null) + { + if ($typeid == null) { + $type_str = 'group'; + } + else { + $db = SQL::get_instance(); + $_key = $db->fetch_assoc($db->query("SELECT `key` FROM group_types WHERE id = ?", $typeid)); + $type_str = $_key['key']; + } + + // Check if the group_type has a specific base DN specified. + $base_dn = $this->conf->get($type_str . "_group_base_dn"); + // If not, take the regular user_base_dn + if (!$base_dn) + $base_dn = $this->conf->get("group_base_dn"); + + // TODO: The rdn is configurable as well. + // Use [$type_str . "_"]user_rdn_attr + $dn = "cn=" . $attrs['cn'] . "," . $base_dn; + + return $this->_add($dn, $attrs); + } + + public function group_delete($group) + { + $group_dn = $this->entry_dn($group); + + if (!$group_dn) { + return false; + } + + return $this->_delete($group_dn); + } + + public function group_edit($group, $attributes, $typeid = null) + { +/* + // Get the type "key" string for the next few settings. + if ($typeid == null) { + $type_str = 'group'; + } + else { + $db = SQL::get_instance(); + $_key = $db->fetch_assoc($db->query("SELECT `key` FROM group_types WHERE id = ?", $typeid)); + $type_str = $_key['key']; + } +*/ + // Group identifier + $unique_attr = $this->unique_attribute(); + $attributes[$unique_attr] = $group; + + // Now that values have been re-generated where necessary, compare + // the new group attributes to the original group attributes. + $_group = $this->entry_find_by_attribute(array($unique_attr => $attributes[$unique_attr])); + + if (!$_group) { + //console("Could not find group"); + return false; + } + + $_group_dn = key($_group); + $_group = $this->group_info($_group_dn, array_keys($attributes)); + + // We should start throwing stuff over the fence here. + return $this->modify_entry($_group_dn, $_group[$_group_dn], $attributes); + } + + public function group_find_by_attribute($attribute) + { + return $this->entry_find_by_attribute($attribute); + } + + public function group_info($group, $attributes = array('*')) + { + $group_dn = $this->entry_dn($group); + + if (!$group_dn) { + return false; + } + + return self::normalize_result($this->_search($group_dn, '(objectclass=*)', $attributes)); + } + + public function group_members_list($group, $recurse = true) + { + $group_dn = $this->entry_dn($group); + + if (!$group_dn) { + return false; + } + + return $this->_list_group_members($group_dn, null, $recurse); + } + public function list_domains() { $domains = $this->domains_list(); @@ -484,6 +661,37 @@ class LDAP return $users; } + public function list_resources($attributes = array(), $search = array(), $params = array()) + { + if (!empty($params['sort_by'])) { + if (is_array($params['sort_by'])) { + foreach ($params['sort_by'] as $attrib) { + if (!in_array($attrib, $attributes)) { + $attributes[] = $attrib; + } + } + } else { + if (!in_array($params['sort_by'], $attributes)) { + $attributes[] = $params['sort_by']; + } + } + } + + $resources = $this->resources_list($attributes, $search); + $resources = self::normalize_result($resources); + + if (!empty($params['sort_by'])) { + $this->sort_result_key = $params['sort_by']; + uasort($resources, array($this, 'sort_result')); + + if ($params['sort_order'] == 'DESC') { + $resources = array_reverse($resources, true); + } + } + + return $resources; + } + public function list_roles($attributes = array(), $search = array(), $params = array()) { if (!empty($params['sort_by'])) { @@ -507,218 +715,207 @@ class LDAP return $roles; } - public function user_add($attrs, $typeid = null) + public function resource_add($attrs, $typeid = null) { if ($typeid == null) { - $type_str = 'user'; + $type_str = 'resource'; } else { $db = SQL::get_instance(); - $_key = $db->fetch_assoc($db->query("SELECT `key` FROM user_types WHERE id = ?", $typeid)); + $_key = $db->fetch_assoc($db->query("SELECT `key` FROM resource_types WHERE id = ?", $typeid)); $type_str = $_key['key']; } - // Check if the user_type has a specific base DN specified. - $base_dn = $this->conf->get($this->domain, $type_str . "_user_base_dn"); + // Check if the resource_type has a specific base DN specified. + $base_dn = $this->conf->get($type_str . "_resource_base_dn"); // If not, take the regular user_base_dn if (!$base_dn) - $base_dn = $this->conf->get($this->domain, "user_base_dn"); - - // If no user_base_dn either, take the user type specific from the parent - // configuration - if (!$base_dn) - $base_dn = $this->conf->get('ldap', $type_str . "_user_base_dn"); - - if (!empty($attrs['ou'])) { - $base_dn = $attrs['ou']; - } + $base_dn = $this->conf->get("resource_base_dn"); // TODO: The rdn is configurable as well. // Use [$type_str . "_"]user_rdn_attr - $dn = "uid=" . $attrs['uid'] . "," . $base_dn; + $dn = "cn=" . $attrs['cn'] . "," . $base_dn; return $this->_add($dn, $attrs); } - public function user_edit($user, $attributes, $typeid = null) + public function resource_delete($resource) + { + $resource_dn = $this->entry_dn($resource); + + if (!$resource_dn) { + return false; + } + + return $this->_delete($resource_dn); + } + + public function resource_edit($resource, $attributes, $typeid = null) { /* // Get the type "key" string for the next few settings. if ($typeid == null) { - $type_str = 'user'; + $type_str = 'resource'; } else { $db = SQL::get_instance(); - $_key = $db->fetch_assoc($db->query("SELECT `key` FROM user_types WHERE id = ?", $typeid)); + $_key = $db->fetch_assoc($db->query("SELECT `key` FROM resource_types WHERE id = ?", $typeid)); $type_str = $_key['key']; } */ + // Group identifier $unique_attr = $this->unique_attribute(); - $attributes[$unique_attr] = $user; + $attributes[$unique_attr] = $resource; // Now that values have been re-generated where necessary, compare - // the new group attributes to the original group attributes. - $_user = $this->entry_find_by_attribute(array($unique_attr => $attributes[$unique_attr])); + // the new resource attributes to the original resource attributes. + $_resource = $this->entry_find_by_attribute(array($unique_attr => $attributes[$unique_attr])); - if (!$_user) { - //console("Could not find user"); + if (!$_resource) { + //console("Could not find resource"); return false; } - $_user_dn = key($_user); - $_user = $this->user_info($_user_dn, array_keys($attributes)); - - //console("user_edit \$_user", $_user); + $_resource_dn = key($_resource); + $_resource = $this->resource_info($_resource_dn, array_keys($attributes)); // We should start throwing stuff over the fence here. - return $this->modify_entry($_user_dn, $_user[$_user_dn], $attributes); + return $this->modify_entry($_resource_dn, $_resource[$_resource_dn], $attributes); } - public function user_delete($user) + public function resource_find_by_attribute($attribute) { - $user_dn = $this->entry_dn($user); - - if (!$user_dn) { - return false; - } - - return $this->_delete($user_dn); + return $this->entry_find_by_attribute($attribute); } /** - * User attributes + * Resource attributes * * */ - public function user_info($user, $attributes = array('*')) + public function resource_info($resource, $attributes = array('*')) { - $user_dn = $this->entry_dn($user); + $resource_dn = $this->entry_dn($resource); - if (!$user_dn) + if (!$resource_dn) return false; - return self::normalize_result($this->_search($user_dn, '(objectclass=*)', $attributes)); + return self::normalize_result($this->_search($resource_dn, '(objectclass=*)', $attributes)); } - public function user_find_by_attribute($attribute) + public function resource_members_list($resource, $recurse = true) { - return $this->entry_find_by_attribute($attribute); - } + $resource_dn = $this->entry_dn($resource); - public function find_user_groups($member_dn) - { - error_log(__FILE__ . "(" . __LINE__ . "): " . $member_dn); - - $groups = array(); - - $root_dn = $this->domain_root_dn($this->domain); - - // TODO: Do not query for both, it's either one or the other - $entries = $this->_search($root_dn, "(|" . - "(&(objectclass=groupofnames)(member=$member_dn))" . - "(&(objectclass=groupofuniquenames)(uniquemember=$member_dn))" . - ")"); - - $entries = self::normalize_result($entries); - - foreach ($entries as $entry_dn => $entry_attributes) { - $groups[] = $entry_dn; + if (!$resource_dn) { + return false; } - return $groups; + return $this->_list_resource_members($resource_dn, null, $recurse); } - public function group_add($attrs, $typeid = null) + public function user_add($attrs, $typeid = null) { if ($typeid == null) { - $type_str = 'group'; + $type_str = 'user'; } else { $db = SQL::get_instance(); - $_key = $db->fetch_assoc($db->query("SELECT `key` FROM group_types WHERE id = ?", $typeid)); + $_key = $db->fetch_assoc($db->query("SELECT `key` FROM user_types WHERE id = ?", $typeid)); $type_str = $_key['key']; } - // Check if the group_type has a specific base DN specified. - $base_dn = $this->conf->get($type_str . "_group_base_dn"); + // Check if the user_type has a specific base DN specified. + $base_dn = $this->conf->get($this->domain, $type_str . "_user_base_dn"); // If not, take the regular user_base_dn - if (!$base_dn) - $base_dn = $this->conf->get("group_base_dn"); + if (empty($base_dn)) + $base_dn = $this->conf->get($this->domain, "user_base_dn"); + + // If no user_base_dn either, take the user type specific from the parent + // configuration + if (empty($base_dn)) + $base_dn = $this->conf->get('ldap', $type_str . "_user_base_dn"); + + // If still no base dn to add the user to... use the toplevel dn + if (empty($base_dn)) + $base_dn = $this->conf->get($this->domain, "base_dn"); + if (empty($base_dn)) + $base_dn = $this->conf->get('ldap', "base_dn"); + + if (!empty($attrs['ou'])) { + $base_dn = $attrs['ou']; + } + + //console("Base DN now: $base_dn"); // TODO: The rdn is configurable as well. // Use [$type_str . "_"]user_rdn_attr - $dn = "cn=" . $attrs['cn'] . "," . $base_dn; + $dn = "uid=" . $attrs['uid'] . "," . $base_dn; return $this->_add($dn, $attrs); } - public function group_edit($group, $attributes, $typeid = null) + public function user_edit($user, $attributes, $typeid = null) { /* // Get the type "key" string for the next few settings. if ($typeid == null) { - $type_str = 'group'; + $type_str = 'user'; } else { $db = SQL::get_instance(); - $_key = $db->fetch_assoc($db->query("SELECT `key` FROM group_types WHERE id = ?", $typeid)); + $_key = $db->fetch_assoc($db->query("SELECT `key` FROM user_types WHERE id = ?", $typeid)); $type_str = $_key['key']; } */ - // Group identifier $unique_attr = $this->unique_attribute(); - $attributes[$unique_attr] = $group; + $attributes[$unique_attr] = $user; // Now that values have been re-generated where necessary, compare // the new group attributes to the original group attributes. - $_group = $this->entry_find_by_attribute(array($unique_attr => $attributes[$unique_attr])); + $_user = $this->entry_find_by_attribute(array($unique_attr => $attributes[$unique_attr])); - if (!$_group) { - //console("Could not find group"); + if (!$_user) { + //console("Could not find user"); return false; } - $_group_dn = key($_group); - $_group = $this->group_info($_group_dn, array_keys($attributes)); - - // We should start throwing stuff over the fence here. - return $this->modify_entry($_group_dn, $_group[$_group_dn], $attributes); - } - - public function group_delete($group) - { - $group_dn = $this->entry_dn($group); + $_user_dn = key($_user); + $_user = $this->user_info($_user_dn, array_keys($attributes)); - if (!$group_dn) { - return false; - } + //console("Auth::LDAP::user_edit() existing \$_user info", $_user); - return $this->_delete($group_dn); + // We should start throwing stuff over the fence here. + return $this->modify_entry($_user_dn, $_user[$_user_dn], $attributes); } - public function group_info($group, $attributes = array('*')) + public function user_delete($user) { - $group_dn = $this->entry_dn($group); + $user_dn = $this->entry_dn($user); - if (!$group_dn) { + if (!$user_dn) { return false; } - return self::normalize_result($this->_search($group_dn, '(objectclass=*)', $attributes)); + return $this->_delete($user_dn); } - public function group_members_list($group, $recurse = true) + /** + * User attributes + * + * + */ + public function user_info($user, $attributes = array('*')) { - $group_dn = $this->entry_dn($group); + $user_dn = $this->entry_dn($user); - if (!$group_dn) { + if (!$user_dn) return false; - } - return $this->_list_group_members($group_dn, null, $recurse); + return self::normalize_result($this->_search($user_dn, '(objectclass=*)', $attributes)); } - public function group_find_by_attribute($attribute) + public function user_find_by_attribute($attribute) { return $this->entry_find_by_attribute($attribute); } @@ -738,11 +935,11 @@ class LDAP return false; } - error_log("Searching for domain $domain"); - error_log("From domain to root dn"); + //console("Searching for domain $domain"); + //console("From domain to root dn"); if (($this->_bind($conf->get('ldap', 'bind_dn'), $conf->get('ldap', 'bind_pw'))) == false) { - error_log("WARNING: Invalid Service bind credentials supplied"); + //console("WARNING: Invalid Service bind credentials supplied"); $this->_bind($conf->manager_bind_dn, $conf->manager_bind_pw); } @@ -770,7 +967,7 @@ class LDAP $this->_unbind(); - error_log("Using $domain_rootdn"); + //console("Using $domain_rootdn"); return $domain_rootdn; } @@ -805,16 +1002,16 @@ class LDAP return $result; } - private function _search($base_dn, $search_filter = '(objectClass=*)', $attributes = array('*')) - { - return $this->__search($base_dn, $search_filter, $attributes); - } - private function domains_list() { $section = $this->conf->get('kolab', 'auth_mechanism'); $base_dn = $this->conf->get($section, 'domain_base_dn'); - $filter = $this->conf->get($section, 'kolab_domain_filter'); + $filter = $this->conf->get($section, 'domain_filter'); + + $kolab_filter = $this->conf->get($section, 'kolab_domain_filter'); + if (empty($filter) && !empty($kolab_filter)) { + $filter = $kolab_filter; + } return $this->_search($base_dn, $filter); } @@ -837,7 +1034,7 @@ class LDAP } } - private function entry_find_by_attribute($attribute) + private function entry_find_by_attribute($attribute, $base_dn = null) { if (empty($attribute) || !is_array($attribute) || count($attribute) > 1) { return false; @@ -855,16 +1052,18 @@ class LDAP $filter .= ")"; - $base_dn = $this->domain_root_dn($this->domain); + if (empty($base_dn)) { + $base_dn = $this->domain_root_dn($this->domain); + } $result = self::normalize_result($this->_search($base_dn, $filter, array_keys($attribute))); if (count($result) > 0) { - error_log("Results found: " . implode(', ', array_keys($result))); + //console("Results found: " . implode(', ', array_keys($result))); return $result; } else { - error_log("No result"); + //console("No result"); return false; } } @@ -999,7 +1198,7 @@ class LDAP $rdn_attr = $rdn_components[0]; - //console($rdn_attr); + //console("Auth::LDAP::modify_entry() using rdn attribute: " . $rdn_attr); $mod_array = Array( "add" => Array(), // For use with ldap_mod_add() @@ -1009,32 +1208,91 @@ class LDAP ); // This is me cheating. Remove this special attribute. - $old_ou = $old_attrs['ou']; - $new_ou = $new_attrs['ou']; - unset($old_attrs['ou']); - unset($new_attrs['ou']); + if (array_key_exists('ou', $old_attrs) || array_key_exists('ou', $new_attrs)) { + $old_ou = $old_attrs['ou']; + $new_ou = $new_attrs['ou']; + unset($old_attrs['ou']); + unset($new_attrs['ou']); + } else { + $old_ou = null; + $new_ou = null; + } // Compare each attribute value of the old attrs with the corresponding value // in the new attrs, if any. foreach ($old_attrs as $attr => $old_attr_value) { if (array_key_exists($attr, $new_attrs)) { - $_sort1 = false; - $_sort2 = false; - if (is_array($new_attrs[$attr])) { + if (is_array($old_attrs[$attr]) && is_array($new_attrs[$attr])) { $_sort1 = $new_attrs[$attr]; sort($_sort1); - } - if (is_array($old_attr_value)) { $_sort2 = $old_attr_value; sort($_sort2); + } else { + $_sort1 = true; + $_sort2 = false; } if (!($new_attrs[$attr] === $old_attr_value) && !($_sort1 === $_sort2)) { //console("Attribute $attr changed from", $old_attr_value, "to", $new_attrs[$attr]); if ($attr === $rdn_attr) { - $mod_array['rename']['dn'] = $subject_dn; - $mod_array['rename']['new_rdn'] = $rdn_attr . '=' . $new_attrs[$attr]; + //console("This attribute is the RDN attribute. Let's see if it is multi-valued, and if the original still exists in the new value."); + if (is_array($old_attrs[$attr])) { + if (!is_array($new_attrs[$attr])) { + if (in_array($new_attrs[$attr], $old_attrs[$attr])) { + // TODO: Need to remove all $old_attrs[$attr] values not equal to $new_attrs[$attr], and not equal to the current $rdn_attr value [0] + + //console("old attrs. is array, new attrs. is not array. new attr. exists in old attrs."); + + $rdn_attr_value = array_shift($old_attrs[$attr]); + $_attr_to_remove = array(); + + foreach ($old_attrs[$attr] as $value) { + if (strtolower($value) != strtolower($new_attrs[$attr])) { + $_attr_to_remove[] = $value; + } + } + + //console("Adding to delete attribute $attr values:" . implode(', ', $_attr_to_remove)); + + $mod_array['delete'][$attr] = $_attr_to_remove; + + if (strtolower($new_attrs[$attr]) !== strtolower($rdn_attr_value)) { + //console("new attrs is not the same as the old rdn value, issuing a rename"); + $mod_array['rename']['dn'] = $subject_dn; + $mod_array['rename']['new_rdn'] = $rdn_attr . '=' . $new_attrs[$attr][0]; + } + + } else { + //console("new attrs is not the same as any of the old rdn value, issuing a full rename"); + $mod_array['rename']['dn'] = $subject_dn; + $mod_array['rename']['new_rdn'] = $rdn_attr . '=' . $new_attrs[$attr]; + } + } else { + // TODO: See if the rdn attr. value is still in $new_attrs[$attr] + if (in_array($old_attrs[$attr][0], $new_attrs[$attr])) { + //console("Simply replacing attr $attr as rnd attr value is preserved."); + $mod_array['replace'][$attr] = $new_attrs[$attr]; + } else { + // TODO: This fails. + $mod_array['rename']['dn'] = $subject_dn; + $mod_array['rename']['new_rdn'] = $rdn_attr . '=' . $new_attrs[$attr][0]; + $mod_array['delete'][$attr] = $old_attrs[$attr][0]; + } + } + } else { + if (!is_array($new_attrs[$attr])) { + //console("Renaming " . $old_attrs[$attr] . " to " . $new_attrs[$attr]); + $mod_array['rename']['dn'] = $subject_dn; + $mod_array['rename']['new_rdn'] = $rdn_attr . '=' . $new_attrs[$attr]; + } else { + //console("Adding to replace"); + // An additional attribute value is being supplied. Just replace and continue. + $mod_array['replace'][$attr] = $new_attrs[$attr]; + continue; + } + } + } else { if (empty($new_attrs[$attr])) { switch ($attr) { @@ -1095,7 +1353,7 @@ class LDAP $old_ou = implode(',', $subject_dn_components); } - if (!(strtolower($old_ou) === strtolower($new_ou))) { + if (!(empty($old_ou) || empty($new_ou)) && !(strtolower($old_ou) === strtolower($new_ou))) { $mod_array['rename']['new_parent'] = $new_ou; if (empty($mod_array['rename']['dn']) || empty($mod_array['rename']['new_rdn'])) { $mod_array['rename']['dn'] = $subject_dn; @@ -1117,15 +1375,43 @@ class LDAP { $this->_bind($_SESSION['user']->user_bind_dn, $_SESSION['user']->user_bind_pw); + //console($attributes); + // Opportunities to set false include failed ldap commands. $result = true; + if (is_array($attributes['rename']) && !empty($attributes['rename'])) { + $olddn = $attributes['rename']['dn']; + $newrdn = $attributes['rename']['new_rdn']; + if (!empty($attributes['rename']['new_parent'])) { + $new_parent = $attributes['rename']['new_parent']; + } else { + $new_parent = null; + } + + //console("Attempt to rename $olddn to $newrdn,$new_parent"); + + $result = ldap_rename($this->conn, $olddn, $newrdn, $new_parent, true); + if ($result) { + if ($new_parent) { + $subject_dn = $newrdn . ',' . $new_parent; + } else { + $old_parent_dn_components = ldap_explode_dn($olddn, 0); + unset($old_parent_dn_components["count"]); + $old_rdn = array_shift($old_parent_dn_components); + $old_parent_dn = implode(",", $old_parent_dn_components); + $subject_dn = $newrdn . ',' . $old_parent_dn; + } + } + + } + if (is_array($attributes['replace']) && !empty($attributes['replace'])) { $result = ldap_mod_replace($this->conn, $subject_dn, $attributes['replace']); } if (!$result) { - //console("Failed to replace the following attributes", $attributes['replace']); + //console("Failed to replace the following attributes on subject " . $subject_dn, $attributes['replace']); return false; } @@ -1148,22 +1434,8 @@ class LDAP return false; } - if (is_array($attributes['rename']) && !empty($attributes['rename'])) { - $olddn = $attributes['rename']['dn']; - $newrdn = $attributes['rename']['new_rdn']; - if (!empty($attributes['rename']['new_parent'])) { - $new_parent = $attributes['rename']['new_parent']; - } else { - $new_parent = null; - } - - //console("Attempt to rename $olddn to $newrdn,$new_parent"); - - $result = ldap_rename($this->conn, $olddn, $newrdn, $new_parent, true); - } - if (!$result) { - error_log("LDAP Error: " . $this->_errstr()); + //console("LDAP Error: " . $this->_errstr()); return false; } @@ -1248,6 +1520,32 @@ class LDAP return $result['']['supportedcontrol']; } + private function resources_list($attributes = array(), $search = array()) + { + $conf = Conf::get_instance(); + + $base_dn = $conf->get('resource_base_dn'); + + if (!$base_dn) + $base_dn = "ou=Resources," . $conf->get('base_dn'); + + $filter = $conf->get('resource_filter'); + if (!$filter) + $filter = '(objectclass=*)'; + + if (empty($attributes) || !is_array($attributes)) { + $attributes = array('*'); + } + + if ($s_filter = $this->_search_filter($search)) { + // join search filter with objectClass filter + $filter = '(&' . $filter . $s_filter . ')'; + } + + return $this->_search($base_dn, $filter, $attributes); + } + + private function users_list($attributes = array(), $search = array()) { $conf = Conf::get_instance(); @@ -1442,6 +1740,33 @@ class LDAP return true; } + private function _domain_add_alias($domain, $parent) + { + $conf = Conf::get_instance(); + $domain_base_dn = $conf->get('ldap', 'domain_base_dn'); + $domain_filter = $conf->get('ldap', 'domain_filter'); + + $domain_name_attribute = $conf->get('ldap', 'domain_name_attribute'); + + $domain_filter = '(&(' . $domain_name_attribute . '=' . $parent . ')' . $domain_filter . ')'; + + $domain_entry = self::normalize_result($this->_search($domain_base_dn, $domain_filter)); + + // TODO: Catch not having found any such parent domain + + $domain_dn = key($domain_entry); + + // private function modify_entry($subject_dn, $old_attrs, $new_attrs) + + $_old_attr = array($domain_name_attribute => $domain_entry[$domain_dn][$domain_name_attribute]); + $_new_attr = array($domain_name_attribute => array($domain_entry[$domain_dn][$domain_name_attribute], $domain)); + + return $this->modify_entry($domain_dn, $_old_attr, $_new_attr); + + + + } + /** * Shortcut to ldap_bind() */ @@ -1458,13 +1783,13 @@ class LDAP } // TODO: Debug logging - error_log("->_bind() Binding with $dn"); + //console("->_bind() Binding with $dn"); $this->bind_dn = $dn; $this->bind_pw = $pw; if (($bind_ok = ldap_bind($this->conn, $dn, $pw)) == false) { - error_log("LDAP Error: " . $this->_errstr()); + //console("LDAP Error: " . $this->_errstr()); // Issue error message return false; } @@ -1481,14 +1806,16 @@ class LDAP return true; } + ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 9); + // TODO: Debug logging - error_log("Connecting to " . $this->_ldap_server . " on port " . $this->_ldap_port); + //console("Connecting to " . $this->_ldap_server . " on port " . $this->_ldap_port); $connection = ldap_connect($this->_ldap_server, $this->_ldap_port); if ($connection == false) { $this->conn = null; // TODO: Debug logging - error_log("Not connected: " . ldap_err2str() . "(no.) " . ldap_errno()); + //console("Not connected: " . ldap_err2str() . "(no.) " . ldap_errno()); return false; } @@ -1497,7 +1824,7 @@ class LDAP ldap_set_option($this->conn, LDAP_OPT_PROTOCOL_VERSION, 3); // TODO: Debug logging - error_log("Connected!"); + //console("Connected!"); return true; } @@ -1580,6 +1907,11 @@ class LDAP return $ldap_entries; } + private function _search($base_dn, $search_filter = '(objectClass=*)', $attributes = array('*')) + { + return $this->__search($base_dn, $search_filter, $attributes); + } + /** * Shortcut to ldap_search() */ @@ -1600,15 +1932,17 @@ class LDAP } if (($search_results = @ldap_search($this->conn, $base_dn, $search_filter, $attributes)) == false) { - //message("Could not search in " . __METHOD__ . " in " . __FILE__ . " on line " . __LINE__ . ": " . $this->_errstr()); + //console("Could not search in " . __METHOD__ . " in " . __FILE__ . " on line " . __LINE__ . ": " . $this->_errstr()); return false; } if (($entries = ldap_get_entries($this->conn, $search_results)) == false) { - //message("Could not get the results of the search: " . $this->_errstr()); + //console("Could not get the results of the search: " . $this->_errstr()); return false; } + //console("__search() entries:", $entries); + return $entries; } @@ -1704,13 +2038,13 @@ class LDAP */ private function _probe_root_dn($entry_root_dn) { - error_log("Running for entry root dn: " . $entry_root_dn); + //console("Running for entry root dn: " . $entry_root_dn); if (($tmpconn = ldap_connect($this->_ldap_server)) == false) { //message("LDAP Error: " . $this->_errstr()); return false; } - error_log("User DN: " . $_SESSION['user']->user_bind_dn); + //console("User DN: " . $_SESSION['user']->user_bind_dn); if (($bind_success = ldap_bind($tmpconn, $_SESSION['user']->user_bind_dn, $_SESSION['user']->user_bind_pw)) == false) { //message("LDAP Error: " . $this->_errstr()); @@ -1771,7 +2105,7 @@ class LDAP $this->_bind($this->conf->get('manager_bind_dn'), $this->conf->get('manager_bind_pw')); } - error_log("Searching for a group dn in $root_dn, with search filter: $search_filter"); + //console("Searching for a group dn in $root_dn, with search filter: $search_filter"); $search_results = ldap_search($this->conn, $root_dn, $search_filter); @@ -1795,7 +2129,7 @@ class LDAP $this->_bind($this->conf->get('manager_bind_dn'), $this->conf->get('manager_bind_pw')); } - error_log("Searching for a user dn in $root_dn, with search filter: $search_filter"); + //console("Searching for a user dn in $root_dn, with search filter: $search_filter"); $search_results = ldap_search($this->conn, $root_dn, $search_filter); @@ -1819,10 +2153,10 @@ class LDAP if (is_array($entry) && in_array('objectclass', $entry)) { if (!in_array(array('groupofnames', 'groupofuniquenames', 'groupofurls'), $entry['objectclass'])) { - error_log("Called _list_groups_members on a non-group!"); + //console("Called _list_groups_members on a non-group!"); } else { - error_log("Called list_group_members(" . $dn . ")"); + //console("Called list_group_members(" . $dn . ")"); } } @@ -1855,7 +2189,7 @@ class LDAP private function _list_group_member($dn, $members, $recurse = true) { - error_log("Called _list_group_member(" . $dn . ")"); + //console("Called _list_group_member(" . $dn . ")"); $group_members = array(); @@ -1932,7 +2266,7 @@ class LDAP private function _list_group_memberurl($dn, $memberurls, $recurse = true) { - error_log("Called _list_group_memberurl(" . $dn . ")"); + //console("Called _list_group_memberurl(" . $dn . ")"); // Use the member attributes to return an array of member ldap objects // NOTE that the member attribute is supposed to contain a DN @@ -1946,7 +2280,7 @@ class LDAP foreach ($entries as $entry_dn => $_entry) { $group_members[$entry_dn] = $_entry; - error_log("Found " . $entry_dn); + //console("Found " . $entry_dn); if ($recurse) { // Nested group @@ -1970,7 +2304,7 @@ class LDAP */ private function _parse_memberurl($url) { - error_log("Parsing URL: " . $url); + //console("Parsing URL: " . $url); preg_match('/(.*):\/\/(.*)\/(.*)\?(.*)\?(.*)\?(.*)/', $url, $matches); return $matches; } |