summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2004-04-12 11:18:32 +0000
committerAndrew Bartlett <abartlet@samba.org>2004-04-12 11:18:32 +0000
commit8eeafff8b24d3dcef763a385dd99fedda280179d (patch)
tree2e318adfdbe84a55fd00441ed29b296c5067c12d
parentd7d3833358664165d036ea131f0afb11b08060b1 (diff)
downloadsamba-8eeafff8b24d3dcef763a385dd99fedda280179d.tar.gz
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
-rw-r--r--source/libsmb/cliconnect.c63
-rw-r--r--source/libsmb/passchange.c83
-rw-r--r--source/libsmb/smbencrypt.c12
3 files changed, 115 insertions, 43 deletions
diff --git a/source/libsmb/cliconnect.c b/source/libsmb/cliconnect.c
index cdf58c5b913..06c9b5ea91a 100644
--- a/source/libsmb/cliconnect.c
+++ b/source/libsmb/cliconnect.c
@@ -40,6 +40,18 @@ static const struct {
{-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.
****************************************************************************/
@@ -47,6 +59,8 @@ static const struct {
static BOOL cli_session_setup_lanman2(struct cli_state *cli, const char *user,
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;
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) {
/* Encrypted mode needed, and non encrypted password supplied. */
- passlen = 24;
- SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
+ lm_response = data_blob(NULL, 24);
+ SMBencrypt(pass, cli->secblob.data,(uchar *)lm_response.data);
} else if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen == 24) {
/* Encrypted mode needed, and encrypted password supplied. */
- memcpy(pword, pass, passlen);
+ lm_response = data_blob(pass, passlen);
} else if (passlen > 0) {
/* Plaintext mode needed, assume plaintext supplied. */
passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
+ lm_response = data_blob(pass, passlen);
}
/* 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_vwv4,1);
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);
- memcpy(p,pword,passlen);
+ memcpy(p,lm_response.data,lm_response.length);
p += passlen;
p += clistr_push(cli, p, user, -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);
fstrcpy(cli->user_name, user);
+ if (session_key.data) {
+ /* Have plaintext orginal */
+ cli_set_session_key(cli, session_key);
+ }
+
return True;
}
@@ -248,18 +268,6 @@ static BOOL cli_session_setup_plaintext(struct cli_state *cli, const char *user,
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
is not negotiated.
@@ -310,22 +318,39 @@ static BOOL cli_session_setup_nt1(struct cli_state *cli, const char *user,
uchar nt_hash[16];
E_md4hash(pass, nt_hash);
+#ifdef LANMAN_ONLY
+ nt_response = data_blob(NULL, 0);
+#else
nt_response = data_blob(NULL, 24);
SMBNTencrypt(pass,cli->secblob.data,nt_response.data);
-
+#endif
/* non encrypted password supplied. Ignore ntpass. */
if (lp_client_lanman_auth()) {
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 {
/* LM disabled, place NT# in LM field instead */
lm_response = data_blob(nt_response.data, nt_response.length);
}
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);
+#endif
}
+#ifdef LANMAN_ONLY
+ cli_simple_set_signing(cli, session_key, lm_response);
+#else
cli_simple_set_signing(cli, session_key, nt_response);
+#endif
} else {
/* pre-encrypted password supplied. Only used for
security=server, can't do
diff --git a/source/libsmb/passchange.c b/source/libsmb/passchange.c
index dc0cbbcb7cc..9f46c131fee 100644
--- a/source/libsmb/passchange.c
+++ b/source/libsmb/passchange.c
@@ -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,
- new_passwd, old_passwd))) {
-
- if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)
- || NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) {
- /* try the old Lanman method */
- 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",
- 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);
+ if (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 for reasons such as wrong password, too short etc ... */
+
+ 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));
+ cli_shutdown(&cli);
+ return False;
+ }
+
+ /* OK, that failed, so try again... */
+ cli_nt_session_close(&cli);
+
+ /* Try anonymous NTLMSSP... */
+ init_creds(&creds, "", "", NULL);
+ cli_init_creds(&cli, &creds);
+
+ 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));
+ cli_shutdown(&cli);
+ 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 False;
+ 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 rejected the password change: Error was : %s.\n",
- remote_machine, get_friendly_nt_error_msg(result));
+ 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;
}
diff --git a/source/libsmb/smbencrypt.c b/source/libsmb/smbencrypt.c
index 3b8a375bea5..44f7428086b 100644
--- a/source/libsmb/smbencrypt.c
+++ b/source/libsmb/smbencrypt.c
@@ -28,13 +28,17 @@
/*
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);
@@ -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, (char *)p24, 24);
#endif
+
+ return ret;
}
/**