return auth_context->challenge.data;
}
+ auth_context->challenge_may_be_modified = False;
+
for (auth_method = auth_context->auth_method_list; auth_method; auth_method = auth_method->next) {
if (auth_method->get_chal == NULL) {
DEBUG(5, ("auth_get_challenge: module %s did not want to specify a challenge\n", auth_method->name));
chal, sizeof(chal));
challenge_set_by = "random";
+ auth_context->challenge_may_be_modified = True;
}
DEBUG(5, ("auth_context challenge created by %s\n", challenge_set_by));
DEBUG(5, ("challenge is: \n"));
- dump_data(5, (const char*)auth_context->challenge.data, auth_context->challenge.length);
+ dump_data(5, (const char *)auth_context->challenge.data, auth_context->challenge.length);
SMB_ASSERT(auth_context->challenge.length == 8);
const struct auth_usersupplied_info *user_info,
struct auth_serversupplied_info **server_info)
{
-
- NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
- const char *pdb_username;
+ /* if all the modules say 'not for me' this is reasonable */
+ NTSTATUS nt_status = NT_STATUS_NO_SUCH_USER;
auth_methods *auth_method;
TALLOC_CTX *mem_ctx;
auth_context->challenge_set_by));
DEBUG(10, ("challenge is: \n"));
- dump_data(5, (const char*)auth_context->challenge.data, auth_context->challenge.length);
+ dump_data(5, (const char *)auth_context->challenge.data, auth_context->challenge.length);
#ifdef DEBUG_PASSWORD
DEBUG(100, ("user_info has passwords of length %d and %d\n",
return NT_STATUS_LOGON_FAILURE;
for (auth_method = auth_context->auth_method_list;auth_method; auth_method = auth_method->next) {
+ NTSTATUS result;
+
mem_ctx = talloc_init("%s authentication for user %s\\%s", auth_method->name,
user_info->domain.str, user_info->smb_name.str);
- nt_status = auth_method->auth(auth_context, auth_method->private_data, mem_ctx, user_info, server_info);
+ result = auth_method->auth(auth_context, auth_method->private_data, mem_ctx, user_info, server_info);
+
+ /* check if the module did anything */
+ if ( NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_NOT_IMPLEMENTED) ) {
+ DEBUG(10,("check_ntlm_password: %s had nothing to say\n", auth_method->name));
+ talloc_destroy(mem_ctx);
+ continue;
+ }
+
+ nt_status = result;
+
if (NT_STATUS_IS_OK(nt_status)) {
- DEBUG(3, ("check_ntlm_password: %s authentication for user [%s] suceeded\n",
+ DEBUG(3, ("check_ntlm_password: %s authentication for user [%s] succeeded\n",
auth_method->name, user_info->smb_name.str));
} else {
DEBUG(5, ("check_ntlm_password: %s authentication for user [%s] FAILED with error %s\n",
talloc_destroy(mem_ctx);
- if (NT_STATUS_IS_OK(nt_status))
- break;
+ if ( NT_STATUS_IS_OK(nt_status))
+ {
+ break;
+ }
}
/* This is one of the few places the *relies* (rather than just sets defaults
smb_user_control(user_info, *server_info, nt_status);
if (NT_STATUS_IS_OK(nt_status)) {
- pdb_username = pdb_get_username((*server_info)->sam_account);
- if (!(*server_info)->guest) {
- /* We might not be root if we are an RPC call */
- become_root();
- nt_status = smb_pam_accountcheck(pdb_username);
- unbecome_root();
-
- if (NT_STATUS_IS_OK(nt_status)) {
- DEBUG(5, ("check_ntlm_password: PAM Account for user [%s] suceeded\n",
- pdb_username));
- } else {
- DEBUG(3, ("check_ntlm_password: PAM Account for user [%s] FAILED with error %s\n",
- pdb_username, nt_errstr(nt_status)));
- }
- }
-
if (NT_STATUS_IS_OK(nt_status)) {
DEBUG((*server_info)->guest ? 5 : 2,
- ("check_ntlm_password: %sauthentication for user [%s] -> [%s] -> [%s] suceeded\n",
+ ("check_ntlm_password: %sauthentication for user [%s] -> [%s] succeeded\n",
(*server_info)->guest ? "guest " : "",
user_info->smb_name.str,
- user_info->internal_username.str,
- pdb_username));
+ user_info->internal_username.str));
}
}
static void free_auth_context(struct auth_context **auth_context)
{
- if (*auth_context != NULL)
+ auth_methods *auth_method;
+
+ if (*auth_context) {
+ /* Free private data of context's authentication methods */
+ for (auth_method = (*auth_context)->auth_method_list; auth_method; auth_method = auth_method->next) {
+ if (auth_method->free_private_data) {
+ auth_method->free_private_data (&auth_method->private_data);
+ auth_method->private_data = NULL;
+ }
+ }
+
talloc_destroy((*auth_context)->mem_ctx);
- *auth_context = NULL;
+ *auth_context = NULL;
+ }
}
/***************************************************************************
{
case SEC_DOMAIN:
DEBUG(5,("Making default auth method list for security=domain\n"));
- auth_method_list = str_list_make("guest sam winbind ntdomain", NULL);
+ auth_method_list = str_list_make("guest sam winbind:ntdomain", NULL);
break;
case SEC_SERVER:
DEBUG(5,("Making default auth method list for security=server\n"));
break;
case SEC_ADS:
DEBUG(5,("Making default auth method list for security=ADS\n"));
- auth_method_list = str_list_make("guest sam ads winbind ntdomain", NULL);
+ auth_method_list = str_list_make("guest sam winbind:ntdomain", NULL);
break;
default:
DEBUG(5,("Unknown auth method!\n"));
return nt_status;
}
- (*auth_context)->challenge = data_blob(chal, 8);
+ (*auth_context)->challenge = data_blob_talloc((*auth_context)->mem_ctx, chal, 8);
(*auth_context)->challenge_set_by = "fixed";
return nt_status;
}
sizeof(struct auth_usersupplied_info),
sizeof(struct auth_serversupplied_info),
sizeof(struct auth_str),
- sizeof(struct auth_unistr)
};
return &critical_sizes;
*/
/* version 1 - version from samba 3.0 - metze */
/* version 2 - initial samba4 version - metze */
-#define AUTH_INTERFACE_VERSION 2
+/* version 3 - subsequent samba4 version - abartlet */
+#define AUTH_INTERFACE_VERSION 3
/* AUTH_STR - string */
typedef struct auth_str
char *str;
} AUTH_STR;
-/* AUTH_UNISTR - unicode string or buffer */
-typedef struct auth_unistr
-{
- int len;
- uchar *unistr;
-} AUTH_UNISTR;
-
-#define AUTH_FLAG_NONE 0x000000
-#define AUTH_FLAG_PLAINTEXT 0x000001
-#define AUTH_FLAG_LM_RESP 0x000002
-#define AUTH_FLAG_NTLM_RESP 0x000004
-#define AUTH_FLAG_NTLMv2_RESP 0x000008
-
typedef struct auth_usersupplied_info
{
+
DATA_BLOB lm_resp;
DATA_BLOB nt_resp;
+ DATA_BLOB lm_interactive_pwd;
+ DATA_BLOB nt_interactive_pwd;
DATA_BLOB plaintext_password;
BOOL encrypted;
- uint32 auth_flags;
-
AUTH_STR client_domain; /* domain name string */
AUTH_STR domain; /* domain name after mapping */
AUTH_STR internal_username; /* username after mapping */
AUTH_STR smb_name; /* username before mapping */
AUTH_STR wksta_name; /* workstation name (netbios calling name) unicode string */
+
} auth_usersupplied_info;
#define SAM_FILL_NAME 0x01
NT_USER_TOKEN *ptok;
- uint8 session_key[16];
- uint8 first_8_lm_hash[8];
- DATA_BLOB nt_session_key;
+ DATA_BLOB user_session_key;
DATA_BLOB lm_session_key;
-
+
uint32 sam_fill_level; /* How far is this structure filled? */
SAM_ACCOUNT *sam_account;
void *my_private_data,
TALLOC_CTX *mem_ctx,
const struct auth_usersupplied_info *user_info,
- struct auth_serversupplied_info **server_info);
+ auth_serversupplied_info **server_info);
DATA_BLOB (*get_chal)(const struct auth_context *auth_context,
void **my_private_data,
/* Function to send a keepalive message on the above structure */
void (*send_keepalive)(void **private_data);
+
} auth_methods;
+typedef NTSTATUS (*auth_init_function)(struct auth_context *, const char *, struct auth_methods **);
+
+struct auth_init_function_entry {
+ const char *name;
+ /* Function to create a member of the authmethods list */
+
+ auth_init_function init;
+
+ struct auth_init_function_entry *prev, *next;
+};
+
typedef struct auth_ntlmssp_state
{
TALLOC_CTX *mem_ctx;
int sizeof_auth_unistr;
};
-#endif /* _SAMBA_AUTH_H */
+#endif /* _SMBAUTH_H_ */
/*
Unix SMB/CIFS implementation.
- Generic authenticaion types
+ Generic authentication types
Copyright (C) Andrew Bartlett 2001-2002
Copyright (C) Jelmer Vernooij 2002
const auth_usersupplied_info *user_info,
auth_serversupplied_info **server_info)
{
- NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
+ /* mark this as 'not for me' */
+ NTSTATUS nt_status = NT_STATUS_NOT_IMPLEMENTED;
if (!(user_info->internal_username.str
&& *user_info->internal_username.str)) {
return NT_STATUS_OK;
}
+#ifdef DEVELOPER
/**
* Return an error based on username
*
long error_num;
fstrcpy(user, user_info->smb_name.str);
- if (strncasecmp("NT_STATUS", user, strlen("NT_STATUS")) == 0) {
- strupper(user);
+ if (strnequal("NT_STATUS", user, strlen("NT_STATUS"))) {
+ strupper_m(user);
return nt_status_string_to_code(user);
}
- strlower(user);
+ strlower_m(user);
error_num = strtoul(user, NULL, 16);
DEBUG(5,("check_name_to_ntstatus_security: Error for user %s was %lx\n", user, error_num));
return nt_status;
}
-/** Module initailisation function */
+/** Module initialisation function */
static NTSTATUS auth_init_name_to_ntstatus(struct auth_context *auth_context, const char *param, auth_methods **auth_method)
{
}
/**
- * Return a 'fixed' challenge instead of a varaible one.
+ * Return a 'fixed' challenge instead of a variable one.
*
* The idea of this function is to make packet snifs consistant
* with a fixed challenge, so as to aid debugging.
const auth_usersupplied_info *user_info,
auth_serversupplied_info **server_info)
{
- return NT_STATUS_UNSUCCESSFUL;
+ return NT_STATUS_NOT_IMPLEMENTED;
}
/****************************************************************************
(*auth_method)->name = "fixed_challenge";
return NT_STATUS_OK;
}
+#endif /* DEVELOPER */
NTSTATUS auth_builtin_init(void)
{
DATA_BLOB null_password = data_blob(NULL, 0);
BOOL encrypted = (smb->negotiate.encrypted_passwords && password_blob.length == 24);
- NTSTATUS status;
if (encrypted) {
/*
* but fall-through as required.
* NTLMv2 makes no sense here.
*/
- status = pass_check_smb(smb, smb_name, lp_workgroup(), null_password,
- password_blob, null_password, encrypted);
- if (NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_IS_OK(pass_check_smb(smb, smb_name, lp_workgroup(), null_password, password_blob, null_password, encrypted))) {
return True;
}
- status = pass_check_smb(smb, smb_name, lp_workgroup(), password_blob,
- null_password, null_password, encrypted);
+ if (NT_STATUS_IS_OK(pass_check_smb(smb, smb_name, lp_workgroup(), password_blob, null_password, null_password, encrypted))) {
+ return True;
+ }
} else {
- status = pass_check_smb(smb, smb_name, lp_workgroup(), null_password,
- null_password, password_blob, encrypted);
+ if (NT_STATUS_IS_OK(pass_check_smb(smb, smb_name, lp_workgroup(), null_password, null_password, password_blob, encrypted))) {
+ return True;
+ }
}
- return NT_STATUS_IS_OK(status);
+ return False;
}
* Return the session keys used on the connection.
*/
-static NTSTATUS auth_ntlmssp_check_password(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *nt_session_key, DATA_BLOB *lm_session_key)
+static NTSTATUS auth_ntlmssp_check_password(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
{
AUTH_NTLMSSP_STATE *auth_ntlmssp_state = ntlmssp_state->auth_context;
- uint32 auth_flags = AUTH_FLAG_NONE;
auth_usersupplied_info *user_info = NULL;
- DATA_BLOB plaintext_password = data_blob(NULL, 0);
NTSTATUS nt_status;
- if (auth_ntlmssp_state->ntlmssp_state->lm_resp.length) {
- auth_flags |= AUTH_FLAG_LM_RESP;
- }
-
- if (auth_ntlmssp_state->ntlmssp_state->nt_resp.length == 24) {
- auth_flags |= AUTH_FLAG_NTLM_RESP;
- } else if (auth_ntlmssp_state->ntlmssp_state->nt_resp.length > 24) {
- auth_flags |= AUTH_FLAG_NTLMv2_RESP;
- }
-
#if 0
/* 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 */
+
set_remote_machine_name(auth_ntlmssp_state->ntlmssp_state->workstation, 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);
+
reload_services(True);
-#endif
+#endif
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->workstation,
- auth_ntlmssp_state->ntlmssp_state->lm_resp,
- auth_ntlmssp_state->ntlmssp_state->nt_resp,
- plaintext_password,
- auth_flags, True);
+ 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,
+ NULL, NULL, NULL,
+ True);
if (!NT_STATUS_IS_OK(nt_status)) {
return nt_status;
if (!NT_STATUS_IS_OK(nt_status)) {
return nt_status;
}
- if (auth_ntlmssp_state->server_info->nt_session_key.length) {
- DEBUG(5, ("Got NT session key of length %u\n", auth_ntlmssp_state->server_info->nt_session_key.length));
- *nt_session_key = data_blob_talloc(auth_ntlmssp_state->mem_ctx,
- auth_ntlmssp_state->server_info->nt_session_key.data,
- auth_ntlmssp_state->server_info->nt_session_key.length);
- } else if (auth_ntlmssp_state->server_info->lm_session_key.length) {
- DEBUG(5, ("Got LM session key of length %u\n", auth_ntlmssp_state->server_info->lm_session_key.length));
- *lm_session_key = data_blob_talloc(auth_ntlmssp_state->mem_ctx,
+ if (auth_ntlmssp_state->server_info->user_session_key.length) {
+ DEBUG(10, ("Got NT session key of length %u\n", auth_ntlmssp_state->server_info->user_session_key.length));
+ *user_session_key = data_blob_talloc(ntlmssp_state->mem_ctx,
+ auth_ntlmssp_state->server_info->user_session_key.data,
+ auth_ntlmssp_state->server_info->user_session_key.length);
+ }
+ if (auth_ntlmssp_state->server_info->lm_session_key.length) {
+ DEBUG(10, ("Got LM session key of length %u\n", auth_ntlmssp_state->server_info->lm_session_key.length));
+ *lm_session_key = data_blob_talloc(ntlmssp_state->mem_ctx,
auth_ntlmssp_state->server_info->lm_session_key.data,
auth_ntlmssp_state->server_info->lm_session_key.length);
- } else {
- *nt_session_key = data_blob_talloc(auth_ntlmssp_state->mem_ctx,
- auth_ntlmssp_state->server_info->session_key, 16);
}
return nt_status;
}
Password and authentication handling
Copyright (C) Andrew Tridgell 1992-2000
Copyright (C) Luke Kenneth Casson Leighton 1996-2000
- Copyright (C) Andrew Bartlett 2001
+ Copyright (C) Andrew Bartlett 2001-2003
+ Copyright (C) Gerald Carter 2003
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
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_AUTH
-/****************************************************************************
-core of smb password checking routine.
-****************************************************************************/
-static BOOL smb_pwd_check_ntlmv1(DATA_BLOB nt_response,
- const uchar *part_passwd,
- DATA_BLOB sec_blob,
- uint8 user_sess_key[16])
-{
- /* Finish the encryption of part_passwd. */
- uchar p24[24];
-
- if (part_passwd == NULL) {
- DEBUG(10,("No password set - DISALLOWING access\n"));
- /* No password set - always false ! */
- return False;
- }
-
- if (sec_blob.length != 8) {
- DEBUG(0, ("smb_pwd_check_ntlmv1: incorrect challenge size (%d)\n", sec_blob.length));
- return False;
- }
-
- if (nt_response.length != 24) {
- DEBUG(0, ("smb_pwd_check_ntlmv1: incorrect password length (%d)\n", nt_response.length));
- return False;
- }
-
- SMBOWFencrypt(part_passwd, sec_blob.data, p24);
- if (user_sess_key != NULL)
- {
- SMBsesskeygen_ntv1(part_passwd, NULL, user_sess_key);
- }
-
-
-
-#if DEBUG_PASSWORD
- DEBUG(100,("Part password (P16) was |"));
- dump_data(100, part_passwd, 16);
- DEBUG(100,("Password from client was |"));
- dump_data(100, nt_response.data, nt_response.length);
- DEBUG(100,("Given challenge was |"));
- dump_data(100, sec_blob.data, sec_blob.length);
- DEBUG(100,("Value from encryption was |"));
- dump_data(100, p24, 24);
-#endif
- return (memcmp(p24, nt_response.data, 24) == 0);
-}
-
-
-/****************************************************************************
-core of smb password checking routine. (NTLMv2, LMv2)
-
-Note: The same code works with both NTLMv2 and LMv2.
-****************************************************************************/
-static BOOL smb_pwd_check_ntlmv2(const DATA_BLOB ntv2_response,
- const uchar *part_passwd,
- const DATA_BLOB sec_blob,
- const char *user, const char *domain,
- uint8 user_sess_key[16])
-{
- /* Finish the encryption of part_passwd. */
- uchar kr[16];
- uchar value_from_encryption[16];
- uchar client_response[16];
- DATA_BLOB client_key_data;
-
- if (part_passwd == NULL)
- {
- DEBUG(10,("No password set - DISALLOWING access\n"));
- /* No password set - always False */
- return False;
- }
-
- if (ntv2_response.length < 16) {
- /* We MUST have more than 16 bytes, or the stuff below will go
- crazy... */
- DEBUG(0, ("smb_pwd_check_ntlmv2: incorrect password length (%d)\n",
- ntv2_response.length));
- return False;
- }
-
- client_key_data = data_blob(ntv2_response.data+16, ntv2_response.length-16);
- /*
- todo: should we be checking this for anything? We can't for LMv2,
- but for NTLMv2 it is meant to contain the current time etc.
- */
-
- memcpy(client_response, ntv2_response.data, sizeof(client_response));
-
- if (!ntv2_owf_gen(part_passwd, user, domain, kr)) {
- return False;
- }
-
- SMBOWFencrypt_ntv2(kr, &sec_blob, &client_key_data, value_from_encryption);
- if (user_sess_key != NULL)
- {
- SMBsesskeygen_ntv2(kr, value_from_encryption, user_sess_key);
- }
-
-#if DEBUG_PASSWORD
- DEBUG(100,("Part password (P16) was |"));
- dump_data(100, part_passwd, 16);
- DEBUG(100,("Password from client was |"));
- dump_data(100, ntv2_response.data, ntv2_response.length);
- DEBUG(100,("Variable data from client was |"));
- dump_data(100, client_key_data.data, client_key_data.length);
- DEBUG(100,("Given challenge was |"));
- dump_data(100, sec_blob.data, sec_blob.length);
- DEBUG(100,("Value from encryption was |"));
- dump_data(100, value_from_encryption, 16);
-#endif
- data_blob_clear_free(&client_key_data);
- return (memcmp(value_from_encryption, client_response, 16) == 0);
-}
-
-
/****************************************************************************
Do a specific test for an smb password being correct, given a smb_password and
the lanman and NT responses.
****************************************************************************/
+
static NTSTATUS sam_password_ok(const struct auth_context *auth_context,
TALLOC_CTX *mem_ctx,
SAM_ACCOUNT *sampass,
const auth_usersupplied_info *user_info,
- uint8 user_sess_key[16])
+ DATA_BLOB *user_sess_key,
+ DATA_BLOB *lm_sess_key)
{
uint16 acct_ctrl;
- const uint8 *nt_pw, *lm_pw;
- uint32 auth_flags;
+ const uint8 *lm_pw, *nt_pw;
+ const char *username = pdb_get_username(sampass);
acct_ctrl = pdb_get_acct_ctrl(sampass);
- if (acct_ctrl & ACB_PWNOTREQ)
- {
- if (lp_null_passwords())
- {
- DEBUG(3,("Account for user '%s' has no password and null passwords are allowed.\n", pdb_get_username(sampass)));
- return(NT_STATUS_OK);
- }
- else
- {
- DEBUG(3,("Account for user '%s' has no password and null passwords are NOT allowed.\n", pdb_get_username(sampass)));
- return(NT_STATUS_LOGON_FAILURE);
- }
- }
-
- auth_flags = user_info->auth_flags;
-
- if (IS_SAM_DEFAULT(sampass, PDB_NTPASSWD)) {
- DEBUG(3,("sam_password_ok: NO NT password stored for user %s.\n",
- pdb_get_username(sampass)));
- /* No return, we want to check the LM hash below in this case */
- auth_flags &= (~(AUTH_FLAG_NTLMv2_RESP | AUTH_FLAG_NTLM_RESP));
- }
-
- if (auth_flags & AUTH_FLAG_NTLMv2_RESP) {
- nt_pw = pdb_get_nt_passwd(sampass);
- /* We have the NT MD4 hash challenge available - see if we can
- use it (ie. does it exist in the smbpasswd file).
- */
- DEBUG(4,("sam_password_ok: Checking NTLMv2 password with domain [%s]\n", user_info->client_domain.str));
- if (smb_pwd_check_ntlmv2( user_info->nt_resp,
- nt_pw, auth_context->challenge,
- user_info->smb_name.str,
- user_info->client_domain.str,
- user_sess_key))
- {
- return NT_STATUS_OK;
- }
-
- DEBUG(4,("sam_password_ok: Checking NTLMv2 password without a domain\n"));
- if (smb_pwd_check_ntlmv2( user_info->nt_resp,
- nt_pw, auth_context->challenge,
- user_info->smb_name.str,
- "",
- user_sess_key))
- {
+ if (acct_ctrl & ACB_PWNOTREQ) {
+ if (lp_null_passwords()) {
+ DEBUG(3,("Account for user '%s' has no password and null passwords are allowed.\n", username));
return NT_STATUS_OK;
} else {
- DEBUG(3,("sam_password_ok: NTLMv2 password check failed\n"));
- return NT_STATUS_WRONG_PASSWORD;
- }
- } else if (auth_flags & AUTH_FLAG_NTLM_RESP) {
- if (lp_ntlm_auth()) {
- nt_pw = pdb_get_nt_passwd(sampass);
- /* We have the NT MD4 hash challenge available - see if we can
- use it (ie. does it exist in the smbpasswd file).
- */
- DEBUG(4,("sam_password_ok: Checking NT MD4 password\n"));
- if (smb_pwd_check_ntlmv1(user_info->nt_resp,
- nt_pw, auth_context->challenge,
- user_sess_key))
- {
- return NT_STATUS_OK;
- } else {
- DEBUG(3,("sam_password_ok: NT MD4 password check failed for user %s\n",pdb_get_username(sampass)));
- return NT_STATUS_WRONG_PASSWORD;
- }
- } else {
- DEBUG(2,("sam_password_ok: NTLMv1 passwords NOT PERMITTED for user %s\n",pdb_get_username(sampass)));
- /* no return, becouse we might pick up LMv2 in the LM feild */
- }
+ DEBUG(3,("Account for user '%s' has no password and null passwords are NOT allowed.\n", username));
+ return NT_STATUS_LOGON_FAILURE;
+ }
}
-
- if (auth_flags & AUTH_FLAG_LM_RESP) {
- if (user_info->lm_resp.length != 24) {
- DEBUG(2,("sam_password_ok: invalid LanMan password length (%d) for user %s\n",
- user_info->nt_resp.length, pdb_get_username(sampass)));
- }
-
- if (!lp_lanman_auth()) {
- DEBUG(3,("sam_password_ok: Lanman passwords NOT PERMITTED for user %s\n",pdb_get_username(sampass)));
- } else if (IS_SAM_DEFAULT(sampass, PDB_LMPASSWD)) {
- DEBUG(3,("sam_password_ok: NO LanMan password set for user %s (and no NT password supplied)\n",pdb_get_username(sampass)));
- } else {
- lm_pw = pdb_get_lanman_passwd(sampass);
-
- DEBUG(4,("sam_password_ok: Checking LM password\n"));
- if (smb_pwd_check_ntlmv1(user_info->lm_resp,
- lm_pw, auth_context->challenge,
- user_sess_key))
- {
- return NT_STATUS_OK;
- }
- }
- if (IS_SAM_DEFAULT(sampass, PDB_NTPASSWD)) {
- DEBUG(4,("sam_password_ok: LM password check failed for user, no NT password %s\n",pdb_get_username(sampass)));
- return NT_STATUS_WRONG_PASSWORD;
- }
-
- nt_pw = pdb_get_nt_passwd(sampass);
-
- /* This is for 'LMv2' authentication. almost NTLMv2 but limited to 24 bytes.
- - related to Win9X, legacy NAS pass-though authentication
- */
- DEBUG(4,("sam_password_ok: Checking LMv2 password with domain %s\n", user_info->client_domain.str));
- if (smb_pwd_check_ntlmv2( user_info->lm_resp,
- nt_pw, auth_context->challenge,
- user_info->smb_name.str,
- user_info->client_domain.str,
- user_sess_key))
- {
- return NT_STATUS_OK;
- }
-
- DEBUG(4,("sam_password_ok: Checking LMv2 password without a domain\n"));
- if (smb_pwd_check_ntlmv2( user_info->lm_resp,
- nt_pw, auth_context->challenge,
- user_info->smb_name.str,
- "",
- user_sess_key))
- {
- return NT_STATUS_OK;
- }
+ lm_pw = pdb_get_lanman_passwd(sampass);
+ nt_pw = pdb_get_nt_passwd(sampass);
- /* Apparently NT accepts NT responses in the LM field
- - I think this is related to Win9X pass-though authentication
- */
- DEBUG(4,("sam_password_ok: Checking NT MD4 password in LM field\n"));
- if (lp_ntlm_auth())
- {
- if (smb_pwd_check_ntlmv1(user_info->lm_resp,
- nt_pw, auth_context->challenge,
- user_sess_key))
- {
- return NT_STATUS_OK;
- }
- DEBUG(3,("sam_password_ok: LM password, NT MD4 password in LM field and LMv2 failed for user %s\n",pdb_get_username(sampass)));
- return NT_STATUS_WRONG_PASSWORD;
- } else {
- DEBUG(3,("sam_password_ok: LM password and LMv2 failed for user %s, and NT MD4 password in LM field not permitted\n",pdb_get_username(sampass)));
- return NT_STATUS_WRONG_PASSWORD;
- }
-
- }
-
- /* Should not be reached, but if they send nothing... */
- DEBUG(3,("sam_password_ok: NEITHER LanMan nor NT password supplied for user %s\n",pdb_get_username(sampass)));
- return NT_STATUS_WRONG_PASSWORD;
+ return ntlm_password_check(mem_ctx, &auth_context->challenge,
+ &user_info->lm_resp, &user_info->nt_resp,
+ &user_info->lm_interactive_pwd, &user_info->nt_interactive_pwd,
+ username,
+ user_info->smb_name.str,
+ user_info->client_domain.str,
+ lm_pw, nt_pw, user_sess_key, lm_sess_key);
}
+
/****************************************************************************
Do a specific test for a SAM_ACCOUNT being vaild for this connection
(ie not disabled, expired and the like).
****************************************************************************/
+
static NTSTATUS sam_account_ok(TALLOC_CTX *mem_ctx,
SAM_ACCOUNT *sampass,
const auth_usersupplied_info *user_info)
/* Quit if the account was disabled. */
if (acct_ctrl & ACB_DISABLED) {
- DEBUG(1,("Account for user '%s' was disabled.\n", pdb_get_username(sampass)));
+ DEBUG(1,("sam_account_ok: Account for user '%s' was disabled.\n", pdb_get_username(sampass)));
return NT_STATUS_ACCOUNT_DISABLED;
}
+ /* Quit if the account was locked out. */
+ if (acct_ctrl & ACB_AUTOLOCK) {
+ DEBUG(1,("sam_account_ok: Account for user %s was locked out.\n", pdb_get_username(sampass)));
+ return NT_STATUS_ACCOUNT_LOCKED_OUT;
+ }
+
/* Test account expire time */
kickoff_time = pdb_get_kickoff_time(sampass);
if (kickoff_time != 0 && time(NULL) > kickoff_time) {
- DEBUG(1,("Account for user '%s' has expried.\n", pdb_get_username(sampass)));
- DEBUG(3,("Account expired at '%ld' unix time.\n", (long)kickoff_time));
+ DEBUG(1,("sam_account_ok: Account for user '%s' has expired.\n", pdb_get_username(sampass)));
+ DEBUG(3,("sam_account_ok: Account expired at '%ld' unix time.\n", (long)kickoff_time));
return NT_STATUS_ACCOUNT_EXPIRED;
}
/* check for immediate expiry "must change at next logon" */
if (must_change_time == 0 && last_set_time != 0) {
- DEBUG(1,("Account for user '%s' password must change!.\n", pdb_get_username(sampass)));
+ DEBUG(1,("sam_account_ok: Account for user '%s' password must change!.\n", pdb_get_username(sampass)));
return NT_STATUS_PASSWORD_MUST_CHANGE;
}
/* check for expired password */
if (must_change_time < time(NULL) && must_change_time != 0) {
- DEBUG(1,("Account for user '%s' password expired!.\n", pdb_get_username(sampass)));
- DEBUG(1,("Password expired at '%s' (%ld) unix time.\n", timestring(mem_ctx, must_change_time), (long)must_change_time));
+ DEBUG(1,("sam_account_ok: Account for user '%s' password expired!.\n", pdb_get_username(sampass)));
+ DEBUG(1,("sam_account_ok: Password expired at '%s' (%ld) unix time.\n", timestring(mem_ctx, must_change_time), (long)must_change_time));
return NT_STATUS_PASSWORD_EXPIRED;
}
}
/* Test workstation. Workstation list is comma separated. */
workstation_list = talloc_strdup(mem_ctx, pdb_get_workstations(sampass));
-
- if (!workstation_list) return NT_STATUS_NO_MEMORY;
+ if (!workstation_list)
+ return NT_STATUS_NO_MEMORY;
if (*workstation_list) {
BOOL invalid_ws = True;
fstring tok;
while (next_token(&s, tok, ",", sizeof(tok))) {
- DEBUG(10,("checking for workstation match %s and %s (len=%d)\n",
+ DEBUG(10,("sam_account_ok: checking for workstation match %s and %s (len=%d)\n",
tok, user_info->wksta_name.str, user_info->wksta_name.len));
if(strequal(tok, user_info->wksta_name.str)) {
invalid_ws = False;
return NT_STATUS_OK;
}
-
/****************************************************************************
check if a username/password is OK assuming the password is a 24 byte
SMB hash supplied in the user_info structure
SAM_ACCOUNT *sampass=NULL;
BOOL ret;
NTSTATUS nt_status;
- uint8 user_sess_key[16];
- const uint8* lm_hash;
+ DATA_BLOB user_sess_key = data_blob(NULL, 0);
+ DATA_BLOB lm_sess_key = data_blob(NULL, 0);
if (!user_info || !auth_context) {
return NT_STATUS_UNSUCCESSFUL;
}
- /* Can't use the talloc version here, becouse the returned struct gets
+ /* Can't use the talloc version here, because the returned struct gets
kept on the server_info */
if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam(&sampass))) {
return nt_status;
ret = pdb_getsampwnam(sampass, user_info->internal_username.str);
unbecome_root();
- if (ret == False)
- {
- DEBUG(3,("Couldn't find user '%s' in passdb file.\n", user_info->internal_username.str));
+ if (ret == False) {
+ DEBUG(3,("check_sam_security: Couldn't find user '%s' in passdb file.\n", user_info->internal_username.str));
pdb_free_sam(&sampass);
return NT_STATUS_NO_SUCH_USER;
}
- nt_status = sam_account_ok(mem_ctx, sampass, user_info);
+ /* Quit if the account was locked out. */
+ if (pdb_get_acct_ctrl(sampass) & ACB_AUTOLOCK) {
+ DEBUG(3,("check_sam_security: Account for user %s was locked out.\n", pdb_get_username(sampass)));
+ return NT_STATUS_ACCOUNT_LOCKED_OUT;
+ }
+
+ nt_status = sam_password_ok(auth_context, mem_ctx, sampass,
+ user_info, &user_sess_key, &lm_sess_key);
if (!NT_STATUS_IS_OK(nt_status)) {
pdb_free_sam(&sampass);
return nt_status;
}
- nt_status = sam_password_ok(auth_context, mem_ctx, sampass, user_info, user_sess_key);
+ nt_status = sam_account_ok(mem_ctx, sampass, user_info);
if (!NT_STATUS_IS_OK(nt_status)) {
pdb_free_sam(&sampass);
return nt_status;
}
- lm_hash = pdb_get_lanman_passwd((*server_info)->sam_account);
- if (lm_hash) {
- memcpy((*server_info)->first_8_lm_hash, lm_hash, 8);
- }
-
- memcpy((*server_info)->session_key, user_sess_key, sizeof(user_sess_key));
+ (*server_info)->user_session_key = user_sess_key;
+ (*server_info)->lm_session_key = lm_sess_key;
return nt_status;
}
/* module initialisation */
-static NTSTATUS auth_init_sam(struct auth_context *auth_context, const char *param, auth_methods **auth_method)
+static NTSTATUS auth_init_sam_ignoredomain(struct auth_context *auth_context, const char *param, auth_methods **auth_method)
{
if (!make_auth_methods(auth_context, auth_method)) {
return NT_STATUS_NO_MEMORY;
}
(*auth_method)->auth = check_sam_security;
- (*auth_method)->name = "sam";
+ (*auth_method)->name = "sam_ignoredomain";
return NT_STATUS_OK;
}
}
/* module initialisation */
-static NTSTATUS auth_init_samstrict(struct auth_context *auth_context, const char *param, auth_methods **auth_method)
+static NTSTATUS auth_init_sam(struct auth_context *auth_context, const char *param, auth_methods **auth_method)
{
if (!make_auth_methods(auth_context, auth_method)) {
return NT_STATUS_NO_MEMORY;
}
(*auth_method)->auth = check_samstrict_security;
- (*auth_method)->name = "samstrict";
- return NT_STATUS_OK;
-}
-
-/****************************************************************************
-Check SAM security (above) but with a few extra checks if we're a DC.
-****************************************************************************/
-
-static NTSTATUS check_samstrict_dc_security(const struct auth_context *auth_context,
- void *my_private_data,
- TALLOC_CTX *mem_ctx,
- const auth_usersupplied_info *user_info,
- auth_serversupplied_info **server_info)
-{
-
- if (!user_info || !auth_context) {
- return NT_STATUS_LOGON_FAILURE;
- }
-
- /* If we are a domain member, we must not
- attempt to check the password locally,
- unless it is one of our aliases, empty
- or our domain if we are a logon server.*/
-
-
- if ((strcasecmp(lp_workgroup(), user_info->domain.str) != 0) &&
- (!is_myname(user_info->domain.str))) {
- DEBUG(7,("The requested user domain is not the local server name or our domain. [%s]\\[%s]\n",
- user_info->domain.str,user_info->internal_username.str));
- return NT_STATUS_NO_SUCH_USER;
- }
-
- return check_sam_security(auth_context, my_private_data, mem_ctx, user_info, server_info);
-}
-
-/* module initialisation */
-static NTSTATUS auth_init_samstrict_dc(struct auth_context *auth_context, const char *param, auth_methods **auth_method)
-{
- if (!make_auth_methods(auth_context, auth_method)) {
- return NT_STATUS_NO_MEMORY;
- }
-
- (*auth_method)->auth = check_samstrict_dc_security;
- (*auth_method)->name = "samstrict_dc";
+ (*auth_method)->name = "sam";
return NT_STATUS_OK;
}
return ret;
}
- ops.name = "samstrict";
- ops.init = auth_init_samstrict;
- ret = register_backend("auth", &ops);
- if (!NT_STATUS_IS_OK(ret)) {
- DEBUG(0,("Failed to register '%s' auth backend!\n",
- ops.name));
- return ret;
- }
-
- ops.name = "samstrict_dc";
- ops.init = auth_init_samstrict_dc;
+ ops.name = "sam_ignoredomain";
+ ops.init = auth_init_sam_ignoredomain;
ret = register_backend("auth", &ops);
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(0,("Failed to register '%s' auth backend!\n",
/****************************************************************************
Create a UNIX user on demand.
****************************************************************************/
-static int smb_create_user(const char *unix_user, const char *homedir)
+
+static int smb_create_user(const char *domain, const char *unix_username, const char *homedir)
{
pstring add_script;
int ret;
pstrcpy(add_script, lp_adduser_script());
if (! *add_script)
return -1;
- all_string_sub(add_script, "%u", unix_user, sizeof(pstring));
+ all_string_sub(add_script, "%u", unix_username, sizeof(pstring));
+ if (domain)
+ all_string_sub(add_script, "%D", domain, sizeof(pstring));
if (homedir)
all_string_sub(add_script, "%H", homedir, sizeof(pstring));
ret = smbrun(add_script,NULL);
*/
if(lp_adduser_script() && !(pwd = Get_Pwnam(user_info->internal_username.str))) {
- smb_create_user(user_info->internal_username.str, NULL);
+ smb_create_user(user_info->domain.str, user_info->internal_username.str, NULL);
}
}
}
const char *client_domain,
const char *domain,
const char *wksta_name,
- DATA_BLOB lm_pwd, DATA_BLOB nt_pwd,
- DATA_BLOB plaintext,
- uint32 auth_flags, BOOL encrypted)
+ DATA_BLOB *lm_pwd, DATA_BLOB *nt_pwd,
+ DATA_BLOB *lm_interactive_pwd, DATA_BLOB *nt_interactive_pwd,
+ DATA_BLOB *plaintext,
+ BOOL encrypted)
{
DEBUG(5,("attempting to make a user_info for %s (%s)\n", internal_username, smb_name));
*user_info = malloc(sizeof(**user_info));
if (!user_info) {
- DEBUG(0,("malloc failed for user_info (size %d)\n", sizeof(*user_info)));
+ DEBUG(0,("malloc failed for user_info (size %lu)\n", (unsigned long)sizeof(*user_info)));
return NT_STATUS_NO_MEMORY;
}
DEBUG(5,("making blobs for %s's user_info struct\n", internal_username));
- (*user_info)->lm_resp = data_blob(lm_pwd.data, lm_pwd.length);
- (*user_info)->nt_resp = data_blob(nt_pwd.data, nt_pwd.length);
- (*user_info)->plaintext_password = data_blob(plaintext.data, plaintext.length);
+ if (lm_pwd)
+ (*user_info)->lm_resp = data_blob(lm_pwd->data, lm_pwd->length);
+ if (nt_pwd)
+ (*user_info)->nt_resp = data_blob(nt_pwd->data, nt_pwd->length);
+ if (lm_interactive_pwd)
+ (*user_info)->lm_interactive_pwd = data_blob(lm_interactive_pwd->data, lm_interactive_pwd->length);
+ if (nt_interactive_pwd)
+ (*user_info)->nt_interactive_pwd = data_blob(nt_interactive_pwd->data, nt_interactive_pwd->length);
+
+ if (plaintext)
+ (*user_info)->plaintext_password = data_blob(plaintext->data, plaintext->length);
(*user_info)->encrypted = encrypted;
- (*user_info)->auth_flags = auth_flags;
DEBUG(10,("made an %sencrypted user_info for %s (%s)\n", encrypted ? "":"un" , internal_username, smb_name));
const char *smb_name,
const char *client_domain,
const char *wksta_name,
- DATA_BLOB lm_pwd, DATA_BLOB nt_pwd,
- DATA_BLOB plaintext,
- uint32 ntlmssp_flags, BOOL encrypted)
+ DATA_BLOB *lm_pwd, DATA_BLOB *nt_pwd,
+ DATA_BLOB *lm_interactive_pwd, DATA_BLOB *nt_interactive_pwd,
+ DATA_BLOB *plaintext,
+ BOOL encrypted)
{
const char *domain;
fstring internal_username;
DEBUG(5, ("make_user_info_map: Mapping user [%s]\\[%s] from workstation [%s]\n",
client_domain, smb_name, wksta_name));
- if (lp_allow_trusted_domains() && *client_domain) {
-
- /* the client could have given us a workstation name
- or other crap for the workgroup - we really need a
- way of telling if this domain name is one of our
- trusted domain names
-
- Also don't allow "" as a domain, fixes a Win9X bug
- where it doens't supply a domain for logon script
- 'net use' commands.
-
- The way I do it here is by checking if the fully
- qualified username exists. This is rather reliant
- on winbind, but until we have a better method this
- will have to do
- */
+ /* don't allow "" as a domain, fixes a Win9X bug
+ where it doens't supply a domain for logon script
+ 'net use' commands. */
+ if ( *client_domain )
domain = client_domain;
-
- if ((smb_name) && (*smb_name)) { /* Don't do this for guests */
- char *user = NULL;
- if (asprintf(&user, "%s%s%s",
- client_domain, lp_winbind_separator(),
- smb_name) < 0) {
- DEBUG(0, ("make_user_info_map: asprintf() failed!\n"));
- return NT_STATUS_NO_MEMORY;
- }
-
- DEBUG(5, ("make_user_info_map: testing for user %s\n", user));
-
- if (Get_Pwnam(user) == NULL) {
- DEBUG(5, ("make_user_info_map: test for user %s failed\n", user));
- domain = lp_workgroup();
- DEBUG(5, ("make_user_info_map: trusted domain %s doesn't appear to exist, using %s\n",
- client_domain, domain));
- } else {
- DEBUG(5, ("make_user_info_map: using trusted domain %s\n", domain));
- }
- SAFE_FREE(user);
- }
- } else {
+ else
domain = lp_workgroup();
- }
+
+ /* we know that it is a trusted domain (and we are allowing them) or it is our domain */
- return make_user_info(user_info,
- smb_name, internal_username,
- client_domain, domain,
- wksta_name,
+ return make_user_info(user_info, smb_name, internal_username,
+ client_domain, domain, wksta_name,
lm_pwd, nt_pwd,
- plaintext,
- ntlmssp_flags, encrypted);
-
+ lm_interactive_pwd, nt_interactive_pwd,
+ plaintext, encrypted);
}
/****************************************************************************
NTSTATUS nt_status;
DATA_BLOB lm_blob = data_blob(lm_network_pwd, lm_pwd_len);
DATA_BLOB nt_blob = data_blob(nt_network_pwd, nt_pwd_len);
- DATA_BLOB plaintext_blob = data_blob(NULL, 0);
- uint32 auth_flags = AUTH_FLAG_NONE;
-
- if (lm_pwd_len)
- auth_flags |= AUTH_FLAG_LM_RESP;
- if (nt_pwd_len == 24) {
- auth_flags |= AUTH_FLAG_NTLM_RESP;
- } else if (nt_pwd_len != 0) {
- auth_flags |= AUTH_FLAG_NTLMv2_RESP;
- }
nt_status = make_user_info_map(user_info,
- smb_name, client_domain,
- wksta_name,
- lm_blob, nt_blob,
- plaintext_blob,
- auth_flags, True);
+ smb_name, client_domain,
+ wksta_name,
+ lm_pwd_len ? &lm_blob : NULL,
+ nt_pwd_len ? &nt_blob : NULL,
+ NULL, NULL, NULL,
+ True);
ret = NT_STATUS_IS_OK(nt_status) ? True : False;
unsigned char local_lm_response[24];
unsigned char local_nt_response[24];
unsigned char key[16];
- uint32 auth_flags = AUTH_FLAG_NONE;
ZERO_STRUCT(key);
memcpy(key, dc_sess_key, 8);
dump_data(100, nt_pwd, sizeof(nt_pwd));
#endif
- SamOEMhash((uchar *)lm_pwd, key, sizeof(lm_pwd));
- SamOEMhash((uchar *)nt_pwd, key, sizeof(nt_pwd));
+ if (lm_interactive_pwd)
+ SamOEMhash((uchar *)lm_pwd, key, sizeof(lm_pwd));
+
+ if (nt_interactive_pwd)
+ SamOEMhash((uchar *)nt_pwd, key, sizeof(nt_pwd));
#ifdef DEBUG_PASSWORD
DEBUG(100,("decrypt of lm owf password:"));
dump_data(100, nt_pwd, sizeof(nt_pwd));
#endif
- SMBOWFencrypt((const unsigned char *)lm_pwd, chal, local_lm_response);
- SMBOWFencrypt((const unsigned char *)nt_pwd, chal, local_nt_response);
+ if (lm_interactive_pwd)
+ SMBOWFencrypt((const unsigned char *)lm_pwd, chal, local_lm_response);
+
+ if (nt_interactive_pwd)
+ SMBOWFencrypt((const unsigned char *)nt_pwd, chal, local_nt_response);
/* Password info paranoia */
- ZERO_STRUCT(lm_pwd);
- ZERO_STRUCT(nt_pwd);
ZERO_STRUCT(key);
{
BOOL ret;
NTSTATUS nt_status;
- DATA_BLOB local_lm_blob = data_blob(local_lm_response, sizeof(local_lm_response));
- DATA_BLOB local_nt_blob = data_blob(local_nt_response, sizeof(local_nt_response));
- DATA_BLOB plaintext_blob = data_blob(NULL, 0);
+ DATA_BLOB local_lm_blob;
+ DATA_BLOB local_nt_blob;
- if (lm_interactive_pwd)
- auth_flags |= AUTH_FLAG_LM_RESP;
- if (nt_interactive_pwd)
- auth_flags |= AUTH_FLAG_NTLM_RESP;
+ DATA_BLOB lm_interactive_blob;
+ DATA_BLOB nt_interactive_blob;
+
+ if (lm_interactive_pwd) {
+ local_lm_blob = data_blob(local_lm_response, sizeof(local_lm_response));
+ lm_interactive_blob = data_blob(lm_pwd, sizeof(lm_pwd));
+ ZERO_STRUCT(lm_pwd);
+ }
+
+ if (nt_interactive_pwd) {
+ local_nt_blob = data_blob(local_nt_response, sizeof(local_nt_response));
+ nt_interactive_blob = data_blob(nt_pwd, sizeof(nt_pwd));
+ ZERO_STRUCT(nt_pwd);
+ }
nt_status = make_user_info_map(user_info,
smb_name, client_domain,
wksta_name,
- local_lm_blob,
- local_nt_blob,
- plaintext_blob,
- auth_flags, True);
-
+ lm_interactive_pwd ? &local_lm_blob : NULL,
+ nt_interactive_pwd ? &local_nt_blob : NULL,
+ lm_interactive_pwd ? &lm_interactive_blob : NULL,
+ nt_interactive_pwd ? &nt_interactive_blob : NULL,
+ NULL,
+ True);
+
ret = NT_STATUS_IS_OK(nt_status) ? True : False;
data_blob_free(&local_lm_blob);
data_blob_free(&local_nt_blob);
+ data_blob_free(&lm_interactive_blob);
+ data_blob_free(&nt_interactive_blob);
return ret;
}
}
DATA_BLOB local_lm_blob;
DATA_BLOB local_nt_blob;
NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
- uint32 auth_flags = AUTH_FLAG_NONE;
/*
* Not encrypted - do so.
dump_data(100, plaintext_password.data, plaintext_password.length);
#endif
- SMBencrypt( (const uchar *)plaintext_password.data, (const uchar*)chal, local_lm_response);
+ SMBencrypt( (const char *)plaintext_password.data, (const uchar*)chal, local_lm_response);
local_lm_blob = data_blob(local_lm_response, 24);
/* We can't do an NT hash here, as the password needs to be
case insensitive */
local_nt_blob = data_blob(NULL, 0);
- auth_flags = (AUTH_FLAG_PLAINTEXT | AUTH_FLAG_LM_RESP);
} else {
local_lm_blob = data_blob(NULL, 0);
local_nt_blob = data_blob(NULL, 0);
ret = make_user_info_map(user_info, smb_name,
client_domain,
sub_get_remote_machine(),
- local_lm_blob,
- local_nt_blob,
- plaintext_password,
- auth_flags, False);
+ local_lm_blob.data ? &local_lm_blob : NULL,
+ local_nt_blob.data ? &local_nt_blob : NULL,
+ NULL, NULL,
+ plaintext_password.data ? &plaintext_password : NULL,
+ False);
data_blob_free(&local_lm_blob);
return NT_STATUS_IS_OK(ret) ? True : False;
const char *client_domain,
DATA_BLOB lm_resp, DATA_BLOB nt_resp)
{
- uint32 auth_flags = AUTH_FLAG_NONE;
-
- DATA_BLOB no_plaintext_blob = data_blob(NULL, 0);
-
- if (lm_resp.length == 24) {
- auth_flags |= AUTH_FLAG_LM_RESP;
- }
- if (nt_resp.length == 0) {
- } else if (nt_resp.length == 24) {
- auth_flags |= AUTH_FLAG_NTLM_RESP;
- } else {
- auth_flags |= AUTH_FLAG_NTLMv2_RESP;
- }
-
return make_user_info_map(user_info, smb_name,
client_domain,
sub_get_remote_machine(),
- lm_resp,
- nt_resp,
- no_plaintext_blob,
- auth_flags, True);
+ lm_resp.data ? &lm_resp : NULL,
+ nt_resp.data ? &nt_resp : NULL,
+ NULL, NULL, NULL,
+ True);
}
/****************************************************************************
BOOL make_user_info_guest(auth_usersupplied_info **user_info)
{
- DATA_BLOB lm_blob = data_blob(NULL, 0);
- DATA_BLOB nt_blob = data_blob(NULL, 0);
- DATA_BLOB plaintext_blob = data_blob(NULL, 0);
- uint32 auth_flags = AUTH_FLAG_NONE;
NTSTATUS nt_status;
nt_status = make_user_info(user_info,
- "","",
- "","",
- "",
- nt_blob, lm_blob,
- plaintext_blob,
- auth_flags, True);
+ "","",
+ "","",
+ "",
+ NULL, NULL,
+ NULL, NULL,
+ NULL,
+ True);
return NT_STATUS_IS_OK(nt_status) ? True : False;
}
DEBUGC(dbg_class, dbg_lev, ("NT user token of user %s\n",
sid_to_string(sid_str, &token->user_sids[0]) ));
- DEBUGADDC(dbg_class, dbg_lev, ("contains %i SIDs\n", token->num_sids));
+ DEBUGADDC(dbg_class, dbg_lev, ("contains %lu SIDs\n", (unsigned long)token->num_sids));
for (i = 0; i < token->num_sids; i++)
- DEBUGADDC(dbg_class, dbg_lev, ("SID[%3i]: %s\n", i,
+ DEBUGADDC(dbg_class, dbg_lev, ("SID[%3lu]: %s\n", (unsigned long)i,
sid_to_string(sid_str, &token->user_sids[i])));
}
return NULL;
}
- group_sids = malloc(sizeof(DOM_SID) * ngroups);
+ group_sids = malloc(sizeof(DOM_SID) * ngroups);
if (!group_sids) {
DEBUG(0, ("create_nt_token: malloc() failed for DOM_SID list!\n"));
return NULL;
nt_status = make_server_info_sam(server_info, sampass);
if (NT_STATUS_IS_OK(nt_status)) {
+ static const char zeros[16];
(*server_info)->guest = True;
+
+ /* annoying, but the Guest really does have a session key,
+ and it is all zeros! */
+ (*server_info)->user_session_key = data_blob(zeros, sizeof(zeros));
+ (*server_info)->lm_session_key = data_blob(zeros, sizeof(zeros));
}
+
return nt_status;
}
NT_USER_TOKEN *nt_user_token;
- uint8 session_key[16];
+ DATA_BLOB session_key;
char *session_keystr; /* used by utmp and pam session code.
TDB key string */
--- /dev/null
+/*
+ Unix SMB/CIFS implementation.
+ Password and authentication handling
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Andrew Bartlett 2001-2003
+ Copyright (C) Gerald Carter 2003
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_AUTH
+
+/****************************************************************************
+ Core of smb password checking routine.
+****************************************************************************/
+
+static BOOL smb_pwd_check_ntlmv1(const DATA_BLOB *nt_response,
+ const uchar *part_passwd,
+ const DATA_BLOB *sec_blob,
+ DATA_BLOB *user_sess_key)
+{
+ /* Finish the encryption of part_passwd. */
+ uchar p24[24];
+
+ if (part_passwd == NULL) {
+ DEBUG(10,("No password set - DISALLOWING access\n"));
+ /* No password set - always false ! */
+ return False;
+ }
+
+ if (sec_blob->length != 8) {
+ DEBUG(0, ("smb_pwd_check_ntlmv1: incorrect challenge size (%lu)\n",
+ (unsigned long)sec_blob->length));
+ return False;
+ }
+
+ if (nt_response->length != 24) {
+ DEBUG(0, ("smb_pwd_check_ntlmv1: incorrect password length (%lu)\n",
+ (unsigned long)nt_response->length));
+ return False;
+ }
+
+ SMBOWFencrypt(part_passwd, sec_blob->data, p24);
+ if (user_sess_key != NULL) {
+ *user_sess_key = data_blob(NULL, 16);
+ SMBsesskeygen_ntv1(part_passwd, NULL, user_sess_key->data);
+ }
+
+
+#if DEBUG_PASSWORD
+ DEBUG(100,("Part password (P16) was |\n"));
+ dump_data(100, part_passwd, 16);
+ DEBUGADD(100,("Password from client was |\n"));
+ dump_data(100, nt_response->data, nt_response->length);
+ DEBUGADD(100,("Given challenge was |\n"));
+ dump_data(100, sec_blob->data, sec_blob->length);
+ DEBUGADD(100,("Value from encryption was |\n"));
+ dump_data(100, p24, 24);
+#endif
+ return (memcmp(p24, nt_response->data, 24) == 0);
+}
+
+/****************************************************************************
+ Core of smb password checking routine. (NTLMv2, LMv2)
+ Note: The same code works with both NTLMv2 and LMv2.
+****************************************************************************/
+
+static BOOL smb_pwd_check_ntlmv2(const DATA_BLOB *ntv2_response,
+ const uchar *part_passwd,
+ const DATA_BLOB *sec_blob,
+ const char *user, const char *domain,
+ BOOL upper_case_domain, /* should the domain be transformed into upper case? */
+ DATA_BLOB *user_sess_key)
+{
+ /* Finish the encryption of part_passwd. */
+ uchar kr[16];
+ uchar value_from_encryption[16];
+ uchar client_response[16];
+ DATA_BLOB client_key_data;
+
+ if (part_passwd == NULL) {
+ DEBUG(10,("No password set - DISALLOWING access\n"));
+ /* No password set - always False */
+ return False;
+ }
+
+ if (sec_blob->length != 8) {
+ DEBUG(0, ("smb_pwd_check_ntlmv2: incorrect challenge size (%lu)\n",
+ (unsigned long)sec_blob->length));
+ return False;
+ }
+
+ if (ntv2_response->length < 24) {
+ /* We MUST have more than 16 bytes, or the stuff below will go
+ crazy. No known implementation sends less than the 24 bytes
+ for LMv2, let alone NTLMv2. */
+ DEBUG(0, ("smb_pwd_check_ntlmv2: incorrect password length (%lu)\n",
+ (unsigned long)ntv2_response->length));
+ return False;
+ }
+
+ client_key_data = data_blob(ntv2_response->data+16, ntv2_response->length-16);
+ /*
+ todo: should we be checking this for anything? We can't for LMv2,
+ but for NTLMv2 it is meant to contain the current time etc.
+ */
+
+ memcpy(client_response, ntv2_response->data, sizeof(client_response));
+
+ if (!ntv2_owf_gen(part_passwd, user, domain, upper_case_domain, kr)) {
+ return False;
+ }
+
+ SMBOWFencrypt_ntv2(kr, sec_blob, &client_key_data, value_from_encryption);
+ if (user_sess_key != NULL) {
+ *user_sess_key = data_blob(NULL, 16);
+ SMBsesskeygen_ntv2(kr, value_from_encryption, user_sess_key->data);
+ }
+
+#if DEBUG_PASSWORD
+ DEBUG(100,("Part password (P16) was |\n"));
+ dump_data(100, part_passwd, 16);
+ DEBUGADD(100,("Password from client was |\n"));
+ dump_data(100, ntv2_response->data, ntv2_response->length);
+ DEBUGADD(100,("Variable data from client was |\n"));
+ dump_data(100, client_key_data.data, client_key_data.length);
+ DEBUGADD(100,("Given challenge was |\n"));
+ dump_data(100, sec_blob->data, sec_blob->length);
+ DEBUGADD(100,("Value from encryption was |\n"));
+ dump_data(100, value_from_encryption, 16);
+#endif
+ data_blob_clear_free(&client_key_data);
+ return (memcmp(value_from_encryption, client_response, 16) == 0);
+}
+
+/**
+ * Check a challenge-response password against the value of the NT or
+ * LM password hash.
+ *
+ * @param mem_ctx talloc context
+ * @param challenge 8-byte challenge. If all zero, forces plaintext comparison
+ * @param nt_response 'unicode' NT response to the challenge, or unicode password
+ * @param lm_response ASCII or LANMAN response to the challenge, or password in DOS code page
+ * @param username internal Samba username, for log messages
+ * @param client_username username the client used
+ * @param client_domain domain name the client used (may be mapped)
+ * @param nt_pw MD4 unicode password from our passdb or similar
+ * @param lm_pw LANMAN ASCII password from our passdb or similar
+ * @param user_sess_key User session key
+ * @param lm_sess_key LM session key (first 8 bytes of the LM hash)
+ */
+
+NTSTATUS ntlm_password_check(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *challenge,
+ const DATA_BLOB *lm_response,
+ const DATA_BLOB *nt_response,
+ const DATA_BLOB *lm_interactive_pwd,
+ const DATA_BLOB *nt_interactive_pwd,
+ const char *username,
+ const char *client_username,
+ const char *client_domain,
+ const uint8 *lm_pw, const uint8 *nt_pw,
+ DATA_BLOB *user_sess_key,
+ DATA_BLOB *lm_sess_key)
+{
+ static const unsigned char zeros[8];
+ if (nt_pw == NULL) {
+ DEBUG(3,("ntlm_password_check: NO NT password stored for user %s.\n",
+ username));
+ }
+
+ if (nt_interactive_pwd && nt_interactive_pwd->length && nt_pw) {
+ if (nt_interactive_pwd->length != 16) {
+ DEBUG(3,("ntlm_password_check: Interactive logon: Invalid NT password length (%d) supplied for user %s\n", (int)nt_interactive_pwd->length,
+ username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ if (memcmp(nt_interactive_pwd->data, nt_pw, 16) == 0) {
+ if (user_sess_key) {
+ *user_sess_key = data_blob(NULL, 16);
+ SMBsesskeygen_ntv1(nt_pw, NULL, user_sess_key->data);
+ }
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(3,("ntlm_password_check: Interactive logon: NT password check failed for user %s\n",
+ username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ } else if (lm_interactive_pwd && lm_interactive_pwd->length && lm_pw) {
+ if (lm_interactive_pwd->length != 16) {
+ DEBUG(3,("ntlm_password_check: Interactive logon: Invalid LANMAN password length (%d) supplied for user %s\n", (int)lm_interactive_pwd->length,
+ username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ if (!lp_lanman_auth()) {
+ DEBUG(3,("ntlm_password_check: Interactive logon: only LANMAN password supplied for user %s, and LM passwords are disabled!\n",
+ username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ if (memcmp(lm_interactive_pwd->data, lm_pw, 16) == 0) {
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(3,("ntlm_password_check: Interactive logon: LANMAN password check failed for user %s\n",
+ username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+ }
+
+ /* Check for cleartext netlogon. Used by Exchange 5.5. */
+ if (challenge->length == sizeof(zeros) &&
+ (memcmp(challenge->data, zeros, challenge->length) == 0 )) {
+
+ DEBUG(4,("ntlm_password_check: checking plaintext passwords for user %s\n",
+ username));
+ if (nt_pw && nt_response->length) {
+ unsigned char pwhash[16];
+ mdfour(pwhash, nt_response->data, nt_response->length);
+ if (memcmp(pwhash, nt_pw, sizeof(pwhash)) == 0) {
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(3,("ntlm_password_check: NT (Unicode) plaintext password check failed for user %s\n",
+ username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ } else if (!lp_lanman_auth()) {
+ DEBUG(3,("ntlm_password_check: (plaintext password check) LANMAN passwords NOT PERMITTED for user %s\n",
+ username));
+
+ } else if (lm_pw && lm_response->length) {
+ uchar dospwd[14];
+ uchar p16[16];
+ ZERO_STRUCT(dospwd);
+
+ memcpy(dospwd, lm_response->data, MIN(lm_response->length, sizeof(dospwd)));
+ /* Only the fisrt 14 chars are considered, password need not be null terminated. */
+
+ /* we *might* need to upper-case the string here */
+ E_P16((const unsigned char *)dospwd, p16);
+
+ if (memcmp(p16, lm_pw, sizeof(p16)) == 0) {
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(3,("ntlm_password_check: LANMAN (ASCII) plaintext password check failed for user %s\n",
+ username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+ } else {
+ DEBUG(3, ("Plaintext authentication for user %s attempted, but neither NT nor LM passwords available\n", username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+ }
+
+ if (nt_response->length != 0 && nt_response->length < 24) {
+ DEBUG(2,("ntlm_password_check: invalid NT password length (%lu) for user %s\n",
+ (unsigned long)nt_response->length, username));
+ }
+
+ if (nt_response->length >= 24 && nt_pw) {
+ if (nt_response->length > 24) {
+ /* We have the NT MD4 hash challenge available - see if we can
+ use it
+ */
+ DEBUG(4,("ntlm_password_check: Checking NTLMv2 password with domain [%s]\n", client_domain));
+ if (smb_pwd_check_ntlmv2( nt_response,
+ nt_pw, challenge,
+ client_username,
+ client_domain,
+ False,
+ user_sess_key)) {
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(4,("ntlm_password_check: Checking NTLMv2 password with uppercased version of domain [%s]\n", client_domain));
+ if (smb_pwd_check_ntlmv2( nt_response,
+ nt_pw, challenge,
+ client_username,
+ client_domain,
+ True,
+ user_sess_key)) {
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(4,("ntlm_password_check: Checking NTLMv2 password without a domain\n"));
+ if (smb_pwd_check_ntlmv2( nt_response,
+ nt_pw, challenge,
+ client_username,
+ "",
+ False,
+ user_sess_key)) {
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(3,("ntlm_password_check: NTLMv2 password check failed\n"));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+ }
+
+ if (lp_ntlm_auth()) {
+ /* We have the NT MD4 hash challenge available - see if we can
+ use it (ie. does it exist in the smbpasswd file).
+ */
+ DEBUG(4,("ntlm_password_check: Checking NT MD4 password\n"));
+ if (smb_pwd_check_ntlmv1(nt_response,
+ nt_pw, challenge,
+ user_sess_key)) {
+ /* The LM session key for this response is not very secure,
+ so use it only if we otherwise allow LM authentication */
+
+ if (lp_lanman_auth() && lm_pw) {
+ uint8 first_8_lm_hash[16];
+ memcpy(first_8_lm_hash, lm_pw, 8);
+ memset(first_8_lm_hash + 8, '\0', 8);
+ *lm_sess_key = data_blob(first_8_lm_hash, 16);
+ }
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(3,("ntlm_password_check: NT MD4 password check failed for user %s\n",
+ username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+ } else {
+ DEBUG(2,("ntlm_password_check: NTLMv1 passwords NOT PERMITTED for user %s\n",
+ username));
+ /* no return, becouse we might pick up LMv2 in the LM field */
+ }
+ }
+
+ if (lm_response->length == 0) {
+ DEBUG(3,("ntlm_password_check: NEITHER LanMan nor NT password supplied for user %s\n",
+ username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ if (lm_response->length < 24) {
+ DEBUG(2,("ntlm_password_check: invalid LanMan password length (%lu) for user %s\n",
+ (unsigned long)nt_response->length, username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ if (!lp_lanman_auth()) {
+ DEBUG(3,("ntlm_password_check: Lanman passwords NOT PERMITTED for user %s\n",
+ username));
+ } else if (!lm_pw) {
+ DEBUG(3,("ntlm_password_check: NO LanMan password set for user %s (and no NT password supplied)\n",
+ username));
+ } else {
+ DEBUG(4,("ntlm_password_check: Checking LM password\n"));
+ if (smb_pwd_check_ntlmv1(lm_response,
+ lm_pw, challenge,
+ NULL)) {
+ uint8 first_8_lm_hash[16];
+ memcpy(first_8_lm_hash, lm_pw, 8);
+ memset(first_8_lm_hash + 8, '\0', 8);
+ *user_sess_key = data_blob(first_8_lm_hash, 16);
+ *lm_sess_key = data_blob(first_8_lm_hash, 16);
+ return NT_STATUS_OK;
+ }
+ }
+
+ if (!nt_pw) {
+ DEBUG(4,("ntlm_password_check: LM password check failed for user, no NT password %s\n",username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ /* This is for 'LMv2' authentication. almost NTLMv2 but limited to 24 bytes.
+ - related to Win9X, legacy NAS pass-though authentication
+ */
+ DEBUG(4,("ntlm_password_check: Checking LMv2 password with domain %s\n", client_domain));
+ if (smb_pwd_check_ntlmv2( lm_response,
+ nt_pw, challenge,
+ client_username,
+ client_domain,
+ False,
+ NULL)) {
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(4,("ntlm_password_check: Checking LMv2 password with upper-cased version of domain %s\n", client_domain));
+ if (smb_pwd_check_ntlmv2( lm_response,
+ nt_pw, challenge,
+ client_username,
+ client_domain,
+ True,
+ NULL)) {
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(4,("ntlm_password_check: Checking LMv2 password without a domain\n"));
+ if (smb_pwd_check_ntlmv2( lm_response,
+ nt_pw, challenge,
+ client_username,
+ "",
+ False,
+ NULL)) {
+ return NT_STATUS_OK;
+ }
+
+ /* Apparently NT accepts NT responses in the LM field
+ - I think this is related to Win9X pass-though authentication
+ */
+ DEBUG(4,("ntlm_password_check: Checking NT MD4 password in LM field\n"));
+ if (lp_ntlm_auth()) {
+ if (smb_pwd_check_ntlmv1(lm_response,
+ nt_pw, challenge,
+ NULL)) {
+ /* The session key for this response is still very odd.
+ It not very secure, so use it only if we otherwise
+ allow LM authentication */
+
+ if (lp_lanman_auth() && lm_pw) {
+ uint8 first_8_lm_hash[16];
+ memcpy(first_8_lm_hash, lm_pw, 8);
+ memset(first_8_lm_hash + 8, '\0', 8);
+ *user_sess_key = data_blob(first_8_lm_hash, 16);
+ *lm_sess_key = data_blob(first_8_lm_hash, 16);
+ }
+ return NT_STATUS_OK;
+ }
+ DEBUG(3,("ntlm_password_check: LM password, NT MD4 password in LM field and LMv2 failed for user %s\n",username));
+ } else {
+ DEBUG(3,("ntlm_password_check: LM password and LMv2 failed for user %s, and NT MD4 password in LM field not permitted\n",username));
+ }
+ return NT_STATUS_WRONG_PASSWORD;
+}
+
data_blob_free(&(*ntlmssp_state)->chal);
data_blob_free(&(*ntlmssp_state)->lm_resp);
data_blob_free(&(*ntlmssp_state)->nt_resp);
-
+ data_blob_free(&(*ntlmssp_state)->encrypted_session_key);
talloc_destroy(mem_ctx);
}
ntlmssp_state->unicode = False;
}
- if (neg_flags & NTLMSSP_NEGOTIATE_LM_KEY && allow_lm) {
+ if ((neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) && allow_lm) {
/* other end forcing us to use LM */
ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY;
ntlmssp_state->use_ntlmv2 = False;
ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
}
+ if (neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN) {
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
+ }
+
if (!(neg_flags & NTLMSSP_NEGOTIATE_NTLM2)) {
ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
- ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
}
if (!(neg_flags & NTLMSSP_NEGOTIATE_128)) {
ntlmssp_handle_neg_flags(ntlmssp_state, neg_flags, lp_lanman_auth());
- chal_flags = ntlmssp_state->neg_flags;
-
- target_name = ntlmssp_target_name(ntlmssp_state,
- neg_flags, &chal_flags);
- if (target_name == NULL)
- return NT_STATUS_INVALID_PARAMETER;
-
/* Ask our caller what challenge they would like in the packet */
cryptkey = ntlmssp_state->get_challenge(ntlmssp_state);
ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
}
+ /* The flags we send back are not just the negotiated flags,
+ * they are also 'what is in this packet'. Therfore, we
+ * operate on 'chal_flags' from here on
+ */
+
+ chal_flags = ntlmssp_state->neg_flags;
+
+ /* get the right name to fill in as 'target' */
+ target_name = ntlmssp_target_name(ntlmssp_state,
+ neg_flags, &chal_flags);
+ if (target_name == NULL)
+ return NT_STATUS_INVALID_PARAMETER;
+
ntlmssp_state->chal = data_blob_talloc(ntlmssp_state->mem_ctx, cryptkey, 8);
ntlmssp_state->internal_chal = data_blob_talloc(ntlmssp_state->mem_ctx, cryptkey, 8);
-
/* This should be a 'netbios domain -> DNS domain' mapping */
dnsdomname[0] = '\0';
dnsname[0] = '\0';
get_myfullname(dnsname);
- strlower_m(dnsname);
/* This creates the 'blob' of names that appears at the end of the packet */
if (chal_flags & NTLMSSP_CHAL_TARGET_INFO)
* @return Errors or NT_STATUS_OK.
*/
-static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state,
- const DATA_BLOB request, DATA_BLOB *reply)
+static NTSTATUS ntlmssp_server_preauth(struct ntlmssp_state *ntlmssp_state,
+ const DATA_BLOB request)
{
- DATA_BLOB encrypted_session_key = data_blob(NULL, 0);
- DATA_BLOB nt_session_key = data_blob(NULL, 0);
- DATA_BLOB lm_session_key = data_blob(NULL, 0);
- DATA_BLOB session_key = data_blob(NULL, 0);
uint32 ntlmssp_command, auth_flags;
NTSTATUS nt_status;
- /* used by NTLM2 */
- BOOL doing_ntlm2 = False;
-
- uchar session_nonce[16];
uchar session_nonce_hash[16];
const char *parse_string;
char *user = NULL;
char *workstation = NULL;
- /* parse the NTLMSSP packet */
- *reply = data_blob(NULL, 0);
-
#if 0
file_save("ntlmssp_auth.dat", request.data, request.length);
#endif
&domain,
&user,
&workstation,
- &encrypted_session_key,
+ &ntlmssp_state->encrypted_session_key,
&auth_flags)) {
DEBUG(1, ("ntlmssp_server_auth: failed to parse NTLMSSP:\n"));
dump_data(2, (const char *)request.data, request.length);
SAFE_FREE(domain);
SAFE_FREE(user);
SAFE_FREE(workstation);
- data_blob_free(&encrypted_session_key);
+ data_blob_free(&ntlmssp_state->encrypted_session_key);
auth_flags = 0;
/* Try again with a shorter string (Win9X truncates this packet) */
}
}
+ if (auth_flags)
+ ntlmssp_handle_neg_flags(ntlmssp_state, auth_flags, lp_lanman_auth());
+
if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, domain))) {
SAFE_FREE(domain);
SAFE_FREE(user);
SAFE_FREE(workstation);
- data_blob_free(&encrypted_session_key);
+ data_blob_free(&ntlmssp_state->encrypted_session_key);
return nt_status;
}
SAFE_FREE(domain);
SAFE_FREE(user);
SAFE_FREE(workstation);
- data_blob_free(&encrypted_session_key);
+ data_blob_free(&ntlmssp_state->encrypted_session_key);
return nt_status;
}
SAFE_FREE(domain);
SAFE_FREE(user);
SAFE_FREE(workstation);
- data_blob_free(&encrypted_session_key);
+ data_blob_free(&ntlmssp_state->encrypted_session_key);
return nt_status;
}
struct MD5Context md5_session_nonce_ctx;
SMB_ASSERT(ntlmssp_state->internal_chal.data && ntlmssp_state->internal_chal.length == 8);
- doing_ntlm2 = True;
+ ntlmssp_state->doing_ntlm2 = True;
- memcpy(session_nonce, ntlmssp_state->internal_chal.data, 8);
- memcpy(&session_nonce[8], ntlmssp_state->lm_resp.data, 8);
+ memcpy(ntlmssp_state->session_nonce, ntlmssp_state->internal_chal.data, 8);
+ memcpy(&ntlmssp_state->session_nonce[8], ntlmssp_state->lm_resp.data, 8);
MD5Init(&md5_session_nonce_ctx);
- MD5Update(&md5_session_nonce_ctx, session_nonce, 16);
+ MD5Update(&md5_session_nonce_ctx, ntlmssp_state->session_nonce, 16);
MD5Final(session_nonce_hash, &md5_session_nonce_ctx);
ntlmssp_state->chal = data_blob_talloc(ntlmssp_state->mem_ctx, session_nonce_hash, 8);
/* We changed the effective challenge - set it */
if (!NT_STATUS_IS_OK(nt_status = ntlmssp_state->set_challenge(ntlmssp_state, &ntlmssp_state->chal))) {
- data_blob_free(&encrypted_session_key);
+ data_blob_free(&ntlmssp_state->encrypted_session_key);
return nt_status;
}
}
}
+ return NT_STATUS_OK;
+}
- /* Finally, actually ask if the password is OK */
- if (!NT_STATUS_IS_OK(nt_status = ntlmssp_state->check_password(ntlmssp_state, &nt_session_key, &lm_session_key))) {
- data_blob_free(&encrypted_session_key);
- return nt_status;
- }
+/**
+ * Next state function for the Authenticate packet
+ *
+ * @param ntlmssp_state NTLMSSP State
+ * @param request The request, as a DATA_BLOB
+ * @param reply The reply, as an allocated DATA_BLOB, caller to free.
+ * @return Errors or NT_STATUS_OK.
+ */
+
+static NTSTATUS ntlmssp_server_postauth(struct ntlmssp_state *ntlmssp_state,
+ DATA_BLOB *user_session_key,
+ DATA_BLOB *lm_session_key,
+ DATA_BLOB *reply)
+{
+ NTSTATUS nt_status;
+ DATA_BLOB session_key = data_blob(NULL, 0);
+
+ /* parse the NTLMSSP packet */
+ *reply = data_blob(NULL, 0);
+
+ if (user_session_key)
+ dump_data_pw("USER session key:\n", user_session_key->data, user_session_key->length);
- dump_data_pw("NT session key:\n", nt_session_key.data, nt_session_key.length);
- dump_data_pw("LM first-8:\n", lm_session_key.data, lm_session_key.length);
+ if (lm_session_key)
+ dump_data_pw("LM first-8:\n", lm_session_key->data, lm_session_key->length);
/* Handle the different session key derivation for NTLM2 */
- if (doing_ntlm2) {
- if (nt_session_key.data && nt_session_key.length == 16) {
+ if (ntlmssp_state->doing_ntlm2) {
+ if (user_session_key && user_session_key->data && user_session_key->length == 16) {
session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16);
- hmac_md5(nt_session_key.data, session_nonce,
- sizeof(session_nonce), session_key.data);
+ hmac_md5(user_session_key->data, ntlmssp_state->session_nonce,
+ sizeof(ntlmssp_state->session_nonce), session_key.data);
+ DEBUG(10,("ntlmssp_server_auth: Created NTLM2 session key.\n"));
dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
-
+
+ } else {
+ DEBUG(10,("ntlmssp_server_auth: Failed to create NTLM2 session key.\n"));
+ session_key = data_blob(NULL, 0);
}
} else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) {
- if (lm_session_key.data && lm_session_key.length >= 8 &&
- ntlmssp_state->lm_resp.data && ntlmssp_state->lm_resp.length == 24) {
- session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16);
- SMBsesskeygen_lmv1(lm_session_key.data, ntlmssp_state->lm_resp.data,
- session_key.data);
- dump_data_pw("LM session key:\n", session_key.data, session_key.length);
+ if (lm_session_key && lm_session_key->data && lm_session_key->length >= 8) {
+ if (ntlmssp_state->lm_resp.data && ntlmssp_state->lm_resp.length == 24) {
+ session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16);
+ SMBsesskeygen_lm_sess_key(lm_session_key->data, ntlmssp_state->lm_resp.data,
+ session_key.data);
+ DEBUG(10,("ntlmssp_server_auth: Created NTLM session key.\n"));
+ dump_data_pw("LM session key:\n", session_key.data, session_key.length);
+ } else {
+ /* use the key unmodified - it's
+ * probably a NULL key from the guest
+ * login */
+ session_key = *lm_session_key;
+ }
+ } else {
+ DEBUG(10,("ntlmssp_server_auth: Failed to create NTLM session key.\n"));
+ session_key = data_blob(NULL, 0);
}
- } else if (nt_session_key.data) {
- session_key = nt_session_key;
+ } else if (user_session_key && user_session_key->data) {
+ session_key = *user_session_key;
+ DEBUG(10,("ntlmssp_server_auth: Using unmodified nt session key.\n"));
dump_data_pw("unmodified session key:\n", session_key.data, session_key.length);
+ } else if (lm_session_key && lm_session_key->data) {
+ session_key = *lm_session_key;
+ DEBUG(10,("ntlmssp_server_auth: Using unmodified lm session key.\n"));
+ dump_data_pw("unmodified session key:\n", session_key.data, session_key.length);
+ } else {
+ DEBUG(10,("ntlmssp_server_auth: Failed to create unmodified session key.\n"));
+ session_key = data_blob(NULL, 0);
}
/* With KEY_EXCH, the client supplies the proposed session key,
but encrypts it with the long-term key */
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
- if (!encrypted_session_key.data || encrypted_session_key.length != 16) {
- data_blob_free(&encrypted_session_key);
+ if (!ntlmssp_state->encrypted_session_key.data
+ || ntlmssp_state->encrypted_session_key.length != 16) {
+ data_blob_free(&ntlmssp_state->encrypted_session_key);
DEBUG(1, ("Client-supplied KEY_EXCH session key was of invalid length (%u)!\n",
- encrypted_session_key.length));
+ ntlmssp_state->encrypted_session_key.length));
return NT_STATUS_INVALID_PARAMETER;
} else if (!session_key.data || session_key.length != 16) {
DEBUG(5, ("server session key is invalid (len == %u), cannot do KEY_EXCH!\n",
session_key.length));
+ ntlmssp_state->session_key = session_key;
} else {
- dump_data_pw("KEY_EXCH session key (enc):\n", encrypted_session_key.data, encrypted_session_key.length);
- SamOEMhash(encrypted_session_key.data,
+ dump_data_pw("KEY_EXCH session key (enc):\n",
+ ntlmssp_state->encrypted_session_key.data,
+ ntlmssp_state->encrypted_session_key.length);
+ SamOEMhash(ntlmssp_state->encrypted_session_key.data,
session_key.data,
- encrypted_session_key.length);
+ ntlmssp_state->encrypted_session_key.length);
ntlmssp_state->session_key = data_blob_talloc(ntlmssp_state->mem_ctx,
- encrypted_session_key.data,
- encrypted_session_key.length);
- dump_data_pw("KEY_EXCH session key:\n", session_key.data, session_key.length);
+ ntlmssp_state->encrypted_session_key.data,
+ ntlmssp_state->encrypted_session_key.length);
+ dump_data_pw("KEY_EXCH session key:\n", ntlmssp_state->encrypted_session_key.data,
+ ntlmssp_state->encrypted_session_key.length);
}
} else {
ntlmssp_state->session_key = session_key;
}
- data_blob_free(&encrypted_session_key);
+ nt_status = ntlmssp_sign_init(ntlmssp_state);
+
+ data_blob_free(&ntlmssp_state->encrypted_session_key);
/* allow arbitarily many authentications */
ntlmssp_state->expected_state = NTLMSSP_AUTH;
return nt_status;
}
+
+/**
+ * Next state function for the Authenticate packet
+ *
+ * @param ntlmssp_state NTLMSSP State
+ * @param request The request, as a DATA_BLOB
+ * @param reply The reply, as an allocated DATA_BLOB, caller to free.
+ * @return Errors or NT_STATUS_OK.
+ */
+
+static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state,
+ const DATA_BLOB request, DATA_BLOB *reply)
+{
+ DATA_BLOB user_session_key = data_blob(NULL, 0);
+ DATA_BLOB lm_session_key = data_blob(NULL, 0);
+ NTSTATUS nt_status;
+
+ /* parse the NTLMSSP packet */
+ *reply = data_blob(NULL, 0);
+
+ if (!NT_STATUS_IS_OK(nt_status = ntlmssp_server_preauth(ntlmssp_state, request))) {
+ return nt_status;
+ }
+
+ /*
+ * Note we don't check here for NTLMv2 auth settings. If NTLMv2 auth
+ * is required (by "ntlm auth = no" and "lm auth = no" being set in the
+ * smb.conf file) and no NTLMv2 response was sent then the password check
+ * will fail here. JRA.
+ */
+
+ /* Finally, actually ask if the password is OK */
+
+ if (!NT_STATUS_IS_OK(nt_status = ntlmssp_state->check_password(ntlmssp_state,
+ &user_session_key, &lm_session_key))) {
+ return nt_status;
+ }
+
+ return ntlmssp_server_postauth(ntlmssp_state, &user_session_key, &lm_session_key, reply);
+}
+
/**
* Create an NTLMSSP state machine
*
}
if (!ntlmssp_state->password) {
+ static const uchar zeros[16];
/* do nothing - blobs are zero length */
+
+ /* session key is all zeros */
+ session_key = data_blob_talloc(ntlmssp_state->mem_ctx, zeros, 16);
+
+ /* not doing NLTM2 without a password */
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
} else if (ntlmssp_state->use_ntlmv2) {
if (!struct_blob.length) {
uchar nt_hash[16];
uchar session_nonce[16];
uchar session_nonce_hash[16];
- uchar nt_session_key[16];
+ uchar user_session_key[16];
E_md4hash(ntlmssp_state->password, nt_hash);
lm_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24);
DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
DEBUG(5, ("challenge is: \n"));
- dump_data(5, session_nonce_hash, 8);
+ dump_data(5, (const char *)session_nonce_hash, 8);
nt_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24);
SMBNTencrypt(ntlmssp_state->password,
session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16);
- SMBsesskeygen_ntv1(nt_hash, NULL, nt_session_key);
- hmac_md5(nt_session_key, session_nonce, sizeof(session_nonce), session_key.data);
+ SMBsesskeygen_ntv1(nt_hash, NULL, user_session_key);
+ hmac_md5(user_session_key, session_nonce, sizeof(session_nonce), session_key.data);
dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
} else {
/* Key exchange encryptes a new client-generated session key with
the password-derived key */
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
+ /* Make up a new session key */
uint8 client_session_key[16];
-
- generate_random_buffer(client_session_key, sizeof(client_session_key), False);
+ generate_random_buffer(client_session_key, sizeof(client_session_key), False);
+
+ /* Encrypt the new session key with the old one */
encrypted_session_key = data_blob(client_session_key, sizeof(client_session_key));
dump_data_pw("KEY_EXCH session key:\n", encrypted_session_key.data, encrypted_session_key.length);
-
SamOEMhash(encrypted_session_key.data, session_key.data, encrypted_session_key.length);
+ dump_data_pw("KEY_EXCH session key (enc):\n", encrypted_session_key.data, encrypted_session_key.length);
+
+ /* Mark the new session key as the 'real' session key */
data_blob_free(&session_key);
session_key = data_blob_talloc(ntlmssp_state->mem_ctx, client_session_key, sizeof(client_session_key));
- dump_data_pw("KEY_EXCH session key (enc):\n", encrypted_session_key.data, encrypted_session_key.length);
}
/* this generates the actual auth packet */
*ntlmssp_state = talloc_zero(mem_ctx, sizeof(**ntlmssp_state));
if (!*ntlmssp_state) {
- DEBUG(0,("ntlmssp_server_start: talloc failed!\n"));
+ DEBUG(0,("ntlmssp_client_start: talloc failed!\n"));
talloc_destroy(mem_ctx);
return NT_STATUS_NO_MEMORY;
}
DATA_BLOB session_key;
uint32 neg_flags; /* the current state of negotiation with the NTLMSSP partner */
+
+ /* internal variables used by NTLM2 */
+ BOOL doing_ntlm2;
+ uchar session_nonce[16];
+
+ /* internal variables used by KEY_EXCH (client-supplied user session key */
+ DATA_BLOB encrypted_session_key;
void *auth_context;
/* if odd length and unicode */
return False;
}
-
+ if (blob->data + ptr < (uint8 *)ptr || blob->data + ptr < blob->data)
+ return False;
+
if (0 < len1) {
pull_string(NULL, p, blob->data + ptr, sizeof(p),
len1,
if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
return False;
}
-
+
+ if (blob->data + ptr < (uint8 *)ptr || blob->data + ptr < blob->data)
+ return False;
+
if (0 < len1) {
pull_string(NULL, p, blob->data + ptr, sizeof(p),
len1,
if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
return False;
}
+
+ if (blob->data + ptr < (uint8 *)ptr || blob->data + ptr < blob->data)
+ return False;
+
*b = data_blob(blob->data + ptr, len1);
}
break;
len1 = va_arg(ap, unsigned);
/* make sure its in the right format - be strict */
NEED_DATA(len1);
+ if (blob->data + head_ofs < (uint8 *)head_ofs || blob->data + head_ofs < blob->data)
+ return False;
+
*b = data_blob(blob->data + head_ofs, len1);
head_ofs += len1;
break;
break;
case 'C':
s = va_arg(ap, char *);
+
+ if (blob->data + head_ofs < (uint8 *)head_ofs || blob->data + head_ofs < blob->data)
+ return False;
+
head_ofs += pull_string(NULL, p, blob->data+head_ofs, sizeof(p),
blob->length - head_ofs,
STR_ASCII|STR_TERMINATE);
hash[257] = index_j;
}
-static void calc_hash(unsigned char *hash, const char *k2, int k2l)
+static void calc_hash(unsigned char hash[258], const char *k2, int k2l)
{
unsigned char j = 0;
int ind;
hash[257] = 0;
}
-static void calc_ntlmv2_hash(unsigned char hash[16], char digest[16],
+static void calc_ntlmv2_hash(unsigned char hash[258], unsigned char digest[16],
DATA_BLOB session_key,
const char *constant)
{
MD5Init(&ctx3);
MD5Update(&ctx3, session_key.data, session_key.length);
- MD5Update(&ctx3, (const unsigned char *)constant, strlen(constant));
- MD5Final((unsigned char *)digest, &ctx3);
+ MD5Update(&ctx3, (const unsigned char *)constant, strlen(constant)+1);
+ MD5Final(digest, &ctx3);
calc_hash(hash, digest, 16);
}
{
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
HMACMD5Context ctx;
- char seq_num[4];
+ uchar seq_num[4];
uchar digest[16];
SIVAL(seq_num, 0, ntlmssp_state->ntlmssp_seq_num);
hmac_md5_init_limK_to_64((const unsigned char *)(ntlmssp_state->send_sign_const), 16, &ctx);
- hmac_md5_update((const unsigned char *)seq_num, 4, &ctx);
+ hmac_md5_update(seq_num, 4, &ctx);
hmac_md5_update(data, length, &ctx);
hmac_md5_final(digest, &ctx);
, ntlmssp_state->ntlmssp_seq_num)) {
return NT_STATUS_NO_MEMORY;
}
- switch (direction) {
- case NTLMSSP_SEND:
- NTLMSSPcalc_ap(ntlmssp_state->send_sign_hash, sig->data+4, sig->length-4);
- break;
- case NTLMSSP_RECEIVE:
- NTLMSSPcalc_ap(ntlmssp_state->recv_sign_hash, sig->data+4, sig->length-4);
- break;
+
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
+ switch (direction) {
+ case NTLMSSP_SEND:
+ NTLMSSPcalc_ap(ntlmssp_state->send_sign_hash, sig->data+4, sig->length-4);
+ break;
+ case NTLMSSP_RECEIVE:
+ NTLMSSPcalc_ap(ntlmssp_state->recv_sign_hash, sig->data+4, sig->length-4);
+ break;
+ }
}
} else {
uint32 crc;
}
NTSTATUS ntlmssp_sign_packet(NTLMSSP_STATE *ntlmssp_state,
- const uchar *data, size_t length,
- DATA_BLOB *sig)
+ const uchar *data, size_t length,
+ DATA_BLOB *sig)
{
- NTSTATUS nt_status = ntlmssp_make_packet_signature(ntlmssp_state, data, length, NTLMSSP_SEND, sig);
+ NTSTATUS nt_status;
+ if (!ntlmssp_state->session_key.length) {
+ DEBUG(3, ("NO session key, cannot check sign packet\n"));
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ nt_status = ntlmssp_make_packet_signature(ntlmssp_state, data, length, NTLMSSP_SEND, sig);
/* increment counter on send */
ntlmssp_state->ntlmssp_seq_num++;
DATA_BLOB local_sig;
NTSTATUS nt_status;
+ if (!ntlmssp_state->session_key.length) {
+ DEBUG(3, ("NO session key, cannot check packet signature\n"));
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
if (sig->length < 8) {
DEBUG(0, ("NTLMSSP packet check failed due to short signature (%lu bytes)!\n",
(unsigned long)sig->length));
return NT_STATUS_ACCESS_DENIED;
}
- data_blob_free(&local_sig);
-
/* increment counter on recieive */
ntlmssp_state->ntlmssp_seq_num++;
uchar *data, size_t length,
DATA_BLOB *sig)
{
+ if (!ntlmssp_state->session_key.length) {
+ DEBUG(3, ("NO session key, cannot seal packet\n"));
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
DEBUG(10,("ntlmssp_seal_data: seal\n"));
dump_data_pw("ntlmssp clear data\n", data, length);
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
uchar *data, size_t length,
DATA_BLOB *sig)
{
+ if (!ntlmssp_state->session_key.length) {
+ DEBUG(3, ("NO session key, cannot unseal packet\n"));
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
DEBUG(10,("ntlmssp__unseal_data: seal\n"));
dump_data_pw("ntlmssp sealed data\n", data, length);
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
DEBUG(3, ("NTLMSSP Sign/Seal - Initialising with flags:\n"));
debug_ntlmssp_flags(ntlmssp_state->neg_flags);
+ if (!ntlmssp_state->session_key.length) {
+ DEBUG(3, ("NO session key, cannot intialise signing\n"));
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2)
{
const char *send_sign_const;
calc_ntlmv2_hash(ntlmssp_state->recv_sign_hash,
ntlmssp_state->recv_sign_const,
- ntlmssp_state->session_key, send_sign_const);
+ ntlmssp_state->session_key, recv_sign_const);
dump_data_pw("NTLMSSP receive sign hash:\n",
ntlmssp_state->recv_sign_hash,
sizeof(ntlmssp_state->recv_sign_hash));
calc_ntlmv2_hash(ntlmssp_state->recv_seal_hash,
ntlmssp_state->recv_seal_const,
- ntlmssp_state->session_key, send_seal_const);
+ ntlmssp_state->session_key, recv_seal_const);
dump_data_pw("NTLMSSP receive seal hash:\n",
ntlmssp_state->recv_sign_hash,
sizeof(ntlmssp_state->recv_sign_hash));
SMB_SUBSYSTEM(LIBCLI_AUTH,[],
[libcli/auth/ntlmssp.o libcli/auth/ntlmssp_parse.o \
libcli/auth/ntlmssp_sign.o libcli/auth/schannel.o \
- libcli/auth/credentials.o libcli/auth/session.o],
+ libcli/auth/credentials.o libcli/auth/session.o \
+ libcli/auth/ntlm_check.o],
libcli/auth/libcli_auth_public_proto.h)
SMB_SUBSYSTEM(LIBCLI_NMB,[],
/*
This implements the X/Open SMB password encryption
It takes a password ('unix' string), a 8 byte "crypt key"
- and puts 24 bytes of encrypted password into p24 */
-void SMBencrypt(const char *passwd, const uchar *c8, uchar p24[24])
+ and puts 24 bytes of encrypted password into p24
+
+ Returns False if password must have been truncated to create LM hash
+*/
+BOOL SMBencrypt(const char *passwd, const uchar *c8, uchar p24[24])
{
+ BOOL ret;
uchar p21[21];
memset(p21,'\0',21);
- E_deshash(passwd, p21);
+ ret = E_deshash(passwd, p21);
SMBOWFencrypt(p21, c8, p24);
dump_data(100, (const char *)c8, 8);
dump_data(100, (char *)p24, 24);
#endif
+
+ return ret;
}
/**
* Creates the DES forward-only Hash of the users password in DOS ASCII charset
* @param passwd password in 'unix' charset.
* @param p16 return password hashed with DES, caller allocated 16 byte buffer
+ * @return False if password was > 14 characters, and therefore may be incorrect, otherwise True
+ * @note p16 is filled in regardless
*/
-void E_deshash(const char *passwd, uchar p16[16])
+BOOL E_deshash(const char *passwd, uchar p16[16])
{
+ BOOL ret = True;
fstring dospwd;
ZERO_STRUCT(dospwd);
/* Password must be converted to DOS charset - null terminated, uppercase. */
push_ascii(dospwd, passwd, sizeof(dospwd), STR_UPPER|STR_TERMINATE);
-
+
/* Only the fisrt 14 chars are considered, password need not be null terminated. */
E_P16((const unsigned char *)dospwd, p16);
+ if (strlen(dospwd) > 14) {
+ ret = False;
+ }
+
ZERO_STRUCT(dospwd);
+
+ return ret;
}
/**
/* Does both the NTLMv2 owfs of a user's password */
BOOL ntv2_owf_gen(const uchar owf[16],
- const char *user_in, const char *domain_in, uchar kr_buf[16])
+ const char *user_in, const char *domain_in,
+ BOOL upper_case_domain, /* Transform the domain into UPPER case */
+ uchar kr_buf[16])
{
smb_ucs2_t *user;
smb_ucs2_t *domain;
}
strupper_w(user);
- strupper_w(domain);
+
+ if (upper_case_domain)
+ strupper_w(domain);
SMB_ASSERT(user_byte_len >= 2);
SMB_ASSERT(domain_byte_len >= 2);
#endif
}
-BOOL make_oem_passwd_hash(char data[516], const char *passwd,
- const uchar old_pw_hash[16],
- BOOL unicode)
-{
- int new_pw_len = strlen(passwd) * (unicode ? 2 : 1);
-
- if (new_pw_len > 512)
- {
- DEBUG(0,("make_oem_passwd_hash: new password is too long.\n"));
- return False;
- }
-
- /*
- * Now setup the data area.
- * We need to generate a random fill
- * for this area to make it harder to
- * decrypt. JRA.
- */
- generate_random_buffer((unsigned char *)data, 516, False);
- push_string(NULL, &data[512 - new_pw_len], passwd, new_pw_len,
- STR_NOALIGN | (unicode?STR_UNICODE:STR_ASCII));
- SIVAL(data, 512, new_pw_len);
-
-#ifdef DEBUG_PASSWORD
- DEBUG(100,("make_oem_passwd_hash\n"));
- dump_data(100, data, 516);
-#endif
- SamOEMhash((unsigned char *)data,
- (const unsigned char *)old_pw_hash,
- 516);
-
- return True;
-}
-
/* Does the md5 encryption from the Key Response for NTLMv2. */
void SMBOWFencrypt_ntv2(const uchar kr[16],
const DATA_BLOB *srv_chal,
#endif
}
+void SMBsesskeygen_lm_sess_key(const uchar lm_hash[16],
+ const uchar lm_resp[24], /* only uses 8 */
+ uint8 sess_key[16])
+{
+ uchar p24[24];
+ uchar partial_lm_hash[16];
+
+ memcpy(partial_lm_hash, lm_hash, 8);
+ memset(partial_lm_hash + 8, 0xbd, 8);
+
+ SMBOWFencrypt(partial_lm_hash, lm_resp, p24);
+
+ memcpy(sess_key, p24, 16);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("SMBsesskeygen_lmv1_jerry:\n"));
+ dump_data(100, sess_key, 16);
+#endif
+}
+
DATA_BLOB NTLMv2_generate_names_blob(const char *hostname,
const char *domain)
{
DATA_BLOB names_blob = data_blob(NULL, 0);
msrpc_gen(&names_blob, "aaa",
- True, NTLMSSP_NAME_TYPE_DOMAIN, domain,
- True, NTLMSSP_NAME_TYPE_SERVER, hostname,
- True, 0, "");
+ NTLMSSP_NAME_TYPE_DOMAIN, domain,
+ NTLMSSP_NAME_TYPE_SERVER, hostname,
+ 0, "");
return names_blob;
}
const DATA_BLOB *server_chal,
const DATA_BLOB *names_blob,
DATA_BLOB *lm_response, DATA_BLOB *nt_response,
- DATA_BLOB *nt_session_key)
+ DATA_BLOB *user_session_key)
{
uchar nt_hash[16];
uchar ntlm_v2_hash[16];
the username and domain.
This prevents username swapping during the auth exchange
*/
- if (!ntv2_owf_gen(nt_hash, user, domain, ntlm_v2_hash)) {
+ if (!ntv2_owf_gen(nt_hash, user, domain, True, ntlm_v2_hash)) {
return False;
}
if (nt_response) {
*nt_response = NTLMv2_generate_response(ntlm_v2_hash, server_chal,
names_blob);
- if (nt_session_key) {
- *nt_session_key = data_blob(NULL, 16);
+ if (user_session_key) {
+ *user_session_key = data_blob(NULL, 16);
/* The NTLMv2 calculations also provide a session key, for signing etc later */
/* use only the first 16 bytes of nt_response for session key */
- SMBsesskeygen_ntv2(ntlm_v2_hash, nt_response->data, nt_session_key->data);
+ SMBsesskeygen_ntv2(ntlm_v2_hash, nt_response->data, user_session_key->data);
}
}
new_pw_len = push_string(NULL, new_pw,
password,
sizeof(new_pw), string_flags);
- if (new_pw_len > 512) {
- return False;
- }
memcpy(&buffer[512 - new_pw_len], new_pw, new_pw_len);
returned password including termination.
************************************************************/
BOOL decode_pw_buffer(char in_buffer[516], char *new_pwrd,
- int new_pwrd_size, uint32 *new_pw_len)
+ int new_pwrd_size, uint32 *new_pw_len,
+ int string_flags)
{
int byte_len=0;
/*
Warning !!! : This function is called from some rpc call.
- The password IN the buffer is a UNICODE string.
+ The password IN the buffer may be a UNICODE string.
The password IN new_pwrd is an ASCII string
If you reuse that code somewhere else check first.
*/
dump_data(100, in_buffer, 516);
#endif
- /* Password cannot be longer than 128 characters */
- if ( (byte_len < 0) || (byte_len > new_pwrd_size - 1)) {
+ /* Password cannot be longer than the size of the password buffer */
+ if ( (byte_len < 0) || (byte_len > 512)) {
DEBUG(0, ("decode_pw_buffer: incorrect password length (%d).\n", byte_len));
DEBUG(0, ("decode_pw_buffer: check that 'encrypt passwords = yes'\n"));
return False;
}
- /* decode into the return buffer. Buffer must be a pstring */
- *new_pw_len = pull_string(NULL, new_pwrd, &in_buffer[512 - byte_len], new_pwrd_size, byte_len, STR_UNICODE);
+ /* decode into the return buffer. Buffer length supplied */
+ *new_pw_len = pull_string(NULL, new_pwrd, &in_buffer[512 - byte_len], new_pwrd_size,
+ byte_len, string_flags);
#ifdef DEBUG_PASSWORD
DEBUG(100,("decode_pw_buffer: new_pwrd: "));
return True;
}
-
SAFE_FREE(vuser->unix_homedir);
SAFE_FREE(vuser->logon_script);
+ data_blob_free(&vuser->session_key);
+
session_yield(vuser);
free_server_info(&vuser->server_info);
* @param server_info The token returned from the authentication process.
* (now 'owned' by register_vuid)
*
+ * @param session_key The User session key for the login session (now also 'owned' by register_vuid)
+ *
+ * @param smb_name The untranslated name of the user
+ *
* @return Newly allocated vuid, biased by an offset. (This allows us to
* tell random client vuid's (normally zero) from valid vuids.)
*
int register_vuid(struct server_context *smb,
struct auth_serversupplied_info *server_info,
+ DATA_BLOB *session_key,
const char *smb_name)
{
user_struct *vuser = NULL;
}
}
- memcpy(vuser->session_key, server_info->session_key, sizeof(vuser->session_key));
+ vuser->session_key = *session_key;
DEBUG(10,("register_vuid: (%u,%u) %s %s %s guest=%d\n",
(unsigned int)vuser->uid,
auth_usersupplied_info *user_info = NULL;
auth_serversupplied_info *server_info = NULL;
DATA_BLOB null_blob;
+ DATA_BLOB session_key;
if (!req->smb->negotiate.done_sesssetup) {
req->smb->negotiate.max_send = sess->old.in.bufsize;
user_info,
&server_info);
if (!NT_STATUS_IS_OK(status)) {
- return NT_STATUS_ACCESS_DENIED;
+ return nt_status_squash(status);
+ }
+
+ if (server_info->user_session_key.data) {
+ session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length);
+ } else {
+ session_key = data_blob(NULL, 0);
}
sess->old.out.action = 0;
- sess->old.out.vuid = register_vuid(req->smb, server_info, sess->old.in.user);
+ sess->old.out.vuid = register_vuid(req->smb, server_info, &session_key, sess->old.in.user);
sesssetup_common_strings(req,
&sess->old.out.os,
&sess->old.out.lanman,
NTSTATUS status;
auth_usersupplied_info *user_info = NULL;
auth_serversupplied_info *server_info = NULL;
+ DATA_BLOB session_key;
if (!req->smb->negotiate.done_sesssetup) {
req->smb->negotiate.max_send = sess->nt1.in.bufsize;
user_info,
&server_info);
if (!NT_STATUS_IS_OK(status)) {
- return NT_STATUS_ACCESS_DENIED;
+ return nt_status_squash(status);
+ }
+
+ if (server_info->user_session_key.data) {
+ session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length);
+ } else {
+ session_key = data_blob(NULL, 0);
}
sess->nt1.out.action = 0;
- sess->nt1.out.vuid = register_vuid(req->smb, server_info, sess->old.in.user);
+ sess->nt1.out.vuid = register_vuid(req->smb, server_info, &session_key, sess->old.in.user);
sesssetup_common_strings(req,
&sess->nt1.out.os,
&sess->nt1.out.lanman,