b6b438
From 23f422c0df67c0f9e701e0deb5f1708a930a98bd Mon Sep 17 00:00:00 2001
b6b438
From: Andreas Schneider <asn@samba.org>
b6b438
Date: Tue, 19 Feb 2019 17:40:29 +0100
b6b438
Subject: [PATCH 037/187] s4:rpc_server: Use GnuTLS RC4 for samr password
b6b438
b6b438
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14031
b6b438
b6b438
Signed-off-by: Andreas Schneider <asn@samba.org>
b6b438
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
b6b438
(cherry picked from commit 4326e7de6ba0ce02ab23af7297d2f7242988daa4)
b6b438
---
b6b438
 source4/rpc_server/samr/samr_password.c | 105 ++++++++++++++++++++----
b6b438
 1 file changed, 89 insertions(+), 16 deletions(-)
b6b438
b6b438
diff --git a/source4/rpc_server/samr/samr_password.c b/source4/rpc_server/samr/samr_password.c
b6b438
index fde0de2c3cc..b04e37f06f3 100644
b6b438
--- a/source4/rpc_server/samr/samr_password.c
b6b438
+++ b/source4/rpc_server/samr/samr_password.c
b6b438
@@ -24,7 +24,7 @@
b6b438
 #include "rpc_server/dcerpc_server.h"
b6b438
 #include "rpc_server/samr/dcesrv_samr.h"
b6b438
 #include "system/time.h"
b6b438
-#include "../lib/crypto/crypto.h"
b6b438
+#include "lib/crypto/md4.h"
b6b438
 #include "dsdb/samdb/samdb.h"
b6b438
 #include "auth/auth.h"
b6b438
 #include "libcli/auth/libcli_auth.h"
b6b438
@@ -119,13 +119,15 @@ NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call,
b6b438
 				       "samAccountName",
b6b438
 				       NULL };
b6b438
 	struct samr_Password *lm_pwd;
b6b438
-	DATA_BLOB lm_pwd_blob;
b6b438
 	uint8_t new_lm_hash[16];
b6b438
 	struct samr_Password lm_verifier;
b6b438
 	size_t unicode_pw_len;
b6b438
 	size_t converted_size = 0;
b6b438
 	const char *user_samAccountName = NULL;
b6b438
 	struct dom_sid *user_objectSid = NULL;
b6b438
+	gnutls_cipher_hd_t cipher_hnd = NULL;
b6b438
+	gnutls_datum_t lm_session_key;
b6b438
+	int rc;
b6b438
 
b6b438
 	if (pwbuf == NULL) {
b6b438
 		return NT_STATUS_INVALID_PARAMETER;
b6b438
@@ -179,9 +181,28 @@ NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call,
b6b438
 	}
b6b438
 
b6b438
 	/* decrypt the password we have been given */
b6b438
-	lm_pwd_blob = data_blob(lm_pwd->hash, sizeof(lm_pwd->hash));
b6b438
-	arcfour_crypt_blob(pwbuf->data, 516, &lm_pwd_blob);
b6b438
-	data_blob_free(&lm_pwd_blob);
b6b438
+	lm_session_key = (gnutls_datum_t) {
b6b438
+		.data = lm_pwd->hash,
b6b438
+		.size = sizeof(lm_pwd->hash),
b6b438
+	};
b6b438
+
b6b438
+	rc = gnutls_cipher_init(&cipher_hnd,
b6b438
+				GNUTLS_CIPHER_ARCFOUR_128,
b6b438
+				&lm_session_key,
b6b438
+				NULL);
b6b438
+	if (rc < 0) {
b6b438
+		status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
b6b438
+		goto failed;
b6b438
+	}
b6b438
+
b6b438
+	rc = gnutls_cipher_decrypt(cipher_hnd,
b6b438
+				   pwbuf->data,
b6b438
+				   516);
b6b438
+	gnutls_cipher_deinit(cipher_hnd);
b6b438
+	if (rc < 0) {
b6b438
+		status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
b6b438
+		goto failed;
b6b438
+	}
b6b438
 
b6b438
 	if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
b6b438
 		DEBUG(3,("samr: failed to decode password buffer\n"));
b6b438
@@ -315,7 +336,6 @@ NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
b6b438
 				       "badPwdCount", "badPasswordTime",
b6b438
 				       "objectSid", NULL };
b6b438
 	struct samr_Password *nt_pwd, *lm_pwd;
b6b438
-	DATA_BLOB nt_pwd_blob;
b6b438
 	struct samr_DomInfo1 *dominfo = NULL;
b6b438
 	struct userPwdChangeFailureInformation *reject = NULL;
b6b438
 	enum samPwdChangeReason reason = SAM_PWD_CHANGE_NO_ERROR;
b6b438
@@ -325,6 +345,9 @@ NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
b6b438
 	struct dom_sid *user_objectSid = NULL;
b6b438
 	enum ntlm_auth_level ntlm_auth_level
b6b438
 		= lpcfg_ntlm_auth(dce_call->conn->dce_ctx->lp_ctx);
