From 6cf3db91499ebd245b08997a319edf36cfee3365 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Tue, 28 Jul 2009 15:06:11 -0400 Subject: [PATCH] s3:winbind: Add NDR-based parent-child communication to winbind --- nsswitch/winbind_struct_protocol.h | 3 + source3/Makefile.in | 8 +- source3/librpc/gen_ndr/cli_wbint.c | 159 ++++++++++++++++ source3/librpc/gen_ndr/cli_wbint.h | 15 ++ source3/librpc/gen_ndr/ndr_wbint.c | 110 +++++++++++ source3/librpc/gen_ndr/ndr_wbint.h | 18 ++ source3/librpc/gen_ndr/srv_wbint.c | 130 +++++++++++++ source3/librpc/gen_ndr/srv_wbint.h | 9 + source3/librpc/gen_ndr/wbint.h | 22 +++ source3/librpc/idl/wbint.idl | 14 ++ source3/winbindd/winbindd.h | 1 + source3/winbindd/winbindd_domain.c | 4 + source3/winbindd/winbindd_dual.c | 13 ++ source3/winbindd/winbindd_dual_ndr.c | 273 +++++++++++++++++++++++++++ source3/winbindd/winbindd_dual_srv.c | 30 +++ source3/winbindd/winbindd_idmap.c | 4 + source3/winbindd/winbindd_locator.c | 4 + source3/winbindd/winbindd_proto.h | 6 + 18 files changed, 822 insertions(+), 1 deletion(-) create mode 100644 source3/librpc/gen_ndr/cli_wbint.c create mode 100644 source3/librpc/gen_ndr/cli_wbint.h create mode 100644 source3/librpc/gen_ndr/ndr_wbint.c create mode 100644 source3/librpc/gen_ndr/ndr_wbint.h create mode 100644 source3/librpc/gen_ndr/srv_wbint.c create mode 100644 source3/librpc/gen_ndr/srv_wbint.h create mode 100644 source3/librpc/gen_ndr/wbint.h create mode 100644 source3/librpc/idl/wbint.idl create mode 100644 source3/winbindd/winbindd_dual_ndr.c create mode 100644 source3/winbindd/winbindd_dual_srv.c diff --git a/nsswitch/winbind_struct_protocol.h b/nsswitch/winbind_struct_protocol.h index 1785c309066..bd144101f24 100644 --- a/nsswitch/winbind_struct_protocol.h +++ b/nsswitch/winbind_struct_protocol.h @@ -169,6 +169,8 @@ enum winbindd_cmd { WINBINDD_DUAL_USERINFO, WINBINDD_DUAL_GETSIDALIASES, + WINBINDD_DUAL_NDRCMD, + /* Complete the challenge phase of the NTLM authentication protocol using cached password. */ WINBINDD_CCACHE_NTLMAUTH, @@ -247,6 +249,7 @@ struct winbindd_request { fstring groupname; /* getgrnam */ uid_t uid; /* getpwuid, uid_to_sid */ gid_t gid; /* getgrgid, gid_to_sid */ + uint32_t ndrcmd; struct { /* We deliberatedly don't split into domain/user to avoid having the client know what the separator diff --git a/source3/Makefile.in b/source3/Makefile.in index ecfbcd0b9c3..1686a9c8093 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -1138,6 +1138,11 @@ WINBINDD_OBJ1 = \ winbindd/winbindd_ads.o \ winbindd/winbindd_passdb.o \ winbindd/winbindd_dual.o \ + winbindd/winbindd_dual_ndr.o \ + winbindd/winbindd_dual_srv.o \ + librpc/gen_ndr/cli_wbint.o \ + librpc/gen_ndr/srv_wbint.o \ + librpc/gen_ndr/ndr_wbint.o \ winbindd/winbindd_async.o \ winbindd/winbindd_creds.o \ winbindd/winbindd_cred_cache.o \ @@ -1322,7 +1327,8 @@ samba3-idl:: srcdir="$(srcdir)" ../librpc/build_idl.sh ../librpc/idl/*.idl @PIDL_OUTPUTDIR="librpc/gen_ndr" PIDL_ARGS="$(PIDL_ARGS)" CPP="$(CPP)" PIDL="../pidl/pidl" \ srcdir="$(srcdir)" $(srcdir)/script/build_idl.sh \ - librpc/idl/messaging.idl librpc/idl/libnetapi.idl librpc/idl/notify.idl + librpc/idl/messaging.idl librpc/idl/libnetapi.idl librpc/idl/notify.idl \ + librpc/idl/wbint.idl ##################################################################### diff --git a/source3/librpc/gen_ndr/cli_wbint.c b/source3/librpc/gen_ndr/cli_wbint.c new file mode 100644 index 00000000000..044fdf9d1c5 --- /dev/null +++ b/source3/librpc/gen_ndr/cli_wbint.c @@ -0,0 +1,159 @@ +/* + * Unix SMB/CIFS implementation. + * client auto-generated by pidl. DO NOT MODIFY! + */ + +#include "includes.h" +#include "librpc/gen_ndr/cli_wbint.h" + +struct rpccli_wbint_Ping_state { + struct wbint_Ping orig; + struct wbint_Ping tmp; + TALLOC_CTX *out_mem_ctx; + NTSTATUS (*dispatch_recv)(struct tevent_req *req, TALLOC_CTX *mem_ctx); +}; + +static void rpccli_wbint_Ping_done(struct tevent_req *subreq); + +struct tevent_req *rpccli_wbint_Ping_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct rpc_pipe_client *cli, + uint32_t _in_data /* [in] */, + uint32_t *_out_data /* [out] [ref] */) +{ + struct tevent_req *req; + struct rpccli_wbint_Ping_state *state; + struct tevent_req *subreq; + + req = tevent_req_create(mem_ctx, &state, + struct rpccli_wbint_Ping_state); + if (req == NULL) { + return NULL; + } + state->out_mem_ctx = NULL; + state->dispatch_recv = cli->dispatch_recv; + + /* In parameters */ + state->orig.in.in_data = _in_data; + + /* Out parameters */ + state->orig.out.out_data = _out_data; + + if (DEBUGLEVEL >= 10) { + NDR_PRINT_IN_DEBUG(wbint_Ping, &state->orig); + } + + state->out_mem_ctx = talloc_named_const(state, 0, + "rpccli_wbint_Ping_out_memory"); + if (tevent_req_nomem(state->out_mem_ctx, req)) { + return tevent_req_post(req, ev); + } + + /* make a temporary copy, that we pass to the dispatch function */ + state->tmp = state->orig; + + subreq = cli->dispatch_send(state, ev, cli, + &ndr_table_wbint, + NDR_WBINT_PING, + &state->tmp); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, rpccli_wbint_Ping_done, req); + return req; +} + +static void rpccli_wbint_Ping_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct rpccli_wbint_Ping_state *state = tevent_req_data( + req, struct rpccli_wbint_Ping_state); + NTSTATUS status; + TALLOC_CTX *mem_ctx; + + if (state->out_mem_ctx) { + mem_ctx = state->out_mem_ctx; + } else { + mem_ctx = state; + } + + status = state->dispatch_recv(subreq, mem_ctx); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + + /* Copy out parameters */ + *state->orig.out.out_data = *state->tmp.out.out_data; + + /* Reset temporary structure */ + ZERO_STRUCT(state->tmp); + + if (DEBUGLEVEL >= 10) { + NDR_PRINT_OUT_DEBUG(wbint_Ping, &state->orig); + } + + tevent_req_done(req); +} + +NTSTATUS rpccli_wbint_Ping_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx) +{ + struct rpccli_wbint_Ping_state *state = tevent_req_data( + req, struct rpccli_wbint_Ping_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + tevent_req_received(req); + return status; + } + + /* Steal possbile out parameters to the callers context */ + talloc_steal(mem_ctx, state->out_mem_ctx); + + tevent_req_received(req); + return NT_STATUS_OK; +} + +NTSTATUS rpccli_wbint_Ping(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + uint32_t in_data /* [in] */, + uint32_t *out_data /* [out] [ref] */) +{ + struct wbint_Ping r; + NTSTATUS status; + + /* In parameters */ + r.in.in_data = in_data; + + if (DEBUGLEVEL >= 10) { + NDR_PRINT_IN_DEBUG(wbint_Ping, &r); + } + + status = cli->dispatch(cli, + mem_ctx, + &ndr_table_wbint, + NDR_WBINT_PING, + &r); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (DEBUGLEVEL >= 10) { + NDR_PRINT_OUT_DEBUG(wbint_Ping, &r); + } + + if (NT_STATUS_IS_ERR(status)) { + return status; + } + + /* Return variables */ + *out_data = *r.out.out_data; + + /* Return result */ + return NT_STATUS_OK; +} + diff --git a/source3/librpc/gen_ndr/cli_wbint.h b/source3/librpc/gen_ndr/cli_wbint.h new file mode 100644 index 00000000000..25b13f2b648 --- /dev/null +++ b/source3/librpc/gen_ndr/cli_wbint.h @@ -0,0 +1,15 @@ +#include "librpc/gen_ndr/ndr_wbint.h" +#ifndef __CLI_WBINT__ +#define __CLI_WBINT__ +struct tevent_req *rpccli_wbint_Ping_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct rpc_pipe_client *cli, + uint32_t _in_data /* [in] */, + uint32_t *_out_data /* [out] [ref] */); +NTSTATUS rpccli_wbint_Ping_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx); +NTSTATUS rpccli_wbint_Ping(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + uint32_t in_data /* [in] */, + uint32_t *out_data /* [out] [ref] */); +#endif /* __CLI_WBINT__ */ diff --git a/source3/librpc/gen_ndr/ndr_wbint.c b/source3/librpc/gen_ndr/ndr_wbint.c new file mode 100644 index 00000000000..fed1ce2f1e6 --- /dev/null +++ b/source3/librpc/gen_ndr/ndr_wbint.c @@ -0,0 +1,110 @@ +/* parser auto-generated by pidl */ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_wbint.h" + +static enum ndr_err_code ndr_push_wbint_Ping(struct ndr_push *ndr, int flags, const struct wbint_Ping *r) +{ + if (flags & NDR_IN) { + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.in_data)); + } + if (flags & NDR_OUT) { + if (r->out.out_data == NULL) { + return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer"); + } + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.out_data)); + } + return NDR_ERR_SUCCESS; +} + +static enum ndr_err_code ndr_pull_wbint_Ping(struct ndr_pull *ndr, int flags, struct wbint_Ping *r) +{ + TALLOC_CTX *_mem_save_out_data_0; + if (flags & NDR_IN) { + ZERO_STRUCT(r->out); + + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.in_data)); + NDR_PULL_ALLOC(ndr, r->out.out_data); + ZERO_STRUCTP(r->out.out_data); + } + if (flags & NDR_OUT) { + if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) { + NDR_PULL_ALLOC(ndr, r->out.out_data); + } + _mem_save_out_data_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->out.out_data, LIBNDR_FLAG_REF_ALLOC); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.out_data)); + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_out_data_0, LIBNDR_FLAG_REF_ALLOC); + } + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ void ndr_print_wbint_Ping(struct ndr_print *ndr, const char *name, int flags, const struct wbint_Ping *r) +{ + ndr_print_struct(ndr, name, "wbint_Ping"); + ndr->depth++; + if (flags & NDR_SET_VALUES) { + ndr->flags |= LIBNDR_PRINT_SET_VALUES; + } + if (flags & NDR_IN) { + ndr_print_struct(ndr, "in", "wbint_Ping"); + ndr->depth++; + ndr_print_uint32(ndr, "in_data", r->in.in_data); + ndr->depth--; + } + if (flags & NDR_OUT) { + ndr_print_struct(ndr, "out", "wbint_Ping"); + ndr->depth++; + ndr_print_ptr(ndr, "out_data", r->out.out_data); + ndr->depth++; + ndr_print_uint32(ndr, "out_data", *r->out.out_data); + ndr->depth--; + ndr->depth--; + } + ndr->depth--; +} + +static const struct ndr_interface_call wbint_calls[] = { + { + "wbint_Ping", + sizeof(struct wbint_Ping), + (ndr_push_flags_fn_t) ndr_push_wbint_Ping, + (ndr_pull_flags_fn_t) ndr_pull_wbint_Ping, + (ndr_print_function_t) ndr_print_wbint_Ping, + false, + }, + { NULL, 0, NULL, NULL, NULL, false } +}; + +static const char * const wbint_endpoint_strings[] = { + "ncalrpc:", +}; + +static const struct ndr_interface_string_array wbint_endpoints = { + .count = 1, + .names = wbint_endpoint_strings +}; + +static const char * const wbint_authservice_strings[] = { + "host", +}; + +static const struct ndr_interface_string_array wbint_authservices = { + .count = 1, + .names = wbint_authservice_strings +}; + + +const struct ndr_interface_table ndr_table_wbint = { + .name = "wbint", + .syntax_id = { + {0xbf09192c,0xed60,0x4928,{0x9d,0xff},{0xd0,0xd7,0xbc,0xb0,0x3e,0xd8}}, + NDR_WBINT_VERSION + }, + .helpstring = NDR_WBINT_HELPSTRING, + .num_calls = 1, + .calls = wbint_calls, + .endpoints = &wbint_endpoints, + .authservices = &wbint_authservices +}; + diff --git a/source3/librpc/gen_ndr/ndr_wbint.h b/source3/librpc/gen_ndr/ndr_wbint.h new file mode 100644 index 00000000000..6c380876872 --- /dev/null +++ b/source3/librpc/gen_ndr/ndr_wbint.h @@ -0,0 +1,18 @@ +/* header auto-generated by pidl */ + +#include "librpc/ndr/libndr.h" +#include "librpc/gen_ndr/wbint.h" + +#ifndef _HEADER_NDR_wbint +#define _HEADER_NDR_wbint + +#define NDR_WBINT_UUID "bf09192c-ed60-4928-9dff-d0d7bcb03ed8" +#define NDR_WBINT_VERSION 1.0 +#define NDR_WBINT_NAME "wbint" +#define NDR_WBINT_HELPSTRING "winbind parent-child protocol" +extern const struct ndr_interface_table ndr_table_wbint; +#define NDR_WBINT_PING (0x00) + +#define NDR_WBINT_CALL_COUNT (1) +void ndr_print_wbint_Ping(struct ndr_print *ndr, const char *name, int flags, const struct wbint_Ping *r); +#endif /* _HEADER_NDR_wbint */ diff --git a/source3/librpc/gen_ndr/srv_wbint.c b/source3/librpc/gen_ndr/srv_wbint.c new file mode 100644 index 00000000000..0a3569b8748 --- /dev/null +++ b/source3/librpc/gen_ndr/srv_wbint.c @@ -0,0 +1,130 @@ +/* + * Unix SMB/CIFS implementation. + * server auto-generated by pidl. DO NOT MODIFY! + */ + +#include "includes.h" +#include "librpc/gen_ndr/srv_wbint.h" + +static bool api_wbint_Ping(pipes_struct *p) +{ + const struct ndr_interface_call *call; + struct ndr_pull *pull; + struct ndr_push *push; + enum ndr_err_code ndr_err; + DATA_BLOB blob; + struct wbint_Ping *r; + + call = &ndr_table_wbint.calls[NDR_WBINT_PING]; + + r = talloc(talloc_tos(), struct wbint_Ping); + if (r == NULL) { + return false; + } + + if (!prs_data_blob(&p->in_data.data, &blob, r)) { + talloc_free(r); + return false; + } + + pull = ndr_pull_init_blob(&blob, r, NULL); + if (pull == NULL) { + talloc_free(r); + return false; + } + + pull->flags |= LIBNDR_FLAG_REF_ALLOC; + ndr_err = call->ndr_pull(pull, NDR_IN, r); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + talloc_free(r); + return false; + } + + if (DEBUGLEVEL >= 10) { + NDR_PRINT_IN_DEBUG(wbint_Ping, r); + } + + ZERO_STRUCT(r->out); + r->out.out_data = talloc_zero(r, uint32_t); + if (r->out.out_data == NULL) { + talloc_free(r); + return false; + } + + _wbint_Ping(p, r); + + if (p->rng_fault_state) { + talloc_free(r); + /* Return true here, srv_pipe_hnd.c will take care */ + return true; + } + + if (DEBUGLEVEL >= 10) { + NDR_PRINT_OUT_DEBUG(wbint_Ping, r); + } + + push = ndr_push_init_ctx(r, NULL); + if (push == NULL) { + talloc_free(r); + return false; + } + + ndr_err = call->ndr_push(push, NDR_OUT, r); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + talloc_free(r); + return false; + } + + blob = ndr_push_blob(push); + if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) { + talloc_free(r); + return false; + } + + talloc_free(r); + + return true; +} + + +/* Tables */ +static struct api_struct api_wbint_cmds[] = +{ + {"WBINT_PING", NDR_WBINT_PING, api_wbint_Ping}, +}; + +void wbint_get_pipe_fns(struct api_struct **fns, int *n_fns) +{ + *fns = api_wbint_cmds; + *n_fns = sizeof(api_wbint_cmds) / sizeof(struct api_struct); +} + +NTSTATUS rpc_wbint_dispatch(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, const struct ndr_interface_table *table, uint32_t opnum, void *_r) +{ + if (cli->pipes_struct == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + switch (opnum) + { + case NDR_WBINT_PING: { + struct wbint_Ping *r = (struct wbint_Ping *)_r; + ZERO_STRUCT(r->out); + r->out.out_data = talloc_zero(mem_ctx, uint32_t); + if (r->out.out_data == NULL) { + return NT_STATUS_NO_MEMORY; + } + + _wbint_Ping(cli->pipes_struct, r); + return NT_STATUS_OK; + } + + default: + return NT_STATUS_NOT_IMPLEMENTED; + } +} + +NTSTATUS rpc_wbint_init(void) +{ + return rpc_srv_register(SMB_RPC_INTERFACE_VERSION, "wbint", "wbint", &ndr_table_wbint, api_wbint_cmds, sizeof(api_wbint_cmds) / sizeof(struct api_struct)); +} diff --git a/source3/librpc/gen_ndr/srv_wbint.h b/source3/librpc/gen_ndr/srv_wbint.h new file mode 100644 index 00000000000..af3d21a43dd --- /dev/null +++ b/source3/librpc/gen_ndr/srv_wbint.h @@ -0,0 +1,9 @@ +#include "librpc/gen_ndr/ndr_wbint.h" +#ifndef __SRV_WBINT__ +#define __SRV_WBINT__ +void _wbint_Ping(pipes_struct *p, struct wbint_Ping *r); +void wbint_get_pipe_fns(struct api_struct **fns, int *n_fns); +NTSTATUS rpc_wbint_dispatch(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, const struct ndr_interface_table *table, uint32_t opnum, void *r); +void _wbint_Ping(pipes_struct *p, struct wbint_Ping *r); +NTSTATUS rpc_wbint_init(void); +#endif /* __SRV_WBINT__ */ diff --git a/source3/librpc/gen_ndr/wbint.h b/source3/librpc/gen_ndr/wbint.h new file mode 100644 index 00000000000..641d960a1ba --- /dev/null +++ b/source3/librpc/gen_ndr/wbint.h @@ -0,0 +1,22 @@ +/* header auto-generated by pidl */ + +#include + +#include "libcli/util/ntstatus.h" + +#ifndef _HEADER_wbint +#define _HEADER_wbint + + +struct wbint_Ping { + struct { + uint32_t in_data; + } in; + + struct { + uint32_t *out_data;/* [ref] */ + } out; + +}; + +#endif /* _HEADER_wbint */ diff --git a/source3/librpc/idl/wbint.idl b/source3/librpc/idl/wbint.idl new file mode 100644 index 00000000000..40a4545a3af --- /dev/null +++ b/source3/librpc/idl/wbint.idl @@ -0,0 +1,14 @@ +[ + uuid("bf09192c-ed60-4928-9dff-d0d7bcb03ed8"), + endpoint("ncalrpc:"), + pointer_default(unique), + version(1.0), + helpstring("winbind parent-child protocol") +] +interface wbint +{ + void wbint_Ping( + [in] uint32 in_data, + [out] uint32 *out_data + ); +} \ No newline at end of file diff --git a/source3/winbindd/winbindd.h b/source3/winbindd/winbindd.h index 8f0db446170..baab7fd11a3 100644 --- a/source3/winbindd/winbindd.h +++ b/source3/winbindd/winbindd.h @@ -138,6 +138,7 @@ struct winbindd_child { int sock; struct tevent_queue *queue; + struct rpc_pipe_client *rpccli; struct timed_event *lockout_policy_event; struct timed_event *machine_password_change_event; diff --git a/source3/winbindd/winbindd_domain.c b/source3/winbindd/winbindd_domain.c index 8c52df3e16a..5ff2e16abb7 100644 --- a/source3/winbindd/winbindd_domain.c +++ b/source3/winbindd/winbindd_domain.c @@ -121,6 +121,10 @@ static const struct winbindd_child_dispatch_table domain_dispatch_table[] = { .name = "CCACHE_NTLM_AUTH", .struct_cmd = WINBINDD_CCACHE_NTLMAUTH, .struct_fn = winbindd_dual_ccache_ntlm_auth, + },{ + .name = "NDRCMD", + .struct_cmd = WINBINDD_DUAL_NDRCMD, + .struct_fn = winbindd_dual_ndrcmd, },{ .name = NULL, } diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c index 1985dd8b12b..2158834bdd5 100644 --- a/source3/winbindd/winbindd_dual.c +++ b/source3/winbindd/winbindd_dual.c @@ -592,6 +592,8 @@ void setup_child(struct winbindd_child *child, child->table = table; child->queue = tevent_queue_create(NULL, "winbind_child"); SMB_ASSERT(child->queue != NULL); + child->rpccli = wbint_rpccli_create(NULL, child); + SMB_ASSERT(child->rpccli != NULL); } struct winbindd_child *children = NULL; @@ -1307,6 +1309,16 @@ bool winbindd_reinit_after_fork(const char *logfilename) return true; } +/* + * In a child there will be only one domain, reference that here. + */ +static struct winbindd_domain *child_domain; + +struct winbindd_domain *wb_child_domain(void) +{ + return child_domain; +} + static bool fork_domain_child(struct winbindd_child *child) { int fdpair[2]; @@ -1321,6 +1333,7 @@ static bool fork_domain_child(struct winbindd_child *child) } else { DEBUG(10, ("fork_domain_child called without domain.\n")); } + child_domain = child->domain; if (socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair) != 0) { DEBUG(0, ("Could not open child pipe: %s\n", diff --git a/source3/winbindd/winbindd_dual_ndr.c b/source3/winbindd/winbindd_dual_ndr.c new file mode 100644 index 00000000000..f72d6615a02 --- /dev/null +++ b/source3/winbindd/winbindd_dual_ndr.c @@ -0,0 +1,273 @@ +/* + Unix SMB/CIFS implementation. + + Provide parent->child communication based on NDR marshalling + + Copyright (C) Volker Lendecke 2009 + + 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 . +*/ + +/* + * This file implements an RPC between winbind parent and child processes, + * leveraging the autogenerated marshalling routines for MSRPC. This is not + * MSRPC, as it does not go through the whole DCERPC fragmentation, we just + * leverage much the same infrastructure we already have for it. + */ + +#include "includes.h" +#include "winbindd/winbindd.h" +#include "winbindd/winbindd_proto.h" +#include "librpc/gen_ndr/srv_wbint.h" + +struct wb_ndr_transport_priv { + struct winbindd_child *child; +}; + +struct wb_ndr_dispatch_state { + const struct ndr_interface_call *call; + void *r; + struct ndr_push *push; + struct winbindd_request request; + struct winbindd_response *response; +}; + +static void wb_ndr_dispatch_done(struct tevent_req *subreq); + +static struct tevent_req *wb_ndr_dispatch_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct rpc_pipe_client *cli, + const struct ndr_interface_table *table, + uint32_t opnum, + void *r) +{ + struct tevent_req *req, *subreq; + struct wb_ndr_dispatch_state *state; + struct wb_ndr_transport_priv *transport = talloc_get_type_abort( + cli->transport->priv, struct wb_ndr_transport_priv); + DATA_BLOB blob; + enum ndr_err_code ndr_err; + + req = tevent_req_create(mem_ctx, &state, + struct wb_ndr_dispatch_state); + if (req == NULL) { + return NULL; + } + + state->r = r; + state->call = &table->calls[opnum]; + + state->push = ndr_push_init_ctx(state, NULL); + if (tevent_req_nomem(state->push, req)) { + return tevent_req_post(req, ev); + } + + ndr_err = state->call->ndr_push(state->push, NDR_IN, r); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + tevent_req_nterror(req, ndr_map_error2ntstatus(ndr_err)); + TALLOC_FREE(state->push); + return tevent_req_post(req, ev); + } + + blob = ndr_push_blob(state->push); + + state->request.cmd = WINBINDD_DUAL_NDRCMD; + state->request.data.ndrcmd = opnum; + state->request.extra_data.data = (char *)blob.data; + state->request.extra_len = blob.length; + + subreq = wb_child_request_send(state, ev, transport->child, + &state->request); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, wb_ndr_dispatch_done, req); + return req; +} + +static void wb_ndr_dispatch_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_ndr_dispatch_state *state = tevent_req_data( + req, struct wb_ndr_dispatch_state); + int ret, err; + + ret = wb_child_request_recv(subreq, state, &state->response, &err); + TALLOC_FREE(subreq); + if (ret == -1) { + tevent_req_nterror(req, map_nt_error_from_unix(err)); + return; + } + tevent_req_done(req); +} + +static NTSTATUS wb_ndr_dispatch_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx) +{ + struct wb_ndr_dispatch_state *state = tevent_req_data( + req, struct wb_ndr_dispatch_state); + NTSTATUS status; + struct ndr_pull *pull; + enum ndr_err_code ndr_err; + DATA_BLOB blob; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + + blob.data = (uint8_t *)state->response->extra_data.data; + blob.length = state->response->length + - sizeof(struct winbindd_response); + + pull = ndr_pull_init_blob(&blob, mem_ctx, NULL); + if (pull == NULL) { + return NT_STATUS_NO_MEMORY; + } + + /* have the ndr parser alloc memory for us */ + pull->flags |= LIBNDR_FLAG_REF_ALLOC; + ndr_err = state->call->ndr_pull(pull, NDR_OUT, state->r); + TALLOC_FREE(pull); + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return ndr_map_error2ntstatus(ndr_err); + } + + return NT_STATUS_OK; +} + +static NTSTATUS wb_ndr_dispatch(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + const struct ndr_interface_table *table, + uint32_t opnum, void *r) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct event_context *ev; + struct tevent_req *req; + NTSTATUS status = NT_STATUS_OK; + + ev = event_context_init(frame); + if (ev == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + + req = wb_ndr_dispatch_send(frame, ev, cli, table, opnum, r); + if (req == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + + if (!tevent_req_poll(req, ev)) { + status = map_nt_error_from_unix(errno); + goto fail; + } + + status = wb_ndr_dispatch_recv(req, mem_ctx); + fail: + TALLOC_FREE(frame); + return status; +} + +struct rpc_pipe_client *wbint_rpccli_create(TALLOC_CTX *mem_ctx, + struct winbindd_child *child) +{ + struct rpc_pipe_client *result; + struct wb_ndr_transport_priv *transp; + + result = talloc(mem_ctx, struct rpc_pipe_client); + if (result == NULL) { + return NULL; + } + result->abstract_syntax = ndr_table_wbint.syntax_id; + result->transfer_syntax = ndr_transfer_syntax; + result->dispatch = wb_ndr_dispatch; + result->dispatch_send = wb_ndr_dispatch_send; + result->dispatch_recv = wb_ndr_dispatch_recv; + result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN; + result->max_recv_frag = RPC_MAX_PDU_FRAG_LEN; + result->desthost = NULL; + result->srv_name_slash = NULL; + + /* + * Initialize a fake transport. Due to our own wb_ndr_dispatch + * function we don't use all the fragmentation engine in + * cli_pipe, which would use all the _read and _write + * functions in rpc_cli_transport. But we need a place to + * store the child struct in, and we're re-using + * result->transport->priv for that. + */ + + result->transport = talloc_zero(result, struct rpc_cli_transport); + if (result->transport == NULL) { + TALLOC_FREE(result); + return NULL; + } + transp = talloc(result->transport, struct wb_ndr_transport_priv); + if (transp == NULL) { + TALLOC_FREE(result); + return NULL; + } + transp->child = child; + result->transport->priv = transp; + return result; +} + +enum winbindd_result winbindd_dual_ndrcmd(struct winbindd_domain *domain, + struct winbindd_cli_state *state) +{ + pipes_struct p; + struct api_struct *fns; + int num_fns; + bool ret; + + wbint_get_pipe_fns(&fns, &num_fns); + + if (state->request->data.ndrcmd >= num_fns) { + return WINBINDD_ERROR; + } + + ZERO_STRUCT(p); + p.mem_ctx = talloc_stackframe(); + p.in_data.data.buffer_size = state->request->extra_len; + p.in_data.data.data_p = state->request->extra_data.data; + prs_init(&p.out_data.rdata, 0, state->mem_ctx, false); + + ret = fns[state->request->data.ndrcmd].fn(&p); + TALLOC_FREE(p.mem_ctx); + if (!ret) { + return WINBINDD_ERROR; + } + + state->response->extra_data.data = + talloc_memdup(state->mem_ctx, p.out_data.rdata.data_p, + p.out_data.rdata.data_offset); + state->response->length += p.out_data.rdata.data_offset; + prs_mem_free(&p.out_data.rdata); + if (state->response->extra_data.data == NULL) { + return WINBINDD_ERROR; + } + return WINBINDD_OK; +} + +/* + * Just a dummy to make srv_wbint.c happy + */ +NTSTATUS rpc_srv_register(int version, const char *clnt, const char *srv, + const struct ndr_interface_table *iface, + const struct api_struct *cmds, int size) +{ + return NT_STATUS_OK; +} diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c new file mode 100644 index 00000000000..5d2d7f389d0 --- /dev/null +++ b/source3/winbindd/winbindd_dual_srv.c @@ -0,0 +1,30 @@ +/* + Unix SMB/CIFS implementation. + + In-Child server implementation of the routines defined in wbint.idl + + Copyright (C) Volker Lendecke 2009 + + 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 . +*/ + +#include "includes.h" +#include "winbindd/winbindd.h" +#include "winbindd/winbindd_proto.h" +#include "librpc/gen_ndr/srv_wbint.h" + +void _wbint_Ping(pipes_struct *p, struct wbint_Ping *r) +{ + *r->out.out_data = r->in.in_data; +} diff --git a/source3/winbindd/winbindd_idmap.c b/source3/winbindd/winbindd_idmap.c index 6e24a9c2127..7bcc58a0140 100644 --- a/source3/winbindd/winbindd_idmap.c +++ b/source3/winbindd/winbindd_idmap.c @@ -564,6 +564,10 @@ static const struct winbindd_child_dispatch_table idmap_dispatch_table[] = { .name = "ALLOCATE_GID", .struct_cmd = WINBINDD_ALLOCATE_GID, .struct_fn = winbindd_dual_allocate_gid, + },{ + .name = "NDRCMD", + .struct_cmd = WINBINDD_DUAL_NDRCMD, + .struct_fn = winbindd_dual_ndrcmd, },{ .name = NULL, } diff --git a/source3/winbindd/winbindd_locator.c b/source3/winbindd/winbindd_locator.c index 43dadfae295..b35d8dcf545 100644 --- a/source3/winbindd/winbindd_locator.c +++ b/source3/winbindd/winbindd_locator.c @@ -164,6 +164,10 @@ static const struct winbindd_child_dispatch_table locator_dispatch_table[] = { .name = "DSGETDCNAME", .struct_cmd = WINBINDD_DSGETDCNAME, .struct_fn = dual_dsgetdcname, + },{ + .name = "NDRCMD", + .struct_cmd = WINBINDD_DUAL_NDRCMD, + .struct_fn = winbindd_dual_ndrcmd, },{ .name = NULL, } diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h index c9decf8cc4a..f9ef776c5dc 100644 --- a/source3/winbindd/winbindd_proto.h +++ b/source3/winbindd/winbindd_proto.h @@ -330,6 +330,7 @@ void winbind_msg_dump_domain_list(struct messaging_context *msg_ctx, struct server_id server_id, DATA_BLOB *data); bool winbindd_reinit_after_fork(const char *logfilename); +struct winbindd_domain *wb_child_domain(void); /* The following definitions come from winbindd/winbindd_group.c */ @@ -594,4 +595,9 @@ NTSTATUS wb_ping_recv(struct tevent_req *req, enum winbindd_result winbindd_dual_ping(struct winbindd_domain *domain, struct winbindd_cli_state *state); +struct rpc_pipe_client *wbint_rpccli_create(TALLOC_CTX *mem_ctx, + struct winbindd_child *child); +enum winbindd_result winbindd_dual_ndrcmd(struct winbindd_domain *domain, + struct winbindd_cli_state *state); + #endif /* _WINBINDD_PROTO_H_ */ -- 2.34.1