From 77ad00d4135375af6bdd82524ed6570d4687c71f Mon Sep 17 00:00:00 2001 From: Alexander Sulfrian Date: Tue, 19 Jan 2016 01:41:22 +0100 Subject: 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. --- service_passwords.c | 132 ++++++++++++++++++++++++++++++++++++---------------- 1 file 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=" 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); } -- cgit v1.2.3-1-g7c22