1
0
mirror of https://github.com/samba-team/samba.git synced 2025-08-04 08:22:08 +03:00

r176: Improve our fallback code for password changes - this would be better

with more correct NTLMSSP support in client and server, but it will do
for now.

Also implement LANMAN password only in the classical session setup code, but
#ifdef'ed out.  In Samba4, I'll make this run-time so we can torture it.

Lanman passwords over 14 dos characters long could be considered
'invalid' (they are truncated) - so SMBencrypt now returns 'False' if
it generates such a password.

Andrew Bartlett
(This used to be commit 565305f7bb)
This commit is contained in:
Andrew Bartlett
2004-04-12 11:18:32 +00:00
committed by Gerald (Jerry) Carter
parent 1560755556
commit 85a307bb3e
3 changed files with 116 additions and 44 deletions

View File

@ -40,6 +40,18 @@ static const struct {
{-1,NULL} {-1,NULL}
}; };
/**
* Set the user session key for a connection
* @param cli The cli structure to add it too
* @param session_key The session key used. (A copy of this is taken for the cli struct)
*
*/
static void cli_set_session_key (struct cli_state *cli, const DATA_BLOB session_key)
{
cli->user_session_key = data_blob(session_key.data, session_key.length);
}
/**************************************************************************** /****************************************************************************
Do an old lanman2 style session setup. Do an old lanman2 style session setup.
****************************************************************************/ ****************************************************************************/
@ -47,6 +59,8 @@ static const struct {
static BOOL cli_session_setup_lanman2(struct cli_state *cli, const char *user, static BOOL cli_session_setup_lanman2(struct cli_state *cli, const char *user,
const char *pass, size_t passlen, const char *workgroup) const char *pass, size_t passlen, const char *workgroup)
{ {
DATA_BLOB session_key = data_blob(NULL, 0);
DATA_BLOB lm_response = data_blob(NULL, 0);
fstring pword; fstring pword;
char *p; char *p;
@ -66,14 +80,15 @@ static BOOL cli_session_setup_lanman2(struct cli_state *cli, const char *user,
if (passlen > 0 && (cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen != 24) { if (passlen > 0 && (cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen != 24) {
/* Encrypted mode needed, and non encrypted password supplied. */ /* Encrypted mode needed, and non encrypted password supplied. */
passlen = 24; lm_response = data_blob(NULL, 24);
SMBencrypt(pass,cli->secblob.data,(uchar *)pword); SMBencrypt(pass, cli->secblob.data,(uchar *)lm_response.data);
} else if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen == 24) { } else if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen == 24) {
/* Encrypted mode needed, and encrypted password supplied. */ /* Encrypted mode needed, and encrypted password supplied. */
memcpy(pword, pass, passlen); lm_response = data_blob(pass, passlen);
} else if (passlen > 0) { } else if (passlen > 0) {
/* Plaintext mode needed, assume plaintext supplied. */ /* Plaintext mode needed, assume plaintext supplied. */
passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE); passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
lm_response = data_blob(pass, passlen);
} }
/* send a session setup command */ /* send a session setup command */
@ -87,10 +102,10 @@ static BOOL cli_session_setup_lanman2(struct cli_state *cli, const char *user,
SSVAL(cli->outbuf,smb_vwv3,2); SSVAL(cli->outbuf,smb_vwv3,2);
SSVAL(cli->outbuf,smb_vwv4,1); SSVAL(cli->outbuf,smb_vwv4,1);
SIVAL(cli->outbuf,smb_vwv5,cli->sesskey); SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
SSVAL(cli->outbuf,smb_vwv7,passlen); SSVAL(cli->outbuf,smb_vwv7,lm_response.length);
p = smb_buf(cli->outbuf); p = smb_buf(cli->outbuf);
memcpy(p,pword,passlen); memcpy(p,lm_response.data,lm_response.length);
p += passlen; p += passlen;
p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER); p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER); p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
@ -111,6 +126,11 @@ static BOOL cli_session_setup_lanman2(struct cli_state *cli, const char *user,
cli->vuid = SVAL(cli->inbuf,smb_uid); cli->vuid = SVAL(cli->inbuf,smb_uid);
fstrcpy(cli->user_name, user); fstrcpy(cli->user_name, user);
if (session_key.data) {
/* Have plaintext orginal */
cli_set_session_key(cli, session_key);
}
return True; return True;
} }
@ -248,18 +268,6 @@ static BOOL cli_session_setup_plaintext(struct cli_state *cli, const char *user,
return True; return True;
} }
/**
* Set the user session key for a connection
* @param cli The cli structure to add it too
* @param session_key The session key used. (A copy of this is taken for the cli struct)
*
*/
static void cli_set_session_key (struct cli_state *cli, const DATA_BLOB session_key)
{
cli->user_session_key = data_blob(session_key.data, session_key.length);
}
/**************************************************************************** /****************************************************************************
do a NT1 NTLM/LM encrypted session setup - for when extended security do a NT1 NTLM/LM encrypted session setup - for when extended security
is not negotiated. is not negotiated.
@ -310,22 +318,39 @@ static BOOL cli_session_setup_nt1(struct cli_state *cli, const char *user,
uchar nt_hash[16]; uchar nt_hash[16];
E_md4hash(pass, nt_hash); E_md4hash(pass, nt_hash);
#ifdef LANMAN_ONLY
nt_response = data_blob(NULL, 0);
#else
nt_response = data_blob(NULL, 24); nt_response = data_blob(NULL, 24);
SMBNTencrypt(pass,cli->secblob.data,nt_response.data); SMBNTencrypt(pass,cli->secblob.data,nt_response.data);
#endif
/* non encrypted password supplied. Ignore ntpass. */ /* non encrypted password supplied. Ignore ntpass. */
if (lp_client_lanman_auth()) { if (lp_client_lanman_auth()) {
lm_response = data_blob(NULL, 24); lm_response = data_blob(NULL, 24);
SMBencrypt(pass,cli->secblob.data, lm_response.data); if (!SMBencrypt(pass,cli->secblob.data, lm_response.data)) {
/* Oops, the LM response is invalid, just put
the NT response there instead */
data_blob_free(&lm_response);
lm_response = data_blob(nt_response.data, nt_response.length);
}
} else { } else {
/* LM disabled, place NT# in LM field instead */ /* LM disabled, place NT# in LM field instead */
lm_response = data_blob(nt_response.data, nt_response.length); lm_response = data_blob(nt_response.data, nt_response.length);
} }
session_key = data_blob(NULL, 16); session_key = data_blob(NULL, 16);
#ifdef LANMAN_ONLY
E_deshash(pass, session_key.data);
memset(&session_key.data[8], '\0', 8);
#else
SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data); SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
#endif
} }
#ifdef LANMAN_ONLY
cli_simple_set_signing(cli, session_key, lm_response);
#else
cli_simple_set_signing(cli, session_key, nt_response); cli_simple_set_signing(cli, session_key, nt_response);
#endif
} else { } else {
/* pre-encrypted password supplied. Only used for /* pre-encrypted password supplied. Only used for
security=server, can't do security=server, can't do

View File

@ -121,32 +121,73 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name,
} }
} }
if (!NT_STATUS_IS_OK(result = cli_samr_chgpasswd_user(&cli, cli.mem_ctx, user_name, if (NT_STATUS_IS_OK(result = cli_samr_chgpasswd_user(&cli, cli.mem_ctx, user_name,
new_passwd, old_passwd))) { new_passwd, old_passwd))) {
/* Great - it all worked! */
cli_shutdown(&cli);
return True;
if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) } else if (!(NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)
|| NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) { || NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))) {
/* try the old Lanman method */ /* it failed, but for reasons such as wrong password, too short etc ... */
if (lp_client_lanman_auth()) {
if (!cli_oem_change_password(&cli, user_name, new_passwd, old_passwd)) { slprintf(err_str, err_str_len-1, "machine %s rejected the password change: Error was : %s.\n",
slprintf(err_str, err_str_len-1, "machine %s rejected the password change: Error was : %s.\n", remote_machine, get_friendly_nt_error_msg(result));
remote_machine, cli_errstr(&cli) ); cli_shutdown(&cli);
cli_shutdown(&cli); return False;
return False; }
}
} else { /* OK, that failed, so try again... */
slprintf(err_str, err_str_len-1, "machine %s does not support SAMR connections, but LANMAN password changed are disabled\n", cli_nt_session_close(&cli);
remote_machine);
cli_shutdown(&cli); /* Try anonymous NTLMSSP... */
return False; init_creds(&creds, "", "", NULL);
} cli_init_creds(&cli, &creds);
} else {
slprintf(err_str, err_str_len-1, "machine %s rejected the password change: Error was : %s.\n", result = NT_STATUS_UNSUCCESSFUL;
/* OK, this is ugly, but... */
if ( cli_nt_session_open( &cli, PI_SAMR )
&& NT_STATUS_IS_OK(result
= cli_samr_chgpasswd_user(&cli, cli.mem_ctx, user_name,
new_passwd, old_passwd))) {
/* Great - it all worked! */
cli_shutdown(&cli);
return True;
} else {
if (!(NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)
|| NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))) {
/* it failed, but again it was due to things like new password too short */
slprintf(err_str, err_str_len-1,
"machine %s rejected the (anonymous) password change: Error was : %s.\n",
remote_machine, get_friendly_nt_error_msg(result)); remote_machine, get_friendly_nt_error_msg(result));
cli_shutdown(&cli); cli_shutdown(&cli);
return False; return False;
} }
/* We have failed to change the user's password, and we think the server
just might not support SAMR password changes, so fall back */
if (lp_client_lanman_auth()) {
if (cli_oem_change_password(&cli, user_name, new_passwd, old_passwd)) {
/* SAMR failed, but the old LanMan protocol worked! */
cli_shutdown(&cli);
return True;
}
slprintf(err_str, err_str_len-1,
"machine %s rejected the password change: Error was : %s.\n",
remote_machine, cli_errstr(&cli) );
cli_shutdown(&cli);
return False;
} else {
slprintf(err_str, err_str_len-1,
"machine %s does not support SAMR connections, but LANMAN password changed are disabled\n",
remote_machine);
cli_shutdown(&cli);
return False;
}
} }
cli_shutdown(&cli);
return True;
} }

View File

@ -28,13 +28,17 @@
/* /*
This implements the X/Open SMB password encryption This implements the X/Open SMB password encryption
It takes a password ('unix' string), a 8 byte "crypt key" It takes a password ('unix' string), a 8 byte "crypt key"
and puts 24 bytes of encrypted password into p24 */ and puts 24 bytes of encrypted password into p24
void SMBencrypt(const char *passwd, const uchar *c8, uchar p24[24])
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]; uchar p21[21];
memset(p21,'\0',21); memset(p21,'\0',21);
E_deshash(passwd, p21); ret = E_deshash(passwd, p21);
SMBOWFencrypt(p21, c8, p24); SMBOWFencrypt(p21, c8, p24);
@ -44,6 +48,8 @@ void SMBencrypt(const char *passwd, const uchar *c8, uchar p24[24])
dump_data(100, (const char *)c8, 8); dump_data(100, (const char *)c8, 8);
dump_data(100, (char *)p24, 24); dump_data(100, (char *)p24, 24);
#endif #endif
return ret;
} }
/** /**