1
0
mirror of https://github.com/samba-team/samba.git synced 2025-03-09 08:58:35 +03:00

s3:rpc_server: Implement dcesrv_samr_ChangePasswordUser4()

Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
This commit is contained in:
Andreas Schneider 2022-02-28 13:51:40 +01:00 committed by Andreas Schneider
parent 68b7863f19
commit 1ca42e12ef
3 changed files with 174 additions and 0 deletions

View File

@ -54,6 +54,7 @@
#include "passdb.h"
#include "auth.h"
#include "lib/util/sys_rw.h"
#include "librpc/rpc/dcerpc_samr.h"
#include "lib/crypto/gnutls_helpers.h"
#include <gnutls/gnutls.h>
@ -1297,3 +1298,63 @@ NTSTATUS pass_oem_change(char *user, const char *rhost,
return nt_status;
}
NTSTATUS samr_set_password_aes(TALLOC_CTX *mem_ctx,
struct samu *sampass,
const char *rhost,
const DATA_BLOB *cdk,
struct samr_EncryptedPasswordAES *pwbuf,
enum samPwdChangeReason *reject_reason)
{
DATA_BLOB pw_data = data_blob_null;
DATA_BLOB new_password = data_blob_null;
const DATA_BLOB ciphertext =
data_blob_const(pwbuf->cipher, pwbuf->cipher_len);
DATA_BLOB iv = data_blob_const(pwbuf->salt, sizeof(pwbuf->salt));
char *new_password_str = NULL;
NTSTATUS status;
bool ok;
status = samba_gnutls_aead_aes_256_cbc_hmac_sha512_decrypt(
mem_ctx,
&ciphertext,
cdk,
&samr_aes256_enc_key_salt,
&samr_aes256_mac_key_salt,
&iv,
pwbuf->auth_data,
&pw_data);
if (!NT_STATUS_IS_OK(status)) {
return NT_STATUS_WRONG_PASSWORD;
}
ok = decode_pwd_string_from_buffer514(mem_ctx,
pw_data.data,
CH_UTF16,
&new_password);
TALLOC_FREE(pw_data.data);
if (!ok) {
DBG_NOTICE("samr: failed to decode password buffer\n");
return NT_STATUS_WRONG_PASSWORD;
}
new_password_str = talloc_strndup(mem_ctx,
(char *)new_password.data,
new_password.length);
TALLOC_FREE(new_password.data);
if (new_password_str == NULL) {
return NT_STATUS_NO_MEMORY;
}
become_root();
status = change_oem_password(sampass,
rhost,
NULL,
new_password_str,
true,
reject_reason);
unbecome_root();
TALLOC_FREE(new_password_str);
return status;
}

View File

@ -7677,8 +7677,115 @@ void _samr_Opnum72NotUsedOnWire(struct pipes_struct *p,
NTSTATUS _samr_ChangePasswordUser4(struct pipes_struct *p,
struct samr_ChangePasswordUser4 *r)
{
#ifdef HAVE_GNUTLS_PBKDF2
TALLOC_CTX *frame = talloc_stackframe();
struct dcesrv_call_state *dce_call = p->dce_call;
struct dcesrv_connection *dcesrv_conn = dce_call->conn;
const struct tsocket_address *remote_address =
dcesrv_connection_get_remote_address(dcesrv_conn);
enum samPwdChangeReason reject_reason;
char *rhost = NULL;
struct samu *sampass = NULL;
char *username = NULL;
uint32_t acct_ctrl = 0;
const uint8_t *nt_pw = NULL;
gnutls_datum_t nt_key;
gnutls_datum_t salt = {
.data = r->in.password->salt,
.size = sizeof(r->in.password->salt),
};
uint8_t cdk_data[16] = {0};
DATA_BLOB cdk = {
.data = cdk_data,
.length = sizeof(cdk_data),
};
NTSTATUS status = NT_STATUS_WRONG_PASSWORD;
bool ok;
int rc;
r->out.result = NT_STATUS_WRONG_PASSWORD;
DBG_NOTICE("_samr_ChangePasswordUser4\n");
if (r->in.account->string == NULL) {
return NT_STATUS_INVALID_PARAMETER;
}
if (r->in.password == NULL) {
return NT_STATUS_INVALID_PARAMETER;
}
if (r->in.password->PBKDF2Iterations < 5000 ||
r->in.password->PBKDF2Iterations > 1000000) {
return NT_STATUS_INVALID_PARAMETER;
}
(void)map_username(frame, r->in.account->string, &username);
if (username == NULL) {
return NT_STATUS_NO_MEMORY;
}
rhost = tsocket_address_inet_addr_string(remote_address, frame);
if (rhost == NULL) {
status = NT_STATUS_NO_MEMORY;
goto done;
}
sampass = samu_new(frame);
if (sampass == NULL) {
status = NT_STATUS_NO_MEMORY;
goto done;
}
become_root();
ok = pdb_getsampwnam(sampass, username);
unbecome_root();
if (!ok) {
status = NT_STATUS_NO_SUCH_USER;
goto done;
}
acct_ctrl = pdb_get_acct_ctrl(sampass);
if (acct_ctrl & ACB_AUTOLOCK) {
status = NT_STATUS_ACCOUNT_LOCKED_OUT;
goto done;
}
nt_pw = pdb_get_nt_passwd(sampass);
nt_key = (gnutls_datum_t){
.data = discard_const_p(uint8_t, nt_pw),
.size = NT_HASH_LEN,
};
rc = gnutls_pbkdf2(GNUTLS_MAC_SHA512,
&nt_key,
&salt,
r->in.password->PBKDF2Iterations,
cdk.data,
cdk.length);
if (rc < 0) {
BURN_DATA(cdk_data);
status = NT_STATUS_WRONG_PASSWORD;
goto done;
}
status = samr_set_password_aes(frame,
sampass,
rhost,
&cdk,
r->in.password,
&reject_reason);
BURN_DATA(cdk_data);
if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
return NT_STATUS_WRONG_PASSWORD;
}
done:
TALLOC_FREE(frame);
return status;
#else /* HAVE_GNUTLS_PBKDF2 */
p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
return NT_STATUS_NOT_IMPLEMENTED;
#endif /* HAVE_GNUTLS_PBKDF2 */
}
/* include the generated boilerplate */

View File

@ -79,3 +79,9 @@ NTSTATUS check_password_complexity(const char *username,
const char *fullname,
const char *password,
enum samPwdChangeReason *samr_reject_reason);
NTSTATUS samr_set_password_aes(TALLOC_CTX *mem_ctx,
struct samu *sampass,
const char *rhost,
const DATA_BLOB *cdk,
struct samr_EncryptedPasswordAES *pwbuf,
enum samPwdChangeReason *reject_reason);