1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-11 05:18:09 +03:00

r23890: Allow wbinfo -a to work against Samba4's winbind.

Add a test for wbinfo -a to test_member.sh

Reimplement the server-side 'pam_auth' and 'pam_auth_crap' calls to
use the same SamLogon code as auth_winbind uses.

In my previous code, we did not bind to the LSA and SAMR pipes, before
attempting operations.  We now do this (how we passed any tests before
is beyond me).

This required some rework, particularly to make it easier to setup
secondary connections.  The new rpc_secondary_auth_connection()
function also performs the bind.

The dcerpc_connect.c file was getting to big, so things have been
merged into dcerpc_secondary.c.

Andrew Bartlett
(This used to be commit 365778a993)
This commit is contained in:
Andrew Bartlett 2007-07-16 11:27:29 +00:00 committed by Gerald (Jerry) Carter
parent 3ccf9ff2ab
commit c86e98aa80
8 changed files with 398 additions and 332 deletions

View File

@ -476,7 +476,8 @@ OBJ_FILES = \
rpc/dcerpc_smb.o \ rpc/dcerpc_smb.o \
rpc/dcerpc_smb2.o \ rpc/dcerpc_smb2.o \
rpc/dcerpc_sock.o \ rpc/dcerpc_sock.o \
rpc/dcerpc_connect.o rpc/dcerpc_connect.o \
rpc/dcerpc_secondary.o
PRIVATE_DEPENDENCIES = \ PRIVATE_DEPENDENCIES = \
samba-socket LIBCLI_RESOLVE LIBCLI_SMB LIBCLI_SMB2 \ samba-socket LIBCLI_RESOLVE LIBCLI_SMB LIBCLI_SMB2 \
LIBNDR NDR_DCERPC RPC_NDR_EPMAPPER \ LIBNDR NDR_DCERPC RPC_NDR_EPMAPPER \

View File

