mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 10:47:18 +00:00 
			
		
		
		
	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
This commit is contained in:
		| @@ -1212,6 +1212,90 @@ static struct ast_config *config_ldap(const char *basedn, const char *table_name | ||||
| 	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, | ||||
| @@ -1376,12 +1460,30 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a | ||||
| 		} | ||||
| 		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); | ||||
| 		} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user