[Asterisk-code-review] res config ldap: Don't try to delete non-existent attributes (asterisk[13])
Sean Bright
asteriskteam at digium.com
Mon Feb 20 06:00:17 CST 2017
Sean Bright has uploaded a new change for review. ( https://gerrit.asterisk.org/5008 )
Change subject: res_config_ldap: Don't try to delete non-existent attributes
......................................................................
res_config_ldap: Don't try to delete non-existent attributes
OpenLDAP will raise an error when we try to delete an LDAP attribute
that doesn't exist. We need to filter out LDAP_MOD_DELETE requests
based on which attributes the current LDAP entry actually has. There
is of course a small window of opportunity for this to still fail,
but it is much less likely now.
Change-Id: I3fe1b04472733e43151563aaf9f8b49980273e6b
---
M res/res_config_ldap.c
1 file changed, 104 insertions(+), 2 deletions(-)
git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/08/5008/1
diff --git a/res/res_config_ldap.c b/res/res_config_ldap.c
index b004e78..374f0db 100644
--- a/res/res_config_ldap.c
+++ b/res/res_config_ldap.c
@@ -1214,6 +1214,90 @@
return cfg;
}
+/*!
+ * \internal
+ * \brief Remove LDAP_MOD_DELETE modifications that will not succeed
+ *
+ * \details
+ * A LDAP_MOD_DELETE operation will fail if the LDAP entry does not already have
+ * the corresponding attribute. Because we may be updating multiple LDAP entries
+ * in a single call to update_ldap(), we may need our own copy of the
+ * modifications array for each one.
+ *
+ * \note
+ * This function dynamically allocates memory. If it returns a non-NULL pointer,
+ * it is up to the caller to free it with ldap_mods_free()
+ *
+ * \returns an LDAPMod * if modifications needed to be removed, NULL otherwise.
+ */
+static LDAPMod **massage_mods_for_entry(LDAPMessage *entry, LDAPMod **mods, size_t count)
+{
+ size_t i;
+ int remove[count];
+ size_t remove_count = 0;
+
+ for (i = 0; i < count; i++) {
+ BerElement *ber = NULL;
+ char *attribute;
+ int exists = 0;
+
+ if (mods[i]->mod_op != LDAP_MOD_DELETE) {
+ continue;
+ }
+
+ /* If we are deleting something, it has to exist */
+ attribute = ldap_first_attribute(ldapConn, entry, &ber);
+ while (attribute) {
+ if (!strcasecmp(attribute, mods[i]->mod_type)) {
+ /* OK, we have the attribute */
+ exists = 1;
+ ldap_memfree(attribute);
+ break;
+ }
+
+ ldap_memfree(attribute);
+ attribute = ldap_next_attribute(ldapConn, entry, ber);
+ }
+
+ if (!exists) {
+ remove[remove_count++] = i;
+ }
+ }
+
+ if (remove_count) {
+ size_t k, remove_index;
+ LDAPMod **x = ldap_memcalloc(count - remove_count + 1, sizeof(LDAPMod *));
+ for (i = 0, k = 0; i < count; i++) {
+ int skip = 0;
+ /* Is this one we have to remove? */
+ for (remove_index = 0; !skip && remove_index < remove_count; remove_index++) {
+ skip = (remove[remove_index] == i);
+ }
+
+ if (skip) {
+ ast_debug(3, "Skipping %s deletion because it doesn't exist\n",
+ mods[i]->mod_type);
+ continue;
+ }
+
+ x[k] = ldap_memcalloc(1, sizeof(LDAPMod));
+ x[k]->mod_op = mods[i]->mod_op;
+ x[k]->mod_type = ldap_strdup(mods[i]->mod_type);
+ if (mods[i]->mod_values) {
+ x[k]->mod_values = ldap_memcalloc(2, sizeof(char *));
+ x[k]->mod_values[0] = ldap_strdup(mods[i]->mod_values[0]);
+ }
+ k++;
+ }
+ /* NULL terminate */
+ x[k] = NULL;
+ return x;
+ }
+
+ return NULL;
+}
+
+
/* \brief Function to update a set of values in ldap static mode
*/
static int update_ldap(const char *basedn, const char *table_name, const char *attribute,
@@ -1378,12 +1462,30 @@
}
ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
- for (i = 0; ldap_entry; i++) {
+ for (i = 0; ldap_entry; i++) {
+ LDAPMod **working = ldap_mods;
+ LDAPMod **massaged = massage_mods_for_entry(ldap_entry, ldap_mods, mods_size - 1);
+
+ if (massaged) {
+ /* Did we massage everything out of the list? */
+ if (massaged[0] == NULL) {
+ ast_debug(3, "Nothing left to modify - skipping\n");
+ ldap_mods_free(massaged, 1);
+ continue;
+ }
+ working = massaged;
+ }
+
dn = ldap_get_dn(ldapConn, ldap_entry);
- if ((error = ldap_modify_ext_s(ldapConn, dn, ldap_mods, NULL, NULL)) != LDAP_SUCCESS) {
+ if ((error = ldap_modify_ext_s(ldapConn, dn, working, NULL, NULL)) != LDAP_SUCCESS) {
ast_log(LOG_ERROR, "Couldn't modify '%s'='%s', dn:%s because %s\n",
attribute, lookup, dn, ldap_err2string(error));
}
+
+ if (massaged) {
+ ldap_mods_free(massaged, 1);
+ }
+
ldap_memfree(dn);
ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
}
--
To view, visit https://gerrit.asterisk.org/5008
To unsubscribe, visit https://gerrit.asterisk.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I3fe1b04472733e43151563aaf9f8b49980273e6b
Gerrit-PatchSet: 1
Gerrit-Project: asterisk
Gerrit-Branch: 13
Gerrit-Owner: Sean Bright <sean.bright at gmail.com>
More information about the asterisk-code-review
mailing list