]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
libcli: Implement a tstream dcerpc_binding_handle
authorRalph Boehme <slow@samba.org>
Wed, 29 Jun 2016 11:47:18 +0000 (12:47 +0100)
committerAndrew Bartlett <abartlet@samba.org>
Wed, 25 Oct 2023 22:23:38 +0000 (22:23 +0000)
This implements a dcerpc_binding_handle that does just pass request and
response blob passing.

Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
libcli/tstream_binding_handle/tstream_binding_handle.c [new file with mode: 0644]
libcli/tstream_binding_handle/tstream_binding_handle.h [new file with mode: 0644]
libcli/tstream_binding_handle/wscript_build [new file with mode: 0644]
wscript_build

diff --git a/libcli/tstream_binding_handle/tstream_binding_handle.c b/libcli/tstream_binding_handle/tstream_binding_handle.c
new file mode 100644 (file)
index 0000000..76f54a7
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   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 "includes.h"
+#include <tevent.h>
+#include "libcli/tstream_binding_handle/tstream_binding_handle.h"
+#include "system/filesys.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "lib/tsocket/tsocket.h"
+#include "lib/util/debug.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "libcli/smb/tstream_smbXcli_np.h"
+
+struct tstream_bh_state {
+       struct tstream_context *stream;
+       struct tevent_queue *write_queue;
+       const struct ndr_interface_table *table;
+       uint32_t request_timeout;
+       size_t call_initial_read_size;
+       tstream_read_pdu_blob_full_fn_t *complete_pdu_fn;
+       void *complete_pdu_fn_private;
+};
+
+static bool tstream_bh_is_connected(struct dcerpc_binding_handle *h)
+{
+       struct tstream_bh_state *hs = dcerpc_binding_handle_data(
+               h, struct tstream_bh_state);
+       ssize_t ret;
+
+       if (hs->stream == NULL) {
+               return false;
+       }
+
+       ret = tstream_pending_bytes(hs->stream);
+       if (ret == -1) {
+               return false;
+       }
+
+       return true;
+}
+
+static uint32_t tstream_bh_set_timeout(struct dcerpc_binding_handle *h,
+                                      uint32_t timeout)
+{
+       struct tstream_bh_state *hs = dcerpc_binding_handle_data(
+               h, struct tstream_bh_state);
+       uint32_t old;
+
+       old = hs->request_timeout;
+       hs->request_timeout = timeout;
+
+       return old;
+}
+
+struct tstream_bh_disconnect_state {
+       struct tstream_bh_state *hs;
+};
+
+static void tstream_bh_disconnect_done(struct tevent_req *subreq);
+
+static struct tevent_req *tstream_bh_disconnect_send(
+       TALLOC_CTX *mem_ctx,
+       struct tevent_context *ev,
+       struct dcerpc_binding_handle *h)
+{
+       struct tstream_bh_state *hs = dcerpc_binding_handle_data(
+               h, struct tstream_bh_state);
+       struct tevent_req *req = NULL;
+       struct tstream_bh_disconnect_state *state = NULL;
+       struct tevent_req *subreq = NULL;
+       bool ok;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct tstream_bh_disconnect_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       state->hs = hs;
+
+       ok = tstream_bh_is_connected(h);
+       if (!ok) {
+               tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
+               return tevent_req_post(req, ev);
+       }
+
+       subreq = tstream_disconnect_send(state, ev, hs->stream);
+       if (tevent_req_nomem(subreq, req)) {
+               tevent_req_post(req, ev);
+               return req;
+       }
+       tevent_req_set_callback(subreq, tstream_bh_disconnect_done, req);
+
+       return req;
+}
+
+static void tstream_bh_disconnect_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct tstream_bh_disconnect_state *state = tevent_req_data(
+               req, struct tstream_bh_disconnect_state);
+       int ret, err;
+
+       ret = tstream_disconnect_recv(subreq, &err);
+       TALLOC_FREE(subreq);
+       if (ret != 0) {
+               DBG_ERR("tstream_bh_disconnect failed [%s]\n", strerror(err));
+               tevent_req_nterror(req, map_nt_error_from_unix_common(err));
+               return;
+       }
+
+       state->hs->stream = NULL;
+}
+
+static NTSTATUS tstream_bh_disconnect_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 tstream_bh_call_state {
+       struct tevent_context *ev;
+       struct tstream_context *stream;
+       struct tstream_bh_state *hs;
+       struct iovec out_data;
+       DATA_BLOB in_data;
+};
+
+static void tstream_bh_call_writev_done(struct tevent_req *subreq);
+static void tstream_bh_call_read_pdu_done(struct tevent_req *subreq);
+
+static struct tevent_req *tstream_bh_call_send(TALLOC_CTX *mem_ctx,
+                                              struct tevent_context *ev,
+                                              struct dcerpc_binding_handle *h,
+                                              const struct GUID *object,
+                                              uint32_t opnum,
+                                              uint32_t in_flags,
+                                              const uint8_t *out_data,
+                                              size_t out_length)
+{
+       struct tstream_bh_state *hs = dcerpc_binding_handle_data(
+               h, struct tstream_bh_state);
+       struct tevent_req *req = NULL;
+       struct tevent_req *subreq = NULL;
+       struct tstream_bh_call_state* state = NULL;
+       struct timeval timeout;
+       bool ok;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct tstream_bh_call_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       *state = (struct tstream_bh_call_state) {
+               .ev = ev,
+               .stream = hs->stream,
+               .hs = hs,
+               .out_data = {
+                       .iov_base = discard_const_p(uint8_t, out_data),
+                       .iov_len = out_length,
+               },
+       };
+
+       ok = tstream_bh_is_connected(h);
+       if (!ok) {
+               tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
+               return tevent_req_post(req, ev);
+       }
+
+       if (tstream_is_smbXcli_np(hs->stream)) {
+               tstream_smbXcli_np_use_trans(hs->stream);
+       }
+       if (tevent_queue_length(hs->write_queue) > 0) {
+               tevent_req_nterror(req, NT_STATUS_PIPE_BUSY);
+       }
+
+       timeout = timeval_current_ofs(hs->request_timeout, 0);
+
+       subreq = tstream_writev_queue_send(state, ev,
+                                          state->stream,
+                                          hs->write_queue,
+                                          &state->out_data, 1);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       if (!tevent_req_set_endtime(subreq, ev, timeout)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, tstream_bh_call_writev_done, req);
+
+       subreq = tstream_read_pdu_blob_send(state,
+                                           ev,
+                                           hs->stream,
+                                           hs->call_initial_read_size,
+                                           hs->complete_pdu_fn,
+                                           hs->complete_pdu_fn_private);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       if (!tevent_req_set_endtime(subreq, ev, timeout)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, tstream_bh_call_read_pdu_done, req);
+
+       return req;
+}
+
+static void tstream_bh_call_writev_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct tstream_bh_call_state *state = tevent_req_data(
+               req, struct tstream_bh_call_state);
+       int ret, err;
+
+       ret = tstream_writev_queue_recv(subreq, &err);
+       TALLOC_FREE(subreq);
+       if (ret == -1) {
+               state->hs->stream = NULL;
+               tevent_req_nterror(req, map_nt_error_from_unix_common(err));
+               return;
+       }
+}
+
+static void tstream_bh_call_read_pdu_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct tstream_bh_call_state *state = tevent_req_data(
+               req, struct tstream_bh_call_state);
+       NTSTATUS status;
+
+       status = tstream_read_pdu_blob_recv(subreq, state, &state->in_data);
+       TALLOC_FREE(subreq);
+       if (!NT_STATUS_IS_OK(status)) {
+               state->hs->stream = NULL;
+               tevent_req_nterror(req, status);
+               return;
+       }
+
+       tevent_req_done(req);
+}
+
+static NTSTATUS tstream_bh_call_recv(struct tevent_req *req,
+                                    TALLOC_CTX *mem_ctx,
+                                    uint8_t **in_data,
+                                    size_t *in_length,
+                                    uint32_t *in_flags)
+{
+       NTSTATUS status;
+       struct tstream_bh_call_state *state = tevent_req_data(
+               req, struct tstream_bh_call_state);
+
+       if (tevent_req_is_nterror(req, &status)) {
+               tevent_req_received(req);
+               return status;
+       }
+
+       *in_data = talloc_move(mem_ctx, &state->in_data.data);
+       *in_length = state->in_data.length;
+
+       tevent_req_received(req);
+       return NT_STATUS_OK;
+}
+
+static const struct dcerpc_binding_handle_ops tstream_bh_ops = {
+       .name                   = "tstream_binding_handle",
+       .is_connected           = tstream_bh_is_connected,
+       .set_timeout            = tstream_bh_set_timeout,
+       .raw_call_send          = tstream_bh_call_send,
+       .raw_call_recv          = tstream_bh_call_recv,
+       .disconnect_send        = tstream_bh_disconnect_send,
+       .disconnect_recv        = tstream_bh_disconnect_recv,
+};
+
+struct dcerpc_binding_handle *tstream_binding_handle_create(
+       TALLOC_CTX *mem_ctx,
+       const struct ndr_interface_table *table,
+       struct tstream_context **stream,
+       size_t call_initial_read_size,
+       tstream_read_pdu_blob_full_fn_t *complete_pdu_fn,
+       void *complete_pdu_fn_private,
+       uint32_t max_data)
+{
+       struct dcerpc_binding_handle *h = NULL;
+       struct tstream_bh_state *hs = NULL;
+
+       h = dcerpc_binding_handle_create(mem_ctx,
+                                        &tstream_bh_ops,
+                                        NULL,
+                                        table,
+                                        &hs,
+                                        struct tstream_bh_state,
+                                        __location__);
+       if (h == NULL) {
+               return NULL;
+       }
+
+       hs->table = table;
+       hs->stream = talloc_move(hs, stream);
+       hs->call_initial_read_size = call_initial_read_size;
+       hs->complete_pdu_fn = complete_pdu_fn;
+       hs->complete_pdu_fn_private = complete_pdu_fn_private;
+
+       hs->write_queue = tevent_queue_create(hs, "write_queue");
+       if (hs->write_queue == NULL) {
+               TALLOC_FREE(h);
+               return NULL;
+       }
+
+       if (max_data > 0) {
+               tstream_smbXcli_np_set_max_data(hs->stream, max_data);
+       }
+
+       return h;
+}
diff --git a/libcli/tstream_binding_handle/tstream_binding_handle.h b/libcli/tstream_binding_handle/tstream_binding_handle.h
new file mode 100644 (file)
index 0000000..a43e242
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   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 _TSTREAM_BINDING_HANDLE_H_
+#define _TSTREAM_BINDING_HANDLE_H_
+
+#include <talloc.h>
+#include "librpc/rpc/dcerpc.h"
+#include "librpc/rpc/dcerpc_proto.h"
+#include "librpc/rpc/rpc_common.h"
+#include "libcli/util/tstream.h"
+
+struct dcerpc_binding_handle *tstream_binding_handle_create(
+       TALLOC_CTX *mem_ctx,
+       const struct ndr_interface_table *table,
+       struct tstream_context **stream,
+       size_t call_initial_read_size,
+       tstream_read_pdu_blob_full_fn_t *complete_pdu_fn,
+       void *complete_pdu_fn_private,
+       uint32_t max_data);
+
+#endif /* _TSTREAM_BINDING_HANDLE_H_ */
diff --git a/libcli/tstream_binding_handle/wscript_build b/libcli/tstream_binding_handle/wscript_build
new file mode 100644 (file)
index 0000000..622ed70
--- /dev/null
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+bld.SAMBA_SUBSYSTEM('tstream_binding_handle',
+                    source='tstream_binding_handle.c',
+                    deps='tevent LIBTSOCKET')
index 19fc31054d11740daead840ce6dca5a8d8b0b74d..9379da5a098c2022b8d4c71f5d2bb10f8b15e25f 100644 (file)
@@ -124,6 +124,7 @@ bld.RECURSE('source4/lib/policy')
 bld.RECURSE('libcli/named_pipe_auth')
 if bld.CONFIG_GET('ENABLE_SELFTEST'):
     bld.RECURSE('testsuite/unittests')
+bld.RECURSE('libcli/tstream_binding_handle')
 
 if bld.CONFIG_GET('KRB5_VENDOR') in (None, 'heimdal'):
     if bld.CONFIG_GET("HEIMDAL_KRB5_CONFIG") and bld.CONFIG_GET("USING_SYSTEM_KRB5"):