1
0
mirror of https://github.com/samba-team/samba.git synced 2025-10-24 15:33:20 +03:00
Files
samba-mirror/source/torture/rpc/xplogin.c
Andrew Tridgell f9413ce792 r12116: got rid of composite_trigger_done() and composite_trigger_error(), and
instead make the normal composite_done() and composite_error()
functions automatically trigger a delayed callback if the caller has
had no opportunity to setup a async callback

this removes one of the common mistakes in writing a composite function
2007-10-10 13:47:11 -05:00

2199 lines
60 KiB
C

/*
Unix SMB/CIFS implementation.
Test code to simulate an XP logon.
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/auth/credentials.h"
#include "libcli/raw/libcliraw.h"
#include "librpc/gen_ndr/ndr_samr.h"
#include "librpc/gen_ndr/ndr_netlogon.h"
#include "librpc/gen_ndr/ndr_srvsvc.h"
#include "libcli/composite/composite.h"
#include "libcli/smb_composite/smb_composite.h"
#include "lib/events/events.h"
#include "winbind/wb_async_helpers.h"
struct get_schannel_creds_state {
struct composite_context *ctx;
struct cli_credentials *wks_creds;
struct dcerpc_pipe *p;
struct netr_ServerReqChallenge r;
struct creds_CredentialState *creds_state;
struct netr_Credential netr_cred;
uint32_t negotiate_flags;
struct netr_ServerAuthenticate2 a;
};
static void get_schannel_creds_recv_bind(struct composite_context *ctx);
static void get_schannel_creds_recv_auth(struct rpc_request *req);
static void get_schannel_creds_recv_chal(struct rpc_request *req);
static void get_schannel_creds_recv_pipe(struct composite_context *ctx);
static struct composite_context *get_schannel_creds_send(TALLOC_CTX *mem_ctx,
struct cli_credentials *wks_creds,
struct smbcli_tree *tree,
struct event_context *ev)
{
struct composite_context *result, *ctx;
struct get_schannel_creds_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 = ev;
state = talloc(result, struct get_schannel_creds_state);
if (state == NULL) goto failed;
result->private_data = state;
state->ctx = result;
state->wks_creds = wks_creds;
state->p = dcerpc_pipe_init(state, ev);
if (state->p == NULL) goto failed;
ctx = dcerpc_pipe_open_smb_send(state->p->conn, tree, "\\netlogon");
if (ctx == NULL) goto failed;
ctx->async.fn = get_schannel_creds_recv_pipe;
ctx->async.private_data = state;
return result;
failed:
talloc_free(result);
return NULL;
}
static void get_schannel_creds_recv_pipe(struct composite_context *ctx)
{
struct get_schannel_creds_state *state =
talloc_get_type(ctx->async.private_data,
struct get_schannel_creds_state);
state->ctx->status = dcerpc_pipe_open_smb_recv(ctx);
if (!composite_is_ok(state->ctx)) return;
ctx = dcerpc_bind_auth_none_send(state, state->p,
DCERPC_NETLOGON_UUID,
DCERPC_NETLOGON_VERSION);
composite_continue(state->ctx, ctx, get_schannel_creds_recv_bind,
state);
}
static void get_schannel_creds_recv_bind(struct composite_context *ctx)
{
struct get_schannel_creds_state *state =
talloc_get_type(ctx->async.private_data,
struct get_schannel_creds_state);
struct rpc_request *req;
state->ctx->status = dcerpc_bind_auth_none_recv(ctx);
if (!composite_is_ok(state->ctx)) return;
state->r.in.computer_name =
cli_credentials_get_workstation(state->wks_creds);
state->r.in.server_name =
talloc_asprintf(state, "\\\\%s",
dcerpc_server_name(state->p));
if (composite_nomem(state->r.in.server_name, state->ctx)) return;
state->r.in.credentials = talloc(state, struct netr_Credential);
if (composite_nomem(state->r.in.credentials, state->ctx)) return;
state->r.out.credentials = talloc(state, struct netr_Credential);
if (composite_nomem(state->r.out.credentials, state->ctx)) return;
generate_random_buffer(state->r.in.credentials->data,
sizeof(state->r.in.credentials->data));
req = dcerpc_netr_ServerReqChallenge_send(state->p, state, &state->r);
composite_continue_rpc(state->ctx, req,
get_schannel_creds_recv_chal, state);
}
static void get_schannel_creds_recv_chal(struct rpc_request *req)
{
struct get_schannel_creds_state *state =
talloc_get_type(req->async.private,
struct get_schannel_creds_state);
const struct samr_Password *mach_pwd;
state->ctx->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(state->ctx)) return;
state->ctx->status = state->r.out.result;
if (!composite_is_ok(state->ctx)) return;
state->creds_state = talloc(state, struct creds_CredentialState);
if (composite_nomem(state->creds_state, state->ctx)) return;
mach_pwd = cli_credentials_get_nt_hash(state->wks_creds, state);
if (composite_nomem(mach_pwd, state->ctx)) return;
state->negotiate_flags = NETLOGON_NEG_AUTH2_FLAGS;
creds_client_init(state->creds_state, state->r.in.credentials,
state->r.out.credentials, mach_pwd,
&state->netr_cred, state->negotiate_flags);
state->a.in.server_name =
talloc_reference(state, state->r.in.server_name);
state->a.in.account_name =
cli_credentials_get_username(state->wks_creds);
state->a.in.secure_channel_type =
cli_credentials_get_secure_channel_type(state->wks_creds);
state->a.in.computer_name =
cli_credentials_get_workstation(state->wks_creds);
state->a.in.negotiate_flags = &state->negotiate_flags;
state->a.out.negotiate_flags = &state->negotiate_flags;
state->a.in.credentials = &state->netr_cred;
state->a.out.credentials = &state->netr_cred;
req = dcerpc_netr_ServerAuthenticate2_send(state->p, state, &state->a);
composite_continue_rpc(state->ctx, req,
get_schannel_creds_recv_auth, state);
}
static void get_schannel_creds_recv_auth(struct rpc_request *req)
{
struct get_schannel_creds_state *state =
talloc_get_type(req->async.private,
struct get_schannel_creds_state);
state->ctx->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(state->ctx)) return;
state->ctx->status = state->a.out.result;
if (!composite_is_ok(state->ctx)) return;
if (!creds_client_check(state->creds_state,
state->a.out.credentials)) {
DEBUG(5, ("Server got us invalid creds\n"));
composite_error(state->ctx, NT_STATUS_UNSUCCESSFUL);
return;
}
cli_credentials_set_netlogon_creds(state->wks_creds,
state->creds_state);
composite_done(state->ctx);
}
static NTSTATUS get_schannel_creds_recv(struct composite_context *c,
TALLOC_CTX *mem_ctx,
struct dcerpc_pipe **netlogon_pipe)
{
NTSTATUS status = composite_wait(c);
if (NT_STATUS_IS_OK(status)) {
struct get_schannel_creds_state *state =
talloc_get_type(c->private_data,
struct get_schannel_creds_state);
*netlogon_pipe = talloc_steal(mem_ctx, state->p);
}
talloc_free(c);
return status;
}
/*
List trustdoms
*/
struct lsa_enumtrust_state {
struct dcerpc_pipe *lsa_pipe;
struct lsa_ObjectAttribute attr;
struct policy_handle handle;
struct lsa_OpenPolicy2 o;
struct lsa_Close c;
uint32_t resume_handle;
struct lsa_DomainList domains;
struct lsa_EnumTrustDom e;
};
static void lsa_enumtrust_recvclose(struct rpc_request *req)
{
struct composite_context *c =
talloc_get_type(req->async.private,
struct composite_context);
c->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(c)) return;
composite_done(c);
}
static void lsa_enumtrust_recvtrust(struct rpc_request *req)
{
struct composite_context *c =
talloc_get_type(req->async.private,
struct composite_context);
struct lsa_enumtrust_state *state =
talloc_get_type(c->private_data, struct lsa_enumtrust_state);
c->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(c)) return;
c->status = state->e.out.result;
if (NT_STATUS_EQUAL(c->status, NT_STATUS_NO_MORE_ENTRIES)) {
state->c.in.handle = &state->handle;
state->c.out.handle = &state->handle;
req = dcerpc_lsa_Close_send(state->lsa_pipe, state, &state->c);
composite_continue_rpc(c, req, lsa_enumtrust_recvclose, c);
return;
}
state->e.in.handle = &state->handle;
state->e.in.resume_handle = &state->resume_handle;
state->e.in.max_size = 1000;
state->e.out.resume_handle = &state->resume_handle;
ZERO_STRUCT(state->domains);
state->e.out.domains = &state->domains;
req = dcerpc_lsa_EnumTrustDom_send(state->lsa_pipe, state, &state->e);
composite_continue_rpc(c, req, lsa_enumtrust_recvtrust, c);
}
static void lsa_enumtrust_recvpol(struct rpc_request *req)
{
struct composite_context *c =
talloc_get_type(req->async.private,
struct composite_context);
struct lsa_enumtrust_state *state =
talloc_get_type(c->private_data, struct lsa_enumtrust_state);
c->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(c)) return;
c->status = state->o.out.result;
if (!composite_is_ok(c)) return;
state->e.in.handle = &state->handle;
state->resume_handle = 0;
state->e.in.resume_handle = &state->resume_handle;
state->e.in.max_size = 1000;
state->e.out.resume_handle = &state->resume_handle;
ZERO_STRUCT(state->domains);
state->e.out.domains = &state->domains;
req = dcerpc_lsa_EnumTrustDom_send(state->lsa_pipe, state, &state->e);
composite_continue_rpc(c, req, lsa_enumtrust_recvtrust, c);
}
static void lsa_enumtrust_recvbind(struct composite_context *creq)
{
struct composite_context *c =
talloc_get_type(creq->async.private_data,
struct composite_context);
struct lsa_enumtrust_state *state =
talloc_get_type(c->private_data, struct lsa_enumtrust_state);
struct rpc_request *req;
c->status = dcerpc_bind_auth_none_recv(creq);
if (!composite_is_ok(c)) return;
ZERO_STRUCT(state->attr);
state->o.in.attr = &state->attr;
state->o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
state->o.in.system_name = talloc_asprintf(
state, "\\\\%s", dcerpc_server_name(state->lsa_pipe));
if (composite_nomem(state->o.in.system_name, c)) return;
state->o.out.handle = &state->handle;
req = dcerpc_lsa_OpenPolicy2_send(state->lsa_pipe, state, &state->o);
composite_continue_rpc(c, req, lsa_enumtrust_recvpol, c);
}
static void lsa_enumtrust_recvsmb(struct composite_context *creq)
{
struct composite_context *c =
talloc_get_type(creq->async.private_data,
struct composite_context);
struct lsa_enumtrust_state *state =
talloc_get_type(c->private_data, struct lsa_enumtrust_state);
c->status = dcerpc_pipe_open_smb_recv(creq);
if (!composite_is_ok(c)) return;
creq = dcerpc_bind_auth_none_send(state, state->lsa_pipe,
DCERPC_LSARPC_UUID,
DCERPC_LSARPC_VERSION);
composite_continue(c, creq, lsa_enumtrust_recvbind, c);
}
static struct composite_context *lsa_enumtrust_send(TALLOC_CTX *mem_ctx,
struct smbcli_tree *tree)
{
struct composite_context *c, *creq;
struct lsa_enumtrust_state *state;
c = talloc_zero(mem_ctx, struct composite_context);
if (c == NULL) return NULL;
state = talloc(c, struct lsa_enumtrust_state);
if (state == NULL) {
c->status = NT_STATUS_NO_MEMORY;
goto failed;
}
c->state = COMPOSITE_STATE_IN_PROGRESS;
c->private_data = state;
c->event_ctx = tree->session->transport->socket->event.ctx;
state->lsa_pipe = dcerpc_pipe_init(state, c->event_ctx);
if (state->lsa_pipe == NULL) {
c->status = NT_STATUS_NO_MEMORY;
goto failed;
}
creq = dcerpc_pipe_open_smb_send(state->lsa_pipe->conn, tree,
"\\lsarpc");
if (creq == NULL) {
c->status = NT_STATUS_NO_MEMORY;
goto failed;
}
composite_continue(c, creq, lsa_enumtrust_recvsmb, c);
return c;
failed:
composite_error(c, c->status);
return c;
}
static NTSTATUS lsa_enumtrust_recv(struct composite_context *creq)
{
NTSTATUS result = composite_wait(creq);
talloc_free(creq);
return result;
}
/*
Get us an schannel-bound netlogon pipe
*/
struct get_netlogon_schannel_state {
struct cli_credentials *creds;
struct dcerpc_pipe *pipe;
};
/*
Receive the schannel'ed bind
*/
static void get_netlogon_schannel_bind(struct composite_context *creq)
{
struct composite_context *c =
talloc_get_type(creq->async.private_data,
struct composite_context);
c->status = dcerpc_bind_auth_recv(creq);
if (!composite_is_ok(c)) return;
composite_done(c);
}
/*
Receive the pipe
*/
static void get_netlogon_schannel_pipe(struct composite_context *creq)
{
struct composite_context *c =
talloc_get_type(creq->async.private_data,
struct composite_context);
struct get_netlogon_schannel_state *state =
talloc_get_type(c->private_data,
struct get_netlogon_schannel_state);
c->status = dcerpc_pipe_open_smb_recv(creq);
if (!composite_is_ok(c)) return;
state->pipe->conn->flags |= (DCERPC_SIGN | DCERPC_SEAL);
creq = dcerpc_bind_auth_send(state, state->pipe,
DCERPC_NETLOGON_UUID,
DCERPC_NETLOGON_VERSION,
state->creds,
DCERPC_AUTH_TYPE_SCHANNEL,
NULL);
composite_continue(c, creq, get_netlogon_schannel_bind, c);
}
static struct composite_context *get_netlogon_schannel_send(TALLOC_CTX *mem_ctx,
struct smbcli_tree *tree,
struct cli_credentials *creds)
{
struct composite_context *c, *creq;
struct get_netlogon_schannel_state *state;
c = talloc_zero(mem_ctx, struct composite_context);
if (c == NULL) return NULL;
state = talloc(c, struct get_netlogon_schannel_state);
if (state == NULL) {
c->status = NT_STATUS_NO_MEMORY;
goto failed;
}
c->state = COMPOSITE_STATE_IN_PROGRESS;
c->private_data = state;
c->event_ctx = tree->session->transport->socket->event.ctx;
state->pipe = dcerpc_pipe_init(state, c->event_ctx);
if (state->pipe == NULL) {
c->status = NT_STATUS_NO_MEMORY;
goto failed;
}
state->creds = creds;
creq = dcerpc_pipe_open_smb_send(state->pipe->conn, tree,
"\\netlogon");
if (creq == NULL) {
c->status = NT_STATUS_NO_MEMORY;
goto failed;
}
creq->async.fn = get_netlogon_schannel_pipe;
creq->async.private_data = c;
return c;
failed:
composite_error(c, c->status);
return c;
}
static NTSTATUS get_netlogon_schannel_recv(struct composite_context *c,
TALLOC_CTX *mem_ctx,
struct dcerpc_pipe **pipe)
{
NTSTATUS result = composite_wait(c);
if (NT_STATUS_IS_OK(result)) {
struct get_netlogon_schannel_state *state =
talloc_get_type(c->private_data,
struct get_netlogon_schannel_state);
*pipe = talloc_steal(mem_ctx, state->pipe);
}
return result;
}
/*
lsa_lookupsids, given just an smb tree
*/
struct lookupsids_state {
struct dcerpc_pipe *lsa_pipe;
int num_sids;
const struct dom_sid **sids;
struct wb_sid_object **names;
struct policy_handle handle;
struct lsa_ObjectAttribute a;
struct lsa_OpenPolicy2 o;
struct lsa_Close c;
};
static void lookupsids_recv_close(struct rpc_request *req)
{
struct composite_context *c =
talloc_get_type(req->async.private,
struct composite_context);
struct lookupsids_state *state =
talloc_get_type(c->private_data,
struct lookupsids_state);
c->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(c)) return;
c->status = state->c.out.result;
if (!composite_is_ok(c)) return;
composite_done(c);
}
static void lookupsids_recv_names(struct composite_context *creq)
{
struct composite_context *c =
talloc_get_type(creq->async.private_data,
struct composite_context);
struct lookupsids_state *state =
talloc_get_type(c->private_data,
struct lookupsids_state);
struct rpc_request *req;
c->status = wb_lsa_lookupsids_recv(creq, state, &state->names);
if (!composite_is_ok(c)) return;
state->c.in.handle = &state->handle;
state->c.out.handle = &state->handle;
req = dcerpc_lsa_Close_send(state->lsa_pipe, state, &state->c);
composite_continue_rpc(c, req, lookupsids_recv_close, c);
}
static void lookupsids_recv_pol(struct rpc_request *req)
{
struct composite_context *c =
talloc_get_type(req->async.private,
struct composite_context);
struct lookupsids_state *state =
talloc_get_type(c->private_data,
struct lookupsids_state);
struct composite_context *creq;
c->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(c)) return;
c->status = state->o.out.result;
if (!composite_is_ok(c)) return;
creq = wb_lsa_lookupsids_send(state, state->lsa_pipe, &state->handle,
state->num_sids, state->sids);
composite_continue(c, creq, lookupsids_recv_names, c);
}
static void lookupsids_recv_bind(struct composite_context *creq)
{
struct composite_context *c =
talloc_get_type(creq->async.private_data,
struct composite_context);
struct lookupsids_state *state =
talloc_get_type(c->private_data,
struct lookupsids_state);
struct rpc_request *req;
c->status = dcerpc_bind_auth_none_recv(creq);
if (!composite_is_ok(c)) return;
ZERO_STRUCT(state->a);
ZERO_STRUCT(state->handle);
state->o.in.attr = &state->a;
state->o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
state->o.out.handle = &state->handle;
state->o.in.system_name =
talloc_asprintf(state, "\\\\%s",
dcerpc_server_name(state->lsa_pipe));
if (composite_nomem(state->o.in.system_name, c)) return;
req = dcerpc_lsa_OpenPolicy2_send(state->lsa_pipe, state,
&state->o);
composite_continue_rpc(c, req, lookupsids_recv_pol, c);
}
static void lookupsids_recv_pipe(struct composite_context *creq)
{
struct composite_context *c =
talloc_get_type(creq->async.private_data,
struct composite_context);
struct lookupsids_state *state =
talloc_get_type(c->private_data,
struct lookupsids_state);
c->status = dcerpc_pipe_open_smb_recv(creq);
if (!composite_is_ok(c)) return;
creq = dcerpc_bind_auth_none_send(state, state->lsa_pipe,
DCERPC_LSARPC_UUID,
DCERPC_LSARPC_VERSION);
composite_continue(c, creq, lookupsids_recv_bind, c);
}
static struct composite_context *lookupsids_send(TALLOC_CTX *mem_ctx,
struct smbcli_tree *tree,
int num_sids,
const struct dom_sid **sids)
{
struct composite_context *c, *creq;
struct lookupsids_state *state;
c = talloc_zero(mem_ctx, struct composite_context);
if (c == NULL) return NULL;
state = talloc(c, struct lookupsids_state);
if (state == NULL) {
c->status = NT_STATUS_NO_MEMORY;
goto failed;
}
c->state = COMPOSITE_STATE_IN_PROGRESS;
c->private_data = state;
c->event_ctx = tree->session->transport->socket->event.ctx;
state->num_sids = num_sids;
state->sids = talloc_reference(state, sids);
state->lsa_pipe = dcerpc_pipe_init(state, c->event_ctx);
if (state->lsa_pipe == NULL) {
c->status = NT_STATUS_NO_MEMORY;
goto failed;
}
creq = dcerpc_pipe_open_smb_send(state->lsa_pipe->conn, tree,
"\\lsarpc");
if (creq == NULL) {
c->status = NT_STATUS_NO_MEMORY;
goto failed;
}
creq->async.fn = lookupsids_recv_pipe;
creq->async.private_data = c;
return c;
failed:
composite_error(c, c->status);
return c;
}
static NTSTATUS lookupsids_recv(struct composite_context *creq,
TALLOC_CTX *mem_ctx,
int *num_names,
struct wb_sid_object ***names)
{
NTSTATUS result = composite_wait(creq);
if (NT_STATUS_IS_OK(result)) {
struct lookupsids_state *state =
talloc_get_type(creq->private_data,
struct lookupsids_state);
*num_names = state->num_sids;
*names = talloc_steal(mem_ctx, state->names);
}
talloc_free(creq);
return result;
}
/*
Get me a samr pipe and a domain handle on the main domain (not the builtin
one)
*/
struct get_samr_domain_state {
struct dcerpc_pipe *samr_pipe;
struct policy_handle connect_handle;
struct policy_handle domain_handle;
struct policy_handle group_handle;
struct samr_Connect2 conn;
uint32_t resume_handle;
struct samr_EnumDomains e;
struct samr_LookupDomain l;
struct samr_OpenDomain o;
struct samr_Close c;
};
static void get_samr_domain_recv_connclose(struct rpc_request *req)
{
struct composite_context *c =
talloc_get_type(req->async.private,
struct composite_context);
struct get_samr_domain_state *state =
talloc_get_type(c->private_data,
struct get_samr_domain_state);
c->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(c)) return;
c->status = state->c.out.result;
if (!composite_is_ok(c)) return;
composite_done(c);
}
static void get_samr_domain_recv_domopen(struct rpc_request *req)
{
struct composite_context *c =
talloc_get_type(req->async.private,
struct composite_context);
struct get_samr_domain_state *state =
talloc_get_type(c->private_data,
struct get_samr_domain_state);
c->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(c)) return;
c->status = state->o.out.result;
if (!composite_is_ok(c)) return;
state->c.in.handle = &state->connect_handle;
state->c.out.handle = &state->connect_handle;
req = dcerpc_samr_Close_send(state->samr_pipe, state,
&state->c);
composite_continue_rpc(c, req, get_samr_domain_recv_connclose, c);
}
static void get_samr_domain_recv_domsid(struct rpc_request *req)
{
struct composite_context *c =
talloc_get_type(req->async.private,
struct composite_context);
struct get_samr_domain_state *state =
talloc_get_type(c->private_data,
struct get_samr_domain_state);
c->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(c)) return;
c->status = state->l.out.result;
if (!composite_is_ok(c)) return;
state->o.in.connect_handle = &state->connect_handle;
state->o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
state->o.in.sid = state->l.out.sid;
state->o.out.domain_handle = &state->domain_handle;
req = dcerpc_samr_OpenDomain_send(state->samr_pipe, state,
&state->o);
composite_continue_rpc(c, req, get_samr_domain_recv_domopen, c);
}
static void get_samr_domain_recv_domains(struct rpc_request *req)
{
struct composite_context *c =
talloc_get_type(req->async.private,
struct composite_context);
struct get_samr_domain_state *state =
talloc_get_type(c->private_data,
struct get_samr_domain_state);
int entry = 0;
c->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(c)) return;
c->status = state->e.out.result;
if (!composite_is_ok(c)) return;
if ((state->e.out.num_entries != 2) ||
(state->e.out.sam->count != 2)) {
composite_error(c, NT_STATUS_INVALID_PARAMETER);
return;
}
if (strcasecmp(state->e.out.sam->entries[0].name.string,
"Builtin") == 0) {
entry = 1;
}
state->l.in.connect_handle = &state->connect_handle;
state->l.in.domain_name = &state->e.out.sam->entries[entry].name;
req = dcerpc_samr_LookupDomain_send(state->samr_pipe, state,
&state->l);
composite_continue_rpc(c, req, get_samr_domain_recv_domsid, c);
}
static void get_samr_domain_recv_conn(struct rpc_request *req)
{
struct composite_context *c =
talloc_get_type(req->async.private,
struct composite_context);
struct get_samr_domain_state *state =
talloc_get_type(c->private_data,
struct get_samr_domain_state);
c->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(c)) return;
c->status = state->conn.out.result;
if (!composite_is_ok(c)) return;
state->resume_handle = 0;
state->e.in.connect_handle = &state->connect_handle;
state->e.in.resume_handle = &state->resume_handle;
state->e.in.buf_size = 8192;
state->e.out.resume_handle = &state->resume_handle;
req = dcerpc_samr_EnumDomains_send(state->samr_pipe, state,
&state->e);
composite_continue_rpc(c, req, get_samr_domain_recv_domains, c);
}
static void get_samr_domain_recv_bind(struct composite_context *creq)
{
struct composite_context *c =
talloc_get_type(creq->async.private_data,
struct composite_context);
struct get_samr_domain_state *state =
talloc_get_type(c->private_data,
struct get_samr_domain_state);
struct rpc_request *req;
c->status = dcerpc_bind_auth_none_recv(creq);
if (!composite_is_ok(c)) return;
state->conn.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
state->conn.in.system_name = talloc_asprintf(
state, "\\\\%s", dcerpc_server_name(state->samr_pipe));
if (composite_nomem(state->conn.in.system_name, c)) return;
state->conn.out.connect_handle = &state->connect_handle;
req = dcerpc_samr_Connect2_send(state->samr_pipe, state,
&state->conn);
composite_continue_rpc(c, req, get_samr_domain_recv_conn, c);
}
static void get_samr_domain_recv_pipe(struct composite_context *creq)
{
struct composite_context *c =
talloc_get_type(creq->async.private_data,
struct composite_context);
struct get_samr_domain_state *state =
talloc_get_type(c->private_data,
struct get_samr_domain_state);
c->status = dcerpc_pipe_open_smb_recv(creq);
if (!composite_is_ok(c)) return;
creq = dcerpc_bind_auth_none_send(state, state->samr_pipe,
DCERPC_SAMR_UUID,
DCERPC_SAMR_VERSION);
composite_continue(c, creq, get_samr_domain_recv_bind, c);
}
static struct composite_context *get_samr_domain_send(TALLOC_CTX *mem_ctx,
struct smbcli_tree *tree)
{
struct composite_context *c, *creq;
struct get_samr_domain_state *state;
c = talloc_zero(mem_ctx, struct composite_context);
if (c == NULL) return NULL;
state = talloc(c, struct get_samr_domain_state);
if (state == NULL) {
c->status = NT_STATUS_NO_MEMORY;
goto failed;
}
c->state = COMPOSITE_STATE_IN_PROGRESS;
c->private_data = state;
c->event_ctx = tree->session->transport->socket->event.ctx;
state->samr_pipe = dcerpc_pipe_init(state, c->event_ctx);
if (state->samr_pipe == NULL) {
c->status = NT_STATUS_NO_MEMORY;
goto failed;
}
creq = dcerpc_pipe_open_smb_send(state->samr_pipe->conn, tree,
"\\samr");
if (creq == NULL) {
c->status = NT_STATUS_NO_MEMORY;
goto failed;
}
creq->async.fn = get_samr_domain_recv_pipe;
creq->async.private_data = c;
return c;
failed:
composite_error(c, c->status);
return c;
}
static NTSTATUS get_samr_domain_recv(struct composite_context *creq,
TALLOC_CTX *mem_ctx,
struct dcerpc_pipe **pipe,
struct policy_handle *handle,
struct dom_sid **domain_sid)
{
NTSTATUS result = composite_wait(creq);
if (NT_STATUS_IS_OK(result)) {
struct get_samr_domain_state *state =
talloc_get_type(creq->private_data,
struct get_samr_domain_state);
*pipe = talloc_steal(mem_ctx, state->samr_pipe);
*handle = state->domain_handle;
*domain_sid = talloc_steal(mem_ctx, state->l.out.sid);
}
talloc_free(creq);
return result;
}
/*
Get us the names & types of the members of the domain admins group.
Yes, I've got a workstation setup that does it. Twice. -- VL
*/
struct domadmins_state {
struct dcerpc_pipe *samr_pipe;
struct dom_sid *domain_sid;
struct policy_handle domain_handle;
struct policy_handle group_handle;
uint32_t resume_handle;
struct samr_Close c;
struct samr_OpenGroup og;
struct samr_QueryGroupMember m;
int num_names;
struct wb_sid_object **names;
};
static void domadmins_recv_domclose(struct rpc_request *req)
{
struct composite_context *c =
talloc_get_type(req->async.private,
struct composite_context);
struct domadmins_state *state =
talloc_get_type(c->private_data,
struct domadmins_state);
c->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(c)) return;
c->status = state->c.out.result;
if (!composite_is_ok(c)) return;
composite_done(c);
}
static void domadmins_recv_groupclose(struct rpc_request *req)
{
struct composite_context *c =
talloc_get_type(req->async.private,
struct composite_context);
struct domadmins_state *state =
talloc_get_type(c->private_data,
struct domadmins_state);
c->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(c)) return;
c->status = state->c.out.result;
if (!composite_is_ok(c)) return;
state->c.in.handle = &state->domain_handle;
state->c.out.handle = &state->domain_handle;
req = dcerpc_samr_Close_send(state->samr_pipe, state,
&state->c);
composite_continue_rpc(c, req, domadmins_recv_domclose, c);
}
static void domadmins_recv_names(struct composite_context *creq)
{
struct composite_context *c =
talloc_get_type(creq->async.private_data,
struct composite_context);
struct domadmins_state *state =
talloc_get_type(c->private_data,
struct domadmins_state);
struct rpc_request *req;
c->status = lookupsids_recv(creq, state, &state->num_names,
&state->names);
if (!composite_is_ok(c)) return;
state->c.in.handle = &state->group_handle;
state->c.out.handle = &state->group_handle;
req = dcerpc_samr_Close_send(state->samr_pipe, state,
&state->c);
composite_continue_rpc(c, req, domadmins_recv_groupclose, c);
}
static void domadmins_recv_members(struct rpc_request *req)
{
struct composite_context *c =
talloc_get_type(req->async.private,
struct composite_context);
struct domadmins_state *state =
talloc_get_type(c->private_data,
struct domadmins_state);
struct composite_context *creq;
const struct dom_sid **sids;
int i;
c->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(c)) return;
c->status = state->m.out.result;
if (!composite_is_ok(c)) return;
state->num_names = state->m.out.rids->count;
sids = talloc_array(state, const struct dom_sid *, state->num_names);
if (composite_nomem(sids, c)) return;
for (i=0; i<state->num_names; i++) {
sids[i] = dom_sid_add_rid(sids, state->domain_sid,
state->m.out.rids->rids[i]);
if (composite_nomem(sids[i], c)) return;
}
creq = lookupsids_send(state, dcerpc_smb_tree(state->samr_pipe->conn),
state->num_names, sids);
composite_continue(c, creq, domadmins_recv_names, c);
}
static void domadmins_recv_group(struct rpc_request *req)
{
struct composite_context *c =
talloc_get_type(req->async.private,
struct composite_context);
struct domadmins_state *state =
talloc_get_type(c->private_data,
struct domadmins_state);
c->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(c)) return;
c->status = state->og.out.result;
if (!composite_is_ok(c)) return;
state->m.in.group_handle = &state->group_handle;
req = dcerpc_samr_QueryGroupMember_send(state->samr_pipe, state,
&state->m);
composite_continue_rpc(c, req, domadmins_recv_members, c);
}
static void domadmins_recv_domain(struct composite_context *creq)
{
struct composite_context *c =
talloc_get_type(creq->async.private_data,
struct composite_context);
struct domadmins_state *state =
talloc_get_type(c->private_data,
struct domadmins_state);
struct rpc_request *req;
c->status = get_samr_domain_recv(creq, state, &state->samr_pipe,
&state->domain_handle,
&state->domain_sid);
if (!composite_is_ok(c)) return;
state->og.in.domain_handle = &state->domain_handle;
state->og.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
state->og.in.rid = 512;
state->og.out.group_handle = &state->group_handle;
req = dcerpc_samr_OpenGroup_send(state->samr_pipe, state,
&state->og);
composite_continue_rpc(c, req, domadmins_recv_group, c);
}
static struct composite_context *domadmins_send(TALLOC_CTX *mem_ctx,
struct smbcli_tree *tree)
{
struct composite_context *c, *creq;
struct domadmins_state *state;
c = talloc_zero(mem_ctx, struct composite_context);
if (c == NULL) return NULL;
state = talloc(c, struct domadmins_state);
if (state == NULL) {
c->status = NT_STATUS_NO_MEMORY;
goto failed;
}
c->state = COMPOSITE_STATE_IN_PROGRESS;
c->private_data = state;
c->event_ctx = tree->session->transport->socket->event.ctx;
creq = get_samr_domain_send(state, tree);
if (creq == NULL) {
c->status = NT_STATUS_NO_MEMORY;
goto failed;
}
creq->async.fn = domadmins_recv_domain;
creq->async.private_data = c;
return c;
failed:
composite_error(c, c->status);
return c;
}
static NTSTATUS domadmins_recv(struct composite_context *creq,
TALLOC_CTX *mem_ctx,
int *num_names, struct wb_sid_object ***names)
{
NTSTATUS result = composite_wait(creq);
if (NT_STATUS_IS_OK(result)) {
struct domadmins_state *state =
talloc_get_type(creq->private_data,
struct domadmins_state);
*num_names = state->num_names;
*names = talloc_steal(mem_ctx, state->names);
}
talloc_free(creq);
return result;
}
/*
Get us the groups a user is in
*/
struct memberships_state {
const char *username;
struct dcerpc_pipe *samr_pipe;
struct dom_sid *domain_sid;
struct policy_handle domain_handle;
struct policy_handle user_handle;
struct lsa_String name;
struct samr_LookupNames l;
struct samr_OpenUser o;
struct samr_Close c;
struct samr_GetGroupsForUser g;
struct lsa_SidArray sids;
struct samr_GetAliasMembership ga;
struct samr_Ids samr_ids;
uint32_t *rids;
struct samr_LookupRids r;
};
static void memberships_recv_closedom(struct rpc_request *req)
{
struct composite_context *c =
talloc_get_type(req->async.private,
struct composite_context);
struct memberships_state *state =
talloc_get_type(c->private_data,
struct memberships_state);
c->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(c)) return;
c->status = state->c.out.result;
if (!composite_is_ok(c)) return;
composite_done(c);
}
static void memberships_recv_closeuser(struct rpc_request *req)
{
struct composite_context *c =
talloc_get_type(req->async.private,
struct composite_context);
struct memberships_state *state =
talloc_get_type(c->private_data,
struct memberships_state);
c->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(c)) return;
c->status = state->c.out.result;
if (!composite_is_ok(c)) return;
state->c.in.handle = &state->domain_handle;
state->c.out.handle = &state->domain_handle;
req = dcerpc_samr_Close_send(state->samr_pipe, state,
&state->c);
composite_continue_rpc(c, req, memberships_recv_closedom, c);
}
static void memberships_recv_names(struct rpc_request *req)
{
struct composite_context *c =
talloc_get_type(req->async.private,
struct composite_context);
struct memberships_state *state =
talloc_get_type(c->private_data,
struct memberships_state);
c->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(c)) return;
c->status = state->r.out.result;
if (!composite_is_ok(c)) return;
state->c.in.handle = &state->user_handle;
state->c.out.handle = &state->user_handle;
req = dcerpc_samr_Close_send(state->samr_pipe, state,
&state->c);
composite_continue_rpc(c, req, memberships_recv_closeuser, c);
}
static void memberships_recv_aliases(struct rpc_request *req)
{
struct composite_context *c =
talloc_get_type(req->async.private,
struct composite_context);
struct memberships_state *state =
talloc_get_type(c->private_data,
struct memberships_state);
int i, rid_index, num_rids;
c->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(c)) return;
c->status = state->ga.out.result;
if (!composite_is_ok(c)) return;
num_rids = state->g.out.rids->count +
state->ga.out.rids->count + 1;
state->rids = talloc_array(state, uint32_t, num_rids);
if (composite_nomem(state->rids, c)) return;
rid_index = 0;
/* User */
state->rids[rid_index++] = state->l.out.rids.ids[0];
/* Groups */
for (i=0; i<state->g.out.rids->count; i++) {
state->rids[rid_index++] = state->g.out.rids->rids[i].rid;
}
/* Aliases (aka domain local groups) */
for (i=0; i<state->ga.out.rids->count; i++) {
state->rids[rid_index++] = state->ga.out.rids->ids[i];
}
state->r.in.domain_handle = &state->domain_handle;
state->r.in.num_rids = num_rids;
state->r.in.rids = state->rids;
req = dcerpc_samr_LookupRids_send(state->samr_pipe, state,
&state->r);
composite_continue_rpc(c, req, memberships_recv_names, c);
}
static void memberships_recv_mem(struct rpc_request *req)
{
struct composite_context *c =
talloc_get_type(req->async.private,
struct composite_context);
struct memberships_state *state =
talloc_get_type(c->private_data,
struct memberships_state);
int i;
c->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(c)) return;
c->status = state->g.out.result;
if (!composite_is_ok(c)) return;
state->sids.num_sids = state->g.out.rids->count+1;
state->sids.sids = talloc_array(state, struct lsa_SidPtr,
state->sids.num_sids);
if (composite_nomem(state->sids.sids, c)) return;
state->sids.sids[0].sid = dom_sid_add_rid(state->sids.sids,
state->domain_sid,
state->l.out.rids.ids[0]);
if (composite_nomem(state->sids.sids[0].sid, c)) return;
for (i=0; i<state->g.out.rids->count; i++) {
state->sids.sids[i+1].sid = dom_sid_add_rid(
state->sids.sids, state->domain_sid,
state->g.out.rids->rids[i].rid);
if (composite_nomem(state->sids.sids[i+1].sid, c)) return;
}
state->ga.in.sids = &state->sids;
state->ga.in.domain_handle = &state->domain_handle;
state->ga.out.rids = &state->samr_ids;
req = dcerpc_samr_GetAliasMembership_send(state->samr_pipe, state,
&state->ga);
composite_continue_rpc(c, req, memberships_recv_aliases, c);
}
static void memberships_recv_user(struct rpc_request *req)
{
struct composite_context *c =
talloc_get_type(req->async.private,
struct composite_context);
struct memberships_state *state =
talloc_get_type(c->private_data,
struct memberships_state);
c->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(c)) return;
c->status = state->o.out.result;
if (!composite_is_ok(c)) return;
state->g.in.user_handle = &state->user_handle;
req = dcerpc_samr_GetGroupsForUser_send(state->samr_pipe, state,
&state->g);
composite_continue_rpc(c, req, memberships_recv_mem, c);
}
static void memberships_recv_rid(struct rpc_request *req)
{
struct composite_context *c =
talloc_get_type(req->async.private,
struct composite_context);
struct memberships_state *state =
talloc_get_type(c->private_data,
struct memberships_state);
c->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(c)) return;
c->status = state->l.out.result;
if (!composite_is_ok(c)) return;
if (state->l.out.rids.count != 1) {
composite_error(c, NT_STATUS_INVALID_PARAMETER);
return;
}
state->o.in.domain_handle = &state->domain_handle;
state->o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
state->o.in.rid = state->l.out.rids.ids[0];
state->o.out.user_handle = &state->user_handle;
req = dcerpc_samr_OpenUser_send(state->samr_pipe, state,
&state->o);
composite_continue_rpc(c, req, memberships_recv_user, c);
}
static void memberships_recv_domain(struct composite_context *creq)
{
struct composite_context *c =
talloc_get_type(creq->async.private_data,
struct composite_context);
struct memberships_state *state =
talloc_get_type(c->private_data,
struct memberships_state);
struct rpc_request *req;
c->status = get_samr_domain_recv(creq, state, &state->samr_pipe,
&state->domain_handle,
&state->domain_sid);
if (!composite_is_ok(c)) return;
state->l.in.domain_handle = &state->domain_handle;
state->l.in.num_names = 1;
state->name.string = state->username;
state->l.in.names = &state->name;
req = dcerpc_samr_LookupNames_send(state->samr_pipe, state,
&state->l);
composite_continue_rpc(c, req, memberships_recv_rid, c);
}
static struct composite_context *memberships_send(TALLOC_CTX *mem_ctx,
struct smbcli_tree *tree,
const char *username)
{
struct composite_context *c, *creq;
struct memberships_state *state;
c = talloc_zero(mem_ctx, struct composite_context);
if (c == NULL) return NULL;
state = talloc(c, struct memberships_state);
if (state == NULL) {
c->status = NT_STATUS_NO_MEMORY;
goto failed;
}
c->state = COMPOSITE_STATE_IN_PROGRESS;
c->private_data = state;
c->event_ctx = tree->session->transport->socket->event.ctx;
state->username = talloc_strdup(state, username);
if (state->username == NULL) {
c->status = NT_STATUS_NO_MEMORY;
goto failed;
}
creq = get_samr_domain_send(state, tree);
if (creq == NULL) {
c->status = NT_STATUS_NO_MEMORY;
goto failed;
}
creq->async.fn = memberships_recv_domain;
creq->async.private_data = c;
return c;
failed:
composite_error(c, c->status);
return c;
}
static NTSTATUS memberships_recv(struct composite_context *creq)
{
NTSTATUS result = composite_wait(creq);
talloc_free(creq);
return result;
}
/*
Download ntconfig.pol.
*/
struct ntconfig_state {
struct smbcli_session *session;
struct cli_credentials *user_creds;
struct smb_composite_sesssetup s;
struct smbcli_tree *tree;
union smb_tcon t;
struct smb_composite_loadfile l;
};
static void ntconfig_recv_file(struct composite_context *creq)
{
struct composite_context *c =
talloc_get_type(creq->async.private_data,
struct composite_context);
struct ntconfig_state *state =
talloc_get_type(c->private_data,
struct ntconfig_state);
c->status = smb_composite_loadfile_recv(creq, state);
if (!composite_is_ok(c)) return;
composite_done(c);
}
static void ntconfig_recv_tcon(struct smbcli_request *req)
{
struct composite_context *c =
talloc_get_type(req->async.private,
struct composite_context);
struct ntconfig_state *state =
talloc_get_type(c->private_data,
struct ntconfig_state);
struct composite_context *creq;
c->status = smb_raw_tcon_recv(req, state, &state->t);
if (!composite_is_ok(c)) return;
state->tree->tid = state->t.tconx.out.tid;
state->l.in.fname = "ntconfig.pol";
creq = smb_composite_loadfile_send(state->tree, &state->l);
composite_continue(c, creq, ntconfig_recv_file, c);
}
static void ntconfig_recv_sesssetup(struct composite_context *creq)
{
struct composite_context *c =
talloc_get_type(creq->async.private_data,
struct composite_context);
struct ntconfig_state *state =
talloc_get_type(c->private_data,
struct ntconfig_state);
struct smbcli_request *req;
c->status = smb_composite_sesssetup_recv(creq);
if (!composite_is_ok(c)) return;
state->session->vuid = state->s.out.vuid;
state->tree = smbcli_tree_init(state->session, state, True);
if (composite_nomem(state->tree, c)) return;
state->t.generic.level = RAW_TCON_TCONX;
state->t.tconx.in.flags = 0;
state->t.tconx.in.password = data_blob(NULL, 0);
state->t.tconx.in.path = talloc_asprintf(
state, "\\\\%s\\%s",
state->session->transport->socket->hostname,
"NETLOGON");
if (composite_nomem(state->t.tconx.in.path, c)) return;
state->t.tconx.in.device = "?????";
req = smb_raw_tcon_send(state->tree, &state->t);
composite_continue_smb(c, req, ntconfig_recv_tcon, c);
}
static struct composite_context *ntconfig_send(TALLOC_CTX *mem_ctx,
struct smbcli_transport *transport,
struct cli_credentials *user_creds)
{
struct composite_context *c, *creq;
struct ntconfig_state *state;
c = talloc_zero(mem_ctx, struct composite_context);
if (c == NULL) return NULL;
state = talloc(c, struct ntconfig_state);
if (state == NULL) {
c->status = NT_STATUS_NO_MEMORY;
goto failed;
}
c->state = COMPOSITE_STATE_IN_PROGRESS;
c->private_data = state;
c->event_ctx = transport->socket->event.ctx;
state->user_creds = talloc_reference(state, user_creds);
state->session = smbcli_session_init(transport, state, False);
state->s.in.sesskey = transport->negotiate.sesskey;
state->s.in.capabilities = transport->negotiate.capabilities;
state->s.in.credentials = state->user_creds;
state->s.in.workgroup = cli_credentials_get_domain(state->user_creds);
creq = smb_composite_sesssetup_send(state->session, &state->s);
if (creq == NULL) {
c->status = NT_STATUS_NO_MEMORY;
goto failed;
}
creq->async.fn = ntconfig_recv_sesssetup;
creq->async.private_data = c;
return c;
failed:
composite_error(c, c->status);
return c;
}
/*
Right now we throw it away...
*/
static NTSTATUS ntconfig_recv(struct composite_context *creq)
{
NTSTATUS result = composite_wait(creq);
talloc_free(creq);
return result;
}
struct xp_login_state {
struct timeval timeout;
const char *dc_name;
const char *dc_ip;
const char *wks_domain;
const char *wks_name;
const char *wks_pwd;
const char *user_domain;
const char *user_name;
const char *user_pwd;
struct cli_credentials *user_creds;
int num_sids;
const struct dom_sid **sids;
int num_names;
struct wb_sid_object **names;
int num_domadmins;
struct wb_sid_object **domadmins;
int num_memberships_done;
struct smb_composite_connect conn;
struct cli_credentials *wks_creds;
struct dcerpc_pipe *netlogon_pipe;
struct dcerpc_pipe *netlogon_schannel_pipe;
struct dcerpc_pipe *lsa_pipe;
struct creds_CredentialState *creds_state;
struct netr_Authenticator auth, auth2;
struct netr_NetworkInfo ninfo;
struct netr_LogonSamLogon r;
};
static void xp_login_recv_conn(struct composite_context *ctx);
static void xp_login_start(struct event_context *ev, struct timed_event *te,
struct timeval tv, void *p);
static void xp_login_recv_auth2(struct composite_context *ctx);
static void xp_login_recv_trusts(struct composite_context *creq);
static void xp_login_recv_schannel(struct composite_context *creq);
static void xp_login_recv_samlogon(struct rpc_request *req);
static void xp_login_recv_names(struct composite_context *creq);
static void xp_login_recv_domadmins(struct composite_context *creq);
static void xp_login_recv_ntconfig(struct composite_context *creq);
static void xp_login_recv_memberships(struct composite_context *creq);
static struct composite_context *xp_login_send(TALLOC_CTX *mem_ctx,
struct timeval timeout,
struct event_context *event_ctx,
const char *dc_name,
const char *dc_ip,
const char *wks_domain,
const char *wks_name,
const char *wks_pwd,
const char *user_domain,
const char *user_name,
const char *user_pwd)
{
struct composite_context *c;
struct xp_login_state *state;
c = talloc_zero(mem_ctx, struct composite_context);
if (c == NULL) return NULL;
state = talloc(c, struct xp_login_state);
if (state == NULL) {
c->status = NT_STATUS_NO_MEMORY;
goto failed;
}
c->state = COMPOSITE_STATE_IN_PROGRESS;
c->private_data = state;
c->event_ctx = event_ctx;
state->timeout = timeout;
state->dc_name = dc_name;
state->dc_ip = dc_ip;
state->wks_domain = wks_domain;
state->wks_name = wks_name;
state->wks_pwd = wks_pwd;
state->user_domain = user_domain;
state->user_name = user_name;
state->user_pwd = user_pwd;
state->wks_creds = cli_credentials_init(state);
if (state->wks_creds == NULL) goto failed;
cli_credentials_set_conf(state->wks_creds);
cli_credentials_set_domain(state->wks_creds, wks_domain,
CRED_SPECIFIED);
cli_credentials_set_workstation(state->wks_creds, wks_name,
CRED_SPECIFIED);
cli_credentials_set_username(state->wks_creds,
talloc_asprintf(state, "%s$", wks_name),
CRED_SPECIFIED);
cli_credentials_set_password(state->wks_creds, wks_pwd,
CRED_SPECIFIED);
cli_credentials_set_secure_channel_type(state->wks_creds,
SEC_CHAN_WKSTA);
state->conn.in.dest_host = dc_name;
state->conn.in.port = 0;
state->conn.in.called_name = dc_name;
state->conn.in.service = "IPC$";
state->conn.in.service_type = "IPC";
state->conn.in.credentials = cli_credentials_init(state);
if (state->conn.in.credentials == NULL) goto failed;
cli_credentials_set_conf(state->conn.in.credentials);
cli_credentials_set_anonymous(state->conn.in.credentials);
cli_credentials_set_workstation(state->conn.in.credentials, wks_name,
CRED_SPECIFIED);
state->conn.in.fallback_to_anonymous = False;
state->conn.in.workgroup = wks_domain;
event_add_timed(c->event_ctx, state,
timeval_current_ofs(state->timeout.tv_sec,
state->timeout.tv_usec),
xp_login_start, c);
return c;
failed:
composite_error(c, c->status);
return c;
}
static void xp_login_start(struct event_context *ev, struct timed_event *te,
struct timeval tv, void *p)
{
struct composite_context *c =
talloc_get_type(p, struct composite_context);
struct xp_login_state *state =
talloc_get_type(c->private_data, struct xp_login_state);
struct composite_context *creq;
creq = smb_composite_connect_send(&state->conn, state, c->event_ctx);
composite_continue(c, creq, xp_login_recv_conn, c);
}
static void xp_login_recv_conn(struct composite_context *creq)
{
struct composite_context *c =
talloc_get_type(creq->async.private_data,
struct composite_context);
struct xp_login_state *state =
talloc_get_type(c->private_data, struct xp_login_state);
c->status = smb_composite_connect_recv(creq, state);
if (!composite_is_ok(c)) return;
creq = get_schannel_creds_send(state, state->wks_creds,
state->conn.out.tree, c->event_ctx);
composite_continue(c, creq, xp_login_recv_auth2, c);
}
static void xp_login_recv_auth2(struct composite_context *creq)
{
struct composite_context *c =
talloc_get_type(creq->async.private_data,
struct composite_context);
struct xp_login_state *state =
talloc_get_type(c->private_data, struct xp_login_state);
c->status = get_schannel_creds_recv(creq, state,
&state->netlogon_pipe);
if (!composite_is_ok(c)) return;
creq = lsa_enumtrust_send(state,
dcerpc_smb_tree(state->netlogon_pipe->conn));
composite_continue(c, creq, xp_login_recv_trusts, c);
}
static void xp_login_recv_trusts(struct composite_context *creq)
{
struct composite_context *c =
talloc_get_type(creq->async.private_data,
struct composite_context);
struct xp_login_state *state =
talloc_get_type(c->private_data, struct xp_login_state);
c->status = lsa_enumtrust_recv(creq);
if (!composite_is_ok(c)) return;
creq = get_netlogon_schannel_send(
state, dcerpc_smb_tree(state->netlogon_pipe->conn),
state->wks_creds);
composite_continue(c, creq, xp_login_recv_schannel, c);
}
static void xp_login_recv_schannel(struct composite_context *creq)
{
struct composite_context *c =
talloc_get_type(creq->async.private_data,
struct composite_context);
struct xp_login_state *state =
talloc_get_type(c->private_data, struct xp_login_state);
struct rpc_request *req;
const char *workstation;
DATA_BLOB chal, nt_resp, lm_resp, names_blob;
int flags = CLI_CRED_NTLM_AUTH;
c->status = get_netlogon_schannel_recv(creq, state,
&state->netlogon_schannel_pipe);
if (!composite_is_ok(c)) return;
if (lp_client_lanman_auth()) {
flags |= CLI_CRED_LANMAN_AUTH;
}
if (lp_client_ntlmv2_auth()) {
flags |= CLI_CRED_NTLMv2_AUTH;
}
state->user_creds = cli_credentials_init(state);
if (composite_nomem(state->user_creds, c)) return;
cli_credentials_set_conf(state->user_creds);
cli_credentials_set_workstation(state->user_creds, state->wks_name, CRED_SPECIFIED);
cli_credentials_set_domain(state->user_creds, state->user_domain, CRED_SPECIFIED);
cli_credentials_set_username(state->user_creds, state->user_name, CRED_SPECIFIED);
cli_credentials_set_password(state->user_creds, state->user_pwd, CRED_SPECIFIED);
chal = data_blob_talloc(state, NULL, 8);
if (composite_nomem(chal.data, c)) return;
generate_random_buffer(chal.data, chal.length);
cli_credentials_get_ntlm_username_domain(state->user_creds, state,
&state->user_name,
&state->user_domain);
/* for best compatability with multiple vitual netbios names
* on the host, this should be generated from the
* cli_credentials associated with the machine account */
workstation = cli_credentials_get_workstation(state->user_creds);
names_blob = NTLMv2_generate_names_blob(
state,
cli_credentials_get_workstation(state->user_creds),
cli_credentials_get_domain(state->user_creds));
c->status = cli_credentials_get_ntlm_response(
state->user_creds, state, &flags, chal, names_blob,
&lm_resp, &nt_resp, NULL, NULL);
if (!composite_is_ok(c)) return;
state->creds_state =
cli_credentials_get_netlogon_creds(state->wks_creds);
creds_client_authenticator(state->creds_state, &state->auth);
state->ninfo.identity_info.account_name.string = state->user_name;
state->ninfo.identity_info.domain_name.string = state->user_domain;
state->ninfo.identity_info.parameter_control = 0;
state->ninfo.identity_info.logon_id_low = 0;
state->ninfo.identity_info.logon_id_high = 0;
state->ninfo.identity_info.workstation.string = state->wks_name;
state->ninfo.nt.length = nt_resp.length;
state->ninfo.nt.data = nt_resp.data;
state->ninfo.lm.length = lm_resp.length;
state->ninfo.lm.data = lm_resp.data;
memcpy(state->ninfo.challenge, chal.data,
sizeof(state->ninfo.challenge));
state->r.in.server_name = talloc_asprintf(
state, "\\\\%s", dcerpc_server_name(state->netlogon_pipe));
if (composite_nomem(state->r.in.server_name, c)) return;
ZERO_STRUCT(state->auth2);
state->r.in.workstation =
cli_credentials_get_workstation(state->wks_creds);
state->r.in.credential = &state->auth;
state->r.in.return_authenticator = &state->auth2;
state->r.in.logon_level = 2;
state->r.in.validation_level = 3;
state->r.in.logon.network = &state->ninfo;
state->r.out.return_authenticator = NULL;
req = dcerpc_netr_LogonSamLogon_send(state->netlogon_schannel_pipe,
state, &state->r);
composite_continue_rpc(c, req, xp_login_recv_samlogon, c);
}
static void xp_login_recv_samlogon(struct rpc_request *req)
{
struct composite_context *c =
talloc_get_type(req->async.private,
struct composite_context);
struct xp_login_state *state =
talloc_get_type(c->private_data, struct xp_login_state);
struct composite_context *creq;
struct netr_SamInfo3 *sam3;
int i;
c->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(c)) return;
if ((state->r.out.return_authenticator == NULL) ||
(!creds_client_check(state->creds_state,
&state->r.out.return_authenticator->cred))) {
DEBUG(0, ("Credentials check failed!\n"));
composite_error(c, NT_STATUS_ACCESS_DENIED);
return;
}
c->status = state->r.out.result;
if (!composite_is_ok(c)) return;
sam3 = state->r.out.validation.sam3;
state->num_sids = sam3->base.groups.count + 1;
state->sids = talloc_array(state, const struct dom_sid *, state->num_sids);
if (composite_nomem(state->sids, c)) return;
state->sids[0] = dom_sid_add_rid(state->sids, sam3->base.domain_sid,
sam3->base.rid);
if (composite_nomem(state->sids[0], c)) return;
for (i=0; i<sam3->base.groups.count; i++) {
state->sids[i+1] = dom_sid_add_rid(state->sids,
sam3->base.domain_sid,
sam3->base.groups.rids[i].rid);
if (composite_nomem(state->sids[i+1], c)) return;
}
creq = lookupsids_send(state, dcerpc_smb_tree(state->netlogon_pipe->conn),
state->num_sids, state->sids);
composite_continue(c, creq, xp_login_recv_names, c);
}
static void xp_login_recv_names(struct composite_context *creq)
{
struct composite_context *c =
talloc_get_type(creq->async.private_data,
struct composite_context);
struct xp_login_state *state =
talloc_get_type(c->private_data, struct xp_login_state);
c->status = lookupsids_recv(creq, state, &state->num_names,
&state->names);
if (!composite_is_ok(c)) return;
creq = domadmins_send(state,
dcerpc_smb_tree(state->netlogon_pipe->conn));
composite_continue(c, creq, xp_login_recv_domadmins, c);
}
static void xp_login_recv_domadmins(struct composite_context *creq)
{
struct composite_context *c =
talloc_get_type(creq->async.private_data,
struct composite_context);
struct xp_login_state *state =
talloc_get_type(c->private_data, struct xp_login_state);
struct smbcli_tree *tree;
c->status = domadmins_recv(creq, state, &state->num_domadmins,
&state->domadmins);
if (!composite_is_ok(c)) return;
tree = dcerpc_smb_tree(state->netlogon_pipe->conn);
creq = ntconfig_send(state, tree->session->transport,
state->user_creds);
composite_continue(c, creq, xp_login_recv_ntconfig, c);
}
static void xp_login_recv_ntconfig(struct composite_context *creq)
{
struct composite_context *c =
talloc_get_type(creq->async.private_data,
struct composite_context);
struct xp_login_state *state =
talloc_get_type(c->private_data, struct xp_login_state);
c->status = ntconfig_recv(creq);
if (!NT_STATUS_IS_OK(c->status)) {
DEBUG(3, ("downloading ntconfig.pol failed: %s\n",
nt_errstr(c->status)));
/* Continue, we don't care */
}
state->num_memberships_done = 0;
creq = memberships_send(state,
dcerpc_smb_tree(state->netlogon_pipe->conn),
state->user_name);
composite_continue(c, creq, xp_login_recv_memberships, c);
}
static void xp_login_recv_memberships(struct composite_context *creq)
{
struct composite_context *c =
talloc_get_type(creq->async.private_data,
struct composite_context);
struct xp_login_state *state =
talloc_get_type(c->private_data, struct xp_login_state);
c->status = memberships_recv(creq);
if (!composite_is_ok(c)) return;
state->num_memberships_done += 1;
if (state->num_memberships_done < 3) {
/* Yes, this is ususally done more than once. It might be due
to ntconfig.pol and local security policy settings. */
creq = memberships_send(
state, dcerpc_smb_tree(state->netlogon_pipe->conn),
state->user_name);
composite_continue(c, creq, xp_login_recv_memberships, c);
return;
}
composite_done(c);
}
static NTSTATUS xp_login_recv(struct composite_context *ctx)
{
NTSTATUS status = composite_wait(ctx);
talloc_free(ctx);
return status;
}
static void xp_login_done(struct composite_context *ctx)
{
int *count = (int *)(ctx->async.private_data);
*count += 1;
}
struct pwdentry {
const char *domain;
const char *name;
const char *pass;
};
static BOOL read_pwd_file(TALLOC_CTX *mem_ctx,
const char *fname, int *numlines,
struct pwdentry ***result)
{
char **lines;
int i;
lines = file_lines_load(fname, numlines, mem_ctx);
if (lines == NULL) {
DEBUG(0, ("Could not load file %s: %s\n",
fname, strerror(errno)));
return False;
}
if (*numlines == 0) {
DEBUG(0, ("no entries in file %s\n", fname));
return False;
}
*result = talloc_array(mem_ctx, struct pwdentry *, *numlines);
if (*result == NULL) {
DEBUG(0, ("talloc failed\n"));
return False;
}
for (i=0; i<(*numlines); i++) {
char *p, *q;
(*result)[i] = talloc_zero(*result, struct pwdentry);
if ((*result)[i] == NULL) {
DEBUG(0, ("talloc failed\n"));
return False;
}
p = lines[i];
q = strchr(p, '\\');
if (q != NULL) {
*q = '\0';
(*result)[i]->domain = lines[i];
p = q+1;
} else {
(*result)[i]->domain = lp_workgroup();
}
q = strchr(p, '%');
if (q == NULL) {
DEBUG(0, ("Invalid entry: %s\n", q));
return False;
}
*q = '\0';
(*result)[i]->name = p;
(*result)[i]->pass = q+1;
}
return True;
}
#if 0
/* Stolen from testjoin.c for easy mass-joining */p
static BOOL joinme(int i)
{
TALLOC_CTX *mem_ctx;
struct test_join *join_ctx;
struct cli_credentials *machine_credentials;
const char *machine_password;
const char *name;
mem_ctx = talloc_init("torture_rpc_netlogon");
name = talloc_asprintf(mem_ctx, "wks%3d", i);
join_ctx = torture_join_domain(name, ACB_WSTRUST,
&machine_credentials);
if (!join_ctx) {
talloc_free(mem_ctx);
printf("Failed to join as BDC\n");
return False;
}
machine_password = cli_credentials_get_password(machine_credentials);
printf("%s%%%s\n", name, machine_password);
talloc_free(mem_ctx);
return True;
}
#endif
BOOL torture_rpc_login(void)
{
TALLOC_CTX *mem_ctx;
struct event_context *event_ctx;
BOOL result = False;
extern int torture_numops;
int i, num_events;
int num_finished = 0;
struct composite_context **ctx;
struct pwdentry **wks_list;
struct pwdentry **user_list;
int num_wks = 0;
int num_user = 0;
#if 0
for (i=0; i<torture_numops; i++) {
if (!joinme(i)) {
DEBUG(0, ("join %d failed\n", i));
return False;
}
}
return False;
#endif
mem_ctx = talloc_init("rpc_login");
if (mem_ctx == NULL) {
DEBUG(0, ("talloc_init failed\n"));
return False;
}
if (!read_pwd_file(mem_ctx, "wks.pwd", &num_wks, &wks_list)) {
return False;
}
if (torture_numops > num_wks) {
DEBUG(0, ("more workstations (%d) than ops (%d) needed\n",
num_wks, torture_numops));
return False;
}
if (!read_pwd_file(mem_ctx, "user.pwd", &num_user, &user_list)) {
return False;
}
event_ctx = event_context_init(mem_ctx);
if (event_ctx == NULL) {
DEBUG(0, ("event_context_init failed\n"));
goto done;
}
ctx = talloc_array(mem_ctx, struct composite_context *,
torture_numops);
if (ctx == NULL) {
DEBUG(0, ("talloc_array failed\n"));
goto done;
}
for (i=0; i<torture_numops; i++) {
int wks_idx = random() % num_wks;
int user_idx = random() % num_user;
DEBUG(3, ("random indices: wks %d, user %d\n", wks_idx, user_idx));
ctx[i] = xp_login_send(
mem_ctx, timeval_set(0, i*lp_parm_int(-1, "torture",
"timeout", 0)),
event_ctx,
lp_parm_string(-1, "torture", "host"),
lp_parm_string(-1, "torture", "host"),
lp_workgroup(),
wks_list[wks_idx]->name,
wks_list[wks_idx]->pass,
user_list[user_idx]->domain,
user_list[user_idx]->name,
user_list[user_idx]->pass);
if (ctx[i] == NULL) {
DEBUG(0, ("xp_login_send failed\n"));
goto done;
}
ctx[i]->async.fn = xp_login_done;
ctx[i]->async.private_data = &num_finished;
/* Avoid duplicate usage of workstation accounts. They would
* conflict if multiple reqchal/auth2/schannel-binds cross
* each other */
wks_list[wks_idx] = wks_list[num_wks-1];
num_wks -= 1;
}
num_events = 0;
while (num_finished < torture_numops) {
event_loop_once(event_ctx);
num_events += 1;
}
DEBUG(0, ("num_events = %d\n", num_events));
for (i=0; i<torture_numops; i++) {
DEBUG(0, ("login %3d returned %s\n", i,
nt_errstr(xp_login_recv(ctx[i]))));
}
result = True;
done:
talloc_free(mem_ctx);
return result;
}