summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Sulfrian <alex@spline.inf.fu-berlin.de>2016-01-19 01:41:22 +0100
committerAlexander Sulfrian <alex@spline.inf.fu-berlin.de>2016-01-19 01:41:22 +0100
commit77ad00d4135375af6bdd82524ed6570d4687c71f (patch)
treea04e3178e61f945db73e6f6373024c2c254fcd09
parenteb900d4ac34f4049b4a1716722db1287d0a6a29f (diff)
downloadldap-plugin-77ad00d4135375af6bdd82524ed6570d4687c71f.tar.gz
ldap-plugin-77ad00d4135375af6bdd82524ed6570d4687c71f.tar.bz2
ldap-plugin-77ad00d4135375af6bdd82524ed6570d4687c71f.zip
Remove ugly hack to free all memory by manually creating copy
If using "slapi_entry_dup" it will create two internal copies of the old DN, that could not be free'd without reference to internal data structures. So now we create a new Slapi_Entry, copy all attributes and set the new DN.
-rw-r--r--service_passwords.c132
1 files changed, 93 insertions, 39 deletions
diff --git a/service_passwords.c b/service_passwords.c
index 9e42bab..9943734 100644
--- a/service_passwords.c
+++ b/service_passwords.c
@@ -290,41 +290,99 @@ static int auth_with_password_fallback(char *dn, struct berval *credentials)
return 1;
}
-/** Free the memory of the current DN of an \c Slapi_Entry and set a new DN.
+/** Add an attribute to an entry.
*
- * This function update the DN in the supplied \c Slapi_Entry. In ontrast to the
- * \c slapi_entry_set_dn method, it tries to free the memory of the old DN. It
- * is a bit difficult because the DN is stored twice inside the \c Slapi_Entry
- * and there is only a method to get a reference to one of the values. So this
- * function tries do guess the memory layout of the \c Slapi_Entry and only
- * calls free on the second copy if the memory position of the first entry is
- * like the expected position.
+ * This function adds the given attribute to the given entry. The attribute is
+ * copied and merged with all values that are already available for the type
+ * of the attribute.
*
- * @param[in,out] entry The \c Slapi_Entry to manipulate.
- * @param[in] dn The new DN to set in the entry. The value is copied into the
- * entry, so the caller have to free the memory afterwards.
+ * @param[in,out] entry Entry to be modified.
+ * @param[in] attr Attribute that should be added to the entry. The attribute
+ * values are copied to the entry.
*/
-static void entry_set_dn(Slapi_Entry *entry, char *dn)
+static void entry_add_attr(Slapi_Entry *entry, Slapi_Attr *attr)
{
- char *old_dn = NULL;
-
- /* This is save. */
- old_dn = slapi_entry_get_dn(entry);
- slapi_ch_free_string(&old_dn);
-
- /* Try to gess the layout of Slapi_Entry because there is no slapi method
- to get a reference to the e_nname value. This might break with other
- versions of openldap. */
- struct Entry {
- unsigned long e_id;
- struct berval e_name;
- struct berval e_nname;
- };
- if (((struct Entry*)entry)->e_name.bv_val == old_dn) {
- slapi_ch_free_string(&((struct Entry*)entry)->e_nname.bv_val);
- }
-
- slapi_entry_set_dn(entry, dn);
+ struct berval **vals = NULL;
+ char *type = NULL;
+
+ slapi_attr_get_type(attr, &type);
+ slapi_attr_get_values(attr, &vals);
+ slapi_entry_attr_merge(entry, type, vals);
+ ber_bvecfree(vals);
+}
+
+/** Copy all attributes from one \c Slapi_Entry to another.
+ *
+ * This function iterates over all attributes in \c from and adds the attributes
+ * to \c to. Attributes already contained in \c to will be preserved.
+ *
+ * @param[in,out] to Target for the copy operation.
+ * @param[in] from Source of the attribuutes to copy.
+ */
+static void entry_copy_attrs(Slapi_Entry *to, Slapi_Entry *from)
+{
+ Slapi_Attr *attr = NULL;
+
+ slapi_entry_first_attr(from, &attr);
+ while (attr) {
+ entry_add_attr(to, attr);
+ slapi_entry_next_attr(from, attr, &attr);
+ }
+}
+
+/** Create a copy of an \c Slapi_Entry with a new DN.
+ *
+ * This function creates a copy of a \c Slapi_Entry without using
+ * \c slapi_entry_dup because, that would copy the two internal values for the
+ * DN, that cannot be free'd with slapi_* methods. So this creates a new
+ * \c Slapi_Entry, set the new DN and copies all the attributes from the old
+ * entry to the newly allocated entry. The caller has to ensure, that the
+ returned \c Slapi_Entry get free'd.
+ *
+ * @param[in] entry Source entry to create a copy from.
+ * @param[in] dn The new DN of the copied entry.
+ * @return The newly allocated \c Slapi_Entry.
+ */
+static Slapi_Entry *entry_dup_new_dn(Slapi_Entry *entry, char *dn)
+{
+ Slapi_Entry *new_entry = NULL;
+
+ new_entry = slapi_entry_alloc();
+ slapi_entry_set_dn(new_entry, dn);
+ entry_copy_attrs(new_entry, entry);
+
+ return new_entry;
+}
+
+/** Creates a copy of the entry and prepend the service prefix to the DN.
+ *
+ * This function creates a copy of the supplied entry and prepend its DN with
+ * the "cn=<service>" prefix. The caller is responsible for freeing the memory
+ * of the returned new \c Slapi_Entry.
+ *
+ * @param[in] entry The source entry for the copy with the original DN
+ * value. All attributes will be in the newly created entry,
+ * too.
+ * @param[in] service The name of the service, that should be contained in the
+ * prefix for the new DN. The service name should be not
+ * longer than 251 chars (longer values will be truncated).
+ * @return A new \c Slapi_Entry with the modified DN.
+ */
+static Slapi_Entry *prepend_service_prefix(Slapi_Entry *entry, char *service)
+{
+ Slapi_Entry *new_entry = NULL;
+ char rdn[255] = {0};
+ char *old_dn = NULL;
+ char *new_dn = NULL;
+
+ old_dn = slapi_entry_get_dn(entry);
+ snprintf(rdn, 254, "cn=%s", service);
+ new_dn = slapi_dn_plus_rdn(old_dn, rdn);
+
+ new_entry = entry_dup_new_dn(entry, new_dn);
+ slapi_ch_free_string(&new_dn);
+
+ return new_entry;
}
/** \c PRE_BIND plugin to allow password fallback.
@@ -454,9 +512,7 @@ static int pre_entry(Slapi_PBlock *pb)
char *service;
char *parent_dn = NULL;
- char rdn[255];
const char *result_dn = NULL;
- char *new_dn = NULL;
Slapi_Entry *new_entry;
int rc = 0;
@@ -512,13 +568,11 @@ static int pre_entry(Slapi_PBlock *pb)
/* modify the dn of the returned entry */
if (dn_contains_uid(result_dn) == 0) {
- snprintf(rdn, 254, "cn=%s", service);
- new_dn = slapi_dn_plus_rdn(result_dn, rdn);
-
- new_entry = slapi_entry_dup(entry);
- entry_set_dn(new_entry, new_dn);
- slapi_ch_free_string(&new_dn);
+ new_entry = prepend_service_prefix(entry, service);
+ /* Set the new entry as the new result in the pblock and also set the
+ the REP_ENTRY_MUSTBEFREED flag, so that the entry gets free'd when
+ ready. */
slapi_pblock_set(pb, SLAPI_SEARCH_RESULT_ENTRY, new_entry);
}