s3:rpc_client: add dcerpc_binding_handle backend
authorStefan Metzmacher <metze@samba.org>
Fri, 6 Aug 2010 09:30:51 +0000 (11:30 +0200)
committerStefan Metzmacher <metze@samba.org>
Thu, 12 Aug 2010 12:31:21 +0000 (14:31 +0200)
metze

source3/Makefile.in
source3/include/client.h
source3/librpc/rpc/dcerpc.h
source3/rpc_client/cli_pipe.c

index fbb479c531435b4d6fb4986ceebe0e6790910c23..12086c246c9ea10b4f37741a6f947c6205e967a7 100644 (file)
@@ -570,6 +570,7 @@ LIBMSRPC_GEN_OBJ = librpc/gen_ndr/cli_lsa.o \
                   librpc/gen_ndr/cli_drsuapi.o \
                   librpc/gen_ndr/cli_spoolss.o \
                   ../librpc/rpc/dcerpc_util.o \
+                  ../librpc/rpc/binding_handle.o \
                   librpc/rpc/dcerpc_helpers.o \
                   $(LIBNDR_GEN_OBJ) \
                   $(RPCCLIENT_NDR_OBJ)
index 505f7e4d3c57f072d1cc23c67d1c0e8eb3c38e66..c702996b8bfd77e7777c82db31d8b9e7b0d6580f 100644 (file)
@@ -104,10 +104,13 @@ struct rpc_cli_transport {
        void *priv;
 };
 
+struct dcerpc_binding_handle;
+
 struct rpc_pipe_client {
        struct rpc_pipe_client *prev, *next;
 
        struct rpc_cli_transport *transport;
+       struct dcerpc_binding_handle *binding_handle;
 
        struct ndr_syntax_id abstract_syntax;
        struct ndr_syntax_id transfer_syntax;
index f07403ae44e3fa9e3eb63947d62fafe5777a1974..117d860199e99e78834af909cf5f8f1bc4f6e7d3 100644 (file)
@@ -153,4 +153,132 @@ NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth,
                           DATA_BLOB *raw_pkt,
                           size_t *pad_len);
 
