Ejemplo n.º 1
1
 /**
  * Update the entry on the directory server
  *
  * This will evaluate all changes made so far and send them
  * to the directory server.
  * Please note, that if you make changes to objectclasses wich
  * have mandatory attributes set, update() will currently fail.
  * Remove the entry from the server and readd it as new in such cases.
  * This also will deal with problems with setting structural object classes.
  *
  * @param Net_LDAP2 $ldap If passed, a call to setLDAP() is issued prior update, thus switching the LDAP-server. This is for perl-ldap interface compliance
  *
  * @access public
  * @return true|Net_LDAP2_Error
  * @todo Entry rename with a DN containing special characters needs testing!
  */
 public function update($ldap = null)
 {
     if ($ldap) {
         $msg = $this->setLDAP($ldap);
         if (Net_LDAP2::isError($msg)) {
             return PEAR::raiseError('You passed an invalid $ldap variable to update()');
         }
     }
     // ensure we have a valid LDAP object
     $ldap =& $this->getLDAP();
     if (!$ldap instanceof Net_LDAP2) {
         return PEAR::raiseError("The entries LDAP object is not valid");
     }
     // Get and check link
     $link = $ldap->getLink();
     if (!is_resource($link)) {
         return PEAR::raiseError("Could not update entry: internal LDAP link is invalid");
     }
     /*
      * Delete the entry
      */
     if (true === $this->_delete) {
         return $ldap->delete($this);
     }
     /*
      * New entry
      */
     if (true === $this->_new) {
         $msg = $ldap->add($this);
         if (Net_LDAP2::isError($msg)) {
             return $msg;
         }
         $this->_new = false;
         $this->_changes['add'] = array();
         $this->_changes['delete'] = array();
         $this->_changes['replace'] = array();
         $this->_original = $this->_attributes;
         $return = true;
         return $return;
     }
     /*
      * Rename/move entry
      */
     if (false == is_null($this->_newdn)) {
         if ($ldap->getLDAPVersion() !== 3) {
             return PEAR::raiseError("Renaming/Moving an entry is only supported in LDAPv3");
         }
         // make dn relative to parent (needed for ldap rename)
         $parent = Net_LDAP2_Util::ldap_explode_dn($this->_newdn, array('casefolding' => 'none', 'reverse' => false, 'onlyvalues' => false));
         if (Net_LDAP2::isError($parent)) {
             return $parent;
         }
         $child = array_shift($parent);
         // maybe the dn consist of a multivalued RDN, we must build the dn in this case
         // because the $child-RDN is an array!
         if (is_array($child)) {
             $child = Net_LDAP2_Util::canonical_dn($child);
         }
         $parent = Net_LDAP2_Util::canonical_dn($parent);
         // rename/move
         if (false == @ldap_rename($link, $this->_dn, $child, $parent, true)) {
             return PEAR::raiseError("Entry not renamed: " . @ldap_error($link), @ldap_errno($link));
         }
         // reflect changes to local copy
         $this->_dn = $this->_newdn;
         $this->_newdn = null;
     }
     /*
      * Carry out modifications to the entry
      */
     // ADD
     foreach ($this->_changes["add"] as $attr => $value) {
         // if attribute exists, add new values
         if ($this->exists($attr)) {
             if (false === @ldap_mod_add($link, $this->dn(), array($attr => $value))) {
                 return PEAR::raiseError("Could not add new values to attribute {$attr}: " . @ldap_error($link), @ldap_errno($link));
             }
         } else {
             // new attribute
             if (false === @ldap_modify($link, $this->dn(), array($attr => $value))) {
                 return PEAR::raiseError("Could not add new attribute {$attr}: " . @ldap_error($link), @ldap_errno($link));
             }
         }
         // all went well here, I guess
         unset($this->_changes["add"][$attr]);
     }
     // DELETE
     foreach ($this->_changes["delete"] as $attr => $value) {
         // In LDAPv3 you need to specify the old values for deleting
         if (is_null($value) && $ldap->getLDAPVersion() === 3) {
             $value = $this->_original[$attr];
         }
         if (false === @ldap_mod_del($link, $this->dn(), array($attr => $value))) {
             return PEAR::raiseError("Could not delete attribute {$attr}: " . @ldap_error($link), @ldap_errno($link));
         }
         unset($this->_changes["delete"][$attr]);
     }
     // REPLACE
     foreach ($this->_changes["replace"] as $attr => $value) {
         if (false === @ldap_modify($link, $this->dn(), array($attr => $value))) {
             return PEAR::raiseError("Could not replace attribute {$attr} values: " . @ldap_error($link), @ldap_errno($link));
         }
         unset($this->_changes["replace"][$attr]);
     }
     // all went well, so _original (server) becomes _attributes (local copy)
     $this->_original = $this->_attributes;
     $return = true;
     return $return;
 }
