diff options
-rw-r--r-- | source3/libsmb/cliconnect.c | 63 | ||||
-rw-r--r-- | source3/libsmb/passchange.c | 83 | ||||
-rw-r--r-- | source3/libsmb/smbencrypt.c | 12 |
3 files changed, 115 insertions, 43 deletions
diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index cdf58c5b91..06c9b5ea91 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/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/source3/libsmb/passchange.c b/source3/libsmb/passchange.c index dc0cbbcb7c..9f46c131fe 100644 --- a/source3/libsmb/passchange.c +++ b/source3/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/source3/libsmb/smbencrypt.c b/source3/libsmb/smbencrypt.c index 3b8a375bea..44f7428086 100644 --- a/source3/libsmb/smbencrypt.c +++ b/source3/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; } /** |