s3:messages: allow messaging_filtered_read_send() to use wrapper tevent_context
authorStefan Metzmacher <metze@samba.org>
Fri, 23 Mar 2018 13:48:46 +0000 (14:48 +0100)
committerRalph Boehme <slow@samba.org>
Wed, 11 Jul 2018 21:04:24 +0000 (23:04 +0200)
As it gets 'messaging_context' as argument, we're sure a messaging context
with a raw tevent context already exist.

It means we can allow a wrapper tevent context that wrapps the main tevent
context of the messaging context.

The use of tevent_req_defer_callback() makes sure that the callers
callback function calls messaging_filtered_read_recv() from the
correct "wrapped" environment.

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
source3/lib/messages.c

index 1a5ea4659aa41f9fa709717f4e3712a0533bf88a..dab53f1c48e30a620ea8707f52eaa687b63e821b 100644 (file)
@@ -206,7 +206,7 @@ static bool messaging_register_event_context(struct messaging_context *ctx,
                        continue;
                }
 
                        continue;
                }
 
-               if (reg->ev == ev) {
+               if (tevent_context_same_loop(reg->ev, ev)) {
                        reg->refcount += 1;
                        return true;
                }
                        reg->refcount += 1;
                        return true;
                }
@@ -255,7 +255,7 @@ static bool messaging_deregister_event_context(struct messaging_context *ctx,
                        continue;
                }
 
                        continue;
                }
 
-               if (reg->ev == ev) {
+               if (tevent_context_same_loop(reg->ev, ev)) {
                        reg->refcount -= 1;
 
                        if (reg->refcount == 0) {
                        reg->refcount -= 1;
 
                        if (reg->refcount == 0) {
@@ -1034,7 +1034,9 @@ struct tevent_req *messaging_filtered_read_send(
        state->filter = filter;
        state->private_data = private_data;
 
        state->filter = filter;
        state->private_data = private_data;
 
-       if (tevent_context_is_wrapper(ev)) {
+       if (tevent_context_is_wrapper(ev) &&
+           !tevent_context_same_loop(ev, msg_ctx->event_ctx))
+       {
                /* This is really a programmer error! */
                DBG_ERR("Wrapper tevent context doesn't use main context.\n");
                tevent_req_error(req, EINVAL);
                /* This is really a programmer error! */
                DBG_ERR("Wrapper tevent context doesn't use main context.\n");
                tevent_req_error(req, EINVAL);
@@ -1043,7 +1045,11 @@ struct tevent_req *messaging_filtered_read_send(
 
        /*
         * We have to defer the callback here, as we might be called from
 
        /*
         * We have to defer the callback here, as we might be called from
-        * within a different tevent_context than state->ev
+        * within a different tevent_context than state->ev.
+        *
+        * This is important for two cases:
+        * 1. nested event contexts, used by blocking ctdb calls
+        * 2. possible impersonation using wrapper tevent contexts.
         */
        tevent_req_defer_callback(req, state->ev);
 
         */
        tevent_req_defer_callback(req, state->ev);
 
@@ -1339,7 +1345,7 @@ static bool messaging_dispatch_waiters(struct messaging_context *msg_ctx,
 
                state = tevent_req_data(
                        req, struct messaging_filtered_read_state);
 
                state = tevent_req_data(
                        req, struct messaging_filtered_read_state);
-               if ((ev == state->ev) &&
+               if (tevent_context_same_loop(ev, state->ev) &&
                    state->filter(rec, state->private_data)) {
                        messaging_filtered_read_done(req, rec);
                        return true;
                    state->filter(rec, state->private_data)) {
                        messaging_filtered_read_done(req, rec);
                        return true;