--- /dev/null
+/*
+ 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);
+}
#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;
(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__ */