diff options
author | Volker Lendecke <vl@samba.org> | 2009-07-28 15:06:11 -0400 |
---|---|---|
committer | Volker Lendecke <vl@samba.org> | 2009-08-05 03:21:19 -0400 |
commit | 6cf3db91499ebd245b08997a319edf36cfee3365 (patch) | |
tree | a7355f3e0b25e2a13964b7500c77980e94cf2373 /source3/winbindd | |
parent | ddd13c6816e7d289406948fe2f68db1aba7669d3 (diff) | |
download | samba-6cf3db91499ebd245b08997a319edf36cfee3365.tar.gz samba-6cf3db91499ebd245b08997a319edf36cfee3365.tar.bz2 samba-6cf3db91499ebd245b08997a319edf36cfee3365.zip |
s3:winbind: Add NDR-based parent-child communication to winbind
Diffstat (limited to 'source3/winbindd')
-rw-r--r-- | source3/winbindd/winbindd.h | 1 | ||||
-rw-r--r-- | source3/winbindd/winbindd_domain.c | 4 | ||||
-rw-r--r-- | source3/winbindd/winbindd_dual.c | 13 | ||||
-rw-r--r-- | source3/winbindd/winbindd_dual_ndr.c | 273 | ||||
-rw-r--r-- | source3/winbindd/winbindd_dual_srv.c | 30 | ||||
-rw-r--r-- | source3/winbindd/winbindd_idmap.c | 4 | ||||
-rw-r--r-- | source3/winbindd/winbindd_locator.c | 4 | ||||
-rw-r--r-- | source3/winbindd/winbindd_proto.h | 6 |
8 files changed, 335 insertions, 0 deletions
diff --git a/source3/winbindd/winbindd.h b/source3/winbindd/winbindd.h index 8f0db44617..baab7fd11a 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 8c52df3e16..5ff2e16abb 100644 --- a/source3/winbindd/winbindd_domain.c +++ b/source3/winbindd/winbindd_domain.c @@ -122,6 +122,10 @@ static const struct winbindd_child_dispatch_table domain_dispatch_table[] = { .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 1985dd8b12..2158834bdd 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 0000000000..f72d6615a0 --- /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 <http://www.gnu.org/licenses/>. +*/ + +/* + * 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 0000000000..5d2d7f389d --- /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 <http://www.gnu.org/licenses/>. +*/ + +#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 6e24a9c212..7bcc58a014 100644 --- a/source3/winbindd/winbindd_idmap.c +++ b/source3/winbindd/winbindd_idmap.c @@ -565,6 +565,10 @@ static const struct winbindd_child_dispatch_table idmap_dispatch_table[] = { .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 43dadfae29..b35d8dcf54 100644 --- a/source3/winbindd/winbindd_locator.c +++ b/source3/winbindd/winbindd_locator.c @@ -165,6 +165,10 @@ static const struct winbindd_child_dispatch_table locator_dispatch_table[] = { .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 c9decf8cc4..f9ef776c5d 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_ */ |