libcli/smb: add smb_direct daemon infrastructure
authorRalph Boehme <slow@samba.org>
Sun, 18 Sep 2016 13:53:23 +0000 (15:53 +0200)
committerStefan Metzmacher <metze@samba.org>
Fri, 1 Jun 2018 12:35:03 +0000 (14:35 +0200)
Pair-programmed-with: Stefan Metzmacher <metze@samba.org>

libcli/smb/smb_direct.h [new file with mode: 0644]
libcli/smb/smb_direct_daemon.c [new file with mode: 0644]
libcli/smb/wscript

diff --git a/libcli/smb/smb_direct.h b/libcli/smb/smb_direct.h
new file mode 100644 (file)
index 0000000..1902370
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Stefan Metzmacher 2016
+ * Copyright (C) Ralph Boehme 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _LIBCLI_SMB_SMB_DIRECT_H_
+#define _LIBCLI_SMB_SMB_DIRECT_H_
+
+#define SMB_DIRECT_LISTEN_BACKLOG 100
+
+struct tevent_req *smb_direct_daemon_send(TALLOC_CTX *mem_ctx,
+                                         struct tevent_context *ev);
+
+int smb_direct_daemon_recv(struct tevent_req *req);
+
+#endif /* _LIBCLI_SMB_SMB_DIRECT_H_ */
diff --git a/libcli/smb/smb_direct_daemon.c b/libcli/smb/smb_direct_daemon.c
new file mode 100644 (file)
index 0000000..caee841
--- /dev/null
@@ -0,0 +1,710 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Stefan Metzmacher 2016
+ * Copyright (C) Ralph Boehme 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/network.h"
+#include <tevent.h>
+#include "lib/util/tevent_unix.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "lib/util/blocking.h"
+#include "lib/tsocket/tsocket.h"
+#include "lib/util/debug.h"
+#include "lib/util/data_blob.h"
+#include "librpc/gen_ndr/smb_direct_daemon.h"
+#include "librpc/gen_ndr/ndr_smb_direct_daemon.h"
+#include "librpc/ndr/libndr.h"
+#include "libcli/util/tstream.h"
+#include "lib/util/byteorder.h"
+#include "lib/util/samba_util.h"
+#include "smb_direct.h"
+#include "smb_direct_util.h"
+
+struct smb_direct_daemon_state {
+       /*
+        * Global state of the daemon
+        */
+
+       /* Our tevent context */
+       struct tevent_context *ev;
+
+       /* Lockfile fd */
+       int socket_lock_fd;
+
+       /*
+        * Path, fd and fde for the listening UNIX domain socket
+        */
+       char *listen_path;
+       int listen_fd;
+       struct tevent_fd *listen_fde;
+
+       struct sdd_listen_params params;
+};
+
+struct smb_direct_daemon_conn {
+       /*
+        * Connection object, one for each peer.
+        */
+
+       /* Backpointer to the global daemon state */
+       struct smb_direct_daemon_state *daemon_state;
+
+       /* Our tevent context */
+       struct tevent_context *ev;
+
+       /*
+        * We use the tstream_context for general protocol data
+        * exchange and use the fd for fd-passing with
+        * sendmsg()/recvmsg().
+        */
+       int conn_fd;
+       struct tstream_context *stream;
+
+       /* true if our peer is root */
+       bool privileged;
+
+       /*
+        * A connection in the listening state can only be used with
+        * smb_direct_accept() to accept a connection fd.
+        */
+       bool listening;
+};
+
+static struct tevent_req *smb_direct_daemon_conn_send(
+       TALLOC_CTX *mem_ctx,
+       struct tevent_context *ev,
+       struct smb_direct_daemon_state *daemon_state,
+       bool privileged,
+       int conn_fd,
+       struct tstream_context **stream);
+
+static int smb_direct_daemon_conn_recv(struct tevent_req *req);
+
+struct smbd_direct_daemon_write_state {
+       struct smb_direct_daemon_conn *conn;
+       DATA_BLOB out_data;
+       struct iovec iov;
+};
+
+static void smbd_direct_daemon_write_done(struct tevent_req *subreq);
+
+static struct tevent_req *smbd_direct_daemon_write_send(
+       struct smb_direct_daemon_conn *conn,
+       DATA_BLOB out_data)
+{
+       struct tevent_req *req = NULL;
+       struct smbd_direct_daemon_write_state *write_state = NULL;
+       struct tevent_req *subreq = NULL;
+
+       req = tevent_req_create(conn, &write_state,
+                               struct smbd_direct_daemon_write_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       *write_state = (struct smbd_direct_daemon_write_state) {
+               .conn = conn,
+               .out_data = out_data,
+       };
+       talloc_steal(write_state, write_state->out_data.data);
+
+       write_state->iov = (struct iovec) {
+               .iov_base = write_state->out_data.data,
+               .iov_len = write_state->out_data.length
+       };
+
+       subreq = tstream_writev_send(write_state, conn->ev, conn->stream,
+                                    &write_state->iov, 1);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, conn->ev);
+       }
+       tevent_req_set_callback(subreq, smbd_direct_daemon_write_done, req);
+
+       return req;
+}
+
+static void smbd_direct_daemon_write_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       int result;
+       int err;
+
+       result = tstream_writev_recv(subreq, &err);
+       if (result == -1) {
+               tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
+               return;
+       }
+
+       tevent_req_done(req);
+}
+
+static NTSTATUS smbd_direct_daemon_write_recv(struct tevent_req *req)
+{
+       NTSTATUS status;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               tevent_req_received(req);
+               return status;
+       }
+
+       tevent_req_received(req);
+       return NT_STATUS_OK;
+}
+
+struct smbd_direct_daemon_read_state {
+       struct smb_direct_daemon_conn *conn;
+       DATA_BLOB in_data;
+};
+
+static void smbd_direct_daemon_read_done(struct tevent_req *subreq);
+
+static NTSTATUS smbd_direct_daemon_packet_full(void *private_data,
+                                              DATA_BLOB blob,
+                                              size_t *size)
+{
+       size_t packet_len;
+
+       if (blob.length < 4) {
+               return STATUS_MORE_ENTRIES;
+       }
+
+       packet_len = IVAL(&blob.data[0], 0);
+       if (packet_len < 5 || packet_len > 0x1000) {
+               return NT_STATUS_DATA_ERROR;
+       }
+
+       *size = packet_len;
+
+       if (*size > blob.length) {
+               return STATUS_MORE_ENTRIES;
+       }
+
+       return NT_STATUS_OK;
+}
+
+static struct tevent_req *smbd_direct_daemon_read_send(
+       struct smb_direct_daemon_conn *conn)
+{
+       struct tevent_req *req = NULL;
+       struct smbd_direct_daemon_read_state *read_state = NULL;
+       struct tevent_req *subreq = NULL;
+
+       req = tevent_req_create(conn, &read_state,
+                               struct smbd_direct_daemon_read_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       *read_state = (struct smbd_direct_daemon_read_state) {
+               .conn = conn,
+       };
+
+       subreq = tstream_read_pdu_blob_send(read_state,
+                                           conn->ev,
+                                           conn->stream,
+                                           4, /* initial_read_size */
+                                           smbd_direct_daemon_packet_full,
+                                           read_state);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, conn->ev);
+       }
+       tevent_req_set_callback(subreq, smbd_direct_daemon_read_done, req);
+
+       return req;
+}
+
+static void smbd_direct_daemon_read_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct smbd_direct_daemon_read_state *read_state = tevent_req_data(
+               req, struct smbd_direct_daemon_read_state);
+       NTSTATUS status;
+
+       status = tstream_read_pdu_blob_recv(subreq, read_state,
+                                           &read_state->in_data);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               DBG_ERR("tstream_read_pdu_blob_recv [%s]",
+                       nt_errstr(status));
+               return;
+       }
+
+       tevent_req_done(req);
+}
+
+static NTSTATUS smbd_direct_daemon_read_recv(struct tevent_req *req,
+                                            TALLOC_CTX *mem_ctx,
+                                            DATA_BLOB *in_data)
+{
+       struct smbd_direct_daemon_read_state *read_state = tevent_req_data(
+               req, struct smbd_direct_daemon_read_state);
+       NTSTATUS status;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               DBG_ERR("tstream_read_pdu_blob_recv [%s]",
+                       nt_errstr(status));
+               tevent_req_received(req);
+               return status;
+       }
+
+       *in_data = read_state->in_data;
+       talloc_steal(mem_ctx, in_data->data);
+
+       tevent_req_received(req);
+       return NT_STATUS_OK;
+}
+
+static void smb_direct_daemon_req_cleanup(struct tevent_req *req,
+                                         enum tevent_req_state req_state)
+{
+       struct smb_direct_daemon_state *state = tevent_req_data(
+               req, struct smb_direct_daemon_state);
+
+       TALLOC_FREE(state->listen_fde);
+
+       if (state->listen_path != NULL) {
+               unlink(state->listen_path);
+               TALLOC_FREE(state->listen_path);
+       }
+
+       if (state->listen_fd != -1) {
+               close(state->listen_fd);
+               state->listen_fd = -1;
+       }
+
+       if (state->socket_lock_fd != -1) {
+               close(state->socket_lock_fd);
+               state->socket_lock_fd = -1;
+       }
+}
+
+static void smb_direct_daemon_listen_handler(struct tevent_context *ev,
+                                            struct tevent_fd *fde,
+                                            uint16_t flags,
+                                            void *private_data);
+
+struct tevent_req *smb_direct_daemon_send(TALLOC_CTX *mem_ctx,
+                                         struct tevent_context *ev)
+{
+       struct tevent_req *req = NULL;
+       struct smb_direct_daemon_state *state = NULL;
+       char *lock_path = NULL;
+       char *listen_path = NULL;
+       union {
+               struct sockaddr_un su;
+               struct sockaddr sa;
+       } addr;
+       int ret;
+       bool ok;
+
+       req = tevent_req_create(mem_ctx, &state, struct smb_direct_daemon_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       *state = (struct smb_direct_daemon_state) {
+               .ev = ev,
+               .listen_fd = -1,
+               .socket_lock_fd = -1,
+       };
+
+       tevent_req_set_cleanup_fn(req, smb_direct_daemon_req_cleanup);
+
+       lock_path = smb_direct_lock_path(state);
+       if (tevent_req_nomem(lock_path, req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       state->socket_lock_fd = open(lock_path, O_CREAT|O_RDWR, 0700);
+       if (state->socket_lock_fd == -1) {
+               DBG_ERR("Can't open socket lockfile %s [%s]\n",
+                       lock_path, strerror(errno));
+               tevent_req_error(req, errno);
+               return tevent_req_post(req, ev);
+       }
+
+       ok = fcntl_lock(state->socket_lock_fd, F_SETLK, 0, 0, F_WRLCK);
+       if (!ok) {
+               DBG_ERR("Can't lock socket lockfile %s [%s]\n",
+                       lock_path, strerror(errno));
+               tevent_req_error(req, errno);
+               return tevent_req_post(req, ev);
+       }
+
+       listen_path = smb_direct_socket_path(state);
+       if (tevent_req_nomem(listen_path, req)) {
+               DBG_ERR("smb_direct_socket_path failed\n");
+               return tevent_req_post(req, ev);
+       }
+
+       if (strlen(listen_path) > sizeof(addr.su.sun_path) - 1) {
+               DBG_ERR("listen_path too long [%s]\n", listen_path);
+               tevent_req_error(req, ENAMETOOLONG);
+               return tevent_req_post(req, ev);
+       }
+
+       unlink(listen_path);
+
+       ZERO_STRUCT(addr);
+       addr.su.sun_family = AF_UNIX;
+       strncpy(addr.su.sun_path, listen_path,
+               sizeof(addr.su.sun_path) - 1);
+
+       state->listen_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (state->listen_fd == -1) {
+               DBG_ERR("socket failed [%s]\n", strerror(errno));
+               tevent_req_error(req, errno);
+               return tevent_req_post(req, ev);
+       }
+
+       set_close_on_exec(state->listen_fd);
+
+       ret = bind(state->listen_fd, &addr.sa, sizeof(addr.su));
+       if (ret != 0) {
+               DBG_ERR("bind failed [%s]\n", strerror(errno));
+               tevent_req_error(req, errno);
+               return tevent_req_post(req, ev);
+       }
+
+       /*
+        * Once the bind has created the socket file set the path in
+        * the state for the cleanup function.
+        */
+       state->listen_path = listen_path;
+
+       ret = listen(state->listen_fd, SMB_DIRECT_LISTEN_BACKLOG);
+       if (ret != 0) {
+               DBG_ERR("listen failed [%s]\n", strerror(errno));
+               tevent_req_error(req, errno);
+               return tevent_req_post(req, ev);
+       }
+
+       set_blocking(state->listen_fd, false);
+
+       state->listen_fde = tevent_add_fd(ev, state,
+                                         state->listen_fd,
+                                         TEVENT_FD_READ,
+                                         smb_direct_daemon_listen_handler,
+                                         req);
+       if (tevent_req_nomem(state->listen_fde, req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       DBG_NOTICE("smb_direct_daemon started\n");
+
+       return req;
+}
+
+static void smb_direct_daemon_conn_disconnect(struct tevent_req *subreq);
+
+static void smb_direct_daemon_listen_handler(struct tevent_context *ev,
+                                            struct tevent_fd *fde,
+                                            uint16_t flags,
+                                            void *private_data)
+{
+       struct tevent_req *req = talloc_get_type_abort(
+               private_data, struct tevent_req);
+       struct smb_direct_daemon_state *daemon_state = tevent_req_data(
+               req, struct smb_direct_daemon_state);
+       int conn_fd;
+       int ret;
+       uid_t peer_uid = -1;
+       gid_t peer_gid = -1;
+       bool privileged = false;
+       struct tstream_context *stream = NULL;
+       struct tevent_req *subreq = NULL;
+
+       conn_fd = accept(daemon_state->listen_fd, NULL, NULL);
+       if (conn_fd == -1) {
+               if (errno != EINTR && errno != EAGAIN) {
+                       DBG_WARNING("accept failed [%s]\n", strerror(errno));
+               }
+               return;
+       }
+
+       set_close_on_exec(conn_fd);
+
+       ret = getpeereid(conn_fd, &peer_uid, &peer_gid);
+       if (ret != 0) {
+               DBG_WARNING("getpeereid failed [%s]\n", strerror(errno));
+               close(conn_fd);
+               return;
+       }
+
+       if (peer_uid == geteuid()) {
+               privileged = true;
+       }
+
+       set_blocking(conn_fd, false);
+
+       ret = tstream_bsd_existing_socket(daemon_state, conn_fd, &stream);
+       if (ret != 0) {
+               DBG_WARNING("tstream_bsd_existing_socket failed [%s]\n",
+                           strerror(errno));
+               close(conn_fd);
+               return;
+       }
+
+       subreq = smb_direct_daemon_conn_send(daemon_state,
+                                            daemon_state->ev,
+                                            daemon_state,
+                                            privileged,
+                                            conn_fd, &stream);
+       if (subreq == NULL) {
+               DBG_WARNING("smb_direct_daemon_conn_send failed [%s]\n",
+                           strerror(errno));
+               TALLOC_FREE(stream);
+               return;
+       }
+       tevent_req_set_callback(subreq, smb_direct_daemon_conn_disconnect, req);
+}
+
+static void smb_direct_daemon_conn_disconnect(struct tevent_req *subreq)
+{
+       int ret;
+
+       ret = smb_direct_daemon_conn_recv(subreq);
+       TALLOC_FREE(subreq);
+       if (ret != 0) {
+               DBG_DEBUG("smb_direct_daemon_conn_send failed\n");
+       }
+}
+
+int smb_direct_daemon_recv(struct tevent_req *req)
+{
+       return tevent_req_simple_recv_unix(req);
+}
+
+static NTSTATUS smbd_direct_daemon_ping(
+       struct sdd_packet_ping_request *ping_request,
+       struct sdd_packet_ping_response *ping_response)
+{
+       ping_response->data = ping_request->data;
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS smbd_direct_daemon_listen(
+       struct smb_direct_daemon_conn *conn,
+       struct sdd_packet_listen_request *listen_request,
+       struct sdd_packet_listen_response *listen_response)
+{
+       conn->daemon_state->params = listen_request->params;
+       conn->listening = true;
+       listen_response->status = 0;
+
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS smbd_direct_daemon_dispatch(struct smb_direct_daemon_conn *conn,
+                                           DATA_BLOB in_data,
+                                           DATA_BLOB *out_data)
+{
+       struct sdd_packetB *request_packet = NULL;
+       struct sdd_packetB *response_packet = NULL;
+       enum ndr_err_code ndr_err;
+       NTSTATUS status;
+
+       if (conn->listening) {
+               return NT_STATUS_INVALID_MESSAGE;
+       }
+
+       request_packet = talloc_zero(conn, struct sdd_packetB);
+       if (request_packet == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       response_packet = talloc_zero(conn, struct sdd_packetB);
+       if (response_packet == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       ndr_err = ndr_pull_struct_blob_all(
+               &in_data, request_packet, request_packet,
+               (ndr_pull_flags_fn_t)ndr_pull_sdd_packetB);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               return NT_STATUS_DATA_ERROR;
+       }
+
+       switch (request_packet->command) {
+
+       case SDD_PING_REQUEST: {
+               struct sdd_packet_ping_response ping_response;
+
+               ZERO_STRUCT(ping_response);
+
+               status = smbd_direct_daemon_ping(
+                       &request_packet->packet.ping_request,
+                       &ping_response);
+               if (!NT_STATUS_IS_OK(status)) {
+                       goto fail;
+               }
+
+               response_packet->command = SDD_PING_RESPONSE;
+               response_packet->packet.ping_response = ping_response;
+               break;
+       }
+
+       case SDD_LISTEN_REQUEST: {
+               struct sdd_packet_listen_response listen_response;
+
+               ZERO_STRUCT(listen_response);
+
+               status = smbd_direct_daemon_listen(
+                       conn,
+                       &request_packet->packet.listen_request,
+                       &listen_response);
+               if (!NT_STATUS_IS_OK(status)) {
+                       goto fail;
+               }
+
+               response_packet->command = SDD_LISTEN_RESPONSE;
+               response_packet->packet.listen_response = listen_response;
+               break;
+       }
+
+       default:
+               status = NT_STATUS_DATA_ERROR;
+               break;
+       }
+
+       ndr_err = ndr_push_struct_blob(
+               out_data, conn, response_packet,
+               (ndr_push_flags_fn_t)ndr_push_sdd_packetB);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               status = NT_STATUS_DATA_ERROR;
+               goto fail;
+       }
+
+       SIVAL(&out_data->data[0], 0, out_data->length);
+
+fail:
+       TALLOC_FREE(request_packet);
+       TALLOC_FREE(response_packet);
+       return status;
+}
+
+static void smbd_direct_daemon_conn_handler(struct tevent_req *read_req);
+static void smbd_direct_daemon_conn_handler_next(struct tevent_req *write_req);
+
+/**
+ * @brief Handle an already accepted connection
+ *
+ * Connection handler, called just after the connection was accepted.
+ **/
+static struct tevent_req *smb_direct_daemon_conn_send(
+       TALLOC_CTX *mem_ctx,
+       struct tevent_context *ev,
+       struct smb_direct_daemon_state *daemon_state,
+       bool privileged,
+       int conn_fd,
+       struct tstream_context **stream)
+{
+       struct tevent_req *req = NULL;
+       struct smb_direct_daemon_conn *conn = NULL;
+       struct tevent_req *subreq = NULL;
+
+       req = tevent_req_create(mem_ctx, &conn, struct smb_direct_daemon_conn);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       *conn = (struct smb_direct_daemon_conn) {
+               .ev = ev,
+               .daemon_state = daemon_state,
+               .conn_fd = conn_fd,
+               .stream = talloc_move(conn, stream),
+               .privileged = privileged,
+       };
+
+       subreq = smbd_direct_daemon_read_send(conn);
+       if (tevent_req_nomem(subreq, req)) {
+               tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, smbd_direct_daemon_conn_handler, req);
+
+       return req;
+}
+
+static void smbd_direct_daemon_conn_handler(struct tevent_req *read_req)
+{
+       struct tevent_req *conn_req = tevent_req_callback_data(
+               read_req, struct tevent_req);
+       struct smb_direct_daemon_conn *conn = tevent_req_data(
+               conn_req, struct smb_direct_daemon_conn);
+       struct tevent_req *write_req = NULL;
+       NTSTATUS status;
+       DATA_BLOB in_data;
+       DATA_BLOB out_data;
+
+       status = smbd_direct_daemon_read_recv(read_req, conn, &in_data);
+       TALLOC_FREE(read_req);
+       if (tevent_req_nterror(conn_req, status)) {
+               DBG_ERR("smbd_direct_daemon_read_recv [%s]",
+                       nt_errstr(status));
+               return;
+       }
+
+       status = smbd_direct_daemon_dispatch(conn, in_data, &out_data);
+       if (tevent_req_nterror(conn_req, status)) {
+               DBG_ERR("smbd_direct_daemon_read_recv [%s]",
+                       nt_errstr(status));
+               return;
+       }
+
+       write_req = smbd_direct_daemon_write_send(conn, out_data);
+       if (tevent_req_nomem(write_req, conn_req)) {
+               return;
+       }
+       tevent_req_set_callback(write_req,
+                               smbd_direct_daemon_conn_handler_next,
+                               conn_req);
+}
+
+static void smbd_direct_daemon_conn_handler_next(struct tevent_req *write_req)
+{
+       NTSTATUS status;
+       struct tevent_req *conn_req = tevent_req_callback_data(
+               write_req,  struct tevent_req);
+       struct smb_direct_daemon_conn *conn = tevent_req_data(
+               conn_req, struct smb_direct_daemon_conn);
+       struct tevent_req *read_req = NULL;
+
+       status = smbd_direct_daemon_write_recv(write_req);
+       TALLOC_FREE(write_req);
+       if (tevent_req_nterror(conn_req, status)) {
+               DBG_ERR("smbd_direct_daemon_write_recv [%s]",
+                       nt_errstr(status));
+               return;
+       }
+
+       read_req = smbd_direct_daemon_read_send(conn);
+       if (tevent_req_nomem(read_req, conn_req)) {
+               return;
+       }
+       tevent_req_set_callback(read_req,
+                               smbd_direct_daemon_conn_handler,
+                               conn_req);
+}
+
+static int smb_direct_daemon_conn_recv(struct tevent_req *req)
+{
+       return tevent_req_simple_recv_unix(req);
+}
index df5b9b8fb680e475f429f3f5a3c67e6ff9a6b00f..339cbfb3370935b30f792d4830856a0753fb4a27 100644 (file)
@@ -31,11 +31,17 @@ def build(bld):
     bld.SAMBA_SUBSYSTEM('smb_direct',
                        source='''
                             smb_direct_util.c
+                            smb_direct_daemon.c
                         ''',
+                        deps='rdmacm ibverbs',
                         public_deps='''
                             talloc
                             samba-util
                             samba-hostconfig
+                            tevent
+                            LIBTSOCKET
+                            LIBSAMBA_TSOCKET
+                            NDR_SMB_DIRECT_DAEMON
                         ''')
 
     bld.SAMBA_LIBRARY('smb_transport',
@@ -45,7 +51,7 @@ def build(bld):
             smb_transport_tcp.c
             smb_transport_direct.c
         ''',
-        deps='LIBASYNC_REQ rdmacm ibverbs',
+        deps='LIBASYNC_REQ rdmacm ibverbs smb_direct',
         public_deps='talloc tevent samba-util',
         private_library=True,
         private_headers='''