Cosmetic corrections for the DSDB module
[ira/wip.git] / source4 / dsdb / samdb / ldb_modules / schema_fsmo.c
index 8ceeba98048c3ac38771bf8a838a265a87367193..0266654811ffd511deb71d994447c6b11a13b3dc 100644 (file)
 #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 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
+       }
+};
+
+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) {
@@ -66,197 +85,351 @@ static int schema_fsmo_init(struct ldb_module *module)
                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 = dsdb_new_schema(mem_ctx, lp_iconv_convenience(ldb_get_opaque(module->ldb, "loadparm")));
-       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;
-       }
-       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;
+       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);
+       }
+
+       /* 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;
+}
+
+static int generate_dITContentRules(struct ldb_context *ldb, struct ldb_message *msg,
+                                   const struct dsdb_schema *schema) 
+{
+       const struct dsdb_class *class;
+       int ret;
 
-               DLIST_ADD_END(schema->attributes, sa, struct dsdb_attribute *);
+       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;
+
+
+/* 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_steal(mem_ctx, c_res);
+       /* Only entries are interesting, and we handle the case of the parent seperatly */
 
-       for (i=0; i < c_res->count; i++) {
-               struct dsdb_class *sc;
+       switch (ares->type) {
+       case LDB_REPLY_ENTRY:
 
-               sc = talloc_zero(schema, struct dsdb_class);
-               if (!sc) {
-                       ldb_oom(module->ldb);
-                       return LDB_ERR_OPERATIONS_ERROR;
+               if (ldb_dn_compare(ares->message->dn, mc->aggregate_dn) != 0) {
+                       return ldb_module_send_entry(ac->req, ares->message);
                }
 
-               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;
+               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;
+                               }
+                       }
                }
 
-               DLIST_ADD_END(schema->classes, sc, struct dsdb_class *);
-       }
-       talloc_free(c_res);
+               return ldb_module_send_entry(ac->req, ares->message);
 
-       /* 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;
+       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
 };