diff options
Diffstat (limited to 'source3/libsmb')
-rw-r--r-- | source3/libsmb/clirap.c | 12 | ||||
-rw-r--r-- | source3/libsmb/passchange.c | 88 | ||||
-rw-r--r-- | source3/libsmb/smbencrypt.c | 68 |
3 files changed, 113 insertions, 55 deletions
diff --git a/source3/libsmb/clirap.c b/source3/libsmb/clirap.c index 79ad38fc8c..36bc403e0b 100644 --- a/source3/libsmb/clirap.c +++ b/source3/libsmb/clirap.c @@ -291,7 +291,6 @@ BOOL cli_oem_change_password(struct cli_state *cli, const char *user, const char char *rparam = NULL; char *rdata = NULL; unsigned int rprcnt, rdrcnt; - pstring dos_new_password; if (strlen(user) >= sizeof(fstring)-1) { DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user)); @@ -317,10 +316,13 @@ BOOL cli_oem_change_password(struct cli_state *cli, const char *user, const char */ E_deshash(old_password, old_pw_hash); - clistr_push(cli, dos_new_password, new_password, sizeof(dos_new_password), STR_TERMINATE|STR_ASCII); - - if (!make_oem_passwd_hash( data, dos_new_password, old_pw_hash, False)) - return False; + encode_pw_buffer(data, new_password, STR_ASCII); + +#ifdef DEBUG_PASSWORD + DEBUG(100,("make_oem_passwd_hash\n")); + dump_data(100, data, 516); +#endif + SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, 516); /* * Now place the old password hash in the data. diff --git a/source3/libsmb/passchange.c b/source3/libsmb/passchange.c index 41b6095520..dc0cbbcb7c 100644 --- a/source3/libsmb/passchange.c +++ b/source3/libsmb/passchange.c @@ -30,6 +30,9 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name, struct nmb_name calling, called; struct cli_state cli; struct in_addr ip; + struct ntuser_creds creds; + + NTSTATUS result; *err_str = '\0'; @@ -66,18 +69,28 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name, return False; } - /* - * We should connect as the anonymous user here, in case - * the server has "must change password" checked... - * Thanks to <Nicholas.S.Jenkins@cdc.com> for this fix. - */ + /* Given things like SMB signing, restrict anonymous and the like, + try an authenticated connection first */ + if (!cli_session_setup(&cli, user_name, old_passwd, strlen(old_passwd)+1, old_passwd, strlen(old_passwd)+1, "")) { + /* + * We should connect as the anonymous user here, in case + * the server has "must change password" checked... + * Thanks to <Nicholas.S.Jenkins@cdc.com> for this fix. + */ - if (!cli_session_setup(&cli, "", "", 0, "", 0, "")) { - slprintf(err_str, err_str_len-1, "machine %s rejected the session setup. Error was : %s.\n", - remote_machine, cli_errstr(&cli) ); - cli_shutdown(&cli); - return False; - } + if (!cli_session_setup(&cli, "", "", 0, "", 0, "")) { + slprintf(err_str, err_str_len-1, "machine %s rejected the session setup. Error was : %s.\n", + remote_machine, cli_errstr(&cli) ); + cli_shutdown(&cli); + return False; + } + + init_creds(&creds, "", "", NULL); + cli_init_creds(&cli, &creds); + } else { + init_creds(&creds, user_name, "", old_passwd); + cli_init_creds(&cli, &creds); + } if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) { slprintf(err_str, err_str_len-1, "machine %s rejected the tconX on the IPC$ share. Error was : %s.\n", @@ -86,13 +99,54 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name, return False; } - 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; - } + /* Try not to give the password away to easily */ + + cli.pipe_auth_flags = AUTH_PIPE_NTLMSSP; + cli.pipe_auth_flags |= AUTH_PIPE_SIGN; + cli.pipe_auth_flags |= AUTH_PIPE_SEAL; + if ( !cli_nt_session_open( &cli, PI_SAMR ) ) { + 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); + cli_shutdown(&cli); + return False; + } + } + + 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); + 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)); + cli_shutdown(&cli); + return False; + } + } cli_shutdown(&cli); return True; } diff --git a/source3/libsmb/smbencrypt.c b/source3/libsmb/smbencrypt.c index cfcc24a1df..1d192b816a 100644 --- a/source3/libsmb/smbencrypt.c +++ b/source3/libsmb/smbencrypt.c @@ -70,20 +70,29 @@ void E_md4hash(const char *passwd, uchar p16[16]) * 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; } /** @@ -219,24 +228,7 @@ void SMBNTencrypt(const char *passwd, uchar *c8, uchar *p24) BOOL make_oem_passwd_hash(char data[516], const char *passwd, 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); + encode_pw_buffer(data, passwd, (unicode?STR_UNICODE:STR_ASCII)); #ifdef DEBUG_PASSWORD DEBUG(100,("make_oem_passwd_hash\n")); @@ -473,37 +465,46 @@ BOOL SMBNTLMv2encrypt(const char *user, const char *domain, const char *password } /*********************************************************** - encode a password buffer. The caller gets to figure out - what to put in it. + encode a password buffer with a unicode password. The buffer + is filled with random data to make it harder to attack. ************************************************************/ -BOOL encode_pw_buffer(char buffer[516], char *new_pw, int new_pw_length) +BOOL encode_pw_buffer(char buffer[516], const char *password, int string_flags) { - generate_random_buffer((unsigned char *)buffer, 516, True); + uchar new_pw[512]; + size_t new_pw_len; - memcpy(&buffer[512 - new_pw_length], new_pw, new_pw_length); + new_pw_len = push_string(NULL, new_pw, + password, + sizeof(new_pw), string_flags); + + memcpy(&buffer[512 - new_pw_len], new_pw, new_pw_len); + + generate_random_buffer((unsigned char *)buffer, 512 - new_pw_len, True); /* * The length of the new password is in the last 4 bytes of * the data buffer. */ - SIVAL(buffer, 512, new_pw_length); - + SIVAL(buffer, 512, new_pw_len); + ZERO_STRUCT(new_pw); return True; } + /*********************************************************** decode a password buffer *new_pw_len is the length in bytes of the possibly mulitbyte 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. */ @@ -516,15 +517,16 @@ BOOL decode_pw_buffer(char in_buffer[516], char *new_pwrd, 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: ")); |