The Samba-Bugzilla – Attachment 643 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]
Another revision of the same changes.
samba-3.0.6-schema3.patch (text/plain), 19.15 KB, created by
Igor Belyi
on 2004-09-06 23:01:43 UTC
(
hide
)
Description:
Another revision of the same changes.
Filename:
MIME Type:
Creator:
Igor Belyi
Created:
2004-09-06 23:01:43 UTC
Size:
19.15 KB
patch
obsolete
>diff -ru samba-3.0.6.orig/source/include/includes.h samba-3.0.6/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/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/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/source/include/smbldap.h 2004-09-06 23:46:39.000000000 -0400 >@@ -149,8 +149,17 @@ > smb_event_id_t event_id; > > struct timeval last_rebind; >+ >+ void *ObjectClass_OID_Hash; >+ void *ObjectClass_Name_Hash; >+ void *AttributeType_OID_Hash; >+ void *AttributeType_Name_Hash; > }; > >+char** smbldap_getRemovableAttrs(struct smbldap_state *ldap_state, >+ LDAPMessage * entry, const char *objectClass); >+void smbldap_freeRemovableAttrs(char** delAttrs); >+ > #endif /* HAVE_LDAP */ > > struct smbldap_state; >diff -ru samba-3.0.6.orig/source/lib/smbldap.c samba-3.0.6/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/source/lib/smbldap.c 2004-09-07 01:57:35.000000000 -0400 >@@ -159,6 +159,432 @@ > { 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; >+ >+static void hash_destroy(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; >+ } >+ 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); >+} >+ >+static int hash_create(int size, schema_hash_table_t *hash, >+ void (*cleanFn)(void*)) >+{ >+ unsigned int i; >+ >+ hash->cleanFn = cleanFn; >+ 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 schema into a hash for easy retrieval >+ * params: >+ * values - schema strings whose objects need to be hashed. >+ * 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(char **values, >+ schema_hash_table_t *OID_Hash, >+ schema_hash_table_t *Name_Hash, >+ void (*cleanFn)(void*), >+ void* (*getOIDandNames)(char*, char**, char***)) >+{ >+ int count, i; >+ >+ count = ldap_count_values(values); >+ >+ /* Reset hash tables */ >+ hash_destroy(OID_Hash); >+ if( hash_create(count, OID_Hash, cleanFn) == 0 ) >+ return LDAP_NO_MEMORY; >+ >+ hash_destroy(Name_Hash); >+ if( hash_create(count, Name_Hash, NULL) == 0 ) >+ return 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)); >+ return LDAP_NO_MEMORY; >+ } >+ >+ 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)); >+ return LDAP_NO_MEMORY; >+ } >+ } >+ } >+ } >+ >+ return LDAP_SUCCESS; >+} >+ >+/* >+ * 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; >+} >+ >+/* Read and hash objectClass and attributeType schemas */ >+static int smbldap_read_schema(struct smbldap_state *ldap_state) >+{ >+ LDAPMessage *res, *entry; >+ LDAP* ldap_struct = ldap_state->ldap_struct; >+ int rc; >+ char **values; >+ char *schAttrs[3] = {"objectClasses", "attributeTypes", 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); >+ >+ values = ldap_get_values(ldap_struct, entry, schAttrs[0]); >+ rc = smbldap_hash_schema(values, >+ ldap_state->ObjectClass_OID_Hash, >+ ldap_state->ObjectClass_Name_Hash, >+ (void (*)(void*))ldap_objectclass_free, >+ getObjOIDandNames); >+ ldap_value_free(values); >+ >+ if(rc == LDAP_SUCCESS) { >+ values = ldap_get_values(ldap_struct, entry, schAttrs[1]); >+ rc = smbldap_hash_schema(values, >+ ldap_state->AttributeType_OID_Hash, >+ ldap_state->AttributeType_Name_Hash, >+ (void (*)(void*))ldap_attributetype_free, >+ getAttrOIDandNames); >+ ldap_value_free(values); >+ } >+ >+ ldap_memfree(res); >+ return rc; >+} >+ >+/* Free hashes used to keep schemas */ >+static void smbldap_free_schema(struct smbldap_state *ldap_state) >+{ >+ hash_destroy(ldap_state->ObjectClass_Name_Hash); >+ hash_destroy(ldap_state->ObjectClass_OID_Hash); >+ hash_destroy(ldap_state->AttributeType_Name_Hash); >+ hash_destroy(ldap_state->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(struct smbldap_state *ldap_state, >+ LDAPMessage *entry, >+ const char* objectClass) >+{ >+ LDAPAttributeType* valueType; >+ LDAP *ldap_struct = ldap_state->ldap_struct; >+ int count, i; >+ BerElement *berP; >+ char *attr, **classes, **curr, **delAttrs = NULL; >+ schema_hash_entry_t item, *result, *objectClassItem; >+ schema_hash_table_t objectAttrHash; >+ schema_hash_table_t otherAttrHash; >+ >+ /* >+ * 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, ldap_state->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, ldap_state->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; >+ >+ /* Hash attributes belonging to objectClasses but not to _objectClass_. */ >+ classes = ldap_get_values(ldap_struct, entry, "objectClass"); >+ for(i=0; result && classes[i]; i++) { >+ item.key = classes[i]; >+ result = hash_search(item, FIND, ldap_state->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); >+ >+ /* 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; >+ >+ /* Iterate 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, ldap_state->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_destroy(&objectAttrHash); >+ 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 +1276,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))) { >+ 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")); >@@ -1137,6 +1572,7 @@ > > SAFE_FREE((*ldap_state)->bind_dn); > SAFE_FREE((*ldap_state)->bind_secret); >+ smbldap_free_schema(*ldap_state); > > smb_unregister_idle_event((*ldap_state)->event_id); > >@@ -1164,6 +1600,18 @@ > (*smbldap_state)->uri = "ldap://localhost"; > } > >+ (*smbldap_state)->ObjectClass_OID_Hash = talloc_zero(mem_ctx, sizeof(schema_hash_table_t)); >+ (*smbldap_state)->ObjectClass_Name_Hash = talloc_zero(mem_ctx, sizeof(schema_hash_table_t)); >+ (*smbldap_state)->AttributeType_OID_Hash = talloc_zero(mem_ctx, sizeof(schema_hash_table_t)); >+ (*smbldap_state)->AttributeType_Name_Hash = talloc_zero(mem_ctx, sizeof(schema_hash_table_t)); >+ if(!(*smbldap_state)->ObjectClass_OID_Hash || >+ !(*smbldap_state)->ObjectClass_Name_Hash || >+ !(*smbldap_state)->AttributeType_OID_Hash || >+ !(*smbldap_state)->AttributeType_Name_Hash) { >+ DEBUG(0, ("talloc() failed for one of LDAP schema hashes.\n")); >+ return NT_STATUS_NO_MEMORY; >+ } >+ > (*smbldap_state)->event_id = > smb_register_idle_event(smbldap_idle_fn, (void *)(*smbldap_state), > SMBLDAP_IDLE_TIME); >diff -ru samba-3.0.6.orig/source/passdb/pdb_ldap.c samba-3.0.6/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/source/passdb/pdb_ldap.c 2004-09-06 23:47:13.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, 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); >diff -ru samba-3.0.6.orig/source/rpc_server/srv_samr_nt.c samba-3.0.6/source/rpc_server/srv_samr_nt.c >--- samba-3.0.6.orig/source/rpc_server/srv_samr_nt.c 2004-05-25 10:09:33.000000000 -0400 >+++ samba-3.0.6/source/rpc_server/srv_samr_nt.c 2004-09-06 12:36:16.000000000 -0400 >@@ -3668,6 +3668,13 @@ > return NT_STATUS_NO_SUCH_USER; > } > >+ /* and delete the samba side */ >+ if (!pdb_delete_sam_account(sam_pass)) { >+ DEBUG(5,("_samr_delete_dom_user:Failed to delete entry for user %s.\n", pdb_get_username(sam_pass))); >+ pdb_free_sam(&sam_pass); >+ return NT_STATUS_CANNOT_DELETE; >+ } >+ > /* delete the unix side */ > /* > * note: we don't check if the delete really happened >@@ -3676,13 +3683,6 @@ > */ > smb_delete_user(pdb_get_username(sam_pass)); > >- /* and delete the samba side */ >- if (!pdb_delete_sam_account(sam_pass)) { >- DEBUG(5,("_samr_delete_dom_user:Failed to delete entry for user %s.\n", pdb_get_username(sam_pass))); >- pdb_free_sam(&sam_pass); >- return NT_STATUS_CANNOT_DELETE; >- } >- > pdb_free_sam(&sam_pass); > > if (!close_policy_hnd(p, &q_u->user_pol))
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