From e72760b218e60acfc04c6c22a43820683172df09 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 16 Jan 2008 15:14:05 +1100 Subject: Rework linked_attributes module for the REPLACE case. This moves to a smarter 'find the delta' based operation of the linked attributes module, when the caller asks for a 'replace' of the link source. Previously we would spray operations all over the database, even if the net result was just to modify one record. This also means we need the transaction safety less, which may be useful for some LDAP backends that don't provide this functionality on the LDAP server. Andrew Bartlett (This used to be commit 8c88e4eb1c0a606e7899091525260e8d6558ffd0) --- source4/dsdb/samdb/ldb_modules/linked_attributes.c | 92 ++++++++++++++++++++-- 1 file changed, 86 insertions(+), 6 deletions(-) (limited to 'source4/dsdb/samdb/ldb_modules') diff --git a/source4/dsdb/samdb/ldb_modules/linked_attributes.c b/source4/dsdb/samdb/ldb_modules/linked_attributes.c index 803d24e34e..b3fdffe566 100644 --- a/source4/dsdb/samdb/ldb_modules/linked_attributes.c +++ b/source4/dsdb/samdb/ldb_modules/linked_attributes.c @@ -279,6 +279,27 @@ static int linked_attributes_add(struct ldb_module *module, struct ldb_request * return setup_modifies(module->ldb, ac, ac, req->op.add.message, NULL, req->op.add.message->dn); } +struct merge { + struct ldb_dn *dn; + bool add; + bool ignore; +}; + +static int merge_cmp(struct merge *merge1, struct merge *merge2) { + int ret; + ret = ldb_dn_compare(merge1->dn, merge2->dn); + if (ret == 0) { + if (merge1->add == merge2->add) { + return 0; + } + if (merge1->add == true) { + return 1; + } + return -1; + } + return ret; +} + static int linked_attributes_mod_replace_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) { struct replace_context *ac2 = talloc_get_type(context, struct replace_context); @@ -296,16 +317,63 @@ static int linked_attributes_mod_replace_search_callback(struct ldb_context *ldb /* See if this element already exists */ if (search_el) { - int ret; + + struct merge *merged_list = NULL; + + int ret, size = 0, i; struct ldb_message *msg = ldb_msg_new(ac); if (!msg) { ldb_oom(ac->module->ldb); return LDB_ERR_OPERATIONS_ERROR; } - /* Lazy option: Delete and add the elements on all members */ - msg->num_elements = 1; - msg->elements = search_el; + /* Add all the existing elements, marking as 'proposed for delete' by setting .add = false */ + for (i=0; i < search_el->num_values; i++) { + merged_list = talloc_realloc(ares, merged_list, struct merge, size + 1); + merged_list[size].dn = ldb_dn_new(merged_list, ldb, (char *)search_el->values[i].data); + merged_list[size].add = false; + merged_list[size].ignore = false; + size++; + } + + /* Add all the new replacement elements, marking as 'proposed for add' by setting .add = true */ + for (i=0; i < ac2->el->num_values; i++) { + merged_list = talloc_realloc(ares, merged_list, struct merge, size + 1); + merged_list[size].dn = ldb_dn_new(merged_list, ldb, (char *)ac2->el->values[i].data); + merged_list[size].add = true; + merged_list[size].ignore = false; + size++; + } + + /* Sort the list, so we can pick out an add and delete for the same DN, and eliminate them */ + qsort(merged_list, size, + sizeof(*merged_list), + (comparison_fn_t)merge_cmp); + + /* Now things are sorted, it is trivial to mark pairs of DNs as 'ignore' */ + for (i=0; i + 1 < size; i++) { + if (ldb_dn_compare(merged_list[i].dn, + merged_list[i+1].dn) == 0 + /* Fortunetly the sort also sorts 'add == false' first */ + && merged_list[i].add == false + && merged_list[i+1].add == true) { + + /* Mark as ignore, so we include neither in the actual operations */ + merged_list[i].ignore = true; + merged_list[i+1].ignore = true; + } + } + + /* Arrange to delete anything the search found that we don't re-add */ + for (i=0; i < size; i++) { + if (merged_list[i].ignore == false + && merged_list[i].add == false) { + ldb_msg_add_steal_string(msg, search_el->name, + ldb_dn_get_linearized(merged_list[i].dn)); + } + } + + /* The DN to set on the linked attributes is the original DN of the modify message */ msg->dn = ac->orig_req->op.mod.message->dn; ret = setup_modifies(ac->module->ldb, ac2, ac, msg, ares->message->dn, NULL); @@ -313,13 +381,21 @@ static int linked_attributes_mod_replace_search_callback(struct ldb_context *ldb return ret; } - msg->elements = ac2->el; + /* Now add links for all the actually new elements */ + for (i=0; i < size; i++) { + if (merged_list[i].ignore == false && merged_list[i].add == true) { + ldb_msg_add_steal_string(msg, search_el->name, + ldb_dn_get_linearized(merged_list[i].dn)); + } + } ret = setup_modifies(ac->module->ldb, ac2, ac, msg, NULL, ares->message->dn); if (ret != LDB_SUCCESS) { return ret; } + talloc_free(merged_list); + } else { /* Looks like it doesn't exist, process like an 'add' */ struct ldb_message *msg = ldb_msg_new(ac); @@ -411,6 +487,7 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques return LDB_ERR_OBJECT_CLASS_VIOLATION; } + /* Replace with new set of values */ if (((el->flags & LDB_FLAG_MOD_MASK) == LDB_FLAG_MOD_REPLACE) && el->num_values > 0) { struct replace_context *ac2 = talloc(ac, struct replace_context); @@ -461,6 +538,8 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques } continue; + + /* Delete all values case */ } else if (((el->flags & LDB_FLAG_MOD_MASK) & (LDB_FLAG_MOD_DELETE|LDB_FLAG_MOD_REPLACE)) && el->num_values == 0) { const char **attrs = talloc_array(ac, const char *, 2); @@ -508,7 +587,8 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques continue; } - /* Prepare the modify (mod element) on the targets */ + + /* Prepare the modify (mod element) on the targets, for a normal modify request */ /* For each value being moded, we need to setup the modify */ for (j=0; j < el->num_values; j++) { -- cgit From d5fd15005c0cad9e9018e81ab5c30b87cb2f605a Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 17 Jan 2008 08:53:18 +1100 Subject: ldb_map objectClass munging: Don't hard-code 'extensibleObject'. This allows objectClass munging to be removed, or modified to not include adding an objectClass, or for that objectClass to be something different. Andrew Bartlett (This used to be commit ee93b4e2ee1dd1cd38bcf14b2bb62556a13cec4a) --- source4/dsdb/samdb/ldb_modules/samba3sam.c | 2 +- source4/dsdb/samdb/ldb_modules/simple_ldap_map.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'source4/dsdb/samdb/ldb_modules') diff --git a/source4/dsdb/samdb/ldb_modules/samba3sam.c b/source4/dsdb/samdb/ldb_modules/samba3sam.c index 0bfc9a3dae..3a666b5380 100644 --- a/source4/dsdb/samdb/ldb_modules/samba3sam.c +++ b/source4/dsdb/samdb/ldb_modules/samba3sam.c @@ -918,7 +918,7 @@ static int samba3sam_init(struct ldb_module *module) { int ret; - ret = ldb_map_init(module, samba3_attributes, samba3_objectclasses, NULL, "samba3sam"); + ret = ldb_map_init(module, samba3_attributes, samba3_objectclasses, NULL, NULL, "samba3sam"); if (ret != LDB_SUCCESS) return ret; diff --git a/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c b/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c index 970106787b..6e66d0783a 100644 --- a/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c +++ b/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c @@ -667,7 +667,7 @@ static int entryuuid_init(struct ldb_module *module) struct map_private *map_private; struct entryuuid_private *entryuuid_private; - ret = ldb_map_init(module, entryuuid_attributes, entryuuid_objectclasses, entryuuid_wildcard_attributes, NULL); + ret = ldb_map_init(module, entryuuid_attributes, entryuuid_objectclasses, entryuuid_wildcard_attributes, "extensibleObject", NULL); if (ret != LDB_SUCCESS) return ret; @@ -688,7 +688,7 @@ static int nsuniqueid_init(struct ldb_module *module) struct map_private *map_private; struct entryuuid_private *entryuuid_private; - ret = ldb_map_init(module, nsuniqueid_attributes, NULL, nsuniqueid_wildcard_attributes, NULL); + ret = ldb_map_init(module, nsuniqueid_attributes, NULL, nsuniqueid_wildcard_attributes, "extensibleObject", NULL); if (ret != LDB_SUCCESS) return ret; -- cgit From 8d36d43e5258aa80855a9baa707a9fcad77a0d03 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 18 Jan 2008 10:13:43 +1100 Subject: Add in a new module to handle instanceType This code raided from the repl_meta_data module, which probably needs to be downsized to just handling the replication data. Andrew Bartlett (This used to be commit 2a418f33705a792d9d16cf1d4aa3dcda467e6e04) --- source4/dsdb/samdb/ldb_modules/config.mk | 13 +++ source4/dsdb/samdb/ldb_modules/instancetype.c | 128 ++++++++++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 source4/dsdb/samdb/ldb_modules/instancetype.c (limited to 'source4/dsdb/samdb/ldb_modules') diff --git a/source4/dsdb/samdb/ldb_modules/config.mk b/source4/dsdb/samdb/ldb_modules/config.mk index a41a29b5dd..dc407fbd8a 100644 --- a/source4/dsdb/samdb/ldb_modules/config.mk +++ b/source4/dsdb/samdb/ldb_modules/config.mk @@ -333,3 +333,16 @@ OBJ_FILES = \ # End MODULE ldb_normalise ################################################ +################################################ +# Start MODULE ldb_instancetype +[MODULE::ldb_instancetype] +INIT_FUNCTION = ldb_instancetype_init +CFLAGS = -Ilib/ldb/include +OUTPUT_TYPE = SHARED_LIBRARY +PRIVATE_DEPENDENCIES = LIBTALLOC +SUBSYSTEM = LIBLDB +OBJ_FILES = \ + instancetype.o +# End MODULE ldb_instancetype +################################################ + diff --git a/source4/dsdb/samdb/ldb_modules/instancetype.c b/source4/dsdb/samdb/ldb_modules/instancetype.c new file mode 100644 index 0000000000..ee1f2ff7ba --- /dev/null +++ b/source4/dsdb/samdb/ldb_modules/instancetype.c @@ -0,0 +1,128 @@ +/* + ldb database library + + Copyright (C) Simo Sorce 2004-2006 + Copyright (C) Andrew Bartlett 2005 + Copyright (C) Andrew Tridgell 2005 + Copyright (C) Stefan Metzmacher 2007 + + ** NOTE! The following LGPL license applies to the ldb + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see . +*/ + +/* + * Name: ldb + * + * Component: ldb instancetype module + * + * Description: add an instanceType onto every new record + * + * Author: Simo Sorce + */ + +#include "includes.h" +#include "ldb/include/ldb_includes.h" +#include "librpc/gen_ndr/ndr_misc.h" +#include "param/param.h" +#include "dsdb/samdb/samdb.h" +#include "dsdb/common/flags.h" + +/* add_record: add instancetype attribute */ +static int instancetype_add(struct ldb_module *module, struct ldb_request *req) +{ + struct ldb_request *down_req; + struct ldb_message *msg; + uint32_t instance_type; + int ret; + const struct ldb_control *partition_ctrl; + const struct dsdb_control_current_partition *partition; + + + ldb_debug(module->ldb, LDB_DEBUG_TRACE, "instancetype_add_record\n"); + + /* do not manipulate our control entries */ + if (ldb_dn_is_special(req->op.add.message->dn)) { + return ldb_next_request(module, req); + } + + partition_ctrl = ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID); + if (!partition_ctrl) { + ldb_debug_set(module->ldb, LDB_DEBUG_FATAL, + "instancetype_add: no current partition control found"); + return LDB_ERR_CONSTRAINT_VIOLATION; + } + + partition = talloc_get_type(partition_ctrl->data, + struct dsdb_control_current_partition); + SMB_ASSERT(partition && partition->version == DSDB_CONTROL_CURRENT_PARTITION_VERSION); + + down_req = talloc(req, struct ldb_request); + if (down_req == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + *down_req = *req; + + /* we have to copy the message as the caller might have it as a const */ + down_req->op.add.message = msg = ldb_msg_copy_shallow(down_req, req->op.add.message); + if (msg == NULL) { + talloc_free(down_req); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* + * TODO: calculate correct instance type + */ + instance_type = INSTANCE_TYPE_WRITE; + if (ldb_dn_compare(partition->dn, msg->dn) == 0) { + instance_type |= INSTANCE_TYPE_IS_NC_HEAD; + if (ldb_dn_compare(msg->dn, samdb_base_dn(module->ldb)) != 0) { + instance_type |= INSTANCE_TYPE_NC_ABOVE; + } + } + + ret = ldb_msg_add_fmt(msg, "instanceType", "%u", instance_type); + if (ret != LDB_SUCCESS) { + talloc_free(down_req); + ldb_oom(module->ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + ldb_set_timeout_from_prev_req(module->ldb, req, down_req); + + /* 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 const struct ldb_module_ops instancetype_ops = { + .name = "instancetype", + .add = instancetype_add, +}; + + +int ldb_instancetype_init(void) +{ + return ldb_register_module(&instancetype_ops); +} -- cgit From 564e021ed974b4bb3472ec3fc091746663808afd Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 18 Jan 2008 12:16:27 +1100 Subject: Correct authorship of instanceType module Andrew Bartlett (This used to be commit d427cf4fa67e84ccdece9a3fb31d8e89379a86e7) --- source4/dsdb/samdb/ldb_modules/instancetype.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/dsdb/samdb/ldb_modules') diff --git a/source4/dsdb/samdb/ldb_modules/instancetype.c b/source4/dsdb/samdb/ldb_modules/instancetype.c index ee1f2ff7ba..064c28ec65 100644 --- a/source4/dsdb/samdb/ldb_modules/instancetype.c +++ b/source4/dsdb/samdb/ldb_modules/instancetype.c @@ -31,7 +31,7 @@ * * Description: add an instanceType onto every new record * - * Author: Simo Sorce + * Author: Andrew Bartlett */ #include "includes.h" -- cgit From f106e67599a02426d5eaf87e9d76bec486427add Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 18 Jan 2008 13:27:05 +1100 Subject: Search for memberOf when clients ask for a wildcard against OpenLDAP The memberOf module in OpenLDAP make this attribute operational, so we need to add it here or clients won't get it when using *. Andrew Bartlett (This used to be commit 35148fd51f22d81fe9f590b7d6f13285c35656a7) --- source4/dsdb/samdb/ldb_modules/simple_ldap_map.c | 1 + 1 file changed, 1 insertion(+) (limited to 'source4/dsdb/samdb/ldb_modules') diff --git a/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c b/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c index 6e66d0783a..acf2fd622c 100644 --- a/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c +++ b/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c @@ -448,6 +448,7 @@ static const char * const entryuuid_wildcard_attributes[] = { "whenChanged", "usnCreated", "usnChanged", + "memberOf", 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') 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') 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