s3:messaging: make it possible to receive a fd array from another process
authorStefan Metzmacher <metze@samba.org>
Tue, 24 Jun 2014 05:39:05 +0000 (07:39 +0200)
committerMichael Adam <obnox@samba.org>
Wed, 24 Sep 2014 06:44:11 +0000 (08:44 +0200)
In order to receive the fd array the caller needs to use
messaging_filtered_read_send/recv(). For all higher level
methods we silently close/ignore the fd array.

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Michael Adam <obnox@samba.org>
source3/lib/dbwrap/dbwrap_watch.c
source3/lib/messages.c
source3/lib/messages_dgm.c
source3/lib/messages_dgm.h
source3/librpc/idl/messaging.idl

index a5f1ebd5bffef2556104d006e19642627fb4d8bc..9ff8fc24b487494fcfad60115964238cab53144e 100644 (file)
@@ -299,6 +299,9 @@ static bool dbwrap_record_watch_filter(struct messaging_rec *rec,
        if (rec->msg_type != MSG_DBWRAP_MODIFIED) {
                return false;
        }
+       if (rec->num_fds != 0) {
+               return false;
+       }
        if (rec->buf.length != state->w_key.dsize) {
                return false;
        }
index 0e0259236ed82f103375e7fb92c3712a15b26287..56108abd2127e42c162f169a0883b54077606c5b 100644 (file)
@@ -204,6 +204,7 @@ bool message_send_all(struct messaging_context *msg_ctx,
 }
 
 static void messaging_recv_cb(const uint8_t *msg, size_t msg_len,
+                             const int *fds, size_t num_fds,
                              void *private_data)
 {
        struct messaging_context *msg_ctx = talloc_get_type_abort(
@@ -211,19 +212,38 @@ static void messaging_recv_cb(const uint8_t *msg, size_t msg_len,
        const struct messaging_hdr *hdr;
        struct server_id_buf idbuf;
        struct messaging_rec rec;
+       int64_t fds64[MIN(num_fds, INT8_MAX)];
+       size_t i;
 
        if (msg_len < sizeof(*hdr)) {
+               for (i=0; i < num_fds; i++) {
+                       close(fds[i]);
+               }
                DEBUG(1, ("message too short: %u\n", (unsigned)msg_len));
                return;
        }
 
+       if (num_fds > INT8_MAX) {
+               for (i=0; i < num_fds; i++) {
+                       close(fds[i]);
+               }
+               DEBUG(1, ("too many fds: %u\n", (unsigned)num_fds));
+               return;
+       }
+
+       for (i=0; i < num_fds; i++) {
+               fds64[i] = fds[i];
+       }
+
        /*
         * messages_dgm guarantees alignment, so we can cast here
         */
        hdr = (const struct messaging_hdr *)msg;
 
-       DEBUG(10, ("%s: Received message 0x%x len %u from %s\n", __func__,
-                  (unsigned)hdr->msg_type, (unsigned)(msg_len - sizeof(*hdr)),
+       DEBUG(10, ("%s: Received message 0x%x len %u (num_fds:%u) from %s\n",
+                  __func__, (unsigned)hdr->msg_type,
+                  (unsigned)(msg_len - sizeof(*hdr)),
+                  (unsigned)num_fds,
                   server_id_str_buf(hdr->src, &idbuf)));
 
        rec = (struct messaging_rec) {
@@ -232,7 +252,9 @@ static void messaging_recv_cb(const uint8_t *msg, size_t msg_len,
                .src = hdr->src,
                .dest = hdr->dst,
                .buf.data = discard_const_p(uint8, msg) + sizeof(*hdr),
-               .buf.length = msg_len - sizeof(*hdr)
+               .buf.length = msg_len - sizeof(*hdr),
+               .num_fds = num_fds,
+               .fds = fds64,
        };
 
        messaging_dispatch_rec(msg_ctx, &rec);
@@ -501,9 +523,10 @@ static struct messaging_rec *messaging_rec_dup(TALLOC_CTX *mem_ctx,
                                               struct messaging_rec *rec)
 {
        struct messaging_rec *result;
+       size_t fds_size = sizeof(int64_t) * rec->num_fds;
 
-       result = talloc_pooled_object(mem_ctx, struct messaging_rec,
-                                     1, rec->buf.length);
+       result = talloc_pooled_object(mem_ctx, struct messaging_rec, 2,
+                                     rec->buf.length + fds_size);
        if (result == NULL) {
                return NULL;
        }
@@ -513,6 +536,13 @@ static struct messaging_rec *messaging_rec_dup(TALLOC_CTX *mem_ctx,
 
        result->buf.data = talloc_memdup(result, rec->buf.data,
                                         rec->buf.length);
+
+       result->fds = NULL;
+       if (result->num_fds > 0) {
+               result->fds = talloc_array(result, int64_t, result->num_fds);
+               memcpy(result->fds, rec->fds, fds_size);
+       }
+
        return result;
 }
 
@@ -692,6 +722,10 @@ static bool messaging_read_filter(struct messaging_rec *rec,
        struct messaging_read_state *state = talloc_get_type_abort(
                private_data, struct messaging_read_state);
 
+       if (rec->num_fds != 0) {
+               return false;
+       }
+
        return rec->msg_type == state->msg_type;
 }
 
@@ -825,6 +859,7 @@ void messaging_dispatch_rec(struct messaging_context *msg_ctx,
 {
        struct messaging_callback *cb, *next;
        unsigned i;
+       size_t j;
 
        for (cb = msg_ctx->callbacks; cb != NULL; cb = next) {
                next = cb->next;
@@ -832,6 +867,16 @@ void messaging_dispatch_rec(struct messaging_context *msg_ctx,
                        continue;
                }
 
+               /*
+                * the old style callbacks don't support fd passing
+                */
+               for (j=0; j < rec->num_fds; j++) {
+                       int fd = rec->fds[j];
+                       close(fd);
+               }
+               rec->num_fds = 0;
+               rec->fds = NULL;
+
                if (server_id_same_process(&rec->src, &rec->dest)) {
                        /*
                         * This is a self-send. We are called here from
@@ -859,6 +904,12 @@ void messaging_dispatch_rec(struct messaging_context *msg_ctx,
        }
 
        if (!messaging_append_new_waiters(msg_ctx)) {
+               for (j=0; j < rec->num_fds; j++) {
+                       int fd = rec->fds[j];
+                       close(fd);
+               }
+               rec->num_fds = 0;
+               rec->fds = NULL;
                return;
        }
 
@@ -889,10 +940,26 @@ void messaging_dispatch_rec(struct messaging_context *msg_ctx,
                        req, struct messaging_filtered_read_state);
                if (state->filter(rec, state->private_data)) {
                        messaging_filtered_read_done(req, rec);
+
+                       /*
+                        * Only the first one gets the fd-array
+                        */
+                       rec->num_fds = 0;
+                       rec->fds = NULL;
                }
 
                i += 1;
        }
+
+       /*
+        * If the fd-array isn't used, just close it.
+        */
+       for (j=0; j < rec->num_fds; j++) {
+               int fd = rec->fds[j];
+               close(fd);
+       }
+       rec->num_fds = 0;
+       rec->fds = NULL;
 }
 
 static int mess_parent_dgm_cleanup(void *private_data);
index 7ba79fcfd0abd3026d5d7d0a7954ff4995235030..68307698a5c77e84c77555bc9f6670feb79614a4 100644 (file)
@@ -44,6 +44,8 @@ struct messaging_dgm_context {
 
        void (*recv_cb)(const uint8_t *msg,
                        size_t msg_len,
+                       const int *fds,
+                       size_t num_fds,
                        void *private_data);
        void *recv_cb_private_data;
 
@@ -179,6 +181,8 @@ int messaging_dgm_init(struct tevent_context *ev,
                       uid_t dir_owner,
                       void (*recv_cb)(const uint8_t *msg,
                                       size_t msg_len,
+                                      const int *fds,
+                                      size_t num_fds,
                                       void *private_data),
                       void *recv_cb_private_data)
 {
@@ -330,15 +334,9 @@ static void messaging_dgm_recv(struct unix_msg_ctx *ctx,
 {
        struct messaging_dgm_context *dgm_ctx = talloc_get_type_abort(
                private_data, struct messaging_dgm_context);
-       size_t i;
 
-       /* for now we ignore passed file descriptors */
-       for (i = 0; i < num_fds; i++) {
-               close(fds[i]);
-               fds[i] = -1;
-       }
-
-       dgm_ctx->recv_cb(msg, msg_len, dgm_ctx->recv_cb_private_data);
+       dgm_ctx->recv_cb(msg, msg_len, fds, num_fds,
+                        dgm_ctx->recv_cb_private_data);
 }
 
 int messaging_dgm_cleanup(pid_t pid)
index 169d863219f0a56e45af84f875aa7291c4fe27cc..3c915c18ef14779635b2ef53ad50a550483665fb 100644 (file)
@@ -26,6 +26,8 @@ int messaging_dgm_init(struct tevent_context *ev,
                       uid_t dir_owner,
                       void (*recv_cb)(const uint8_t *msg,
                                       size_t msg_len,
+                                      const int *fds,
+                                      size_t num_fds,
                                       void *private_data),
                       void *recv_cb_private_data);
 void messaging_dgm_destroy(void);
index 66d4ae598ce56634fd1a1dc53c5cb4f23dc9d5d5..ce40a7bb25602e90dd12e46409dec6b7f4c589c9 100644 (file)
@@ -130,5 +130,7 @@ interface messaging
                server_id dest;
                server_id src;
                DATA_BLOB buf;
+               uint8 num_fds;
+               dlong fds[num_fds];
        } messaging_rec;
 }