Ejemplo n.º 2
0
 /**
  * Write the entry or entries to the LDIF file.
  *
  * If you want to build an LDIF file containing several entries AND
  * you want to call write_entry() several times, you must open the filehandle
  * in append mode ("a"), otherwise you will always get the last entry only.
  *
  * @param Net_LDAP2_Entry|array $entries Entry or array of entries
  *
  * @return void
  * @todo implement operations on whole entries (adding a whole entry)
  */
 public function write_entry($entries)
 {
     if (!is_array($entries)) {
         $entries = array($entries);
     }
     foreach ($entries as $entry) {
         $this->_entrynum++;
         if (!$entry instanceof Net_LDAP2_Entry) {
             $this->dropError('Net_LDAP2_LDIF error: entry ' . $this->_entrynum . ' is not an Net_LDAP2_Entry object');
         } else {
             if ($this->_options['change']) {
                 // LDIF change mode
                 // fetch change information from entry
                 $entry_attrs_changes = $entry->getChanges();
                 $num_of_changes = count($entry_attrs_changes['add']) + count($entry_attrs_changes['replace']) + count($entry_attrs_changes['delete']);
                 $is_changed = $num_of_changes > 0 || $entry->willBeDeleted() || $entry->willBeMoved();
                 // write version if not done yet
                 // also write DN of entry
                 if ($is_changed) {
                     if (!$this->_version_written) {
                         $this->write_version();
                     }
                     $this->writeDN($entry->currentDN());
                 }
                 // process changes
                 // TODO: consider DN add!
                 if ($entry->willBeDeleted()) {
                     $this->writeLine("changetype: delete" . PHP_EOL);
                 } elseif ($entry->willBeMoved()) {
                     $this->writeLine("changetype: modrdn" . PHP_EOL);
                     $olddn = Net_LDAP2_Util::ldap_explode_dn($entry->currentDN(), array('casefold' => 'none'));
                     // maybe gives a bug if using multivalued RDNs
                     $oldrdn = array_shift($olddn);
                     $oldparent = implode(',', $olddn);
                     $newdn = Net_LDAP2_Util::ldap_explode_dn($entry->dn(), array('casefold' => 'none'));
                     // maybe gives a bug if using multivalued RDNs
                     $rdn = array_shift($newdn);
                     $parent = implode(',', $newdn);
                     $this->writeLine("newrdn: " . $rdn . PHP_EOL);
                     $this->writeLine("deleteoldrdn: 1" . PHP_EOL);
                     if ($parent !== $oldparent) {
                         $this->writeLine("newsuperior: " . $parent . PHP_EOL);
                     }
                     // TODO: What if the entry has attribute changes as well?
                     //       I think we should check for that and make a dummy
                     //       entry with the changes that is written to the LDIF file
                 } elseif ($num_of_changes > 0) {
                     // write attribute change data
                     $this->writeLine("changetype: modify" . PHP_EOL);
                     foreach ($entry_attrs_changes as $changetype => $entry_attrs) {
                         foreach ($entry_attrs as $attr_name => $attr_values) {
                             $this->writeLine("{$changetype}: {$attr_name}" . PHP_EOL);
                             if ($attr_values !== null) {
                                 $this->writeAttribute($attr_name, $attr_values, $changetype);
                             }
                             $this->writeLine("-" . PHP_EOL);
                         }
                     }
                 }
                 // finish this entrys data if we had changes
                 if ($is_changed) {
                     $this->finishEntry();
                 }
             } else {
                 // LDIF-content mode
                 // fetch attributes for further processing
                 $entry_attrs = $entry->getValues();
                 // sort and put objectclass-attrs to first position
                 if ($this->_options['sort']) {
                     ksort($entry_attrs);
                     if (array_key_exists('objectclass', $entry_attrs)) {
                         $oc = $entry_attrs['objectclass'];
                         unset($entry_attrs['objectclass']);
                         $entry_attrs = array_merge(array('objectclass' => $oc), $entry_attrs);
                     }
                 }
                 // write data
                 if (!$this->_version_written) {
                     $this->write_version();
                 }
                 $this->writeDN($entry->dn());
                 foreach ($entry_attrs as $attr_name => $attr_values) {
                     $this->writeAttribute($attr_name, $attr_values);
                 }
                 $this->finishEntry();
             }
         }
     }
 }
