summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBartłomiej Piotrowski <bpiotrowski@alpinelinux.org>2014-03-13 08:01:28 +0100
committerBartłomiej Piotrowski <bpiotrowski@alpinelinux.org>2014-03-13 08:01:28 +0100
commit76de16d250f042fac913558e3579a5b9e4a21a5c (patch)
treeb1020c62416422452743088a70cbda834ca84c8b
parenta48dd9fb484b74733e8b1c6827712e9770eafe16 (diff)
downloadaports-76de16d250f042fac913558e3579a5b9e4a21a5c.tar.bz2
aports-76de16d250f042fac913558e3579a5b9e4a21a5c.tar.xz
main/samba: security fix for CVE-2013-4496 and CVE-2013-6442
-rw-r--r--main/samba/APKBUILD12
-rw-r--r--main/samba/samba-4.1.5-CVE-2013-4496-CVE-2013-6442.patch1149
2 files changed, 1157 insertions, 4 deletions
diff --git a/main/samba/APKBUILD b/main/samba/APKBUILD
index bfe6ab75b..30d8166a0 100644
--- a/main/samba/APKBUILD
+++ b/main/samba/APKBUILD
@@ -1,7 +1,7 @@
# Maintainer: Natanael Copa <ncopa@alpinelinux.org>
pkgname=samba
pkgver=4.1.3
-pkgrel=0
+pkgrel=1
pkgdesc="Tools to access a server's filespace and printers via SMB"
url="http://www.samba.org"
arch="all"
@@ -22,6 +22,7 @@ source="http://us1.samba.org/samba/ftp/stable/samba-$pkgver.tar.gz
samba.initd
samba.confd
samba.logrotate
+ samba-4.1.5-CVE-2013-4496-CVE-2013-6442.patch
"
pkggroups="winbind"
@@ -289,12 +290,15 @@ libs() {
md5sums="a5dbfe87f4cb3d9d91e15e5df99a59a1 samba-4.1.3.tar.gz
044c756d3c33c2d610c40bcd76cfb75c samba.initd
c150433426e18261e6e3eed3930e1a76 samba.confd
-b7cafabfb4fa5b3ab5f2e857d8d1c733 samba.logrotate"
+b7cafabfb4fa5b3ab5f2e857d8d1c733 samba.logrotate
+7907376d241adef1b9c8197484aef192 samba-4.1.5-CVE-2013-4496-CVE-2013-6442.patch"
sha256sums="71da208d412b8d15ee26d2a76b2247df357242177d995fe5d9320355432e24db samba-4.1.3.tar.gz
86646cb845aababd9e8655994379526f03327a2cc33b489c3a7dea83ab689c8f samba.initd
1d12f98a7727967b04eb123109b34cfffef320822dc0e8059286b6e3394c3fc0 samba.confd
-4c2b7d529126b2fc4f62fb09d99e49a87632d723a2d9d289a61e37dd84145be1 samba.logrotate"
+4c2b7d529126b2fc4f62fb09d99e49a87632d723a2d9d289a61e37dd84145be1 samba.logrotate
+ed57a4a50d95f43b2ff2d52a3a00e812e8b5589c226cb3be9d69cd4e5a15b2d8 samba-4.1.5-CVE-2013-4496-CVE-2013-6442.patch"
sha512sums="c3e08df4e23c02ab759e819809ac8b146972508bbbbfc666e47ac180dea75dde85564e839aa4935e43f9b894bdf650fd3ed36463e70e9065c6e1c745142984d5 samba-4.1.3.tar.gz
59d05252b8ebbe6ba6a419edc86b66b9541d0bac9dbe810cccb20e64f6044e2900cc6c0979e077741ed00fbbf2d51f9184c83715013299782707b44e39aa99b1 samba.initd
4faf581ecef3ec38319e3c4ab6d3995c51fd7ba83180dc5553a2ff4dfb92efadb43030c543292130c4ed0c281dc0972c6973d52d48062c5edb39bb1c4bbb6dd6 samba.confd
-f88ebe59ca3a9e9b77dd5993c13ef3e73a838efb8ed858088b464a330132d662f33e25c27819e38835389dee23057a3951de11bae1eef55db8ff5e1ec6760053 samba.logrotate"
+f88ebe59ca3a9e9b77dd5993c13ef3e73a838efb8ed858088b464a330132d662f33e25c27819e38835389dee23057a3951de11bae1eef55db8ff5e1ec6760053 samba.logrotate
+52c835409d59dac7d153a83b1ccf86ccafe2e49d7da5f643575fb1826cb1e55ac691ff1071764c92ada0e9bb557c060fd52340dd96258a7e18b87f044329f295 samba-4.1.5-CVE-2013-4496-CVE-2013-6442.patch"
diff --git a/main/samba/samba-4.1.5-CVE-2013-4496-CVE-2013-6442.patch b/main/samba/samba-4.1.5-CVE-2013-4496-CVE-2013-6442.patch
new file mode 100644
index 000000000..f448a3ccc
--- /dev/null
+++ b/main/samba/samba-4.1.5-CVE-2013-4496-CVE-2013-6442.patch
@@ -0,0 +1,1149 @@
+From c129261c506c6b941630fd7f4bc72820eb272761 Mon Sep 17 00:00:00 2001
+From: Andrew Bartlett <abartlet@samba.org>
+Date: Fri, 1 Nov 2013 14:55:44 +1300
+Subject: [PATCH 1/4] CVE-2013-4496:s3-samr: Block attempts to crack passwords
+ via repeated password changes
+
+Bug: https://bugzilla.samba.org/show_bug.cgi?id=10245
+
+Signed-off-by: Andrew Bartlett <abartlet@samba.org>
+Signed-off-by: Stefan Metzmacher <metze@samba.org>
+Signed-off-by: Jeremy Allison <jra@samba.org>
+Reviewed-by: Stefan Metzmacher <metze@samba.org>
+Reviewed-by: Jeremy Allison <jra@samba.org>
+Reviewed-by: Andreas Schneider <asn@samba.org>
+---
+ source3/rpc_server/samr/srv_samr_chgpasswd.c | 55 ++++++++++++++++
+ source3/rpc_server/samr/srv_samr_nt.c | 90 +++++++++++++++++++++-----
+ 2 files changed, 129 insertions(+), 16 deletions(-)
+
+diff --git a/source3/rpc_server/samr/srv_samr_chgpasswd.c b/source3/rpc_server/samr/srv_samr_chgpasswd.c
+index db1f459..1c9c33a 100644
+--- a/source3/rpc_server/samr/srv_samr_chgpasswd.c
++++ b/source3/rpc_server/samr/srv_samr_chgpasswd.c
+@@ -1106,6 +1106,8 @@ NTSTATUS pass_oem_change(char *user, const char *rhost,
+ 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 @@ NTSTATUS pass_oem_change(char *user, const char *rhost,
+ 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 @@ NTSTATUS pass_oem_change(char *user, const char *rhost,
+ 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;
+diff --git a/source3/rpc_server/samr/srv_samr_nt.c b/source3/rpc_server/samr/srv_samr_nt.c
+index b366eda..98e8bea 100644
+--- a/source3/rpc_server/samr/srv_samr_nt.c
++++ b/source3/rpc_server/samr/srv_samr_nt.c
+@@ -1722,9 +1722,11 @@ NTSTATUS _samr_ChangePasswordUser(struct pipes_struct *p,
+ NTSTATUS status;
+ bool ret = false;
+ struct samr_user_info *uinfo;
+- struct samu *pwd;
++ struct samu *pwd = NULL;
+ struct samr_Password new_lmPwdHash, new_ntPwdHash, checkHash;
+ struct samr_Password lm_pwd, nt_pwd;
++ bool updated_badpw = false;
++ NTSTATUS update_login_attempts_status;
+
+ uinfo = policy_handle_find(p, r->in.user_handle,
+ SAMR_USER_ACCESS_SET_PASSWORD, NULL,
+@@ -1736,6 +1738,15 @@ NTSTATUS _samr_ChangePasswordUser(struct pipes_struct *p,
+ DEBUG(5,("_samr_ChangePasswordUser: sid:%s\n",
+ sid_string_dbg(&uinfo->sid)));
+
++ /* 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;
++ }
++
+ if (!(pwd = samu_new(NULL))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+@@ -1749,6 +1760,14 @@ NTSTATUS _samr_ChangePasswordUser(struct pipes_struct *p,
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
++ /* Quit if the account was locked out. */
++ if (pdb_get_acct_ctrl(pwd) & ACB_AUTOLOCK) {
++ DEBUG(3, ("Account for user %s was locked out.\n",
++ pdb_get_username(pwd)));
++ status = NT_STATUS_ACCOUNT_LOCKED_OUT;
++ goto out;
++ }
++
+ {
+ const uint8_t *lm_pass, *nt_pass;
+
+@@ -1757,29 +1776,19 @@ NTSTATUS _samr_ChangePasswordUser(struct pipes_struct *p,
+
+ if (!lm_pass || !nt_pass) {
+ status = NT_STATUS_WRONG_PASSWORD;
+- goto out;
++ goto update_login;
+ }
+
+ 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;
++ goto update_login;
+ }
+
+ /* decrypt and check the new nt hash */
+@@ -1787,7 +1796,7 @@ NTSTATUS _samr_ChangePasswordUser(struct pipes_struct *p,
+ 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;
++ goto update_login;
+ }
+
+ /* The NT Cross is not required by Win2k3 R2, but if present
+@@ -1796,7 +1805,7 @@ NTSTATUS _samr_ChangePasswordUser(struct pipes_struct *p,
+ 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;
++ goto update_login;
+ }
+ }
+
+@@ -1806,7 +1815,7 @@ NTSTATUS _samr_ChangePasswordUser(struct pipes_struct *p,
+ 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;
++ goto update_login;
+ }
+ }
+
+@@ -1817,6 +1826,55 @@ NTSTATUS _samr_ChangePasswordUser(struct pipes_struct *p,
+ }
+
+ status = pdb_update_sam_account(pwd);
++
++update_login:
++
++ /*
++ * 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(pwd,
++ NT_STATUS_IS_OK(status));
++
++ if (!NT_STATUS_IS_OK(status)) {
++ bool increment_bad_pw_count = false;
++
++ if (NT_STATUS_EQUAL(status,NT_STATUS_WRONG_PASSWORD) &&
++ (pdb_get_acct_ctrl(pwd) & 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(pwd);
++ updated_badpw = true;
++ } else {
++ pdb_update_bad_password_count(pwd,
++ &updated_badpw);
++ }
++ } else {
++
++ if ((pdb_get_acct_ctrl(pwd) & ACB_NORMAL) &&
++ (pdb_get_bad_password_count(pwd) > 0)){
++ pdb_set_bad_password_count(pwd, 0, PDB_CHANGED);
++ pdb_set_bad_password_time(pwd, 0, PDB_CHANGED);
++ updated_badpw = true;
++ }
++ }
++
++ if (updated_badpw) {
++ NTSTATUS update_status;
++ become_root();
++ update_status = pdb_update_sam_account(pwd);
++ unbecome_root();
++
++ if (!NT_STATUS_IS_OK(update_status)) {
++ DEBUG(1, ("Failed to modify entry: %s\n",
++ nt_errstr(update_status)));
++ }
++ }
++
+ out:
+ TALLOC_FREE(pwd);
+
+--
+1.7.9.5
+
+
+From fab5ee090e2e4765441b82e17a6cbb98523f6943 Mon Sep 17 00:00:00 2001
+From: Stefan Metzmacher <metze@samba.org>
+Date: Tue, 5 Nov 2013 14:04:20 +0100
+Subject: [PATCH 2/4] CVE-2013-4496:s3:auth: fix memory leak in the
+ ACCOUNT_LOCKED_OUT case.
+
+Bug: https://bugzilla.samba.org/show_bug.cgi?id=10245
+
+Signed-off-by: Stefan Metzmacher <metze@samba.org>
+Reviewed-by: Jeremy Allison <jra@samba.org>
+Signed-off-by: Andrew Bartlett <abartlet@samba.org>
+Reviewed-by: Andreas Schneider <asn@samba.org>
+---
+ source3/auth/check_samsec.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/source3/auth/check_samsec.c b/source3/auth/check_samsec.c
+index 7ed8cc2..94f30b1 100644
+--- a/source3/auth/check_samsec.c
++++ b/source3/auth/check_samsec.c
+@@ -408,6 +408,7 @@ NTSTATUS check_sam_security(const DATA_BLOB *challenge,
+ /* 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;
+ }
+
+--
+1.7.9.5
+
+
+From bf3443c12f2a67481eb2e45ca41b906c438d06da Mon Sep 17 00:00:00 2001
+From: Andrew Bartlett <abartlet@samba.org>
+Date: Tue, 5 Nov 2013 16:16:46 +1300
+Subject: [PATCH 3/4] CVE-2013-4496:samr: Remove ChangePasswordUser
+
+This old password change mechanism does not provide the plaintext to
+validate against password complexity, and it is not used by modern
+clients.
+
+The missing features in both implementations (by design) were:
+
+ - the password complexity checks (no plaintext)
+ - the minimum password length (no plaintext)
+
+Additionally, the source3 version did not check:
+
+ - the minimum password age
+ - pdb_get_pass_can_change() which checks the security
+ descriptor for the 'user cannot change password' setting.
+ - the password history
+ - the output of the 'passwd program' if 'unix passwd sync = yes'.
+
+Finally, the mechanism was almost useless, as it was incorrectly
+only made available to administrative users with permission
+to reset the password. It is removed here so that it is not
+mistakenly reinstated in the future.
+
+Andrew Bartlett
+
+Bug: https://bugzilla.samba.org/show_bug.cgi?id=10245
+
+Signed-off-by: Andrew Bartlett <abartlet@samba.org>
+Reviewed-by: Andreas Schneider <asn@samba.org>
+Reviewed-by: Stefan Metzmacher <metze@samba.org>
+---
+ source3/rpc_server/samr/srv_samr_nt.c | 169 +-------------------
+ source3/smbd/lanman.c | 254 -------------------------------
+ source4/rpc_server/samr/samr_password.c | 145 +-----------------
+ source4/torture/rpc/samr.c | 6 +
+ 4 files changed, 20 insertions(+), 554 deletions(-)
+
+diff --git a/source3/rpc_server/samr/srv_samr_nt.c b/source3/rpc_server/samr/srv_samr_nt.c
+index 98e8bea..99f03ec 100644
+--- a/source3/rpc_server/samr/srv_samr_nt.c
++++ b/source3/rpc_server/samr/srv_samr_nt.c
+@@ -1713,172 +1713,19 @@ NTSTATUS _samr_LookupNames(struct pipes_struct *p,
+ }
+
+ /****************************************************************
+- _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 = NULL;
+- struct samr_Password new_lmPwdHash, new_ntPwdHash, checkHash;
+- struct samr_Password lm_pwd, nt_pwd;
+- bool updated_badpw = false;
+- NTSTATUS update_login_attempts_status;
+-
+- 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)));
+-
+- /* 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;
+- }
+-
+- 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;
+- }
+-
+- /* Quit if the account was locked out. */
+- if (pdb_get_acct_ctrl(pwd) & ACB_AUTOLOCK) {
+- DEBUG(3, ("Account for user %s was locked out.\n",
+- pdb_get_username(pwd)));
+- status = NT_STATUS_ACCOUNT_LOCKED_OUT;
+- goto out;
+- }
+-
+- {
+- 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 update_login;
+- }
+-
+- memcpy(&lm_pwd.hash, lm_pass, sizeof(lm_pwd.hash));
+- memcpy(&nt_pwd.hash, nt_pass, sizeof(nt_pwd.hash));
+- }
+-
+- /* 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 update_login;
+- }
+-
+- /* 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 update_login;
+- }
+-
+- /* 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 update_login;
+- }
+- }
+-
+- /* 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 update_login;
+- }
+- }
+-
+- 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);
+-
+-update_login:
+-
+- /*
+- * 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(pwd,
+- NT_STATUS_IS_OK(status));
+-
+- if (!NT_STATUS_IS_OK(status)) {
+- bool increment_bad_pw_count = false;
+-
+- if (NT_STATUS_EQUAL(status,NT_STATUS_WRONG_PASSWORD) &&
+- (pdb_get_acct_ctrl(pwd) & 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(pwd);
+- updated_badpw = true;
+- } else {
+- pdb_update_bad_password_count(pwd,
+- &updated_badpw);
+- }
+- } else {
+-
+- if ((pdb_get_acct_ctrl(pwd) & ACB_NORMAL) &&
+- (pdb_get_bad_password_count(pwd) > 0)){
+- pdb_set_bad_password_count(pwd, 0, PDB_CHANGED);
+- pdb_set_bad_password_time(pwd, 0, PDB_CHANGED);
+- updated_badpw = true;
+- }
+- }
+-
+- if (updated_badpw) {
+- NTSTATUS update_status;
+- become_root();
+- update_status = pdb_update_sam_account(pwd);
+- unbecome_root();
+-
+- if (!NT_STATUS_IS_OK(update_status)) {
+- DEBUG(1, ("Failed to modify entry: %s\n",
+- nt_errstr(update_status)));
+- }
+- }
+-
+- out:
+- TALLOC_FREE(pwd);
+-
+- return status;
++ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ /*******************************************************************
+diff --git a/source3/smbd/lanman.c b/source3/smbd/lanman.c
+index e6b9530..1b734a7 100644
+--- a/source3/smbd/lanman.c
++++ b/source3/smbd/lanman.c
+@@ -2948,259 +2948,6 @@ static bool api_NetRemoteTOD(struct smbd_server_connection *sconn,
+ }
+
+ /****************************************************************************
+- 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 @@ static const struct {
+ {"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},
+diff --git a/source4/rpc_server/samr/samr_password.c b/source4/rpc_server/samr/samr_password.c
+index 2d9c48a..9d6c921 100644
+--- a/source4/rpc_server/samr/samr_password.c
++++ b/source4/rpc_server/samr/samr_password.c
+@@ -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;
+ }
+
+ /*
+diff --git a/source4/torture/rpc/samr.c b/source4/torture/rpc/samr.c
+index a0a5f1a..cdfa2b8 100644
+--- a/source4/torture/rpc/samr.c
++++ b/source4/torture/rpc/samr.c
+@@ -1759,6 +1759,12 @@ static bool test_ChangePasswordUser(struct dcerpc_binding_handle *b,
+ 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");
+--
+1.7.9.5
+
+
+From b0281ad59d3ba8b32787ce112fb4a83d935c60d1 Mon Sep 17 00:00:00 2001
+From: Andrew Bartlett <abartlet@samba.org>
+Date: Thu, 28 Nov 2013 06:50:01 +1300
+Subject: [PATCH 4/4] CVE-2013-4496:Revert remainder of
+ ce895609b04380bfc41e4f8fddc84bd2f9324340
+
+Part of this was removed when ChangePasswordUser was unimplemented,
+but remove the remainder of this flawed commit. Fully check the
+password first, as extract_pw_from_buffer() already does a partial
+check of the password because it needs a correct old password to
+correctly decrypt the length.
+
+Andrew Bartlett
+
+Bug: https://bugzilla.samba.org/show_bug.cgi?id=10245
+
+Signed-off-by: Andrew Bartlett <abartlet@samba.org>
+Reviewed-by: Andreas Schneider <asn@samba.org>
+Reviewed-by: Stefan Metzmacher <metze@samba.org>
+---
+ source4/rpc_server/samr/samr_password.c | 69 ++++++++++++++++---------------
+ 1 file changed, 35 insertions(+), 34 deletions(-)
+
+diff --git a/source4/rpc_server/samr/samr_password.c b/source4/rpc_server/samr/samr_password.c
+index 9d6c921..685a8e7 100644
+--- a/source4/rpc_server/samr/samr_password.c
++++ b/source4/rpc_server/samr/samr_password.c
+@@ -142,6 +142,9 @@ NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call,
+
+ 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,
+@@ -173,11 +176,6 @@ NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call,
+ 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) {
+@@ -267,33 +265,8 @@ NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
+ 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;
+ }
+
+@@ -302,7 +275,6 @@ NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
+
+ 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;
+ }
+@@ -322,13 +294,42 @@ NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
+ 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) {
+--
+1.7.9.5
+
+From 82b1dafad17904bc224b0632486006fe88301b57 Mon Sep 17 00:00:00 2001
+From: Jeremy Allison <jra@samba.org>
+Date: Wed, 18 Dec 2013 13:56:18 -0800
+Subject: [PATCH] CVE-2013-6442: s3:smbcacls - ensure we don't lose an existing
+ ACL when setting owner or group owner.
+
+Bug: https://bugzilla.samba.org/show_bug.cgi?id=10327
+Bug 10327 - CVE-2013-6442: smbcacls --chown | --chgrp dacl regression
+
+Signed-off-by: Jeremy Allison <jra@samba.org>
+Reviewed-by: Stefan Metzmacher <metze@samba.org>
+---
+ source3/utils/smbcacls.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/source3/utils/smbcacls.c b/source3/utils/smbcacls.c
+index 11b7388..e3b7099 100644
+--- a/source3/utils/smbcacls.c
++++ b/source3/utils/smbcacls.c
+@@ -990,7 +990,7 @@ static int owner_set(struct cli_state *cli, enum chown_mode change_mode,
+ return EXIT_FAILED;
+ }
+
+- sd = make_sec_desc(talloc_tos(),old->revision, old->type,
++ sd = make_sec_desc(talloc_tos(),old->revision, SEC_DESC_SELF_RELATIVE,
+ (change_mode == REQUEST_CHOWN) ? &sid : NULL,
+ (change_mode == REQUEST_CHGRP) ? &sid : NULL,
+ NULL, NULL, &sd_size);
+--
+1.8.5.1
+