From 10c1480d166ec8ab3c15a4c3c4597506029980be Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 7 Aug 2007 03:33:26 +0000 Subject: r24259: Rework the objectclass module to use the new schema, rather than the ldb_subclass list. Next step will be to have this module also set the objectCategory and default ntSecurityDescriptor Andrew Bartlett (This used to be commit 0f7135a4685a1117a54c2f019df6c6de22b8dd32) --- source4/dsdb/samdb/ldb_modules/objectclass.c | 691 +++++++++++++++++++++++++++ 1 file changed, 691 insertions(+) create mode 100644 source4/dsdb/samdb/ldb_modules/objectclass.c (limited to 'source4/dsdb/samdb/ldb_modules/objectclass.c') diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c new file mode 100644 index 0000000000..ad11442035 --- /dev/null +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -0,0 +1,691 @@ +/* + ldb database library + + Copyright (C) Simo Sorce 2006 + Copyright (C) Andrew Bartlett 2005-2007 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/* + * Name: ldb + * + * Component: objectClass sorting module + * + * Description: sort the objectClass attribute into the class hierarchy + * + * Author: Andrew Bartlett + */ + + +#include "includes.h" +#include "ldb/include/ldb.h" +#include "ldb/include/ldb_errors.h" +#include "ldb/include/ldb_private.h" +#include "dsdb/samdb/samdb.h" +#include "lib/util/dlinklist.h" +struct oc_context { + + enum oc_step {OC_DO_REQ, OC_SEARCH_SELF, OC_DO_MOD} step; + + struct ldb_module *module; + struct ldb_request *orig_req; + + struct ldb_request *down_req; + + struct ldb_request *search_req; + struct ldb_reply *search_res; + + struct ldb_request *mod_req; +}; + +struct class_list { + struct class_list *prev, *next; + const char *objectclass; +}; + +static struct ldb_handle *oc_init_handle(struct ldb_request *req, struct ldb_module *module) +{ + struct oc_context *ac; + struct ldb_handle *h; + + h = talloc_zero(req, struct ldb_handle); + if (h == NULL) { + ldb_set_errstring(module->ldb, "Out of Memory"); + return NULL; + } + + h->module = module; + + ac = talloc_zero(h, struct oc_context); + if (ac == NULL) { + ldb_set_errstring(module->ldb, "Out of Memory"); + talloc_free(h); + return NULL; + } + + h->private_data = (void *)ac; + + h->state = LDB_ASYNC_INIT; + h->status = LDB_SUCCESS; + + ac->module = module; + ac->orig_req = req; + + return h; +} + +static int objectclass_sort(struct ldb_module *module, + TALLOC_CTX *mem_ctx, + struct ldb_message_element *objectclass_element, + struct class_list **sorted_out) +{ + int i; + int layer; + const struct dsdb_schema *schema = dsdb_get_schema(module->ldb); + struct class_list *sorted = NULL, *parent_class = NULL, + *subclass = NULL, *unsorted = NULL, *current, *poss_subclass; + /* DESIGN: + * + * We work on 4 different 'bins' (implemented here as linked lists): + * + * * sorted: the eventual list, in the order we wish to push + * into the database. This is the only ordered list. + * + * * parent_class: The current parent class 'bin' we are + * trying to find subclasses for + * + * * subclass: The subclasses we have found so far + * + * * unsorted: The remaining objectClasses + * + * The process is a matter of filtering objectClasses up from + * unsorted into sorted. Order is irrelevent in the later 3 'bins'. + * + * We start with 'top' (found and promoted to parent_class + * initially). Then we find (in unsorted) all the direct + * subclasses of 'top'. parent_classes is concatenated onto + * the end of 'sorted', and subclass becomes the list in + * parent_class. + * + * We then repeat, until we find no more subclasses. Any left + * over classes are added to the end. + * + */ + + /* Firstly, dump all the objectClass elements into the + * unsorted bin, except for 'top', which is special */ + for (i=0; i < objectclass_element->num_values; i++) { + current = talloc(mem_ctx, struct class_list); + if (!current) { + ldb_set_errstring(module->ldb, "objectclass: out of memory allocating objectclass list"); + talloc_free(mem_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + current->objectclass = (const char *)objectclass_element->values[i].data; + + /* this is the root of the tree. We will start + * looking for subclasses from here */ + if (ldb_attr_cmp("top", current->objectclass) == 0) { + DLIST_ADD_END(parent_class, current, struct class_list *); + } else { + DLIST_ADD_END(unsorted, current, struct class_list *); + } + } + + /* DEBUGGING aid: how many layers are we down now? */ + layer = 0; + do { + layer++; + /* Find all the subclasses of classes in the + * parent_classes. Push them onto the subclass list */ + + /* Ensure we don't bother if there are no unsorted entries left */ + for (current = parent_class; schema && unsorted && current; current = current->next) { + /* Walk the list of possible subclasses in unsorted */ + for (poss_subclass = unsorted; poss_subclass; ) { + const struct dsdb_class *class = dsdb_class_by_lDAPDisplayName(schema, poss_subclass->objectclass); + struct class_list *next; + + /* Save the next pointer, as the DLIST_ macros will change poss_subclass->next */ + next = poss_subclass->next; + + if (ldb_attr_cmp(class->subClassOf, current->objectclass) == 0) { + DLIST_REMOVE(unsorted, poss_subclass); + DLIST_ADD(subclass, poss_subclass); + + break; + } + poss_subclass = next; + } + } + + /* Now push the parent_classes as sorted, we are done with + these. Add to the END of the list by concatenation */ + DLIST_CONCATENATE(sorted, parent_class, struct class_list *); + + /* and now find subclasses of these */ + parent_class = subclass; + subclass = NULL; + + /* If we didn't find any subclasses we will fall out + * the bottom here */ + } while (parent_class); + + /* This shouldn't happen, and would break MMC, but we can't + * afford to loose objectClasses. Perhaps there was no 'top', + * or some other schema error? + * + * Detecting schema errors is the job of the schema module, so + * at this layer we just try not to loose data + */ + DLIST_CONCATENATE(sorted, unsorted, struct class_list *); + + *sorted_out = sorted; + return LDB_SUCCESS; +} + +static int objectclass_add(struct ldb_module *module, struct ldb_request *req) +{ + struct ldb_message_element *objectclass_element; + struct class_list *sorted, *current; + struct ldb_request *down_req; + struct ldb_message *msg; + int ret; + TALLOC_CTX *mem_ctx; + + ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_add\n"); + + if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */ + return ldb_next_request(module, req); + } + + objectclass_element = ldb_msg_find_element(req->op.add.message, "objectClass"); + + /* If no part of this add has an objectClass, then we don't + * need to make any changes. cn=rootdse doesn't have an objectClass */ + if (!objectclass_element) { + return ldb_next_request(module, req); + } + + mem_ctx = talloc_new(req); + if (mem_ctx == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = objectclass_sort(module, mem_ctx, objectclass_element, &sorted); + if (ret != LDB_SUCCESS) { + return ret; + } + + /* prepare the first operation */ + down_req = talloc(req, struct ldb_request); + if (down_req == NULL) { + ldb_set_errstring(module->ldb, "Out of memory!"); + talloc_free(mem_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + *down_req = *req; /* copy the request */ + + down_req->op.add.message = msg = ldb_msg_copy_shallow(down_req, req->op.add.message); + + if (down_req->op.add.message == NULL) { + talloc_free(mem_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + ldb_msg_remove_attr(msg, "objectClass"); + ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL); + + if (ret != LDB_SUCCESS) { + talloc_free(mem_ctx); + return ret; + } + + /* We must completely replace the existing objectClass entry, + * because we need it sorted */ + + /* Move from the linked list back into an ldb msg */ + for (current = sorted; current; current = current->next) { + ret = ldb_msg_add_string(msg, "objectClass", current->objectclass); + if (ret != LDB_SUCCESS) { + ldb_set_errstring(module->ldb, "objectclass: could not re-add sorted objectclass to modify msg"); + talloc_free(mem_ctx); + return ret; + } + } + + talloc_free(mem_ctx); + ret = ldb_msg_sanity_check(module->ldb, msg); + + if (ret != LDB_SUCCESS) { + return ret; + } + + /* go on with the call chain */ + ret = ldb_next_request(module, down_req); + + /* do not free down_req as the call results may be linked to it, + * it will be freed when the upper level request get freed */ + if (ret == LDB_SUCCESS) { + req->handle = down_req->handle; + } + return ret; +} + +static int objectclass_modify(struct ldb_module *module, struct ldb_request *req) +{ + struct ldb_message_element *objectclass_element; + struct ldb_message *msg; + ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_modify\n"); + + if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */ + return ldb_next_request(module, req); + } + + objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass"); + + /* If no part of this touches the objectClass, then we don't + * need to make any changes. */ + /* If the only operation is the deletion of the objectClass then go on */ + if (!objectclass_element) { + return ldb_next_request(module, req); + } + + switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) { + case LDB_FLAG_MOD_DELETE: + /* Delete everything? Probably totally illigal, but hey! */ + if (objectclass_element->num_values == 0) { + return ldb_next_request(module, req); + } + break; + case LDB_FLAG_MOD_REPLACE: + { + struct ldb_request *down_req; + struct class_list *sorted, *current; + TALLOC_CTX *mem_ctx; + int ret; + mem_ctx = talloc_new(req); + if (mem_ctx == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + /* prepare the first operation */ + down_req = talloc(req, struct ldb_request); + if (down_req == NULL) { + ldb_set_errstring(module->ldb, "Out of memory!"); + talloc_free(mem_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + *down_req = *req; /* copy the request */ + + down_req->op.mod.message = msg = ldb_msg_copy_shallow(down_req, req->op.mod.message); + + if (down_req->op.add.message == NULL) { + talloc_free(mem_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = objectclass_sort(module, mem_ctx, objectclass_element, &sorted); + if (ret != LDB_SUCCESS) { + return ret; + } + + /* We must completely replace the existing objectClass entry, + * because we need it sorted */ + + ldb_msg_remove_attr(msg, "objectClass"); + ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL); + + if (ret != LDB_SUCCESS) { + talloc_free(mem_ctx); + return ret; + } + + /* Move from the linked list back into an ldb msg */ + for (current = sorted; current; current = current->next) { + ret = ldb_msg_add_string(msg, "objectClass", current->objectclass); + if (ret != LDB_SUCCESS) { + ldb_set_errstring(module->ldb, "objectclass: could not re-add sorted objectclass to modify msg"); + talloc_free(mem_ctx); + return ret; + } + } + + talloc_free(mem_ctx); + + ret = ldb_msg_sanity_check(module->ldb, msg); + if (ret != LDB_SUCCESS) { + talloc_free(mem_ctx); + return ret; + } + + /* go on with the call chain */ + ret = ldb_next_request(module, down_req); + + /* do not free down_req as the call results may be linked to it, + * it will be freed when the upper level request get freed */ + if (ret == LDB_SUCCESS) { + req->handle = down_req->handle; + } + return ret; + } + } + + { + struct ldb_handle *h; + struct oc_context *ac; + + h = oc_init_handle(req, module); + if (!h) { + return LDB_ERR_OPERATIONS_ERROR; + } + ac = talloc_get_type(h->private_data, struct oc_context); + + /* return or own handle to deal with this call */ + req->handle = h; + + /* prepare the first operation */ + ac->down_req = talloc(ac, struct ldb_request); + if (ac->down_req == NULL) { + ldb_set_errstring(module->ldb, "Out of memory!"); + return LDB_ERR_OPERATIONS_ERROR; + } + + *(ac->down_req) = *req; /* copy the request */ + + ac->down_req->context = NULL; + ac->down_req->callback = NULL; + ldb_set_timeout_from_prev_req(module->ldb, req, ac->down_req); + + ac->step = OC_DO_REQ; + + return ldb_next_request(module, ac->down_req); + } +} + +static int get_self_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +{ + struct oc_context *ac; + + if (!context || !ares) { + ldb_set_errstring(ldb, "NULL Context or Result in callback"); + return LDB_ERR_OPERATIONS_ERROR; + } + + ac = talloc_get_type(context, struct oc_context); + + /* we are interested only in the single reply (base search) we receive here */ + if (ares->type == LDB_REPLY_ENTRY) { + if (ac->search_res != NULL) { + ldb_set_errstring(ldb, "Too many results"); + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; + } + + ac->search_res = talloc_move(ac, &ares); + } else { + talloc_free(ares); + } + + return LDB_SUCCESS; +} + +static int objectclass_search_self(struct ldb_handle *h) { + + struct oc_context *ac; + static const char * const attrs[] = { "objectClass", NULL }; + + ac = talloc_get_type(h->private_data, struct oc_context); + + /* prepare the search operation */ + ac->search_req = talloc_zero(ac, struct ldb_request); + if (ac->search_req == NULL) { + ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR, "Out of Memory!\n"); + return LDB_ERR_OPERATIONS_ERROR; + } + + ac->search_req->operation = LDB_SEARCH; + ac->search_req->op.search.base = ac->orig_req->op.mod.message->dn; + ac->search_req->op.search.scope = LDB_SCOPE_BASE; + ac->search_req->op.search.tree = ldb_parse_tree(ac->search_req, NULL); + if (ac->search_req->op.search.tree == NULL) { + ldb_set_errstring(ac->module->ldb, "objectclass: Internal error producing null search"); + return LDB_ERR_OPERATIONS_ERROR; + } + ac->search_req->op.search.attrs = attrs; + ac->search_req->controls = NULL; + ac->search_req->context = ac; + ac->search_req->callback = get_self_callback; + ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req); + + ac->step = OC_SEARCH_SELF; + + return ldb_next_request(ac->module, ac->search_req); +} + +static int objectclass_do_mod(struct ldb_handle *h) { + + struct oc_context *ac; + struct ldb_message_element *objectclass_element; + struct ldb_message *msg; + TALLOC_CTX *mem_ctx; + struct class_list *sorted, *current; + int ret; + + ac = talloc_get_type(h->private_data, struct oc_context); + + mem_ctx = talloc_new(ac); + if (mem_ctx == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ac->mod_req = talloc(ac, struct ldb_request); + if (ac->mod_req == NULL) { + talloc_free(mem_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + ac->mod_req->operation = LDB_MODIFY; + ac->mod_req->controls = NULL; + ac->mod_req->context = ac; + ac->mod_req->callback = NULL; + ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->mod_req); + + /* use a new message structure */ + ac->mod_req->op.mod.message = msg = ldb_msg_new(ac->mod_req); + if (msg == NULL) { + ldb_set_errstring(ac->module->ldb, "objectclass: could not create new modify msg"); + talloc_free(mem_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* This is now the objectClass list from the database */ + objectclass_element = ldb_msg_find_element(ac->search_res->message, + "objectClass"); + if (!objectclass_element) { + /* Where did it go? Move along now, nothing to see here */ + talloc_free(mem_ctx); + return LDB_SUCCESS; + } + + /* modify dn */ + msg->dn = ac->orig_req->op.mod.message->dn; + + ret = objectclass_sort(ac->module, mem_ctx, objectclass_element, &sorted); + if (ret != LDB_SUCCESS) { + return ret; + } + + /* We must completely replace the existing objectClass entry. + * We could do a constrained add/del, but we are meant to be + * in a transaction... */ + + ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL); + if (ret != LDB_SUCCESS) { + ldb_set_errstring(ac->module->ldb, "objectclass: could not clear objectclass in modify msg"); + talloc_free(mem_ctx); + return ret; + } + + /* Move from the linked list back into an ldb msg */ + for (current = sorted; current; current = current->next) { + ret = ldb_msg_add_string(msg, "objectClass", current->objectclass); + if (ret != LDB_SUCCESS) { + ldb_set_errstring(ac->module->ldb, "objectclass: could not re-add sorted objectclass to modify msg"); + talloc_free(mem_ctx); + return ret; + } + } + + ret = ldb_msg_sanity_check(ac->module->ldb, msg); + if (ret != LDB_SUCCESS) { + talloc_free(mem_ctx); + return ret; + } + + + h->state = LDB_ASYNC_INIT; + h->status = LDB_SUCCESS; + + ac->step = OC_DO_MOD; + + talloc_free(mem_ctx); + /* perform the search */ + return ldb_next_request(ac->module, ac->mod_req); +} + +static int oc_wait(struct ldb_handle *handle) { + struct oc_context *ac; + int ret; + + if (!handle || !handle->private_data) { + return LDB_ERR_OPERATIONS_ERROR; + } + + if (handle->state == LDB_ASYNC_DONE) { + return handle->status; + } + + handle->state = LDB_ASYNC_PENDING; + handle->status = LDB_SUCCESS; + + ac = talloc_get_type(handle->private_data, struct oc_context); + + switch (ac->step) { + case OC_DO_REQ: + ret = ldb_wait(ac->down_req->handle, LDB_WAIT_NONE); + + if (ret != LDB_SUCCESS) { + handle->status = ret; + goto done; + } + if (ac->down_req->handle->status != LDB_SUCCESS) { + handle->status = ac->down_req->handle->status; + goto done; + } + + if (ac->down_req->handle->state != LDB_ASYNC_DONE) { + return LDB_SUCCESS; + } + + /* mods done, go on */ + return objectclass_search_self(handle); + + case OC_SEARCH_SELF: + ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE); + + if (ret != LDB_SUCCESS) { + handle->status = ret; + goto done; + } + if (ac->search_req->handle->status != LDB_SUCCESS) { + handle->status = ac->search_req->handle->status; + goto done; + } + + if (ac->search_req->handle->state != LDB_ASYNC_DONE) { + return LDB_SUCCESS; + } + + /* self search done, go on */ + return objectclass_do_mod(handle); + + case OC_DO_MOD: + ret = ldb_wait(ac->mod_req->handle, LDB_WAIT_NONE); + + if (ret != LDB_SUCCESS) { + handle->status = ret; + goto done; + } + if (ac->mod_req->handle->status != LDB_SUCCESS) { + handle->status = ac->mod_req->handle->status; + goto done; + } + + if (ac->mod_req->handle->state != LDB_ASYNC_DONE) { + return LDB_SUCCESS; + } + + break; + + default: + ret = LDB_ERR_OPERATIONS_ERROR; + goto done; + } + + ret = LDB_SUCCESS; + +done: + handle->state = LDB_ASYNC_DONE; + return ret; +} + +static int oc_wait_all(struct ldb_handle *handle) { + + int ret; + + while (handle->state != LDB_ASYNC_DONE) { + ret = oc_wait(handle); + if (ret != LDB_SUCCESS) { + return ret; + } + } + + return handle->status; +} + +static int objectclass_wait(struct ldb_handle *handle, enum ldb_wait_type type) +{ + if (type == LDB_WAIT_ALL) { + return oc_wait_all(handle); + } else { + return oc_wait(handle); + } +} + +static const struct ldb_module_ops objectclass_ops = { + .name = "objectclass", + .add = objectclass_add, + .modify = objectclass_modify, + .wait = objectclass_wait +}; + +int ldb_objectclass_init(void) +{ + return ldb_register_module(&objectclass_ops); +} + -- cgit From ae7819d715e80cfbd17c4bec1c93685198febe6a Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 7 Aug 2007 05:58:47 +0000 Subject: r24262: Set the objectCategory by default in the objectclass module, rather than using templates. Modify the samba3sam test to be less fussy, and not use the objectclass module (which requires proper schema stuff now). Andrew Bartlett (This used to be commit 53c248c2645e86fbc8720860aed92a479483b528) --- source4/dsdb/samdb/ldb_modules/objectclass.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'source4/dsdb/samdb/ldb_modules/objectclass.c') diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index ad11442035..259b963ce0 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -161,7 +161,7 @@ static int objectclass_sort(struct ldb_module *module, /* Save the next pointer, as the DLIST_ macros will change poss_subclass->next */ next = poss_subclass->next; - if (ldb_attr_cmp(class->subClassOf, current->objectclass) == 0) { + if (class && ldb_attr_cmp(class->subClassOf, current->objectclass) == 0) { DLIST_REMOVE(unsorted, poss_subclass); DLIST_ADD(subclass, poss_subclass); @@ -199,6 +199,7 @@ static int objectclass_sort(struct ldb_module *module, static int objectclass_add(struct ldb_module *module, struct ldb_request *req) { struct ldb_message_element *objectclass_element; + const struct dsdb_schema *schema = dsdb_get_schema(module->ldb); struct class_list *sorted, *current; struct ldb_request *down_req; struct ldb_message *msg; @@ -265,6 +266,14 @@ static int objectclass_add(struct ldb_module *module, struct ldb_request *req) talloc_free(mem_ctx); return ret; } + /* Last one */ + if (schema && !current->next && !ldb_msg_find_element(msg, "objectCategory")) { + const struct dsdb_class *objectclass + = dsdb_class_by_lDAPDisplayName(schema, current->objectclass); + if (objectclass) { + ldb_msg_add_string(msg, "objectCategory", objectclass->defaultObjectCategory); + } + } } talloc_free(mem_ctx); -- cgit From c4e5fcc349ae8648e50c5fa893fd3fd47336fed2 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 7 Aug 2007 09:01:08 +0000 Subject: r24263: Fix bug 4846 (unable to copy users in MMC Active Directory Users and Computers). We now generate a security descriptor for each object, when it is created. This seems to keep MMC happy. The next step is to honour it. Andrew Bartlett (This used to be commit 72f4ae82463c5c1f9f6b7f18f125c4c8fb56ae4f) --- source4/dsdb/samdb/ldb_modules/objectclass.c | 50 ++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) (limited to 'source4/dsdb/samdb/ldb_modules/objectclass.c') diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index 259b963ce0..a9ef93cab1 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -35,6 +35,11 @@ #include "ldb/include/ldb_private.h" #include "dsdb/samdb/samdb.h" #include "lib/util/dlinklist.h" +#include "librpc/ndr/libndr.h" +#include "librpc/gen_ndr/ndr_security.h" +#include "libcli/security/security.h" +#include "auth/auth.h" + struct oc_context { enum oc_step {OC_DO_REQ, OC_SEARCH_SELF, OC_DO_MOD} step; @@ -196,6 +201,39 @@ static int objectclass_sort(struct ldb_module *module, return LDB_SUCCESS; } +DATA_BLOB *get_sd(struct ldb_module *module, TALLOC_CTX *mem_ctx, + const struct dsdb_class *objectclass) +{ + NTSTATUS status; + DATA_BLOB *linear_sd; + struct auth_session_info *session_info + = ldb_get_opaque(module->ldb, "sessionInfo"); + struct security_descriptor *sd = sddl_decode(mem_ctx, + objectclass->defaultSecurityDescriptor, + samdb_domain_sid(module->ldb)); + if (!session_info || !session_info->security_token) { + return NULL; + } + + sd->owner_sid = session_info->security_token->user_sid; + sd->group_sid = session_info->security_token->group_sid; + + linear_sd = talloc(mem_ctx, DATA_BLOB); + if (!linear_sd) { + return NULL; + } + + status = ndr_push_struct_blob(linear_sd, mem_ctx, sd, + (ndr_push_flags_fn_t)ndr_push_security_descriptor); + + if (!NT_STATUS_IS_OK(status)) { + return NULL; + } + + return linear_sd; + +} + static int objectclass_add(struct ldb_module *module, struct ldb_request *req) { struct ldb_message_element *objectclass_element; @@ -266,12 +304,18 @@ static int objectclass_add(struct ldb_module *module, struct ldb_request *req) talloc_free(mem_ctx); return ret; } - /* Last one */ - if (schema && !current->next && !ldb_msg_find_element(msg, "objectCategory")) { + /* Last one is the critical one */ + if (schema && !current->next) { const struct dsdb_class *objectclass = dsdb_class_by_lDAPDisplayName(schema, current->objectclass); if (objectclass) { - ldb_msg_add_string(msg, "objectCategory", objectclass->defaultObjectCategory); + if (!ldb_msg_find_element(msg, "objectCategory")) { + ldb_msg_add_string(msg, "objectCategory", objectclass->defaultObjectCategory); + } + if (!ldb_msg_find_element(msg, "ntSecurityDescriptor")) { + DATA_BLOB *sd = get_sd(module, mem_ctx, objectclass); + ldb_msg_add_steal_value(msg, "ntSecurityDescriptor", sd); + } } } } -- cgit From 9fd3416452ac82d27dac7b8c16f6ad89f5551f6b Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 8 Aug 2007 06:37:37 +0000 Subject: r24277: Tidyup as requested by metze. Andrew Bartlett (This used to be commit 43d62181f204fb32e487b7689729c1a91b8d23ad) --- source4/dsdb/samdb/ldb_modules/objectclass.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'source4/dsdb/samdb/ldb_modules/objectclass.c') diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index a9ef93cab1..0d55ef07db 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -201,16 +201,18 @@ static int objectclass_sort(struct ldb_module *module, return LDB_SUCCESS; } -DATA_BLOB *get_sd(struct ldb_module *module, TALLOC_CTX *mem_ctx, - const struct dsdb_class *objectclass) +static DATA_BLOB *get_sd(struct ldb_module *module, TALLOC_CTX *mem_ctx, + const struct dsdb_class *objectclass) { NTSTATUS status; DATA_BLOB *linear_sd; struct auth_session_info *session_info = ldb_get_opaque(module->ldb, "sessionInfo"); - struct security_descriptor *sd = sddl_decode(mem_ctx, - objectclass->defaultSecurityDescriptor, - samdb_domain_sid(module->ldb)); + struct security_descriptor *sd + = sddl_decode(mem_ctx, + objectclass->defaultSecurityDescriptor, + samdb_domain_sid(module->ldb)); + if (!session_info || !session_info->security_token) { return NULL; } @@ -300,17 +302,21 @@ static int objectclass_add(struct ldb_module *module, struct ldb_request *req) for (current = sorted; current; current = current->next) { ret = ldb_msg_add_string(msg, "objectClass", current->objectclass); if (ret != LDB_SUCCESS) { - ldb_set_errstring(module->ldb, "objectclass: could not re-add sorted objectclass to modify msg"); + ldb_set_errstring(module->ldb, + "objectclass: could not re-add sorted " + "objectclass to modify msg"); talloc_free(mem_ctx); return ret; } /* Last one is the critical one */ if (schema && !current->next) { const struct dsdb_class *objectclass - = dsdb_class_by_lDAPDisplayName(schema, current->objectclass); + = dsdb_class_by_lDAPDisplayName(schema, + current->objectclass); if (objectclass) { if (!ldb_msg_find_element(msg, "objectCategory")) { - ldb_msg_add_string(msg, "objectCategory", objectclass->defaultObjectCategory); + ldb_msg_add_string(msg, "objectCategory", + objectclass->defaultObjectCategory); } if (!ldb_msg_find_element(msg, "ntSecurityDescriptor")) { DATA_BLOB *sd = get_sd(module, mem_ctx, objectclass); -- cgit From 0eb3ee32049eb5b76308e8ef4dc6af3db544afbb Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 15 Aug 2007 13:14:38 +0000 Subject: r24459: Fix up ldap.js and test_ldb.sh to test the domain_scope control, and to test the behaviour of objectCategory=user searches. It turns out (thanks to a hint on http://blog.joeware.net/2005/12/08/147/) that objectCategory=user maps into objectCategory=CN=Person,... (by the defaultObjectCategory of that objectclass). Simplify the entryUUID module by using the fact that we now set the DN as the canoncical form of objectCategory. Andrew Bartlett (This used to be commit b474be9507df51982a604289215bb1868124fc24) --- source4/dsdb/samdb/ldb_modules/objectclass.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source4/dsdb/samdb/ldb_modules/objectclass.c') diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index 0d55ef07db..f7b2da9b83 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -318,9 +318,9 @@ static int objectclass_add(struct ldb_module *module, struct ldb_request *req) ldb_msg_add_string(msg, "objectCategory", objectclass->defaultObjectCategory); } - if (!ldb_msg_find_element(msg, "ntSecurityDescriptor")) { + if (!ldb_msg_find_element(msg, "nTSecurityDescriptor")) { DATA_BLOB *sd = get_sd(module, mem_ctx, objectclass); - ldb_msg_add_steal_value(msg, "ntSecurityDescriptor", sd); + ldb_msg_add_steal_value(msg, "nTSecurityDescriptor", sd); } } } -- cgit From 714c5c92ef8e80b3510e222ce621401e55d05d7e Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 28 Aug 2007 05:43:26 +0000 Subject: r24731: Remove unused code - if we hit these error conditions, then we are dead anyway, and a segfault would leave us with more infomation. Andrew Bartlett (This used to be commit 62320616ff8795ff18c8f49029d81f12558c10ed) --- source4/dsdb/samdb/ldb_modules/objectclass.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'source4/dsdb/samdb/ldb_modules/objectclass.c') diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index f7b2da9b83..04cf8efdb2 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -480,11 +480,6 @@ static int get_self_callback(struct ldb_context *ldb, void *context, struct ldb_ { struct oc_context *ac; - if (!context || !ares) { - ldb_set_errstring(ldb, "NULL Context or Result in callback"); - return LDB_ERR_OPERATIONS_ERROR; - } - ac = talloc_get_type(context, struct oc_context); /* we are interested only in the single reply (base search) we receive here */ -- cgit From 8294016a1b72770f5c322decda9b705ed90fd40d Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 3 Sep 2007 02:51:24 +0000 Subject: r24914: In response to bug #4892 by Matthias Wallnöfer , allow the objectclass module to reconstruct the objectclass hierarchy, rather than using templates. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The issue being fixed in particular is that 'top' was not being set on containers. This should ensure we do this right for all objects. Andrew Bartlett (This used to be commit d17a0058ba8492b8b3f81b6f10fc34b3e45bb8a6) --- source4/dsdb/samdb/ldb_modules/objectclass.c | 46 +++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 8 deletions(-) (limited to 'source4/dsdb/samdb/ldb_modules/objectclass.c') diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index 04cf8efdb2..f2ca92638d 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -92,6 +92,7 @@ static struct ldb_handle *oc_init_handle(struct ldb_request *req, struct ldb_mod } static int objectclass_sort(struct ldb_module *module, + struct ldb_message *msg, /* so that when we create new elements, we put it on the right parent */ TALLOC_CTX *mem_ctx, struct ldb_message_element *objectclass_element, struct class_list **sorted_out) @@ -100,7 +101,7 @@ static int objectclass_sort(struct ldb_module *module, int layer; const struct dsdb_schema *schema = dsdb_get_schema(module->ldb); struct class_list *sorted = NULL, *parent_class = NULL, - *subclass = NULL, *unsorted = NULL, *current, *poss_subclass; + *subclass = NULL, *unsorted = NULL, *current, *poss_subclass, *poss_parent, *new_parent; /* DESIGN: * * We work on 4 different 'bins' (implemented here as linked lists): @@ -149,6 +150,34 @@ static int objectclass_sort(struct ldb_module *module, } } + if (parent_class == NULL) { + current = talloc(mem_ctx, struct class_list); + current->objectclass = talloc_strdup(msg, "top"); + DLIST_ADD_END(parent_class, current, struct class_list *); + } + + /* For each object: find parent chain */ + for (current = unsorted; schema && current; current = current->next) { + const struct dsdb_class *class = dsdb_class_by_lDAPDisplayName(schema, current->objectclass); + if (!class) { + ldb_asprintf_errstring(module->ldb, "objectclass %s is not a valid objectClass in schema", current->objectclass); + return LDB_ERR_OBJECT_CLASS_VIOLATION; + } + for (poss_parent = unsorted; poss_parent; poss_parent = poss_parent->next) { + if (ldb_attr_cmp(poss_parent->objectclass, class->subClassOf) == 0) { + break; + } + } + /* If we didn't get to the end of the list, we need to add this parent */ + if (poss_parent || (ldb_attr_cmp("top", class->subClassOf) == 0)) { + continue; + } + + new_parent = talloc(mem_ctx, struct class_list); + new_parent->objectclass = talloc_strdup(msg, class->subClassOf); + DLIST_ADD_END(unsorted, new_parent, struct class_list *); + } + /* DEBUGGING aid: how many layers are we down now? */ layer = 0; do { @@ -265,11 +294,6 @@ static int objectclass_add(struct ldb_module *module, struct ldb_request *req) return LDB_ERR_OPERATIONS_ERROR; } - ret = objectclass_sort(module, mem_ctx, objectclass_element, &sorted); - if (ret != LDB_SUCCESS) { - return ret; - } - /* prepare the first operation */ down_req = talloc(req, struct ldb_request); if (down_req == NULL) { @@ -287,6 +311,12 @@ static int objectclass_add(struct ldb_module *module, struct ldb_request *req) return LDB_ERR_OPERATIONS_ERROR; } + ret = objectclass_sort(module, msg, mem_ctx, objectclass_element, &sorted); + if (ret != LDB_SUCCESS) { + talloc_free(mem_ctx); + return ret; + } + ldb_msg_remove_attr(msg, "objectClass"); ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL); @@ -398,7 +428,7 @@ static int objectclass_modify(struct ldb_module *module, struct ldb_request *req return LDB_ERR_OPERATIONS_ERROR; } - ret = objectclass_sort(module, mem_ctx, objectclass_element, &sorted); + ret = objectclass_sort(module, msg, mem_ctx, objectclass_element, &sorted); if (ret != LDB_SUCCESS) { return ret; } @@ -579,7 +609,7 @@ static int objectclass_do_mod(struct ldb_handle *h) { /* modify dn */ msg->dn = ac->orig_req->op.mod.message->dn; - ret = objectclass_sort(ac->module, mem_ctx, objectclass_element, &sorted); + ret = objectclass_sort(ac->module, msg, mem_ctx, objectclass_element, &sorted); if (ret != LDB_SUCCESS) { return ret; } -- cgit From c4ebf9587f66ce171f0c4778921c358eb5b94da3 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 19 Oct 2007 05:40:00 +0200 Subject: r25702: Clarify comments and make this module more strict on objectclasses. This is becoming the schema module... Andrew Bartlett (This used to be commit ecea817a3e793f8ac0187dd83a29e62a7d645868) --- source4/dsdb/samdb/ldb_modules/objectclass.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'source4/dsdb/samdb/ldb_modules/objectclass.c') diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index f2ca92638d..97eed3fc5b 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -217,16 +217,14 @@ static int objectclass_sort(struct ldb_module *module, * the bottom here */ } while (parent_class); - /* This shouldn't happen, and would break MMC, but we can't - * afford to loose objectClasses. Perhaps there was no 'top', - * or some other schema error? - * - * Detecting schema errors is the job of the schema module, so - * at this layer we just try not to loose data - */ - DLIST_CONCATENATE(sorted, unsorted, struct class_list *); - - *sorted_out = sorted; + if (unsorted) { + /* This shouldn't happen, and would break MMC, but we can't + * afford to loose objectClasses. Perhaps there was no 'top', + * or some other schema error? + */ + ldb_asprintf_errstring(module->ldb, "objectclass %s is not a valid objectClass in objectClass chain", unsorted->objectclass); + return LDB_ERR_OBJECT_CLASS_VIOLATION; + } return LDB_SUCCESS; } @@ -397,6 +395,7 @@ static int objectclass_modify(struct ldb_module *module, struct ldb_request *req case LDB_FLAG_MOD_DELETE: /* Delete everything? Probably totally illigal, but hey! */ if (objectclass_element->num_values == 0) { + return ldb_next_request(module, req); } break; @@ -474,6 +473,10 @@ static int objectclass_modify(struct ldb_module *module, struct ldb_request *req } } + /* This isn't the default branch of the switch, but a 'in any + * other case'. When a delete isn't for all objectClasses for + * example + */ { struct ldb_handle *h; struct oc_context *ac; -- cgit From 35dc4d9999b6d3284adba96bc408ba55faf3475a Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 19 Oct 2007 06:47:54 +0200 Subject: r25704: Handle the chicken-and-egg problem of setting up the LDB before we get a schema. perhaps i need to look into metze's 'load a schema from ldif' code. Andrew Bartlett (This used to be commit f350ef5f19ec755c93c6c09210cdf276d1b66877) --- source4/dsdb/samdb/ldb_modules/objectclass.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'source4/dsdb/samdb/ldb_modules/objectclass.c') diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index 97eed3fc5b..93c78fd163 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -217,15 +217,22 @@ static int objectclass_sort(struct ldb_module *module, * the bottom here */ } while (parent_class); - if (unsorted) { - /* This shouldn't happen, and would break MMC, but we can't - * afford to loose objectClasses. Perhaps there was no 'top', - * or some other schema error? - */ - ldb_asprintf_errstring(module->ldb, "objectclass %s is not a valid objectClass in objectClass chain", unsorted->objectclass); - return LDB_ERR_OBJECT_CLASS_VIOLATION; + if (!unsorted) { + return LDB_SUCCESS; } - return LDB_SUCCESS; + + if (!schema) { + /* If we don't have schema yet, then just merge the lists again */ + DLIST_CONCATENATE(sorted, unsorted, struct class_list *); + return LDB_SUCCESS; + } + + /* This shouldn't happen, and would break MMC, perhaps there + * was no 'top', a conflict in the objectClasses or some other + * schema error? + */ + ldb_asprintf_errstring(module->ldb, "objectclass %s is not a valid objectClass in objectClass chain", unsorted->objectclass); + return LDB_ERR_OBJECT_CLASS_VIOLATION; } static DATA_BLOB *get_sd(struct ldb_module *module, TALLOC_CTX *mem_ctx, -- cgit From c2e5cf6e31b099e1477113b9e11f760e2bdb5396 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 19 Oct 2007 06:57:19 +0200 Subject: r25705: Ensure we return the out value to the caller. Andrew Bartlett (This used to be commit 3434262ad74c366ac58319c70880ca50898fa78c) --- source4/dsdb/samdb/ldb_modules/objectclass.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'source4/dsdb/samdb/ldb_modules/objectclass.c') diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index 93c78fd163..452896d5a3 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -218,12 +218,14 @@ static int objectclass_sort(struct ldb_module *module, } while (parent_class); if (!unsorted) { + *sorted_out = sorted; return LDB_SUCCESS; } if (!schema) { /* If we don't have schema yet, then just merge the lists again */ DLIST_CONCATENATE(sorted, unsorted, struct class_list *); + *sorted_out = sorted; return LDB_SUCCESS; } -- cgit From 16d039504763139f1221c3ff4643d1a5cb2bdc87 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 29 Oct 2007 21:25:26 +0100 Subject: r25750: Update the objectclass module to improve consistency in Samba4. The aim here is to ensure that if we have CN=Users,DC=samba,DC=example,DC=com that we cannot have a DN of the form cn=admin ,cn=useRS,DC=samba,DC=example,DC=com This module pulls apart the DN, fixes up the relative DN part, and searches for the parent to copy the base from. I've used the objectclass module, as I intend to also validate the placement of child objects, by reading the allowedChildClasses virtual attribute. In the future, I'll also force the attribute names to be consistant (using the case from the schema). Andrew Bartlett (This used to be commit c0a0c69ac5a81cfcb7c7d5ba38db59f8686c30ab) --- source4/dsdb/samdb/ldb_modules/objectclass.c | 429 ++++++++++++++++++++++----- 1 file changed, 351 insertions(+), 78 deletions(-) (limited to 'source4/dsdb/samdb/ldb_modules/objectclass.c') diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index 452896d5a3..14dbe3b313 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -42,7 +42,9 @@ struct oc_context { - enum oc_step {OC_DO_REQ, OC_SEARCH_SELF, OC_DO_MOD} step; + enum oc_step {OC_DO_REQ, OC_SEARCH_SELF, OC_DO_MOD, + OC_SEARCH_ADD_PARENT, OC_DO_ADD, + OC_SEARCH_RENAME_PARENT, OC_DO_RENAME} step; struct ldb_module *module; struct ldb_request *orig_req; @@ -52,7 +54,9 @@ struct oc_context { struct ldb_request *search_req; struct ldb_reply *search_res; + struct ldb_request *add_req; struct ldb_request *mod_req; + struct ldb_request *rename_req; }; struct class_list { @@ -272,53 +276,186 @@ static DATA_BLOB *get_sd(struct ldb_module *module, TALLOC_CTX *mem_ctx, } +static int get_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +{ + struct oc_context *ac; + + ac = talloc_get_type(context, struct oc_context); + + /* we are interested only in the single reply (base search) we receive here */ + if (ares->type == LDB_REPLY_ENTRY) { + if (ac->search_res != NULL) { + ldb_set_errstring(ldb, "Too many results"); + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; + } + + ac->search_res = talloc_move(ac, &ares); + } else { + talloc_free(ares); + } + + return LDB_SUCCESS; +} + +/* Fix up the DN to be in the standard form, taking particular care to match the parent DN + + This should mean that if the parent is: + CN=Users,DC=samba,DC=example,DC=com + and a proposed child is + cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM + + The resulting DN should be: + + CN=Admins,CN=Users,DC=samba,DC=example,DC=com + + */ +static int fix_dn(TALLOC_CTX *mem_ctx, + struct ldb_dn *newdn, struct ldb_dn *parent_dn, + struct ldb_dn **fixed_dn) +{ + char *upper_rdn_attr; + /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */ + *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn); + + /* We need the attribute name in upper case */ + upper_rdn_attr = strupper_talloc(*fixed_dn, + ldb_dn_get_rdn_name(newdn)); + if (!upper_rdn_attr) { + return LDB_ERR_OPERATIONS_ERROR; + } + + /* Create a new child */ + if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) { + return LDB_ERR_OPERATIONS_ERROR; + } + + /* And replace it with CN=foo (we need the attribute in upper case */ + return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, + *ldb_dn_get_rdn_val(newdn)); +} + static int objectclass_add(struct ldb_module *module, struct ldb_request *req) { - struct ldb_message_element *objectclass_element; - const struct dsdb_schema *schema = dsdb_get_schema(module->ldb); - struct class_list *sorted, *current; - struct ldb_request *down_req; - struct ldb_message *msg; - int ret; - TALLOC_CTX *mem_ctx; + static const char * const attrs[] = { NULL }; + + struct ldb_handle *h; + struct oc_context *ac; + struct ldb_dn *parent_dn; + int ret; + ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_add\n"); - if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */ + /* do not manipulate our control entries */ + if (ldb_dn_is_special(req->op.add.message->dn)) { return ldb_next_request(module, req); } - - objectclass_element = ldb_msg_find_element(req->op.add.message, "objectClass"); - /* If no part of this add has an objectClass, then we don't - * need to make any changes. cn=rootdse doesn't have an objectClass */ - if (!objectclass_element) { + /* Need to object to this, but cn=rootdse doesn't hae an objectClass... */ + if (ldb_msg_find_element(req->op.add.message, + "objectClass") == NULL) { return ldb_next_request(module, req); } - mem_ctx = talloc_new(req); + h = oc_init_handle(req, module); + if (!h) { + return LDB_ERR_OPERATIONS_ERROR; + } + ac = talloc_get_type(h->private_data, struct oc_context); + + /* return or own handle to deal with this call */ + req->handle = h; + + parent_dn = ldb_dn_get_parent(ac->search_req, ac->orig_req->op.mod.message->dn); + if (parent_dn == NULL) { + ldb_oom(module->ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + ret = ldb_build_search_req(&ac->search_req, module->ldb, + ac, parent_dn, LDB_SCOPE_BASE, + "(objectClass=*)", + attrs, NULL, + ac, get_search_callback); + if (ret != LDB_SUCCESS) { + return ret; + } + + ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req); + + ac->step = OC_SEARCH_ADD_PARENT; + + return ldb_next_request(ac->module, ac->search_req); +} + +static int objectclass_do_add(struct ldb_handle *h) +{ + const struct dsdb_schema *schema; + struct oc_context *ac; + struct ldb_message_element *objectclass_element; + struct ldb_message *msg; + TALLOC_CTX *mem_ctx; + struct class_list *sorted, *current; + int ret; + + ac = talloc_get_type(h->private_data, struct oc_context); + schema = dsdb_get_schema(ac->module->ldb); + + mem_ctx = talloc_new(ac); if (mem_ctx == NULL) { return LDB_ERR_OPERATIONS_ERROR; } - /* prepare the first operation */ - down_req = talloc(req, struct ldb_request); - if (down_req == NULL) { - ldb_set_errstring(module->ldb, "Out of memory!"); + ac->add_req = talloc(ac, struct ldb_request); + if (ac->add_req == NULL) { talloc_free(mem_ctx); return LDB_ERR_OPERATIONS_ERROR; } - *down_req = *req; /* copy the request */ + *ac->add_req = *ac->orig_req; - down_req->op.add.message = msg = ldb_msg_copy_shallow(down_req, req->op.add.message); + ac->add_req->op.add.message = msg = ldb_msg_copy_shallow(ac->add_req, ac->orig_req->op.add.message); + + ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->add_req); + + /* Check we have a valid parent */ + if (ac->search_res == NULL) { + if (ldb_dn_get_comp_num(ac->orig_req->op.add.message->dn) <= 1) { + /* Allow cn=rootdse and cn=templates for now... */ + } else if (ldb_dn_compare(ldb_get_root_basedn(ac->module->ldb), ac->orig_req->op.add.message->dn) == 0) { + /* Allow the tree to be started */ + } else { + ldb_asprintf_errstring(ac->module->ldb, "objectclass: Cannot add %s, parent does not exist!", + ldb_dn_get_linearized(ac->orig_req->op.add.message->dn)); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + } else { + + /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */ + ret = fix_dn(msg, + ac->orig_req->op.add.message->dn, + ac->search_res->message->dn, + &msg->dn); + + if (ret != LDB_SUCCESS) { + return ret; + } + + /* TODO: Check this is a valid child to this parent, + * by reading the allowedChildClasses and + * allowedChildClasssesEffective attributes */ + + } + + /* This is now the objectClass list from the database */ + objectclass_element = ldb_msg_find_element(msg, "objectClass"); - if (down_req->op.add.message == NULL) { + if (!objectclass_element) { + /* Where did it go? bail now... */ talloc_free(mem_ctx); return LDB_ERR_OPERATIONS_ERROR; } - - ret = objectclass_sort(module, msg, mem_ctx, objectclass_element, &sorted); + ret = objectclass_sort(ac->module, msg, mem_ctx, objectclass_element, &sorted); if (ret != LDB_SUCCESS) { talloc_free(mem_ctx); return ret; @@ -339,7 +476,7 @@ static int objectclass_add(struct ldb_module *module, struct ldb_request *req) for (current = sorted; current; current = current->next) { ret = ldb_msg_add_string(msg, "objectClass", current->objectclass); if (ret != LDB_SUCCESS) { - ldb_set_errstring(module->ldb, + ldb_set_errstring(ac->module->ldb, "objectclass: could not re-add sorted " "objectclass to modify msg"); talloc_free(mem_ctx); @@ -356,7 +493,7 @@ static int objectclass_add(struct ldb_module *module, struct ldb_request *req) objectclass->defaultObjectCategory); } if (!ldb_msg_find_element(msg, "nTSecurityDescriptor")) { - DATA_BLOB *sd = get_sd(module, mem_ctx, objectclass); + DATA_BLOB *sd = get_sd(ac->module, mem_ctx, objectclass); ldb_msg_add_steal_value(msg, "nTSecurityDescriptor", sd); } } @@ -364,21 +501,19 @@ static int objectclass_add(struct ldb_module *module, struct ldb_request *req) } talloc_free(mem_ctx); - ret = ldb_msg_sanity_check(module->ldb, msg); + ret = ldb_msg_sanity_check(ac->module->ldb, msg); if (ret != LDB_SUCCESS) { return ret; } - /* go on with the call chain */ - ret = ldb_next_request(module, down_req); + h->state = LDB_ASYNC_INIT; + h->status = LDB_SUCCESS; - /* do not free down_req as the call results may be linked to it, - * it will be freed when the upper level request get freed */ - if (ret == LDB_SUCCESS) { - req->handle = down_req->handle; - } - return ret; + ac->step = OC_DO_ADD; + + /* perform the add */ + return ldb_next_request(ac->module, ac->add_req); } static int objectclass_modify(struct ldb_module *module, struct ldb_request *req) @@ -387,7 +522,8 @@ static int objectclass_modify(struct ldb_module *module, struct ldb_request *req struct ldb_message *msg; ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_modify\n"); - if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */ + /* do not manipulate our control entries */ + if (ldb_dn_is_special(req->op.mod.message->dn)) { return ldb_next_request(module, req); } @@ -518,54 +654,24 @@ static int objectclass_modify(struct ldb_module *module, struct ldb_request *req } } -static int get_self_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +static int objectclass_search_self(struct ldb_handle *h) { - struct oc_context *ac; - - ac = talloc_get_type(context, struct oc_context); - - /* we are interested only in the single reply (base search) we receive here */ - if (ares->type == LDB_REPLY_ENTRY) { - if (ac->search_res != NULL) { - ldb_set_errstring(ldb, "Too many results"); - talloc_free(ares); - return LDB_ERR_OPERATIONS_ERROR; - } - - ac->search_res = talloc_move(ac, &ares); - } else { - talloc_free(ares); - } - - return LDB_SUCCESS; -} - -static int objectclass_search_self(struct ldb_handle *h) { - + int ret; struct oc_context *ac; static const char * const attrs[] = { "objectClass", NULL }; ac = talloc_get_type(h->private_data, struct oc_context); - /* prepare the search operation */ - ac->search_req = talloc_zero(ac, struct ldb_request); - if (ac->search_req == NULL) { - ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR, "Out of Memory!\n"); - return LDB_ERR_OPERATIONS_ERROR; - } + ret = ldb_build_search_req(&ac->search_req, ac->module->ldb, + ac, ac->orig_req->op.mod.message->dn, LDB_SCOPE_BASE, + "(objectClass=*)", + attrs, NULL, + ac, get_search_callback); - ac->search_req->operation = LDB_SEARCH; - ac->search_req->op.search.base = ac->orig_req->op.mod.message->dn; - ac->search_req->op.search.scope = LDB_SCOPE_BASE; - ac->search_req->op.search.tree = ldb_parse_tree(ac->search_req, NULL); - if (ac->search_req->op.search.tree == NULL) { - ldb_set_errstring(ac->module->ldb, "objectclass: Internal error producing null search"); - return LDB_ERR_OPERATIONS_ERROR; + if (ret != LDB_SUCCESS) { + return ret; } - ac->search_req->op.search.attrs = attrs; - ac->search_req->controls = NULL; - ac->search_req->context = ac; - ac->search_req->callback = get_self_callback; + ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req); ac->step = OC_SEARCH_SELF; @@ -613,9 +719,9 @@ static int objectclass_do_mod(struct ldb_handle *h) { objectclass_element = ldb_msg_find_element(ac->search_res->message, "objectClass"); if (!objectclass_element) { - /* Where did it go? Move along now, nothing to see here */ + /* Where did it go? bail now... */ talloc_free(mem_ctx); - return LDB_SUCCESS; + return LDB_ERR_OPERATIONS_ERROR; } /* modify dn */ @@ -664,6 +770,98 @@ static int objectclass_do_mod(struct ldb_handle *h) { return ldb_next_request(ac->module, ac->mod_req); } +static int objectclass_rename(struct ldb_module *module, struct ldb_request *req) +{ + + static const char * const attrs[] = { NULL }; + + struct ldb_handle *h; + struct oc_context *ac; + struct ldb_dn *parent_dn; + int ret; + + ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_rename\n"); + + if (ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */ + return ldb_next_request(module, req); + } + + h = oc_init_handle(req, module); + if (!h) { + return LDB_ERR_OPERATIONS_ERROR; + } + ac = talloc_get_type(h->private_data, struct oc_context); + + /* return or own handle to deal with this call */ + req->handle = h; + + parent_dn = ldb_dn_get_parent(ac->search_req, ac->orig_req->op.rename.newdn); + if (parent_dn == NULL) { + ldb_oom(module->ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + ret = ldb_build_search_req(&ac->search_req, module->ldb, + ac, parent_dn, LDB_SCOPE_BASE, + "(objectClass=*)", + attrs, NULL, + ac, get_search_callback); + if (ret != LDB_SUCCESS) { + return ret; + } + + ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req); + + ac->step = OC_SEARCH_RENAME_PARENT; + + return ldb_next_request(ac->module, ac->search_req); +} + +static int objectclass_do_rename(struct ldb_handle *h) +{ + struct oc_context *ac; + int ret; + + ac = talloc_get_type(h->private_data, struct oc_context); + + ac->rename_req = talloc(ac, struct ldb_request); + if (ac->rename_req == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + *ac->rename_req = *ac->orig_req; + + ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->rename_req); + + /* Check we have a valid parent */ + if (ac->search_res == NULL) { + ldb_asprintf_errstring(ac->module->ldb, "objectclass: Cannot rename %s, parent does not exist!", + ldb_dn_get_linearized(ac->orig_req->op.rename.newdn)); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + + /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */ + ret = fix_dn(ac->rename_req, + ac->orig_req->op.rename.newdn, + ac->search_res->message->dn, + &ac->rename_req->op.rename.newdn); + + if (ret != LDB_SUCCESS) { + return ret; + } + + /* TODO: Check this is a valid child to this parent, + * by reading the allowedChildClasses and + * allowedChildClasssesEffective attributes */ + + h->state = LDB_ASYNC_INIT; + h->status = LDB_SUCCESS; + + ac->step = OC_DO_RENAME; + + /* perform the rename */ + return ldb_next_request(ac->module, ac->rename_req); +} + static int oc_wait(struct ldb_handle *handle) { struct oc_context *ac; int ret; @@ -738,6 +936,80 @@ static int oc_wait(struct ldb_handle *handle) { break; + case OC_SEARCH_ADD_PARENT: + ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE); + + if (ret != LDB_SUCCESS) { + handle->status = ret; + goto done; + } + if (ac->search_req->handle->status != LDB_SUCCESS) { + handle->status = ac->search_req->handle->status; + goto done; + } + + if (ac->search_req->handle->state != LDB_ASYNC_DONE) { + return LDB_SUCCESS; + } + + /* parent search done, go on */ + return objectclass_do_add(handle); + + case OC_DO_ADD: + ret = ldb_wait(ac->add_req->handle, LDB_WAIT_NONE); + + if (ret != LDB_SUCCESS) { + handle->status = ret; + goto done; + } + if (ac->add_req->handle->status != LDB_SUCCESS) { + handle->status = ac->add_req->handle->status; + goto done; + } + + if (ac->add_req->handle->state != LDB_ASYNC_DONE) { + return LDB_SUCCESS; + } + + break; + + case OC_SEARCH_RENAME_PARENT: + ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE); + + if (ret != LDB_SUCCESS) { + handle->status = ret; + goto done; + } + if (ac->search_req->handle->status != LDB_SUCCESS) { + handle->status = ac->search_req->handle->status; + goto done; + } + + if (ac->search_req->handle->state != LDB_ASYNC_DONE) { + return LDB_SUCCESS; + } + + /* parent search done, go on */ + return objectclass_do_rename(handle); + + case OC_DO_RENAME: + ret = ldb_wait(ac->rename_req->handle, LDB_WAIT_NONE); + + if (ret != LDB_SUCCESS) { + handle->status = ret; + goto done; + } + if (ac->rename_req->handle->status != LDB_SUCCESS) { + handle->status = ac->rename_req->handle->status; + goto done; + } + + if (ac->rename_req->handle->state != LDB_ASYNC_DONE) { + return LDB_SUCCESS; + } + + break; + default: ret = LDB_ERR_OPERATIONS_ERROR; goto done; @@ -777,6 +1049,7 @@ static const struct ldb_module_ops objectclass_ops = { .name = "objectclass", .add = objectclass_add, .modify = objectclass_modify, + .rename = objectclass_rename, .wait = objectclass_wait }; -- cgit From 46210e11f14373a213ec6fa32a20e9e183d641bf Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 30 Oct 2007 21:03:54 +0100 Subject: r25754: More work on normal forms for ldb input. This patch is to ensure that all attributes are in the same case as the schema specifies. In the process, I ensure that all attributes are indeed in the schema. This ensures we use the schema case, not the user supplied case for future responses, which assists any (incorrect, but possible) case sensitive processing on a client. I've also removed more of the subtle 'schema &&' that metze objected to in the for loops, moving to a much more explicit 'if (schema)'. Andrew Bartlett (This used to be commit bfc96fff063e7cc278755c043b9da0ed4b75a615) --- source4/dsdb/samdb/ldb_modules/objectclass.c | 216 ++++++++++++++++++--------- 1 file changed, 147 insertions(+), 69 deletions(-) (limited to 'source4/dsdb/samdb/ldb_modules/objectclass.c') diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index 14dbe3b313..6d40759e7b 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -23,7 +23,11 @@ * * Component: objectClass sorting module * - * Description: sort the objectClass attribute into the class hierarchy + * Description: + * - sort the objectClass attribute into the class + * hierarchy, + * - fix DNs and attributes into 'standard' case + * - Add objectCategory and ntSecurityDescriptor defaults * * Author: Andrew Bartlett */ @@ -61,7 +65,7 @@ struct oc_context { struct class_list { struct class_list *prev, *next; - const char *objectclass; + const struct dsdb_class *objectclass; }; static struct ldb_handle *oc_init_handle(struct ldb_request *req, struct ldb_module *module) @@ -95,7 +99,12 @@ static struct ldb_handle *oc_init_handle(struct ldb_request *req, struct ldb_mod return h; } +/* Sort objectClasses into correct order, and validate that all + * objectClasses specified actually exist in the schema + */ + static int objectclass_sort(struct ldb_module *module, + const struct dsdb_schema *schema, struct ldb_message *msg, /* so that when we create new elements, we put it on the right parent */ TALLOC_CTX *mem_ctx, struct ldb_message_element *objectclass_element, @@ -103,7 +112,6 @@ static int objectclass_sort(struct ldb_module *module, { int i; int layer; - const struct dsdb_schema *schema = dsdb_get_schema(module->ldb); struct class_list *sorted = NULL, *parent_class = NULL, *subclass = NULL, *unsorted = NULL, *current, *poss_subclass, *poss_parent, *new_parent; /* DESIGN: @@ -143,11 +151,15 @@ static int objectclass_sort(struct ldb_module *module, talloc_free(mem_ctx); return LDB_ERR_OPERATIONS_ERROR; } - current->objectclass = (const char *)objectclass_element->values[i].data; + current->objectclass = dsdb_class_by_lDAPDisplayName(schema, (const char *)objectclass_element->values[i].data); + if (!current->objectclass) { + ldb_asprintf_errstring(module->ldb, "objectclass %s is not a valid objectClass in schema", (const char *)objectclass_element->values[i].data); + return LDB_ERR_OBJECT_CLASS_VIOLATION; + } /* this is the root of the tree. We will start * looking for subclasses from here */ - if (ldb_attr_cmp("top", current->objectclass) == 0) { + if (ldb_attr_cmp("top", current->objectclass->lDAPDisplayName) == 0) { DLIST_ADD_END(parent_class, current, struct class_list *); } else { DLIST_ADD_END(unsorted, current, struct class_list *); @@ -156,29 +168,24 @@ static int objectclass_sort(struct ldb_module *module, if (parent_class == NULL) { current = talloc(mem_ctx, struct class_list); - current->objectclass = talloc_strdup(msg, "top"); + current->objectclass = dsdb_class_by_lDAPDisplayName(schema, "top"); DLIST_ADD_END(parent_class, current, struct class_list *); } /* For each object: find parent chain */ for (current = unsorted; schema && current; current = current->next) { - const struct dsdb_class *class = dsdb_class_by_lDAPDisplayName(schema, current->objectclass); - if (!class) { - ldb_asprintf_errstring(module->ldb, "objectclass %s is not a valid objectClass in schema", current->objectclass); - return LDB_ERR_OBJECT_CLASS_VIOLATION; - } for (poss_parent = unsorted; poss_parent; poss_parent = poss_parent->next) { - if (ldb_attr_cmp(poss_parent->objectclass, class->subClassOf) == 0) { + if (ldb_attr_cmp(poss_parent->objectclass->lDAPDisplayName, current->objectclass->subClassOf) == 0) { break; } } /* If we didn't get to the end of the list, we need to add this parent */ - if (poss_parent || (ldb_attr_cmp("top", class->subClassOf) == 0)) { + if (poss_parent || (ldb_attr_cmp("top", current->objectclass->subClassOf) == 0)) { continue; } new_parent = talloc(mem_ctx, struct class_list); - new_parent->objectclass = talloc_strdup(msg, class->subClassOf); + new_parent->objectclass = dsdb_class_by_lDAPDisplayName(schema, current->objectclass->subClassOf); DLIST_ADD_END(unsorted, new_parent, struct class_list *); } @@ -193,13 +200,12 @@ static int objectclass_sort(struct ldb_module *module, for (current = parent_class; schema && unsorted && current; current = current->next) { /* Walk the list of possible subclasses in unsorted */ for (poss_subclass = unsorted; poss_subclass; ) { - const struct dsdb_class *class = dsdb_class_by_lDAPDisplayName(schema, poss_subclass->objectclass); struct class_list *next; /* Save the next pointer, as the DLIST_ macros will change poss_subclass->next */ next = poss_subclass->next; - if (class && ldb_attr_cmp(class->subClassOf, current->objectclass) == 0) { + if (ldb_attr_cmp(poss_subclass->objectclass->subClassOf, current->objectclass->lDAPDisplayName) == 0) { DLIST_REMOVE(unsorted, poss_subclass); DLIST_ADD(subclass, poss_subclass); @@ -237,7 +243,7 @@ static int objectclass_sort(struct ldb_module *module, * was no 'top', a conflict in the objectClasses or some other * schema error? */ - ldb_asprintf_errstring(module->ldb, "objectclass %s is not a valid objectClass in objectClass chain", unsorted->objectclass); + ldb_asprintf_errstring(module->ldb, "objectclass %s is not a valid objectClass in objectClass chain", unsorted->objectclass->lDAPDisplayName); return LDB_ERR_OBJECT_CLASS_VIOLATION; } @@ -335,6 +341,22 @@ static int fix_dn(TALLOC_CTX *mem_ctx, *ldb_dn_get_rdn_val(newdn)); } +/* Fix all attribute names to be in the correct case, and check they are all valid per the schema */ +static int fix_attributes(struct ldb_context *ldb, const struct dsdb_schema *schema, struct ldb_message *msg) +{ + int i; + for (i=0; i < msg->num_elements; i++) { + const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(schema, msg->elements[i].name); + if (!attribute) { + ldb_asprintf_errstring(ldb, "objectclass %s is not a valid objectClass in schema", msg->elements[i].name); + return LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE; + } + msg->elements[i].name = attribute->lDAPDisplayName; + } + + return LDB_SUCCESS; +} + static int objectclass_add(struct ldb_module *module, struct ldb_request *req) { @@ -447,53 +469,56 @@ static int objectclass_do_add(struct ldb_handle *h) } - /* This is now the objectClass list from the database */ - objectclass_element = ldb_msg_find_element(msg, "objectClass"); - - if (!objectclass_element) { - /* Where did it go? bail now... */ - talloc_free(mem_ctx); - return LDB_ERR_OPERATIONS_ERROR; - } - ret = objectclass_sort(ac->module, msg, mem_ctx, objectclass_element, &sorted); - if (ret != LDB_SUCCESS) { - talloc_free(mem_ctx); - return ret; - } - - ldb_msg_remove_attr(msg, "objectClass"); - ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL); - - if (ret != LDB_SUCCESS) { - talloc_free(mem_ctx); - return ret; - } - - /* We must completely replace the existing objectClass entry, - * because we need it sorted */ + if (schema) { + ret = fix_attributes(ac->module->ldb, schema, msg); + if (ret != LDB_SUCCESS) { + talloc_free(mem_ctx); + return ret; + } - /* Move from the linked list back into an ldb msg */ - for (current = sorted; current; current = current->next) { - ret = ldb_msg_add_string(msg, "objectClass", current->objectclass); + /* This is now the objectClass list from the database */ + objectclass_element = ldb_msg_find_element(msg, "objectClass"); + + if (!objectclass_element) { + /* Where did it go? bail now... */ + talloc_free(mem_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + ret = objectclass_sort(ac->module, schema, msg, mem_ctx, objectclass_element, &sorted); + if (ret != LDB_SUCCESS) { + talloc_free(mem_ctx); + return ret; + } + + ldb_msg_remove_attr(msg, "objectClass"); + ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL); + if (ret != LDB_SUCCESS) { - ldb_set_errstring(ac->module->ldb, - "objectclass: could not re-add sorted " - "objectclass to modify msg"); talloc_free(mem_ctx); return ret; } - /* Last one is the critical one */ - if (schema && !current->next) { - const struct dsdb_class *objectclass - = dsdb_class_by_lDAPDisplayName(schema, - current->objectclass); - if (objectclass) { + + /* We must completely replace the existing objectClass entry, + * because we need it sorted */ + + /* Move from the linked list back into an ldb msg */ + for (current = sorted; current; current = current->next) { + ret = ldb_msg_add_string(msg, "objectClass", current->objectclass->lDAPDisplayName); + if (ret != LDB_SUCCESS) { + ldb_set_errstring(ac->module->ldb, + "objectclass: could not re-add sorted " + "objectclass to modify msg"); + talloc_free(mem_ctx); + return ret; + } + /* Last one is the critical one */ + if (!current->next) { if (!ldb_msg_find_element(msg, "objectCategory")) { ldb_msg_add_string(msg, "objectCategory", - objectclass->defaultObjectCategory); + current->objectclass->defaultObjectCategory); } if (!ldb_msg_find_element(msg, "nTSecurityDescriptor")) { - DATA_BLOB *sd = get_sd(ac->module, mem_ctx, objectclass); + DATA_BLOB *sd = get_sd(ac->module, mem_ctx, current->objectclass); ldb_msg_add_steal_value(msg, "nTSecurityDescriptor", sd); } } @@ -503,6 +528,7 @@ static int objectclass_do_add(struct ldb_handle *h) talloc_free(mem_ctx); ret = ldb_msg_sanity_check(ac->module->ldb, msg); + if (ret != LDB_SUCCESS) { return ret; } @@ -520,6 +546,9 @@ static int objectclass_modify(struct ldb_module *module, struct ldb_request *req { struct ldb_message_element *objectclass_element; struct ldb_message *msg; + const struct dsdb_schema *schema = dsdb_get_schema(module->ldb); + int ret; + ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_modify\n"); /* do not manipulate our control entries */ @@ -527,29 +556,57 @@ static int objectclass_modify(struct ldb_module *module, struct ldb_request *req return ldb_next_request(module, req); } + /* Without schema, there isn't much to do here */ + if (!schema) { + return ldb_next_request(module, req); + } objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass"); /* If no part of this touches the objectClass, then we don't * need to make any changes. */ - /* If the only operation is the deletion of the objectClass then go on */ + + /* If the only operation is the deletion of the objectClass + * then go on with just fixing the attribute case */ if (!objectclass_element) { - return ldb_next_request(module, req); + struct ldb_request *down_req = talloc(req, struct ldb_request); + if (down_req == NULL) { + ldb_set_errstring(module->ldb, "Out of memory!"); + return LDB_ERR_OPERATIONS_ERROR; + } + + *down_req = *req; /* copy the request */ + + down_req->op.mod.message = msg = ldb_msg_copy_shallow(down_req, req->op.mod.message); + + if (down_req->op.mod.message == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = fix_attributes(module->ldb, schema, msg); + if (ret != LDB_SUCCESS) { + return ret; + } + + /* go on with the call chain */ + ret = ldb_next_request(module, down_req); + + /* do not free down_req as the call results may be linked to it, + * it will be freed when the upper level request get freed */ + if (ret == LDB_SUCCESS) { + req->handle = down_req->handle; + } + return ret; } switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) { case LDB_FLAG_MOD_DELETE: - /* Delete everything? Probably totally illigal, but hey! */ - if (objectclass_element->num_values == 0) { - - return ldb_next_request(module, req); - } + return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED; break; case LDB_FLAG_MOD_REPLACE: { struct ldb_request *down_req; struct class_list *sorted, *current; TALLOC_CTX *mem_ctx; - int ret; mem_ctx = talloc_new(req); if (mem_ctx == NULL) { return LDB_ERR_OPERATIONS_ERROR; @@ -567,12 +624,18 @@ static int objectclass_modify(struct ldb_module *module, struct ldb_request *req down_req->op.mod.message = msg = ldb_msg_copy_shallow(down_req, req->op.mod.message); - if (down_req->op.add.message == NULL) { + if (down_req->op.mod.message == NULL) { talloc_free(mem_ctx); return LDB_ERR_OPERATIONS_ERROR; } - ret = objectclass_sort(module, msg, mem_ctx, objectclass_element, &sorted); + ret = fix_attributes(module->ldb, schema, msg); + if (ret != LDB_SUCCESS) { + talloc_free(mem_ctx); + return ret; + } + + ret = objectclass_sort(module, schema, msg, mem_ctx, objectclass_element, &sorted); if (ret != LDB_SUCCESS) { return ret; } @@ -590,7 +653,7 @@ static int objectclass_modify(struct ldb_module *module, struct ldb_request *req /* Move from the linked list back into an ldb msg */ for (current = sorted; current; current = current->next) { - ret = ldb_msg_add_string(msg, "objectClass", current->objectclass); + ret = ldb_msg_add_string(msg, "objectClass", current->objectclass->lDAPDisplayName); if (ret != LDB_SUCCESS) { ldb_set_errstring(module->ldb, "objectclass: could not re-add sorted objectclass to modify msg"); talloc_free(mem_ctx); @@ -638,12 +701,25 @@ static int objectclass_modify(struct ldb_module *module, struct ldb_request *req /* prepare the first operation */ ac->down_req = talloc(ac, struct ldb_request); if (ac->down_req == NULL) { - ldb_set_errstring(module->ldb, "Out of memory!"); + ldb_oom(ac->module->ldb); return LDB_ERR_OPERATIONS_ERROR; } *(ac->down_req) = *req; /* copy the request */ + ac->down_req->op.mod.message = msg = ldb_msg_copy_shallow(ac->down_req, req->op.mod.message); + + if (ac->down_req->op.mod.message == NULL) { + ldb_oom(ac->module->ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = fix_attributes(ac->module->ldb, schema, msg); + if (ret != LDB_SUCCESS) { + ldb_oom(ac->module->ldb); + return ret; + } + ac->down_req->context = NULL; ac->down_req->callback = NULL; ldb_set_timeout_from_prev_req(module->ldb, req, ac->down_req); @@ -681,6 +757,7 @@ static int objectclass_search_self(struct ldb_handle *h) static int objectclass_do_mod(struct ldb_handle *h) { + const struct dsdb_schema *schema; struct oc_context *ac; struct ldb_message_element *objectclass_element; struct ldb_message *msg; @@ -689,6 +766,7 @@ static int objectclass_do_mod(struct ldb_handle *h) { int ret; ac = talloc_get_type(h->private_data, struct oc_context); + schema = dsdb_get_schema(ac->module->ldb); mem_ctx = talloc_new(ac); if (mem_ctx == NULL) { @@ -727,7 +805,7 @@ static int objectclass_do_mod(struct ldb_handle *h) { /* modify dn */ msg->dn = ac->orig_req->op.mod.message->dn; - ret = objectclass_sort(ac->module, msg, mem_ctx, objectclass_element, &sorted); + ret = objectclass_sort(ac->module, schema, msg, mem_ctx, objectclass_element, &sorted); if (ret != LDB_SUCCESS) { return ret; } @@ -745,7 +823,7 @@ static int objectclass_do_mod(struct ldb_handle *h) { /* Move from the linked list back into an ldb msg */ for (current = sorted; current; current = current->next) { - ret = ldb_msg_add_string(msg, "objectClass", current->objectclass); + ret = ldb_msg_add_string(msg, "objectClass", current->objectclass->lDAPDisplayName); if (ret != LDB_SUCCESS) { ldb_set_errstring(ac->module->ldb, "objectclass: could not re-add sorted objectclass to modify msg"); talloc_free(mem_ctx); -- cgit From 2de30ecd942e05e5416a9f14c91d58324a0bc6eb Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 30 Oct 2007 23:35:04 +0100 Subject: r25755: Fix a couple of memory leaks, in particular a new leak onto the NULL context caused by my objectclass module work. Andrew Bartlett (This used to be commit 2a835d900fee71e4461d5d18e39b4358fa6fdfba) --- source4/dsdb/samdb/ldb_modules/objectclass.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'source4/dsdb/samdb/ldb_modules/objectclass.c') diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index 6d40759e7b..12a6359037 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -389,7 +389,7 @@ static int objectclass_add(struct ldb_module *module, struct ldb_request *req) /* return or own handle to deal with this call */ req->handle = h; - parent_dn = ldb_dn_get_parent(ac->search_req, ac->orig_req->op.mod.message->dn); + parent_dn = ldb_dn_get_parent(ac, ac->orig_req->op.mod.message->dn); if (parent_dn == NULL) { ldb_oom(module->ldb); return LDB_ERR_OPERATIONS_ERROR; @@ -403,6 +403,8 @@ static int objectclass_add(struct ldb_module *module, struct ldb_request *req) return ret; } + talloc_steal(ac->search_req, parent_dn); + ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req); ac->step = OC_SEARCH_ADD_PARENT; @@ -873,7 +875,7 @@ static int objectclass_rename(struct ldb_module *module, struct ldb_request *req /* return or own handle to deal with this call */ req->handle = h; - parent_dn = ldb_dn_get_parent(ac->search_req, ac->orig_req->op.rename.newdn); + parent_dn = ldb_dn_get_parent(ac, ac->orig_req->op.rename.newdn); if (parent_dn == NULL) { ldb_oom(module->ldb); return LDB_ERR_OPERATIONS_ERROR; @@ -886,7 +888,7 @@ static int objectclass_rename(struct ldb_module *module, struct ldb_request *req if (ret != LDB_SUCCESS) { return ret; } - + talloc_steal(ac->search_req, parent_dn); ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req); ac->step = OC_SEARCH_RENAME_PARENT; -- cgit From a4c79f06ae84057cb635f8b9fbb280d865afce7b Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 31 Oct 2007 04:41:36 +0100 Subject: r25762: This test belongs best with the other checks for a valid parent, in the objectclass module. Andrew Bartlett (This used to be commit 16a292fcb134adec110cbc4c8f0fb03323750a45) --- source4/dsdb/samdb/ldb_modules/objectclass.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'source4/dsdb/samdb/ldb_modules/objectclass.c') diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index 12a6359037..0cd00e3834 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -865,6 +865,14 @@ static int objectclass_rename(struct ldb_module *module, struct ldb_request *req if (ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */ return ldb_next_request(module, req); } + + /* Firstly ensure we are not trying to rename it to be a child of itself */ + if ((ldb_dn_compare_base(req->op.rename.olddn, req->op.rename.newdn) == 0) + && (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) != 0)) { + ldb_asprintf_errstring(module->ldb, "Cannot rename %s to be a child of itself", + ldb_dn_get_linearized(req->op.rename.olddn)); + return LDB_ERR_UNWILLING_TO_PERFORM; + } h = oc_init_handle(req, module); if (!h) { -- cgit From 529763a9aa192a6785ba878aceeb1683c2510913 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 9 Nov 2007 19:24:51 +0100 Subject: r25920: ndr: change NTSTAUS into enum ndr_err_code (samba4 callers) lib/messaging/ lib/registry/ lib/ldb-samba/ librpc/rpc/ auth/auth_winbind.c auth/gensec/ auth/kerberos/ dsdb/repl/ dsdb/samdb/ dsdb/schema/ torture/ cluster/ctdb/ kdc/ ntvfs/ipc/ torture/rap/ ntvfs/ utils/getntacl.c ntptr/ smb_server/ libcli/wrepl/ wrepl_server/ libcli/cldap/ libcli/dgram/ libcli/ldap/ libcli/raw/ libcli/nbt/ libnet/ winbind/ rpc_server/ metze (This used to be commit 6223c7fddc972687eb577e04fc1c8e0604c35435) --- source4/dsdb/samdb/ldb_modules/objectclass.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'source4/dsdb/samdb/ldb_modules/objectclass.c') diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index 0cd00e3834..50ea2ec4e2 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -250,7 +250,7 @@ static int objectclass_sort(struct ldb_module *module, static DATA_BLOB *get_sd(struct ldb_module *module, TALLOC_CTX *mem_ctx, const struct dsdb_class *objectclass) { - NTSTATUS status; + enum ndr_err_code ndr_err; DATA_BLOB *linear_sd; struct auth_session_info *session_info = ldb_get_opaque(module->ldb, "sessionInfo"); @@ -271,10 +271,9 @@ static DATA_BLOB *get_sd(struct ldb_module *module, TALLOC_CTX *mem_ctx, return NULL; } - status = ndr_push_struct_blob(linear_sd, mem_ctx, sd, - (ndr_push_flags_fn_t)ndr_push_security_descriptor); - - if (!NT_STATUS_IS_OK(status)) { + ndr_err = ndr_push_struct_blob(linear_sd, mem_ctx, sd, + (ndr_push_flags_fn_t)ndr_push_security_descriptor); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { return NULL; } -- cgit From 5d4f507a65144d8fe30b3fcd0b9cbcdc088146c6 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 13 Nov 2007 22:54:52 +0100 Subject: r25942: Make various ldb modules handle an LDB backend that enforces validity of Base DNs in searches (returning an error of LDB_ERR_NO_SUCH_ENTRY). We need to handle this if ldb_tdb is to behave correctly compared with LDAP, as well as if we are using an LDAP backend. In doing so, I realised that subtree_rename and subtree_delete (prevention) need rather different wait loops, so it seemed easier to split it out into it's own module. I've fixed the licence on both of these modules to be GPLv3. Andrew Bartlett (This used to be commit d3894c90f31fb45e038ab478cd9d7d34962d069b) --- source4/dsdb/samdb/ldb_modules/objectclass.c | 29 +++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) (limited to 'source4/dsdb/samdb/ldb_modules/objectclass.c') diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index 50ea2ec4e2..5626d9a891 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -68,6 +68,8 @@ struct class_list { const struct dsdb_class *objectclass; }; +static int objectclass_do_add(struct ldb_handle *h); + static struct ldb_handle *oc_init_handle(struct ldb_request *req, struct ldb_module *module) { struct oc_context *ac; @@ -388,11 +390,17 @@ static int objectclass_add(struct ldb_module *module, struct ldb_request *req) /* return or own handle to deal with this call */ req->handle = h; - parent_dn = ldb_dn_get_parent(ac, ac->orig_req->op.mod.message->dn); + /* If there isn't a parent, just go on to the add processing */ + if (ldb_dn_get_comp_num(ac->orig_req->op.add.message->dn) == 1) { + return objectclass_do_add(h); + } + + parent_dn = ldb_dn_get_parent(ac, ac->orig_req->op.add.message->dn); if (parent_dn == NULL) { ldb_oom(module->ldb); return LDB_ERR_OPERATIONS_ERROR; } + ret = ldb_build_search_req(&ac->search_req, module->ldb, ac, parent_dn, LDB_SCOPE_BASE, "(objectClass=*)", @@ -443,9 +451,7 @@ static int objectclass_do_add(struct ldb_handle *h) /* Check we have a valid parent */ if (ac->search_res == NULL) { - if (ldb_dn_get_comp_num(ac->orig_req->op.add.message->dn) <= 1) { - /* Allow cn=rootdse and cn=templates for now... */ - } else if (ldb_dn_compare(ldb_get_root_basedn(ac->module->ldb), ac->orig_req->op.add.message->dn) == 0) { + if (ldb_dn_compare(ldb_get_root_basedn(ac->module->ldb), ac->orig_req->op.add.message->dn) == 0) { /* Allow the tree to be started */ } else { ldb_asprintf_errstring(ac->module->ldb, "objectclass: Cannot add %s, parent does not exist!", @@ -461,6 +467,8 @@ static int objectclass_do_add(struct ldb_handle *h) &msg->dn); if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ac->module->ldb, "Could not munge DN %s into normal form", + ldb_dn_get_linearized(ac->orig_req->op.add.message->dn)); return ret; } @@ -601,7 +609,9 @@ static int objectclass_modify(struct ldb_module *module, struct ldb_request *req switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) { case LDB_FLAG_MOD_DELETE: - return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED; + if (objectclass_element->num_values == 0) { + return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED; + } break; case LDB_FLAG_MOD_REPLACE: { @@ -1026,11 +1036,12 @@ static int oc_wait(struct ldb_handle *handle) { case OC_SEARCH_ADD_PARENT: ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE); - if (ret != LDB_SUCCESS) { + if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) { handle->status = ret; goto done; } - if (ac->search_req->handle->status != LDB_SUCCESS) { + if (ac->search_req->handle->status != LDB_SUCCESS + && ac->search_req->handle->status != LDB_ERR_NO_SUCH_OBJECT) { handle->status = ac->search_req->handle->status; goto done; } @@ -1063,11 +1074,11 @@ static int oc_wait(struct ldb_handle *handle) { case OC_SEARCH_RENAME_PARENT: ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE); - if (ret != LDB_SUCCESS) { + if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) { handle->status = ret; goto done; } - if (ac->search_req->handle->status != LDB_SUCCESS) { + if (ac->search_req->handle->status != LDB_SUCCESS && ac->search_req->handle->status != LDB_ERR_NO_SUCH_OBJECT) { handle->status = ac->search_req->handle->status; goto done; } -- cgit From d4fbd381fa5f75a76870531fe15bace4550e0f01 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 4 Dec 2007 03:37:41 +0100 Subject: r26282: These modules expect errors, but if we don't wipe the error string, we get phony error strings at the caller, which is very confusing. Andrew Bartlett (This used to be commit 9ac7f4f6098b392dbe4a883a802d2417e074586a) --- source4/dsdb/samdb/ldb_modules/objectclass.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'source4/dsdb/samdb/ldb_modules/objectclass.c') diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index 5626d9a891..b996f05250 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -453,6 +453,9 @@ static int objectclass_do_add(struct ldb_handle *h) if (ac->search_res == NULL) { if (ldb_dn_compare(ldb_get_root_basedn(ac->module->ldb), ac->orig_req->op.add.message->dn) == 0) { /* Allow the tree to be started */ + + /* but don't keep any error string, it's meaningless */ + ldb_set_errstring(ac->module->ldb, NULL); } else { ldb_asprintf_errstring(ac->module->ldb, "objectclass: Cannot add %s, parent does not exist!", ldb_dn_get_linearized(ac->orig_req->op.add.message->dn)); -- cgit From 6d2f6f1aae2fd20dec9ed37019de26c7b33b7d2c Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 5 Dec 2007 00:35:19 +0100 Subject: r26297: Correct error message. This function verifies attributes, not objectclasses. Andrew Bartlett (This used to be commit 47422b5e59027461efd7bc45534f9da8e37e3f48) --- source4/dsdb/samdb/ldb_modules/objectclass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/dsdb/samdb/ldb_modules/objectclass.c') diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index b996f05250..da5cae1c65 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -349,7 +349,7 @@ static int fix_attributes(struct ldb_context *ldb, const struct dsdb_schema *sch for (i=0; i < msg->num_elements; i++) { const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(schema, msg->elements[i].name); if (!attribute) { - ldb_asprintf_errstring(ldb, "objectclass %s is not a valid objectClass in schema", msg->elements[i].name); + ldb_asprintf_errstring(ldb, "attribute %s is not a valid attribute in schema", msg->elements[i].name); return LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE; } msg->elements[i].name = attribute->lDAPDisplayName; -- cgit From 3e75f222bcdf114238cc4f2bcc61332dc059135f Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 19 Dec 2007 23:27:42 +0100 Subject: r26539: Remove unnecessary statics. (This used to be commit e53e79eebef3ece6978f0a2b4a1ee0a0814bb5d2) --- source4/dsdb/samdb/ldb_modules/objectclass.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'source4/dsdb/samdb/ldb_modules/objectclass.c') diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index da5cae1c65..44a940f97b 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -361,7 +361,7 @@ static int fix_attributes(struct ldb_context *ldb, const struct dsdb_schema *sch static int objectclass_add(struct ldb_module *module, struct ldb_request *req) { - static const char * const attrs[] = { NULL }; + const char * const attrs[] = { NULL }; struct ldb_handle *h; struct oc_context *ac; @@ -748,7 +748,7 @@ static int objectclass_search_self(struct ldb_handle *h) { int ret; struct oc_context *ac; - static const char * const attrs[] = { "objectClass", NULL }; + const char * const attrs[] = { "objectClass", NULL }; ac = talloc_get_type(h->private_data, struct oc_context); @@ -865,7 +865,7 @@ static int objectclass_do_mod(struct ldb_handle *h) { static int objectclass_rename(struct ldb_module *module, struct ldb_request *req) { - static const char * const attrs[] = { NULL }; + const char * const attrs[] = { NULL }; struct ldb_handle *h; struct oc_context *ac; -- cgit From 0500b87092540d300b4e021a0fb95ce16a44fbd2 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 20 Dec 2007 00:02:15 +0100 Subject: r26540: Revert my previous commit after concerns raised by Andrew. (This used to be commit 6ac86f8be7d9a8c5ab396a93e6d1e6819e11f173) --- source4/dsdb/samdb/ldb_modules/objectclass.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'source4/dsdb/samdb/ldb_modules/objectclass.c') diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index 44a940f97b..da5cae1c65 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -361,7 +361,7 @@ static int fix_attributes(struct ldb_context *ldb, const struct dsdb_schema *sch static int objectclass_add(struct ldb_module *module, struct ldb_request *req) { - const char * const attrs[] = { NULL }; + static const char * const attrs[] = { NULL }; struct ldb_handle *h; struct oc_context *ac; @@ -748,7 +748,7 @@ static int objectclass_search_self(struct ldb_handle *h) { int ret; struct oc_context *ac; - const char * const attrs[] = { "objectClass", NULL }; + static const char * const attrs[] = { "objectClass", NULL }; ac = talloc_get_type(h->private_data, struct oc_context); @@ -865,7 +865,7 @@ static int objectclass_do_mod(struct ldb_handle *h) { static int objectclass_rename(struct ldb_module *module, struct ldb_request *req) { - const char * const attrs[] = { NULL }; + static const char * const attrs[] = { NULL }; struct ldb_handle *h; struct oc_context *ac; -- cgit From 86dc05e99f124db47f2743d1fc23117a7f5145ab Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Tue, 1 Jan 2008 22:05:05 -0600 Subject: r26638: libndr: Require explicitly specifying iconv_convenience for ndr_struct_push_blob(). (This used to be commit 61ad78ac98937ef7a9aa32075a91a1c95b7606b3) --- source4/dsdb/samdb/ldb_modules/objectclass.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'source4/dsdb/samdb/ldb_modules/objectclass.c') diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index da5cae1c65..d3beedc689 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -43,6 +43,7 @@ #include "librpc/gen_ndr/ndr_security.h" #include "libcli/security/security.h" #include "auth/auth.h" +#include "param/param.h" struct oc_context { @@ -273,7 +274,9 @@ static DATA_BLOB *get_sd(struct ldb_module *module, TALLOC_CTX *mem_ctx, return NULL; } - ndr_err = ndr_push_struct_blob(linear_sd, mem_ctx, sd, + ndr_err = ndr_push_struct_blob(linear_sd, mem_ctx, + lp_iconv_convenience(ldb_get_opaque(module->ldb, "loadparm")), + sd, (ndr_push_flags_fn_t)ndr_push_security_descriptor); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { return NULL; -- cgit From 391f089d71b4b51a130819ab681dcd1253f16b8c Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 18 Jan 2008 16:56:41 +1100 Subject: Add showInAdvancedViewOnly to every new object Unless already set, the default value for this comes from the defaultHidingValue in the schema. Andrew Bartlett (This used to be commit 673f1805006f879fa5302aab8411767a22488e64) --- source4/dsdb/samdb/ldb_modules/objectclass.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'source4/dsdb/samdb/ldb_modules/objectclass.c') diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index d3beedc689..871c38476b 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -532,6 +532,10 @@ static int objectclass_do_add(struct ldb_handle *h) ldb_msg_add_string(msg, "objectCategory", current->objectclass->defaultObjectCategory); } + if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly")) { + ldb_msg_add_string(msg, "showInAdvancedViewOnly", + current->objectclass->defaultHidingValue ? "TRUE" : "FALSE"); + } if (!ldb_msg_find_element(msg, "nTSecurityDescriptor")) { DATA_BLOB *sd = get_sd(ac->module, mem_ctx, current->objectclass); ldb_msg_add_steal_value(msg, "nTSecurityDescriptor", sd); -- cgit From 7e2ea67b2118d31d11ed668d081568f7ef2243ae Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 18 Jan 2008 18:08:49 +1100 Subject: Only set showOnlyInAdvancedView: TRUE when adding default values. False is the default, so only set this when the schema requires the hiding behaviour. Andrew Bartlett (This used to be commit 45f6ccefda39e8f0a9820ba55b1924b7cfb12262) --- source4/dsdb/samdb/ldb_modules/objectclass.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source4/dsdb/samdb/ldb_modules/objectclass.c') diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index 871c38476b..737475ca78 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -532,9 +532,9 @@ static int objectclass_do_add(struct ldb_handle *h) ldb_msg_add_string(msg, "objectCategory", current->objectclass->defaultObjectCategory); } - if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly")) { + if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (current->objectclass->defaultHidingValue == true)) { ldb_msg_add_string(msg, "showInAdvancedViewOnly", - current->objectclass->defaultHidingValue ? "TRUE" : "FALSE"); + "TRUE"); } if (!ldb_msg_find_element(msg, "nTSecurityDescriptor")) { DATA_BLOB *sd = get_sd(ac->module, mem_ctx, current->objectclass); -- cgit From 16109a40c0abd8c30a5eb9bf9ef692bfae9dfc7d Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 20 Feb 2008 01:54:32 +0100 Subject: Use struct-based rather than function-based initialization for ldb modules everywhere. (This used to be commit 85c96a325867f7bcdb412ebc53f8a47dbf7cd89b) --- source4/dsdb/samdb/ldb_modules/objectclass.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'source4/dsdb/samdb/ldb_modules/objectclass.c') diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index 737475ca78..98eeed7cde 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -1153,16 +1153,10 @@ static int objectclass_wait(struct ldb_handle *handle, enum ldb_wait_type type) } } -static const struct ldb_module_ops objectclass_ops = { +const struct ldb_module_ops ldb_objectclass_module_ops = { .name = "objectclass", .add = objectclass_add, .modify = objectclass_modify, .rename = objectclass_rename, .wait = objectclass_wait }; - -int ldb_objectclass_init(void) -{ - return ldb_register_module(&objectclass_ops); -} - -- cgit From 39a817d310964f8e9a63cfb096b3ad24fa03bd5e Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 20 Feb 2008 04:33:43 +0100 Subject: Fix use of some modules (needed _PUBLIC_). (This used to be commit ce332130ea77159832da23bab760fa26921719e2) --- source4/dsdb/samdb/ldb_modules/objectclass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/dsdb/samdb/ldb_modules/objectclass.c') diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index 98eeed7cde..e63ad4de56 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -1153,7 +1153,7 @@ static int objectclass_wait(struct ldb_handle *handle, enum ldb_wait_type type) } } -const struct ldb_module_ops ldb_objectclass_module_ops = { +_PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = { .name = "objectclass", .add = objectclass_add, .modify = objectclass_modify, -- cgit From 58edd6d17951553cb6b693b37ce88454668b1c50 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 13 Mar 2008 10:27:09 +1100 Subject: Don't segfault on invalid objectClass input. If the objectClass found does not include a defaultSecurityDescriptor, then we should not segfault in the SDDL parser. Andrew Bartlett (This used to be commit 5a92771fb55149fcf24f21f30e4c6a622bef44f8) --- source4/dsdb/samdb/ldb_modules/objectclass.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'source4/dsdb/samdb/ldb_modules/objectclass.c') diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index e63ad4de56..537a56045d 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -257,12 +257,17 @@ static DATA_BLOB *get_sd(struct ldb_module *module, TALLOC_CTX *mem_ctx, DATA_BLOB *linear_sd; struct auth_session_info *session_info = ldb_get_opaque(module->ldb, "sessionInfo"); - struct security_descriptor *sd - = sddl_decode(mem_ctx, - objectclass->defaultSecurityDescriptor, - samdb_domain_sid(module->ldb)); + struct security_descriptor *sd; - if (!session_info || !session_info->security_token) { + if (!objectclass->defaultSecurityDescriptor) { + return NULL; + } + + sd = sddl_decode(mem_ctx, + objectclass->defaultSecurityDescriptor, + samdb_domain_sid(module->ldb)); + + if (!sd || !session_info || !session_info->security_token) { return NULL; } @@ -538,7 +543,9 @@ static int objectclass_do_add(struct ldb_handle *h) } if (!ldb_msg_find_element(msg, "nTSecurityDescriptor")) { DATA_BLOB *sd = get_sd(ac->module, mem_ctx, current->objectclass); - ldb_msg_add_steal_value(msg, "nTSecurityDescriptor", sd); + if (sd) { + ldb_msg_add_steal_value(msg, "nTSecurityDescriptor", sd); + } } } } -- cgit From 4a2ba0c047249fa6f7f4c78313b3b221d9a5bcc7 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 13 Mar 2008 14:12:50 +1100 Subject: Bail out, rather than segfault on no domain sid. Andrew Bartlett (This used to be commit 7e85f318b571d1a909dffad0ecd661468ed497ca) --- source4/dsdb/samdb/ldb_modules/objectclass.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'source4/dsdb/samdb/ldb_modules/objectclass.c') diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index 537a56045d..4d4ef585cb 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -258,14 +258,15 @@ static DATA_BLOB *get_sd(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct auth_session_info *session_info = ldb_get_opaque(module->ldb, "sessionInfo"); struct security_descriptor *sd; + struct dom_sid *domain_sid = samdb_domain_sid(module->ldb); - if (!objectclass->defaultSecurityDescriptor) { + if (!objectclass->defaultSecurityDescriptor || !domain_sid) { return NULL; } sd = sddl_decode(mem_ctx, objectclass->defaultSecurityDescriptor, - samdb_domain_sid(module->ldb)); + domain_sid); if (!sd || !session_info || !session_info->security_token) { return NULL; -- cgit From c222f8196ab018c53579ceb3ffeeb1a9b3e77b6b Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 8 Sep 2008 11:10:24 +1000 Subject: Try to implement the right logic for systemFlags The MS-ADTS document has quite detailed instrucitons on how these flags should be processed. This change also causes the correct sign-wrapping to occour, as these are declared as signed integers. Andrew Bartlett (This used to be commit 5c3d237a6d721dc75166bdc5ac0c6e76a4495bf7) --- source4/dsdb/samdb/ldb_modules/objectclass.c | 37 ++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'source4/dsdb/samdb/ldb_modules/objectclass.c') diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index 4d4ef585cb..b048a8d8e1 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -534,6 +534,8 @@ static int objectclass_do_add(struct ldb_handle *h) } /* Last one is the critical one */ if (!current->next) { + struct ldb_message_element *el; + int32_t systemFlags = 0; if (!ldb_msg_find_element(msg, "objectCategory")) { ldb_msg_add_string(msg, "objectCategory", current->objectclass->defaultObjectCategory); @@ -548,6 +550,41 @@ static int objectclass_do_add(struct ldb_handle *h) ldb_msg_add_steal_value(msg, "nTSecurityDescriptor", sd); } } + + /* There are very special rules for systemFlags, see MS-ADTS 3.1.1.5.2.4 */ + el = ldb_msg_find_element(msg, "systemFlags"); + + systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0); + + if (el) { + /* Only these flags may be set by a client, but we can't tell between a client and our provision at this point */ + /* systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE); */ + ldb_msg_remove_element(msg, el); + } + + /* This flag is only allowed on attributeSchema objects */ + if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "attributeSchema") == 0) { + systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN; + } + + if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "server") == 0) { + systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE); + } else if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "site") == 0 + || ldb_attr_cmp(current->objectclass->lDAPDisplayName, "serverContainer") == 0 + || ldb_attr_cmp(current->objectclass->lDAPDisplayName, "ntDSDSA") == 0) { + systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE); + + } else if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "siteLink") == 0 + || ldb_attr_cmp(current->objectclass->lDAPDisplayName, "siteLinkBridge") == 0 + || ldb_attr_cmp(current->objectclass->lDAPDisplayName, "nTDSConnection") == 0) { + systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME); + } + + /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */ + + if (el || systemFlags != 0) { + samdb_msg_add_int(ac->module->ldb, msg, msg, "systemFlags", systemFlags); + } } } } -- cgit