From 9593101ec118dd242bf25fabf3e17c58269e632c Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sun, 25 Sep 2005 21:01:56 +0000 Subject: r10491: First step towards wbinfo -t: This issues a name request for the primary domain and gets the DC's name via a mailslot call. Metze, I renamed wbsrv_queue_reply to wbsrv_send_reply in accordance with irpc_send_reply. Having _queue_ here and _send_ there is a bit confusing. And as everything is async anyway, the semantics should not be too much of a problem. Volker (This used to be commit 4637964b19c6e9f7d201b287e2d409d029fced01) --- source4/winbind/config.mk | 3 +- source4/winbind/wb_async_helpers.c | 206 +++++++++++++++++++++++++++++++++++ source4/winbind/wb_async_helpers.h | 36 ++++++ source4/winbind/wb_samba3_cmd.c | 64 +++++++++++ source4/winbind/wb_samba3_protocol.c | 3 + source4/winbind/wb_server.c | 4 +- source4/winbind/wb_server.h | 21 ++-- 7 files changed, 324 insertions(+), 13 deletions(-) create mode 100644 source4/winbind/wb_async_helpers.c create mode 100644 source4/winbind/wb_async_helpers.h (limited to 'source4/winbind') diff --git a/source4/winbind/config.mk b/source4/winbind/config.mk index dea0782575..5f055768c0 100644 --- a/source4/winbind/config.mk +++ b/source4/winbind/config.mk @@ -8,7 +8,8 @@ SUBSYSTEM = SERVER_SERVICE INIT_OBJ_FILES = \ winbind/wb_server.o \ winbind/wb_samba3_protocol.o \ - winbind/wb_samba3_cmd.o + winbind/wb_samba3_cmd.o \ + winbind/wb_async_helpers.o REQUIRED_SUBSYSTEMS = # End MODULE server_service_winbind ################################################ diff --git a/source4/winbind/wb_async_helpers.c b/source4/winbind/wb_async_helpers.c new file mode 100644 index 0000000000..17efd06c81 --- /dev/null +++ b/source4/winbind/wb_async_helpers.c @@ -0,0 +1,206 @@ +/* + Unix SMB/CIFS implementation. + + Copyright (C) Volker Lendecke 2005 + + 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 2 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +/* + a composite API for finding a DC and its name +*/ + +#include "includes.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/composite/composite.h" +#include "winbind/wb_async_helpers.h" + +#include "librpc/gen_ndr/nbt.h" +#include "librpc/gen_ndr/samr.h" +#include "lib/messaging/irpc.h" +#include "librpc/gen_ndr/irpc.h" +#include "librpc/gen_ndr/ndr_irpc.h" + +struct finddcs_state { + struct wb_finddcs *io; + struct composite_context *creq; + + struct nbtd_getdcname *r; + struct irpc_request *ireq; +}; + +static void finddcs_getdc(struct irpc_request *req) +{ + struct composite_context *c = talloc_get_type(req->async.private, + struct composite_context); + struct finddcs_state *state = + talloc_get_type(c->private, struct finddcs_state); + + c->status = irpc_call_recv(req); + if (!NT_STATUS_IS_OK(c->status)) { + goto done; + } + + state->io->out.dcs[0].name = talloc_steal(state->io->out.dcs, + state->r->out.dcname); + + c->status = NT_STATUS_OK; + c->state = SMBCLI_REQUEST_DONE; + + done: + if (!NT_STATUS_IS_OK(c->status)) { + c->state = SMBCLI_REQUEST_ERROR; + } + + if (c->state >= SMBCLI_REQUEST_DONE && + c->async.fn) { + c->async.fn(c); + } +} + +/* + called when name resolution is finished +*/ +static void finddcs_resolve(struct composite_context *res_ctx) +{ + struct composite_context *c = talloc_get_type(res_ctx->async.private, + struct composite_context); + struct finddcs_state *state = + talloc_get_type(c->private, struct finddcs_state); + uint32_t *nbt_servers; + + state->io->out.num_dcs = 1; + state->io->out.dcs = talloc_array(state, struct nbt_dc_name, + state->io->out.num_dcs); + if (state->io->out.dcs == NULL) { + c->status = NT_STATUS_NO_MEMORY; + goto done; + } + + c->status = resolve_name_recv(res_ctx, state->io->out.dcs, + &state->io->out.dcs[0].address); + if (!NT_STATUS_IS_OK(c->status)) { + goto done; + } + + nbt_servers = irpc_servers_byname(state->io->in.msg_ctx, "nbt_server"); + if ((nbt_servers == NULL) || (nbt_servers[0] == 0)) { + c->status = NT_STATUS_NO_LOGON_SERVERS; + goto done; + } + + state->r = talloc(state, struct nbtd_getdcname); + if (state->r == NULL) { + c->status = NT_STATUS_NO_MEMORY; + goto done; + } + + state->r->in.domainname = talloc_strdup(state->r, lp_workgroup()); + state->r->in.ip_address = state->io->out.dcs[0].address; + state->r->in.my_computername = lp_netbios_name(); + state->r->in.my_accountname = talloc_asprintf(state->r, "%s$", + lp_netbios_name()); + state->r->in.account_control = ACB_WSTRUST; + state->r->in.domain_sid = secrets_get_domain_sid(state->r, + lp_workgroup()); + + if ((state->r->in.domainname == NULL) || + (state->r->in.my_accountname == NULL)) { + DEBUG(0, ("talloc failed\n")); + c->status = NT_STATUS_NO_MEMORY; + goto done; + } + if (state->r->in.domain_sid == NULL) { + c->status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + goto done; + } + + state->ireq = irpc_call_send(state->io->in.msg_ctx, nbt_servers[0], + &dcerpc_table_irpc, DCERPC_NBTD_GETDCNAME, + state->r, state); + + if (state->ireq == NULL) { + c->status = NT_STATUS_NO_MEMORY; + goto done; + } + + c->status = NT_STATUS_OK; + state->ireq->async.fn = finddcs_getdc; + state->ireq->async.private = c; + + done: + if (!NT_STATUS_IS_OK(c->status)) { + c->state = SMBCLI_REQUEST_ERROR; + } + + if (c->state >= SMBCLI_REQUEST_DONE && + c->async.fn) { + c->async.fn(c); + } +} + +struct composite_context *wb_finddcs_send(struct wb_finddcs *io, + struct event_context *event_ctx) +{ + struct composite_context *c; + struct finddcs_state *state; + struct nbt_name name; + + c = talloc_zero(NULL, struct composite_context); + if (c == NULL) goto failed; + c->state = SMBCLI_REQUEST_SEND; + c->event_ctx = event_ctx; + + state = talloc(c, struct finddcs_state); + if (state == NULL) goto failed; + + state->io = io; + + make_nbt_name(&name, io->in.domain, 0x1c); + state->creq = resolve_name_send(&name, c->event_ctx, + lp_name_resolve_order()); + + if (state->creq == NULL) goto failed; + state->creq->async.private = c; + state->creq->async.fn = finddcs_resolve; + c->private = state; + + return c; +failed: + talloc_free(c); + return NULL; +} + +NTSTATUS wb_finddcs_recv(struct composite_context *c, TALLOC_CTX *mem_ctx) +{ + NTSTATUS status; + + status = composite_wait(c); + + if (NT_STATUS_IS_OK(status)) { + struct finddcs_state *state = + talloc_get_type(c->private, struct finddcs_state); + talloc_steal(mem_ctx, state->io->out.dcs); + } + + talloc_free(c); + return status; +} + +NTSTATUS wb_finddcs(struct wb_finddcs *io, TALLOC_CTX *mem_ctx, + struct event_context *ev) +{ + struct composite_context *c = wb_finddcs_send(io, ev); + return wb_finddcs_recv(c, mem_ctx); +} diff --git a/source4/winbind/wb_async_helpers.h b/source4/winbind/wb_async_helpers.h new file mode 100644 index 0000000000..6c4f1d84a8 --- /dev/null +++ b/source4/winbind/wb_async_helpers.h @@ -0,0 +1,36 @@ +/* + Unix SMB/CIFS implementation. + + SMB composite request interfaces + + Copyright (C) Volker Lendecke 2005 + + 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 2 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +struct wb_finddcs { + struct { + struct messaging_context *msg_ctx; + const char *domain; + } in; + + struct { + int num_dcs; + struct nbt_dc_name { + const char *address; + const char *name; + } *dcs; + } out; +}; diff --git a/source4/winbind/wb_samba3_cmd.c b/source4/winbind/wb_samba3_cmd.c index 14e9ac9e6d..4ff54e25b4 100644 --- a/source4/winbind/wb_samba3_cmd.c +++ b/source4/winbind/wb_samba3_cmd.c @@ -26,6 +26,10 @@ #include "nsswitch/winbindd_nss.h" #include "winbind/wb_server.h" #include "winbind/wb_samba3_protocol.h" +#include "winbind/wb_async_helpers.h" +#include "librpc/gen_ndr/nbt.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/composite/composite.h" NTSTATUS wbsrv_samba3_interface_version(struct wbsrv_samba3_call *s3call) { @@ -48,3 +52,63 @@ NTSTATUS wbsrv_samba3_ping(struct wbsrv_samba3_call *s3call) s3call->response.result = WINBINDD_OK; return NT_STATUS_OK; } + +struct check_machacc_state { + struct wb_finddcs *io; +}; + +static void wbsrv_samba3_check_machacc_reply(struct composite_context *action) +{ + struct wbsrv_samba3_call *s3call = + talloc_get_type(action->async.private, + struct wbsrv_samba3_call); + struct check_machacc_state *state = + talloc_get_type(s3call->private_data, + struct check_machacc_state); + NTSTATUS status; + + status = wb_finddcs_recv(action, s3call); + if (NT_STATUS_IS_OK(status)) { + DEBUG(10, ("Got name %s\n", state->io->out.dcs[0].name)); + s3call->response.result = WINBINDD_OK; + } else { + DEBUG(10, ("Got no addr: %s\n", nt_errstr(status))); + s3call->response.result = WINBINDD_ERROR; + } + + status = wbsrv_send_reply(s3call->call); + if (!NT_STATUS_IS_OK(status)) { + wbsrv_terminate_connection(s3call->call->wbconn, + "wbsrv_queue_reply() failed"); + return; + } +} + +NTSTATUS wbsrv_samba3_check_machacc(struct wbsrv_samba3_call *s3call) +{ + struct composite_context *resolve_req; + struct check_machacc_state *state; + + DEBUG(5, ("check_machacc called\n")); + + state = talloc(s3call, struct check_machacc_state); + NT_STATUS_HAVE_NO_MEMORY(state); + + state->io = talloc(s3call, struct wb_finddcs); + NT_STATUS_HAVE_NO_MEMORY(state->io); + s3call->private_data = state; + + state->io->in.msg_ctx = s3call->call->wbconn->conn->msg_ctx; + state->io->in.domain = lp_workgroup(); + + resolve_req = wb_finddcs_send(state->io, s3call->call->event_ctx); + NT_STATUS_HAVE_NO_MEMORY(resolve_req); + + /* setup the callbacks */ + resolve_req->async.fn = wbsrv_samba3_check_machacc_reply; + resolve_req->async.private = s3call; + + /* tell the caller we reply later */ + s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC; + return NT_STATUS_OK; +} diff --git a/source4/winbind/wb_samba3_protocol.c b/source4/winbind/wb_samba3_protocol.c index a5ad66ae16..4519f89540 100644 --- a/source4/winbind/wb_samba3_protocol.c +++ b/source4/winbind/wb_samba3_protocol.c @@ -77,6 +77,9 @@ NTSTATUS wbsrv_samba3_handle_call(struct wbsrv_call *call) case WINBINDD_PING: return wbsrv_samba3_ping(s3call); + + case WINBINDD_CHECK_MACHACC: + return wbsrv_samba3_check_machacc(s3call); } s3call->response.result = WINBINDD_ERROR; diff --git a/source4/winbind/wb_server.c b/source4/winbind/wb_server.c index d8d8f19465..e18ea16662 100644 --- a/source4/winbind/wb_server.c +++ b/source4/winbind/wb_server.c @@ -149,7 +149,7 @@ static void wbsrv_recv(struct stream_connection *conn, uint16_t flags) * and queue the reply, this implies talloc_free(call), * and set the socket to readable again */ - status = wbsrv_queue_reply(call); + status = wbsrv_send_reply(call); if (!NT_STATUS_IS_OK(status)) goto failed; return; @@ -170,7 +170,7 @@ failed: * return; * to drop the connection */ -NTSTATUS wbsrv_queue_reply(struct wbsrv_call *call) +NTSTATUS wbsrv_send_reply(struct wbsrv_call *call) { struct wbsrv_connection *wbconn = call->wbconn; const struct wbsrv_protocol_ops *ops = wbconn->listen_socket->ops; diff --git a/source4/winbind/wb_server.h b/source4/winbind/wb_server.h index 2c93c02323..0c00394f7d 100644 --- a/source4/winbind/wb_server.h +++ b/source4/winbind/wb_server.h @@ -91,16 +91,17 @@ struct wbsrv_connection { NOTE about async replies: if the backend wants to reply later: - - it should set the WBSRV_CALL_FLAGS_REPLY_ASYNC flag, and may set a talloc_destructor - on the this structure or on the private_data (if it's a talloc child of this structure), - so that wbsrv_terminate_connection called by another call clean up the whole connection - correct. - - When the backend is ready to reply it should call wbsrv_queue_reply(call), - wbsrv_queue_reply implies talloc_free(call), so the backend should use talloc_reference(call), - if it needs it later. - - If wbsrv_queue_reply doesn't return NT_STATUS_OK, the backend function should call, - wbsrv_terminate_connection(call->wbconn, nt_errstr(status)); - return; + + - it should set the WBSRV_CALL_FLAGS_REPLY_ASYNC flag, and may set a + talloc_destructor on the this structure or on the private_data (if it's a + talloc child of this structure), so that wbsrv_terminate_connection + called by another call clean up the whole connection correct. + - When the backend is ready to reply it should call wbsrv_send_reply(call), + wbsrv_send_reply implies talloc_free(call), so the backend should use + talloc_reference(call), if it needs it later. + - If wbsrv_send_reply doesn't return NT_STATUS_OK, the backend function + should call, wbsrv_terminate_connection(call->wbconn, nt_errstr(status)); + return; */ struct wbsrv_call { -- cgit