1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00

auth: Remove plugable password-check functions from gensec_ntlmssp

The auth4_context layer now provides the plugability here.

Andrew Bartlett
This commit is contained in:
Andrew Bartlett 2012-02-07 17:47:42 +11:00
parent 83810f8afa
commit 111d9f3eb2
5 changed files with 105 additions and 228 deletions

View File

@ -35,138 +35,6 @@
#include "param/param.h"
/**
* Return the challenge as determined by the authentication subsystem
* @return an 8 byte random challenge
*/
static NTSTATUS auth_ntlmssp_get_challenge(const struct ntlmssp_state *ntlmssp_state,
uint8_t chal[8])
{
struct gensec_ntlmssp_context *gensec_ntlmssp =
talloc_get_type_abort(ntlmssp_state->callback_private,
struct gensec_ntlmssp_context);
struct auth4_context *auth_context = gensec_ntlmssp->gensec_security->auth_context;
NTSTATUS status = NT_STATUS_NOT_IMPLEMENTED;
if (auth_context->get_ntlm_challenge) {
status = auth_context->get_ntlm_challenge(auth_context, chal);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("auth_ntlmssp_get_challenge: failed to get challenge: %s\n",
nt_errstr(status)));
return status;
}
}
return status;
}
/**
* Some authentication methods 'fix' the challenge, so we may not be able to set it
*
* @return If the effective challenge used by the auth subsystem may be modified
*/
static bool auth_ntlmssp_may_set_challenge(const struct ntlmssp_state *ntlmssp_state)
{
struct gensec_ntlmssp_context *gensec_ntlmssp =
talloc_get_type_abort(ntlmssp_state->callback_private,
struct gensec_ntlmssp_context);
struct auth4_context *auth_context = gensec_ntlmssp->gensec_security->auth_context;
if (auth_context->challenge_may_be_modified) {
return auth_context->challenge_may_be_modified(auth_context);
}
return false;
}
/**
* NTLM2 authentication modifies the effective challenge,
* @param challenge The new challenge value
*/
static NTSTATUS auth_ntlmssp_set_challenge(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *challenge)
{
struct gensec_ntlmssp_context *gensec_ntlmssp =
talloc_get_type_abort(ntlmssp_state->callback_private,
struct gensec_ntlmssp_context);
struct auth4_context *auth_context = gensec_ntlmssp->gensec_security->auth_context;
NTSTATUS nt_status = NT_STATUS_NOT_IMPLEMENTED;
const uint8_t *chal;
if (challenge->length != 8) {
return NT_STATUS_INVALID_PARAMETER;
}
chal = challenge->data;
if (auth_context->set_ntlm_challenge) {
nt_status = auth_context->set_ntlm_challenge(auth_context,
chal,
"NTLMSSP callback (NTLM2)");
}
return nt_status;
}
/**
* Check the password on an NTLMSSP login.
*
* Return the session keys used on the connection.
*/
static NTSTATUS auth_ntlmssp_check_password(struct ntlmssp_state *ntlmssp_state,
TALLOC_CTX *mem_ctx,
DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
{
struct gensec_ntlmssp_context *gensec_ntlmssp =
talloc_get_type_abort(ntlmssp_state->callback_private,
struct gensec_ntlmssp_context);
struct auth4_context *auth_context = gensec_ntlmssp->gensec_security->auth_context;
NTSTATUS nt_status = NT_STATUS_NOT_IMPLEMENTED;
struct auth_usersupplied_info *user_info;
user_info = talloc_zero(ntlmssp_state, struct auth_usersupplied_info);
if (!user_info) {
return NT_STATUS_NO_MEMORY;
}
user_info->logon_parameters = MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT;
user_info->flags = 0;
user_info->mapped_state = false;
user_info->client.account_name = ntlmssp_state->user;
user_info->client.domain_name = ntlmssp_state->domain;
user_info->workstation_name = ntlmssp_state->client.netbios_name;
user_info->remote_host = gensec_get_remote_address(gensec_ntlmssp->gensec_security);
user_info->password_state = AUTH_PASSWORD_RESPONSE;
user_info->password.response.lanman = ntlmssp_state->lm_resp;
user_info->password.response.lanman.data = talloc_steal(user_info, ntlmssp_state->lm_resp.data);
user_info->password.response.nt = ntlmssp_state->nt_resp;
user_info->password.response.nt.data = talloc_steal(user_info, ntlmssp_state->nt_resp.data);
if (auth_context->check_ntlm_password) {
nt_status = auth_context->check_ntlm_password(auth_context,
gensec_ntlmssp,
user_info,
&gensec_ntlmssp->server_returned_info,
user_session_key, lm_session_key);
}
talloc_free(user_info);
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(5,("%s: Checking NTLMSSP password for %s\\%s failed: %s\n",
__location__,
user_info->client.domain_name,
user_info->client.account_name,
nt_errstr(nt_status)));
}
NT_STATUS_NOT_OK_RETURN(nt_status);
talloc_steal(mem_ctx, user_session_key->data);
talloc_steal(mem_ctx, lm_session_key->data);
return nt_status;
}
/**
* Return the credentials of a logged on user, including session keys
* etc.
@ -244,8 +112,6 @@ NTSTATUS gensec_ntlmssp_server_start(struct gensec_security *gensec_security)
}
gensec_ntlmssp->ntlmssp_state = ntlmssp_state;
ntlmssp_state->callback_private = gensec_ntlmssp;
ntlmssp_state->role = NTLMSSP_SERVER;
ntlmssp_state->expected_state = NTLMSSP_NEGOTIATE;
@ -291,11 +157,6 @@ NTSTATUS gensec_ntlmssp_server_start(struct gensec_security *gensec_security)
ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL;
}
ntlmssp_state->get_challenge = auth_ntlmssp_get_challenge;
ntlmssp_state->may_set_challenge = auth_ntlmssp_may_set_challenge;
ntlmssp_state->set_challenge = auth_ntlmssp_set_challenge;
ntlmssp_state->check_password = auth_ntlmssp_check_password;
if (lpcfg_server_role(gensec_security->settings->lp_ctx) == ROLE_STANDALONE) {
ntlmssp_state->server.is_standalone = true;
} else {

View File

@ -62,17 +62,14 @@ static const struct ntlmssp_callbacks {
};
static NTSTATUS gensec_ntlmssp_update_find(struct ntlmssp_state *ntlmssp_state,
static NTSTATUS gensec_ntlmssp_update_find(struct gensec_ntlmssp_context *gensec_ntlmssp,
const DATA_BLOB input, uint32_t *idx)
{
struct gensec_ntlmssp_context *gensec_ntlmssp =
talloc_get_type_abort(ntlmssp_state->callback_private,
struct gensec_ntlmssp_context);
struct gensec_security *gensec_security = gensec_ntlmssp->gensec_security;
uint32_t ntlmssp_command;
uint32_t i;
if (ntlmssp_state->expected_state == NTLMSSP_DONE) {
if (gensec_ntlmssp->ntlmssp_state->expected_state == NTLMSSP_DONE) {
/* We are strict here because other modules, which we
* don't fully control (such as GSSAPI) are also
* strict, but are tested less often */
@ -82,7 +79,7 @@ static NTSTATUS gensec_ntlmssp_update_find(struct ntlmssp_state *ntlmssp_state,
}
if (!input.length) {
switch (ntlmssp_state->role) {
switch (gensec_ntlmssp->ntlmssp_state->role) {
case NTLMSSP_CLIENT:
ntlmssp_command = NTLMSSP_INITIAL;
break;
@ -98,7 +95,7 @@ static NTSTATUS gensec_ntlmssp_update_find(struct ntlmssp_state *ntlmssp_state,
break;
}
} else {
if (!msrpc_parse(ntlmssp_state,
if (!msrpc_parse(gensec_ntlmssp->ntlmssp_state,
&input, "Cd",
"NTLMSSP",
&ntlmssp_command)) {
@ -108,13 +105,14 @@ static NTSTATUS gensec_ntlmssp_update_find(struct ntlmssp_state *ntlmssp_state,
}
}
if (ntlmssp_command != ntlmssp_state->expected_state) {
DEBUG(2, ("got NTLMSSP command %u, expected %u\n", ntlmssp_command, ntlmssp_state->expected_state));
if (ntlmssp_command != gensec_ntlmssp->ntlmssp_state->expected_state) {
DEBUG(2, ("got NTLMSSP command %u, expected %u\n", ntlmssp_command,
gensec_ntlmssp->ntlmssp_state->expected_state));
return NT_STATUS_INVALID_PARAMETER;
}
for (i=0; i < ARRAY_SIZE(ntlmssp_callbacks); i++) {
if (ntlmssp_callbacks[i].role == ntlmssp_state->role &&
if (ntlmssp_callbacks[i].role == gensec_ntlmssp->ntlmssp_state->role &&
ntlmssp_callbacks[i].command == ntlmssp_command) {
*idx = i;
return NT_STATUS_OK;
@ -122,7 +120,7 @@ static NTSTATUS gensec_ntlmssp_update_find(struct ntlmssp_state *ntlmssp_state,
}
DEBUG(1, ("failed to find NTLMSSP callback for NTLMSSP mode %u, command %u\n",
ntlmssp_state->role, ntlmssp_command));
gensec_ntlmssp->ntlmssp_state->role, ntlmssp_command));
return NT_STATUS_INVALID_PARAMETER;
}
@ -158,7 +156,7 @@ NTSTATUS gensec_ntlmssp_update(struct gensec_security *gensec_security,
out_mem_ctx = ntlmssp_state;
}
status = gensec_ntlmssp_update_find(ntlmssp_state, input, &i);
status = gensec_ntlmssp_update_find(gensec_ntlmssp, input, &i);
NT_STATUS_NOT_OK_RETURN(status);
status = ntlmssp_callbacks[i].sync_fn(gensec_security, out_mem_ctx, input, out);

View File

@ -92,58 +92,6 @@ struct ntlmssp_state
uint32_t neg_flags; /* the current state of negotiation with the NTLMSSP partner */
/**
* Private data for the callback functions
*/
void *callback_private;
/**
* Callback to get the 'challenge' used for NTLM authentication.
*
* @param ntlmssp_state This structure
* @return 8 bytes of challenge data, determined by the server to be the challenge for NTLM authentication
*
*/
NTSTATUS (*get_challenge)(const struct ntlmssp_state *ntlmssp_state,
uint8_t challenge[8]);
/**
* Callback to find if the challenge used by NTLM authentication may be modified
*
* The NTLM2 authentication scheme modifies the effective challenge, but this is not compatiable with the
* current 'security=server' implementation..
*
* @param ntlmssp_state This structure
* @return Can the challenge be set to arbitary values?
*
*/
bool (*may_set_challenge)(const struct ntlmssp_state *ntlmssp_state);
/**
* Callback to set the 'challenge' used for NTLM authentication.
*
* The callback may use the void *auth_context to store state information, but the same value is always available
* from the DATA_BLOB chal on this structure.
*
* @param ntlmssp_state This structure
* @param challenge 8 bytes of data, agreed by the client and server to be the effective challenge for NTLM2 authentication
*
*/
NTSTATUS (*set_challenge)(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *challenge);
/**
* Callback to check the user's password.
*
* The callback must reads the feilds of this structure for the information it needs on the user
* @param ntlmssp_state This structure
* @param mem_ctx Talloc context for LM and NT session key to be returned on
* @param nt_session_key If an NT session key is returned by the authentication process, return it here
* @param lm_session_key If an LM session key is returned by the authentication process, return it here
*
*/
NTSTATUS (*check_password)(struct ntlmssp_state *ntlmssp_state, TALLOC_CTX *mem_ctx,
DATA_BLOB *nt_session_key, DATA_BLOB *lm_session_key);
union ntlmssp_crypt_state *crypt;
};

View File

@ -317,12 +317,6 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
talloc_steal(out_mem_ctx, out->data);
ntlmssp_state->chal = challenge_blob;
ntlmssp_state->lm_resp = lm_response;
talloc_steal(ntlmssp_state->lm_resp.data, lm_response.data);
ntlmssp_state->nt_resp = nt_response;
talloc_steal(ntlmssp_state->nt_resp.data, nt_response.data);
ntlmssp_state->expected_state = NTLMSSP_DONE;
if (gensec_security->want_features & (GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL)) {
@ -358,8 +352,6 @@ NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security)
return NT_STATUS_NO_MEMORY;
}
ntlmssp_state->callback_private = gensec_ntlmssp;
gensec_ntlmssp->ntlmssp_state = ntlmssp_state;
ntlmssp_state = gensec_ntlmssp->ntlmssp_state;

View File

@ -28,6 +28,7 @@
#include "../libcli/auth/libcli_auth.h"
#include "../lib/crypto/crypto.h"
#include "auth/gensec/gensec.h"
#include "auth/common_auth.h"
/**
* Determine correct target name flags for reply, given server role
@ -75,6 +76,7 @@ NTSTATUS gensec_ntlmssp_server_negotiate(struct gensec_security *gensec_security
talloc_get_type_abort(gensec_security->private_data,
struct gensec_ntlmssp_context);
struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp->ntlmssp_state;
struct auth4_context *auth_context = gensec_security->auth_context;
DATA_BLOB struct_blob;
uint32_t neg_flags = 0;
uint32_t ntlmssp_command, chal_flags;
@ -117,16 +119,23 @@ NTSTATUS gensec_ntlmssp_server_negotiate(struct gensec_security *gensec_security
ntlmssp_handle_neg_flags(ntlmssp_state, neg_flags, ntlmssp_state->allow_lm_key);
/* Ask our caller what challenge they would like in the packet */
status = ntlmssp_state->get_challenge(ntlmssp_state, cryptkey);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("ntlmssp_server_negotiate: backend doesn't give a challenge: %s\n",
nt_errstr(status)));
return status;
if (auth_context->get_ntlm_challenge) {
status = auth_context->get_ntlm_challenge(auth_context, cryptkey);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("gensec_ntlmssp_server_negotiate: failed to get challenge: %s\n",
nt_errstr(status)));
return status;
}
} else {
DEBUG(1, ("gensec_ntlmssp_server_negotiate: backend doesn't give a challenge\n"));
return NT_STATUS_NOT_IMPLEMENTED;
}
/* Check if we may set the challenge */
if (!ntlmssp_state->may_set_challenge(ntlmssp_state)) {
ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
if (auth_context->challenge_may_be_modified) {
if (!auth_context->challenge_may_be_modified(auth_context)) {
ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
}
}
/* The flags we send back are not just the negotiated flags,
@ -254,10 +263,13 @@ struct ntlmssp_server_auth_state {
* @return Errors or NT_STATUS_OK.
*/
static NTSTATUS ntlmssp_server_preauth(struct ntlmssp_state *ntlmssp_state,
static NTSTATUS ntlmssp_server_preauth(struct gensec_security *gensec_security,
struct gensec_ntlmssp_context *gensec_ntlmssp,
struct ntlmssp_server_auth_state *state,
const DATA_BLOB request)
{
struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp->ntlmssp_state;
struct auth4_context *auth_context = gensec_security->auth_context;
uint32_t ntlmssp_command, auth_flags;
NTSTATUS nt_status;
@ -376,15 +388,23 @@ static NTSTATUS ntlmssp_server_preauth(struct ntlmssp_state *ntlmssp_state,
MD5Update(&md5_session_nonce_ctx, state->session_nonce, 16);
MD5Final(session_nonce_hash, &md5_session_nonce_ctx);
ntlmssp_state->chal = data_blob_talloc(
ntlmssp_state, session_nonce_hash, 8);
/* LM response is no longer useful */
data_blob_free(&ntlmssp_state->lm_resp);
/* We changed the effective challenge - set it */
if (!NT_STATUS_IS_OK(nt_status = ntlmssp_state->set_challenge(ntlmssp_state, &ntlmssp_state->chal))) {
return nt_status;
if (auth_context->set_ntlm_challenge) {
nt_status = auth_context->set_ntlm_challenge(auth_context,
session_nonce_hash,
"NTLMSSP callback (NTLM2)");
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(1, ("gensec_ntlmssp_server_negotiate: failed to get challenge: %s\n",
nt_errstr(nt_status)));
return nt_status;
}
} else {
DEBUG(1, ("gensec_ntlmssp_server_negotiate: backend doesn't have facility for challenge to be set\n"));
return NT_STATUS_NOT_IMPLEMENTED;
}
/* LM Key is incompatible. */
@ -394,6 +414,62 @@ static NTSTATUS ntlmssp_server_preauth(struct ntlmssp_state *ntlmssp_state,
return NT_STATUS_OK;
}
/**
* Check the password on an NTLMSSP login.
*
* Return the session keys used on the connection.
*/
static NTSTATUS ntlmssp_server_check_password(struct gensec_security *gensec_security,
struct gensec_ntlmssp_context *gensec_ntlmssp,
TALLOC_CTX *mem_ctx,
DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
{
struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp->ntlmssp_state;
struct auth4_context *auth_context = gensec_ntlmssp->gensec_security->auth_context;
NTSTATUS nt_status = NT_STATUS_NOT_IMPLEMENTED;
struct auth_usersupplied_info *user_info;
user_info = talloc_zero(ntlmssp_state, struct auth_usersupplied_info);
if (!user_info) {
return NT_STATUS_NO_MEMORY;
}
user_info->logon_parameters = MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT;
user_info->flags = 0;
user_info->mapped_state = false;
user_info->client.account_name = ntlmssp_state->user;
user_info->client.domain_name = ntlmssp_state->domain;
user_info->workstation_name = ntlmssp_state->client.netbios_name;
user_info->remote_host = gensec_get_remote_address(gensec_ntlmssp->gensec_security);
user_info->password_state = AUTH_PASSWORD_RESPONSE;
user_info->password.response.lanman = ntlmssp_state->lm_resp;
user_info->password.response.lanman.data = talloc_steal(user_info, ntlmssp_state->lm_resp.data);
user_info->password.response.nt = ntlmssp_state->nt_resp;
user_info->password.response.nt.data = talloc_steal(user_info, ntlmssp_state->nt_resp.data);
if (auth_context->check_ntlm_password) {
nt_status = auth_context->check_ntlm_password(auth_context,
gensec_ntlmssp,
user_info,
&gensec_ntlmssp->server_returned_info,
user_session_key, lm_session_key);
}
talloc_free(user_info);
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(5, (__location__ ": Checking NTLMSSP password for %s\\%s failed: %s\n", user_info->client.domain_name, user_info->client.account_name, nt_errstr(nt_status)));
}
NT_STATUS_NOT_OK_RETURN(nt_status);
talloc_steal(mem_ctx, user_session_key->data);
talloc_steal(mem_ctx, lm_session_key->data);
return nt_status;
}
/**
* Next state function for the Authenticate packet
* (after authentication - figures out the session keys etc)
@ -402,9 +478,11 @@ static NTSTATUS ntlmssp_server_preauth(struct ntlmssp_state *ntlmssp_state,
* @return Errors or NT_STATUS_OK.
*/
static NTSTATUS ntlmssp_server_postauth(struct ntlmssp_state *ntlmssp_state,
static NTSTATUS ntlmssp_server_postauth(struct gensec_security *gensec_security,
struct gensec_ntlmssp_context *gensec_ntlmssp,
struct ntlmssp_server_auth_state *state)
{
struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp->ntlmssp_state;
DATA_BLOB user_session_key = state->user_session_key;
DATA_BLOB lm_session_key = state->lm_session_key;
NTSTATUS nt_status = NT_STATUS_OK;
@ -558,7 +636,7 @@ NTSTATUS gensec_ntlmssp_server_auth(struct gensec_security *gensec_security,
return NT_STATUS_NO_MEMORY;
}
nt_status = ntlmssp_server_preauth(ntlmssp_state, state, in);
nt_status = ntlmssp_server_preauth(gensec_security, gensec_ntlmssp, state, in);
if (!NT_STATUS_IS_OK(nt_status)) {
TALLOC_FREE(state);
return nt_status;
@ -572,7 +650,7 @@ NTSTATUS gensec_ntlmssp_server_auth(struct gensec_security *gensec_security,
*/
/* Finally, actually ask if the password is OK */
nt_status = ntlmssp_state->check_password(ntlmssp_state,
nt_status = ntlmssp_server_check_password(gensec_security, gensec_ntlmssp,
state,
&state->user_session_key,
&state->lm_session_key);
@ -589,7 +667,7 @@ NTSTATUS gensec_ntlmssp_server_auth(struct gensec_security *gensec_security,
ntlmssp_state->check_password, the ntlmssp_server_postpath
can be done in a callback */
nt_status = ntlmssp_server_postauth(ntlmssp_state, state);
nt_status = ntlmssp_server_postauth(gensec_security, gensec_ntlmssp, state);
TALLOC_FREE(state);
return nt_status;
}