dsdb: Do not permit nested event loops when in a transaction, use a nested event...
authorAndrew Bartlett <abartlet@samba.org>
Thu, 17 Apr 2014 03:39:56 +0000 (15:39 +1200)
committerStefan Metzmacher <metze@samba.org>
Tue, 6 May 2014 11:36:20 +0000 (13:36 +0200)
It is never safe to execute arbitary code inside a transaction - we
need to get in and get out, not run other events for the rest of the
server.

This patch avoids that by creating a private event loop during
transactions, so no unexpected operations fire, and returning the
original one when we finish it.

If an event fires during an LDB transaction, an unrelated operation
can occur during the transaction, and if the transaction were to be
cancelled, there would be a silent rollback (despite the client having
been indicated success).

Additionally, other processes could be called via IRPC that need to
operate on the database but are locked out due to the ongoing
transaction.

Andrew Bartlett

BUG: https://bugzilla.samba.org/show_bug.cgi?id=10582
Change-Id: I22322fc006e61d7291da17cdf6431416ebb7b30f
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
Autobuild-User(master): Stefan Metzmacher <metze@samba.org>
Autobuild-Date(master): Tue May  6 13:36:20 CEST 2014 on sn-devel-104

source4/dsdb/samdb/ldb_modules/rootdse.c

index 87fbe6654d9c0836c2127b7a28f3192e36617b9d..b13dc9e5c591bff585f76c486235d4f5be434913 100644 (file)
@@ -36,6 +36,7 @@
 #include "librpc/gen_ndr/ndr_irpc_c.h"
 #include "lib/tsocket/tsocket.h"
 #include "cldap_server/cldap_server.h"
+#include "lib/events/events.h"
 
 struct rootdse_private_data {
        unsigned int num_controls;
@@ -43,6 +44,8 @@ struct rootdse_private_data {
        unsigned int num_partitions;
        struct ldb_dn **partitions;
        bool block_anonymous;
+       struct tevent_context *saved_ev;
+       struct tevent_context *private_ev;
 };
 
 struct rootdse_context {
@@ -1356,6 +1359,67 @@ static int rootdse_add(struct ldb_module *module, struct ldb_request *req)
        return LDB_ERR_NAMING_VIOLATION;
 }
 
+static int rootdse_start_trans(struct ldb_module *module)
+{
+       int ret;
+       struct ldb_context *ldb = ldb_module_get_ctx(module);
+       struct rootdse_private_data *data = talloc_get_type_abort(ldb_module_get_private(module),
+                                                                 struct rootdse_private_data);
+       ret = ldb_next_start_trans(module);
+       if (ret == LDB_SUCCESS) {
+               if (data->private_ev != NULL) {
+                       return ldb_operr(ldb);
+               }
+               data->private_ev = s4_event_context_init(data);
+               if (data->private_ev == NULL) {
+                       return ldb_operr(ldb);
+               }
+               data->saved_ev = ldb_get_event_context(ldb);
+               ldb_set_event_context(ldb, data->private_ev);
+       }
+       return ret;
+}
+
+static int rootdse_end_trans(struct ldb_module *module)
+{
+       int ret;
+       struct ldb_context *ldb = ldb_module_get_ctx(module);
+       struct rootdse_private_data *data = talloc_get_type_abort(ldb_module_get_private(module),
+                                                                 struct rootdse_private_data);
+       ret = ldb_next_end_trans(module);
+       if (data->saved_ev == NULL) {
+               return ldb_operr(ldb);
+       }
+
+       if (data->private_ev != ldb_get_event_context(ldb)) {
+               return ldb_operr(ldb);
+       }
+       ldb_set_event_context(ldb, data->saved_ev);
+       data->saved_ev = NULL;
+       TALLOC_FREE(data->private_ev);
+       return ret;
+}
+
+static int rootdse_del_trans(struct ldb_module *module)
+{
+       int ret;
+       struct ldb_context *ldb = ldb_module_get_ctx(module);
+       struct rootdse_private_data *data = talloc_get_type_abort(ldb_module_get_private(module),
+                                                                 struct rootdse_private_data);
+       ret = ldb_next_del_trans(module);
+       if (data->saved_ev == NULL) {
+               return ldb_operr(ldb);
+       }
+
+       if (data->private_ev != ldb_get_event_context(ldb)) {
+               return ldb_operr(ldb);
+       }
+       ldb_set_event_context(ldb, data->saved_ev);
+       data->saved_ev = NULL;
+       TALLOC_FREE(data->private_ev);
+       return ret;
+}
+
 struct fsmo_transfer_state {
        struct ldb_context *ldb;
        struct ldb_request *req;
@@ -1383,7 +1447,7 @@ static void rootdse_fsmo_transfer_callback(struct tevent_req *treq)
                 * Now that it is failed, start the transaction up
                 * again so the wrappers can close it without additional error
                 */
-               ldb_next_start_trans(module);
+               rootdse_start_trans(module);
                ldb_module_done(req, NULL, NULL, LDB_ERR_UNAVAILABLE);
                return;
        }
@@ -1393,7 +1457,7 @@ static void rootdse_fsmo_transfer_callback(struct tevent_req *treq)
                 * Now that it is failed, start the transaction up
                 * again so the wrappers can close it without additional error
                 */
-               ldb_next_start_trans(module);
+               rootdse_start_trans(module);
                ldb_module_done(req, NULL, NULL, LDB_ERR_UNAVAILABLE);
                return;
        }
@@ -1402,7 +1466,7 @@ static void rootdse_fsmo_transfer_callback(struct tevent_req *treq)
         * Now that it is done, start the transaction up again so the
         * wrappers can close it without error
         */
-       ret = ldb_next_start_trans(module);
+       ret = rootdse_start_trans(module);
        ldb_module_done(req, NULL, NULL, ret);
 }
 
@@ -1443,7 +1507,7 @@ static int rootdse_become_master(struct ldb_module *module,
         * this gives the least supprise to this supprising action (as
         * we will never record anything done to this point
         */
-       ldb_next_del_trans(module);
+       rootdse_del_trans(module);
 
        msg = imessaging_client_init(tmp_ctx, lp_ctx,
                                    ldb_get_event_context(ldb));
@@ -1612,15 +1676,18 @@ static int rootdse_extended(struct ldb_module *module, struct ldb_request *req)
 }
 
 static const struct ldb_module_ops ldb_rootdse_module_ops = {
-       .name           = "rootdse",
-       .init_context   = rootdse_init,
-       .search         = rootdse_search,
-       .request        = rootdse_request,
-       .add            = rootdse_add,
-       .modify         = rootdse_modify,
-       .rename         = rootdse_rename,
-       .extended       = rootdse_extended,
-       .del            = rootdse_delete
+       .name              = "rootdse",
+       .init_context      = rootdse_init,
+       .search            = rootdse_search,
+       .request           = rootdse_request,
+       .add               = rootdse_add,
+       .modify            = rootdse_modify,
+       .rename            = rootdse_rename,
+       .extended          = rootdse_extended,
+       .del               = rootdse_delete,
+       .start_transaction = rootdse_start_trans,
+       .end_transaction   = rootdse_end_trans,
+       .del_transaction   = rootdse_del_trans
 };
 
 int ldb_rootdse_module_init(const char *version)