dsdb/samdb: add resolve_oids module
authorStefan Metzmacher <metze@samba.org>
Sat, 19 Sep 2009 05:01:26 +0000 (07:01 +0200)
committerStefan Metzmacher <metze@samba.org>
Sun, 20 Sep 2009 04:44:17 +0000 (06:44 +0200)
Windows Servers allow OID strings to be used instead of
attribute/class names.

For now we only resolve the OIDs in the search expressions,
the rest will follow.

metze

source4/dsdb/samdb/ldb_modules/config.mk
source4/dsdb/samdb/ldb_modules/resolve_oids.c [new file with mode: 0644]

index f868f8a9db9f568ff20d3f4ed10ae4dd230648b6..9384d062a4cde643ce59b3fbe59ed8c10228b1ee 100644 (file)
@@ -346,3 +346,14 @@ SUBSYSTEM = LIBLDB
 ################################################
 
 ldb_descriptor_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/descriptor.o
+
+################################################
+# Start MODULE ldb_resolve_oids
+[MODULE::ldb_resolve_oids]
+SUBSYSTEM = LIBLDB
+PRIVATE_DEPENDENCIES = SAMDB LIBTALLOC LIBEVENTS LIBNDR
+INIT_FUNCTION = LDB_MODULE(resolve_oids)
+# End MODULE ldb_resolve_oids
+################################################
+
+ldb_resolve_oids_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/resolve_oids.o
diff --git a/source4/dsdb/samdb/ldb_modules/resolve_oids.c b/source4/dsdb/samdb/ldb_modules/resolve_oids.c
new file mode 100644 (file)
index 0000000..f4d9eba
--- /dev/null
@@ -0,0 +1,427 @@
+/*
+   ldb database library
+
+   Copyright (C) Stefan Metzmacher <metze@samba.org> 2009
+
+   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/>.
+*/
+
+#include "includes.h"
+#include "ldb_module.h"
+#include "dsdb/samdb/samdb.h"
+
+static int resolve_oids_replace_value(struct ldb_context *ldb,
+                                     struct dsdb_schema *schema,
+                                     const struct dsdb_attribute *a,
+                                     struct ldb_val *valp)
+{
+       const struct dsdb_attribute *va = NULL;
+       const struct dsdb_class *vo = NULL;
+       const void *p2;
+       char *str = NULL;
+
+       if (a->syntax->oMSyntax != 6) {
+               return LDB_SUCCESS;
+       }
+
+       if (valp) {
+               p2 = memchr(valp->data, '.', valp->length);
+       } else {
+               p2 = NULL;
+       }
+
+       if (!p2) {
+               return LDB_SUCCESS;
+       }
+
+       switch (a->attributeID_id) {
+       case DRSUAPI_ATTRIBUTE_objectClass:
+       case DRSUAPI_ATTRIBUTE_subClassOf:
+       case DRSUAPI_ATTRIBUTE_auxiliaryClass:
+       case DRSUAPI_ATTRIBUTE_systemPossSuperiors:
+       case DRSUAPI_ATTRIBUTE_possSuperiors:
+               str = talloc_strndup(schema, (char *)valp->data, valp->length);
+               if (!str) {
+                       ldb_oom(ldb);
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+               vo = dsdb_class_by_governsID_oid(schema, str);
+               talloc_free(str);
+               if (!vo) {
+                       return LDB_SUCCESS;
+               }
+               *valp = data_blob_string_const(vo->lDAPDisplayName);
+               return LDB_SUCCESS;
+       case DRSUAPI_ATTRIBUTE_systemMustContain:
+       case DRSUAPI_ATTRIBUTE_systemMayContain:
+       case DRSUAPI_ATTRIBUTE_mustContain:
+       case DRSUAPI_ATTRIBUTE_mayContain:
+               str = talloc_strndup(schema, (char *)valp->data, valp->length);
+               if (!str) {
+                       ldb_oom(ldb);
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+               va = dsdb_attribute_by_attributeID_oid(schema, str);
+               talloc_free(str);
+               if (!va) {
+                       return LDB_SUCCESS;
+               }
+               *valp = data_blob_string_const(va->lDAPDisplayName);
+               return LDB_SUCCESS;
+       case DRSUAPI_ATTRIBUTE_governsID:
+       case DRSUAPI_ATTRIBUTE_attributeID:
+       case DRSUAPI_ATTRIBUTE_attributeSyntax:
+               return LDB_SUCCESS;
+       }
+
+       return LDB_SUCCESS;
+}
+
+static int resolve_oids_parse_tree_replace(struct ldb_context *ldb,
+                                          struct dsdb_schema *schema,
+                                          struct ldb_parse_tree *tree)
+{
+       int i;
+       const struct dsdb_attribute *a = NULL;
+       const char **attrp;
+       const char *p1;
+       const void *p2;
+       struct ldb_val *valp = NULL;
+
+       switch (tree->operation) {
+       case LDB_OP_AND:
+       case LDB_OP_OR:
+               for (i=0;i<tree->u.list.num_elements;i++) {
+                       resolve_oids_parse_tree_replace(ldb, schema,
+                                                       tree->u.list.elements[i]);
+               }
+               return LDB_SUCCESS;
+       case LDB_OP_NOT:
+               resolve_oids_parse_tree_replace(ldb, schema,
+                                               tree->u.isnot.child);
+               return LDB_SUCCESS;
+       case LDB_OP_EQUALITY:
+       case LDB_OP_GREATER:
+       case LDB_OP_LESS:
+       case LDB_OP_APPROX:
+               attrp = &tree->u.equality.attr;
+               valp = &tree->u.equality.value;
+               break;
+       case LDB_OP_SUBSTRING:
+               attrp = &tree->u.substring.attr;
+               break;
+       case LDB_OP_PRESENT:
+               attrp = &tree->u.present.attr;
+               break;
+       case LDB_OP_EXTENDED:
+               attrp = &tree->u.extended.attr;
+               valp = &tree->u.extended.value;
+               break;
+       default:
+               return LDB_SUCCESS;
+       }
+
+       p1 = strchr(*attrp, '.');
+
+       if (valp) {
+               p2 = memchr(valp->data, '.', valp->length);
+       } else {
+               p2 = NULL;
+       }
+
+       if (!p1 && !p2) {
+               return LDB_SUCCESS;
+       }
+
+       if (p1) {
+               a = dsdb_attribute_by_attributeID_oid(schema, *attrp);
+       } else {
+               a = dsdb_attribute_by_lDAPDisplayName(schema, *attrp);
+       }
+       if (!a) {
+               return LDB_SUCCESS;
+       }
+
+       *attrp = a->lDAPDisplayName;
+
+       if (!p2) {
+               return LDB_SUCCESS;
+       }
+
+       if (a->syntax->oMSyntax != 6) {
+               return LDB_SUCCESS;
+       }
+
+       return resolve_oids_replace_value(ldb, schema, a, valp);
+}
+
+static int resolve_oids_element_replace(struct ldb_context *ldb,
+                                       struct dsdb_schema *schema,
+                                       struct ldb_message_element *el)
+{
+       int i;
+       const struct dsdb_attribute *a = NULL;
+       const char *p1;
+
+       p1 = strchr(el->name, '.');
+
+       if (p1) {
+               a = dsdb_attribute_by_attributeID_oid(schema, el->name);
+       } else {
+               a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
+       }
+       if (!a) {
+               return LDB_SUCCESS;
+       }
+
+       el->name = a->lDAPDisplayName;
+
+       for (i=0; i < el->num_values; i++) {
+               int ret;
+               ret = resolve_oids_replace_value(ldb, schema, a,
+                                                &el->values[i]);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
+       }
+
+       return LDB_SUCCESS;
+}
+
+static int resolve_oids_message_replace(struct ldb_context *ldb,
+                                       struct dsdb_schema *schema,
+                                       struct ldb_message *msg)
+{
+       int i;
+
+       for (i=0; i < msg->num_elements; i++) {
+               int ret;
+               ret = resolve_oids_element_replace(ldb, schema,
+                                                  &msg->elements[i]);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
+       }
+
+       return LDB_SUCCESS;
+}
+
+struct resolve_oids_context {
+       struct ldb_module *module;
+       struct ldb_request *req;
+};
+
+static int resolve_oids_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+       struct ldb_context *ldb;
+       struct resolve_oids_context *ac;
+
+       ac = talloc_get_type_abort(req->context, struct resolve_oids_context);
+       ldb = ldb_module_get_ctx(ac->module);
+
+       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:
+               return ldb_module_send_entry(ac->req, ares->message, ares->controls);
+
+       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);
+
+       }
+       return LDB_SUCCESS;
+}
+
+static int resolve_oids_search(struct ldb_module *module, struct ldb_request *req)
+{
+       struct ldb_context *ldb;
+       struct dsdb_schema *schema;
+       struct ldb_parse_tree *tree;
+       struct ldb_request *down_req;
+       struct resolve_oids_context *ac;
+       int ret;
+
+       ldb = ldb_module_get_ctx(module);
+       schema = dsdb_get_schema(ldb);
+
+       if (!schema) {
+               return ldb_next_request(module, req);
+       }
+
+       /* do not manipulate our control entries */
+       if (ldb_dn_is_special(req->op.search.base)) {
+               return ldb_next_request(module, req);
+       }
+
+       ac = talloc(req, struct resolve_oids_context);
+       if (ac == NULL) {
+               ldb_oom(ldb);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+       ac->module = module;
+       ac->req = req;
+
+       tree = ldb_parse_tree_copy_shallow(ac, req->op.search.tree);
+       if (!tree) {
+               ldb_oom(ldb);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       ret = resolve_oids_parse_tree_replace(ldb, schema,
+                                             tree);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       ret = ldb_build_search_req_ex(&down_req, ldb, ac,
+                                     req->op.search.base,
+                                     req->op.search.scope,
+                                     tree,
+                                     req->op.search.attrs,
+                                     req->controls,
+                                     ac, resolve_oids_callback,
+                                     req);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       /* go on with the call chain */
+       return ldb_next_request(module, down_req);
+}
+
+static int resolve_oids_add(struct ldb_module *module, struct ldb_request *req)
+{
+       struct ldb_context *ldb;
+       struct dsdb_schema *schema;
+       int ret;
+       struct ldb_message *msg;
+       struct ldb_request *down_req;
+       struct resolve_oids_context *ac;
+
+       ldb = ldb_module_get_ctx(module);
+       schema = dsdb_get_schema(ldb);
+
+       if (!schema) {
+               return ldb_next_request(module, req);
+       }
+
+       /* do not manipulate our control entries */
+       if (ldb_dn_is_special(req->op.add.message->dn)) {
+               return ldb_next_request(module, req);
+       }
+
+       ac = talloc(req, struct resolve_oids_context);
+       if (ac == NULL) {
+               ldb_oom(ldb);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+       ac->module = module;
+       ac->req = req;
+
+       msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
+       if (!msg) {
+               ldb_oom(ldb);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       ret = resolve_oids_message_replace(ldb, schema, msg);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       ret = ldb_build_add_req(&down_req, ldb, ac,
+                               msg,
+                               req->controls,
+                               ac, resolve_oids_callback,
+                               req);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       /* go on with the call chain */
+       return ldb_next_request(module, down_req);
+}
+
+static int resolve_oids_modify(struct ldb_module *module, struct ldb_request *req)
+{
+       struct ldb_context *ldb;
+       struct dsdb_schema *schema;
+       int ret;
+       struct ldb_message *msg;
+       struct ldb_request *down_req;
+       struct resolve_oids_context *ac;
+
+       ldb = ldb_module_get_ctx(module);
+       schema = dsdb_get_schema(ldb);
+
+       if (!schema) {
+               return ldb_next_request(module, req);
+       }
+
+       /* do not manipulate our control entries */
+       if (ldb_dn_is_special(req->op.mod.message->dn)) {
+               return ldb_next_request(module, req);
+       }
+
+       ac = talloc(req, struct resolve_oids_context);
+       if (ac == NULL) {
+               ldb_oom(ldb);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+       ac->module = module;
+       ac->req = req;
+
+       /* we have to copy the message as the caller might have it as a const */
+       msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
+       if (msg == NULL) {
+               ldb_oom(ldb);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       ret = resolve_oids_message_replace(ldb, schema, msg);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       ret = ldb_build_mod_req(&down_req, ldb, ac,
+                               msg,
+                               req->controls,
+                               ac, resolve_oids_callback,
+                               req);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       /* go on with the call chain */
+       return ldb_next_request(module, down_req);
+}
+
+_PUBLIC_ const struct ldb_module_ops ldb_resolve_oids_module_ops = {
+       .name           = "resolve_oids",
+       .search         = resolve_oids_search,
+       .add            = resolve_oids_add,
+       .modify         = resolve_oids_modify,
+};
+