Description: fix password lockout not enforced for SAMR password changes Origin: upstream, http://www.samba.org/samba/ftp/patches/security/samba-4.1.5-CVE-2013-4496-CVE-2013-6442.patch Index: samba-4.1.3+dfsg/source3/auth/check_samsec.c =================================================================== --- samba-4.1.3+dfsg.orig/source3/auth/check_samsec.c 2013-06-13 05:21:02.000000000 -0400 +++ samba-4.1.3+dfsg/source3/auth/check_samsec.c 2014-03-17 08:31:35.389866740 -0400 @@ -408,6 +408,7 @@ /* 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", username)); + TALLOC_FREE(sampass); return NT_STATUS_ACCOUNT_LOCKED_OUT; } Index: samba-4.1.3+dfsg/source3/rpc_server/samr/srv_samr_chgpasswd.c =================================================================== --- samba-4.1.3+dfsg.orig/source3/rpc_server/samr/srv_samr_chgpasswd.c 2013-06-13 05:21:02.000000000 -0400 +++ samba-4.1.3+dfsg/source3/rpc_server/samr/srv_samr_chgpasswd.c 2014-03-17 08:31:35.385866740 -0400 @@ -1106,6 +1106,8 @@ struct samu *sampass = NULL; NTSTATUS nt_status; bool ret = false; + bool updated_badpw = false; + NTSTATUS update_login_attempts_status; if (!(sampass = samu_new(NULL))) { return NT_STATUS_NO_MEMORY; @@ -1121,6 +1123,13 @@ return NT_STATUS_NO_SUCH_USER; } + /* 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", user)); + TALLOC_FREE(sampass); + return NT_STATUS_ACCOUNT_LOCKED_OUT; + } + nt_status = check_oem_password(user, password_encrypted_with_lm_hash, old_lm_hash_encrypted, @@ -1129,6 +1138,52 @@ sampass, &new_passwd); + /* + * Notify passdb backend of login success/failure. If not + * NT_STATUS_OK the backend doesn't like the login + */ + update_login_attempts_status = pdb_update_login_attempts(sampass, + NT_STATUS_IS_OK(nt_status)); + + if (!NT_STATUS_IS_OK(nt_status)) { + bool increment_bad_pw_count = false; + + if (NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) && + (pdb_get_acct_ctrl(sampass) & ACB_NORMAL) && + NT_STATUS_IS_OK(update_login_attempts_status)) + { + increment_bad_pw_count = true; + } + + if (increment_bad_pw_count) { + pdb_increment_bad_password_count(sampass); + updated_badpw = true; + } else { + pdb_update_bad_password_count(sampass, + &updated_badpw); + } + } else { + + if ((pdb_get_acct_ctrl(sampass) & ACB_NORMAL) && + (pdb_get_bad_password_count(sampass) > 0)){ + pdb_set_bad_password_count(sampass, 0, PDB_CHANGED); + pdb_set_bad_password_time(sampass, 0, PDB_CHANGED); + updated_badpw = true; + } + } + + if (updated_badpw) { + NTSTATUS update_status; + become_root(); + update_status = pdb_update_sam_account(sampass); + unbecome_root(); + + if (!NT_STATUS_IS_OK(update_status)) { + DEBUG(1, ("Failed to modify entry: %s\n", + nt_errstr(update_status))); + } + } + if (!NT_STATUS_IS_OK(nt_status)) { TALLOC_FREE(sampass); return nt_status; Index: samba-4.1.3+dfsg/source3/rpc_server/samr/srv_samr_nt.c =================================================================== --- samba-4.1.3+dfsg.orig/source3/rpc_server/samr/srv_samr_nt.c 2013-12-05 04:16:48.000000000 -0500 +++ samba-4.1.3+dfsg/source3/rpc_server/samr/srv_samr_nt.c 2014-03-17 08:31:35.389866740 -0400 @@ -1713,114 +1713,19 @@ } /**************************************************************** - _samr_ChangePasswordUser + _samr_ChangePasswordUser. + + So old it is just not worth implementing + because it does not supply a plaintext and so we can't do password + complexity checking and cannot update other services that use a + plaintext password via passwd chat/pam password change/ldap password + sync. ****************************************************************/ NTSTATUS _samr_ChangePasswordUser(struct pipes_struct *p, struct samr_ChangePasswordUser *r) { - NTSTATUS status; - bool ret = false; - struct samr_user_info *uinfo; - struct samu *pwd; - struct samr_Password new_lmPwdHash, new_ntPwdHash, checkHash; - struct samr_Password lm_pwd, nt_pwd; - - uinfo = policy_handle_find(p, r->in.user_handle, - SAMR_USER_ACCESS_SET_PASSWORD, NULL, - struct samr_user_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - DEBUG(5,("_samr_ChangePasswordUser: sid:%s\n", - sid_string_dbg(&uinfo->sid))); - - if (!(pwd = samu_new(NULL))) { - return NT_STATUS_NO_MEMORY; - } - - become_root(); - ret = pdb_getsampwsid(pwd, &uinfo->sid); - unbecome_root(); - - if (!ret) { - TALLOC_FREE(pwd); - return NT_STATUS_WRONG_PASSWORD; - } - - { - const uint8_t *lm_pass, *nt_pass; - - lm_pass = pdb_get_lanman_passwd(pwd); - nt_pass = pdb_get_nt_passwd(pwd); - - if (!lm_pass || !nt_pass) { - status = NT_STATUS_WRONG_PASSWORD; - goto out; - } - - memcpy(&lm_pwd.hash, lm_pass, sizeof(lm_pwd.hash)); - memcpy(&nt_pwd.hash, nt_pass, sizeof(nt_pwd.hash)); - } - - /* basic sanity checking on parameters. Do this before any database ops */ - if (!r->in.lm_present || !r->in.nt_present || - !r->in.old_lm_crypted || !r->in.new_lm_crypted || - !r->in.old_nt_crypted || !r->in.new_nt_crypted) { - /* we should really handle a change with lm not - present */ - status = NT_STATUS_INVALID_PARAMETER_MIX; - goto out; - } - - /* decrypt and check the new lm hash */ - D_P16(lm_pwd.hash, r->in.new_lm_crypted->hash, new_lmPwdHash.hash); - D_P16(new_lmPwdHash.hash, r->in.old_lm_crypted->hash, checkHash.hash); - if (memcmp(checkHash.hash, lm_pwd.hash, 16) != 0) { - status = NT_STATUS_WRONG_PASSWORD; - goto out; - } - - /* decrypt and check the new nt hash */ - D_P16(nt_pwd.hash, r->in.new_nt_crypted->hash, new_ntPwdHash.hash); - D_P16(new_ntPwdHash.hash, r->in.old_nt_crypted->hash, checkHash.hash); - if (memcmp(checkHash.hash, nt_pwd.hash, 16) != 0) { - status = NT_STATUS_WRONG_PASSWORD; - goto out; - } - - /* The NT Cross is not required by Win2k3 R2, but if present - check the nt cross hash */ - if (r->in.cross1_present && r->in.nt_cross) { - D_P16(lm_pwd.hash, r->in.nt_cross->hash, checkHash.hash); - if (memcmp(checkHash.hash, new_ntPwdHash.hash, 16) != 0) { - status = NT_STATUS_WRONG_PASSWORD; - goto out; - } - } - - /* The LM Cross is not required by Win2k3 R2, but if present - check the lm cross hash */ - if (r->in.cross2_present && r->in.lm_cross) { - D_P16(nt_pwd.hash, r->in.lm_cross->hash, checkHash.hash); - if (memcmp(checkHash.hash, new_lmPwdHash.hash, 16) != 0) { - status = NT_STATUS_WRONG_PASSWORD; - goto out; - } - } - - if (!pdb_set_nt_passwd(pwd, new_ntPwdHash.hash, PDB_CHANGED) || - !pdb_set_lanman_passwd(pwd, new_lmPwdHash.hash, PDB_CHANGED)) { - status = NT_STATUS_ACCESS_DENIED; - goto out; - } - - status = pdb_update_sam_account(pwd); - out: - TALLOC_FREE(pwd); - - return status; + return NT_STATUS_NOT_IMPLEMENTED; } /******************************************************************* Index: samba-4.1.3+dfsg/source3/smbd/lanman.c =================================================================== --- samba-4.1.3+dfsg.orig/source3/smbd/lanman.c 2013-12-05 04:18:10.000000000 -0500 +++ samba-4.1.3+dfsg/source3/smbd/lanman.c 2014-03-17 08:31:35.389866740 -0400 @@ -2948,259 +2948,6 @@ } /**************************************************************************** - Set the user password. -*****************************************************************************/ - -static bool api_SetUserPassword(struct smbd_server_connection *sconn, - connection_struct *conn,uint64_t vuid, - char *param, int tpscnt, - char *data, int tdscnt, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *np = get_safe_str_ptr(param,tpscnt,param,2); - char *p = NULL; - fstring user; - fstring pass1,pass2; - TALLOC_CTX *mem_ctx = talloc_tos(); - NTSTATUS status, result; - struct rpc_pipe_client *cli = NULL; - struct policy_handle connect_handle, domain_handle, user_handle; - struct lsa_String domain_name; - struct dom_sid2 *domain_sid; - struct lsa_String names; - struct samr_Ids rids; - struct samr_Ids types; - struct samr_Password old_lm_hash; - struct samr_Password new_lm_hash; - int errcode = NERR_badpass; - uint32_t rid; - int encrypted; - int min_pwd_length; - struct dcerpc_binding_handle *b = NULL; - - /* Skip 2 strings. */ - p = skip_string(param,tpscnt,np); - p = skip_string(param,tpscnt,p); - - if (!np || !p) { - return False; - } - - /* Do we have a string ? */ - if (skip_string(param,tpscnt,p) == NULL) { - return False; - } - pull_ascii_fstring(user,p); - - p = skip_string(param,tpscnt,p); - if (!p) { - return False; - } - - memset(pass1,'\0',sizeof(pass1)); - memset(pass2,'\0',sizeof(pass2)); - /* - * We use 31 here not 32 as we're checking - * the last byte we want to access is safe. - */ - if (!is_offset_safe(param,tpscnt,p,31)) { - return False; - } - memcpy(pass1,p,16); - memcpy(pass2,p+16,16); - - encrypted = get_safe_SVAL(param,tpscnt,p+32,0,-1); - if (encrypted == -1) { - errcode = W_ERROR_V(WERR_INVALID_PARAM); - goto out; - } - - min_pwd_length = get_safe_SVAL(param,tpscnt,p+34,0,-1); - if (min_pwd_length == -1) { - errcode = W_ERROR_V(WERR_INVALID_PARAM); - goto out; - } - - *rparam_len = 4; - *rparam = smb_realloc_limit(*rparam,*rparam_len); - if (!*rparam) { - return False; - } - - *rdata_len = 0; - - DEBUG(3,("Set password for <%s> (encrypted: %d, min_pwd_length: %d)\n", - user, encrypted, min_pwd_length)); - - ZERO_STRUCT(connect_handle); - ZERO_STRUCT(domain_handle); - ZERO_STRUCT(user_handle); - - status = rpc_pipe_open_interface(mem_ctx, &ndr_table_samr.syntax_id, - conn->session_info, - conn->sconn->remote_address, - conn->sconn->msg_ctx, - &cli); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("api_SetUserPassword: could not connect to samr: %s\n", - nt_errstr(status))); - errcode = W_ERROR_V(ntstatus_to_werror(status)); - goto out; - } - - b = cli->binding_handle; - - status = dcerpc_samr_Connect2(b, mem_ctx, - lp_netbios_name(), - SAMR_ACCESS_CONNECT_TO_SERVER | - SAMR_ACCESS_ENUM_DOMAINS | - SAMR_ACCESS_LOOKUP_DOMAIN, - &connect_handle, - &result); - if (!NT_STATUS_IS_OK(status)) { - errcode = W_ERROR_V(ntstatus_to_werror(status)); - goto out; - } - if (!NT_STATUS_IS_OK(result)) { - errcode = W_ERROR_V(ntstatus_to_werror(result)); - goto out; - } - - init_lsa_String(&domain_name, get_global_sam_name()); - - status = dcerpc_samr_LookupDomain(b, mem_ctx, - &connect_handle, - &domain_name, - &domain_sid, - &result); - if (!NT_STATUS_IS_OK(status)) { - errcode = W_ERROR_V(ntstatus_to_werror(status)); - goto out; - } - if (!NT_STATUS_IS_OK(result)) { - errcode = W_ERROR_V(ntstatus_to_werror(result)); - goto out; - } - - status = dcerpc_samr_OpenDomain(b, mem_ctx, - &connect_handle, - SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, - domain_sid, - &domain_handle, - &result); - if (!NT_STATUS_IS_OK(status)) { - errcode = W_ERROR_V(ntstatus_to_werror(status)); - goto out; - } - if (!NT_STATUS_IS_OK(result)) { - errcode = W_ERROR_V(ntstatus_to_werror(result)); - goto out; - } - - init_lsa_String(&names, user); - - status = dcerpc_samr_LookupNames(b, mem_ctx, - &domain_handle, - 1, - &names, - &rids, - &types, - &result); - if (!NT_STATUS_IS_OK(status)) { - errcode = W_ERROR_V(ntstatus_to_werror(status)); - goto out; - } - if (!NT_STATUS_IS_OK(result)) { - errcode = W_ERROR_V(ntstatus_to_werror(result)); - goto out; - } - - if (rids.count != 1) { - errcode = W_ERROR_V(WERR_NO_SUCH_USER); - goto out; - } - if (rids.count != types.count) { - errcode = W_ERROR_V(WERR_INVALID_PARAM); - goto out; - } - if (types.ids[0] != SID_NAME_USER) { - errcode = W_ERROR_V(WERR_INVALID_PARAM); - goto out; - } - - rid = rids.ids[0]; - - status = dcerpc_samr_OpenUser(b, mem_ctx, - &domain_handle, - SAMR_USER_ACCESS_CHANGE_PASSWORD, - rid, - &user_handle, - &result); - if (!NT_STATUS_IS_OK(status)) { - errcode = W_ERROR_V(ntstatus_to_werror(status)); - goto out; - } - if (!NT_STATUS_IS_OK(result)) { - errcode = W_ERROR_V(ntstatus_to_werror(result)); - goto out; - } - - if (encrypted == 0) { - E_deshash(pass1, old_lm_hash.hash); - E_deshash(pass2, new_lm_hash.hash); - } else { - ZERO_STRUCT(old_lm_hash); - ZERO_STRUCT(new_lm_hash); - memcpy(old_lm_hash.hash, pass1, MIN(strlen(pass1), 16)); - memcpy(new_lm_hash.hash, pass2, MIN(strlen(pass2), 16)); - } - - status = dcerpc_samr_ChangePasswordUser(b, mem_ctx, - &user_handle, - true, /* lm_present */ - &old_lm_hash, - &new_lm_hash, - false, /* nt_present */ - NULL, /* old_nt_crypted */ - NULL, /* new_nt_crypted */ - false, /* cross1_present */ - NULL, /* nt_cross */ - false, /* cross2_present */ - NULL, /* lm_cross */ - &result); - if (!NT_STATUS_IS_OK(status)) { - errcode = W_ERROR_V(ntstatus_to_werror(status)); - goto out; - } - if (!NT_STATUS_IS_OK(result)) { - errcode = W_ERROR_V(ntstatus_to_werror(result)); - goto out; - } - - errcode = NERR_Success; - out: - - if (b && is_valid_policy_hnd(&user_handle)) { - dcerpc_samr_Close(b, mem_ctx, &user_handle, &result); - } - if (b && is_valid_policy_hnd(&domain_handle)) { - dcerpc_samr_Close(b, mem_ctx, &domain_handle, &result); - } - if (b && is_valid_policy_hnd(&connect_handle)) { - dcerpc_samr_Close(b, mem_ctx, &connect_handle, &result); - } - - memset((char *)pass1,'\0',sizeof(fstring)); - memset((char *)pass2,'\0',sizeof(fstring)); - - SSVAL(*rparam,0,errcode); - SSVAL(*rparam,2,0); /* converter word */ - return(True); -} - -/**************************************************************************** Set the user password (SamOEM version - gets plaintext). ****************************************************************************/ @@ -5797,7 +5544,6 @@ {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */ {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */ {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms}, - {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword}, {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon}, {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo}, {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum}, Index: samba-4.1.3+dfsg/source4/rpc_server/samr/samr_password.c =================================================================== --- samba-4.1.3+dfsg.orig/source4/rpc_server/samr/samr_password.c 2013-12-05 04:16:48.000000000 -0500 +++ samba-4.1.3+dfsg/source4/rpc_server/samr/samr_password.c 2014-03-17 08:31:35.393866741 -0400 @@ -33,150 +33,17 @@ /* samr_ChangePasswordUser + + So old it is just not worth implementing + because it does not supply a plaintext and so we can't do password + complexity checking and cannot update all the other password hashes. + */ NTSTATUS dcesrv_samr_ChangePasswordUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_ChangePasswordUser *r) { - struct dcesrv_handle *h; - struct samr_account_state *a_state; - struct ldb_context *sam_ctx; - struct ldb_message **res; - int ret; - struct samr_Password new_lmPwdHash, new_ntPwdHash, checkHash; - struct samr_Password *lm_pwd, *nt_pwd; - NTSTATUS status = NT_STATUS_OK; - const char * const attrs[] = { "dBCSPwd", "unicodePwd" , NULL }; - - DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER); - - a_state = h->data; - - /* basic sanity checking on parameters. Do this before any database ops */ - if (!r->in.lm_present || !r->in.nt_present || - !r->in.old_lm_crypted || !r->in.new_lm_crypted || - !r->in.old_nt_crypted || !r->in.new_nt_crypted) { - /* we should really handle a change with lm not - present */ - return NT_STATUS_INVALID_PARAMETER_MIX; - } - - /* Connect to a SAMDB with system privileges for fetching the old pw - * hashes. */ - sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, - dce_call->conn->dce_ctx->lp_ctx, - system_session(dce_call->conn->dce_ctx->lp_ctx), 0); - if (sam_ctx == NULL) { - return NT_STATUS_INVALID_SYSTEM_SERVICE; - } - - /* fetch the old hashes */ - ret = gendb_search_dn(sam_ctx, mem_ctx, - a_state->account_dn, &res, attrs); - if (ret != 1) { - return NT_STATUS_WRONG_PASSWORD; - } - - status = samdb_result_passwords(mem_ctx, - dce_call->conn->dce_ctx->lp_ctx, - res[0], &lm_pwd, &nt_pwd); - if (!NT_STATUS_IS_OK(status) || !nt_pwd) { - return NT_STATUS_WRONG_PASSWORD; - } - - /* decrypt and check the new lm hash */ - if (lm_pwd) { - D_P16(lm_pwd->hash, r->in.new_lm_crypted->hash, new_lmPwdHash.hash); - D_P16(new_lmPwdHash.hash, r->in.old_lm_crypted->hash, checkHash.hash); - } - - /* decrypt and check the new nt hash */ - D_P16(nt_pwd->hash, r->in.new_nt_crypted->hash, new_ntPwdHash.hash); - D_P16(new_ntPwdHash.hash, r->in.old_nt_crypted->hash, checkHash.hash); - - /* The NT Cross is not required by Win2k3 R2, but if present - check the nt cross hash */ - if (r->in.cross1_present && r->in.nt_cross && lm_pwd) { - D_P16(lm_pwd->hash, r->in.nt_cross->hash, checkHash.hash); - } - - /* The LM Cross is not required by Win2k3 R2, but if present - check the lm cross hash */ - if (r->in.cross2_present && r->in.lm_cross && lm_pwd) { - D_P16(nt_pwd->hash, r->in.lm_cross->hash, checkHash.hash); - } - - /* Start a SAM with user privileges for the password change */ - sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, - dce_call->conn->dce_ctx->lp_ctx, - dce_call->conn->auth_state.session_info, 0); - if (sam_ctx == NULL) { - return NT_STATUS_INVALID_SYSTEM_SERVICE; - } - - /* Start transaction */ - ret = ldb_transaction_start(sam_ctx); - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx))); - return NT_STATUS_TRANSACTION_ABORTED; - } - - /* Performs the password modification. We pass the old hashes read out - * from the database since they were already checked against the user- - * provided ones. */ - status = samdb_set_password(sam_ctx, mem_ctx, - a_state->account_dn, - a_state->domain_state->domain_dn, - NULL, &new_lmPwdHash, &new_ntPwdHash, - lm_pwd, nt_pwd, /* this is a user password change */ - NULL, - NULL); - if (!NT_STATUS_IS_OK(status)) { - ldb_transaction_cancel(sam_ctx); - return status; - } - - /* decrypt and check the new lm hash */ - if (lm_pwd) { - if (memcmp(checkHash.hash, lm_pwd, 16) != 0) { - ldb_transaction_cancel(sam_ctx); - return NT_STATUS_WRONG_PASSWORD; - } - } - - if (memcmp(checkHash.hash, nt_pwd, 16) != 0) { - ldb_transaction_cancel(sam_ctx); - return NT_STATUS_WRONG_PASSWORD; - } - - /* The NT Cross is not required by Win2k3 R2, but if present - check the nt cross hash */ - if (r->in.cross1_present && r->in.nt_cross && lm_pwd) { - if (memcmp(checkHash.hash, new_ntPwdHash.hash, 16) != 0) { - ldb_transaction_cancel(sam_ctx); - return NT_STATUS_WRONG_PASSWORD; - } - } - - /* The LM Cross is not required by Win2k3 R2, but if present - check the lm cross hash */ - if (r->in.cross2_present && r->in.lm_cross && lm_pwd) { - if (memcmp(checkHash.hash, new_lmPwdHash.hash, 16) != 0) { - ldb_transaction_cancel(sam_ctx); - return NT_STATUS_WRONG_PASSWORD; - } - } - - /* And this confirms it in a transaction commit */ - ret = ldb_transaction_commit(sam_ctx); - if (ret != LDB_SUCCESS) { - DEBUG(1,("Failed to commit transaction to change password on %s: %s\n", - ldb_dn_get_linearized(a_state->account_dn), - ldb_errstring(sam_ctx))); - return NT_STATUS_TRANSACTION_ABORTED; - } - - return NT_STATUS_OK; + return NT_STATUS_NOT_IMPLEMENTED; } /* @@ -275,6 +142,9 @@ E_deshash(new_pass, new_lm_hash); E_old_pw_hash(new_lm_hash, lm_pwd->hash, lm_verifier.hash); + if (memcmp(lm_verifier.hash, r->in.hash->hash, 16) != 0) { + return NT_STATUS_WRONG_PASSWORD; + } /* Connect to a SAMDB with user privileges for the password change */ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, @@ -306,11 +176,6 @@ return status; } - if (memcmp(lm_verifier.hash, r->in.hash->hash, 16) != 0) { - ldb_transaction_cancel(sam_ctx); - return NT_STATUS_WRONG_PASSWORD; - } - /* And this confirms it in a transaction commit */ ret = ldb_transaction_commit(sam_ctx); if (ret != LDB_SUCCESS) { @@ -400,33 +265,8 @@ goto failed; } - /* Connect to a SAMDB with user privileges for the password change */ - sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, - dce_call->conn->dce_ctx->lp_ctx, - dce_call->conn->auth_state.session_info, 0); - if (sam_ctx == NULL) { - return NT_STATUS_INVALID_SYSTEM_SERVICE; - } - - ret = ldb_transaction_start(sam_ctx); - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx))); - return NT_STATUS_TRANSACTION_ABORTED; - } - - /* Performs the password modification. We pass the old hashes read out - * from the database since they were already checked against the user- - * provided ones. */ - status = samdb_set_password(sam_ctx, mem_ctx, - user_dn, NULL, - &new_password, - NULL, NULL, - lm_pwd, nt_pwd, /* this is a user password change */ - &reason, - &dominfo); - - if (!NT_STATUS_IS_OK(status)) { - ldb_transaction_cancel(sam_ctx); + if (r->in.nt_verifier == NULL) { + status = NT_STATUS_WRONG_PASSWORD; goto failed; } @@ -435,7 +275,6 @@ E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash); if (memcmp(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) { - ldb_transaction_cancel(sam_ctx); status = NT_STATUS_WRONG_PASSWORD; goto failed; } @@ -455,13 +294,42 @@ E_deshash(new_pass, new_lm_hash); E_old_pw_hash(new_nt_hash, lm_pwd->hash, lm_verifier.hash); if (memcmp(lm_verifier.hash, r->in.lm_verifier->hash, 16) != 0) { - ldb_transaction_cancel(sam_ctx); status = NT_STATUS_WRONG_PASSWORD; goto failed; } } } + /* Connect to a SAMDB with user privileges for the password change */ + sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, + dce_call->conn->dce_ctx->lp_ctx, + dce_call->conn->auth_state.session_info, 0); + if (sam_ctx == NULL) { + return NT_STATUS_INVALID_SYSTEM_SERVICE; + } + + ret = ldb_transaction_start(sam_ctx); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx))); + return NT_STATUS_TRANSACTION_ABORTED; + } + + /* Performs the password modification. We pass the old hashes read out + * from the database since they were already checked against the user- + * provided ones. */ + status = samdb_set_password(sam_ctx, mem_ctx, + user_dn, NULL, + &new_password, + NULL, NULL, + lm_pwd, nt_pwd, /* this is a user password change */ + &reason, + &dominfo); + + if (!NT_STATUS_IS_OK(status)) { + ldb_transaction_cancel(sam_ctx); + goto failed; + } + /* And this confirms it in a transaction commit */ ret = ldb_transaction_commit(sam_ctx); if (ret != LDB_SUCCESS) { Index: samba-4.1.3+dfsg/source4/torture/rpc/samr.c =================================================================== --- samba-4.1.3+dfsg.orig/source4/torture/rpc/samr.c 2013-12-05 04:16:48.000000000 -0500 +++ samba-4.1.3+dfsg/source4/torture/rpc/samr.c 2014-03-17 08:31:35.393866741 -0400 @@ -1759,6 +1759,12 @@ torture_comment(tctx, "(%s:%s) old_password[%s] new_password[%s] status[%s]\n", __location__, __FUNCTION__, oldpass, newpass, nt_errstr(r.out.result)); + + /* Do not proceed if this call has been removed */ + if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_NOT_IMPLEMENTED)) { + return true; + } + if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION)) { torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_WRONG_PASSWORD, "ChangePasswordUser failed: expected NT_STATUS_WRONG_PASSWORD because we broke the LM hash");