handle NLTMSSP, server side
Copyright (C) Andrew Tridgell 2001
- Copyright (C) Andrew Bartlett 2001-2003
+ 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
#include "includes.h"
#include "auth.h"
-#include "../libcli/auth/ntlmssp.h"
-#include "ntlmssp_wrap.h"
-#include "../librpc/gen_ndr/netlogon.h"
-#include "../lib/tsocket/tsocket.h"
-#include "auth/gensec/gensec.h"
-
-NTSTATUS auth_ntlmssp_session_info(TALLOC_CTX *mem_ctx,
- struct auth_ntlmssp_state *auth_ntlmssp_state,
- struct auth_session_info **session_info)
+#include "libcli/security/security.h"
+
+NTSTATUS auth3_generate_session_info(struct auth4_context *auth_context,
+ TALLOC_CTX *mem_ctx,
+ void *server_returned_info,
+ const char *original_user_name,
+ uint32_t session_info_flags,
+ struct auth_session_info **session_info)
{
+ struct auth_user_info_dc *user_info = NULL;
+ struct auth_serversupplied_info *server_info = NULL;
NTSTATUS nt_status;
- if (auth_ntlmssp_state->gensec_security) {
- nt_status = gensec_session_info(auth_ntlmssp_state->gensec_security,
- mem_ctx,
- session_info);
- return nt_status;
+ /*
+ * This is a hack, some callers...
+ *
+ * Some callers pass auth_user_info_dc, the SCHANNEL and
+ * NCALRPC_AS_SYSTEM gensec modules.
+ *
+ * While the reset passes auth3_check_password() returned.
+ */
+ user_info = talloc_get_type(server_returned_info,
+ struct auth_user_info_dc);
+ if (user_info != NULL) {
+ const struct dom_sid *sid;
+ int cmp;
+
+ /*
+ * This should only be called from SCHANNEL or NCALRPC_AS_SYSTEM
+ */
+ if (user_info->num_sids != 1) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ sid = &user_info->sids[PRIMARY_USER_SID_INDEX];
+
+ cmp = dom_sid_compare(sid, &global_sid_System);
+ if (cmp == 0) {
+ return make_session_info_system(mem_ctx, session_info);
+ }
+
+ cmp = dom_sid_compare(sid, &global_sid_Anonymous);
+ if (cmp == 0) {
+ return make_session_info_anonymous(mem_ctx, session_info);
+ }
+
+ return NT_STATUS_INTERNAL_ERROR;
}
+ server_info = talloc_get_type_abort(server_returned_info,
+ struct auth_serversupplied_info);
nt_status = create_local_token(mem_ctx,
- auth_ntlmssp_state->server_info,
- &auth_ntlmssp_state->ntlmssp_state->session_key,
- auth_ntlmssp_state->ntlmssp_state->user,
+ server_info,
+ NULL,
+ original_user_name,
session_info);
-
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(10, ("create_local_token failed: %s\n",
nt_errstr(nt_status)));
+ return nt_status;
}
- return nt_status;
+
+ return NT_STATUS_OK;
}
/**
* @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 auth_ntlmssp_state *auth_ntlmssp_state =
- (struct auth_ntlmssp_state *)ntlmssp_state->callback_private;
- auth_ntlmssp_state->auth_context->get_ntlm_challenge(
- auth_ntlmssp_state->auth_context, chal);
+ struct auth_context *auth_context = talloc_get_type_abort(auth4_context->private_data,
+ struct auth_context);
+ auth_get_ntlm_challenge(auth_context, chal);
return NT_STATUS_OK;
}
-/**
- * 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 auth_ntlmssp_state *auth_ntlmssp_state =
- (struct auth_ntlmssp_state *)ntlmssp_state->callback_private;
- struct auth_context *auth_context = auth_ntlmssp_state->auth_context;
-
- return auth_context->challenge_may_be_modified;
-}
-
/**
* 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 auth_ntlmssp_state *auth_ntlmssp_state =
- (struct auth_ntlmssp_state *)ntlmssp_state->callback_private;
- struct auth_context *auth_context = auth_ntlmssp_state->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"));
* 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,
+ uint8_t *pauthoritative,
+ void **server_returned_info,
+ DATA_BLOB *session_key, DATA_BLOB *lm_session_key)
{
- struct auth_ntlmssp_state *auth_ntlmssp_state =
- (struct auth_ntlmssp_state *)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;
- /* the client has given us its machine name (which we otherwise would not get on port 445).
- we need to possibly reload smb.conf if smb.conf includes depend on the machine name */
+ /*
+ * Be authoritative by default.
+ */
+ *pauthoritative = 1;
+
+ /* 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(auth_ntlmssp_state->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(auth_ntlmssp_state->ntlmssp_state->user);
-
- lp_load(get_dyn_CONFIGFILE(), false, false, true, true);
-
- nt_status = make_user_info_map(&user_info,
- auth_ntlmssp_state->ntlmssp_state->user,
- auth_ntlmssp_state->ntlmssp_state->domain,
- auth_ntlmssp_state->ntlmssp_state->client.netbios_name,
- auth_ntlmssp_state->remote_address,
- auth_ntlmssp_state->ntlmssp_state->lm_resp.data ? &auth_ntlmssp_state->ntlmssp_state->lm_resp : NULL,
- auth_ntlmssp_state->ntlmssp_state->nt_resp.data ? &auth_ntlmssp_state->ntlmssp_state->nt_resp : NULL,
+ sub_set_smb_name(user_info->client.account_name);
+
+ lp_load_with_shares(get_dyn_CONFIGFILE());
+
+ nt_status = make_user_info_map(talloc_tos(),
+ &mapped_user_info,
+ user_info->client.account_name,
+ user_info->client.domain_name,
+ user_info->workstation_name,
+ user_info->remote_host,
+ user_info->local_host,
+ user_info->service_description,
+ 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);
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 = auth_ntlmssp_state->auth_context->check_ntlm_password(auth_ntlmssp_state->auth_context,
- user_info, &auth_ntlmssp_state->server_info);
+ mapped_user_info->flags = user_info->flags;
- username_was_mapped = user_info->was_mapped;
-
- free_user_info(&user_info);
+ nt_status = auth_check_ntlm_password(mem_ctx,
+ auth_context,
+ mapped_user_info,
+ &server_info,
+ pauthoritative);
if (!NT_STATUS_IS_OK(nt_status)) {
- nt_status = do_map_to_guest_server_info(nt_status,
- &auth_ntlmssp_state->server_info,
- auth_ntlmssp_state->ntlmssp_state->user,
- auth_ntlmssp_state->ntlmssp_state->domain);
+ DEBUG(5,("Checking NTLMSSP password for %s\\%s failed: "
+ "%s, authoritative=%u\n",
+ user_info->client.domain_name,
+ user_info->client.account_name,
+ nt_errstr(nt_status),
+ *pauthoritative));
}
+ username_was_mapped = mapped_user_info->was_mapped;
+
+ TALLOC_FREE(mapped_user_info);
+
if (!NT_STATUS_IS_OK(nt_status)) {
+ nt_status = do_map_to_guest_server_info(mem_ctx,
+ nt_status,
+ user_info->client.account_name,
+ user_info->client.domain_name,
+ &server_info);
+ if (NT_STATUS_IS_OK(nt_status)) {
+ *pauthoritative = 1;
+ *server_returned_info = talloc_steal(mem_ctx, server_info);
+ }
return nt_status;
}
- talloc_steal(auth_ntlmssp_state, auth_ntlmssp_state->server_info);
-
- auth_ntlmssp_state->server_info->nss_token |= username_was_mapped;
+ server_info->nss_token |= username_was_mapped;
/* Clear out the session keys, and pass them to the caller.
* 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 (auth_ntlmssp_state->server_info->session_key.length) {
+ if (session_key) {
DEBUG(10, ("Got NT session key of length %u\n",
- (unsigned int)auth_ntlmssp_state->server_info->session_key.length));
- *session_key = auth_ntlmssp_state->server_info->session_key;
- talloc_steal(mem_ctx, auth_ntlmssp_state->server_info->session_key.data);
- auth_ntlmssp_state->server_info->session_key = data_blob_null;
+ (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 (auth_ntlmssp_state->server_info->lm_session_key.length) {
+ if (lm_session_key) {
DEBUG(10, ("Got LM session key of length %u\n",
- (unsigned int)auth_ntlmssp_state->server_info->lm_session_key.length));
- *lm_session_key = auth_ntlmssp_state->server_info->lm_session_key;
- talloc_steal(mem_ctx, auth_ntlmssp_state->server_info->lm_session_key.data);
- auth_ntlmssp_state->server_info->lm_session_key = data_blob_null;
- }
- return nt_status;
-}
-
-NTSTATUS auth_ntlmssp_prepare(const struct tsocket_address *remote_address,
- struct auth_ntlmssp_state **auth_ntlmssp_state)
-{
- NTSTATUS nt_status;
- bool is_standalone;
- const char *netbios_name;
- const char *netbios_domain;
- const char *dns_name;
- char *dns_domain;
- struct auth_ntlmssp_state *ans;
- struct auth_context *auth_context;
-
- ans = talloc_zero(NULL, struct auth_ntlmssp_state);
- if (!ans) {
- DEBUG(0,("auth_ntlmssp_start: talloc failed!\n"));
- return NT_STATUS_NO_MEMORY;
- }
-
- nt_status = make_auth_context_subsystem(talloc_tos(), &auth_context);
- if (!NT_STATUS_IS_OK(nt_status)) {
- TALLOC_FREE(ans);
- return nt_status;
- }
-
- ans->auth_context = talloc_steal(ans, auth_context);
-
- if (auth_context->prepare_gensec) {
- nt_status = auth_context->prepare_gensec(ans, &ans->gensec_security);
- if (!NT_STATUS_IS_OK(nt_status)) {
- TALLOC_FREE(ans);
- return nt_status;
- } else {
- *auth_ntlmssp_state = ans;
- return NT_STATUS_OK;
- }
- }
-
- if ((enum server_role)lp_server_role() == ROLE_STANDALONE) {
- is_standalone = true;
- } else {
- is_standalone = false;
- }
-
- netbios_name = lp_netbios_name();
- netbios_domain = lp_workgroup();
- /* This should be a 'netbios domain -> DNS domain' mapping */
- dns_domain = get_mydnsdomname(talloc_tos());
- if (dns_domain) {
- strlower_m(dns_domain);
- }
- dns_name = get_mydnsfullname();
-
- ans->remote_address = tsocket_address_copy(remote_address, ans);
- if (ans->remote_address == NULL) {
- DEBUG(0,("auth_ntlmssp_start: talloc failed!\n"));
- return NT_STATUS_NO_MEMORY;
- }
-
- nt_status = ntlmssp_server_start(ans,
- is_standalone,
- netbios_name,
- netbios_domain,
- dns_name,
- dns_domain,
- &ans->ntlmssp_state);
- if (!NT_STATUS_IS_OK(nt_status)) {
- return nt_status;
- }
-
- ans->ntlmssp_state->callback_private = ans;
- ans->ntlmssp_state->get_challenge = auth_ntlmssp_get_challenge;
- ans->ntlmssp_state->may_set_challenge = auth_ntlmssp_may_set_challenge;
- ans->ntlmssp_state->set_challenge = auth_ntlmssp_set_challenge;
- ans->ntlmssp_state->check_password = auth_ntlmssp_check_password;
-
- *auth_ntlmssp_state = ans;
- return NT_STATUS_OK;
-}
-
-NTSTATUS auth_generic_start(struct auth_ntlmssp_state *auth_ntlmssp_state, const char *oid)
-{
- if (auth_ntlmssp_state->auth_context->gensec_start_mech_by_oid) {
- return auth_ntlmssp_state->auth_context->gensec_start_mech_by_oid(auth_ntlmssp_state->gensec_security, oid);
+ (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;
}
- if (strcmp(oid, GENSEC_OID_NTLMSSP) != 0) {
- /* The caller will then free the auth_ntlmssp_state,
- * undoing what was done in auth_ntlmssp_prepare().
- *
- * We can't do that logic here, as
- * auth_ntlmssp_want_feature() may have been called in
- * between.
- */
- return NT_STATUS_NOT_IMPLEMENTED;
- }
-
- return NT_STATUS_OK;
-}
-
-NTSTATUS auth_ntlmssp_start(struct auth_ntlmssp_state *auth_ntlmssp_state)
-{
- return auth_generic_start(auth_ntlmssp_state, GENSEC_OID_NTLMSSP);
+ *server_returned_info = talloc_steal(mem_ctx, server_info);
+ return nt_status;
}