From 69307693dc47cdaa931551c99914e85273037886 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 5 Nov 2005 23:46:57 +0000 Subject: r11528: Separate finding dcs from initializing a domain. Makes it easier to possibly support cldap and other stuff in the future. This temporarily disables wbinfo -t, but that will come back soon. Try an ldap bind using gss-spnego. This got me krb5 binds against "our" w2k3 and a trusted w2k, although with some memleaks from krb5 and a BAD_OPTION tgs-rep error. Volker (This used to be commit d14948fdf687c8f70ef9ec35445b7eb04da84253) --- source4/winbind/config.mk | 2 + source4/winbind/wb_async_helpers.c | 3 + source4/winbind/wb_async_helpers.h | 4 - source4/winbind/wb_dom_info.c | 166 +++++++++++++++++++++ source4/winbind/wb_dom_info_trusted.c | 240 ++++++++++++++++++++++++++++++ source4/winbind/wb_init_domain.c | 268 +++++++++++----------------------- source4/winbind/wb_samba3_cmd.c | 2 + source4/winbind/wb_samba3_protocol.c | 2 + source4/winbind/wb_server.c | 38 +---- source4/winbind/wb_server.h | 22 +-- source4/winbind/wb_sid2domain.c | 177 +++++++--------------- 11 files changed, 569 insertions(+), 355 deletions(-) create mode 100644 source4/winbind/wb_dom_info.c create mode 100644 source4/winbind/wb_dom_info_trusted.c (limited to 'source4/winbind') diff --git a/source4/winbind/config.mk b/source4/winbind/config.mk index 6ed4f51cfc..d940a4daf1 100644 --- a/source4/winbind/config.mk +++ b/source4/winbind/config.mk @@ -10,6 +10,8 @@ INIT_OBJ_FILES = \ wb_samba3_protocol.o \ wb_samba3_cmd.o \ wb_init_domain.o \ + wb_dom_info.o \ + wb_dom_info_trusted.o \ wb_sid2domain.o \ wb_connect_lsa.o \ wb_connect_sam.o \ diff --git a/source4/winbind/wb_async_helpers.c b/source4/winbind/wb_async_helpers.c index f00c0725b4..915638abb7 100644 --- a/source4/winbind/wb_async_helpers.c +++ b/source4/winbind/wb_async_helpers.c @@ -666,6 +666,8 @@ NTSTATUS wb_lsa_lookupnames(TALLOC_CTX *mem_ctx, return wb_lsa_lookupnames_recv(c, mem_ctx, sids); } +#if 0 + struct cmd_checkmachacc_state { struct composite_context *ctx; struct wbsrv_call *call; @@ -730,6 +732,7 @@ NTSTATUS wb_cmd_checkmachacc(struct wbsrv_call *call) struct composite_context *c = wb_cmd_checkmachacc_send(call); return wb_cmd_checkmachacc_recv(c); } +#endif struct samr_getuserdomgroups_state { struct composite_context *ctx; diff --git a/source4/winbind/wb_async_helpers.h b/source4/winbind/wb_async_helpers.h index 413747090c..532cd9730c 100644 --- a/source4/winbind/wb_async_helpers.h +++ b/source4/winbind/wb_async_helpers.h @@ -34,7 +34,3 @@ struct wb_sid_object { const char *name; }; -struct wb_dom_info { - const char *name; - const struct dom_sid *sid; -}; diff --git a/source4/winbind/wb_dom_info.c b/source4/winbind/wb_dom_info.c new file mode 100644 index 0000000000..5be28cc055 --- /dev/null +++ b/source4/winbind/wb_dom_info.c @@ -0,0 +1,166 @@ +/* + Unix SMB/CIFS implementation. + + Get a struct wb_dom_info for a domain using DNS, netbios, possibly cldap + etc. + + 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. +*/ + +#include "includes.h" +#include "libcli/composite/composite.h" +#include "libcli/smb_composite/smb_composite.h" +#include "winbind/wb_async_helpers.h" +#include "winbind/wb_server.h" +#include "smbd/service_stream.h" +#include "smbd/service_task.h" +#include "librpc/gen_ndr/nbt.h" +#include "librpc/gen_ndr/ndr_irpc.h" +#include "librpc/gen_ndr/samr.h" +#include "lib/messaging/irpc.h" + +struct get_dom_info_state { + struct composite_context *ctx; + struct wbsrv_service *service; + struct nbtd_getdcname r; + struct wb_dom_info *info; +}; + +static void get_dom_info_recv_addrs(struct composite_context *ctx); +static void get_dom_info_recv_dcname(struct irpc_request *ireq); + +struct composite_context *wb_get_dom_info_send(TALLOC_CTX *mem_ctx, + struct wbsrv_service *service, + const char *domain_name, + const struct dom_sid *sid) +{ + struct composite_context *result, *ctx; + struct get_dom_info_state *state; + struct nbt_name name; + + result = talloc(mem_ctx, struct composite_context); + if (result == NULL) goto failed; + result->state = COMPOSITE_STATE_IN_PROGRESS; + result->async.fn = NULL; + result->event_ctx = service->task->event_ctx; + + state = talloc(result, struct get_dom_info_state); + if (state == NULL) goto failed; + state->ctx = result; + result->private_data = state; + + state->service = service; + + state->info = talloc_zero(state, struct wb_dom_info); + if (state->info == NULL) goto failed; + + state->info->name = talloc_strdup(state->info, domain_name); + if (state->info->name == NULL) goto failed; + state->info->sid = dom_sid_dup(state->info, sid); + if (state->info->sid == NULL) goto failed; + + make_nbt_name(&name, state->info->name, NBT_NAME_LOGON); + + ctx = resolve_name_send(&name, result->event_ctx, + lp_name_resolve_order()); + if (ctx == NULL) goto failed; + + ctx->async.fn = get_dom_info_recv_addrs; + ctx->async.private_data = state; + return result; + + failed: + talloc_free(result); + return NULL; +} + +static void get_dom_info_recv_addrs(struct composite_context *ctx) +{ + struct get_dom_info_state *state = + talloc_get_type(ctx->async.private_data, + struct get_dom_info_state); + uint32_t *nbt_servers; + struct irpc_request *ireq; + + state->ctx->status = resolve_name_recv(ctx, state->info, + &state->info->dc_address); + if (!composite_is_ok(state->ctx)) return; + + nbt_servers = irpc_servers_byname(state->service->task->msg_ctx, + "nbt_server"); + if ((nbt_servers == NULL) || (nbt_servers[0] == 0)) { + composite_error(state->ctx, NT_STATUS_NO_LOGON_SERVERS); + return; + } + + state->r.in.domainname = state->info->name; + state->r.in.ip_address = state->info->dc_address; + state->r.in.my_computername = lp_netbios_name(); + state->r.in.my_accountname = talloc_asprintf(state, "%s$", + lp_netbios_name()); + if (composite_nomem(state->r.in.my_accountname, state->ctx)) return; + state->r.in.account_control = ACB_WSTRUST; + state->r.in.domain_sid = dom_sid_dup(state, state->info->sid); + if (composite_nomem(state->r.in.domain_sid, state->ctx)) return; + + ireq = irpc_call_send(state->service->task->msg_ctx, nbt_servers[0], + &dcerpc_table_irpc, DCERPC_NBTD_GETDCNAME, + &state->r, state); + composite_continue_irpc(state->ctx, ireq, get_dom_info_recv_dcname, + state); +} + +static void get_dom_info_recv_dcname(struct irpc_request *ireq) +{ + struct get_dom_info_state *state = + talloc_get_type(ireq->async.private, + struct get_dom_info_state); + + + state->ctx->status = irpc_call_recv(ireq); + talloc_free(ireq); + if (!composite_is_ok(state->ctx)) return; + + state->info->dc_name = talloc_steal(state->info, state->r.out.dcname); + composite_done(state->ctx); +} + +NTSTATUS wb_get_dom_info_recv(struct composite_context *ctx, + TALLOC_CTX *mem_ctx, + struct wb_dom_info **result) +{ + NTSTATUS status = composite_wait(ctx); + if (NT_STATUS_IS_OK(status)) { + struct get_dom_info_state *state = + talloc_get_type(ctx->private_data, + struct get_dom_info_state); + *result = talloc_steal(mem_ctx, state->info); + } + talloc_free(ctx); + return status; +} + +NTSTATUS wb_get_dom_info(TALLOC_CTX *mem_ctx, + struct wbsrv_service *service, + const char *domain_name, + const struct dom_sid *sid, + struct wb_dom_info **result) +{ + struct composite_context *ctx = + wb_get_dom_info_send(mem_ctx, service, domain_name, sid); + return wb_get_dom_info_recv(ctx, mem_ctx, result); +} diff --git a/source4/winbind/wb_dom_info_trusted.c b/source4/winbind/wb_dom_info_trusted.c new file mode 100644 index 0000000000..ce9e5b9c47 --- /dev/null +++ b/source4/winbind/wb_dom_info_trusted.c @@ -0,0 +1,240 @@ +/* + Unix SMB/CIFS implementation. + + Get a struct wb_dom_info for a trusted domain, relying on "our" DC. + + 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. +*/ + +#include "includes.h" +#include "libcli/composite/composite.h" +#include "libcli/smb_composite/smb_composite.h" +#include "winbind/wb_async_helpers.h" +#include "winbind/wb_server.h" +#include "smbd/service_stream.h" +#include "smbd/service_task.h" +#include "librpc/gen_ndr/nbt.h" +#include "librpc/gen_ndr/ndr_netlogon.h" + +struct trusted_dom_info_state { + struct composite_context *ctx; + struct wbsrv_service *service; + struct wbsrv_domain *my_domain; + + struct netr_DsRGetDCName d; + struct netr_GetAnyDCName g; + + struct wb_dom_info *info; +}; + +static void trusted_dom_info_recv_domain(struct composite_context *ctx); +static void trusted_dom_info_recv_dsr(struct rpc_request *req); +static void trusted_dom_info_recv_dcname(struct rpc_request *req); +static void trusted_dom_info_recv_dcaddr(struct composite_context *ctx); + +struct composite_context *wb_trusted_dom_info_send(TALLOC_CTX *mem_ctx, + struct wbsrv_service *service, + const char *domain_name, + const struct dom_sid *sid) +{ + struct composite_context *result, *ctx; + struct trusted_dom_info_state *state; + + result = talloc(mem_ctx, struct composite_context); + if (result == NULL) goto failed; + result->state = COMPOSITE_STATE_IN_PROGRESS; + result->async.fn = NULL; + result->event_ctx = service->task->event_ctx; + + state = talloc(result, struct trusted_dom_info_state); + if (state == NULL) goto failed; + state->ctx = result; + result->private_data = state; + + state->info = talloc_zero(state, struct wb_dom_info); + if (state->info == NULL) goto failed; + + state->service = service; + + state->info->sid = dom_sid_dup(state->info, sid); + if (state->info->sid == NULL) goto failed; + + state->info->name = talloc_strdup(state->info, domain_name); + if (state->info->name == NULL) goto failed; + + ctx = wb_sid2domain_send(state, service, service->primary_sid); + if (ctx == NULL) goto failed; + + ctx->async.fn = trusted_dom_info_recv_domain; + ctx->async.private_data = state; + return result; + + failed: + talloc_free(result); + return NULL; +} + +static void trusted_dom_info_recv_domain(struct composite_context *ctx) +{ + struct trusted_dom_info_state *state = + talloc_get_type(ctx->async.private_data, + struct trusted_dom_info_state); + struct rpc_request *req; + + state->ctx->status = wb_sid2domain_recv(ctx, &state->my_domain); + if (!composite_is_ok(state->ctx)) return; + + state->d.in.server_unc = + talloc_asprintf(state, "\\\\%s", + state->my_domain->info->dc_name); + if (composite_nomem(state->d.in.server_unc, + state->ctx)) return; + + state->d.in.domain_name = state->info->name; + state->d.in.domain_guid = NULL; + state->d.in.site_guid = NULL; + state->d.in.flags = 0x40000000; + + req = dcerpc_netr_DsRGetDCName_send(state->my_domain->netlogon_pipe, + state, &state->d); + composite_continue_rpc(state->ctx, req, trusted_dom_info_recv_dsr, + state); +} + +/* + * dcerpc_netr_DsRGetDCName has replied + */ + +static void trusted_dom_info_recv_dsr(struct rpc_request *req) +{ + struct trusted_dom_info_state *state = + talloc_get_type(req->async.private, + struct trusted_dom_info_state); + + state->ctx->status = dcerpc_ndr_request_recv(req); + if (!NT_STATUS_IS_OK(state->ctx->status)) { + DEBUG(9, ("dcerpc_ndr_request_recv returned %s\n", + nt_errstr(state->ctx->status))); + goto fallback; + } + + state->ctx->status = + werror_to_ntstatus(state->d.out.result); + if (!NT_STATUS_IS_OK(state->ctx->status)) { + DEBUG(9, ("dsrgetdcname returned %s\n", + nt_errstr(state->ctx->status))); + goto fallback; + } + + /* Hey, that was easy! */ + + state->info->dc_name = talloc_steal(state->info, + state->d.out.info->dc_unc); + if (*state->info->dc_name == '\\') state->info->dc_name++; + if (*state->info->dc_name == '\\') state->info->dc_name++; + + state->info->dc_address = talloc_steal(state->info, + state->d.out.info->dc_address); + if (*state->info->dc_address == '\\') state->info->dc_address++; + if (*state->info->dc_address == '\\') state->info->dc_address++; + + state->info->dns_name = talloc_steal(state->info, + state->d.out.info->domain_name); + + composite_done(state->ctx); + return; + + fallback: + + state->g.in.logon_server = talloc_asprintf( + state, "\\\\%s", + dcerpc_server_name(state->my_domain->netlogon_pipe)); + state->g.in.domainname = state->info->name; + + req = dcerpc_netr_GetAnyDCName_send(state->my_domain->netlogon_pipe, + state, &state->g); + if (composite_nomem(req, state->ctx)) return; + + composite_continue_rpc(state->ctx, req, trusted_dom_info_recv_dcname, + state); +} + +static void trusted_dom_info_recv_dcname(struct rpc_request *req) +{ + struct trusted_dom_info_state *state = + talloc_get_type(req->async.private, + struct trusted_dom_info_state); + struct composite_context *ctx; + struct nbt_name name; + + state->ctx->status = dcerpc_ndr_request_recv(req); + if (!composite_is_ok(state->ctx)) return; + state->ctx->status = werror_to_ntstatus(state->g.out.result); + if (!composite_is_ok(state->ctx)) return; + + state->info->dc_name = talloc_steal(state->info, + state->g.out.dcname); + + if (*state->info->dc_name == '\\') state->info->dc_name++; + if (*state->info->dc_name == '\\') state->info->dc_name++; + + make_nbt_name(&name, state->info->dc_name, 0x20); + ctx = resolve_name_send(&name, state->service->task->event_ctx, + lp_name_resolve_order()); + + composite_continue(state->ctx, ctx, trusted_dom_info_recv_dcaddr, + state); +} + +static void trusted_dom_info_recv_dcaddr(struct composite_context *ctx) +{ + struct trusted_dom_info_state *state = + talloc_get_type(ctx->async.private_data, + struct trusted_dom_info_state); + + state->ctx->status = resolve_name_recv(ctx, state->info, + &state->info->dc_address); + if (!composite_is_ok(state->ctx)) return; + + composite_done(state->ctx); +} + +NTSTATUS wb_trusted_dom_info_recv(struct composite_context *ctx, + TALLOC_CTX *mem_ctx, + struct wb_dom_info **result) +{ + NTSTATUS status = composite_wait(ctx); + if (NT_STATUS_IS_OK(status)) { + struct trusted_dom_info_state *state = + talloc_get_type(ctx->private_data, + struct trusted_dom_info_state); + *result = talloc_steal(mem_ctx, state->info); + } + talloc_free(ctx); + return status; +} + +NTSTATUS wb_trusted_dom_info(TALLOC_CTX *mem_ctx, + struct wbsrv_service *service, + const char *domain_name, + const struct dom_sid *sid, + struct wb_dom_info **result) +{ + struct composite_context *ctx = + wb_trusted_dom_info_send(mem_ctx, service, domain_name, sid); + return wb_trusted_dom_info_recv(ctx, mem_ctx, result); +} diff --git a/source4/winbind/wb_init_domain.c b/source4/winbind/wb_init_domain.c index c5082a9a3e..21ea668043 100644 --- a/source4/winbind/wb_init_domain.c +++ b/source4/winbind/wb_init_domain.c @@ -39,6 +39,8 @@ #include "librpc/gen_ndr/ndr_lsa.h" #include "libcli/auth/credentials.h" +#include "libcli/ldap/ldap_client.h" + /* * Initialize a domain: @@ -67,29 +69,11 @@ struct init_domain_state { struct wbsrv_domain *domain; struct wbsrv_service *service; - int num_dcs; - struct nbt_dc_name *dcs; - const char *dcaddr; - struct smb_composite_connect conn; - struct dcerpc_pipe *auth2_pipe; - struct dcerpc_pipe *netlogon_pipe; - - struct dcerpc_pipe *lsa_pipe; - struct policy_handle *lsa_policy; - - struct dcerpc_pipe *samr_pipe; - struct policy_handle *samr_handle; - struct policy_handle *domain_handle; - - struct ldap_connection *ldap_conn; - struct lsa_QueryInfoPolicy queryinfo; }; -static void init_domain_recv_dcs(struct composite_context *ctx); -static void init_domain_recv_dcip(struct composite_context *ctx); static void init_domain_recv_tree(struct composite_context *ctx); static void init_domain_recv_netlogoncreds(struct composite_context *ctx); static void init_domain_recv_netlogonpipe(struct composite_context *ctx); @@ -98,13 +82,14 @@ static void init_domain_recv_queryinfo(struct rpc_request *req); static void init_domain_recv_ldapconn(struct composite_context *ctx); static void init_domain_recv_samr(struct composite_context *ctx); -struct composite_context *wb_init_domain_send(struct wbsrv_service *service, - struct wbsrv_domain *domain) +struct composite_context *wb_init_domain_send(TALLOC_CTX *mem_ctx, + struct wbsrv_service *service, + struct wb_dom_info *dom_info) { struct composite_context *result, *ctx; struct init_domain_state *state; - result = talloc(domain, struct composite_context); + result = talloc(mem_ctx, struct composite_context); if (result == NULL) goto failed; result->state = COMPOSITE_STATE_IN_PROGRESS; result->async.fn = NULL; @@ -116,112 +101,43 @@ struct composite_context *wb_init_domain_send(struct wbsrv_service *service, result->private_data = state; state->service = service; - state->domain = domain; - - if (domain->dcname != NULL) { - struct nbt_name name; - make_nbt_name(&name, domain->dcname, 0x20); - ctx = resolve_name_send(&name, result->event_ctx, - lp_name_resolve_order()); - if (ctx == NULL) goto failed; - ctx->async.fn = init_domain_recv_dcip; - ctx->async.private_data = state; - return result; - } - if (state->domain->schannel_creds != NULL) { - talloc_free(state->domain->schannel_creds); - } + state->domain = talloc(state, struct wbsrv_domain); + if (state->domain == NULL) goto failed; + + state->domain->info = talloc_reference(state->domain, dom_info); + if (state->domain->info == NULL) goto failed; state->domain->schannel_creds = cli_credentials_init(state->domain); if (state->domain->schannel_creds == NULL) goto failed; + cli_credentials_set_conf(state->domain->schannel_creds); state->ctx->status = cli_credentials_set_machine_account(state->domain-> schannel_creds); if (!NT_STATUS_IS_OK(state->ctx->status)) goto failed; - ctx = wb_finddcs_send(state, domain->name, domain->sid, - result->event_ctx, service->task->msg_ctx); - if (ctx == NULL) goto failed; - - ctx->async.fn = init_domain_recv_dcs; - ctx->async.private_data = state; - return result; - - failed: - talloc_free(result); - return NULL; -} - -static void init_domain_recv_dcs(struct composite_context *ctx) -{ - struct init_domain_state *state = - talloc_get_type(ctx->async.private_data, - struct init_domain_state); - - state->ctx->status = wb_finddcs_recv(ctx, state, &state->num_dcs, - &state->dcs); - if (!composite_is_ok(state->ctx)) return; - - if (state->num_dcs < 1) { - composite_error(state->ctx, NT_STATUS_NO_LOGON_SERVERS); - return; - } - - state->dcaddr = state->dcs[0].address; - - state->domain->dcname = talloc_reference(state->domain, - state->dcs[0].name); - if (composite_nomem(state->domain->dcname, state->ctx)) return; - - state->conn.in.dest_host = state->dcs[0].address; + state->conn.in.dest_host = dom_info->dc_address; state->conn.in.port = 0; - state->conn.in.called_name = state->dcs[0].name; + state->conn.in.called_name = dom_info->dc_name; state->conn.in.service = "IPC$"; state->conn.in.service_type = "IPC"; - state->conn.in.workgroup = state->domain->name; - + state->conn.in.workgroup = dom_info->name; state->conn.in.credentials = state->domain->schannel_creds; - if (state->conn.in.credentials == NULL) { - state->conn.in.credentials = cli_credentials_init(state); - if (composite_nomem(state->conn.in.credentials, state->ctx)) { - return; - } - cli_credentials_set_conf(state->conn.in.credentials); - cli_credentials_set_anonymous(state->conn.in.credentials); - } - state->conn.in.fallback_to_anonymous = True; ctx = smb_composite_connect_send(&state->conn, state->domain, - state->ctx->event_ctx); - composite_continue(state->ctx, ctx, init_domain_recv_tree, state); -} - -static void init_domain_recv_dcip(struct composite_context *ctx) -{ - struct init_domain_state *state = - talloc_get_type(ctx->async.private_data, - struct init_domain_state); - - state->ctx->status = resolve_name_recv(ctx, state, &state->dcaddr); - if (!composite_is_ok(state->ctx)) return; - - state->conn.in.dest_host = state->dcaddr; - state->conn.in.port = 0; - state->conn.in.called_name = state->domain->dcname; - state->conn.in.service = "IPC$"; - state->conn.in.service_type = "IPC"; - state->conn.in.workgroup = state->domain->name; - state->conn.in.credentials = state->domain->schannel_creds; + result->event_ctx); + if (ctx == NULL) goto failed; - state->conn.in.fallback_to_anonymous = True; + ctx->async.fn = init_domain_recv_tree; + ctx->async.private_data = state; + return result; - ctx = smb_composite_connect_send(&state->conn, state->domain, - state->ctx->event_ctx); - composite_continue(state->ctx, ctx, init_domain_recv_tree, state); + failed: + talloc_free(result); + return NULL; } static void init_domain_recv_tree(struct composite_context *ctx) @@ -235,7 +151,7 @@ static void init_domain_recv_tree(struct composite_context *ctx) if ((state->domain->schannel_creds != NULL) && (!cli_credentials_is_anonymous(state->domain->schannel_creds)) && ((lp_server_role() == ROLE_DOMAIN_MEMBER) && - (dom_sid_equal(state->domain->sid, + (dom_sid_equal(state->domain->info->sid, state->service->primary_sid)))) { ctx = wb_get_schannel_creds_send(state, state->domain->schannel_creds, @@ -255,37 +171,36 @@ static void init_domain_recv_netlogoncreds(struct composite_context *ctx) struct init_domain_state *state = talloc_get_type(ctx->async.private_data, struct init_domain_state); + struct dcerpc_pipe *auth2_pipe; struct smbcli_tree *tree = NULL; - state->ctx->status = wb_get_schannel_creds_recv(ctx, state, - &state->auth2_pipe); + state->ctx->status = + wb_get_schannel_creds_recv(ctx, state, &auth2_pipe); if (!composite_is_ok(state->ctx)) return; if (!lp_winbind_sealed_pipes()) { - state->netlogon_pipe = talloc_reference(state, - state->auth2_pipe); + state->domain->netlogon_pipe = talloc_reference(state->domain, + auth2_pipe); ctx = wb_connect_lsa_send(state, state->conn.out.tree, NULL); composite_continue(state->ctx, ctx, init_domain_recv_lsa, state); return; } - state->netlogon_pipe = dcerpc_pipe_init(state, state->ctx->event_ctx); - if (composite_nomem(state->netlogon_pipe, state->ctx)) return; - - if (state->auth2_pipe != NULL) { - tree = dcerpc_smb_tree(state->auth2_pipe->conn); - } + state->domain->netlogon_pipe = + dcerpc_pipe_init(state->domain, state->ctx->event_ctx); + if (composite_nomem(state->domain->netlogon_pipe, state->ctx)) return; + tree = dcerpc_smb_tree(auth2_pipe->conn); if (tree == NULL) { composite_error(state->ctx, NT_STATUS_INTERNAL_ERROR); return; } - ctx = dcerpc_pipe_open_smb_send(state->netlogon_pipe->conn, tree, - "\\netlogon"); - composite_continue(state->ctx, ctx, - init_domain_recv_netlogonpipe, state); + ctx = dcerpc_pipe_open_smb_send(state->domain->netlogon_pipe->conn, + tree, "\\netlogon"); + composite_continue(state->ctx, ctx, init_domain_recv_netlogonpipe, + state); } static void init_domain_recv_netlogonpipe(struct composite_context *ctx) @@ -297,9 +212,10 @@ static void init_domain_recv_netlogonpipe(struct composite_context *ctx) state->ctx->status = dcerpc_pipe_open_smb_recv(ctx); if (!composite_is_ok(state->ctx)) return; - state->netlogon_pipe->conn->flags |= (DCERPC_SIGN | DCERPC_SEAL); + state->domain->netlogon_pipe->conn->flags |= + (DCERPC_SIGN | DCERPC_SEAL); state->ctx->status = - dcerpc_bind_auth_password(state->netlogon_pipe, + dcerpc_bind_auth_password(state->domain->netlogon_pipe, DCERPC_NETLOGON_UUID, DCERPC_NETLOGON_VERSION, state->domain->schannel_creds, @@ -320,19 +236,19 @@ static void init_domain_recv_lsa(struct composite_context *ctx) struct rpc_request *req; - state->ctx->status = wb_connect_lsa_recv(ctx, state, + state->ctx->status = wb_connect_lsa_recv(ctx, state->domain, &state->domain->lsa_auth_type, - &state->lsa_pipe, - &state->lsa_policy); + &state->domain->lsa_pipe, + &state->domain->lsa_policy); if (!composite_is_ok(state->ctx)) return; /* Give the tree to the pipes. */ -// talloc_unlink(state, state->conn.out.tree); + talloc_unlink(state, state->conn.out.tree); - state->queryinfo.in.handle = state->lsa_policy; + state->queryinfo.in.handle = state->domain->lsa_policy; state->queryinfo.in.level = LSA_POLICY_INFO_ACCOUNT_DOMAIN; - req = dcerpc_lsa_QueryInfoPolicy_send(state->lsa_pipe, state, + req = dcerpc_lsa_QueryInfoPolicy_send(state->domain->lsa_pipe, state, &state->queryinfo); composite_continue_rpc(state->ctx, req, init_domain_recv_queryinfo, state); @@ -353,31 +269,33 @@ static void init_domain_recv_queryinfo(struct rpc_request *req) dominfo = &state->queryinfo.out.info->account_domain; - if (strcasecmp(state->domain->name, dominfo->name.string) != 0) { + if (strcasecmp(state->domain->info->name, dominfo->name.string) != 0) { DEBUG(2, ("Expected domain name %s, DC %s said %s\n", - state->domain->name, - dcerpc_server_name(state->lsa_pipe), + state->domain->info->name, + dcerpc_server_name(state->domain->lsa_pipe), dominfo->name.string)); composite_error(state->ctx, NT_STATUS_INVALID_DOMAIN_STATE); return; } - if (!dom_sid_equal(state->domain->sid, dominfo->sid)) { + if (!dom_sid_equal(state->domain->info->sid, dominfo->sid)) { DEBUG(2, ("Expected domain sid %s, DC %s said %s\n", - dom_sid_string(state, state->domain->sid), - dcerpc_server_name(state->lsa_pipe), + dom_sid_string(state, state->domain->info->sid), + dcerpc_server_name(state->domain->lsa_pipe), dom_sid_string(state, dominfo->sid))); composite_error(state->ctx, NT_STATUS_INVALID_DOMAIN_STATE); return; } - state->ldap_conn = ldap_new_connection(state, state->ctx->event_ctx); - composite_nomem(state->ldap_conn, state->ctx); + state->domain->ldap_conn = + ldap_new_connection(state->domain, state->ctx->event_ctx); + composite_nomem(state->domain->ldap_conn, state->ctx); - ldap_url = talloc_asprintf(state, "ldap://%s/", state->dcaddr); + ldap_url = talloc_asprintf(state, "ldap://%s/", + state->domain->info->dc_address); composite_nomem(ldap_url, state->ctx); - ctx = ldap_connect_send(state->ldap_conn, ldap_url); + ctx = ldap_connect_send(state->domain->ldap_conn, ldap_url); composite_continue(state->ctx, ctx, init_domain_recv_ldapconn, state); } @@ -388,16 +306,25 @@ static void init_domain_recv_ldapconn(struct composite_context *ctx) struct init_domain_state); state->ctx->status = ldap_connect_recv(ctx); - DEBUG(0, ("ldap_connect returned %s\n", - nt_errstr(state->ctx->status))); + if (NT_STATUS_IS_OK(state->ctx->status)) { + state->domain->ldap_conn->host = + talloc_strdup(state->domain->ldap_conn, + state->domain->info->dc_name); + state->ctx->status = + ldap_bind_sasl(state->domain->ldap_conn, + state->domain->schannel_creds); + DEBUG(0, ("ldap_bind returned %s\n", + nt_errstr(state->ctx->status))); + } - state->samr_pipe = dcerpc_pipe_init(state, state->ctx->event_ctx); - if (composite_nomem(state->samr_pipe, state->ctx)) return; + state->domain->samr_pipe = + dcerpc_pipe_init(state->domain, state->ctx->event_ctx); + if (composite_nomem(state->domain->samr_pipe, state->ctx)) return; ctx = wb_connect_sam_send(state, state->conn.out.tree, state->domain->lsa_auth_type, state->domain->schannel_creds, - state->domain->sid); + state->domain->info->sid); composite_continue(state->ctx, ctx, init_domain_recv_samr, state); } @@ -407,61 +334,34 @@ static void init_domain_recv_samr(struct composite_context *ctx) talloc_get_type(ctx->async.private_data, struct init_domain_state); - state->ctx->status = wb_connect_sam_recv(ctx, state, &state->samr_pipe, - &state->samr_handle, - &state->domain_handle); + state->ctx->status = wb_connect_sam_recv( + ctx, state->domain, &state->domain->samr_pipe, + &state->domain->samr_handle, &state->domain->domain_handle); if (!composite_is_ok(state->ctx)) return; composite_done(state->ctx); } -NTSTATUS wb_init_domain_recv(struct composite_context *c) +NTSTATUS wb_init_domain_recv(struct composite_context *c, + TALLOC_CTX *mem_ctx, + struct wbsrv_domain **result) { NTSTATUS status = composite_wait(c); if (NT_STATUS_IS_OK(status)) { struct init_domain_state *state = talloc_get_type(c->private_data, struct init_domain_state); - struct wbsrv_domain *domain = state->domain; - - talloc_free(domain->netlogon_auth2_pipe); - domain->netlogon_auth2_pipe = - talloc_steal(domain, state->auth2_pipe); - - talloc_free(domain->netlogon_pipe); - domain->netlogon_pipe = - talloc_steal(domain, state->netlogon_pipe); - - talloc_free(domain->lsa_pipe); - domain->lsa_pipe = - talloc_steal(domain, state->lsa_pipe); - - talloc_free(domain->lsa_policy); - domain->lsa_policy = - talloc_steal(domain, state->lsa_policy); - - talloc_free(domain->samr_pipe); - domain->samr_pipe = - talloc_steal(domain, state->samr_pipe); - - talloc_free(domain->samr_handle); - domain->samr_handle = - talloc_steal(domain, state->samr_handle); - - talloc_free(domain->domain_handle); - domain->domain_handle = - talloc_steal(domain, state->domain_handle); - - domain->initialized = True; + *result = talloc_steal(mem_ctx, state->domain); } talloc_free(c); return status; } -NTSTATUS wb_init_domain(struct wbsrv_service *service, - struct wbsrv_domain *domain) +NTSTATUS wb_init_domain(TALLOC_CTX *mem_ctx, struct wbsrv_service *service, + struct wb_dom_info *dom_info, + struct wbsrv_domain **result) { struct composite_context *c = - wb_init_domain_send(service, domain); - return wb_init_domain_recv(c); + wb_init_domain_send(mem_ctx, service, dom_info); + return wb_init_domain_recv(c, mem_ctx, result); } diff --git a/source4/winbind/wb_samba3_cmd.c b/source4/winbind/wb_samba3_cmd.c index a5e7cb722b..d7496c2263 100644 --- a/source4/winbind/wb_samba3_cmd.c +++ b/source4/winbind/wb_samba3_cmd.c @@ -136,6 +136,7 @@ NTSTATUS wbsrv_samba3_ping(struct wbsrv_samba3_call *s3call) return NT_STATUS_OK; } +#if 0 /* Validate that we have a working pipe to the domain controller. Return any NT error found in the process @@ -169,6 +170,7 @@ static void checkmachacc_recv_creds(struct composite_context *ctx) wbsrv_samba3_async_auth_epilogue(status, s3call); } +#endif /* Find the name of a suitable domain controller, by query on the diff --git a/source4/winbind/wb_samba3_protocol.c b/source4/winbind/wb_samba3_protocol.c index f9e4c54ce2..f9eb7a09d4 100644 --- a/source4/winbind/wb_samba3_protocol.c +++ b/source4/winbind/wb_samba3_protocol.c @@ -75,8 +75,10 @@ NTSTATUS wbsrv_samba3_handle_call(struct wbsrv_call *call) case WINBINDD_INTERFACE_VERSION: return wbsrv_samba3_interface_version(s3call); +#if 0 case WINBINDD_CHECK_MACHACC: return wbsrv_samba3_check_machacc(s3call); +#endif case WINBINDD_PING: return wbsrv_samba3_ping(s3call); diff --git a/source4/winbind/wb_server.c b/source4/winbind/wb_server.c index d12adfc9d4..a66bc0832f 100644 --- a/source4/winbind/wb_server.c +++ b/source4/winbind/wb_server.c @@ -248,32 +248,6 @@ static const struct wbsrv_protocol_ops wbsrv_samba3_protocol_ops = { .push_reply = wbsrv_samba3_push_reply }; -static NTSTATUS init_my_domain(TALLOC_CTX *mem_ctx, - struct wbsrv_domain **domain) -{ - struct wbsrv_domain *result; - - result = talloc_zero(mem_ctx, struct wbsrv_domain); - NT_STATUS_HAVE_NO_MEMORY(result); - - result->name = talloc_strdup(result, lp_workgroup()); - if (result->name == NULL) { - talloc_free(result); - return NT_STATUS_NO_MEMORY; - } - - result->sid = secrets_get_domain_sid(result, lp_workgroup()); - if (result->sid == NULL) { - talloc_free(result); - return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; - } - - result->initialized = False; - - *domain = result; - return NT_STATUS_OK; -} - /* startup the winbind task */ @@ -304,16 +278,14 @@ static void winbind_task_init(struct task_server *task) if (!service) goto nomem; service->task = task; - status = init_my_domain(service, &service->domains); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("Could not init my domain: %s\n", - nt_errstr(status))); - task_server_terminate(task, nt_errstr(status)); + service->primary_sid = secrets_get_domain_sid(service, + lp_workgroup()); + if (service->primary_sid == NULL) { + task_server_terminate( + task, nt_errstr(NT_STATUS_CANT_ACCESS_DOMAIN_INFO)); return; } - service->primary_sid = talloc_reference(service, service->domains->sid); - /* setup the unprivileged samba3 socket */ listen_socket = talloc(service, struct wbsrv_listen_socket); if (!listen_socket) goto nomem; diff --git a/source4/winbind/wb_server.h b/source4/winbind/wb_server.h index 0407d89371..09afffb0c9 100644 --- a/source4/winbind/wb_server.h +++ b/source4/winbind/wb_server.h @@ -45,16 +45,20 @@ struct wbsrv_samconn { NTSTATUS (*seqnum_recv)(struct composite_context *, uint64_t *); }; -struct wbsrv_domain { - struct wbsrv_domain *next, *prev; - - BOOL initialized; - +struct wb_dom_info { const char *name; + const char *dns_name; const struct dom_sid *sid; - const char *dcname; - const char *dc_dnsname; + + const char *dc_name; + const char *dc_dns_name; const char *dc_address; +}; + +struct wbsrv_domain { + struct wbsrv_domain *next, *prev; + + struct wb_dom_info *info; struct dcerpc_pipe *lsa_pipe; struct policy_handle *lsa_policy; @@ -66,12 +70,8 @@ struct wbsrv_domain { struct ldap_connection *ldap_conn; - struct dcerpc_pipe *netlogon_auth2_pipe; struct dcerpc_pipe *netlogon_pipe; struct cli_credentials *schannel_creds; - - BOOL busy; - struct domain_request_state *request_queue; }; /* diff --git a/source4/winbind/wb_sid2domain.c b/source4/winbind/wb_sid2domain.c index 8940c8e9b7..70f8f4c626 100644 --- a/source4/winbind/wb_sid2domain.c +++ b/source4/winbind/wb_sid2domain.c @@ -31,37 +31,16 @@ #include "winbind/wb_async_helpers.h" #include "include/dlinklist.h" -static const char *sam_name(void) -{ - if (lp_server_role() == ROLE_STANDALONE) { - return lp_netbios_name(); - } - return lp_workgroup(); -} - -static struct wbsrv_domain *find_primary_domain(struct wbsrv_service *service) -{ - const char *my_domain_name = sam_name(); - struct wbsrv_domain *domain; - - for (domain = service->domains; domain!=NULL; domain = domain->next) { - if (strcasecmp(domain->name, my_domain_name) == 0) { - break; - } - } - return domain; -} - static struct wbsrv_domain *find_domain_from_sid(struct wbsrv_service *service, const struct dom_sid *sid) { struct wbsrv_domain *domain; for (domain = service->domains; domain!=NULL; domain = domain->next) { - if (dom_sid_equal(domain->sid, sid)) { + if (dom_sid_equal(domain->info->sid, sid)) { break; } - if (dom_sid_in_domain(domain->sid, sid)) { + if (dom_sid_in_domain(domain->info->sid, sid)) { break; } } @@ -71,22 +50,14 @@ static struct wbsrv_domain *find_domain_from_sid(struct wbsrv_service *service, struct sid2domain_state { struct composite_context *ctx; struct wbsrv_service *service; - const struct dom_sid *sid; - - const char *domain_name; - const char *dc_name; - struct dom_sid *domain_sid; + struct dom_sid *sid; - struct wbsrv_domain *my_domain; - struct wbsrv_domain *result; - - struct netr_DsRGetDCName dsr_getdcname; - struct netr_GetAnyDCName getdcname; + struct wbsrv_domain *domain; }; +static void sid2domain_recv_dom_info(struct composite_context *ctx); static void sid2domain_recv_name(struct composite_context *ctx); -static void sid2domain_recv_dsr_dcname(struct rpc_request *req); -static void sid2domain_recv_dcname(struct composite_context *ctx); +static void sid2domain_recv_trusted_dom_info(struct composite_context *ctx); static void sid2domain_recv_init(struct composite_context *ctx); struct composite_context *wb_sid2domain_send(TALLOC_CTX *mem_ctx, @@ -111,24 +82,20 @@ struct composite_context *wb_sid2domain_send(TALLOC_CTX *mem_ctx, state->sid = dom_sid_dup(state, sid); if (state->sid == NULL) goto failed; - state->result = find_domain_from_sid(service, sid); - if (state->result != NULL) { + state->domain = find_domain_from_sid(service, sid); + if (state->domain != NULL) { result->status = NT_STATUS_OK; - if (!state->result->initialized) { - ctx = wb_init_domain_send(service, state->result); - if (ctx == NULL) goto failed; - ctx->async.fn = sid2domain_recv_init; - ctx->async.private_data = state; - return result; - } composite_trigger_done(result); return result; } - state->my_domain = find_primary_domain(service); - if (state->my_domain == NULL) { - result->status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; - composite_trigger_error(result); + if (dom_sid_equal(service->primary_sid, sid) || + dom_sid_in_domain(service->primary_sid, sid)) { + ctx = wb_get_dom_info_send(state, service, lp_workgroup(), + service->primary_sid); + if (ctx == NULL) goto failed; + ctx->async.fn = sid2domain_recv_dom_info; + ctx->async.private_data = state; return result; } @@ -141,110 +108,62 @@ struct composite_context *wb_sid2domain_send(TALLOC_CTX *mem_ctx, failed: talloc_free(result); return NULL; + } -static void sid2domain_recv_name(struct composite_context *ctx) +static void sid2domain_recv_dom_info(struct composite_context *ctx) { struct sid2domain_state *state = talloc_get_type(ctx->async.private_data, struct sid2domain_state); - struct rpc_request *req; - struct wb_sid_object *name; + struct wb_dom_info *info; - state->ctx->status = wb_cmd_lookupsid_recv(ctx, state, &name); + state->ctx->status = wb_get_dom_info_recv(ctx, state, &info); if (!composite_is_ok(state->ctx)) return; - if (name->type == SID_NAME_UNKNOWN) { - composite_error(state->ctx, NT_STATUS_NO_SUCH_DOMAIN); - return; - } + ctx = wb_init_domain_send(state, state->service, info); - state->domain_name = name->domain; - state->domain_sid = dom_sid_dup(state, state->sid); - if (composite_nomem(state->domain_sid, state->ctx)) return; - - if (name->type != SID_NAME_DOMAIN) { - state->domain_sid->num_auths -= 1; - } - - state->dsr_getdcname.in.server_unc = - talloc_asprintf(state, "\\\\%s", state->my_domain->dcname); - if (composite_nomem(state->dsr_getdcname.in.server_unc, - state->ctx)) return; - - state->dsr_getdcname.in.domain_name = state->domain_name; - state->dsr_getdcname.in.domain_guid = NULL; - state->dsr_getdcname.in.site_guid = NULL; - state->dsr_getdcname.in.flags = 0x40000000; - - req = dcerpc_netr_DsRGetDCName_send(state->my_domain->netlogon_pipe, - state, &state->dsr_getdcname); - composite_continue_rpc(state->ctx, req, sid2domain_recv_dsr_dcname, - state); + composite_continue(state->ctx, ctx, sid2domain_recv_init, state); } -static void sid2domain_recv_dsr_dcname(struct rpc_request *req) +static void sid2domain_recv_name(struct composite_context *ctx) { struct sid2domain_state *state = - talloc_get_type(req->async.private, + talloc_get_type(ctx->async.private_data, struct sid2domain_state); - struct composite_context *ctx; + struct wb_sid_object *name; - state->ctx->status = dcerpc_ndr_request_recv(req); - if (!NT_STATUS_IS_OK(state->ctx->status)) { - DEBUG(9, ("dcerpc_ndr_request_recv returned %s\n", - nt_errstr(state->ctx->status))); - goto fallback; - } + state->ctx->status = wb_cmd_lookupsid_recv(ctx, state, &name); + if (!composite_is_ok(state->ctx)) return; - state->ctx->status = - werror_to_ntstatus(state->dsr_getdcname.out.result); - if (!NT_STATUS_IS_OK(state->ctx->status)) { - DEBUG(9, ("dsrgetdcname returned %s\n", - nt_errstr(state->ctx->status))); - goto fallback; + if (name->type == SID_NAME_UNKNOWN) { + composite_error(state->ctx, NT_STATUS_NO_SUCH_DOMAIN); + return; } - DEBUG(0, ("unc: %s, addr: %s, addr_type: %d, domain_name: %s, " - "forest_name: %s\n", - state->dsr_getdcname.out.info->dc_unc, - state->dsr_getdcname.out.info->dc_address, - state->dsr_getdcname.out.info->dc_address_type, - state->dsr_getdcname.out.info->domain_name, - state->dsr_getdcname.out.info->forest_name)); + if (name->type != SID_NAME_DOMAIN) { + state->sid->num_auths -= 1; + } - fallback: + ctx = wb_trusted_dom_info_send(state, state->service, name->domain, + state->sid); - ctx = wb_cmd_getdcname_send(state, state->service, state->domain_name); - composite_continue(state->ctx, ctx, sid2domain_recv_dcname, state); + composite_continue(state->ctx, ctx, sid2domain_recv_trusted_dom_info, + state); } -static void sid2domain_recv_dcname(struct composite_context *ctx) +static void sid2domain_recv_trusted_dom_info(struct composite_context *ctx) { struct sid2domain_state *state = talloc_get_type(ctx->async.private_data, struct sid2domain_state); + struct wb_dom_info *info; - state->ctx->status = wb_cmd_getdcname_recv(ctx, state, - &state->dc_name); + state->ctx->status = wb_trusted_dom_info_recv(ctx, state, &info); if (!composite_is_ok(state->ctx)) return; - state->result = talloc_zero(state, struct wbsrv_domain); - if (composite_nomem(state->result, state->ctx)) return; + ctx = wb_init_domain_send(state, state->service, info); - state->result->name = talloc_steal(state->result, state->domain_name); - state->result->sid = talloc_steal(state->result, state->domain_sid); - state->result->dcname = talloc_steal(state->result, state->dc_name); - - state->result->schannel_creds = cli_credentials_init(state->result); - if (composite_nomem(state->result->schannel_creds, state->ctx)) return; - cli_credentials_set_conf(state->result->schannel_creds); - cli_credentials_set_machine_account(state->result->schannel_creds); - - talloc_steal(state->service, state->result); - DLIST_ADD(state->service->domains, state->result); - - ctx = wb_init_domain_send(state->service, state->result); composite_continue(state->ctx, ctx, sid2domain_recv_init, state); } @@ -253,13 +172,25 @@ static void sid2domain_recv_init(struct composite_context *ctx) struct sid2domain_state *state = talloc_get_type(ctx->async.private_data, struct sid2domain_state); + struct wbsrv_domain *existing; - state->ctx->status = wb_init_domain_recv(ctx); + state->ctx->status = wb_init_domain_recv(ctx, state, + &state->domain); if (!composite_is_ok(state->ctx)) { DEBUG(10, ("Could not init domain\n")); return; } + existing = find_domain_from_sid(state->service, state->sid); + if (existing != NULL) { + DEBUG(5, ("Initialized domain twice, dropping second one\n")); + talloc_free(state->domain); + state->domain = existing; + } + + talloc_steal(state->service, state->domain); + DLIST_ADD(state->service->domains, state->domain); + composite_done(state->ctx); } @@ -271,7 +202,7 @@ NTSTATUS wb_sid2domain_recv(struct composite_context *ctx, struct sid2domain_state *state = talloc_get_type(ctx->private_data, struct sid2domain_state); - *result = state->result; + *result = state->domain; } talloc_free(ctx); return status; -- cgit