librpc/rpc: add dcerpc_pipe_handle* infrastructure
authorStefan Metzmacher <metze@samba.org>
Sat, 2 Oct 2010 03:54:21 +0000 (05:54 +0200)
committerStefan Metzmacher <metze@samba.org>
Tue, 4 Jun 2019 11:14:55 +0000 (13:14 +0200)
Signed-off-by: Stefan Metzmacher <metze@samba.org>
librpc/rpc/pipe_handle.c [new file with mode: 0644]
librpc/rpc/rpc_common.h
librpc/wscript_build

diff --git a/librpc/rpc/pipe_handle.c b/librpc/rpc/pipe_handle.c
new file mode 100644 (file)
index 0000000..30231c1
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   dcerpc pipe handle functions
+
+   Copyright (C) Stefan Metzmacher 2010,2013
+
+   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 "../lib/util/tevent_ntstatus.h"
+#include "librpc/rpc/dcerpc.h"
+#include "rpc_common.h"
+
+struct dcerpc_pipe_handle_connection {
+       const char *chunk_struct_name;
+       size_t chunk_struct_size;
+       struct dcerpc_pipe_handle *p;
+       bool push;
+};
+
+struct dcerpc_pipe_handle {
+       void *private_data;
+       const struct dcerpc_pipe_handle_ops *ops;
+       const char *location;
+       struct dcerpc_pipe_handle_connection *pc;
+       struct tevent_req *current_req;
+};
+
+struct dcerpc_pipe_handle_connection *dcerpc_pipe_handle_connection_create(
+                                       TALLOC_CTX *mem_ctx,
+                                       const char *chunk_struct_name,
+                                       size_t chunk_struct_size)
+{
+       struct dcerpc_pipe_handle_connection *pc;
+
+       pc = talloc_zero(mem_ctx, struct dcerpc_pipe_handle_connection);
+       if (pc == NULL) {
+               return NULL;
+       }
+
+       pc->chunk_struct_name = talloc_strdup(pc, chunk_struct_name);
+       if (pc->chunk_struct_name == NULL) {
+               TALLOC_FREE(pc);
+               return NULL;
+       }
+
+       pc->chunk_struct_size = chunk_struct_size;
+
+       return pc;
+}
+
+bool _dcerpc_pipe_handle_connection_connect(
+                               struct dcerpc_pipe_handle_connection *pc,
+                               const char *chunk_struct_name,
+                               size_t chunk_struct_size,
+                               struct dcerpc_pipe_handle *p,
+                               bool push)
+{
+       if (pc->chunk_struct_size != chunk_struct_size) {
+               return false;
+       }
+
+       if (strcmp(pc->chunk_struct_name, chunk_struct_name) != 0) {
+               return false;
+       }
+
+       pc->p = p;
+       p->pc = pc;
+
+       pc->push = push;
+
+       return true;
+}
+
+void dcerpc_pipe_handle_connection_disconnect(
+                               struct dcerpc_pipe_handle_connection *pc)
+{
+       if (pc == NULL) {
+               return;
+       }
+
+       if (pc->p != NULL) {
+               pc->p->pc = NULL;
+       }
+
+       pc->p = NULL;
+}
+
+static int dcerpc_pipe_handle_destructor(struct dcerpc_pipe_handle *p)
+{
+       dcerpc_pipe_handle_connection_disconnect(p->pc);
+
+       if (p->current_req) {
+               tevent_req_received(p->current_req);
+       }
+
+       return 0;
+}
+
+struct dcerpc_pipe_handle *_dcerpc_pipe_handle_create(
+                                       TALLOC_CTX *mem_ctx,
+                                       const struct dcerpc_pipe_handle_ops *ops,
+                                       void *pstate,
+                                       size_t psize,
+                                       const char *type,
+                                       const char *location)
+{
+       struct dcerpc_pipe_handle *p;
+       void **ppstate = (void **)pstate;
+       void *state;
+
+       p = talloc_zero(mem_ctx, struct dcerpc_pipe_handle);
+       if (p == NULL) {
+               return NULL;
+       }
+       p->ops          = ops;
+       p->location     = location;
+
+       state = talloc_zero_size(p, psize);
+       if (state == NULL) {
+               talloc_free(p);
+               return NULL;
+       }
+       talloc_set_name_const(state, type);
+
+       p->private_data = state;
+
+       talloc_set_destructor(p, dcerpc_pipe_handle_destructor);
+
+       *ppstate = state;
+       return p;
+}
+
+void *_dcerpc_pipe_handle_data(struct dcerpc_pipe_handle *p)
+{
+       return p->private_data;
+}
+
+struct dcerpc_pipe_handle_push_state {
+       const struct dcerpc_pipe_handle_ops *ops;
+       struct dcerpc_pipe_handle *p;
+};
+
+static int dcerpc_pipe_handle_push_state_destructor(
+       struct dcerpc_pipe_handle_push_state *state)
+{
+       if (state->p) {
+               state->p->current_req = NULL;
+       }
+
+       return 0;
+}
+
+static void dcerpc_pipe_handle_push_done(struct tevent_req *subreq);
+
+struct tevent_req *dcerpc_pipe_handle_push_send(TALLOC_CTX *mem_ctx,
+                                       struct tevent_context *ev,
+                                       struct dcerpc_pipe_handle_connection *pc,
+                                       const void *chunk_ptr)
+{
+       struct dcerpc_pipe_handle *p = pc->p;
+       struct tevent_req *req;
+       struct dcerpc_pipe_handle_push_state *state;
+       struct tevent_req *subreq;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct dcerpc_pipe_handle_push_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       if (p == NULL) {
+               tevent_req_nterror(req, NT_STATUS_RPC_PIPE_DISCIPLINE_ERROR);
+               return tevent_req_post(req, ev);
+       }
+
+       if (!pc->push) {
+               tevent_req_nterror(req, NT_STATUS_RPC_PIPE_DISCIPLINE_ERROR);
+               return tevent_req_post(req, ev);
+       }
+
+       if (p->current_req) {
+               tevent_req_nterror(req, NT_STATUS_RPC_PIPE_DISCIPLINE_ERROR);
+               return tevent_req_post(req, ev);
+       }
+
+       state->ops = p->ops;
+       state->p = p;
+
+       talloc_set_destructor(state, dcerpc_pipe_handle_push_state_destructor);
+       p->current_req = req;
+
+       subreq = p->ops->chunk_push_send(state, ev, p, chunk_ptr);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       tevent_req_set_callback(subreq, dcerpc_pipe_handle_push_done, req);
+
+       return req;
+}
+
+static void dcerpc_pipe_handle_push_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq,
+               struct tevent_req);
+       struct dcerpc_pipe_handle_push_state *state =
+               tevent_req_data(req,
+               struct dcerpc_pipe_handle_push_state);
+       NTSTATUS status;
+
+       status = state->ops->chunk_push_recv(subreq);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+
+       tevent_req_done(req);
+}
+
+NTSTATUS dcerpc_pipe_handle_push_recv(struct tevent_req *req)
+{
+       return tevent_req_simple_recv_ntstatus(req);
+}
+
+struct dcerpc_pipe_handle_pull_state {
+       const struct dcerpc_pipe_handle_ops *ops;
+       struct dcerpc_pipe_handle *p;
+};
+
+static int dcerpc_pipe_handle_pull_state_destructor(
+       struct dcerpc_pipe_handle_pull_state *state)
+{
+       if (state->p) {
+               state->p->current_req = NULL;
+       }
+
+       return 0;
+}
+
+static void dcerpc_pipe_handle_pull_done(struct tevent_req *subreq);
+
+struct tevent_req *dcerpc_pipe_handle_pull_send(TALLOC_CTX *mem_ctx,
+                                       struct tevent_context *ev,
+                                       struct dcerpc_pipe_handle_connection *pc,
+                                       void *chunk_mem,
+                                       void *chunk_ptr)
+{
+       struct dcerpc_pipe_handle *p = pc->p;
+       struct tevent_req *req;
+       struct dcerpc_pipe_handle_pull_state *state;
+       struct tevent_req *subreq;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct dcerpc_pipe_handle_pull_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       if (p == NULL) {
+               tevent_req_nterror(req, NT_STATUS_RPC_PIPE_DISCIPLINE_ERROR);
+               return tevent_req_post(req, ev);
+       }
+
+       if (pc->push) {
+               tevent_req_nterror(req, NT_STATUS_RPC_PIPE_DISCIPLINE_ERROR);
+               return tevent_req_post(req, ev);
+       }
+
+       if (p->current_req) {
+               tevent_req_nterror(req, NT_STATUS_RPC_PIPE_DISCIPLINE_ERROR);
+               return tevent_req_post(req, ev);
+       }
+
+       state->ops = p->ops;
+       state->p = p;
+
+       talloc_set_destructor(state, dcerpc_pipe_handle_pull_state_destructor);
+       p->current_req = req;
+
+       subreq = p->ops->chunk_pull_send(state, ev, p, chunk_mem, chunk_ptr);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       tevent_req_set_callback(subreq, dcerpc_pipe_handle_pull_done, req);
+
+       return req;
+}
+
+static void dcerpc_pipe_handle_pull_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq,
+               struct tevent_req);
+       struct dcerpc_pipe_handle_pull_state *state =
+               tevent_req_data(req,
+               struct dcerpc_pipe_handle_pull_state);
+       NTSTATUS status;
+
+       status = state->ops->chunk_pull_recv(subreq);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+
+       tevent_req_done(req);
+}
+
+NTSTATUS dcerpc_pipe_handle_pull_recv(struct tevent_req *req)
+{
+       return tevent_req_simple_recv_ntstatus(req);
+}
index 1fbdb665f9f3e95ebbc61cdce3e358c834009f9b..e2ea739cf3d18a349c5cb36a95c34ef094473881 100644 (file)
@@ -26,6 +26,8 @@
 #include "lib/util/attr.h"
 
 struct dcerpc_binding_handle;