@ -5,7 +5,7 @@
Copyright (C) Andrew Tridgell 2003 Copyright (C) Andrew Tridgell 2003
Copyright (C) Jelmer Vernooij 2004 Copyright (C) Jelmer Vernooij 2004
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2007
Copyright (C) Rafal Szczesniak 2005 Copyright (C) Rafal Szczesniak 2005
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
@ -915,186 +915,3 @@ NTSTATUS dcerpc_pipe_connect(TALLOC_CTX *parent_ctx,
return dcerpc_pipe_connect_recv(c, parent_ctx, pp); return dcerpc_pipe_connect_recv(c, parent_ctx, pp);
} }
struct sec_conn_state {
struct dcerpc_pipe *pipe;
struct dcerpc_pipe *pipe2;
struct dcerpc_binding *binding;
struct smbcli_tree *tree;
};
static void continue_open_smb(struct composite_context *ctx);
static void continue_open_tcp(struct composite_context *ctx);
static void continue_open_pipe(struct composite_context *ctx);
static void continue_pipe_open(struct composite_context *c);
/*
Send request to create a secondary dcerpc connection from a primary
connection
*/
struct composite_context* dcerpc_secondary_connection_send(struct dcerpc_pipe *p,
struct dcerpc_binding *b)
{
struct composite_context *c;
struct sec_conn_state *s;
struct composite_context *pipe_smb_req;
struct composite_context *pipe_tcp_req;
struct composite_context *pipe_ncalrpc_req;
/* composite context allocation and setup */
c = composite_create(p, p->conn->event_ctx);
if (c == NULL) return NULL;
s = talloc_zero(c, struct sec_conn_state);
if (composite_nomem(s, c)) return c;
c->private_data = s;
s->pipe = p;
s->binding = b;
/* initialise second dcerpc pipe based on primary pipe's event context */
s->pipe2 = dcerpc_pipe_init(c, s->pipe->conn->event_ctx);
if (composite_nomem(s->pipe2, c)) return c;
/* open second dcerpc pipe using the same transport as for primary pipe */
switch (s->pipe->conn->transport.transport) {
case NCACN_NP:
/* get smb tree of primary dcerpc pipe opened on smb */
s->tree = dcerpc_smb_tree(s->pipe->conn);
if (!s->tree) {
composite_error(c, NT_STATUS_INVALID_PARAMETER);
return c;
}
pipe_smb_req = dcerpc_pipe_open_smb_send(s->pipe2, s->tree,
s->binding->endpoint);
composite_continue(c, pipe_smb_req, continue_open_smb, c);
return c;
case NCACN_IP_TCP:
pipe_tcp_req = dcerpc_pipe_open_tcp_send(s->pipe2->conn,
s->binding->host,
s->binding->target_hostname,
atoi(s->binding->endpoint));
composite_continue(c, pipe_tcp_req, continue_open_tcp, c);
return c;
case NCALRPC:
pipe_ncalrpc_req = dcerpc_pipe_open_pipe_send(s->pipe2->conn,
s->binding->endpoint);
composite_continue(c, pipe_ncalrpc_req, continue_open_pipe, c);
return c;
default:
/* looks like a transport we don't support */
composite_error(c, NT_STATUS_NOT_SUPPORTED);
}
return c;
}
/*
Stage 2 of secondary_connection: Receive result of pipe open request on smb
*/
static void continue_open_smb(struct composite_context *ctx)
{
struct composite_context *c = talloc_get_type(ctx->async.private_data,
struct composite_context);
c->status = dcerpc_pipe_open_smb_recv(ctx);
if (!composite_is_ok(c)) return;
continue_pipe_open(c);
}
/*
Stage 2 of secondary_connection: Receive result of pipe open request on tcp/ip
*/
static void continue_open_tcp(struct composite_context *ctx)
{
struct composite_context *c = talloc_get_type(ctx->async.private_data,
struct composite_context);
c->status = dcerpc_pipe_open_tcp_recv(ctx);
if (!composite_is_ok(c)) return;
continue_pipe_open(c);
}
/*
Stage 2 of secondary_connection: Receive result of pipe open request on ncalrpc
*/
static void continue_open_pipe(struct composite_context *ctx)
{
struct composite_context *c = talloc_get_type(ctx->async.private_data,
struct composite_context);
c->status = dcerpc_pipe_open_pipe_recv(ctx);
if (!composite_is_ok(c)) return;
continue_pipe_open(c);
}
/*
Stage 3 of secondary_connection: Get binding data and flags from primary pipe
and say if we're done ok.
*/
static void continue_pipe_open(struct composite_context *c)
{
struct sec_conn_state *s;
s = talloc_get_type(c->private_data, struct sec_conn_state);
s->pipe2->conn->flags = s->pipe->conn->flags;
s->pipe2->binding = s->binding;
if (!talloc_reference(s->pipe2, s->binding)) {
composite_error(c, NT_STATUS_NO_MEMORY);
return;
}
composite_done(c);
}
/*
Receive result of secondary rpc connection request and return
second dcerpc pipe.
*/
NTSTATUS dcerpc_secondary_connection_recv(struct composite_context *c,
struct dcerpc_pipe **p2)
{
NTSTATUS status = composite_wait(c);
struct sec_conn_state *s;
s = talloc_get_type(c->private_data, struct sec_conn_state);
if (NT_STATUS_IS_OK(status)) {
*p2 = talloc_steal(s->pipe, s->pipe2);
}
talloc_free(c);
return status;
}
/*
Create a secondary dcerpc connection from a primary connection
- sync version
If the primary is a SMB connection then the secondary connection
will be on the same SMB connection, but using a new fnum
*/
NTSTATUS dcerpc_secondary_connection(struct dcerpc_pipe *p,
struct dcerpc_pipe **p2,
struct dcerpc_binding *b)
{
struct composite_context *c;
c = dcerpc_secondary_connection_send(p, b);
return dcerpc_secondary_connection_recv(c, p2);
}

View File

