From e887969c2a413c4c1119735a5131b3af5b077814 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 4 Nov 2008 17:34:28 +1100 Subject: [PATCH] Use extended DN parsing in LDB An extended_dn is of the output form ;;dc=foo,dc=com but input forms also include and The main ldb_dn code parses this, so we don't need to do so here any more. This also changes now the default format for on-disk storage of DNs. (We search to find the additional details in the extended_dn module before we store any attributes of DN syntax). The extended form is only returned to clients when they ask for it with a control. Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/extended_dn.c | 643 +++++++++++++------ source4/scripting/python/samba/provision.py | 6 +- 2 files changed, 433 insertions(+), 216 deletions(-) diff --git a/source4/dsdb/samdb/ldb_modules/extended_dn.c b/source4/dsdb/samdb/ldb_modules/extended_dn.c index a0602d92815..5c54bf5d4fe 100644 --- a/source4/dsdb/samdb/ldb_modules/extended_dn.c +++ b/source4/dsdb/samdb/ldb_modules/extended_dn.c @@ -2,23 +2,20 @@ ldb database library Copyright (C) Simo Sorce 2005-2008 + Copyright (C) Andrew Bartlett 2007-2008 - ** NOTE! The following LGPL license applies to the ldb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL + 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 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, + 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 - 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 . + 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 . */ /* @@ -26,9 +23,12 @@ * * Component: ldb extended dn control module * - * Description: this module builds a special dn + * Description: this module builds a special dn for returned search + * results nad creates the special DN in the backend store for new + * values. * - * Author: Simo Sorce + * Authors: Simo Sorce + * Andrew Bartlett */ #include "includes.h" @@ -41,6 +41,44 @@ #include +struct extended_dn_replace_list { + struct extended_dn_replace_list *next; + struct ldb_dn *dn; + TALLOC_CTX *mem_ctx; + struct ldb_val *replace_dn; + struct extended_dn_context *ac; + struct ldb_request *search_req; +}; + + +struct extended_dn_context { + const struct dsdb_schema *schema; + struct ldb_module *module; + struct ldb_request *req; + + struct extended_dn_replace_list *ops; + struct extended_dn_replace_list *cur; +}; + + +static struct extended_dn_context *extended_dn_context_init(struct ldb_module *module, + struct ldb_request *req) +{ + struct extended_dn_context *ac; + + ac = talloc_zero(req, struct extended_dn_context); + if (ac == NULL) { + ldb_set_errstring(module->ldb, "Out of Memory"); + return NULL; + } + + ac->schema = dsdb_get_schema(module->ldb); + ac->module = module; + ac->req = req; + + return ac; +} + static bool is_attr_in_list(const char * const * attrs, const char *attr) { int i; @@ -95,112 +133,59 @@ static bool add_attrs(void *mem_ctx, char ***attrs, const char *attr) return true; } -static int inject_extended_dn(struct ldb_message *msg, - struct ldb_context *ldb, - int type, - bool remove_guid, - bool remove_sid) +static int inject_extended_dn(struct ldb_reply *ares, + struct ldb_context *ldb, + int type, + bool remove_guid, + bool remove_sid) { + int ret; const struct ldb_val *val; - struct GUID guid; - struct dom_sid *sid; const DATA_BLOB *guid_blob; const DATA_BLOB *sid_blob; - char *object_guid; - char *object_sid; - char *new_dn; - guid_blob = ldb_msg_find_ldb_val(msg, "objectGUID"); - sid_blob = ldb_msg_find_ldb_val(msg, "objectSID"); + guid_blob = ldb_msg_find_ldb_val(ares->message, "objectGUID"); + sid_blob = ldb_msg_find_ldb_val(ares->message, "objectSID"); if (!guid_blob) { return LDB_ERR_OPERATIONS_ERROR; } - switch (type) { - case 0: - /* return things in hexadecimal format */ - if (sid_blob) { - const char *lower_guid_hex = strlower_talloc(msg, data_blob_hex_string(msg, guid_blob)); - const char *lower_sid_hex = strlower_talloc(msg, data_blob_hex_string(msg, sid_blob)); - if (!lower_guid_hex || !lower_sid_hex) { - return LDB_ERR_OPERATIONS_ERROR; - } - new_dn = talloc_asprintf(msg, ";;%s", - lower_guid_hex, - lower_sid_hex, - ldb_dn_get_linearized(msg->dn)); - } else { - const char *lower_guid_hex = strlower_talloc(msg, data_blob_hex_string(msg, guid_blob)); - if (!lower_guid_hex) { - return LDB_ERR_OPERATIONS_ERROR; - } - new_dn = talloc_asprintf(msg, ";%s", - lower_guid_hex, - ldb_dn_get_linearized(msg->dn)); - } - - break; - case 1: - /* retrieve object_guid */ - guid = samdb_result_guid(msg, "objectGUID"); - object_guid = GUID_string(msg, &guid); - - /* retrieve object_sid */ - object_sid = NULL; - sid = samdb_result_dom_sid(msg, msg, "objectSID"); - if (sid) { - object_sid = dom_sid_string(msg, sid); - if (!object_sid) - return LDB_ERR_OPERATIONS_ERROR; - - } - - /* Normal, sane format */ - if (object_sid) { - new_dn = talloc_asprintf(msg, ";;%s", - object_guid, object_sid, - ldb_dn_get_linearized(msg->dn)); - } else { - new_dn = talloc_asprintf(msg, ";%s", - object_guid, - ldb_dn_get_linearized(msg->dn)); - } - break; - default: - return LDB_ERR_OPERATIONS_ERROR; + ret = ldb_dn_set_extended_component(ares->message->dn, "GUID", guid_blob); + if (ret != LDB_SUCCESS) { + return ret; } - - if (!new_dn) { - return LDB_ERR_OPERATIONS_ERROR; + if (sid_blob) { + ret = ldb_dn_set_extended_component(ares->message->dn, "SID", sid_blob); + if (ret != LDB_SUCCESS) { + return ret; + } } if (remove_guid) { - ldb_msg_remove_attr(msg, "objectGUID"); + ldb_msg_remove_attr(ares->message, "objectGUID"); } if (sid_blob && remove_sid) { - ldb_msg_remove_attr(msg, "objectSID"); + ldb_msg_remove_attr(ares->message, "objectSID"); } - msg->dn = ldb_dn_new(msg, ldb, new_dn); - if (! ldb_dn_validate(msg->dn)) - return LDB_ERR_OPERATIONS_ERROR; - - val = ldb_msg_find_ldb_val(msg, "distinguishedName"); + val = ldb_msg_find_ldb_val(ares->message, "distinguishedName"); if (val) { - ldb_msg_remove_attr(msg, "distinguishedName"); - if (ldb_msg_add_steal_string(msg, "distinguishedName", new_dn)) + ldb_msg_remove_attr(ares->message, "distinguishedName"); + ret = ldb_msg_add_steal_string(ares->message, "distinguishedName", + ldb_dn_extended_linearized(ares->message, ares->message->dn, type)); + if (ret != LDB_SUCCESS) { return LDB_ERR_OPERATIONS_ERROR; + } } - return LDB_SUCCESS; } /* search */ -struct extended_context { - +struct extended_search_context { struct ldb_module *module; + const struct dsdb_schema *schema; struct ldb_request *req; struct ldb_control *control; struct ldb_dn *basedn; @@ -214,10 +199,11 @@ struct extended_context { static int extended_callback(struct ldb_request *req, struct ldb_reply *ares) { - struct extended_context *ac; - int ret; + struct extended_search_context *ac; + int ret, i, j; + struct ldb_message *msg = ares->message; - ac = talloc_get_type(req->context, struct extended_context); + ac = talloc_get_type(req->context, struct extended_search_context); if (!ares) { return ldb_module_done(ac->req, NULL, NULL, @@ -229,34 +215,62 @@ static int extended_callback(struct ldb_request *req, struct ldb_reply *ares) } switch (ares->type) { - case LDB_REPLY_ENTRY: - if (ac->inject) { - /* for each record returned post-process to add any derived - attributes that have been asked for */ - ret = inject_extended_dn(ares->message, ac->module->ldb, - ac->extended_type, ac->remove_guid, - ac->remove_sid); - if (ret != LDB_SUCCESS) { - return ldb_module_done(ac->req, NULL, NULL, ret); - } - } - - return ldb_module_send_entry(ac->req, ares->message); - case LDB_REPLY_REFERRAL: return ldb_module_send_referral(ac->req, ares->referral); case LDB_REPLY_DONE: return ldb_module_done(ac->req, ares->controls, ares->response, LDB_SUCCESS); + case LDB_REPLY_ENTRY: + break; + } + if (ac->inject) { + /* for each record returned post-process to add any derived + attributes that have been asked for */ + ret = inject_extended_dn(ares, ac->module->ldb, + ac->extended_type, ac->remove_guid, + ac->remove_sid); + if (ret != LDB_SUCCESS) { + return ldb_module_done(ac->req, NULL, NULL, ret); + } } - return LDB_SUCCESS; + + for (i = 0; i < msg->num_elements; i++) { + const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(ac->schema, msg->elements[i].name); + if (!attribute) { + continue; + } + /* Look to see if this attributeSyntax is a DN */ + if (!((strcmp(attribute->attributeSyntax_oid, "2.5.5.1") == 0) || + (strcmp(attribute->attributeSyntax_oid, "2.5.5.7") == 0))) { + continue; + } + for (j = 0; j < msg->elements[i].num_values; j++) { + const char *dn_str; + struct ldb_dn *dn = ldb_dn_from_ldb_val(ac, ac->module->ldb, &msg->elements[i].values[j]); + if (!dn) { + return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR); + } + + if (!ac->inject) { + dn_str = talloc_steal(msg->elements[i].values, + ldb_dn_get_linearized(dn)); + } else { + dn_str = talloc_steal(msg->elements[i].values, + ldb_dn_extended_linearized(msg->elements[i].values, + dn, ac->extended_type)); + } + msg->elements[i].values[j] = data_blob_string_const(dn_str); + talloc_free(dn); + } + } + return ldb_module_send_entry(ac->req, msg); } static int extended_base_callback(struct ldb_request *req, struct ldb_reply *ares) { - struct extended_context *ac; + struct extended_search_context *ac; struct ldb_request *down_req; struct ldb_control **saved_controls; struct ldb_message_element *el; @@ -266,7 +280,7 @@ static int extended_base_callback(struct ldb_request *req, struct ldb_reply *are char *valstr = NULL; const char *found = NULL; - ac = talloc_get_type(req->context, struct extended_context); + ac = talloc_get_type(req->context, struct extended_search_context); if (!ares) { return ldb_module_done(ac->req, NULL, NULL, @@ -367,12 +381,12 @@ static int extended_base_callback(struct ldb_request *req, struct ldb_reply *are return LDB_SUCCESS; } -static int extended_search(struct ldb_module *module, struct ldb_request *req) +static int extended_dn_search(struct ldb_module *module, struct ldb_request *req) { struct ldb_control *control; struct ldb_extended_dn_control *extended_ctrl = NULL; struct ldb_control **saved_controls; - struct extended_context *ac; + struct extended_search_context *ac; struct ldb_request *down_req; char **new_attrs; int ret; @@ -390,114 +404,48 @@ static int extended_search(struct ldb_module *module, struct ldb_request *req) NULL }; - if (ldb_dn_is_special(req->op.search.base)) { - char *dn; - - dn = ldb_dn_alloc_linearized(req, req->op.search.base); - if (!dn) { - ldb_oom(module->ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - - if (strncasecmp(dn, "op.search.base)) { + const struct ldb_val *sid_val, *guid_val, *wkguid_val; + struct ldb_dn *dn = req->op.search.base; - str = p; - - p = strchr(str, '>'); - if (!p) { - return LDB_ERR_INVALID_DN_SYNTAX; - } - p[0] = '\0'; - - if (strncasecmp(str, "S-", 2) == 0) { - valstr = str; - } else { - DATA_BLOB binary; - binary = strhex_to_data_blob(NULL, str); - if (!binary.data) { - ldb_oom(module->ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - valstr = ldb_binary_encode(req, binary); - data_blob_free(&binary); - if (!valstr) { - ldb_oom(module->ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - } + sid_val = ldb_dn_get_extended_component(dn, "SID"); + guid_val = ldb_dn_get_extended_component(dn, "GUID"); + wkguid_val = ldb_dn_get_extended_component(dn, "WKGUID"); + if (sid_val) { /* TODO: do a search over all partitions */ base_dn = ldb_get_default_basedn(module->ldb); - base_dn_filter = talloc_asprintf(req, "(objectSid=%s)", valstr); + base_dn_filter = talloc_asprintf(req, "(objectSid=%s)", + ldb_binary_encode(req, *sid_val)); if (!base_dn_filter) { ldb_oom(module->ldb); return LDB_ERR_OPERATIONS_ERROR; } base_dn_scope = LDB_SCOPE_SUBTREE; base_dn_attrs = dnattr; - } else if (strncasecmp(dn, "'); - if (!p) { - return LDB_ERR_INVALID_DN_SYNTAX; - } - p[0] = '\0'; - if (strchr(str, '-')) { - valstr = str; - } else { - DATA_BLOB binary; - binary = strhex_to_data_blob(NULL, str); - if (!binary.data) { - ldb_oom(module->ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - valstr = ldb_binary_encode(req, binary); - data_blob_free(&binary); - if (!valstr) { - ldb_oom(module->ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - } + } else if (guid_val) { /* TODO: do a search over all partitions */ base_dn = ldb_get_default_basedn(module->ldb); - base_dn_filter = talloc_asprintf(req, "(objectGUID=%s)", valstr); + base_dn_filter = talloc_asprintf(req, "(objectGUID=%s)", + ldb_binary_encode(req, *guid_val)); if (!base_dn_filter) { ldb_oom(module->ldb); return LDB_ERR_OPERATIONS_ERROR; } base_dn_scope = LDB_SCOPE_SUBTREE; base_dn_attrs = dnattr; - } else if (strncasecmp(dn, "data, wkguid_val->length); + + p = strchr(wkguid_dup, ','); if (!p) { return LDB_ERR_INVALID_DN_SYNTAX; } @@ -505,7 +453,7 @@ static int extended_search(struct ldb_module *module, struct ldb_request *req) p[0] = '\0'; p++; - wellknown_object = talloc_asprintf(req, "B:32:%s:", &dn[8]); + wellknown_object = talloc_asprintf(req, "B:32:%s:", wkguid_dup); if (!wellknown_object) { ldb_oom(module->ldb); return LDB_ERR_OPERATIONS_ERROR; @@ -519,6 +467,7 @@ static int extended_search(struct ldb_module *module, struct ldb_request *req) p[0] = '\0'; base_dn = ldb_dn_new(req, module->ldb, tail_str); + talloc_free(wkguid_dup); if (!base_dn) { ldb_oom(module->ldb); return LDB_ERR_OPERATIONS_ERROR; @@ -531,16 +480,10 @@ static int extended_search(struct ldb_module *module, struct ldb_request *req) base_dn_scope = LDB_SCOPE_BASE; base_dn_attrs = wkattr; } - talloc_free(dn); } /* check if there's an extended dn control */ control = ldb_request_get_control(req, LDB_CONTROL_EXTENDED_DN_OID); - if (control == NULL && base_dn_filter == NULL) { - /* not found go on */ - return ldb_next_request(module, req); - } - if (control && control->data) { extended_ctrl = talloc_get_type(control->data, struct ldb_extended_dn_control); if (!extended_ctrl) { @@ -548,13 +491,14 @@ static int extended_search(struct ldb_module *module, struct ldb_request *req) } } - ac = talloc_zero(req, struct extended_context); + ac = talloc_zero(req, struct extended_search_context); if (ac == NULL) { ldb_oom(module->ldb); return LDB_ERR_OPERATIONS_ERROR; } ac->module = module; + ac->schema = dsdb_get_schema(module->ldb); ac->req = req; ac->control = control; ac->basedn = NULL; @@ -563,6 +507,12 @@ static int extended_search(struct ldb_module *module, struct ldb_request *req) ac->remove_guid = false; ac->remove_sid = false; + if (!ac->schema) { + /* no schema yet? go on */ + talloc_free(ac); + return ldb_next_request(module, req); + } + if (control) { ac->inject = true; if (extended_ctrl) { @@ -601,6 +551,8 @@ static int extended_search(struct ldb_module *module, struct ldb_request *req) } } + /* If the base DN was an extended DN (perhaps a well known + * GUID) then re-create the search */ if (base_dn) { ret = ldb_build_search_req(&down_req, module->ldb, ac, @@ -645,7 +597,270 @@ static int extended_search(struct ldb_module *module, struct ldb_request *req) return ldb_next_request(module, down_req); } -static int extended_init(struct ldb_module *module) +static int extended_replace_dn(struct ldb_request *req, struct ldb_reply *ares) +{ + struct extended_dn_replace_list *os = talloc_get_type(req->context, + struct extended_dn_replace_list); + + if (!ares) { + return ldb_module_done(os->ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + if (ares->error != LDB_SUCCESS) { + return ldb_module_done(os->ac->req, ares->controls, + ares->response, ares->error); + } + + /* Only entries are interesting, and we only want the olddn */ + switch (ares->type) { + case LDB_REPLY_ENTRY: + { + const struct ldb_val *sid = ldb_msg_find_ldb_val(ares->message, "objectSid"); + const struct ldb_val *guid = ldb_msg_find_ldb_val(ares->message, "objectGUID"); + struct ldb_dn *dn = ares->message->dn; + int ret = ldb_dn_compare(dn, req->op.search.base); + if (ret != 0) { + /* Guh? We only asked for this DN */ + talloc_free(ares); + return ldb_module_done(os->ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + + ret = ldb_dn_set_extended_component(dn, "GUID", guid); + if (ret != LDB_SUCCESS) { + return ret; + } + if (sid) { + ret = ldb_dn_set_extended_component(dn, "SID", sid); + if (ret != LDB_SUCCESS) { + return ret; + } + } + + *os->replace_dn = data_blob_string_const( + ldb_dn_extended_linearized(os->mem_ctx, + dn, 1)); + if (os->replace_dn->data != NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + } + case LDB_REPLY_REFERRAL: + /* ignore */ + break; + + case LDB_REPLY_DONE: + + talloc_free(ares); + + /* Run the next search */ + + if (os->next) { + struct extended_dn_replace_list *next; + + next = os->next; + + talloc_free(os); + + os = next; + return ldb_next_request(os->ac->module, next->search_req); + } else { + /* Otherwise, we are done - let's run the + * request now we have swapped the DNs for the + * full versions */ + return ldb_next_request(os->ac->module, os->ac->req); + } + } + + talloc_free(ares); + return LDB_SUCCESS; +} + +/* We have a 'normal' DN in the inbound request. We need to find out + * what the GUID and SID are on the DN it points to, so we can + * construct an extended DN for storage. + * + * This creates a list of DNs to look up, and the plain DN to replace + */ + +static int extended_store_replace(struct extended_dn_context *ac, + TALLOC_CTX *callback_mem_ctx, + struct ldb_val *plain_dn) +{ + int ret; + struct extended_dn_replace_list *os; + static const char *attrs[] = { + "objectSid", + "objectGUID", + NULL + }; + + struct ldb_dn *dn = ldb_dn_from_ldb_val(ac, ac->module->ldb, plain_dn); + if (!dn || !ldb_dn_validate(dn)) { + ldb_asprintf_errstring(ac->module->ldb, + "could not parse %.*s as a DN", (int)plain_dn->length, plain_dn->data); + return LDB_ERR_INVALID_DN_SYNTAX; + } + + os = talloc_zero(ac, struct extended_dn_replace_list); + if (!os) { + return LDB_ERR_OPERATIONS_ERROR; + } + + os->ac = ac; + + os->mem_ctx = callback_mem_ctx; + + os->dn = talloc_steal(os, dn); + + os->replace_dn = plain_dn; + + if (!os->dn) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_build_search_req(&os->search_req, + ac->module->ldb, ac->ops, dn, LDB_SCOPE_BASE, NULL, + attrs, NULL, os, extended_replace_dn, + ac->req); + + if (ac->ops) { + ac->cur->next = os; + } else { + ac->ops = os; + } + ac->cur = os; + + return LDB_SUCCESS; +} + + +/* add */ +static int extended_dn_add(struct ldb_module *module, struct ldb_request *req) +{ + struct extended_dn_context *ac; + int ret; + int i, j; + + if (ldb_dn_is_special(req->op.add.message->dn)) { + /* do not manipulate our control entries */ + return ldb_next_request(module, req); + } + + ac = extended_dn_context_init(module, req); + if (!ac) { + return LDB_ERR_OPERATIONS_ERROR; + } + + if (!ac->schema) { + /* without schema, this doesn't make any sense */ + talloc_free(ac); + return ldb_next_request(module, req); + } + + for (i=0; i < req->op.add.message->num_elements; i++) { + const struct ldb_message_element *el = &req->op.add.message->elements[i]; + const struct dsdb_attribute *schema_attr + = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name); + if (!schema_attr) { + ldb_asprintf_errstring(module->ldb, + "attribute %s is not a valid attribute in schema", el->name); + return LDB_ERR_OBJECT_CLASS_VIOLATION; + } + + /* We only setup an extended DN GUID on these particular DN objects */ + if (!((strcmp(schema_attr->attributeSyntax_oid, "2.5.5.1") == 0) || + (strcmp(schema_attr->attributeSyntax_oid, "2.5.5.7") == 0))) { + continue; + } + + for (j = 0; j < el->num_values; j++) { + ret = extended_store_replace(ac, req->op.add.message->elements, &el->values[j]); + if (ret != LDB_SUCCESS) { + return ret; + } + } + } + + /* if DNs were set continue */ + if (ac->ops == NULL) { + talloc_free(ac); + return ldb_next_request(module, req); + } + + /* start with the searches */ + return ldb_next_request(module, ac->ops->search_req); +} + +/* modify */ +static int extended_dn_modify(struct ldb_module *module, struct ldb_request *req) +{ + /* Look over list of modifications */ + /* Find if any are for linked attributes */ + /* Determine the effect of the modification */ + /* Apply the modify to the linked entry */ + + int i, j; + struct extended_dn_context *ac; + int ret; + + if (ldb_dn_is_special(req->op.mod.message->dn)) { + /* do not manipulate our control entries */ + return ldb_next_request(module, req); + } + + ac = extended_dn_context_init(module, req); + if (!ac) { + return LDB_ERR_OPERATIONS_ERROR; + } + + if (!ac->schema) { + /* without schema, this doesn't make any sense */ + return ldb_next_request(module, req); + } + + for (i=0; i < req->op.mod.message->num_elements; i++) { + const struct ldb_message_element *el = &req->op.mod.message->elements[i]; + const struct dsdb_attribute *schema_attr + = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name); + if (!schema_attr) { + ldb_asprintf_errstring(module->ldb, + "attribute %s is not a valid attribute in schema", el->name); + return LDB_ERR_OBJECT_CLASS_VIOLATION; + } + + /* We only setup an extended DN GUID on these particular DN objects */ + if (strcmp(schema_attr->attributeSyntax_oid, LDB_SYNTAX_DN) != 0 && + strcmp(schema_attr->attributeSyntax_oid, "1.2.840.113556.1.4.903") != 0) { + continue; + } + + switch (el->flags & LDB_FLAG_MOD_MASK) { + case LDB_FLAG_MOD_REPLACE: + case LDB_FLAG_MOD_ADD: + + /* For each value being added, we need to setup the lookups to fill in the extended DN */ + for (j = 0; j < el->num_values; j++) { + struct ldb_dn *dn = ldb_dn_from_ldb_val(ac, module->ldb, &el->values[j]); + if (!dn || !ldb_dn_validate(dn)) { + ldb_asprintf_errstring(module->ldb, + "could not parse attribute %s as a DN", el->name); + return LDB_ERR_INVALID_DN_SYNTAX; + } + + ret = extended_store_replace(ac, req->op.mod.message->elements, &el->values[j]); + if (ret != LDB_SUCCESS) { + return ret; + } + } + break; + } + } + + + return ret; +} + +static int extended_dn_init(struct ldb_module *module) { int ret; @@ -661,6 +876,8 @@ static int extended_init(struct ldb_module *module) _PUBLIC_ const struct ldb_module_ops ldb_extended_dn_module_ops = { .name = "extended_dn", - .search = extended_search, - .init_context = extended_init + .search = extended_dn_search, + .init_context = extended_dn_init, + .add = extended_dn_add, + .modify = extended_dn_modify, }; diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 823d5e6ff67..87b26126a4e 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -459,7 +459,6 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, "ranged_results", "anr", "server_sort", - "extended_dn", "asq", "rdn_name", "objectclass", @@ -471,8 +470,9 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, "subtree_rename", "subtree_delete", "linked_attributes"] - modules_list2 = ["show_deleted", - "partition"] + modules_list2 = ["extended_dn", + "show_deleted", + "partition"] domaindn_ldb = "users.ldb" if ldap_backend is not None: -- 2.34.1