+struct dcerpc_binding_handle;
+struct GUID;
+struct ndr_interface_table;
+struct ndr_interface_call;
+struct ndr_push;
+struct ndr_pull;
+struct tevent_context;
+
+/*
+ * This is just a hack this should never be used in code,
+ * but it's needed to build the compat stubs for now
+ */
+struct __do_not_use_dcerpc_pipe {
+       struct dcerpc_binding_handle *binding_handle;
+};
+#define dcerpc_pipe __do_not_use_dcerpc_pipe
+
+
+struct dcerpc_binding_handle_ops {
+       const char *name;
+
+       bool (*is_connected)(struct dcerpc_binding_handle *h);
+
+       struct tevent_req *(*raw_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 *in_data,
+                                           size_t in_length);
+       NTSTATUS (*raw_call_recv)(struct tevent_req *req,
+                                 TALLOC_CTX *mem_ctx,
+                                 uint8_t **out_data,
+                                 size_t *out_length,
+                                 uint32_t *out_flags);
+
+       struct tevent_req *(*disconnect_send)(TALLOC_CTX *mem_ctx,
+                                             struct tevent_context *ev,
+                                             struct dcerpc_binding_handle *h);
+       NTSTATUS (*disconnect_recv)(struct tevent_req *req);
+
+       /* TODO: remove the following functions */
+       bool (*push_bigendian)(struct dcerpc_binding_handle *h);
+       bool (*ref_alloc)(struct dcerpc_binding_handle *h);
+       bool (*use_ndr64)(struct dcerpc_binding_handle *h);
+       void (*do_ndr_print)(struct dcerpc_binding_handle *h,
+                            int ndr_flags,
+                            const void *struct_ptr,
+                            const struct ndr_interface_call *call);
+       void (*ndr_push_failed)(struct dcerpc_binding_handle *h,
+                               NTSTATUS error,
+                               const void *struct_ptr,
+                               const struct ndr_interface_call *call);
+       void (*ndr_pull_failed)(struct dcerpc_binding_handle *h,
+                               NTSTATUS error,
+                               const DATA_BLOB *blob,
+                               const struct ndr_interface_call *call);
+       NTSTATUS (*ndr_validate_in)(struct dcerpc_binding_handle *h,
+                                   TALLOC_CTX *mem_ctx,
+                                   const DATA_BLOB *blob,
+                                   const struct ndr_interface_call *call);
+       NTSTATUS (*ndr_validate_out)(struct dcerpc_binding_handle *h,
+                                    struct ndr_pull *pull_in,
+                                    const void *struct_ptr,
+                                    const struct ndr_interface_call *call);
+};
+
+struct dcerpc_binding_handle *_dcerpc_binding_handle_create(TALLOC_CTX *mem_ctx,
+                                       const struct dcerpc_binding_handle_ops *ops,
+                                       const struct GUID *object,
+                                       const struct ndr_interface_table *table,
+                                       void *pstate,
+                                       size_t psize,
+                                       const char *type,
+                                       const char *location);
+#define dcerpc_binding_handle_create(mem_ctx, ops, object, table, \
+                               state, type, location) \
+       _dcerpc_binding_handle_create(mem_ctx, ops, object, table, \
+                               state, sizeof(type), #type, location)
+
+void *_dcerpc_binding_handle_data(struct dcerpc_binding_handle *h);
+#define dcerpc_binding_handle_data(_h, _type) \
+       talloc_get_type_abort(_dcerpc_binding_handle_data(_h), _type)
+
+_DEPRECATED_ void dcerpc_binding_handle_set_ref_alloc(struct dcerpc_binding_handle *h,
+                                                     bool ref_alloc);
+
+_DEPRECATED_ void dcerpc_binding_handle_set_sync_ev(struct dcerpc_binding_handle *h,
+                                                   struct tevent_context *ev);
+
+bool dcerpc_binding_handle_is_connected(struct dcerpc_binding_handle *h);
+
+struct tevent_req *dcerpc_binding_handle_raw_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 *in_data,
+                                               size_t in_length);
+NTSTATUS dcerpc_binding_handle_raw_call_recv(struct tevent_req *req,
+                                            TALLOC_CTX *mem_ctx,
+                                            uint8_t **out_data,
+                                            size_t *out_length,
+                                            uint32_t *out_flags);
+
+struct tevent_req *dcerpc_binding_handle_disconnect_send(TALLOC_CTX *mem_ctx,
+                                               struct tevent_context *ev,
+                                               struct dcerpc_binding_handle *h);
+NTSTATUS dcerpc_binding_handle_disconnect_recv(struct tevent_req *req);
+
+struct tevent_req *dcerpc_binding_handle_call_send(TALLOC_CTX *mem_ctx,
+                                       struct tevent_context *ev,
+                                       struct dcerpc_binding_handle *h,
+                                       const struct GUID *object,
+                                       const struct ndr_interface_table *table,
+                                       uint32_t opnum,
+                                       TALLOC_CTX *r_mem,
+                                       void *r_ptr);
+NTSTATUS dcerpc_binding_handle_call_recv(struct tevent_req *req);
+NTSTATUS dcerpc_binding_handle_call(struct dcerpc_binding_handle *h,
+                                   const struct GUID *object,
+                                   const struct ndr_interface_table *table,
+                                   uint32_t opnum,
+                                   TALLOC_CTX *r_mem,
+                                   void *r_ptr);
+
 #endif /* __DCERPC_H__ */
index b38000ea94d85d4d9ba0ff0797c6573f831df352..18724a6fa88350c3aba710ad91ebbb60ecad1683 100644 (file)
@@ -2019,6 +2019,226 @@ bool rpccli_is_connected(struct rpc_pipe_client *rpc_cli)
        return rpc_cli->transport->is_connected(rpc_cli->transport->priv);
 }
 