@ -0,0 +1,317 @@
/*
Unix SMB/CIFS implementation.
dcerpc connect functions
Copyright (C) Andrew Tridgell 2003
Copyright (C) Jelmer Vernooij 2004
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2007
Copyright (C) Rafal Szczesniak 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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "libcli/composite/composite.h"
#include "lib/events/events.h"
#include "librpc/rpc/dcerpc.h"
#include "auth/credentials/credentials.h"
struct sec_conn_state {
struct dcerpc_pipe *pipe;
struct dcerpc_pipe *pipe2;
struct dcerpc_binding *binding;
struct smbcli_tree *tree;
};
static void continue_open_smb(struct composite_context *ctx);
static void continue_open_tcp(struct composite_context *ctx);
static void continue_open_pipe(struct composite_context *ctx);
static void continue_pipe_open(struct composite_context *c);
/*
Send request to create a secondary dcerpc connection from a primary
connection
*/
struct composite_context* dcerpc_secondary_connection_send(struct dcerpc_pipe *p,
struct dcerpc_binding *b)
{
struct composite_context *c;
struct sec_conn_state *s;
struct composite_context *pipe_smb_req;
struct composite_context *pipe_tcp_req;
struct composite_context *pipe_ncalrpc_req;
/* composite context allocation and setup */
c = composite_create(p, p->conn->event_ctx);
if (c == NULL) return NULL;
s = talloc_zero(c, struct sec_conn_state);
if (composite_nomem(s, c)) return c;
c->private_data = s;
s->pipe = p;
s->binding = b;
/* initialise second dcerpc pipe based on primary pipe's event context */
s->pipe2 = dcerpc_pipe_init(c, s->pipe->conn->event_ctx);
if (composite_nomem(s->pipe2, c)) return c;
/* open second dcerpc pipe using the same transport as for primary pipe */
switch (s->pipe->conn->transport.transport) {
case NCACN_NP:
/* get smb tree of primary dcerpc pipe opened on smb */
s->tree = dcerpc_smb_tree(s->pipe->conn);
if (!s->tree) {
composite_error(c, NT_STATUS_INVALID_PARAMETER);
return c;
}
pipe_smb_req = dcerpc_pipe_open_smb_send(s->pipe2, s->tree,
s->binding->endpoint);
composite_continue(c, pipe_smb_req, continue_open_smb, c);
return c;
case NCACN_IP_TCP:
pipe_tcp_req = dcerpc_pipe_open_tcp_send(s->pipe2->conn,
s->binding->host,
s->binding->target_hostname,
atoi(s->binding->endpoint));
composite_continue(c, pipe_tcp_req, continue_open_tcp, c);
return c;
case NCALRPC:
pipe_ncalrpc_req = dcerpc_pipe_open_pipe_send(s->pipe2->conn,
s->binding->endpoint);
composite_continue(c, pipe_ncalrpc_req, continue_open_pipe, c);
return c;
default:
/* looks like a transport we don't support */
composite_error(c, NT_STATUS_NOT_SUPPORTED);
}
return c;
}
/*
Stage 2 of secondary_connection: Receive result of pipe open request on smb
*/
static void continue_open_smb(struct composite_context *ctx)
{
struct composite_context *c = talloc_get_type(ctx->async.private_data,
struct composite_context);
c->status = dcerpc_pipe_open_smb_recv(ctx);
if (!composite_is_ok(c)) return;
continue_pipe_open(c);
}
/*
Stage 2 of secondary_connection: Receive result of pipe open request on tcp/ip
*/
static void continue_open_tcp(struct composite_context *ctx)
{
struct composite_context *c = talloc_get_type(ctx->async.private_data,
struct composite_context);
c->status = dcerpc_pipe_open_tcp_recv(ctx);
if (!composite_is_ok(c)) return;
continue_pipe_open(c);
}
/*
Stage 2 of secondary_connection: Receive result of pipe open request on ncalrpc
*/
static void continue_open_pipe(struct composite_context *ctx)
{
struct composite_context *c = talloc_get_type(ctx->async.private_data,
struct composite_context);
c->status = dcerpc_pipe_open_pipe_recv(ctx);
if (!composite_is_ok(c)) return;
continue_pipe_open(c);
}
/*
Stage 3 of secondary_connection: Get binding data and flags from primary pipe
and say if we're done ok.
*/
static void continue_pipe_open(struct composite_context *c)
{
struct sec_conn_state *s;
s = talloc_get_type(c->private_data, struct sec_conn_state);
s->pipe2->conn->flags = s->pipe->conn->flags;
s->pipe2->binding = s->binding;
if (!talloc_reference(s->pipe2, s->binding)) {
composite_error(c, NT_STATUS_NO_MEMORY);
return;
}
composite_done(c);
}
/*
Receive result of secondary rpc connection request and return
second dcerpc pipe.
*/
NTSTATUS dcerpc_secondary_connection_recv(struct composite_context *c,
struct dcerpc_pipe **p2)
{
NTSTATUS status = composite_wait(c);
struct sec_conn_state *s;
s = talloc_get_type(c->private_data, struct sec_conn_state);
if (NT_STATUS_IS_OK(status)) {
*p2 = talloc_steal(s->pipe, s->pipe2);
}
talloc_free(c);
return status;
}
/*
Create a secondary dcerpc connection from a primary connection
- sync version
If the primary is a SMB connection then the secondary connection
will be on the same SMB connection, but using a new fnum
*/
NTSTATUS dcerpc_secondary_connection(struct dcerpc_pipe *p,
struct dcerpc_pipe **p2,
struct dcerpc_binding *b)
{
struct composite_context *c;
c = dcerpc_secondary_connection_send(p, b);
return dcerpc_secondary_connection_recv(c, p2);
}
/*
Create a secondary DCERPC connection, then bind (and possibly
authenticate) using the supplied credentials.
This creates a second connection, to the same host (and on ncacn_np on the same connection) as the first
*/
struct sec_auth_conn_state {
struct dcerpc_pipe *pipe2;
struct dcerpc_binding *binding;
const struct dcerpc_interface_table *table;
struct cli_credentials *credentials;
struct composite_context *ctx;
};
static void dcerpc_secondary_auth_connection_bind(struct composite_context *ctx);
static void dcerpc_secondary_auth_connection_continue(struct composite_context *ctx);
struct composite_context* dcerpc_secondary_auth_connection_send(struct dcerpc_pipe *p,
struct dcerpc_binding *binding,
const struct dcerpc_interface_table *table,
struct cli_credentials *credentials)
{
struct composite_context *c, *secondary_conn_ctx;
struct sec_auth_conn_state *s;
/* composite context allocation and setup */
c = composite_create(p, p->conn->event_ctx);
if (c == NULL) return NULL;
s = talloc_zero(c, struct sec_auth_conn_state);
if (composite_nomem(s, c)) return c;
c->private_data = s;
s->ctx = c;
s->binding = binding;
s->table = table;
s->credentials = credentials;
secondary_conn_ctx = dcerpc_secondary_connection_send(p, binding);
if (composite_nomem(secondary_conn_ctx, s->ctx)) {
talloc_free(c);
return NULL;
}
composite_continue(s->ctx, secondary_conn_ctx, dcerpc_secondary_auth_connection_bind,
s);
return c;
}
/*
Stage 2 of secondary_auth_connection:
Having made the secondary connection, we will need to do an (authenticated) bind
*/
static void dcerpc_secondary_auth_connection_bind(struct composite_context *ctx)
{
struct composite_context *secondary_auth_ctx;
struct sec_auth_conn_state *s = talloc_get_type(ctx->async.private_data,
struct sec_auth_conn_state);
s->ctx->status = dcerpc_secondary_connection_recv(ctx, &s->pipe2);
if (!composite_is_ok(s->ctx)) return;
secondary_auth_ctx = dcerpc_pipe_auth_send(s->pipe2, s->binding, s->table, s->credentials);
composite_continue(s->ctx, secondary_auth_ctx, dcerpc_secondary_auth_connection_continue, s);
}
/*
Stage 3 of secondary_auth_connection: Receive result of authenticated bind request
*/
static void dcerpc_secondary_auth_connection_continue(struct composite_context *ctx)
{
struct sec_auth_conn_state *s = talloc_get_type(ctx->async.private_data,
struct sec_auth_conn_state);
s->ctx->status = dcerpc_pipe_auth_recv(ctx, s, &s->pipe2);
if (!composite_is_ok(s->ctx)) return;
composite_done(s->ctx);
}
/*
Receive an authenticated pipe, created as a secondary connection
*/
NTSTATUS dcerpc_secondary_auth_connection_recv(struct composite_context *c,
TALLOC_CTX *mem_ctx,
struct dcerpc_pipe **p)
{
NTSTATUS status = composite_wait(c);
struct sec_auth_conn_state *s;
s = talloc_get_type(c->private_data, struct sec_auth_conn_state);
if (NT_STATUS_IS_OK(status)) {
*p = talloc_steal(mem_ctx, s->pipe2);
}
talloc_free(c);
return status;
}

