dsdb: audit samdb and password changes
[sfrench/samba-autobuild/.git] / source4 / dsdb / samdb / ldb_modules / instancetype.c
index 4ed906f36213e256412d6967bbb9b09a960afee7..9a3fd1141fc056876fb1f00df8e564c295ca19a7 100644 (file)
 #include "../libds/common/flags.h"
 #include "dsdb/samdb/ldb_modules/util.h"
 
-struct it_context {
-       struct ldb_module *module;
-       struct ldb_request *req;
-       struct ldb_request *add_req;
-};
-
-static int it_add_callback(struct ldb_request *req, struct ldb_reply *ares)
-{
-       struct ldb_context *ldb;
-       struct it_context *ac;
-
-       ac = talloc_get_type(req->context, struct it_context);
-       ldb = ldb_module_get_ctx(ac->module);
-
-       if (!ares) {
-               return ldb_module_done(ac->req, NULL, NULL,
-                                       LDB_ERR_OPERATIONS_ERROR);
-       }
-
-       if (ares->type == LDB_REPLY_REFERRAL) {
-               return ldb_module_send_referral(ac->req, ares->referral);
-       }
-
-       if (ares->error != LDB_SUCCESS) {
-               return ldb_module_done(ac->req, ares->controls,
-                                       ares->response, ares->error);
-       }
-
-       if (ares->type != LDB_REPLY_DONE) {
-               ldb_set_errstring(ldb, "Invalid reply type!");
-               return ldb_module_done(ac->req, NULL, NULL,
-                                       LDB_ERR_OPERATIONS_ERROR);
-       }
-
-       /* Add the boilerplate entries */
-
-       return ldb_module_done(ac->req, ares->controls,
-                              ares->response, ares->error);
-}
-
 /* add_record: add instancetype attribute */
 static int instancetype_add(struct ldb_module *module, struct ldb_request *req)
 {
-       struct ldb_context *ldb;
+       struct ldb_context *ldb = ldb_module_get_ctx(module);
        struct ldb_request *down_req;
        struct ldb_message *msg;
-       struct it_context *ac;
-       uint32_t instance_type;
+       struct ldb_message_element *el;
+       uint32_t instanceType;
        int ret;
 
-       ldb = ldb_module_get_ctx(module);
-
-       ldb_debug(ldb, LDB_DEBUG_TRACE, "instancetype_add_record\n");
-
        /* do not manipulate our control entries */
        if (ldb_dn_is_special(req->op.add.message->dn)) {
                return ldb_next_request(module, req);
        }
 
-       if (ldb_msg_find_element(req->op.add.message, "instanceType")) {
-               unsigned int instanceType = ldb_msg_find_attr_as_uint(req->op.add.message, "instanceType", 0);
-               if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
-                       return ldb_next_request(module, req);           
-               }
+       ldb_debug(ldb, LDB_DEBUG_TRACE, "instancetype_add\n");
 
-               /* Forward the 'add' to the modules below, but if it
-                * succeeds, then we might need to add the boilerplate
-                * entries (lost+found, deleted objects) */
-               ac = talloc(req, struct it_context);
-               if (ac == NULL) {
-                       return LDB_ERR_OPERATIONS_ERROR;
+       el = ldb_msg_find_element(req->op.add.message, "instanceType");
+       if (el != NULL) {
+               if (el->num_values != 1) {
+                       ldb_set_errstring(ldb, "instancetype: the 'instanceType' attribute is single-valued!");
+                       return LDB_ERR_UNWILLING_TO_PERFORM;
                }
-               ac->module = module;
-               ac->req = req;
-               
-               ret = ldb_build_add_req(&ac->add_req, ldb_module_get_ctx(ac->module), ac,
-                                       ac->req->op.add.message,
-                                       ac->req->controls,
-                                       ac, it_add_callback,
-                                       ac->req);
-               
-               if (ret != LDB_SUCCESS) {
-                       return ret;
+
+               instanceType = ldb_msg_find_attr_as_uint(req->op.add.message,
+                                                        "instanceType", 0);
+               if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
+                       /*
+                        * If we have no NC add operation (no TYPE_IS_NC_HEAD)
+                        * then "instanceType" can only be "0" or "TYPE_WRITE".
+                        */
+                       if ((instanceType != 0) &&
+                           ((instanceType & INSTANCE_TYPE_WRITE) == 0)) {
+                               ldb_set_errstring(ldb, "instancetype: if TYPE_IS_NC_HEAD wasn't set, then only TYPE_WRITE or 0 are allowed!");
+                               return LDB_ERR_UNWILLING_TO_PERFORM;
+                       }
+               } else {
+                       /*
+                        * If we have a NC add operation then we need also the
+                        * "TYPE_WRITE" flag in order to succeed,
+                        * unless this NC is not instantiated
+                        */
+                       if (ldb_request_get_control(req, DSDB_CONTROL_PARTIAL_REPLICA)) {
+                               if (!(instanceType & INSTANCE_TYPE_UNINSTANT)) {
+                                       ldb_set_errstring(ldb, "instancetype: if TYPE_IS_NC_HEAD "
+                                                         "was set, and we are creating a new NC "
+                                                         "over DsAddEntry then also TYPE_UNINSTANT is requested!");
+                                       return LDB_ERR_UNWILLING_TO_PERFORM;
+                               }
+                       } else {
+                               if (!(instanceType & INSTANCE_TYPE_WRITE)) {
+                                       ldb_set_errstring(ldb, "instancetype: if TYPE_IS_NC_HEAD "
+                                                         "was set, then also TYPE_WRITE is requested!");
+                                       return LDB_ERR_UNWILLING_TO_PERFORM;
+                               }
+                       }
+
+                       /*
+                        * TODO: Confirm we are naming master or start
+                        * a remote call to the naming master to
+                        * create the crossRef object
+                        */
                }
-               
-               /* Do the original add */
-               return ldb_next_request(ac->module, ac->add_req);
+
+               /* we did only tests, so proceed with the original request */
+               return ldb_next_request(module, req);
        }
 
        /* we have to copy the message as the caller might have it as a const */
        msg = ldb_msg_copy_shallow(req, req->op.add.message);
        if (msg == NULL) {
-               ldb_oom(ldb);
-               return LDB_ERR_OPERATIONS_ERROR;
+               return ldb_oom(ldb);
        }
 
        /*
         * TODO: calculate correct instance type
         */
-       instance_type = INSTANCE_TYPE_WRITE;
+       instanceType = INSTANCE_TYPE_WRITE;
 
-       ret = ldb_msg_add_fmt(msg, "instanceType", "%u", instance_type);
+       ret = samdb_msg_add_uint(ldb, msg, msg, "instanceType", instanceType);
        if (ret != LDB_SUCCESS) {
-               ldb_oom(ldb);
-               return LDB_ERR_OPERATIONS_ERROR;
+               return ret;
        }
 
        ret = ldb_build_add_req(&down_req, ldb, req,
@@ -150,6 +127,7 @@ static int instancetype_add(struct ldb_module *module, struct ldb_request *req)
                                req->controls,
                                req, dsdb_next_callback,
                                req);
+       LDB_REQ_SET_LOCATION(down_req);
        if (ret != LDB_SUCCESS) {
                return ret;
        }
@@ -164,17 +142,32 @@ static int instancetype_mod(struct ldb_module *module, struct ldb_request *req)
        struct ldb_context *ldb = ldb_module_get_ctx(module);
        struct ldb_message_element *el;
 
+       /* do not manipulate our control entries */
+       if (ldb_dn_is_special(req->op.mod.message->dn)) {
+               return ldb_next_request(module, req);
+       }
+
+       ldb_debug(ldb, LDB_DEBUG_TRACE, "instancetype_mod\n");
+
        el = ldb_msg_find_element(req->op.mod.message, "instanceType");
        if (el != NULL) {
-               ldb_set_errstring(ldb, "instancetype: the 'instanceType' attribute can never be changed!");
-               return LDB_ERR_CONSTRAINT_VIOLATION;
+               /* Except to allow dbcheck to fix things, this must never be modified */
+               if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
+                       ldb_set_errstring(ldb, "instancetype: the 'instanceType' attribute can never be changed!");
+                       return LDB_ERR_CONSTRAINT_VIOLATION;
+               }
        }
-
        return ldb_next_request(module, req);
 }
 
-_PUBLIC_ const struct ldb_module_ops ldb_instancetype_module_ops = {
+static const struct ldb_module_ops ldb_instancetype_module_ops = {
        .name          = "instancetype",
        .add           = instancetype_add,
        .modify        = instancetype_mod
 };
+
+int ldb_instancetype_module_init(const char *version)
+{
+       LDB_MODULE_CHECK_VERSION(version);
+       return ldb_register_module(&ldb_instancetype_module_ops);
+}