summaryrefslogtreecommitdiff
path: root/source4/dsdb/samdb/ldb_modules/extended_dn_in.c
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2008-12-16 09:21:55 +0100
committerAndrew Bartlett <abartlet@samba.org>2008-12-17 12:29:28 +1100
commit1f28541a241d2dc4c5460344f817d56182a672ce (patch)
tree33dcbea037d3183dd87d3e9410061fbeb00e8a13 /source4/dsdb/samdb/ldb_modules/extended_dn_in.c
parent911cf5d62569e77e9f490f28e776b5b47c81e05b (diff)
downloadsamba-1f28541a241d2dc4c5460344f817d56182a672ce.tar.gz
samba-1f28541a241d2dc4c5460344f817d56182a672ce.tar.bz2
samba-1f28541a241d2dc4c5460344f817d56182a672ce.zip
s4:dsdb: split extended_dn into extended_dn_in, extended_dn_out and extended_dn_store.
By splitting the module, the extended_dn_in and extended_dn_store moudles can use extended_dn_out to actually get the extended DN. This avoids code duplication. The extended_dn_out module also contains a client implementation of the OpenLDAP dereference control (draft-masarati-ldap-deref-00). This also introduces a new control 'DSDB_CONTROL_DN_STORAGE_FORMAT_OID' to ask the extended_dn_out module to return whatever the 'storage format' is. This allows us to work with both OpenLDAP (which performs a dereference at run time) and LDB (which stores the GUID and SID on disk). Signed-off-by: Stefan Metzmacher <metze@samba.org>
Diffstat (limited to 'source4/dsdb/samdb/ldb_modules/extended_dn_in.c')
-rw-r--r--source4/dsdb/samdb/ldb_modules/extended_dn_in.c394
1 files changed, 394 insertions, 0 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/extended_dn_in.c b/source4/dsdb/samdb/ldb_modules/extended_dn_in.c
new file mode 100644
index 0000000000..c3db4fa588
--- /dev/null
+++ b/source4/dsdb/samdb/ldb_modules/extended_dn_in.c
@@ -0,0 +1,394 @@
+/*
+ ldb database library
+
+ Copyright (C) Simo Sorce 2005-2008
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007-2008
+
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb extended dn control module
+ *
+ * Description: this module interprets DNs of the form <SID=S-1-2-4456> into normal DNs.
+ *
+ * Authors: Simo Sorce
+ * Andrew Bartlett
+ */
+
+#include "includes.h"
+#include "ldb/include/ldb.h"
+#include "ldb/include/ldb_errors.h"
+#include "ldb/include/ldb_private.h"
+
+/* search */
+struct extended_search_context {
+ struct ldb_module *module;
+ struct ldb_request *req;
+ struct ldb_dn *basedn;
+ char *wellknown_object;
+ int extended_type;
+};
+
+/* An extra layer of indirection because LDB does not allow the original request to be altered */
+
+static int extended_final_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ int ret = LDB_ERR_OPERATIONS_ERROR;
+ struct extended_search_context *ac;
+ ac = talloc_get_type(req->context, struct extended_search_context);
+
+ if (ares->error != LDB_SUCCESS) {
+ ret = ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ } else {
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+
+ ret = ldb_module_send_entry(ac->req, ares->message, ares->controls);
+ break;
+ case LDB_REPLY_REFERRAL:
+
+ ret = ldb_module_send_referral(ac->req, ares->referral);
+ break;
+ case LDB_REPLY_DONE:
+
+ ret = ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ break;
+ }
+ }
+ return ret;
+}
+
+static int extended_base_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ struct extended_search_context *ac;
+ struct ldb_request *down_req;
+ struct ldb_message_element *el;
+ int ret;
+ size_t i;
+ size_t wkn_len = 0;
+ char *valstr = NULL;
+ const char *found = NULL;
+
+ ac = talloc_get_type(req->context, struct extended_search_context);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ if (!ac->wellknown_object) {
+ ac->basedn = talloc_steal(ac, ares->message->dn);
+ break;
+ }
+
+ wkn_len = strlen(ac->wellknown_object);
+
+ el = ldb_msg_find_element(ares->message, "wellKnownObjects");
+ if (!el) {
+ ac->basedn = NULL;
+ break;
+ }
+
+ for (i=0; i < el->num_values; i++) {
+ valstr = talloc_strndup(ac,
+ (const char *)el->values[i].data,
+ el->values[i].length);
+ if (!valstr) {
+ ldb_oom(ac->module->ldb);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ if (strncasecmp(valstr, ac->wellknown_object, wkn_len) != 0) {
+ talloc_free(valstr);
+ continue;
+ }
+
+ found = &valstr[wkn_len];
+ break;
+ }
+
+ if (!found) {
+ break;
+ }
+
+ ac->basedn = ldb_dn_new(ac, ac->module->ldb, found);
+ talloc_free(valstr);
+ if (!ac->basedn) {
+ ldb_oom(ac->module->ldb);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ break;
+
+ case LDB_REPLY_REFERRAL:
+ break;
+
+ case LDB_REPLY_DONE:
+
+ if (!ac->basedn) {
+ const char *str = talloc_asprintf(req, "Base-DN '%s' not found",
+ ldb_dn_get_linearized(ac->req->op.search.base));
+ ldb_set_errstring(ac->module->ldb, str);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_NO_SUCH_OBJECT);
+ }
+
+ switch (ac->req->operation) {
+ case LDB_SEARCH:
+ ret = ldb_build_search_req_ex(&down_req,
+ ac->module->ldb, ac->req,
+ ac->basedn,
+ ac->req->op.search.scope,
+ ac->req->op.search.tree,
+ ac->req->op.search.attrs,
+ ac->req->controls,
+ ac, extended_final_callback,
+ ac->req);
+ break;
+ case LDB_ADD:
+ {
+ struct ldb_message *add_msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
+ if (!add_msg) {
+ ldb_oom(ac->module->ldb);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ add_msg->dn = ac->basedn;
+
+ ret = ldb_build_add_req(&down_req,
+ ac->module->ldb, ac->req,
+ add_msg,
+ ac->req->controls,
+ ac, extended_final_callback,
+ ac->req);
+ break;
+ }
+ case LDB_MODIFY:
+ {
+ struct ldb_message *mod_msg = ldb_msg_copy_shallow(ac, ac->req->op.mod.message);
+ if (!mod_msg) {
+ ldb_oom(ac->module->ldb);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ mod_msg->dn = ac->basedn;
+
+ ret = ldb_build_mod_req(&down_req,
+ ac->module->ldb, ac->req,
+ mod_msg,
+ ac->req->controls,
+ ac, extended_final_callback,
+ ac->req);
+ break;
+ }
+ case LDB_DELETE:
+ ret = ldb_build_del_req(&down_req,
+ ac->module->ldb, ac->req,
+ ac->basedn,
+ ac->req->controls,
+ ac, extended_final_callback,
+ ac->req);
+ break;
+ case LDB_RENAME:
+ ret = ldb_build_rename_req(&down_req,
+ ac->module->ldb, ac->req,
+ ac->basedn,
+ ac->req->op.rename.newdn,
+ ac->req->controls,
+ ac, extended_final_callback,
+ ac->req);
+ break;
+ default:
+ return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
+
+ return ldb_next_request(ac->module, down_req);
+ }
+ talloc_free(ares);
+ return LDB_SUCCESS;
+}
+
+static int extended_dn_in_fix(struct ldb_module *module, struct ldb_request *req, struct ldb_dn *dn)
+{
+ struct extended_search_context *ac;
+ struct ldb_request *down_req;
+ int ret;
+ struct ldb_dn *base_dn = NULL;
+ enum ldb_scope base_dn_scope = LDB_SCOPE_BASE;
+ const char *base_dn_filter = NULL;
+ const char * const *base_dn_attrs = NULL;
+ char *wellknown_object = NULL;
+ static const char *no_attr[] = {
+ NULL
+ };
+ static const char *wkattr[] = {
+ "wellKnownObjects",
+ NULL
+ };
+
+ if (!ldb_dn_has_extended(dn)) {
+ /* Move along there isn't anything to see here */
+ return ldb_next_request(module, req);
+ } else {
+ /* It looks like we need to map the DN */
+ const struct ldb_val *sid_val, *guid_val, *wkguid_val;
+
+ 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)",
+ 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 = no_attr;
+
+ } 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)",
+ 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 = no_attr;
+
+
+ } else if (wkguid_val) {
+ char *wkguid_dup;
+ char *tail_str;
+ char *p;
+
+ wkguid_dup = talloc_strndup(req, (char *)wkguid_val->data, wkguid_val->length);
+
+ p = strchr(wkguid_dup, ',');
+ if (!p) {
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ p[0] = '\0';
+ p++;
+
+ wellknown_object = talloc_asprintf(req, "B:32:%s:", wkguid_dup);
+ if (!wellknown_object) {
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ tail_str = p;
+
+ 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;
+ }
+ base_dn_filter = talloc_strdup(req, "(objectClass=*)");
+ if (!base_dn_filter) {
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ base_dn_scope = LDB_SCOPE_BASE;
+ base_dn_attrs = wkattr;
+ } else {
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ ac = talloc_zero(req, struct extended_search_context);
+ if (ac == NULL) {
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac->module = module;
+ ac->req = req;
+ ac->basedn = NULL; /* Filled in if the search finds the DN by SID/GUID etc */
+ ac->wellknown_object = wellknown_object;
+
+ /* If the base DN was an extended DN (perhaps a well known
+ * GUID) then search for that, so we can proceed with the original operation */
+
+ ret = ldb_build_search_req(&down_req,
+ module->ldb, ac,
+ base_dn,
+ base_dn_scope,
+ base_dn_filter,
+ base_dn_attrs,
+ NULL,
+ ac, extended_base_callback,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* perform the search */
+ return ldb_next_request(module, down_req);
+ }
+}
+
+static int extended_dn_in_search(struct ldb_module *module, struct ldb_request *req)
+{
+ return extended_dn_in_fix(module, req, req->op.search.base);
+}
+
+static int extended_dn_in_modify(struct ldb_module *module, struct ldb_request *req)
+{
+ return extended_dn_in_fix(module, req, req->op.mod.message->dn);
+}
+
+static int extended_dn_in_del(struct ldb_module *module, struct ldb_request *req)
+{
+ return extended_dn_in_fix(module, req, req->op.del.dn);
+}
+
+static int extended_dn_in_rename(struct ldb_module *module, struct ldb_request *req)
+{
+ return extended_dn_in_fix(module, req, req->op.rename.olddn);
+}
+
+_PUBLIC_ const struct ldb_module_ops ldb_extended_dn_in_module_ops = {
+ .name = "extended_dn_in",
+ .search = extended_dn_in_search,
+ .modify = extended_dn_in_modify,
+ .del = extended_dn_in_del,
+ .rename = extended_dn_in_rename,
+};