View File

@ -5,3 +5,4 @@ incdir=`dirname $0`
plantest "RPC-ECHO against member server with local creds" member $VALGRIND bin/smbtorture $TORTURE_OPTIONS ncacn_np:"\$NETBIOSNAME" -U"\$NETBIOSNAME\\\\\$USERNAME"%"\$PASSWORD" RPC-ECHO "$*" plantest "RPC-ECHO against member server with local creds" member $VALGRIND bin/smbtorture $TORTURE_OPTIONS ncacn_np:"\$NETBIOSNAME" -U"\$NETBIOSNAME\\\\\$USERNAME"%"\$PASSWORD" RPC-ECHO "$*"
plantest "RPC-ECHO against member server with domain creds" member $VALGRIND bin/smbtorture $TORTURE_OPTIONS ncacn_np:"\$NETBIOSNAME" -U"\$DOMAIN\\\\\$DC_USERNAME"%"\$DC_PASSWORD" RPC-ECHO "$*" plantest "RPC-ECHO against member server with domain creds" member $VALGRIND bin/smbtorture $TORTURE_OPTIONS ncacn_np:"\$NETBIOSNAME" -U"\$DOMAIN\\\\\$DC_USERNAME"%"\$DC_PASSWORD" RPC-ECHO "$*"
plantest "wbinfo -a against member server with domain creds" member $VALGRIND bin/wbinfo -a "\$DOMAIN\\\\\$DC_USERNAME"%"\$DC_PASSWORD"

