static void init_domain_recv_lsa_policy(struct tevent_req *subreq) { struct init_domain_state *state = tevent_req_callback_data(subreq, struct init_domain_state); state->ctx->status = dcerpc_lsa_OpenPolicy2_r_recv(subreq, state); TALLOC_FREE(subreq); if ((!NT_STATUS_IS_OK(state->ctx->status) || !NT_STATUS_IS_OK(state->lsa_openpolicy.out.result))) { if (retry_with_schannel(state, state->domain->lsa_binding, &ndr_table_lsarpc, init_domain_recv_lsa_pipe)) { return; } } if (!composite_is_ok(state->ctx)) return; state->ctx->status = state->lsa_openpolicy.out.result; if (!composite_is_ok(state->ctx)) return; state->info = talloc_zero(state->ctx, union lsa_PolicyInformation); if (composite_nomem(state->info, state->ctx)) return; state->queryinfo.in.handle = &state->domain->libnet_ctx->lsa.handle; state->queryinfo.in.level = LSA_POLICY_INFO_ACCOUNT_DOMAIN; state->queryinfo.out.info = &state->info; subreq = dcerpc_lsa_QueryInfoPolicy_r_send(state, state->ctx->event_ctx, state->domain->libnet_ctx->lsa.pipe->binding_handle, &state->queryinfo); if (composite_nomem(subreq, state->ctx)) return; tevent_req_set_callback(subreq, init_domain_recv_queryinfo, state); }
/* 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); }
static struct composite_context *wreplsrv_pull_table_send(TALLOC_CTX *mem_ctx, struct wreplsrv_pull_table_io *io) { struct composite_context *c = NULL; struct wreplsrv_service *service = io->in.partner->service; struct wreplsrv_pull_table_state *state = NULL; c = talloc_zero(mem_ctx, struct composite_context); if (!c) goto failed; state = talloc_zero(c, struct wreplsrv_pull_table_state); if (!state) goto failed; state->c = c; state->io = io; c->state = COMPOSITE_STATE_IN_PROGRESS; c->event_ctx = service->task->event_ctx; c->private_data = state; if (io->in.num_owners) { struct wrepl_wins_owner *partners; uint32_t i; partners = talloc_array(state, struct wrepl_wins_owner, io->in.num_owners); if (composite_nomem(partners, c)) goto failed; for (i=0; i < io->in.num_owners; i++) { partners[i] = io->in.owners[i]; partners[i].address = talloc_strdup(partners, io->in.owners[i].address); if (composite_nomem(partners[i].address, c)) goto failed; } state->table_io.out.num_partners = io->in.num_owners; state->table_io.out.partners = partners; state->stage = WREPLSRV_PULL_TABLE_STAGE_DONE; composite_done(c); return c; } state->stage = WREPLSRV_PULL_TABLE_STAGE_WAIT_CONNECTION; state->creq = wreplsrv_out_connect_send(io->in.partner, WINSREPL_PARTNER_PULL, NULL); if (!state->creq) goto failed; state->creq->async.fn = wreplsrv_pull_table_handler_creq; state->creq->async.private_data = state; return c; failed: talloc_free(c); return NULL; }
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); }
static void init_domain_recv_lsa_policy(struct rpc_request *req) { struct init_domain_state *state = talloc_get_type(req->async.private_data, struct init_domain_state); state->ctx->status = dcerpc_ndr_request_recv(req); if ((!NT_STATUS_IS_OK(state->ctx->status) || !NT_STATUS_IS_OK(state->lsa_openpolicy.out.result))) { if (retry_with_schannel(state, state->domain->lsa_binding, &ndr_table_lsarpc, init_domain_recv_lsa_pipe)) { return; } } if (!composite_is_ok(state->ctx)) return; state->ctx->status = state->lsa_openpolicy.out.result; if (!composite_is_ok(state->ctx)) return; state->info = talloc_zero(state->ctx, union lsa_PolicyInformation); if (composite_nomem(state->info, state->ctx)) return; state->queryinfo.in.handle = &state->domain->libnet_ctx->lsa.handle; state->queryinfo.in.level = LSA_POLICY_INFO_ACCOUNT_DOMAIN; state->queryinfo.out.info = &state->info; req = dcerpc_lsa_QueryInfoPolicy_send(state->domain->libnet_ctx->lsa.pipe, state, &state->queryinfo); composite_continue_rpc(state->ctx, req, init_domain_recv_queryinfo, state); }
static void unbecomeDC_drsuapi_bind_send(struct libnet_UnbecomeDC_state *s) { struct composite_context *c = s->creq; struct drsuapi_DsBindInfo28 *bind_info28; struct tevent_req *subreq; GUID_from_string(DRSUAPI_DS_BIND_GUID, &s->drsuapi.bind_guid); bind_info28 = &s->drsuapi.local_info28; bind_info28->supported_extensions = 0; bind_info28->site_guid = GUID_zero(); bind_info28->pid = 0; bind_info28->repl_epoch = 0; s->drsuapi.bind_info_ctr.length = 28; s->drsuapi.bind_info_ctr.info.info28 = *bind_info28; s->drsuapi.bind_r.in.bind_guid = &s->drsuapi.bind_guid; s->drsuapi.bind_r.in.bind_info = &s->drsuapi.bind_info_ctr; s->drsuapi.bind_r.out.bind_handle = &s->drsuapi.bind_handle; subreq = dcerpc_drsuapi_DsBind_r_send(s, c->event_ctx, s->drsuapi.drsuapi_handle, &s->drsuapi.bind_r); if (composite_nomem(subreq, c)) return; tevent_req_set_callback(subreq, unbecomeDC_drsuapi_bind_recv, s); }
static void unbecomeDC_send_cldap(struct libnet_UnbecomeDC_state *s) { struct composite_context *c = s->creq; struct tevent_req *req; struct tsocket_address *dest_address; int ret; s->cldap.io.in.dest_address = NULL; s->cldap.io.in.dest_port = 0; s->cldap.io.in.realm = s->domain.dns_name; s->cldap.io.in.host = s->dest_dsa.netbios_name; s->cldap.io.in.user = NULL; s->cldap.io.in.domain_guid = NULL; s->cldap.io.in.domain_sid = NULL; s->cldap.io.in.acct_control = -1; s->cldap.io.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX; s->cldap.io.in.map_response = true; ret = tsocket_address_inet_from_strings(s, "ip", s->source_dsa.address, lpcfg_cldap_port(s->libnet->lp_ctx), &dest_address); if (ret != 0) { c->status = map_nt_error_from_unix_common(errno); if (!composite_is_ok(c)) return; } c->status = cldap_socket_init(s, NULL, dest_address, &s->cldap.sock); if (!composite_is_ok(c)) return; req = cldap_netlogon_send(s, s->libnet->event_ctx, s->cldap.sock, &s->cldap.io); if (composite_nomem(req, c)) return; tevent_req_set_callback(req, unbecomeDC_recv_cldap, s); }
_PUBLIC_ void composite_continue_nbt(struct composite_context *ctx, struct nbt_name_request *new_req, void (*continuation)(struct nbt_name_request *), void *private_data) { if (composite_nomem(new_req, ctx)) return; new_req->async.fn = continuation; new_req->async.private_data = private_data; }
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; }
_PUBLIC_ void composite_continue_smb2(struct composite_context *ctx, struct smb2_request *new_req, void (*continuation)(struct smb2_request *), void *private_data) { if (composite_nomem(new_req, ctx)) return; if (new_req->state > SMB2_REQUEST_RECV) { composite_error(ctx, new_req->status); return; } new_req->async.fn = continuation; new_req->async.private_data = private_data; }
_PUBLIC_ void composite_continue(struct composite_context *ctx, struct composite_context *new_ctx, void (*continuation)(struct composite_context *), void *private_data) { if (composite_nomem(new_ctx, ctx)) return; new_ctx->async.fn = continuation; new_ctx->async.private_data = private_data; /* if we are setting up a continuation, and the context has already finished, then we should run the callback with an immediate event, otherwise we can be stuck forever */ if (new_ctx->state >= COMPOSITE_STATE_DONE && continuation) { tevent_add_timer(new_ctx->event_ctx, new_ctx, timeval_zero(), composite_trigger, new_ctx); } }
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); }
/* composite session setup function that hides the details of all the different session setup varients, including the multi-pass nature of the spnego varient */ struct composite_context *smb_composite_sesssetup_send(struct smbcli_session *session, struct smb_composite_sesssetup *io) { struct composite_context *c; struct sesssetup_state *state; NTSTATUS status; c = composite_create(session, session->transport->ev); if (c == NULL) return NULL; state = talloc_zero(c, struct sesssetup_state); if (composite_nomem(state, c)) return c; c->private_data = state; state->io = io; talloc_set_destructor(state, sesssetup_state_destructor); /* no session setup at all in earliest protocol varients */ if (session->transport->negotiate.protocol < PROTOCOL_LANMAN1) { ZERO_STRUCT(io->out); composite_done(c); return c; } /* see what session setup interface we will use */ if (session->transport->negotiate.protocol < PROTOCOL_NT1) { status = session_setup_old(c, session, io, &state->req); } else if (!session->transport->options.use_spnego || !(io->in.capabilities & CAP_EXTENDED_SECURITY)) { status = session_setup_nt1(c, session, io, &state->req); } else { status = session_setup_spnego(c, session, io, &state->req); } if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) || NT_STATUS_IS_OK(status)) { composite_continue_smb(c, state->req, request_handler, c); return c; } composite_error(c, status); return c; }
/* We should now have either an authenticated LSA pipe, or an error. * On success, open a policy handle */ static void init_domain_recv_lsa_pipe(struct composite_context *ctx) { struct init_domain_state *state = talloc_get_type(ctx->async.private_data, struct init_domain_state); struct tevent_req *subreq; state->ctx->status = dcerpc_secondary_auth_connection_recv(ctx, state->domain, &state->domain->libnet_ctx->lsa.pipe); if (NT_STATUS_EQUAL(state->ctx->status, NT_STATUS_LOGON_FAILURE)) { if (retry_with_schannel(state, state->domain->lsa_binding, &ndr_table_lsarpc, init_domain_recv_lsa_pipe)) { return; } } if (!composite_is_ok(state->ctx)) return; talloc_steal(state->domain->libnet_ctx, state->domain->libnet_ctx->lsa.pipe); talloc_reparent(state, state->domain->libnet_ctx->lsa.pipe, state->domain->lsa_binding); state->domain->libnet_ctx->lsa.lsa_handle = state->domain->libnet_ctx->lsa.pipe->binding_handle; state->domain->libnet_ctx->lsa.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; state->domain->libnet_ctx->lsa.name = state->domain->info->name; ZERO_STRUCT(state->domain->libnet_ctx->lsa.handle); state->lsa_openpolicy.in.system_name = talloc_asprintf(state, "\\\\%s", dcerpc_server_name(state->domain->libnet_ctx->lsa.pipe)); ZERO_STRUCT(state->objectattr); state->lsa_openpolicy.in.attr = &state->objectattr; state->lsa_openpolicy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; state->lsa_openpolicy.out.handle = &state->domain->libnet_ctx->lsa.handle; subreq = dcerpc_lsa_OpenPolicy2_r_send(state, state->ctx->event_ctx, state->domain->libnet_ctx->lsa.pipe->binding_handle, &state->lsa_openpolicy); if (composite_nomem(subreq, state->ctx)) return; tevent_req_set_callback(subreq, init_domain_recv_lsa_policy, state); }
static void unbecomeDC_drsuapi_remove_ds_server_send(struct libnet_UnbecomeDC_state *s) { struct composite_context *c = s->creq; struct drsuapi_DsRemoveDSServer *r = &s->drsuapi.rm_ds_srv_r; struct tevent_req *subreq; r->in.bind_handle = &s->drsuapi.bind_handle; r->in.level = 1; r->in.req = talloc(s, union drsuapi_DsRemoveDSServerRequest); r->in.req->req1.server_dn = s->dest_dsa.server_dn_str; r->in.req->req1.domain_dn = s->domain.dn_str; r->in.req->req1.commit = true; r->out.level_out = talloc(s, uint32_t); r->out.res = talloc(s, union drsuapi_DsRemoveDSServerResult); subreq = dcerpc_drsuapi_DsRemoveDSServer_r_send(s, c->event_ctx, s->drsuapi.drsuapi_handle, r); if (composite_nomem(subreq, c)) return; tevent_req_set_callback(subreq, unbecomeDC_drsuapi_remove_ds_server_recv, s); }
struct composite_context *libnet_UnbecomeDC_send(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_UnbecomeDC *r) { struct composite_context *c; struct libnet_UnbecomeDC_state *s; char *tmp_name; c = composite_create(mem_ctx, ctx->event_ctx); if (c == NULL) return NULL; s = talloc_zero(c, struct libnet_UnbecomeDC_state); if (composite_nomem(s, c)) return c; c->private_data = s; s->creq = c; s->libnet = ctx; /* Domain input */ s->domain.dns_name = talloc_strdup(s, r->in.domain_dns_name); if (composite_nomem(s->domain.dns_name, c)) return c; s->domain.netbios_name = talloc_strdup(s, r->in.domain_netbios_name); if (composite_nomem(s->domain.netbios_name, c)) return c; /* Source DSA input */ s->source_dsa.address = talloc_strdup(s, r->in.source_dsa_address); if (composite_nomem(s->source_dsa.address, c)) return c; /* Destination DSA input */ s->dest_dsa.netbios_name= talloc_strdup(s, r->in.dest_dsa_netbios_name); if (composite_nomem(s->dest_dsa.netbios_name, c)) return c; /* Destination DSA dns_name construction */ tmp_name = strlower_talloc(s, s->dest_dsa.netbios_name); if (composite_nomem(tmp_name, c)) return c; s->dest_dsa.dns_name = talloc_asprintf_append_buffer(tmp_name, ".%s", s->domain.dns_name); if (composite_nomem(s->dest_dsa.dns_name, c)) return c; unbecomeDC_send_cldap(s); return c; }
/* We should now have either an authenticated LSA pipe, or an error. * On success, open a policy handle */ static void init_domain_recv_lsa_pipe(struct composite_context *ctx) { struct rpc_request *req; struct init_domain_state *state = talloc_get_type(ctx->async.private_data, struct init_domain_state); state->ctx->status = dcerpc_secondary_connection_recv(ctx, &state->domain->lsa_pipe); if (NT_STATUS_EQUAL(state->ctx->status, NT_STATUS_LOGON_FAILURE)) { if (retry_with_schannel(state, state->domain->lsa_binding, init_domain_recv_lsa_pipe)) { return; } } if (!composite_is_ok(state->ctx)) return; talloc_steal(state->domain, state->domain->lsa_pipe); talloc_steal(state->domain->lsa_pipe, state->domain->lsa_binding); state->domain->lsa_policy_handle = talloc(state, struct policy_handle); if (composite_nomem(state->domain->lsa_policy_handle, state->ctx)) return; state->lsa_openpolicy.in.system_name = talloc_asprintf(state, "\\\\%s", dcerpc_server_name(state->domain->lsa_pipe)); ZERO_STRUCT(state->objectattr); state->lsa_openpolicy.in.attr = &state->objectattr; state->lsa_openpolicy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; state->lsa_openpolicy.out.handle = state->domain->lsa_policy_handle; req = dcerpc_lsa_OpenPolicy2_send(state->domain->lsa_pipe, state, &state->lsa_openpolicy); composite_continue_rpc(state->ctx, req, init_domain_recv_lsa_policy, state); }
static void unbecomeDC_send_cldap(struct libnet_UnbecomeDC_state *s) { struct composite_context *c = s->creq; struct tevent_req *req; s->cldap.io.in.dest_address = s->source_dsa.address; s->cldap.io.in.dest_port = lp_cldap_port(s->libnet->lp_ctx); s->cldap.io.in.realm = s->domain.dns_name; s->cldap.io.in.host = s->dest_dsa.netbios_name; s->cldap.io.in.user = NULL; s->cldap.io.in.domain_guid = NULL; s->cldap.io.in.domain_sid = NULL; s->cldap.io.in.acct_control = -1; s->cldap.io.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX; s->cldap.io.in.map_response = true; c->status = cldap_socket_init(s, s->libnet->event_ctx, NULL, NULL, &s->cldap.sock);//TODO if (!composite_is_ok(c)) return; req = cldap_netlogon_send(s, s->cldap.sock, &s->cldap.io); if (composite_nomem(req, c)) return; tevent_req_set_callback(req, unbecomeDC_recv_cldap, s); }
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; }
/* handler for completion of a smbcli_request sub-request */ static void request_handler(struct smbcli_request *req) { struct composite_context *c = (struct composite_context *)req->async.private_data; struct sesssetup_state *state = talloc_get_type(c->private_data, struct sesssetup_state); struct smbcli_session *session = req->session; DATA_BLOB session_key = data_blob(NULL, 0); DATA_BLOB null_data_blob = data_blob(NULL, 0); NTSTATUS session_key_err, nt_status; struct smbcli_request *check_req = NULL; const char *os = NULL; const char *lanman = NULL; if (req->sign_caller_checks) { req->do_not_free = true; check_req = req; } state->remote_status = smb_raw_sesssetup_recv(req, state, &state->setup); c->status = state->remote_status; state->req = NULL; /* * we only need to check the signature if the * NT_STATUS_OK is returned */ if (!NT_STATUS_IS_OK(state->remote_status)) { talloc_free(check_req); check_req = NULL; } switch (state->setup.old.level) { case RAW_SESSSETUP_OLD: state->io->out.vuid = state->setup.old.out.vuid; /* This doesn't work, as this only happens on old * protocols, where this comparison won't match. */ if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) { /* we neet to reset the vuid for a new try */ session->vuid = 0; if (cli_credentials_wrong_password(state->io->in.credentials)) { nt_status = session_setup_old(c, session, state->io, &state->req); if (NT_STATUS_IS_OK(nt_status)) { talloc_free(check_req); c->status = nt_status; composite_continue_smb(c, state->req, request_handler, c); return; } } } os = state->setup.old.out.os; lanman = state->setup.old.out.lanman; break; case RAW_SESSSETUP_NT1: state->io->out.vuid = state->setup.nt1.out.vuid; if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) { /* we neet to reset the vuid for a new try */ session->vuid = 0; if (cli_credentials_wrong_password(state->io->in.credentials)) { nt_status = session_setup_nt1(c, session, state->io, &state->req); if (NT_STATUS_IS_OK(nt_status)) { talloc_free(check_req); c->status = nt_status; composite_continue_smb(c, state->req, request_handler, c); return; } } } os = state->setup.nt1.out.os; lanman = state->setup.nt1.out.lanman; break; case RAW_SESSSETUP_SPNEGO: state->io->out.vuid = state->setup.spnego.out.vuid; if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) { /* we need to reset the vuid for a new try */ session->vuid = 0; if (cli_credentials_wrong_password(state->io->in.credentials)) { nt_status = session_setup_spnego(c, session, state->io, &state->req); if (NT_STATUS_IS_OK(nt_status)) { talloc_free(check_req); c->status = nt_status; composite_continue_smb(c, state->req, request_handler, c); return; } } } if (!NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(c->status)) { break; } if (NT_STATUS_EQUAL(state->gensec_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { /* The status value here, from the earlier pass at GENSEC is * vital to the security of the system. Even if the other end * accepts, if GENSEC claims 'MORE_PROCESSING_REQUIRED' then * you must keep feeding it blobs, or else the remote * host/attacker might avoid mutal authentication * requirements */ state->gensec_status = gensec_update(session->gensec, state, state->setup.spnego.out.secblob, &state->setup.spnego.in.secblob); c->status = state->gensec_status; if (!NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(c->status)) { break; } } else { state->setup.spnego.in.secblob = data_blob(NULL, 0); } if (NT_STATUS_IS_OK(state->remote_status)) { if (state->setup.spnego.in.secblob.length) { c->status = NT_STATUS_INTERNAL_ERROR; break; } session_key_err = gensec_session_key(session->gensec, session, &session->user_session_key); if (NT_STATUS_IS_OK(session_key_err)) { smbcli_transport_simple_set_signing(session->transport, session->user_session_key, null_data_blob); } } if (state->setup.spnego.in.secblob.length) { /* * set the session->vuid value only for calling * smb_raw_sesssetup_send() */ uint16_t vuid = session->vuid; session->vuid = state->io->out.vuid; state->req = smb_raw_sesssetup_send(session, &state->setup); session->vuid = vuid; if (state->req) { state->req->sign_caller_checks = true; } composite_continue_smb(c, state->req, request_handler, c); return; } os = state->setup.spnego.out.os; lanman = state->setup.spnego.out.lanman; break; case RAW_SESSSETUP_SMB2: c->status = NT_STATUS_INTERNAL_ERROR; break; } if (check_req) { check_req->sign_caller_checks = false; if (!smbcli_request_check_sign_mac(check_req)) { c->status = NT_STATUS_ACCESS_DENIED; } talloc_free(check_req); check_req = NULL; } /* enforce the local signing required flag */ if (NT_STATUS_IS_OK(c->status) && !cli_credentials_is_anonymous(state->io->in.credentials)) { if (!session->transport->negotiate.sign_info.doing_signing && session->transport->negotiate.sign_info.mandatory_signing) { DEBUG(0, ("SMB signing required, but server does not support it\n")); c->status = NT_STATUS_ACCESS_DENIED; } } if (!NT_STATUS_IS_OK(c->status)) { composite_error(c, c->status); return; } if (os) { session->os = talloc_strdup(session, os); if (composite_nomem(session->os, c)) return; } else { session->os = NULL; } if (lanman) { session->lanman = talloc_strdup(session, lanman); if (composite_nomem(session->lanman, c)) return; } else { session->lanman = NULL; } composite_done(c); }
/* handler for completion of a smbcli_request sub-request */ static void request_handler(struct smbcli_request *req) { struct composite_context *c = (struct composite_context *)req->async.private_data; struct sesssetup_state *state = talloc_get_type(c->private_data, struct sesssetup_state); struct smbcli_session *session = req->session; DATA_BLOB null_data_blob = data_blob(NULL, 0); NTSTATUS session_key_err, nt_status; struct smbcli_request *check_req = NULL; const char *os = NULL; const char *lanman = NULL; if (req->sign_caller_checks) { req->do_not_free = true; check_req = req; } state->remote_status = smb_raw_sesssetup_recv(req, state, &state->setup); c->status = state->remote_status; state->req = NULL; /* * we only need to check the signature if the * NT_STATUS_OK is returned */ if (!NT_STATUS_IS_OK(state->remote_status)) { talloc_free(check_req); check_req = NULL; } switch (state->setup.old.level) { case RAW_SESSSETUP_OLD: state->io->out.vuid = state->setup.old.out.vuid; /* This doesn't work, as this only happens on old * protocols, where this comparison won't match. */ if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) { /* we neet to reset the vuid for a new try */ session->vuid = 0; if (cli_credentials_wrong_password(state->io->in.credentials)) { nt_status = session_setup_old(c, session, state->io, &state->req); if (NT_STATUS_IS_OK(nt_status)) { talloc_free(check_req); c->status = nt_status; composite_continue_smb(c, state->req, request_handler, c); return; } } } os = state->setup.old.out.os; lanman = state->setup.old.out.lanman; break; case RAW_SESSSETUP_NT1: state->io->out.vuid = state->setup.nt1.out.vuid; if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) { /* we need to reset the vuid for a new try */ session->vuid = 0; if (cli_credentials_wrong_password(state->io->in.credentials)) { nt_status = session_setup_nt1(c, session, state->io, &state->req); if (NT_STATUS_IS_OK(nt_status)) { talloc_free(check_req); c->status = nt_status; composite_continue_smb(c, state->req, request_handler, c); return; } } } os = state->setup.nt1.out.os; lanman = state->setup.nt1.out.lanman; break; case RAW_SESSSETUP_SPNEGO: state->io->out.vuid = state->setup.spnego.out.vuid; if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) { const char *principal; /* we need to reset the vuid for a new try */ session->vuid = 0; principal = gensec_get_target_principal(session->gensec); if (principal == NULL) { const char *hostname = gensec_get_target_hostname(session->gensec); const char *service = gensec_get_target_service(session->gensec); if (hostname != NULL && service != NULL) { principal = talloc_asprintf(state, "%s/%s", service, hostname); } } if (cli_credentials_failed_kerberos_login(state->io->in.credentials, principal, &state->logon_retries) || cli_credentials_wrong_password(state->io->in.credentials)) { nt_status = session_setup_spnego(c, session, state->io, &state->req); if (NT_STATUS_IS_OK(nt_status)) { talloc_free(check_req); c->status = nt_status; composite_continue_smb(c, state->req, request_handler, c); return; } } } if (!NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(c->status)) { break; } if (NT_STATUS_EQUAL(state->gensec_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { /* The status value here, from the earlier pass at GENSEC is * vital to the security of the system. Even if the other end * accepts, if GENSEC claims 'MORE_PROCESSING_REQUIRED' then * you must keep feeding it blobs, or else the remote * host/attacker might avoid mutal authentication * requirements */ state->gensec_status = gensec_update(session->gensec, state, c->event_ctx, state->setup.spnego.out.secblob, &state->setup.spnego.in.secblob); c->status = state->gensec_status; if (!NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(c->status)) { break; } } else { state->setup.spnego.in.secblob = data_blob(NULL, 0); } if (NT_STATUS_IS_OK(state->remote_status)) { DATA_BLOB session_key; if (state->setup.spnego.in.secblob.length) { c->status = NT_STATUS_INTERNAL_ERROR; break; } session_key_err = gensec_session_key(session->gensec, session, &session_key); if (NT_STATUS_IS_OK(session_key_err)) { smb1cli_conn_activate_signing(session->transport->conn, session_key, null_data_blob); } c->status = smb1cli_session_set_session_key(session->smbXcli, session_key); data_blob_free(&session_key); if (!NT_STATUS_IS_OK(c->status)) { break; } } if (state->setup.spnego.in.secblob.length) { /* * set the session->vuid value only for calling * smb_raw_sesssetup_send() */ uint16_t vuid = session->vuid; session->vuid = state->io->out.vuid; state->req = smb_raw_sesssetup_send(session, &state->setup); session->vuid = vuid; if (state->req && !smb1cli_conn_signing_is_active(state->req->transport->conn)) { state->req->sign_caller_checks = true; } composite_continue_smb(c, state->req, request_handler, c); return; } os = state->setup.spnego.out.os; lanman = state->setup.spnego.out.lanman; break; case RAW_SESSSETUP_SMB2: c->status = NT_STATUS_INTERNAL_ERROR; break; } if (check_req) { bool ok; check_req->sign_caller_checks = false; ok = smb1cli_conn_check_signing(check_req->transport->conn, check_req->in.buffer, 1); if (!ok) { c->status = NT_STATUS_ACCESS_DENIED; } talloc_free(check_req); check_req = NULL; } if (!NT_STATUS_IS_OK(c->status)) { composite_error(c, c->status); return; } if (os) { session->os = talloc_strdup(session, os); if (composite_nomem(session->os, c)) return; } else { session->os = NULL; } if (lanman) { session->lanman = talloc_strdup(session, lanman); if (composite_nomem(session->lanman, c)) return; } else { session->lanman = NULL; } composite_done(c); }
/* send a async dcerpc bind request */ struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *syntax, const struct ndr_syntax_id *transfer_syntax) { struct composite_context *c; struct ncacn_packet pkt; DATA_BLOB blob; struct rpc_request *req; c = composite_create(mem_ctx,p->conn->event_ctx); if (c == NULL) return NULL; c->private_data = p; p->syntax = *syntax; p->transfer_syntax = *transfer_syntax; init_ncacn_hdr(p->conn, &pkt); pkt.ptype = DCERPC_PKT_BIND; pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST; pkt.call_id = p->conn->call_id; pkt.auth_length = 0; if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) { pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX; } if (p->binding->flags & DCERPC_HEADER_SIGNING) { pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN; } pkt.u.bind.max_xmit_frag = 5840; pkt.u.bind.max_recv_frag = 5840; pkt.u.bind.assoc_group_id = p->binding->assoc_group_id; pkt.u.bind.num_contexts = 1; pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1); if (composite_nomem(pkt.u.bind.ctx_list, c)) return c; pkt.u.bind.ctx_list[0].context_id = p->context_id; pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1; pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax; pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax; pkt.u.bind.auth_info = data_blob(NULL, 0); /* construct the NDR form of the packet */ c->status = ncacn_push_auth(&blob, c, p->conn->iconv_convenience, &pkt, p->conn->security_state.auth_info); if (!composite_is_ok(c)) return c; p->conn->transport.recv_data = dcerpc_recv_data; /* * we allocate a dcerpc_request so we can be in the same * request queue as normal requests */ req = talloc_zero(c, struct rpc_request); if (composite_nomem(req, c)) return c; req->state = RPC_REQUEST_PENDING; req->call_id = pkt.call_id; req->async.private_data = c; req->async.callback = dcerpc_composite_fail; req->p = p; req->recv_handler = dcerpc_bind_recv_handler; DLIST_ADD_END(p->conn->pending, req, struct rpc_request *); talloc_set_destructor(req, dcerpc_req_dequeue); c->status = p->conn->transport.send_request(p->conn, &blob, true); if (!composite_is_ok(c)) return c; event_add_timed(c->event_ctx, req, timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0), dcerpc_timeout_handler, req); return c; }
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; }