#include "librpc/gen_ndr/ndr_misc.h"
#include "librpc/gen_ndr/ndr_drsuapi.h"
#include "librpc/gen_ndr/ndr_drsblobs.h"
-#include "lib/util/dlinklist.h"
+#include "../lib/util/dlinklist.h"
+#include "param/param.h"
+
+static int generate_objectClasses(struct ldb_context *ldb, struct ldb_message *msg,
+ const struct dsdb_schema *schema);
+static int generate_attributeTypes(struct ldb_context *ldb, struct ldb_message *msg,
+ const struct dsdb_schema *schema);
+static int generate_dITContentRules(struct ldb_context *ldb, struct ldb_message *msg,
+ const struct dsdb_schema *schema);
+static int generate_extendedAttributeInfo(struct ldb_context *ldb, struct ldb_message *msg,
+ const struct dsdb_schema *schema);
+static int generate_extendedClassInfo(struct ldb_context *ldb, struct ldb_message *msg,
+ const struct dsdb_schema *schema);
+
+static const struct {
+ const char *attr;
+ int (*fn)(struct ldb_context *, struct ldb_message *, const struct dsdb_schema *);
+} generated_attrs[] = {
+ {
+ .attr = "objectClasses",
+ .fn = generate_objectClasses
+ },
+ {
+ .attr = "attributeTypes",
+ .fn = generate_attributeTypes
+ },
+ {
+ .attr = "dITContentRules",
+ .fn = generate_dITContentRules
+ },
+ {
+ .attr = "extendedAttributeInfo",
+ .fn = generate_extendedAttributeInfo
+ },
+ {
+ .attr = "extendedClassInfo",
+ .fn = generate_extendedClassInfo
+ }
+};
+
+struct schema_fsmo_private_data {
+ struct ldb_dn *aggregate_dn;
+};
+
+struct schema_fsmo_search_data {
+ struct ldb_module *module;
+ struct ldb_request *req;
+
+ const struct dsdb_schema *schema;
+};
static int schema_fsmo_init(struct ldb_module *module)
{
- WERROR status;
TALLOC_CTX *mem_ctx;
struct ldb_dn *schema_dn;
struct dsdb_schema *schema;
- struct dsdb_schema_fsmo *schema_fsmo;
- struct ldb_result *schema_res;
- const struct ldb_val *prefix_val;
- const struct ldb_val *info_val;
- struct ldb_val info_val_default;
- struct ldb_result *a_res;
- struct ldb_result *c_res;
- uint32_t i;
+ char *error_string = NULL;
int ret;
- static const char *schema_attrs[] = {
- "prefixMap",
- "schemaInfo",
- "fSMORoleOwner",
- NULL
- };
-
- if (dsdb_get_schema(module->ldb)) {
- return ldb_next_init(module);
- }
+ struct schema_fsmo_private_data *data;
schema_dn = samdb_schema_dn(module->ldb);
if (!schema_dn) {
return ldb_next_init(module);
}
- mem_ctx = talloc_new(module);
- if (!mem_ctx) {
+ data = talloc(module, struct schema_fsmo_private_data);
+ if (data == NULL) {
ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
- schema_fsmo = talloc_zero(mem_ctx, struct dsdb_schema_fsmo);
- if (!schema_fsmo) {
+ /* Check to see if this is a result on the CN=Aggregate schema */
+ data->aggregate_dn = ldb_dn_copy(data, schema_dn);
+ if (!ldb_dn_add_child_fmt(data->aggregate_dn, "CN=Aggregate")) {
ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
- module->private_data = schema_fsmo;
- schema = talloc_zero(mem_ctx, struct dsdb_schema);
- if (!schema) {
+ module->private_data = data;
+
+ if (dsdb_get_schema(module->ldb)) {
+ return ldb_next_init(module);
+ }
+
+ mem_ctx = talloc_new(module);
+ if (!mem_ctx) {
ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
- /*
- * setup the prefix mappings and schema info
- */
- ret = ldb_search(module->ldb, schema_dn,
- LDB_SCOPE_BASE,
- NULL, schema_attrs,
- &schema_res);
+ ret = dsdb_schema_from_schema_dn(mem_ctx, module->ldb,
+ lp_iconv_convenience(ldb_get_opaque(module->ldb, "loadparm")),
+ schema_dn, &schema, &error_string);
+
if (ret == LDB_ERR_NO_SUCH_OBJECT) {
ldb_reset_err_string(module->ldb);
ldb_debug(module->ldb, LDB_DEBUG_WARNING,
"schema_fsmo_init: no schema head present: (skip schema loading)\n");
talloc_free(mem_ctx);
return ldb_next_init(module);
- } else if (ret != LDB_SUCCESS) {
+ }
+
+ if (ret != LDB_SUCCESS) {
ldb_asprintf_errstring(module->ldb,
- "schema_fsmo_init: failed to search the schema head: %s",
- ldb_errstring(module->ldb));
+ "schema_fsmo_init: dsdb_schema load failed: %s",
+ error_string);
talloc_free(mem_ctx);
return ret;
}
- talloc_steal(mem_ctx, schema_res);
- if (schema_res->count == 0) {
- ldb_debug(module->ldb, LDB_DEBUG_WARNING,
- "schema_fsmo_init: no schema head present: (skip schema loading)\n");
- talloc_free(mem_ctx);
- return ldb_next_init(module);
- } else if (schema_res->count > 1) {
+
+ /* dsdb_set_schema() steal schema into the ldb_context */
+ ret = dsdb_set_schema(module->ldb, schema);
+ if (ret != LDB_SUCCESS) {
ldb_debug_set(module->ldb, LDB_DEBUG_FATAL,
- "schema_fsmo_init: [%u] schema heads found on a base search",
- schema_res->count);
+ "schema_fsmo_init: dsdb_set_schema() failed: %d:%s",
+ ret, ldb_strerror(ret));
talloc_free(mem_ctx);
- return LDB_ERR_CONSTRAINT_VIOLATION;
+ return ret;
}
- prefix_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "prefixMap");
- if (!prefix_val) {
- ldb_debug_set(module->ldb, LDB_DEBUG_FATAL,
- "schema_fsmo_init: no prefixMap attribute found");
- talloc_free(mem_ctx);
- return LDB_ERR_CONSTRAINT_VIOLATION;
+ talloc_free(mem_ctx);
+ return ldb_next_init(module);
+}
+
+static int schema_fsmo_add(struct ldb_module *module, struct ldb_request *req)
+{
+ struct dsdb_schema *schema;
+ const char *attributeID = NULL;
+ const char *governsID = NULL;
+ const char *oid_attr = NULL;
+ const char *oid = NULL;
+ uint32_t id32;
+ WERROR status;
+
+ /* special objects should always go through */
+ if (ldb_dn_is_special(req->op.add.message->dn)) {
+ return ldb_next_request(module, req);
}
- info_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "schemaInfo");
- if (!info_val) {
- info_val_default = strhex_to_data_blob("FF0000000000000000000000000000000000000000");
- if (!info_val_default.data) {
- ldb_oom(module->ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- talloc_steal(mem_ctx, info_val_default.data);
- info_val = &info_val_default;
+
+ /* replicated update should always go through */
+ if (ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
+ return ldb_next_request(module, req);
}
- status = dsdb_load_oid_mappings_ldb(schema, prefix_val, info_val);
+ schema = dsdb_get_schema(module->ldb);
+ if (!schema) {
+ return ldb_next_request(module, req);
+ }
+
+ if (!schema->fsmo.we_are_master) {
+ ldb_debug_set(module->ldb, LDB_DEBUG_ERROR,
+ "schema_fsmo_add: we are not master: reject request\n");
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ attributeID = samdb_result_string(req->op.add.message, "attributeID", NULL);
+ governsID = samdb_result_string(req->op.add.message, "governsID", NULL);
+
+ if (attributeID) {
+ oid_attr = "attributeID";
+ oid = attributeID;
+ } else if (governsID) {
+ oid_attr = "governsID";
+ oid = governsID;
+ }
+
+ if (!oid) {
+ return ldb_next_request(module, req);
+ }
+
+ status = dsdb_map_oid2int(schema, oid, &id32);
+ if (W_ERROR_IS_OK(status)) {
+ return ldb_next_request(module, req);
+ } else if (!W_ERROR_EQUAL(WERR_DS_NO_MSDS_INTID, status)) {
+ ldb_debug_set(module->ldb, LDB_DEBUG_ERROR,
+ "schema_fsmo_add: failed to map %s[%s]: %s\n",
+ oid_attr, oid, win_errstr(status));
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ status = dsdb_create_prefix_mapping(module->ldb, schema, oid);
if (!W_ERROR_IS_OK(status)) {
- ldb_debug_set(module->ldb, LDB_DEBUG_FATAL,
- "schema_fsmo_init: failed to load oid mappings: %s",
- win_errstr(status));
+ ldb_debug_set(module->ldb, LDB_DEBUG_ERROR,
+ "schema_fsmo_add: failed to create prefix mapping for %s[%s]: %s\n",
+ oid_attr, oid, win_errstr(status));
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ return ldb_next_request(module, req);
+}
+
+static int schema_fsmo_extended(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_dn *schema_dn;
+ struct dsdb_schema *schema;
+ char *error_string = NULL;
+ int ret;
+ TALLOC_CTX *mem_ctx;
+
+ if (strcmp(req->op.extended.oid, DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID) != 0) {
+ return ldb_next_request(module, req);
+ }
+
+ schema_dn = samdb_schema_dn(module->ldb);
+ if (!schema_dn) {
+ ldb_reset_err_string(module->ldb);
+ ldb_debug(module->ldb, LDB_DEBUG_WARNING,
+ "schema_fsmo_extended: no schema dn present: (skip schema loading)\n");
+ return ldb_next_request(module, req);
+ }
+
+ mem_ctx = talloc_new(module);
+ if (!mem_ctx) {
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = dsdb_schema_from_schema_dn(mem_ctx, module->ldb,
+ lp_iconv_convenience(ldb_get_opaque(module->ldb, "loadparm")),
+ schema_dn, &schema, &error_string);
+
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ ldb_reset_err_string(module->ldb);
+ ldb_debug(module->ldb, LDB_DEBUG_WARNING,
+ "schema_fsmo_extended: no schema head present: (skip schema loading)\n");
talloc_free(mem_ctx);
- return LDB_ERR_CONSTRAINT_VIOLATION;
+ return ldb_next_request(module, req);
}
- /*
- * load the attribute definitions
- */
- ret = ldb_search(module->ldb, schema_dn,
- LDB_SCOPE_ONELEVEL,
- "(objectClass=attributeSchema)", NULL,
- &a_res);
if (ret != LDB_SUCCESS) {
ldb_asprintf_errstring(module->ldb,
- "schema_fsmo_init: failed to search attributeSchema objects: %s",
- ldb_errstring(module->ldb));
+ "schema_fsmo_extended: dsdb_schema load failed: %s",
+ error_string);
+ talloc_free(mem_ctx);
+ return ldb_next_request(module, req);
+ }
+
+ /* Replace the old schema*/
+ ret = dsdb_set_schema(module->ldb, schema);
+ if (ret != LDB_SUCCESS) {
+ ldb_debug_set(module->ldb, LDB_DEBUG_FATAL,
+ "schema_fsmo_extended: dsdb_set_schema() failed: %d:%s",
+ ret, ldb_strerror(ret));
talloc_free(mem_ctx);
return ret;
}
- talloc_steal(mem_ctx, a_res);
- for (i=0; i < a_res->count; i++) {
- struct dsdb_attribute *sa;
+ talloc_free(mem_ctx);
+ return LDB_SUCCESS;
+}
- sa = talloc_zero(schema, struct dsdb_attribute);
- if (!sa) {
- ldb_oom(module->ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
+static int generate_objectClasses(struct ldb_context *ldb, struct ldb_message *msg,
+ const struct dsdb_schema *schema)
+{
+ const struct dsdb_class *class;
+ int ret;
- status = dsdb_attribute_from_ldb(schema, a_res->msgs[i], sa, sa);
- if (!W_ERROR_IS_OK(status)) {
- ldb_debug_set(module->ldb, LDB_DEBUG_FATAL,
- "schema_fsmo_init: failed to load attriute definition: %s:%s",
- ldb_dn_get_linearized(a_res->msgs[i]->dn),
- win_errstr(status));
- talloc_free(mem_ctx);
- return LDB_ERR_CONSTRAINT_VIOLATION;
+ for (class = schema->classes; class; class = class->next) {
+ ret = ldb_msg_add_string(msg, "objectClasses", schema_class_to_description(msg, class));
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+ return LDB_SUCCESS;
+}
+static int generate_attributeTypes(struct ldb_context *ldb, struct ldb_message *msg,
+ const struct dsdb_schema *schema)
+{
+ const struct dsdb_attribute *attribute;
+ int ret;
+
+ for (attribute = schema->attributes; attribute; attribute = attribute->next) {
+ ret = ldb_msg_add_string(msg, "attributeTypes", schema_attribute_to_description(msg, attribute));
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
+ }
+ return LDB_SUCCESS;
+}
- DLIST_ADD_END(schema->attributes, sa, struct dsdb_attribute *);
+static int generate_dITContentRules(struct ldb_context *ldb, struct ldb_message *msg,
+ const struct dsdb_schema *schema)
+{
+ const struct dsdb_class *class;
+ int ret;
+
+ for (class = schema->classes; class; class = class->next) {
+ if (class->auxiliaryClass || class->systemAuxiliaryClass) {
+ char *ditcontentrule = schema_class_to_dITContentRule(msg, class, schema);
+ if (!ditcontentrule) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ret = ldb_msg_add_steal_string(msg, "dITContentRules", ditcontentrule);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
}
- talloc_free(a_res);
+ return LDB_SUCCESS;
+}
- /*
- * load the objectClass definitions
- */
- ret = ldb_search(module->ldb, schema_dn,
- LDB_SCOPE_ONELEVEL,
- "(objectClass=classSchema)", NULL,
- &c_res);
- if (ret != LDB_SUCCESS) {
- ldb_asprintf_errstring(module->ldb,
- "schema_fsmo_init: failed to search classSchema objects: %s",
- ldb_errstring(module->ldb));
- talloc_free(mem_ctx);
- return ret;
+static int generate_extendedAttributeInfo(struct ldb_context *ldb,
+ struct ldb_message *msg,
+ const struct dsdb_schema *schema)
+{
+ const struct dsdb_attribute *attribute;
+ int ret;
+
+ for (attribute = schema->attributes; attribute; attribute = attribute->next) {
+ char *val = schema_attribute_to_extendedInfo(msg, attribute);
+ if (!val) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_msg_add_string(msg, "extendedAttributeInfo", val);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
}
- talloc_steal(mem_ctx, c_res);
- for (i=0; i < c_res->count; i++) {
- struct dsdb_class *sc;
+ return LDB_SUCCESS;
+}
+
+static int generate_extendedClassInfo(struct ldb_context *ldb,
+ struct ldb_message *msg,
+ const struct dsdb_schema *schema)
+{
+ const struct dsdb_class *sclass;
+ int ret;
- sc = talloc_zero(schema, struct dsdb_class);
- if (!sc) {
- ldb_oom(module->ldb);
+ for (sclass = schema->classes; sclass; sclass = sclass->next) {
+ char *val = schema_class_to_extendedInfo(msg, sclass);
+ if (!val) {
+ ldb_oom(ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
- status = dsdb_class_from_ldb(schema, c_res->msgs[i], sc, sc);
- if (!W_ERROR_IS_OK(status)) {
- ldb_debug_set(module->ldb, LDB_DEBUG_FATAL,
- "schema_fsmo_init: failed to load class definition: %s:%s",
- ldb_dn_get_linearized(c_res->msgs[i]->dn),
- win_errstr(status));
- talloc_free(mem_ctx);
- return LDB_ERR_CONSTRAINT_VIOLATION;
+ ret = ldb_msg_add_string(msg, "extendedClassInfo", val);
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
+ }
- DLIST_ADD_END(schema->classes, sc, struct dsdb_class *);
+ return LDB_SUCCESS;
+}
+
+/* Add objectClasses, attributeTypes and dITContentRules from the
+ schema object (they are not stored in the database)
+ */
+static int schema_fsmo_search_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ struct schema_fsmo_search_data *ac;
+ struct schema_fsmo_private_data *mc;
+ int i, ret;
+
+ ac = talloc_get_type(req->context, struct schema_fsmo_search_data);
+ mc = talloc_get_type(ac->module->private_data, struct schema_fsmo_private_data);
+
+ 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);
}
- talloc_free(c_res);
+ /* Only entries are interesting, and we handle the case of the parent seperatly */
- /* dsdb_set_schema() steal schema into the ldb_context */
- ret = dsdb_set_schema(module->ldb, schema);
- if (ret != LDB_SUCCESS) {
- ldb_debug_set(module->ldb, LDB_DEBUG_FATAL,
- "schema_fsmo_init: dsdb_set_schema() failed: %d:%s",
- ret, ldb_strerror(ret));
- talloc_free(mem_ctx);
- return ret;
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+
+ if (ldb_dn_compare(ares->message->dn, mc->aggregate_dn) != 0) {
+ return ldb_module_send_entry(ac->req, ares->message);
+ }
+
+ for (i=0; i < ARRAY_SIZE(generated_attrs); i++) {
+ if (ldb_attr_in_list(ac->req->op.search.attrs, generated_attrs[i].attr)) {
+ ret = generated_attrs[i].fn(ac->module->ldb, ares->message, ac->schema);
+ if (ret != LDB_SUCCESS) {
+ return 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, ares->error);
}
- schema_fsmo->master_dn = ldb_msg_find_attr_as_dn(module->ldb, schema_fsmo, schema_res->msgs[0], "fSMORoleOwner");
- if (ldb_dn_compare(samdb_ntds_settings_dn(module->ldb), schema_fsmo->master_dn) == 0) {
- schema_fsmo->we_are_master = true;
- } else {
- schema_fsmo->we_are_master = false;
+ return LDB_SUCCESS;
+}
+
+/* search */
+static int schema_fsmo_search(struct ldb_module *module, struct ldb_request *req)
+{
+ int i, ret;
+ struct schema_fsmo_search_data *search_context;
+ struct ldb_request *down_req;
+ struct dsdb_schema *schema = dsdb_get_schema(module->ldb);
+
+ if (!schema || !module->private_data) {
+ /* If there is no schema, there is little we can do */
+ return ldb_next_request(module, req);
+ }
+ for (i=0; i < ARRAY_SIZE(generated_attrs); i++) {
+ if (ldb_attr_in_list(req->op.search.attrs, generated_attrs[i].attr)) {
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(generated_attrs)) {
+ /* No request for a generated attr found, nothing to
+ * see here, move along... */
+ return ldb_next_request(module, req);
}
- if (ldb_set_opaque(module->ldb, "dsdb_schema_fsmo", schema_fsmo) != LDB_SUCCESS) {
+ search_context = talloc(req, struct schema_fsmo_search_data);
+ if (!search_context) {
ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
- talloc_steal(module, schema_fsmo);
+ search_context->module = module;
+ search_context->req = req;
+ search_context->schema = schema;
- ldb_debug(module->ldb, LDB_DEBUG_TRACE,
- "schema_fsmo_init: we are master: %s\n",
- (schema_fsmo->we_are_master?"yes":"no"));
+ ret = ldb_build_search_req_ex(&down_req, module->ldb, search_context,
+ req->op.search.base,
+ req->op.search.scope,
+ req->op.search.tree,
+ req->op.search.attrs,
+ req->controls,
+ search_context, schema_fsmo_search_callback,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
- talloc_free(mem_ctx);
- return ldb_next_init(module);
+ return ldb_next_request(module, down_req);
}
+
_PUBLIC_ const struct ldb_module_ops ldb_schema_fsmo_module_ops = {
.name = "schema_fsmo",
- .init_context = schema_fsmo_init
+ .init_context = schema_fsmo_init,
+ .add = schema_fsmo_add,
+ .extended = schema_fsmo_extended,
+ .search = schema_fsmo_search
};