View File

@ -67,8 +67,10 @@ struct composite_context *wb_connect_samr_send(TALLOC_CTX *mem_ctx,
/* this will make the secondary connection on the same IPC$ share, /* this will make the secondary connection on the same IPC$ share,
secured with SPNEGO, NTLMSSP or SCHANNEL */ secured with SPNEGO, NTLMSSP or SCHANNEL */
ctx = dcerpc_secondary_connection_send(domain->netlogon_pipe, ctx = dcerpc_secondary_auth_connection_send(domain->netlogon_pipe,
domain->samr_binding); domain->samr_binding,
&dcerpc_table_samr,
domain->schannel_creds);
composite_continue(state->ctx, ctx, connect_samr_recv_pipe, state); composite_continue(state->ctx, ctx, connect_samr_recv_pipe, state);
return result; return result;
@ -84,8 +86,8 @@ static void connect_samr_recv_pipe(struct composite_context *ctx)
talloc_get_type(ctx->async.private_data, talloc_get_type(ctx->async.private_data,
struct connect_samr_state); struct connect_samr_state);
state->ctx->status = dcerpc_secondary_connection_recv(ctx, state->ctx->status = dcerpc_secondary_auth_connection_recv(ctx, state,
&state->samr_pipe); &state->samr_pipe);
if (!composite_is_ok(state->ctx)) return; if (!composite_is_ok(state->ctx)) return;
state->connect_handle = talloc(state, struct policy_handle); state->connect_handle = talloc(state, struct policy_handle);

View File

@ -45,7 +45,7 @@ struct composite_context *wb_get_dom_info_send(TALLOC_CTX *mem_ctx,
{ {
struct composite_context *result, *ctx; struct composite_context *result, *ctx;
struct get_dom_info_state *state; struct get_dom_info_state *state;
struct dom_sid *dup_sid; struct dom_sid *dom_sid;
result = composite_create(mem_ctx, service->task->event_ctx); result = composite_create(mem_ctx, service->task->event_ctx);
if (result == NULL) goto failed; if (result == NULL) goto failed;
@ -57,11 +57,17 @@ struct composite_context *wb_get_dom_info_send(TALLOC_CTX *mem_ctx,
state->info = talloc_zero(state, struct wb_dom_info); state->info = talloc_zero(state, struct wb_dom_info);
if (state->info == NULL) goto failed; if (state->info == NULL) goto failed;
dup_sid = dom_sid_dup(state, sid); state->info->name = talloc_strdup(state->info, domain_name);
if (dup_sid == NULL) goto failed; if (state->info->name == NULL) goto failed;
state->info->sid = dom_sid_dup(state->info, sid);
if (state->info->sid == NULL) goto failed;
dom_sid = dom_sid_dup(mem_ctx, sid);
if (dom_sid == NULL) goto failed;
ctx = finddcs_send(mem_ctx, domain_name, NBT_NAME_LOGON, ctx = finddcs_send(mem_ctx, domain_name, NBT_NAME_LOGON,
dup_sid, lp_name_resolve_order(), service->task->event_ctx, dom_sid, lp_name_resolve_order(), service->task->event_ctx,
service->task->msg_ctx); service->task->msg_ctx);
if (ctx == NULL) goto failed; if (ctx == NULL) goto failed;

View File

@ -202,7 +202,7 @@ static void init_domain_recv_netlogonpipe(struct composite_context *ctx)
talloc_get_type(ctx->async.private_data, talloc_get_type(ctx->async.private_data,
struct init_domain_state); struct init_domain_state);
state->ctx->status = dcerpc_pipe_connect_b_recv(ctx, state, state->ctx->status = dcerpc_pipe_connect_b_recv(ctx, state->domain,
&state->domain->netlogon_pipe); &state->domain->netlogon_pipe);
if (!composite_is_ok(state->ctx)) { if (!composite_is_ok(state->ctx)) {
@ -224,13 +224,17 @@ static void init_domain_recv_netlogonpipe(struct composite_context *ctx)
/* this will make the secondary connection on the same IPC$ share, /* this will make the secondary connection on the same IPC$ share,
secured with SPNEGO or NTLMSSP */ secured with SPNEGO or NTLMSSP */
ctx = dcerpc_secondary_connection_send(state->domain->netlogon_pipe, ctx = dcerpc_secondary_auth_connection_send(state->domain->netlogon_pipe,
state->domain->lsa_binding); state->domain->lsa_binding,
&dcerpc_table_lsarpc,
state->domain->schannel_creds
);
composite_continue(state->ctx, ctx, init_domain_recv_lsa_pipe, state); composite_continue(state->ctx, ctx, init_domain_recv_lsa_pipe, state);
} }
static bool retry_with_schannel(struct init_domain_state *state, static bool retry_with_schannel(struct init_domain_state *state,
struct dcerpc_binding *binding, struct dcerpc_binding *binding,
const struct dcerpc_interface_table *table,
void (*continuation)(struct composite_context *)) void (*continuation)(struct composite_context *))
{ {
struct composite_context *ctx; struct composite_context *ctx;
@ -246,8 +250,10 @@ static bool retry_with_schannel(struct init_domain_state *state,
/* Try again, likewise on the same IPC$ share, /* Try again, likewise on the same IPC$ share,
secured with SCHANNEL */ secured with SCHANNEL */
ctx = dcerpc_secondary_connection_send(state->domain->netlogon_pipe, ctx = dcerpc_secondary_auth_connection_send(state->domain->netlogon_pipe,
binding); binding,
table,
state->domain->schannel_creds);
composite_continue(state->ctx, ctx, continuation, state); composite_continue(state->ctx, ctx, continuation, state);
return true; return true;
} else { } else {
@ -264,10 +270,11 @@ static void init_domain_recv_lsa_pipe(struct composite_context *ctx)
talloc_get_type(ctx->async.private_data, talloc_get_type(ctx->async.private_data,
struct init_domain_state); struct init_domain_state);
state->ctx->status = dcerpc_secondary_connection_recv(ctx, state->ctx->status = dcerpc_secondary_auth_connection_recv(ctx, state->domain,
&state->domain->lsa_pipe); &state->domain->lsa_pipe);
if (NT_STATUS_EQUAL(state->ctx->status, NT_STATUS_LOGON_FAILURE)) { if (NT_STATUS_EQUAL(state->ctx->status, NT_STATUS_LOGON_FAILURE)) {
if (retry_with_schannel(state, state->domain->lsa_binding, if (retry_with_schannel(state, state->domain->lsa_binding,
&dcerpc_table_lsarpc,
init_domain_recv_lsa_pipe)) { init_domain_recv_lsa_pipe)) {
return; return;
} }
@ -307,6 +314,7 @@ static void init_domain_recv_lsa_policy(struct rpc_request *req)
if ((!NT_STATUS_IS_OK(state->ctx->status) if ((!NT_STATUS_IS_OK(state->ctx->status)
|| !NT_STATUS_IS_OK(state->lsa_openpolicy.out.result))) { || !NT_STATUS_IS_OK(state->lsa_openpolicy.out.result))) {
if (retry_with_schannel(state, state->domain->lsa_binding, if (retry_with_schannel(state, state->domain->lsa_binding,
&dcerpc_table_lsarpc,
init_domain_recv_lsa_pipe)) { init_domain_recv_lsa_pipe)) {
return; return;
} }

View File

@ -28,23 +28,22 @@
#include "libcli/auth/libcli_auth.h" #include "libcli/auth/libcli_auth.h"
#include "librpc/gen_ndr/ndr_netlogon.h" #include "librpc/gen_ndr/ndr_netlogon.h"
#include "librpc/gen_ndr/ndr_netlogon_c.h" #include "librpc/gen_ndr/ndr_netlogon_c.h"
#include "librpc/gen_ndr/winbind.h"
/* Oh, there is so much to keep an eye on when authenticating a user. Oh my! */ /* Oh, there is so much to keep an eye on when authenticating a user. Oh my! */
struct pam_auth_crap_state { struct pam_auth_crap_state {
struct composite_context *ctx; struct composite_context *ctx;
struct event_context *event_ctx; struct event_context *event_ctx;
uint32_t logon_parameters;
const char *domain_name;
const char *user_name;
char *unix_username;
const char *workstation;
DATA_BLOB chal, nt_resp, lm_resp;
struct creds_CredentialState *creds_state; struct winbind_SamLogon *req;
struct netr_Authenticator auth, auth2; char *unix_username;
struct netr_NetworkInfo ninfo; struct netr_NetworkInfo ninfo;
struct netr_LogonSamLogon r; struct netr_LogonSamLogon r;
const char *user_name;
const char *domain_name;
struct netr_UserSessionKey user_session_key; struct netr_UserSessionKey user_session_key;
struct netr_LMSessionKey lm_key; struct netr_LMSessionKey lm_key;
DATA_BLOB info3; DATA_BLOB info3;
@ -54,8 +53,7 @@ struct pam_auth_crap_state {
* NTLM authentication. * NTLM authentication.
*/ */
static void pam_auth_crap_recv_domain(struct composite_context *ctx); static void pam_auth_crap_recv_logon(struct composite_context *ctx);
static void pam_auth_crap_recv_samlogon(struct rpc_request *req);
struct composite_context *wb_cmd_pam_auth_crap_send(TALLOC_CTX *mem_ctx, struct composite_context *wb_cmd_pam_auth_crap_send(TALLOC_CTX *mem_ctx,
struct wbsrv_service *service, struct wbsrv_service *service,
@ -69,6 +67,8 @@ struct composite_context *wb_cmd_pam_auth_crap_send(TALLOC_CTX *mem_ctx,
{ {
struct composite_context *result, *ctx; struct composite_context *result, *ctx;
struct pam_auth_crap_state *state; struct pam_auth_crap_state *state;
struct netr_NetworkInfo *ninfo;
DATA_BLOB tmp_nt_resp, tmp_lm_resp;
result = composite_create(mem_ctx, service->task->event_ctx); result = composite_create(mem_ctx, service->task->event_ctx);
if (result == NULL) goto failed; if (result == NULL) goto failed;
@ -78,35 +78,43 @@ struct composite_context *wb_cmd_pam_auth_crap_send(TALLOC_CTX *mem_ctx,
state->ctx = result; state->ctx = result;
result->private_data = state; result->private_data = state;
state->logon_parameters = logon_parameters; state->req = talloc(state, struct winbind_SamLogon);
state->domain_name = talloc_strdup(state, domain); state->req->in.logon_level = 2;
if (state->domain_name == NULL) goto failed; state->req->in.validation_level = 3;
ninfo = state->req->in.logon.network = talloc(state, struct netr_NetworkInfo);
if (ninfo == NULL) goto failed;
ninfo->identity_info.account_name.string = talloc_strdup(state, user);
ninfo->identity_info.domain_name.string = talloc_strdup(state, domain);
ninfo->identity_info.parameter_control = logon_parameters;
ninfo->identity_info.logon_id_low = 0;
ninfo->identity_info.logon_id_high = 0;
ninfo->identity_info.workstation.string = talloc_strdup(state, workstation);
state->user_name = talloc_strdup(state, user); SMB_ASSERT(chal.length == sizeof(ninfo->challenge));
if (state->user_name == NULL) goto failed; memcpy(ninfo->challenge, chal.data,
sizeof(ninfo->challenge));
tmp_nt_resp = data_blob_talloc(ninfo, nt_resp.data, nt_resp.length);
if ((nt_resp.data != NULL) &&
(tmp_nt_resp.data == NULL)) goto failed;
tmp_lm_resp = data_blob_talloc(ninfo, lm_resp.data, lm_resp.length);
if ((lm_resp.data != NULL) &&
(tmp_lm_resp.data == NULL)) goto failed;
ninfo->nt.length = tmp_nt_resp.length;
ninfo->nt.data = tmp_nt_resp.data;
ninfo->lm.length = tmp_lm_resp.length;
ninfo->lm.data = tmp_lm_resp.data;
state->unix_username = NULL; state->unix_username = NULL;
state->workstation = talloc_strdup(state, workstation); ctx = wb_sam_logon_send(mem_ctx, service, state->req);
if (state->workstation == NULL) goto failed;
state->chal = data_blob_talloc(state, chal.data, chal.length);
if ((chal.data != NULL) && (state->chal.data == NULL)) goto failed;
state->nt_resp = data_blob_talloc(state, nt_resp.data, nt_resp.length);
if ((nt_resp.data != NULL) &&
(state->nt_resp.data == NULL)) goto failed;
state->lm_resp = data_blob_talloc(state, lm_resp.data, lm_resp.length);
if ((lm_resp.data != NULL) &&
(state->lm_resp.data == NULL)) goto failed;
ctx = wb_sid2domain_send(state, service, service->primary_sid);
if (ctx == NULL) goto failed; if (ctx == NULL) goto failed;
ctx->async.fn = pam_auth_crap_recv_domain; composite_continue(result, ctx, pam_auth_crap_recv_logon, state);
ctx->async.private_data = state;
return result; return result;
failed: failed:
@ -119,95 +127,19 @@ struct composite_context *wb_cmd_pam_auth_crap_send(TALLOC_CTX *mem_ctx,
Send of a SamLogon request to authenticate a user. Send of a SamLogon request to authenticate a user.
*/ */
static void pam_auth_crap_recv_domain(struct composite_context *ctx) static void pam_auth_crap_recv_logon(struct composite_context *ctx)
{ {
DATA_BLOB tmp_blob;
struct netr_SamBaseInfo *base;
struct pam_auth_crap_state *state = struct pam_auth_crap_state *state =
talloc_get_type(ctx->async.private_data, talloc_get_type(ctx->async.private_data,
struct pam_auth_crap_state); struct pam_auth_crap_state);
struct rpc_request *req;
struct wbsrv_domain *domain;
state->ctx->status = wb_sid2domain_recv(ctx, &domain); state->ctx->status = wb_sam_logon_recv(ctx, state, state->req);
if (!composite_is_ok(state->ctx)) return; if (!composite_is_ok(state->ctx)) return;
state->creds_state =
cli_credentials_get_netlogon_creds(domain->schannel_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->domain_name;
state->ninfo.identity_info.parameter_control = state->logon_parameters;
state->ninfo.identity_info.logon_id_low = 0;
state->ninfo.identity_info.logon_id_high = 0;
state->ninfo.identity_info.workstation.string = state->workstation;
SMB_ASSERT(state->chal.length == sizeof(state->ninfo.challenge));
memcpy(state->ninfo.challenge, state->chal.data,
sizeof(state->ninfo.challenge));
state->ninfo.nt.length = state->nt_resp.length;
state->ninfo.nt.data = state->nt_resp.data;
state->ninfo.lm.length = state->lm_resp.length;
state->ninfo.lm.data = state->lm_resp.data;
state->r.in.server_name = talloc_asprintf(
state, "\\\\%s", dcerpc_server_name(domain->netlogon_pipe));
if (composite_nomem(state->r.in.server_name, state->ctx)) return;
ZERO_STRUCT(state->auth2);
state->r.in.computer_name =
cli_credentials_get_workstation(domain->schannel_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(domain->netlogon_pipe, state,
&state->r);
composite_continue_rpc(state->ctx, req, pam_auth_crap_recv_samlogon,
state);
}
/*
NTLM Authentication
Check the SamLogon reply, decrypt and parse out the session keys and the
info3 structure.
*/
static void pam_auth_crap_recv_samlogon(struct rpc_request *req)
{
struct pam_auth_crap_state *state =
talloc_get_type(req->async.private_data,
struct pam_auth_crap_state);
struct netr_SamBaseInfo *base;
DATA_BLOB tmp_blob;
state->ctx->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(state->ctx)) 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(state->ctx, NT_STATUS_ACCESS_DENIED);
return;
}
state->ctx->status = state->r.out.result;
if (!composite_is_ok(state->ctx)) return;
/* Decrypt the session keys before we reform the info3, so the
* person on the other end of winbindd pipe doesn't have to.
* They won't have the encryption key anyway */
creds_decrypt_samlogon(state->creds_state,
state->r.in.validation_level,
&state->r.out.validation);
state->ctx->status = ndr_push_struct_blob( state->ctx->status = ndr_push_struct_blob(
&tmp_blob, state, state->r.out.validation.sam3, &tmp_blob, state, state->req->out.validation.sam3,
(ndr_push_flags_fn_t)ndr_push_netr_SamInfo3); (ndr_push_flags_fn_t)ndr_push_netr_SamInfo3);
if (!composite_is_ok(state->ctx)) return; if (!composite_is_ok(state->ctx)) return;
@ -220,25 +152,7 @@ static void pam_auth_crap_recv_samlogon(struct rpc_request *req)
SIVAL(state->info3.data, 0, 1); SIVAL(state->info3.data, 0, 1);
memcpy(state->info3.data+4, tmp_blob.data, tmp_blob.length); memcpy(state->info3.data+4, tmp_blob.data, tmp_blob.length);
/* We actually only ask for level 3, and assume it above, but base = &state->req->out.validation.sam3->base;
* anyway... */
base = NULL;
switch(state->r.in.validation_level) {
case 2:
base = &state->r.out.validation.sam2->base;
break;
case 3:
base = &state->r.out.validation.sam3->base;
break;
case 6:
base = &state->r.out.validation.sam6->base;
break;
}
if (base == NULL) {
composite_error(state->ctx, NT_STATUS_INTERNAL_ERROR);
return;
}
state->user_session_key = base->key; state->user_session_key = base->key;
state->lm_key = base->LMSessKey; state->lm_key = base->LMSessKey;