diff options
-rw-r--r-- | source3/Makefile.in | 1 | ||||
-rw-r--r-- | source3/include/client.h | 3 | ||||
-rw-r--r-- | source3/librpc/rpc/dcerpc.h | 128 | ||||
-rw-r--r-- | source3/rpc_client/cli_pipe.c | 244 |
4 files changed, 376 insertions, 0 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index fbb479c531..12086c246c 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -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) diff --git a/source3/include/client.h b/source3/include/client.h index 505f7e4d3c..c702996b8b 100644 --- a/source3/include/client.h +++ b/source3/include/client.h @@ -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; diff --git a/source3/librpc/rpc/dcerpc.h b/source3/librpc/rpc/dcerpc.h index f07403ae44..117d860199 100644 --- a/source3/librpc/rpc/dcerpc.h +++ b/source3/librpc/rpc/dcerpc.h @@ -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__ */ diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c index b38000ea94..18724a6fa8 100644 --- a/source3/rpc_client/cli_pipe.c +++ b/source3/rpc_client/cli_pipe.c @@ -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; } |