b6b438
+	gnutls_cipher_hd_t cipher_hnd = NULL;
b6b438
+	gnutls_datum_t nt_session_key;
b6b438
+	int rc;
b6b438
 
b6b438
 	*r->out.dominfo = NULL;
b6b438
 	*r->out.reject = NULL;
b6b438
@@ -381,9 +404,28 @@ NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
b6b438
 	}
b6b438
 
b6b438
 	/* decrypt the password we have been given */
b6b438
-	nt_pwd_blob = data_blob(nt_pwd->hash, sizeof(nt_pwd->hash));
b6b438
-	arcfour_crypt_blob(r->in.nt_password->data, 516, &nt_pwd_blob);
b6b438
-	data_blob_free(&nt_pwd_blob);
b6b438
+	nt_session_key = (gnutls_datum_t) {
b6b438
+		.data = nt_pwd->hash,
b6b438
+		.size = sizeof(nt_pwd->hash),
b6b438
+	};
b6b438
+
b6b438
+	rc = gnutls_cipher_init(&cipher_hnd,
b6b438
+				GNUTLS_CIPHER_ARCFOUR_128,
b6b438
+				&nt_session_key,
b6b438
+				NULL);
b6b438
+	if (rc < 0) {
b6b438
+		status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
b6b438
+		goto failed;
b6b438
+	}
b6b438
+
b6b438
+	rc = gnutls_cipher_decrypt(cipher_hnd,
b6b438
+				   r->in.nt_password->data,
b6b438
+				   516);
b6b438
+	gnutls_cipher_deinit(cipher_hnd);
b6b438
+	if (rc < 0) {
b6b438
+		status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
b6b438
+		goto failed;
b6b438
+	}
b6b438
 
b6b438
 	if (!extract_pw_from_buffer(mem_ctx, r->in.nt_password->data, &new_password)) {
b6b438
 		DEBUG(3,("samr: failed to decode password buffer\n"));
b6b438
@@ -547,6 +589,9 @@ NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
b6b438
 	NTSTATUS nt_status;
b6b438
 	DATA_BLOB new_password;
b6b438
 	DATA_BLOB session_key = data_blob(NULL, 0);
b6b438
+	gnutls_cipher_hd_t cipher_hnd = NULL;
b6b438
+	gnutls_datum_t _session_key;
b6b438
+	int rc;
b6b438
 
b6b438
 	nt_status = dcesrv_transport_session_key(dce_call, &session_key);
b6b438
 	if (!NT_STATUS_IS_OK(nt_status)) {
b6b438
@@ -556,7 +601,28 @@ NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
b6b438
 		return NT_STATUS_WRONG_PASSWORD;
b6b438
 	}
b6b438
 
b6b438
-	arcfour_crypt_blob(pwbuf->data, 516, &session_key);
b6b438
+	_session_key = (gnutls_datum_t) {
b6b438
+		.data = session_key.data,
b6b438
+		.size = session_key.length,
b6b438
+	};
b6b438
+
b6b438
+	rc = gnutls_cipher_init(&cipher_hnd,
b6b438
+				GNUTLS_CIPHER_ARCFOUR_128,
b6b438
+				&_session_key,
b6b438
+				NULL);
b6b438
+	if (rc < 0) {
b6b438
+		nt_status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
b6b438
+		goto out;
b6b438
+	}
b6b438
+
b6b438
+	rc = gnutls_cipher_decrypt(cipher_hnd,
b6b438
+				   pwbuf->data,
b6b438
+				   516);
b6b438
+	gnutls_cipher_deinit(cipher_hnd);
b6b438
+	if (rc < 0) {
b6b438
+		nt_status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
b6b438
+		goto out;
b6b438
+	}
b6b438
 
b6b438
 	if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
b6b438
 		DEBUG(3,("samr: failed to decode password buffer\n"));
b6b438
@@ -565,12 +631,19 @@ NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
b6b438
 
b6b438
 	/* set the password - samdb needs to know both the domain and user DNs,
b6b438
 	   so the domain password policy can be used */
b6b438
-	return samdb_set_password(sam_ctx, mem_ctx,
b6b438
-				  account_dn, domain_dn,
b6b438
-				  &new_password,
b6b438
-				  NULL, NULL,
b6b438
-				  NULL, NULL, /* This is a password set, not change */
b6b438
-				  NULL, NULL);
b6b438
+	nt_status = samdb_set_password(sam_ctx,
b6b438
+				       mem_ctx,
b6b438
+				       account_dn,
b6b438
+				       domain_dn,
b6b438
+				       &new_password,
b6b438
+				       NULL,
b6b438
+				       NULL,
b6b438
+				       NULL,
b6b438
+				       NULL, /* This is a password set, not change */
b6b438
+				       NULL,
b6b438
+				       NULL);
b6b438
+out:
b6b438
+	return nt_status;
b6b438
 }
b6b438
 
b6b438
 
b6b438
-- 
b6b438
2.23.0
b6b438