/* 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, &state->domain->netlogon_pipe); if (!composite_is_ok(state->ctx)) { talloc_free(state->domain->netlogon_binding); return; } talloc_steal(state->domain->netlogon_pipe, state->domain->netlogon_binding); state->domain->lsa_binding = init_domain_binding(state, &dcerpc_table_lsarpc); /* For debugging, it can be a real pain if all the traffic is encrypted */ if (lp_winbind_sealed_pipes()) { state->domain->lsa_binding->flags |= (DCERPC_SIGN | DCERPC_SEAL ); } else { state->domain->lsa_binding->flags |= (DCERPC_SIGN); } state->domain->lsa_pipe = NULL; /* this will make the secondary connection on the same IPC$ share, secured with SPNEGO or NTLMSSP */ ctx = dcerpc_secondary_connection_send(state->domain->netlogon_pipe, state->domain->lsa_binding); composite_continue(state->ctx, ctx, init_domain_recv_lsa_pipe, state); }
static void init_domain_recv_queryinfo(struct tevent_req *subreq) { struct init_domain_state *state = tevent_req_callback_data(subreq, struct init_domain_state); struct lsa_DomainInfo *dominfo; struct composite_context *ctx; uint32_t lflags; state->ctx->status = dcerpc_lsa_QueryInfoPolicy_r_recv(subreq, state); TALLOC_FREE(subreq); if (!composite_is_ok(state->ctx)) return; state->ctx->status = state->queryinfo.out.result; if (!composite_is_ok(state->ctx)) return; if (!dom_sid_equal(state->domain->info->sid, &global_sid_Builtin)) { dominfo = &(*state->queryinfo.out.info)->account_domain; if (strcasecmp(state->domain->info->name, dominfo->name.string) != 0) { DEBUG(2, ("Expected domain name %s, DC %s said %s\n", state->domain->info->name, dcerpc_server_name(state->domain->libnet_ctx->lsa.pipe), dominfo->name.string)); composite_error(state->ctx, NT_STATUS_INVALID_DOMAIN_STATE); return; } 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->info->sid), dcerpc_server_name(state->domain->libnet_ctx->lsa.pipe), dom_sid_string(state, dominfo->sid))); composite_error(state->ctx, NT_STATUS_INVALID_DOMAIN_STATE); return; } } state->domain->samr_binding = init_domain_binding(state, &ndr_table_samr); /* We want to use the same flags as the LSA pipe did (so, if * it needed schannel, then we need that here too) */ lflags = dcerpc_binding_get_flags(state->domain->lsa_binding); state->ctx->status = dcerpc_binding_set_flags(state->domain->samr_binding, lflags, 0); if (!composite_is_ok(state->ctx)) return; state->domain->libnet_ctx->samr.pipe = NULL; state->domain->libnet_ctx->samr.samr_handle = NULL; ctx = wb_connect_samr_send(state, state->domain); composite_continue(state->ctx, ctx, init_domain_recv_samr, state); }
/* 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); uint32_t flags; state->ctx->status = dcerpc_pipe_connect_b_recv(ctx, state->domain, &state->domain->netlogon_pipe); if (!composite_is_ok(state->ctx)) { return; } talloc_reparent(state, state->domain->netlogon_pipe, state->domain->netlogon_binding); /* the netlogon connection is ready */ tevent_queue_start(state->domain->netlogon_queue); 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 (lpcfg_winbind_sealed_pipes(state->service->task->lp_ctx)) { flags = DCERPC_SIGN | DCERPC_SEAL; } else { flags = DCERPC_SIGN; } state->ctx->status = dcerpc_binding_set_flags(state->domain->lsa_binding, flags, 0); if (!composite_is_ok(state->ctx)) { return; } state->domain->libnet_ctx->lsa.pipe = NULL; state->domain->libnet_ctx->lsa.lsa_handle = 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, state->domain->libnet_ctx->cred, state->domain->libnet_ctx->lp_ctx ); composite_continue(state->ctx, ctx, init_domain_recv_lsa_pipe, state); }
static void init_domain_recv_queryinfo(struct rpc_request *req) { struct init_domain_state *state = talloc_get_type(req->async.private_data, struct init_domain_state); struct lsa_DomainInfo *dominfo; struct composite_context *ctx; state->ctx->status = dcerpc_ndr_request_recv(req); if (!composite_is_ok(state->ctx)) return; state->ctx->status = state->queryinfo.out.result; if (!composite_is_ok(state->ctx)) return; dominfo = &state->queryinfo.out.info->account_domain; if (strcasecmp(state->domain->info->name, dominfo->name.string) != 0) { DEBUG(2, ("Expected domain name %s, DC %s said %s\n", 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->info->sid, dominfo->sid)) { DEBUG(2, ("Expected domain sid %s, DC %s said %s\n", 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->domain->samr_binding = init_domain_binding(state, &dcerpc_table_samr); /* We want to use the same flags as the LSA pipe did (so, if * it needed schannel, then we need that here too) */ state->domain->samr_binding->flags = state->domain->lsa_binding->flags; state->domain->samr_pipe = NULL; ctx = wb_connect_samr_send(state, state->domain); composite_continue(state->ctx, ctx, init_domain_recv_samr, state); }
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; /* Create a credentials structure */ state->domain->schannel_creds = cli_credentials_init(state->domain); if (state->domain->schannel_creds == NULL) goto failed; cli_credentials_set_event_context(state->domain->schannel_creds, service->task->event_ctx); cli_credentials_set_conf(state->domain->schannel_creds); /* Connect the machine account to the credentials */ state->ctx->status = cli_credentials_set_machine_account(state->domain-> schannel_creds); if (!NT_STATUS_IS_OK(state->ctx->status)) goto failed; state->domain->netlogon_binding = init_domain_binding(state, &dcerpc_table_netlogon); state->domain->netlogon_pipe = NULL; if ((!cli_credentials_is_anonymous(state->domain->schannel_creds)) && ((lp_server_role() == ROLE_DOMAIN_MEMBER) && (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()) { 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, &dcerpc_table_netlogon, state->domain->schannel_creds, service->task->event_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; }
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->service = service; state->domain->info = talloc_reference(state->domain, dom_info); if (state->domain->info == NULL) goto failed; state->domain->dc_name = dom_info->dc->name; state->domain->dc_address = dom_info->dc->address; state->domain->libnet_ctx = libnet_context_init(service->task->event_ctx, service->task->lp_ctx); if (state->domain->libnet_ctx == NULL) goto failed; talloc_steal(state->domain, state->domain->libnet_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; state->domain->netlogon_queue = tevent_queue_create(state->domain, "netlogon_queue"); if (state->domain->netlogon_queue == NULL) goto failed; /* We start the queue when the connection is usable */ tevent_queue_stop(state->domain->netlogon_queue); if ((!cli_credentials_is_anonymous(state->domain->libnet_ctx->cred)) && ((lpcfg_server_role(service->task->lp_ctx) == ROLE_DOMAIN_MEMBER) || (lpcfg_server_role(service->task->lp_ctx) == ROLE_ACTIVE_DIRECTORY_DC)) && (dom_sid_equal(state->domain->info->sid, state->service->primary_sid))) { uint32_t flags = DCERPC_SCHANNEL | DCERPC_SCHANNEL_AUTO; /* For debugging, it can be a real pain if all the traffic is encrypted */ if (lpcfg_winbind_sealed_pipes(service->task->lp_ctx)) { flags |= DCERPC_SIGN | DCERPC_SEAL; } else { flags |= DCERPC_SIGN; } state->ctx->status = dcerpc_binding_set_flags(state->domain->netlogon_binding, flags, 0); if (!NT_STATUS_IS_OK(state->ctx->status)) goto failed; } /* 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; }