Ejemplo n.º 3
0
 /**
  * Tells if a DN does exist in the directory
  *
  * @param string|Net_LDAP2_Entry $dn The DN of the object to test
  *
  * @return boolean|Net_LDAP2_Error
  */
 public function dnExists($dn)
 {
     if (PEAR::isError($dn)) {
         return $dn;
     }
     if ($dn instanceof Net_LDAP2_Entry) {
         $dn = $dn->dn();
     }
     if (false === is_string($dn)) {
         return PEAR::raiseError('Parameter $dn is not a string nor an entry object!');
     }
     // make dn relative to parent
     $base = Net_LDAP2_Util::ldap_explode_dn($dn, array('casefold' => 'none', 'reverse' => false, 'onlyvalues' => false));
     if (self::isError($base)) {
         return $base;
     }
     $entry_rdn = array_shift($base);
     if (is_array($entry_rdn)) {
         // maybe the dn consist of a multivalued RDN, we must build the dn in this case
         // because the $entry_rdn is an array!
         $filter_dn = Net_LDAP2_Util::canonical_dn($entry_rdn);
     }
     $base = Net_LDAP2_Util::canonical_dn($base);
     $result = @ldap_list($this->_link, $base, $entry_rdn, array(), 1, 1);
     if (@ldap_count_entries($this->_link, $result)) {
         return true;
     }
     if (ldap_errno($this->_link) == 32) {
         return false;
     }
     if (ldap_errno($this->_link) != 0) {
         return PEAR::raiseError(ldap_error($this->_link), ldap_errno($this->_link));
     }
     return false;
 }
Ejemplo n.º 4
0
 /**
  * Update the entry on the directory server
  *
  * This will evaluate all changes made so far and send them
  * to the directory server.
  * Please note, that if you make changes to objectclasses wich
  * have mandatory attributes set, update() will currently fail.
  * Remove the entry from the server and readd it as new in such cases.
  * This also will deal with problems with setting structural object classes.
  *
  * @param Net_LDAP2 $ldap If passed, a call to setLDAP() is issued prior update, thus switching the LDAP-server. This is for perl-ldap interface compliance
  *
  * @access public
  * @return true|Net_LDAP2_Error
  * @todo Entry rename with a DN containing special characters needs testing!
  */
 public function update($ldap = null)
 {
     if ($ldap) {
         $msg = $this->setLDAP($ldap);
         if (Net_LDAP2::isError($msg)) {
             return PEAR::raiseError('You passed an invalid $ldap variable to update()');
         }
     }
     // ensure we have a valid LDAP object
     $ldap = $this->getLDAP();
     if (!$ldap instanceof Net_LDAP2) {
         return PEAR::raiseError("The entries LDAP object is not valid");
     }
     // Get and check link
     $link = $ldap->getLink();
     if (!is_resource($link)) {
         return PEAR::raiseError("Could not update entry: internal LDAP link is invalid");
     }
     /*
      * Delete the entry
      */
     if (true === $this->_delete) {
         return $ldap->delete($this);
     }
     /*
      * New entry
      */
     if (true === $this->_new) {
         $msg = $ldap->add($this);
         if (Net_LDAP2::isError($msg)) {
             return $msg;
         }
         $this->_new = false;
         $this->_changes['add'] = array();
         $this->_changes['delete'] = array();
         $this->_changes['replace'] = array();
         $this->_original = $this->_attributes;
         // In case the "new" entry was moved after creation, we must
         // adjust the internal DNs as the entry was already created
         // with the most current DN.
         if (false == is_null($this->_newdn)) {
             $this->_dn = $this->_newdn;
             $this->_newdn = null;
         }
         $return = true;
         return $return;
     }
     /*
      * Rename/move entry
      */
     if (false == is_null($this->_newdn)) {
         if ($ldap->getLDAPVersion() !== 3) {
             return PEAR::raiseError("Renaming/Moving an entry is only supported in LDAPv3");
         }
         // make dn relative to parent (needed for ldap rename)
         $parent = Net_LDAP2_Util::ldap_explode_dn($this->_newdn, array('casefolding' => 'none', 'reverse' => false, 'onlyvalues' => false));
         if (Net_LDAP2::isError($parent)) {
             return $parent;
         }
         $child = array_shift($parent);
         // maybe the dn consist of a multivalued RDN, we must build the dn in this case
         // because the $child-RDN is an array!
         if (is_array($child)) {
             $child = Net_LDAP2_Util::canonical_dn($child);
         }
         $parent = Net_LDAP2_Util::canonical_dn($parent);
         // rename/move
         if (false == @ldap_rename($link, $this->_dn, $child, $parent, false)) {
             return PEAR::raiseError("Entry not renamed: " . @ldap_error($link), @ldap_errno($link));
         }
         // reflect changes to local copy
         $this->_dn = $this->_newdn;
         $this->_newdn = null;
     }
     /*
      * Retrieve a entry that has all attributes we need so that the list of changes to build is created accurately
      */
     $fullEntry = $ldap->getEntry($this->dn());
     if (Net_LDAP2::isError($fullEntry)) {
         return PEAR::raiseError("Could not retrieve a full set of attributes to reconcile changes with");
     }
     $modifications = array();
     // ADD
     foreach ($this->_changes["add"] as $attr => $value) {
         // if attribute exists, we need to combine old and new values
         if ($fullEntry->exists($attr)) {
             $currentValue = $fullEntry->getValue($attr, "all");
             $value = array_merge($currentValue, $value);
         }
         $modifications[$attr] = $value;
     }
     // DELETE
     foreach ($this->_changes["delete"] as $attr => $value) {
         // In LDAPv3 you need to specify the old values for deleting
         if (is_null($value) && $ldap->getLDAPVersion() === 3) {
             $value = $fullEntry->getValue($attr);
         }
         if (!is_array($value)) {
             $value = array($value);
         }
         // Find out what is missing from $value and exclude it
         $currentValue = isset($modifications[$attr]) ? $modifications[$attr] : $fullEntry->getValue($attr, "all");
         $modifications[$attr] = array_values(array_diff($currentValue, $value));
     }
     // REPLACE
     foreach ($this->_changes["replace"] as $attr => $value) {
         $modifications[$attr] = $value;
     }
     // COMMIT
     if (false === @ldap_modify($link, $this->dn(), $modifications)) {
         return PEAR::raiseError("Could not modify the entry: " . @ldap_error($link), @ldap_errno($link));
     }
     // all went well, so _original (server) becomes _attributes (local copy), reset _changes too...
     $this->_changes['add'] = array();
     $this->_changes['delete'] = array();
     $this->_changes['replace'] = array();
     $this->_original = $this->_attributes;
     $return = true;
     return $return;
 }
Ejemplo n.º 5
0
 /**
  * Tell if a DN does exist in the directory
  *
  * @param string $dn The DN of the object to test
  *
  * @return boolean|Net_LDAP2_Error
  */
 public function dnExists($dn)
 {
     if (!is_string($dn)) {
         return PEAR::raiseError('$dn is expected to be a string but is ' . gettype($dn) . ' ' . get_class($dn));
     }
     // make dn relative to parent
     $base = Net_LDAP2_Util::ldap_explode_dn($dn, array('casefold' => 'none', 'reverse' => false, 'onlyvalues' => false));
     if (self::isError($base)) {
         return $base;
     }
     $entry_rdn = array_shift($base);
     if (is_array($entry_rdn)) {
         // maybe the dn consist of a multivalued RDN, we must build the dn in this case
         // because the $entry_rdn is an array!
         $filter_dn = Net_LDAP2_Util::canonical_dn($entry_rdn);
     }
     $base = Net_LDAP2_Util::canonical_dn($base);
     $result = @ldap_list($this->_link, $base, $entry_rdn, array(), 1, 1);
     if (@ldap_count_entries($this->_link, $result)) {
         return true;
     }
     if (ldap_errno($this->_link) == 32) {
         return false;
     }
     if (ldap_errno($this->_link) != 0) {
         return PEAR::raiseError(ldap_error($this->_link), ldap_errno($this->_link));
     }
     return false;
 }
Ejemplo n.º 6
0
 /**
  * Tests Ldap_explode_dn()
  */
 public function testLdap_explode_dn()
 {
     $dn = 'OU=Sales+CN=J. Smith,dc=example,dc=net';
     $expected_casefold_none = array(array('CN=J. Smith', 'OU=Sales'), 'dc=example', 'dc=net');
     $expected_casefold_upper = array(array('CN=J. Smith', 'OU=Sales'), 'DC=example', 'DC=net');
     $expected_casefold_lower = array(array('cn=J. Smith', 'ou=Sales'), 'dc=example', 'dc=net');
     $expected_onlyvalues = array(array('J. Smith', 'Sales'), 'example', 'net');
     $expected_reverse = array_reverse($expected_casefold_upper);
     $dn_exploded_cnone = Net_LDAP2_Util::ldap_explode_dn($dn, array('casefold' => 'none'));
     $this->assertEquals($expected_casefold_none, $dn_exploded_cnone, 'Option casefold none failed');
     $dn_exploded_cupper = Net_LDAP2_Util::ldap_explode_dn($dn, array('casefold' => 'upper'));
     $this->assertEquals($expected_casefold_upper, $dn_exploded_cupper, 'Option casefold upper failed');
     $dn_exploded_clower = Net_LDAP2_Util::ldap_explode_dn($dn, array('casefold' => 'lower'));
     $this->assertEquals($expected_casefold_lower, $dn_exploded_clower, 'Option casefold lower failed');
     $dn_exploded_onlyval = Net_LDAP2_Util::ldap_explode_dn($dn, array('onlyvalues' => true));
     $this->assertEquals($expected_onlyvalues, $dn_exploded_onlyval, 'Option onlyval failed');
     $dn_exploded_reverse = Net_LDAP2_Util::ldap_explode_dn($dn, array('reverse' => true));
     $this->assertEquals($expected_reverse, $dn_exploded_reverse, 'Option reverse failed');
 }