📄 wb_init_domain.c
字号:
/* Unix SMB/CIFS implementation. A composite API for initializing a domain Copyright (C) Volker Lendecke 2005 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007 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 "libcli/composite/composite.h"#include "libcli/smb_composite/smb_composite.h"#include "winbind/wb_server.h"#include "winbind/wb_async_helpers.h"#include "winbind/wb_helper.h"#include "smbd/service_task.h"#include "librpc/gen_ndr/ndr_netlogon.h"#include "librpc/gen_ndr/ndr_lsa_c.h"#include "librpc/gen_ndr/ndr_samr_c.h"#include "libcli/libcli.h"#include "libcli/auth/credentials.h"#include "libcli/security/security.h"#include "libcli/ldap/ldap_client.h"#include "auth/credentials/credentials.h"#include "param/param.h"/* * Initialize a domain: * * - With schannel credentials, try to open the SMB connection and * NETLOGON pipe with the machine creds. This works against W2k3SP1 * with an NTLMSSP session setup. Fall back to anonymous (for the CIFS level). * * - If we have schannel creds, do the auth2 and open the schannel'ed netlogon * pipe. * * - Open LSA. If we have machine creds, try to open with SPNEGO or NTLMSSP. Fall back * to schannel. * * - With queryinfopolicy, verify that we're talking to the right domain * * A bit complex, but with all the combinations I think it's the best we can * get. NT4, W2k3 and W2k all have different combinations, but in the end we * have a signed&sealed lsa connection on all of them. * * Not sure if it is overkill, but it seems to work. */struct init_domain_state { struct composite_context *ctx; struct wbsrv_domain *domain; struct wbsrv_service *service; struct lsa_ObjectAttribute objectattr; struct lsa_OpenPolicy2 lsa_openpolicy; struct lsa_QueryInfoPolicy queryinfo;};static void init_domain_recv_netlogonpipe(struct composite_context *ctx);static void init_domain_recv_lsa_pipe(struct composite_context *ctx);static void init_domain_recv_lsa_policy(struct rpc_request *req);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);static struct dcerpc_binding *init_domain_binding(struct init_domain_state *state, const struct ndr_interface_table *table) { struct dcerpc_binding *binding; NTSTATUS status; /* Make a binding string */ { char *s = talloc_asprintf(state, "ncacn_np:%s", state->domain->dc_name); if (s == NULL) return NULL; status = dcerpc_parse_binding(state, s, &binding); talloc_free(s); if (!NT_STATUS_IS_OK(status)) { return NULL; } } /* Alter binding to contain hostname, but also address (so we don't look it up twice) */ binding->target_hostname = state->domain->dc_name; binding->host = state->domain->dc_address; /* This shouldn't make a network call, as the mappings for named pipes are well known */ status = dcerpc_epm_map_binding(binding, binding, table, state->service->task->event_ctx, state->service->task->lp_ctx); if (!NT_STATUS_IS_OK(status)) { return NULL; } return binding;}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 = composite_create(mem_ctx, service->task->event_ctx); if (result == NULL) goto failed; state = talloc_zero(result, struct init_domain_state); if (state == NULL) goto failed; state->ctx = result; result->private_data = state; state->service = service; 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; /* Caller should check, but to be safe: */ if (dom_info->num_dcs < 1) { goto failed; } /* For now, we just pick the first. The next step will be to * walk the entire list. Also need to fix finddcs() to return * the entire list */ state->domain->dc_name = dom_info->dcs[0].name; state->domain->dc_address = dom_info->dcs[0].address; state->domain->libnet_ctx = libnet_context_init(service->task->event_ctx, service->task->lp_ctx); /* Create a credentials structure */ state->domain->libnet_ctx->cred = cli_credentials_init(state->domain); if (state->domain->libnet_ctx->cred == NULL) goto failed; cli_credentials_set_conf(state->domain->libnet_ctx->cred, service->task->lp_ctx); /* Connect the machine account to the credentials */ state->ctx->status = cli_credentials_set_machine_account(state->domain->libnet_ctx->cred, state->domain->libnet_ctx->lp_ctx); if (!NT_STATUS_IS_OK(state->ctx->status)) goto failed; state->domain->netlogon_binding = init_domain_binding(state, &ndr_table_netlogon); state->domain->netlogon_pipe = NULL; if ((!cli_credentials_is_anonymous(state->domain->libnet_ctx->cred)) && ((lp_server_role(service->task->lp_ctx) == ROLE_DOMAIN_MEMBER) || (lp_server_role(service->task->lp_ctx) == ROLE_DOMAIN_CONTROLLER)) && (dom_sid_equal(state->domain->info->sid, state->service->primary_sid))) { state->domain->netlogon_binding->flags |= DCERPC_SCHANNEL; /* For debugging, it can be a real pain if all the traffic is encrypted */ if (lp_winbind_sealed_pipes(service->task->lp_ctx)) { state->domain->netlogon_binding->flags |= (DCERPC_SIGN | DCERPC_SEAL ); } else { state->domain->netlogon_binding->flags |= (DCERPC_SIGN); } } /* No encryption on anonymous pipes */ ctx = dcerpc_pipe_connect_b_send(state, state->domain->netlogon_binding, &ndr_table_netlogon, state->domain->libnet_ctx->cred, service->task->event_ctx, service->task->lp_ctx); if (composite_nomem(ctx, state->ctx)) { goto failed; } composite_continue(state->ctx, ctx, init_domain_recv_netlogonpipe, state); return result; failed: talloc_free(result); return NULL;}/* Having make a netlogon connection (possibly secured with schannel), * make an LSA connection to the same DC, on the same IPC$ share */static void init_domain_recv_netlogonpipe(struct composite_context *ctx){ struct init_domain_state *state = talloc_get_type(ctx->async.private_data, struct init_domain_state); state->ctx->status = dcerpc_pipe_connect_b_recv(ctx, state->domain, &state->domain->netlogon_pipe); if (!composite_is_ok(state->ctx)) { return; } talloc_steal(state->domain->netlogon_pipe, state->domain->netlogon_binding); state->domain->lsa_binding = init_domain_binding(state, &ndr_table_lsarpc); /* For debugging, it can be a real pain if all the traffic is encrypted */ if (lp_winbind_sealed_pipes(state->service->task->lp_ctx)) { state->domain->lsa_binding->flags |= (DCERPC_SIGN | DCERPC_SEAL ); } else { state->domain->lsa_binding->flags |= (DCERPC_SIGN); } state->domain->libnet_ctx->lsa.pipe = NULL; /* this will make the secondary connection on the same IPC$ share, secured with SPNEGO or NTLMSSP */ ctx = dcerpc_secondary_auth_connection_send(state->domain->netlogon_pipe, state->domain->lsa_binding, &ndr_table_lsarpc,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -