The Samba-Bugzilla – Attachment 640 Details for
Bug 762
ldap Naming violation when deleting user with pdbedit
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch to fix deletion of Samba attributes
samba-3.0.6-schema.patch (text/plain), 18.27 KB, created by
Igor Belyi
on 2004-09-05 18:54:15 UTC
(
hide
)
Description:
Patch to fix deletion of Samba attributes
Filename:
MIME Type:
Creator:
Igor Belyi
Created:
2004-09-05 18:54:15 UTC
Size:
18.27 KB
patch
obsolete
>diff -ru samba-3.0.6.orig/source/include/includes.h samba-3.0.6.new/source/include/includes.h >--- samba-3.0.6.orig/source/include/includes.h 2004-08-19 09:39:13.000000000 -0400 >+++ samba-3.0.6.new/source/include/includes.h 2004-09-04 14:06:25.000000000 -0400 >@@ -409,6 +409,7 @@ > > #if HAVE_LDAP_H > #include <ldap.h> >+#include <ldap_schema.h> > #else > #undef HAVE_LDAP > #endif >diff -ru samba-3.0.6.orig/source/include/smbldap.h samba-3.0.6.new/source/include/smbldap.h >--- samba-3.0.6.orig/source/include/smbldap.h 2004-08-19 09:39:13.000000000 -0400 >+++ samba-3.0.6.new/source/include/smbldap.h 2004-09-05 14:30:45.000000000 -0400 >@@ -129,6 +129,9 @@ > int max_len); > BOOL smbldap_get_single_pstring (LDAP * ldap_struct, LDAPMessage * entry, > const char *attribute, pstring value); >+char** smbldap_getRemovableAttrs(LDAP * ldap_struct, LDAPMessage * entry, >+ const char *objectClass); >+void smbldap_freeRemovableAttrs(char** delAttrs); > > /** > * Struct to keep the state for all the ldap stuff >diff -ru samba-3.0.6.orig/source/lib/smbldap.c samba-3.0.6.new/source/lib/smbldap.c >--- samba-3.0.6.orig/source/lib/smbldap.c 2004-08-19 09:39:12.000000000 -0400 >+++ samba-3.0.6.new/source/lib/smbldap.c 2004-09-05 20:21:50.000000000 -0400 >@@ -159,6 +159,470 @@ > { LDAP_ATTR_LIST_END, NULL } > }; > >+/* >+ * This is local Schema specific implementation of hash. >+ * Neither ./hash.c nor <search.h> implementations serve our needs. >+ * But we do borrow some ideas from both of them. >+ * The main features required by our hash model for schema are: >+ * 1: keys are pointers inside data area. >+ * 2: cleanup function can be different for different hashes >+ * 3: comparison AND hashing should be case insensitive >+ */ >+typedef struct schema_hash_entry { >+ const char *key; >+ void *data; >+ struct schema_hash_entry *next; >+} schema_hash_entry_t; >+ >+typedef struct schema_hash_table { >+ int size; >+ struct schema_hash_entry **table; >+ void (*cleanFn)(void*); >+} schema_hash_table_t; >+ >+typedef enum hash_action {ENTER, FIND} hash_action_t; >+ >+/* >+ * hash_clean() and hash_destroy() are separate for a small optimization by >+ * not recreating hash->table if its size will fit new items. >+ */ >+static void hash_clean(schema_hash_table_t *hash) >+{ >+ int i; >+ schema_hash_entry_t *curr, *next; >+ for(i=0; i<hash->size; i++) { >+ for(curr = hash->table[i]; curr; curr=next) { >+ next = curr->next; >+ if(hash->cleanFn) >+ (*(hash->cleanFn))(curr->data); >+ free(curr); >+ } >+ hash->table[i] = NULL; >+ } >+} >+ >+static void hash_destroy(schema_hash_table_t *hash) >+{ >+ if(hash->table) free(hash->table); >+ hash->table = NULL; >+ hash->size = 0; >+} >+ >+/* primes[] and string_hash are taken from ./hash.c */ >+static unsigned primes[] = >+ {17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209, 16411}; >+ >+/* We need to have string_hash case insensitive */ >+static int string_hash(int hash_size, const char *key) >+{ >+ unsigned int n = 0; >+ const char *p; >+ for (p = key; *p != '\0'; p++) { >+ n = ((n << 5) + n) ^ (unsigned int)tolower(*p); >+ } >+ return (n % hash_size); >+} >+ >+/* Note that _hash_ is suppose to be initialized with at least {0, NULL, NULL} >+ * for hash_create to work correctly (just look at the first 'if'). */ >+static int hash_create(int size, schema_hash_table_t *hash, >+ void (*cleanFn)(void*)) >+{ >+ unsigned int i; >+ >+ if(hash->table != NULL) >+ hash_clean(hash); >+ >+ hash->cleanFn = cleanFn; >+ >+ if(size <= hash->size) >+ return hash->size; >+ >+ free(hash->table); >+ >+ hash->size = 2; >+ while (hash->size < size) >+ hash->size <<= 1; >+ >+ for (i = 0; i < sizeof(primes); i++) { >+ if (primes[i] > hash->size) { >+ hash->size = primes[i]; >+ break; >+ } >+ } >+ >+ hash->table = (schema_hash_entry_t**) >+ malloc(hash->size * sizeof(schema_hash_entry_t*)); >+ if(hash->table == NULL) >+ hash->size = 0; >+ else >+ memset((void*)hash->table, 0, hash->size * sizeof(schema_hash_entry_t*)); >+ >+ return hash->size; >+} >+ >+static schema_hash_entry_t *hash_search(schema_hash_entry_t entry, >+ hash_action_t action, >+ schema_hash_table_t *hash) >+{ >+ schema_hash_entry_t *result; >+ int hashsum = string_hash(hash->size, entry.key); >+ >+ for(result = hash->table[hashsum]; result; result=result->next) >+ if(!StrCaseCmp(result->key, entry.key)) >+ break; >+ >+ if(result == NULL && action == ENTER) { >+ result = (schema_hash_entry_t*)malloc(sizeof(schema_hash_entry_t)); >+ if(result) { >+ result->key = entry.key; >+ result->data = (void*) entry.data; >+ result->next = hash->table[hashsum]; >+ hash->table[hashsum] = result; >+ } >+ } >+ >+ return result; >+} >+ >+/* >+ * smbldap_hash_schema - put read schema into a hash for easy retrieval >+ * params: >+ * ldapp - LDAP structure/connection handle >+ * schAttr - attribute corresponding to a schema to hash. >+ * OID_Hash - pointer to table to hash into by OID >+ * Name_Hash - pointer to table to hash into by Name >+ * cleanFn - cleanup function for the data. >+ * getOIDandNames - function to convert string into an object and return >+ * pointers to OID string and to array of Name strings. >+ * OID and Name pointers should point inside the object. >+ */ >+static int smbldap_hash_schema(LDAP* ldap_struct, char *schAttr, >+ schema_hash_table_t *OID_Hash, >+ schema_hash_table_t *Name_Hash, >+ void (*cleanFn)(void*), >+ void* (*getOIDandNames)(char*, char**, char***)) >+{ >+ LDAPMessage *res, *entry; >+ int rc, count, i; >+ BerElement *berP; >+ char *attr, **values; >+ char *schAttrs[2] = {schAttr, NULL}; >+ >+ /* >+ * We don't use smbldap_search here since read of schema is done in >+ * smbldap_open which in turn is used by smbldap_search and potentially >+ * would result in an infinite loop. >+ */ >+ if((rc = ldap_search_s(ldap_struct, >+ "cn=subschema", >+ LDAP_SCOPE_BASE, >+ "(objectClass=*)", >+ schAttrs, 0, &res)) != LDAP_SUCCESS) { >+ DEBUG(0, ("ldap_search_s: failed for \"cn=subschema\". %s (%d)\n", >+ ldap_err2string(rc), rc)); >+ return rc; >+ } >+ >+ /* LDAP_SCOPE_BASE returns only one entry so we need only the first one */ >+ entry = ldap_first_entry(ldap_struct, res); >+ /* We asked for one attribute only so we need only the first one */ >+ attr = ldap_first_attribute(ldap_struct, entry, &berP); >+ values = ldap_get_values(ldap_struct, entry, attr); >+ count = ldap_count_values(values); >+ >+ /* Reset hash tables */ >+ if( hash_create(count, Name_Hash, NULL) == 0 || >+ hash_create(count, OID_Hash, cleanFn) == 0) { >+ rc = LDAP_NO_MEMORY; >+ } else >+ for(i=0; values[i]; i++) { >+ char* oid; >+ char** names; >+ schema_hash_entry_t item; >+ item.data = (*getOIDandNames)(values[i], &oid, &names); >+ >+ if(item.data) { >+ char **curr; >+ schema_hash_entry_t *result; >+ >+ item.key = oid; >+ result = hash_search(item, ENTER, OID_Hash); >+ if(result == NULL) { >+ DEBUG(0, ("Failed to enter '%s' hash item\n", item.key)); >+ rc = LDAP_NO_MEMORY; >+ break; >+ } >+ >+ for(curr = names; *curr; curr++) { >+ item.key = *curr; >+ result = hash_search(item, ENTER, Name_Hash); >+ if(result == NULL) { >+ DEBUG(0, ("Failed to enter '%s' hash item\n", item.key)); >+ rc = LDAP_NO_MEMORY; >+ break; >+ } >+ } >+ if(result == NULL) >+ break; >+ } >+ } >+ >+ ldap_value_free(values); >+ ldap_memfree(attr); >+ ber_memfree(berP); >+ ldap_memfree(res); >+ >+ return rc; >+} >+ >+/* >+ * Auxilary function to retrive OID and Names from an ObjectClass >+ * schema string. >+ */ >+static void *getObjOIDandNames(char *value, char** oid, char*** names) >+{ >+ int code; >+ const char *err; >+ LDAPObjectClass *result = ldap_str2objectclass(value, &code, &err, >+ LDAP_SCHEMA_ALLOW_NONE); >+ if(result) { >+ *oid = result->oc_oid; >+ *names = result->oc_names; >+ } >+ return result; >+} >+ >+/* >+ * Auxilary function to retrive OID and Names from an AttributeType >+ * schema string. >+ */ >+static void *getAttrOIDandNames(char *value, char** oid, char*** names) >+{ >+ int code; >+ const char *err; >+ LDAPAttributeType *result = ldap_str2attributetype(value, &code, &err, >+ LDAP_SCHEMA_ALLOW_NONE); >+ if(result) { >+ *oid = result->at_oid; >+ *names = result->at_names; >+ } >+ return result; >+} >+ >+static schema_hash_table_t ObjectClass_OID_Hash = {0, NULL, NULL}; >+static schema_hash_table_t ObjectClass_Name_Hash = {0, NULL, NULL}; >+static schema_hash_table_t AttributeType_OID_Hash = {0, NULL, NULL}; >+static schema_hash_table_t AttributeType_Name_Hash = {0, NULL, NULL}; >+ >+/* Read and hash objectClass and attributeType schemas */ >+static int smbldap_read_schema(LDAP* ldap_struct) >+{ >+ int rc; >+ >+ if((rc = smbldap_hash_schema(ldap_struct, "objectClasses", >+ &ObjectClass_OID_Hash, >+ &ObjectClass_Name_Hash, >+ (void (*)(void*))ldap_objectclass_free, >+ getObjOIDandNames)) != LDAP_SUCCESS || >+ (rc = smbldap_hash_schema(ldap_struct, "attributeTypes", >+ &AttributeType_OID_Hash, >+ &AttributeType_Name_Hash, >+ (void (*)(void*))ldap_attributetype_free, >+ getAttrOIDandNames)) != LDAP_SUCCESS) >+ return rc; >+ >+ return LDAP_SUCCESS; >+} >+ >+/* Free hashes used to keep schemas */ >+static void smbldap_free_schema() >+{ >+ hash_clean(&ObjectClass_Name_Hash); >+ hash_destroy(&ObjectClass_Name_Hash); >+ hash_clean(&ObjectClass_OID_Hash); >+ hash_destroy(&ObjectClass_OID_Hash); >+ hash_clean(&AttributeType_Name_Hash); >+ hash_destroy(&AttributeType_Name_Hash); >+ hash_clean(&AttributeType_OID_Hash); >+ hash_destroy(&AttributeType_OID_Hash); >+} >+ >+/* >+ * smbldap_getRemovableAttrs - return an array of attributes which can be >+ * removed from the _entry_ to remove _objectClass_ >+ * from it without leaving it in an alegal state. >+ * params: >+ * ldap_struct - LDAP structure/connection handle >+ * entry - the entry we want to free from _objectClass_ >+ * objectClass - the class we want to remove from the _entry_. >+ * return: >+ * NULL terminated array of attributes eligible for delition. This array >+ * should be freed with a call to smbldap_freeRemovableAttrs after use. >+ * on errors: >+ * return NULL >+ */ >+char** smbldap_getRemovableAttrs(LDAP *ldap_struct, >+ LDAPMessage *entry, >+ const char* objectClass) >+{ >+ LDAPAttributeType* valueType; >+ int count, i; >+ BerElement *berP; >+ char *attr, **classes, **curr, **delAttrs = NULL; >+ schema_hash_entry_t item, *result, *objectClassItem; >+ schema_hash_table_t objectAttrHash = {0, NULL, NULL}; >+ schema_hash_table_t otherAttrHash = {0, NULL, NULL}; >+ >+ /* >+ * Retrieve schema information about _objectClass_ from the hashed LDAP >+ * schema. >+ * Return an error if there's no information about objectClass. >+ */ >+ item.key = objectClass; >+ objectClassItem = hash_search(item, FIND, &ObjectClass_Name_Hash); >+ if(objectClassItem == NULL) >+ return NULL; >+ >+ /* Create auxilary hashes. >+ * objectAttrHash - keeps Attributes used by _objectClass_. >+ * otherAttrHash - keeps Attributes used by other than _objectClass_ >+ * objectClasses >+ * Note: I don't like numbers to come from the top of people heads but this >+ * 25 bellow come exactly from there (my head). 25 is the number of >+ * sambaSamAccount attributes and approximate number of other attributes >+ * in my user entries. (Igor) >+ */ >+ if( hash_create(25, &objectAttrHash, NULL) == 0 || >+ hash_create(25, &otherAttrHash, NULL) == 0) >+ goto attr_errors; >+ >+ /* macro to hash objects of _names_ attributes in _hash_ by their OID >+ * This macro also counts number of attributes in _count_ variable. */ >+#define ADD_ATTRS_OID(names, hash) { \ >+ for(curr=names; result && curr && *curr; curr++, count++) { \ >+ item.key = *curr; \ >+ result = hash_search(item, FIND, &AttributeType_Name_Hash); \ >+ if(result) { \ >+ valueType = result->data; \ >+ item.key = valueType->at_oid; \ >+ item.data = valueType; \ >+ result = hash_search(item, ENTER, &hash); \ >+ } \ >+ } \ >+ } >+ >+ /* macro to fill _hash_ with all _classItem_ attributes. >+ * Note that both attributes which must be present and which may be present >+ * in _classItem_ should be put in _hash_ since similary influence which >+ * attributes should be deleted and which ones should be left untouched. */ >+#define FILL_CLASS_ATTRS(classItem, hash) { \ >+ LDAPObjectClass *valueClass = classItem->data; \ >+ ADD_ATTRS_OID(valueClass->oc_at_oids_must, hash); \ >+ ADD_ATTRS_OID(valueClass->oc_at_oids_may, hash); \ >+ } >+ >+ /* Just to make sure that _result_ is not NULL for the first iteration */ >+ result = &item; >+ >+ /* First iteration over entry's attributes to hash in _otherAttrHash_ >+ * attributes belonging to objectClasses but not to _objectClass_. */ >+ for(attr = ldap_first_attribute(ldap_struct, entry, &berP); >+ result && attr; >+ attr = ldap_next_attribute(ldap_struct, entry, berP)) { >+ if(!StrCaseCmp(attr, "objectClass")) { >+ classes = ldap_get_values(ldap_struct, entry, attr); >+ for(i=0; result && classes[i]; i++) { >+ item.key = classes[i]; >+ result = hash_search(item, FIND, &ObjectClass_Name_Hash); >+ >+ /* Compare 'data' field instead of names since classes can >+ * have different names but 'data' corresponds to a unique OID */ >+ if(result && result->data != objectClassItem->data) >+ FILL_CLASS_ATTRS(result, otherAttrHash); >+ } >+ ldap_value_free(classes); >+ } >+ ldap_memfree(attr); >+ } >+ ber_memfree(berP); >+ >+ /* Hash all _objectClass_ attributes in _objectAttrHash_ */ >+ count = 0; >+ FILL_CLASS_ATTRS(objectClassItem, objectAttrHash); >+ >+#undef ADD_ATTR_OID >+#undef FILL_CLASS_ATTRS >+ >+ /* >+ * _result_ equal NULL can mean one of the following: >+ * 1. one of entry's objectClasses is not in LDAP schema. >+ * 2. one of entry's objectClasses has attribute in its schema which does >+ * not have its schema in LDAP. >+ * 3. attribute fail to be entered into _otherAttrHash_ or _objectAttrHash_ >+ * First two can fail if schema wasn't read correctly or if we have very >+ * bad LDAP servers. Anyway we won't be able to use LDAP schema. >+ */ >+ if(result == NULL) >+ goto attr_errors; >+ >+ /* _count_ contains number of attributes in _objectClass_ which is an >+ * upper bound for number of attributes we will return */ >+ delAttrs = (char**)malloc((count+1) * sizeof(char*)); >+ if(delAttrs == NULL) >+ goto attr_errors; >+ >+ /* Second iteration over entry's attributes to put some of them belonging >+ * to _objectClass_ but not to other objectClasses in delAttrs array. */ >+ curr = delAttrs; >+ for(attr = ldap_first_attribute(ldap_struct, entry, &berP); >+ result && attr; >+ attr = ldap_next_attribute(ldap_struct, entry, berP)) { >+ if(StrCaseCmp(attr, "objectClass")) { >+ item.key = attr; >+ result = hash_search(item, FIND, &AttributeType_Name_Hash); >+ if(result) { >+ valueType = result->data; >+ item.key = valueType->at_oid; >+ if(hash_search(item, FIND, &objectAttrHash) != NULL && >+ hash_search(item, FIND, &otherAttrHash) == NULL) { >+ /* Use _attr_ directly and jump with 'continure' to avoid its memory >+ * to be freed. It will be freed in smbldap_freeRemovableAttrs. */ >+ *curr++ = attr; >+ continue; >+ } >+ } >+ } >+ ldap_memfree(attr); >+ } >+ ber_memfree(berP); >+ *curr = NULL; >+ >+ if(result == NULL) { >+ smbldap_freeRemovableAttrs(delAttrs); >+ delAttrs = NULL; >+ } >+ >+ attr_errors: >+ hash_clean(&objectAttrHash); >+ hash_destroy(&objectAttrHash); >+ hash_clean(&otherAttrHash); >+ hash_destroy(&otherAttrHash); >+ >+ return delAttrs; >+} >+ >+void smbldap_freeRemovableAttrs(char** delAttrs) >+{ >+ char **curr; >+ if(delAttrs) { >+ for(curr = delAttrs; *curr; curr++) >+ ldap_memfree(*curr); >+ free(delAttrs); >+ } >+} >+ >+ > /********************************************************************** > perform a simple table lookup and return the attribute name > **********************************************************************/ >@@ -850,6 +1314,15 @@ > return rc; > } > >+ /* >+ * We need to read LDAP schema here since this is where connection >+ * was just established or reestablished after being closed. >+ * We should always read schema here since LDAP could have >+ * been restarted with new schemas while we were not connected. >+ */ >+ if((rc = smbldap_read_schema(ldap_state->ldap_struct))) { >+ DEBUG(0,("Failed to read LDAP schema. We'll work without it\n")); >+ } > > ldap_state->last_ping = time(NULL); > DEBUG(4,("The LDAP server is succesfully connected\n")); >diff -ru samba-3.0.6.orig/source/passdb/pdb_ldap.c samba-3.0.6.new/source/passdb/pdb_ldap.c >--- samba-3.0.6.orig/source/passdb/pdb_ldap.c 2004-08-19 09:39:13.000000000 -0400 >+++ samba-3.0.6.new/source/passdb/pdb_ldap.c 2004-09-05 20:23:40.000000000 -0400 >@@ -260,7 +260,7 @@ > int rc; > LDAPMessage *entry = NULL; > LDAPMod **mods = NULL; >- char *name, *dn; >+ char *name, *dn, **delAttrs = NULL; > BerElement *ptr = NULL; > > rc = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result); >@@ -289,8 +289,17 @@ > } > > /* Ok, delete only the SAM attributes */ >- >- for (name = ldap_first_attribute(ldap_state->smbldap_state->ldap_struct, entry, &ptr); >+ >+ delAttrs = smbldap_getRemovableAttrs(ldap_state->smbldap_state->ldap_struct, entry, objectclass); >+ if(delAttrs) { >+ char **attrib; >+ for (attrib = delAttrs; *attrib; attrib++) { >+ DEBUG(10, ("ldapsam_delete_entry: deleting attribute %s\n", *attrib)); >+ smbldap_set_mod(&mods, LDAP_MOD_DELETE, *attrib, NULL); >+ } >+ smbldap_freeRemovableAttrs(delAttrs); >+ } else { >+ for (name = ldap_first_attribute(ldap_state->smbldap_state->ldap_struct, entry, &ptr); > name != NULL; > name = ldap_next_attribute(ldap_state->smbldap_state->ldap_struct, entry, ptr)) { > char **attrib; >@@ -300,7 +309,7 @@ > > for (attrib = attrs; *attrib != NULL; attrib++) { > if ((StrCaseCmp(*attrib, name) == 0) && >- !(StrCaseCmp(*attrib, >+ (StrCaseCmp(*attrib, > get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_MOD_TIMESTAMP)))) { > DEBUG(10, ("ldapsam_delete_entry: deleting attribute %s\n", name)); > smbldap_set_mod(&mods, LDAP_MOD_DELETE, name, NULL); >@@ -308,12 +317,13 @@ > } > > ldap_memfree(name); >- } >+ } > >- if (ptr != NULL) { >+ if (ptr != NULL) { > ber_free(ptr, 0); >+ } > } >- >+ > smbldap_set_mod(&mods, LDAP_MOD_DELETE, "objectClass", objectclass); > > rc = smbldap_modify(ldap_state->smbldap_state, dn, mods);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 762
:
281
|
410
|
427
|
640
|
641
|
642
|
643