From: Andrew Bartlett Date: Mon, 30 Jan 2012 11:11:41 +0000 (+1100) Subject: s3-auth Hook checking passwords and generating session_info via the auth4_context X-Git-Tag: samba-4.0.0alpha18~125 X-Git-Url: http://git.samba.org/?p=samba.git;a=commitdiff_plain;h=8adde1b46b49011298e77f44a2053d0ec735a306 s3-auth Hook checking passwords and generating session_info via the auth4_context This avoids creating a second auth_context, as it is a private pointer in the auth4_context that has already been passed in, and makes the gensec_ntlmssp code agnostic to the type of authentication backend behind it. This will in turn allow the ntlmssp server code to be further merged. Andrew Bartlett Signed-off-by: Stefan Metzmacher --- diff --git a/auth/ntlmssp/ntlmssp.h b/auth/ntlmssp/ntlmssp.h index 54d3e53526a..2fed2b1f510 100644 --- a/auth/ntlmssp/ntlmssp.h +++ b/auth/ntlmssp/ntlmssp.h @@ -32,9 +32,6 @@ struct gensec_security; struct ntlmssp_state; struct gensec_ntlmssp_context { - /* used only by s3 server implementation */ - struct auth_context *auth_context; - /* For GENSEC users */ struct gensec_security *gensec_security; void *server_returned_info; diff --git a/source3/auth/auth_generic.c b/source3/auth/auth_generic.c index ca5a2afd47f..b76dcd7e8fe 100644 --- a/source3/auth/auth_generic.c +++ b/source3/auth/auth_generic.c @@ -190,6 +190,12 @@ NTSTATUS auth_generic_prepare(TALLOC_CTX *mem_ctx, return NT_STATUS_NO_MEMORY; } auth4_context->generate_session_info_pac = auth3_generate_session_info_pac; + auth4_context->generate_session_info = auth3_generate_session_info; + auth4_context->get_challenge = auth3_get_challenge; + auth4_context->set_challenge = auth3_set_challenge; + auth4_context->challenge_may_be_modified = auth3_may_set_challenge; + auth4_context->check_password = auth3_check_password; + auth4_context->private_data = talloc_steal(auth4_context, auth_context); lp_ctx = loadparm_init_s3(tmp_ctx, loadparm_s3_context()); if (lp_ctx == NULL) { diff --git a/source3/auth/auth_ntlmssp.c b/source3/auth/auth_ntlmssp.c index b5935e6b282..3e809a7a215 100644 --- a/source3/auth/auth_ntlmssp.c +++ b/source3/auth/auth_ntlmssp.c @@ -4,7 +4,8 @@ handle NLTMSSP, server side Copyright (C) Andrew Tridgell 2001 - Copyright (C) Andrew Bartlett 2001-2003,2011 + Copyright (C) Andrew Bartlett 2001-2005,2011 + Copyright (C) Stefan Metzmacher 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 @@ -30,21 +31,21 @@ #include "librpc/rpc/dcerpc.h" #include "lib/param/param.h" -static NTSTATUS gensec_ntlmssp3_server_session_info(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - struct auth_session_info **session_info) +NTSTATUS auth3_generate_session_info(TALLOC_CTX *mem_ctx, + struct auth4_context *auth_context, + void *server_returned_info, + const char *original_user_name, + uint32_t session_info_flags, + struct auth_session_info **session_info) { - struct gensec_ntlmssp_context *gensec_ntlmssp = - talloc_get_type_abort(gensec_security->private_data, - struct gensec_ntlmssp_context); - struct auth_serversupplied_info *server_info = talloc_get_type_abort(gensec_ntlmssp->server_returned_info, + struct auth_serversupplied_info *server_info = talloc_get_type_abort(server_returned_info, struct auth_serversupplied_info); NTSTATUS nt_status; nt_status = create_local_token(mem_ctx, server_info, - &gensec_ntlmssp->ntlmssp_state->session_key, - gensec_ntlmssp->ntlmssp_state->user, + NULL, + original_user_name, session_info); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(10, ("create_local_token failed: %s\n", @@ -80,13 +81,12 @@ static NTSTATUS gensec_ntlmssp3_server_update(struct gensec_security *gensec_sec * @return an 8 byte random challenge */ -static NTSTATUS auth_ntlmssp_get_challenge(const struct ntlmssp_state *ntlmssp_state, +NTSTATUS auth3_get_challenge(struct auth4_context *auth4_context, uint8_t chal[8]) { - struct gensec_ntlmssp_context *gensec_ntlmssp = - (struct gensec_ntlmssp_context *)ntlmssp_state->callback_private; - gensec_ntlmssp->auth_context->get_ntlm_challenge( - gensec_ntlmssp->auth_context, chal); + struct auth_context *auth_context = talloc_get_type_abort(auth4_context->private_data, + struct auth_context); + auth_context->get_ntlm_challenge(auth_context, chal); return NT_STATUS_OK; } @@ -95,12 +95,10 @@ static NTSTATUS auth_ntlmssp_get_challenge(const struct ntlmssp_state *ntlmssp_s * * @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) +bool auth3_may_set_challenge(struct auth4_context *auth4_context) { - struct gensec_ntlmssp_context *gensec_ntlmssp = - (struct gensec_ntlmssp_context *)ntlmssp_state->callback_private; - struct auth_context *auth_context = gensec_ntlmssp->auth_context; - + struct auth_context *auth_context = talloc_get_type_abort(auth4_context->private_data, + struct auth_context); return auth_context->challenge_may_be_modified; } @@ -108,18 +106,18 @@ static bool auth_ntlmssp_may_set_challenge(const struct ntlmssp_state *ntlmssp_s * 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) +NTSTATUS auth3_set_challenge(struct auth4_context *auth4_context, const uint8_t *chal, + const char *challenge_set_by) { - struct gensec_ntlmssp_context *gensec_ntlmssp = - (struct gensec_ntlmssp_context *)ntlmssp_state->callback_private; - struct auth_context *auth_context = gensec_ntlmssp->auth_context; - - SMB_ASSERT(challenge->length == 8); + struct auth_context *auth_context = talloc_get_type_abort(auth4_context->private_data, + struct auth_context); auth_context->challenge = data_blob_talloc(auth_context, - challenge->data, challenge->length); + chal, 8); + NT_STATUS_HAVE_NO_MEMORY(auth_context->challenge.data); - auth_context->challenge_set_by = "NTLMSSP callback (NTLM2)"; + auth_context->challenge_set_by = talloc_strdup(auth_context, challenge_set_by); + NT_STATUS_HAVE_NO_MEMORY(auth_context->challenge_set_by); DEBUG(5, ("auth_context challenge set by %s\n", auth_context->challenge_set_by)); DEBUG(5, ("challenge is: \n")); @@ -133,12 +131,15 @@ static NTSTATUS auth_ntlmssp_set_challenge(struct ntlmssp_state *ntlmssp_state, * 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 *session_key, DATA_BLOB *lm_session_key) +NTSTATUS auth3_check_password(struct auth4_context *auth4_context, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info, + void **server_returned_info, + DATA_BLOB *session_key, DATA_BLOB *lm_session_key) { - struct gensec_ntlmssp_context *gensec_ntlmssp = - (struct gensec_ntlmssp_context *)ntlmssp_state->callback_private; - struct auth_usersupplied_info *user_info = NULL; + struct auth_context *auth_context = talloc_get_type_abort(auth4_context->private_data, + struct auth_context); + struct auth_usersupplied_info *mapped_user_info = NULL; struct auth_serversupplied_info *server_info; NTSTATUS nt_status; bool username_was_mapped; @@ -146,21 +147,21 @@ static NTSTATUS auth_ntlmssp_check_password(struct ntlmssp_state *ntlmssp_state, /* The client has given us its machine name (which we only get over NBT transport). We need to possibly reload smb.conf if smb.conf includes depend on the machine name. */ - set_remote_machine_name(gensec_ntlmssp->ntlmssp_state->client.netbios_name, True); + set_remote_machine_name(user_info->workstation_name, True); /* setup the string used by %U */ /* sub_set_smb_name checks for weird internally */ - sub_set_smb_name(gensec_ntlmssp->ntlmssp_state->user); + sub_set_smb_name(user_info->client.account_name); lp_load(get_dyn_CONFIGFILE(), false, false, true, true); - nt_status = make_user_info_map(&user_info, - gensec_ntlmssp->ntlmssp_state->user, - gensec_ntlmssp->ntlmssp_state->domain, - gensec_ntlmssp->ntlmssp_state->client.netbios_name, - gensec_get_remote_address(gensec_ntlmssp->gensec_security), - gensec_ntlmssp->ntlmssp_state->lm_resp.data ? &gensec_ntlmssp->ntlmssp_state->lm_resp : NULL, - gensec_ntlmssp->ntlmssp_state->nt_resp.data ? &gensec_ntlmssp->ntlmssp_state->nt_resp : NULL, + nt_status = make_user_info_map(&mapped_user_info, + user_info->client.account_name, + user_info->client.domain_name, + user_info->workstation_name, + user_info->remote_host, + user_info->password.response.lanman.data ? &user_info->password.response.lanman : NULL, + user_info->password.response.nt.data ? &user_info->password.response.nt : NULL, NULL, NULL, NULL, AUTH_PASSWORD_RESPONSE); @@ -168,21 +169,23 @@ static NTSTATUS auth_ntlmssp_check_password(struct ntlmssp_state *ntlmssp_state, return nt_status; } - user_info->logon_parameters = MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT; + mapped_user_info->logon_parameters = user_info->logon_parameters; - nt_status = gensec_ntlmssp->auth_context->check_ntlm_password(gensec_ntlmssp->auth_context, - user_info, &server_info); + mapped_user_info->flags = user_info->flags; - username_was_mapped = user_info->was_mapped; + nt_status = auth_context->check_ntlm_password(auth_context, + mapped_user_info, &server_info); - free_user_info(&user_info); + username_was_mapped = mapped_user_info->was_mapped; + + free_user_info(&mapped_user_info); if (!NT_STATUS_IS_OK(nt_status)) { nt_status = do_map_to_guest_server_info(nt_status, &server_info, - gensec_ntlmssp->ntlmssp_state->user, - gensec_ntlmssp->ntlmssp_state->domain); - gensec_ntlmssp->server_returned_info = server_info; + user_info->client.account_name, + user_info->client.domain_name); + *server_returned_info = talloc_steal(mem_ctx, server_info); return nt_status; } @@ -192,21 +195,194 @@ static NTSTATUS auth_ntlmssp_check_password(struct ntlmssp_state *ntlmssp_state, * They will not be used in this form again - instead the * NTLMSSP code will decide on the final correct session key, * and supply it to create_local_token() */ - if (server_info->session_key.length) { + if (session_key) { DEBUG(10, ("Got NT session key of length %u\n", (unsigned int)server_info->session_key.length)); *session_key = server_info->session_key; talloc_steal(mem_ctx, server_info->session_key.data); server_info->session_key = data_blob_null; } - if (server_info->lm_session_key.length) { + if (lm_session_key) { DEBUG(10, ("Got LM session key of length %u\n", (unsigned int)server_info->lm_session_key.length)); *lm_session_key = server_info->lm_session_key; talloc_steal(mem_ctx, server_info->lm_session_key.data); server_info->lm_session_key = data_blob_null; } - gensec_ntlmssp->server_returned_info = server_info; + + *server_returned_info = talloc_steal(mem_ctx, server_info); + return nt_status; +} + +/** + * 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_challenge) { + status = auth_context->get_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_challenge) { + nt_status = auth_context->set_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_password) { + nt_status = auth_context->check_password(auth_context, + gensec_ntlmssp, + user_info, + &gensec_ntlmssp->server_returned_info, + user_session_key, lm_session_key); + } + talloc_free(user_info); + 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. + * + * Only valid after a successful authentication + * + * May only be called once per authentication. + * + */ + +static NTSTATUS gensec_ntlmssp3_server_session_info(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + struct auth_session_info **session_info) +{ + NTSTATUS nt_status; + struct gensec_ntlmssp_context *gensec_ntlmssp = + talloc_get_type_abort(gensec_security->private_data, + struct gensec_ntlmssp_context); + uint32_t session_info_flags = 0; + + if (gensec_security->want_features & GENSEC_FEATURE_UNIX_TOKEN) { + session_info_flags |= AUTH_SESSION_INFO_UNIX_TOKEN; + } + + session_info_flags |= AUTH_SESSION_INFO_DEFAULT_GROUPS; + + if (gensec_security->auth_context && gensec_security->auth_context->generate_session_info) { + nt_status = gensec_security->auth_context->generate_session_info(mem_ctx, gensec_security->auth_context, + gensec_ntlmssp->server_returned_info, + gensec_ntlmssp->ntlmssp_state->user, + session_info_flags, + session_info); + } else { + DEBUG(0, ("Cannot generate a session_info without the auth_context\n")); + return NT_STATUS_INTERNAL_ERROR; + } + + NT_STATUS_NOT_OK_RETURN(nt_status); + + nt_status = gensec_ntlmssp_session_key(gensec_security, *session_info, + &(*session_info)->session_key); + + if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_USER_SESSION_KEY)) { + (*session_info)->session_key = data_blob_null; + nt_status = NT_STATUS_OK; + } return nt_status; } @@ -242,11 +418,6 @@ static NTSTATUS gensec_ntlmssp3_server_start(struct gensec_security *gensec_secu talloc_get_type_abort(gensec_security->private_data, struct gensec_ntlmssp_context); - nt_status = make_auth_context_subsystem(gensec_ntlmssp, &gensec_ntlmssp->auth_context); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - nt_status = ntlmssp_server_start(gensec_ntlmssp, is_standalone, netbios_name, diff --git a/source3/auth/proto.h b/source3/auth/proto.h index 82d6018556c..bb25fedce6e 100644 --- a/source3/auth/proto.h +++ b/source3/auth/proto.h @@ -67,11 +67,33 @@ NTSTATUS auth_domain_init(void); NTSTATUS auth_netlogond_init(void); -/* The following definitions come from auth/auth_ntlmssp.c */ +/* The following definitions come from auth/auth_generic.c */ NTSTATUS auth_generic_prepare(TALLOC_CTX *mem_ctx, const struct tsocket_address *remote_address, struct gensec_security **gensec_security_out); +/* The following definitions come from auth/auth_ntlmssp.c */ + +NTSTATUS auth3_generate_session_info(TALLOC_CTX *mem_ctx, + struct auth4_context *auth_context, + void *server_returned_info, + const char *original_user_name, + uint32_t session_info_flags, + struct auth_session_info **session_info); + +NTSTATUS auth3_get_challenge(struct auth4_context *auth4_context, + uint8_t chal[8]); + +bool auth3_may_set_challenge(struct auth4_context *auth4_context); +NTSTATUS auth3_set_challenge(struct auth4_context *auth4_context, const uint8_t *chal, + const char *challenge_set_by); + +NTSTATUS auth3_check_password(struct auth4_context *auth4_context, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info, + void **server_returned_info, + DATA_BLOB *session_key, DATA_BLOB *lm_session_key); + /* The following definitions come from auth/auth_sam.c */ NTSTATUS check_sam_security(const DATA_BLOB *challenge, @@ -320,4 +342,5 @@ NTSTATUS make_session_info_krb5(TALLOC_CTX *mem_ctx, DATA_BLOB *session_key, struct auth_session_info **session_info); + #endif /* _AUTH_PROTO_H_ */