From 7fbd18a9dd0fb07aceffd2494de8fc9710a427ce Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sat, 19 Sep 2009 07:01:26 +0200 Subject: dsdb/samdb: add resolve_oids module 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 | 11 + source4/dsdb/samdb/ldb_modules/resolve_oids.c | 427 ++++++++++++++++++++++++++ 2 files changed, 438 insertions(+) create mode 100644 source4/dsdb/samdb/ldb_modules/resolve_oids.c diff --git a/source4/dsdb/samdb/ldb_modules/config.mk b/source4/dsdb/samdb/ldb_modules/config.mk index f868f8a9db..9384d062a4 100644 --- a/source4/dsdb/samdb/ldb_modules/config.mk +++ b/source4/dsdb/samdb/ldb_modules/config.mk @@ -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 index 0000000000..f4d9eba17a --- /dev/null +++ b/source4/dsdb/samdb/ldb_modules/resolve_oids.c @@ -0,0 +1,427 @@ +/* + ldb database library + + Copyright (C) Stefan Metzmacher 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 . +*/ + +#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;iu.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, +}; + -- cgit