+struct rpccli_bh_state {
+       struct rpc_pipe_client *rpc_cli;
+};
+
+static bool rpccli_bh_is_connected(struct dcerpc_binding_handle *h)
+{
+       struct rpccli_bh_state *hs = dcerpc_binding_handle_data(h,
+                                    struct rpccli_bh_state);
+
+       return rpccli_is_connected(hs->rpc_cli);
+}
+
+struct rpccli_bh_raw_call_state {
+       DATA_BLOB in_data;
+       DATA_BLOB out_data;
+       uint32_t out_flags;
+};
+
+static void rpccli_bh_raw_call_done(struct tevent_req *subreq);
+
+static struct tevent_req *rpccli_bh_raw_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 *in_data,
+                                                 size_t in_length)
+{
+       struct rpccli_bh_state *hs = dcerpc_binding_handle_data(h,
+                                    struct rpccli_bh_state);
+       struct tevent_req *req;
+       struct rpccli_bh_raw_call_state *state;
+       bool ok;
+       struct tevent_req *subreq;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct rpccli_bh_raw_call_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       state->in_data.data = discard_const_p(uint8_t, in_data);
+       state->in_data.length = in_length;
+
+       ok = rpccli_bh_is_connected(h);
+       if (!ok) {
+               tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
+               return tevent_req_post(req, ev);
+       }
+
+       subreq = rpc_api_pipe_req_send(state, ev, hs->rpc_cli,
+                                      opnum, &state->in_data);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, rpccli_bh_raw_call_done, req);
+
+       return req;
+}
+
+static void rpccli_bh_raw_call_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq,
+               struct tevent_req);
+       struct rpccli_bh_raw_call_state *state =
+               tevent_req_data(req,
+               struct rpccli_bh_raw_call_state);
+       NTSTATUS status;
+
+       state->out_flags = 0;
+
+       /* TODO: support bigendian responses */
+
+       status = rpc_api_pipe_req_recv(subreq, state, &state->out_data);
+       TALLOC_FREE(subreq);
+       if (!NT_STATUS_IS_OK(status)) {
+               tevent_req_nterror(req, status);
+               return;
+       }
+
+       tevent_req_done(req);
+}
+
+static NTSTATUS rpccli_bh_raw_call_recv(struct tevent_req *req,
+                                       TALLOC_CTX *mem_ctx,
+                                       uint8_t **out_data,
+                                       size_t *out_length,
+                                       uint32_t *out_flags)
+{
+       struct rpccli_bh_raw_call_state *state =
+               tevent_req_data(req,
+               struct rpccli_bh_raw_call_state);
+       NTSTATUS status;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               tevent_req_received(req);
+               return status;
+       }
+
+       *out_data = talloc_move(mem_ctx, &state->out_data.data);
+       *out_length = state->out_data.length;
+       *out_flags = state->out_flags;
+       tevent_req_received(req);
+       return NT_STATUS_OK;
+}
+
+struct rpccli_bh_disconnect_state {
+       uint8_t _dummy;
+};
+
+static struct tevent_req *rpccli_bh_disconnect_send(TALLOC_CTX *mem_ctx,
+                                               struct tevent_context *ev,
+                                               struct dcerpc_binding_handle *h)
+{
+       struct rpccli_bh_state *hs = dcerpc_binding_handle_data(h,
+                                    struct rpccli_bh_state);
+       struct tevent_req *req;
+       struct rpccli_bh_disconnect_state *state;
+       bool ok;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct rpccli_bh_disconnect_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       ok = rpccli_bh_is_connected(h);
+       if (!ok) {
+               tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
+               return tevent_req_post(req, ev);
+       }
+
+       /*
+        * TODO: do a real async disconnect ...
+        *
+        * For now the caller needs to free rpc_cli
+        */
+       hs->rpc_cli = NULL;
+
+       tevent_req_done(req);
+       return tevent_req_post(req, ev);
+}
+
+static NTSTATUS rpccli_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;
+}
+
+static bool rpccli_bh_ref_alloc(struct dcerpc_binding_handle *h)
+{
+       return true;
+}
+
+static void rpccli_bh_do_ndr_print(struct dcerpc_binding_handle *h,
+                                  int ndr_flags,
+                                  const void *_struct_ptr,
+                                  const struct ndr_interface_call *call)
+{
+       void *struct_ptr = discard_const(_struct_ptr);
+
+       if (DEBUGLEVEL < 10) {
+               return;
+       }
+
+       if (ndr_flags & NDR_IN) {
+               ndr_print_function_debug(call->ndr_print,
+                                        call->name,
+                                        ndr_flags,
+                                        struct_ptr);
+       }
+       if (ndr_flags & NDR_OUT) {
+               ndr_print_function_debug(call->ndr_print,
+                                        call->name,
+                                        ndr_flags,
+                                        struct_ptr);
+       }
+}
+
+static const struct dcerpc_binding_handle_ops rpccli_bh_ops = {
+       .name                   = "rpccli",
+       .is_connected           = rpccli_bh_is_connected,
+       .raw_call_send          = rpccli_bh_raw_call_send,
+       .raw_call_recv          = rpccli_bh_raw_call_recv,
+       .disconnect_send        = rpccli_bh_disconnect_send,
+       .disconnect_recv        = rpccli_bh_disconnect_recv,
+
+       .ref_alloc              = rpccli_bh_ref_alloc,
+       .do_ndr_print           = rpccli_bh_do_ndr_print,
+};
+
+/* initialise a rpc_pipe_client binding handle */
+static struct dcerpc_binding_handle *rpccli_bh_create(struct rpc_pipe_client *c)
+{
+       struct dcerpc_binding_handle *h;
+       struct rpccli_bh_state *hs;
+
+       h = dcerpc_binding_handle_create(c,
+                                        &rpccli_bh_ops,
+                                        NULL,
+                                        NULL, /* TODO */
+                                        &hs,
+                                        struct rpccli_bh_state,
+                                        __location__);
+       if (h == NULL) {
+               return NULL;
+       }
+       hs->rpc_cli = c;
+
+       return h;
+}
+
 bool rpccli_get_pwd_hash(struct rpc_pipe_client *rpc_cli, uint8_t nt_hash[16])
 {
        struct auth_ntlmssp_state *a = NULL;
@@ -2261,6 +2481,12 @@ static NTSTATUS rpc_pipe_open_tcp_port(TALLOC_CTX *mem_ctx, const char *host,
 
        result->transport->transport = NCACN_IP_TCP;
 
+       result->binding_handle = rpccli_bh_create(result);
+       if (result->binding_handle == NULL) {
+               TALLOC_FREE(result);
+               return NT_STATUS_NO_MEMORY;
+       }
+
        *presult = result;
        return NT_STATUS_OK;
 
@@ -2478,6 +2704,12 @@ NTSTATUS rpc_pipe_open_ncalrpc(TALLOC_CTX *mem_ctx, const char *socket_path,
 
        result->transport->transport = NCALRPC;
 
+       result->binding_handle = rpccli_bh_create(result);
+       if (result->binding_handle == NULL) {
+               TALLOC_FREE(result);
+               return NT_STATUS_NO_MEMORY;
+       }
+
        *presult = result;
        return NT_STATUS_OK;
 
@@ -2566,6 +2798,12 @@ static NTSTATUS rpc_pipe_open_np(struct cli_state *cli,
        DLIST_ADD(np_ref->cli->pipe_list, np_ref->pipe);
        talloc_set_destructor(np_ref, rpc_pipe_client_np_ref_destructor);
 
+       result->binding_handle = rpccli_bh_create(result);
+       if (result->binding_handle == NULL) {
+               TALLOC_FREE(result);
+               return NT_STATUS_NO_MEMORY;
+       }
+
        *presult = result;
        return NT_STATUS_OK;
 }
@@ -2625,6 +2863,12 @@ NTSTATUS rpc_pipe_open_local(TALLOC_CTX *mem_ctx,
 
        result->transport->transport = NCACN_INTERNAL;
 
+       result->binding_handle = rpccli_bh_create(result);
+       if (result->binding_handle == NULL) {
+               TALLOC_FREE(result);
+               return NT_STATUS_NO_MEMORY;
+       }
+
        *presult = result;
        return NT_STATUS_OK;
 }