diff options
-rw-r--r-- | source4/auth/gensec/schannel_state.c | 2 | ||||
-rw-r--r-- | source4/librpc/idl/netlogon.idl | 6 | ||||
-rw-r--r-- | source4/rpc_server/netlogon/dcerpc_netlogon.c | 132 | ||||
-rw-r--r-- | source4/torture/rpc/netlogon.c | 5 | ||||
-rw-r--r-- | source4/torture/rpc/samlogon.c | 8 | ||||
-rw-r--r-- | source4/torture/rpc/samsync.c | 2 | ||||
-rw-r--r-- | source4/torture/rpc/schannel.c | 30 | ||||
-rw-r--r-- | source4/winbind/wb_pam_auth.c | 2 |
8 files changed, 74 insertions, 113 deletions
diff --git a/source4/auth/gensec/schannel_state.c b/source4/auth/gensec/schannel_state.c index a73e450ec8..beaa8cfb08 100644 --- a/source4/auth/gensec/schannel_state.c +++ b/source4/auth/gensec/schannel_state.c @@ -175,7 +175,7 @@ NTSTATUS schannel_store_session_key(TALLOC_CTX *mem_ctx, NTSTATUS schannel_fetch_session_key_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, const char *computer_name, - const char *domain, + const char *domain, struct creds_CredentialState **creds) { struct ldb_result *res; diff --git a/source4/librpc/idl/netlogon.idl b/source4/librpc/idl/netlogon.idl index fe0a1adbe4..75d1b3316b 100644 --- a/source4/librpc/idl/netlogon.idl +++ b/source4/librpc/idl/netlogon.idl @@ -229,7 +229,7 @@ interface netlogon NTSTATUS netr_LogonSamLogon( [in] [string,charset(UTF16)] uint16 *server_name, - [in] [string,charset(UTF16)] uint16 *workstation, + [in] [string,charset(UTF16)] uint16 *computer_name, [in] netr_Authenticator *credential, [in][out] netr_Authenticator *return_authenticator, [in] uint16 logon_level, @@ -1096,7 +1096,7 @@ interface netlogon /* Function 0x27 */ NTSTATUS netr_LogonSamLogonEx( [in] [string,charset(UTF16)] uint16 *server_name, - [in] [string,charset(UTF16)] uint16 *workstation, + [in] [string,charset(UTF16)] uint16 *computer_name, [in] uint16 logon_level, [in] [switch_is(logon_level)] netr_LogonLevel logon, [in] uint16 validation_level, @@ -1175,7 +1175,7 @@ interface netlogon /* this is the ADS varient. I don't yet know what the "flags" are for */ NTSTATUS netr_LogonSamLogonWithFlags( [in] [string,charset(UTF16)] uint16 *server_name, - [in] [string,charset(UTF16)] uint16 *workstation, + [in] [string,charset(UTF16)] uint16 *computer_name, [in] netr_Authenticator *credential, [in][out] netr_Authenticator *return_authenticator, [in] uint16 logon_level, diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index 176246901b..d506d9192d 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -31,72 +31,9 @@ struct server_pipe_state { struct netr_Credential client_challenge; struct netr_Credential server_challenge; - - /* This is a bit (dangeroursly?) tricky: - - The session key, computer name and domain elements are - valid. - - However the credentials chaining (seed, client, server etc) - should be obtained from the database at runtime */ - struct creds_CredentialState *creds; }; -/* - a client has connected to the netlogon server using schannel, so we need - to re-establish the credentials state -*/ -static NTSTATUS netlogon_schannel_setup(struct dcesrv_call_state *dce_call) -{ - struct server_pipe_state *state; - NTSTATUS status; - - /* We want the client and server challenge zero */ - state = talloc_zero(dce_call->conn, struct server_pipe_state); - if (state == NULL) { - return NT_STATUS_NO_MEMORY; - } - - status = dcerpc_schannel_creds(dce_call->conn->auth_state.gensec_security, - state, - &state->creds); - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(3, ("getting schannel credentials failed with %s\n", nt_errstr(status))); - talloc_free(state); - return status; - } - - dce_call->context->private = state; - - return NT_STATUS_OK; -} - -/* - a hook for bind on the netlogon pipe -*/ -static NTSTATUS netlogon_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *di) -{ - dce_call->context->private = NULL; - - /* if this is a schannel bind then we need to reconstruct the pipe state */ - if (dce_call->conn->auth_state.auth_info && - dce_call->conn->auth_state.auth_info->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { - NTSTATUS status; - - DEBUG(5, ("schannel bind on netlogon\n")); - - status = netlogon_schannel_setup(dce_call); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(3, ("schannel bind on netlogon failed with %s\n", nt_errstr(status))); - return status; - } - } - - return NT_STATUS_OK; -} - -#define DCESRV_INTERFACE_NETLOGON_BIND netlogon_bind - static NTSTATUS netr_ServerReqChallenge(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct netr_ServerReqChallenge *r) { @@ -116,8 +53,6 @@ static NTSTATUS netr_ServerReqChallenge(struct dcesrv_call_state *dce_call, TALL return NT_STATUS_NO_MEMORY; } - pipe_state->creds = NULL; - pipe_state->client_challenge = *r->in.credentials; generate_random_buffer(pipe_state->server_challenge.data, @@ -238,12 +173,6 @@ static NTSTATUS netr_ServerAuthenticate3(struct dcesrv_call_state *dce_call, TAL /* remember this session key state */ nt_status = schannel_store_session_key(mem_ctx, creds); - if (pipe_state->creds) { - talloc_free(pipe_state->creds); - } - talloc_steal(pipe_state, creds); - pipe_state->creds = creds; - return nt_status; } @@ -302,7 +231,7 @@ static NTSTATUS netr_ServerAuthenticate2(struct dcesrv_call_state *dce_call, TAL the caller needs some of that information. */ -static NTSTATUS netr_creds_server_step_check(struct server_pipe_state *pipe_state, +static NTSTATUS netr_creds_server_step_check(const char *computer_name, TALLOC_CTX *mem_ctx, struct netr_Authenticator *received_authenticator, struct netr_Authenticator *return_authenticator, @@ -313,11 +242,6 @@ static NTSTATUS netr_creds_server_step_check(struct server_pipe_state *pipe_stat struct ldb_context *ldb; int ret; - if (!pipe_state) { - DEBUG(1, ("No challenge requested by client, cannot authenticate\n")); - return NT_STATUS_ACCESS_DENIED; - } - ldb = schannel_db_connect(mem_ctx); if (!ldb) { return NT_STATUS_ACCESS_DENIED; @@ -333,8 +257,8 @@ static NTSTATUS netr_creds_server_step_check(struct server_pipe_state *pipe_stat * disconnects) we must update the database every time we * update the structure */ - nt_status = schannel_fetch_session_key_ldb(ldb, ldb, pipe_state->creds->computer_name, - pipe_state->creds->domain, &creds); + nt_status = schannel_fetch_session_key_ldb(ldb, ldb, computer_name, lp_workgroup(), + &creds); if (NT_STATUS_IS_OK(nt_status)) { nt_status = creds_server_step_check(creds, received_authenticator, @@ -365,12 +289,11 @@ static NTSTATUS netr_creds_server_step_check(struct server_pipe_state *pipe_stat static NTSTATUS netr_ServerPasswordSet(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct netr_ServerPasswordSet *r) { - struct server_pipe_state *pipe_state = dce_call->context->private; struct creds_CredentialState *creds; struct ldb_context *sam_ctx; NTSTATUS nt_status; - nt_status = netr_creds_server_step_check(pipe_state, mem_ctx, + nt_status = netr_creds_server_step_check(r->in.computer_name, mem_ctx, &r->in.credential, &r->out.return_authenticator, &creds); NT_STATUS_NOT_OK_RETURN(nt_status); @@ -400,7 +323,6 @@ static NTSTATUS netr_ServerPasswordSet(struct dcesrv_call_state *dce_call, TALLO static NTSTATUS netr_ServerPasswordSet2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct netr_ServerPasswordSet2 *r) { - struct server_pipe_state *pipe_state = dce_call->context->private; struct creds_CredentialState *creds; struct ldb_context *sam_ctx; NTSTATUS nt_status; @@ -410,7 +332,7 @@ static NTSTATUS netr_ServerPasswordSet2(struct dcesrv_call_state *dce_call, TALL struct samr_CryptPassword password_buf; - nt_status = netr_creds_server_step_check(pipe_state, mem_ctx, + nt_status = netr_creds_server_step_check(r->in.computer_name, mem_ctx, &r->in.credential, &r->out.return_authenticator, &creds); NT_STATUS_NOT_OK_RETURN(nt_status); @@ -464,15 +386,15 @@ static WERROR netr_LogonUasLogoff(struct dcesrv_call_state *dce_call, TALLOC_CTX /* - netr_LogonSamLogonEx + netr_LogonSamLogon_base This version of the function allows other wrappers to say 'do not check the credentials' + + We can't do the traditional 'wrapping' format completly, as this function must only run under schannel */ -static NTSTATUS netr_LogonSamLogonEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct netr_LogonSamLogonEx *r) +static NTSTATUS netr_LogonSamLogon_base(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, + struct netr_LogonSamLogonEx *r, struct creds_CredentialState *creds) { - struct server_pipe_state *pipe_state = dce_call->context->private; - struct creds_CredentialState *creds = pipe_state->creds; struct auth_context *auth_context; struct auth_usersupplied_info *user_info; struct auth_serversupplied_info *server_info; @@ -496,7 +418,7 @@ static NTSTATUS netr_LogonSamLogonEx(struct dcesrv_call_state *dce_call, TALLOC_ case 1: case 3: case 5: - if (pipe_state->creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) { + if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) { creds_arcfour_crypt(creds, r->in.logon.password->lmpassword.hash, sizeof(r->in.logon.password->lmpassword.hash)); @@ -633,6 +555,23 @@ static NTSTATUS netr_LogonSamLogonEx(struct dcesrv_call_state *dce_call, TALLOC_ return NT_STATUS_OK; } +static NTSTATUS netr_LogonSamLogonEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, + struct netr_LogonSamLogonEx *r) +{ + NTSTATUS nt_status; + struct creds_CredentialState *creds; + nt_status = schannel_fetch_session_key(mem_ctx, r->in.computer_name, lp_workgroup(), &creds); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + + if (!dce_call->conn->auth_state.auth_info + || dce_call->conn->auth_state.auth_info->auth_type != DCERPC_AUTH_TYPE_SCHANNEL) { + return NT_STATUS_INTERNAL_ERROR; + } + return netr_LogonSamLogon_base(dce_call, mem_ctx, r, creds); +} + /* netr_LogonSamLogonWithFlags @@ -640,8 +579,8 @@ static NTSTATUS netr_LogonSamLogonEx(struct dcesrv_call_state *dce_call, TALLOC_ static NTSTATUS netr_LogonSamLogonWithFlags(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct netr_LogonSamLogonWithFlags *r) { - struct server_pipe_state *pipe_state = dce_call->context->private; NTSTATUS nt_status; + struct creds_CredentialState *creds; struct netr_LogonSamLogonEx r2; struct netr_Authenticator *return_authenticator; @@ -649,21 +588,21 @@ static NTSTATUS netr_LogonSamLogonWithFlags(struct dcesrv_call_state *dce_call, return_authenticator = talloc(mem_ctx, struct netr_Authenticator); NT_STATUS_HAVE_NO_MEMORY(return_authenticator); - nt_status = netr_creds_server_step_check(pipe_state, mem_ctx, + nt_status = netr_creds_server_step_check(r->in.computer_name, mem_ctx, r->in.credential, return_authenticator, - NULL); + &creds); NT_STATUS_NOT_OK_RETURN(nt_status); ZERO_STRUCT(r2); r2.in.server_name = r->in.server_name; - r2.in.workstation = r->in.workstation; + r2.in.computer_name = r->in.computer_name; r2.in.logon_level = r->in.logon_level; r2.in.logon = r->in.logon; r2.in.validation_level = r->in.validation_level; r2.in.flags = r->in.flags; - nt_status = netr_LogonSamLogonEx(dce_call, mem_ctx, &r2); + nt_status = netr_LogonSamLogon_base(dce_call, mem_ctx, &r2, creds); r->out.return_authenticator = return_authenticator; r->out.validation = r2.out.validation; @@ -685,7 +624,7 @@ static NTSTATUS netr_LogonSamLogon(struct dcesrv_call_state *dce_call, TALLOC_CT ZERO_STRUCT(r2); r2.in.server_name = r->in.server_name; - r2.in.workstation = r->in.workstation; + r2.in.computer_name = r->in.computer_name; r2.in.credential = r->in.credential; r2.in.return_authenticator = r->in.return_authenticator; r2.in.logon_level = r->in.logon_level; @@ -947,7 +886,6 @@ static NTSTATUS fill_domain_trust_info(TALLOC_CTX *mem_ctx, struct ldb_message * static NTSTATUS netr_LogonGetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct netr_LogonGetDomainInfo *r) { - struct server_pipe_state *pipe_state = dce_call->context->private; const char * const attrs[] = { "dnsDomain", "objectSid", "objectGUID", "flatName", "securityIdentifier", NULL }; @@ -960,7 +898,7 @@ static NTSTATUS netr_LogonGetDomainInfo(struct dcesrv_call_state *dce_call, TALL const char *local_domain; - status = netr_creds_server_step_check(pipe_state, mem_ctx, + status = netr_creds_server_step_check(r->in.computer_name, mem_ctx, r->in.credential, r->out.return_authenticator, NULL); diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c index 7919e7c441..79e85cce57 100644 --- a/source4/torture/rpc/netlogon.c +++ b/source4/torture/rpc/netlogon.c @@ -539,7 +539,7 @@ BOOL test_netlogon_ops(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, ninfo.identity_info.workstation.string = cli_credentials_get_workstation(credentials); r.in.server_name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p)); - r.in.workstation = cli_credentials_get_workstation(credentials); + r.in.computer_name = cli_credentials_get_workstation(credentials); r.in.credential = &auth; r.in.return_authenticator = &auth2; r.in.logon_level = 2; @@ -564,7 +564,6 @@ BOOL test_netlogon_ops(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, printf("Credential chaining failed\n"); ret = False; } - } r.in.credential = NULL; @@ -573,7 +572,7 @@ BOOL test_netlogon_ops(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, r.in.validation_level = i; - printf("Testing SamLogon with validation level %d\n", i); + printf("Testing SamLogon with validation level %d and a NULL credential\n", i); status = dcerpc_netr_LogonSamLogon(p, mem_ctx, &r); if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) { diff --git a/source4/torture/rpc/samlogon.c b/source4/torture/rpc/samlogon.c index 69c9ff6ea9..03bec56ab6 100644 --- a/source4/torture/rpc/samlogon.c +++ b/source4/torture/rpc/samlogon.c @@ -1335,17 +1335,17 @@ static BOOL test_SamLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, generate_random_buffer(samlogon_state.chall.data, 8); samlogon_state.r_flags.in.server_name = talloc_asprintf(fn_ctx, "\\\\%s", dcerpc_server_name(p)); - samlogon_state.r_flags.in.workstation = TEST_MACHINE_NAME; + samlogon_state.r_flags.in.computer_name = TEST_MACHINE_NAME; samlogon_state.r_flags.in.credential = &samlogon_state.auth; samlogon_state.r_flags.in.return_authenticator = &samlogon_state.auth2; samlogon_state.r_flags.in.flags = 0; samlogon_state.r_ex.in.server_name = talloc_asprintf(fn_ctx, "\\\\%s", dcerpc_server_name(p)); - samlogon_state.r_ex.in.workstation = TEST_MACHINE_NAME; + samlogon_state.r_ex.in.computer_name = TEST_MACHINE_NAME; samlogon_state.r_ex.in.flags = 0; samlogon_state.r.in.server_name = talloc_asprintf(fn_ctx, "\\\\%s", dcerpc_server_name(p)); - samlogon_state.r.in.workstation = TEST_MACHINE_NAME; + samlogon_state.r.in.computer_name = TEST_MACHINE_NAME; samlogon_state.r.in.credential = &samlogon_state.auth; samlogon_state.r.in.return_authenticator = &samlogon_state.auth2; @@ -1415,7 +1415,7 @@ BOOL test_InteractiveLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, creds_client_authenticator(creds, &a); r.in.server_name = talloc_asprintf(fn_ctx, "\\\\%s", dcerpc_server_name(p)); - r.in.workstation = TEST_MACHINE_NAME; + r.in.computer_name = TEST_MACHINE_NAME; r.in.credential = &a; r.in.return_authenticator = &ra; r.in.logon_level = 5; diff --git a/source4/torture/rpc/samsync.c b/source4/torture/rpc/samsync.c index afa47e5932..f0f19f0818 100644 --- a/source4/torture/rpc/samsync.c +++ b/source4/torture/rpc/samsync.c @@ -77,7 +77,7 @@ static NTSTATUS test_SamLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, } r.in.server_name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p)); - r.in.workstation = workstation; + r.in.computer_name = workstation; r.in.credential = &auth; r.in.return_authenticator = &auth2; r.in.logon_level = 2; diff --git a/source4/torture/rpc/schannel.c b/source4/torture/rpc/schannel.c index 80b223656d..3ad781c145 100644 --- a/source4/torture/rpc/schannel.c +++ b/source4/torture/rpc/schannel.c @@ -85,7 +85,7 @@ BOOL test_netlogon_ex_ops(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, ninfo.identity_info.workstation.string = cli_credentials_get_workstation(credentials); r.in.server_name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p)); - r.in.workstation = cli_credentials_get_workstation(credentials); + r.in.computer_name = cli_credentials_get_workstation(credentials); r.in.logon_level = 2; r.in.logon.network = &ninfo; r.in.flags = 0; @@ -238,6 +238,7 @@ static BOOL test_schannel(TALLOC_CTX *mem_ctx, struct dcerpc_pipe *p = NULL; struct dcerpc_pipe *p_netlogon = NULL; struct dcerpc_pipe *p_netlogon2 = NULL; + struct dcerpc_pipe *p_netlogon3 = NULL; struct dcerpc_pipe *p_samr2 = NULL; struct dcerpc_pipe *p_lsa = NULL; struct creds_CredentialState *creds; @@ -395,14 +396,37 @@ static BOOL test_schannel(TALLOC_CTX *mem_ctx, /* Try the schannel-only SamLogonEx operation */ if (!test_netlogon_ex_ops(p_netlogon2, test_ctx, credentials, creds)) { - printf("Failed to process schannel secured NETLOGON EX ops\n"); + printf("Failed to process schannel secured NETLOGON EX ops (on fresh connection)\n"); ret = False; } /* And the more traditional style, proving that the * credentials chaining state is fully present */ if (!test_netlogon_ops(p_netlogon2, test_ctx, credentials, creds)) { - printf("Failed to process schannel secured NETLOGON EX ops\n"); + printf("Failed to process schannel secured NETLOGON ops (on fresh connection)\n"); + ret = False; + } + + /* Drop the socket, we want to start from scratch (again) */ + talloc_free(p_samr2); + + /* We don't want schannel for this test */ + b->flags &= ~DCERPC_AUTH_OPTIONS; + + status = dcerpc_pipe_connect_b(test_ctx, &p_netlogon3, b, &dcerpc_table_netlogon, + credentials, NULL); + if (!NT_STATUS_IS_OK(status)) { + printf("Failed to connect without schannel: %s\n", nt_errstr(status)); + goto failed; + } + + if (test_netlogon_ex_ops(p_netlogon3, test_ctx, credentials, creds)) { + printf("Processed NOT schannel secured NETLOGON EX ops without SCHANNEL (unsafe)\n"); + ret = False; + } + + if (!test_netlogon_ops(p_netlogon3, test_ctx, credentials, creds)) { + printf("Failed to processed NOT schannel secured NETLOGON ops without new ServerAuth\n"); ret = False; } diff --git a/source4/winbind/wb_pam_auth.c b/source4/winbind/wb_pam_auth.c index 593cd22291..f85cfd1f1a 100644 --- a/source4/winbind/wb_pam_auth.c +++ b/source4/winbind/wb_pam_auth.c @@ -153,7 +153,7 @@ static void pam_auth_crap_recv_domain(struct composite_context *ctx) ZERO_STRUCT(state->auth2); - state->r.in.workstation = + 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; |