+struct dcerpc_pipe_handle;
+struct dcerpc_pipe_handle_connection;
 struct GUID;
 struct ndr_interface_table;
 struct ndr_interface_call;
@@ -456,4 +458,67 @@ struct ndr_syntax_id dcerpc_construct_bind_time_features(uint64_t features);
        (DCERPC_AUTH_PAD_ALIGNMENT - (stub_length) % DCERPC_AUTH_PAD_ALIGNMENT):\
        0)
 
+struct dcerpc_pipe_handle_connection *dcerpc_pipe_handle_connection_create(
+                                       TALLOC_CTX *mem_ctx,
+                                       const char *chunk_struct_name,
+                                       size_t chunk_struct_size);
+bool _dcerpc_pipe_handle_connection_connect(
+                               struct dcerpc_pipe_handle_connection *pc,
+                               const char *chunk_struct_name,
+                               size_t chunk_struct_size,
+                               struct dcerpc_pipe_handle *p,
+                               bool push);
+#define dcerpc_pipe_handle_connection_push_connect(pc, csn, css, p) \
+       _dcerpc_pipe_handle_connection_connect(pc, csn, css, p, true)
+#define dcerpc_pipe_handle_connection_pull_connect(pc, csn, css, p) \
+       _dcerpc_pipe_handle_connection_connect(pc, csn, css, p, false)
+void dcerpc_pipe_handle_connection_disconnect(
+                               struct dcerpc_pipe_handle_connection *pc);
+
+struct dcerpc_pipe_handle_ops {
+       const char *name;
+
+       struct tevent_req *(*chunk_push_send)(TALLOC_CTX *mem_ctx,
+                                           struct tevent_context *ev,
+                                           struct dcerpc_pipe_handle *p,
+                                           const void *chunk_ptr);
+       NTSTATUS (*chunk_push_recv)(struct tevent_req *req);
+
+       struct tevent_req *(*chunk_pull_send)(TALLOC_CTX *mem_ctx,
+                                           struct tevent_context *ev,
+                                           struct dcerpc_pipe_handle *p,
+                                           void *chunk_mem,
+                                           void *chunk_ptr);
+       NTSTATUS (*chunk_pull_recv)(struct tevent_req *req);
+};
+
+struct dcerpc_pipe_handle *_dcerpc_pipe_handle_create(
+                                       TALLOC_CTX *mem_ctx,
+                                       const struct dcerpc_pipe_handle_ops *ops,
+                                       void *pstate,
+                                       size_t psize,
+                                       const char *type,
+                                       const char *location);
+#define dcerpc_pipe_handle_create(mem_ctx, ops, \
+                                 state, type) \
+       _dcerpc_pipe_handle_create(mem_ctx, ops, \
+                               state, sizeof(type), #type, __location__)
+
+void *_dcerpc_pipe_handle_data(struct dcerpc_pipe_handle *p);
+#define dcerpc_pipe_handle_data(_p, _type) \
+       talloc_get_type_abort(_dcerpc_pipe_handle_data(_p), _type)
+
+struct tevent_req *dcerpc_pipe_handle_push_send(TALLOC_CTX *mem_ctx,
+                                       struct tevent_context *ev,
+                                       struct dcerpc_pipe_handle_connection *pc,
+                                       const void *chunk_ptr);
+NTSTATUS dcerpc_pipe_handle_push_recv(struct tevent_req *req);
+
+struct tevent_req *dcerpc_pipe_handle_pull_send(TALLOC_CTX *mem_ctx,
+                                       struct tevent_context *ev,
+                                       struct dcerpc_pipe_handle_connection *pc,
+                                       void *chunk_mem,
+                                       void *chunk_ptr);
+NTSTATUS dcerpc_pipe_handle_pull_recv(struct tevent_req *req);
+
 #endif /* __DEFAULT_LIBRPC_RPCCOMMON_H__ */
index 8e113c422b21e9e356cdda2e8f49c2b1cf824465..6b68e1da413d76af7af57522ee7cf2a853d27368 100644 (file)
@@ -731,7 +731,7 @@ bld.SAMBA_LIBRARY('ndr',
     )
 
 bld.SAMBA_LIBRARY('dcerpc-binding',
-    source='rpc/dcerpc_error.c rpc/binding.c rpc/dcerpc_util.c rpc/binding_handle.c',
+    source='rpc/dcerpc_error.c rpc/binding.c rpc/dcerpc_util.c rpc/binding_handle.c rpc/pipe_handle.c',
     deps='ndr tevent NDR_DCERPC LIBTSOCKET tevent-util gensec',
     pc_files=[],
     public_headers='rpc/rpc_common.h',