/* Recv the SAMR details (SamrConnect and SamrOpenDomain handle) and * open an LDAP connection */ static void init_domain_recv_samr(struct composite_context *ctx) { const char *ldap_url; struct init_domain_state *state = talloc_get_type(ctx->async.private_data, struct init_domain_state); state->ctx->status = wb_connect_samr_recv( ctx, state->domain, &state->domain->samr_pipe, &state->domain->samr_handle, &state->domain->domain_handle); if (!composite_is_ok(state->ctx)) return; talloc_steal(state->domain->samr_pipe, state->domain->samr_binding); state->domain->ldap_conn = ldap4_new_connection(state->domain, state->ctx->event_ctx); composite_nomem(state->domain->ldap_conn, state->ctx); ldap_url = talloc_asprintf(state, "ldap://%s/", state->domain->dc_address); composite_nomem(ldap_url, state->ctx); ctx = ldap_connect_send(state->domain->ldap_conn, ldap_url); composite_continue(state->ctx, ctx, init_domain_recv_ldapconn, 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); 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 bool retry_with_schannel(struct init_domain_state *state, struct dcerpc_binding *binding, const struct ndr_interface_table *table, void (*continuation)(struct composite_context *)) { struct composite_context *ctx; state->ctx->status = NT_STATUS_OK; if (state->domain->netlogon_binding->flags & DCERPC_SCHANNEL && !(binding->flags & DCERPC_SCHANNEL)) { /* Opening a policy handle failed, perhaps it was * because we don't get a 'wrong password' error on * NTLMSSP binds */ /* Try again with schannel */ binding->flags |= DCERPC_SCHANNEL; /* Try again, likewise on the same IPC$ share, secured with SCHANNEL */ ctx = dcerpc_secondary_auth_connection_send(state->domain->netlogon_pipe, binding, table, state->domain->libnet_ctx->cred, state->domain->libnet_ctx->lp_ctx); composite_continue(state->ctx, ctx, continuation, state); return true; } else { return false; } }
static void unbecomeDC_drsuapi_connect_send(struct libnet_UnbecomeDC_state *s) { struct composite_context *c = s->creq; struct composite_context *creq; char *binding_str; binding_str = talloc_asprintf(s, "ncacn_ip_tcp:%s[seal,target_hostname=%s]", s->source_dsa.address, s->source_dsa.dns_name); if (composite_nomem(binding_str, c)) return; c->status = dcerpc_parse_binding(s, binding_str, &s->drsuapi.binding); talloc_free(binding_str); if (!composite_is_ok(c)) return; if (DEBUGLEVEL >= 10) { c->status = dcerpc_binding_set_flags(s->drsuapi.binding, DCERPC_DEBUG_PRINT_BOTH, 0); if (!composite_is_ok(c)) return; } creq = dcerpc_pipe_connect_b_send(s, s->drsuapi.binding, &ndr_table_drsuapi, s->libnet->cred, s->libnet->event_ctx, s->libnet->lp_ctx); composite_continue(c, creq, unbecomeDC_drsuapi_connect_recv, s); }
BOOL lsa_domain_opened(struct libnet_context *ctx, const char *domain_name, struct composite_context **parent_ctx, struct libnet_DomainOpen *domain_open, void (*continue_fn)(struct composite_context*), void (*monitor)(struct monitor_msg*)) { struct composite_context *domopen_req; if (parent_ctx == NULL || *parent_ctx == NULL) return False; if (domain_name == NULL) { /* * Try to guess the domain name from credentials, * if it's not been explicitly specified. */ if (policy_handle_empty(&ctx->lsa.handle)) { domain_open->in.type = DOMAIN_LSA; domain_open->in.domain_name = cli_credentials_get_domain(ctx->cred); domain_open->in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; } else { composite_error(*parent_ctx, NT_STATUS_INVALID_PARAMETER); /* this ensures the calling function exits and composite function error gets noticed quickly */ return True; } } else { /* * The domain name has been specified, so check whether the same * domain is already opened. If it is - just return NULL. Start * opening a new domain otherwise. */ if (policy_handle_empty(&ctx->lsa.handle) || !strequal(domain_name, ctx->lsa.name)) { domain_open->in.type = DOMAIN_LSA; domain_open->in.domain_name = domain_name; domain_open->in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; } else { /* domain has already been opened and it's the same domain as requested */ return True; } } /* send request to open the domain */ domopen_req = libnet_DomainOpen_send(ctx, domain_open, monitor); /* see the comment above to find out why true is returned here */ if (composite_nomem(domopen_req, *parent_ctx)) return True; composite_continue(*parent_ctx, domopen_req, continue_fn, *parent_ctx); return False; }
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); }
static BOOL torture_wbem_login_async(struct torture_context *torture) { BOOL ret = True; TALLOC_CTX *mem_ctx = talloc_init("torture_wbem_login_async"); struct com_context *com_ctx = NULL; const char *binding = NULL; struct composite_context *c = NULL; struct composite_context *new_ctx = NULL; struct GUID clsid; struct GUID iid; /* * Initialize our COM and DCOM contexts. */ com_init_ctx(&com_ctx, NULL); dcom_client_init(com_ctx, cmdline_credentials); /* * Pull our needed test arguments from the torture parameters subsystem. */ binding = torture_setting_string(torture, "binding", NULL); /* * Create a new composite for our call sequence, with the private data being * our return flag. */ c = composite_create(mem_ctx, com_ctx->event_ctx); c->private_data = &ret; /* * Create the parameters needed for the activation call: we need the CLSID * and IID for the specific interface we're after. */ GUID_from_string(CLSID_WBEMLEVEL1LOGIN, &clsid); GUID_from_string(COM_IWBEMLEVEL1LOGIN_UUID, &iid); /* * Fire off the asynchronous activation request with all the needed * input parameters. Then wait for the composite to be done within the * context of this function, which allows all the asynchronous magic to * still happen. */ new_ctx = dcom_activate_send(c, &clsid, binding, 1, &iid, com_ctx); composite_continue(c, new_ctx, torture_wbem_login_async_cont, c); composite_wait(new_ctx); talloc_free(c); talloc_report_full(mem_ctx, stdout); return ret; }
/* 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 unbecomeDC_drsuapi_connect_send(struct libnet_UnbecomeDC_state *s) { struct composite_context *c = s->creq; struct composite_context *creq; char *binding_str; binding_str = talloc_asprintf(s, "ncacn_ip_tcp:%s[seal]", s->source_dsa.dns_name); if (composite_nomem(binding_str, c)) return; c->status = dcerpc_parse_binding(s, binding_str, &s->drsuapi.binding); talloc_free(binding_str); if (!composite_is_ok(c)) return; creq = dcerpc_pipe_connect_b_send(s, s->drsuapi.binding, &ndr_table_drsuapi, s->libnet->cred, s->libnet->event_ctx, s->libnet->lp_ctx); composite_continue(c, creq, unbecomeDC_drsuapi_connect_recv, s); }
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; }