From: Andreas Schneider Date: Mon, 28 Feb 2022 12:51:40 +0000 (+0100) Subject: s3:rpc_server: Implement dcesrv_samr_ChangePasswordUser4() X-Git-Tag: samba-4.17.0rc1~191 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=1ca42e12ef27eea29787bb4cebacf325be3e2f9f;p=thirdparty%2Fsamba.git s3:rpc_server: Implement dcesrv_samr_ChangePasswordUser4() Signed-off-by: Andreas Schneider Reviewed-by: Stefan Metzmacher --- diff --git a/source3/rpc_server/samr/srv_samr_chgpasswd.c b/source3/rpc_server/samr/srv_samr_chgpasswd.c index 56dc7397b9d..f1d833a630c 100644 --- a/source3/rpc_server/samr/srv_samr_chgpasswd.c +++ b/source3/rpc_server/samr/srv_samr_chgpasswd.c @@ -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 @@ -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; +} diff --git a/source3/rpc_server/samr/srv_samr_nt.c b/source3/rpc_server/samr/srv_samr_nt.c index ee92014f762..4f8605eb576 100644 --- a/source3/rpc_server/samr/srv_samr_nt.c +++ b/source3/rpc_server/samr/srv_samr_nt.c @@ -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 */ diff --git a/source3/rpc_server/samr/srv_samr_util.h b/source3/rpc_server/samr/srv_samr_util.h index 475e2c3728d..a702d5d449c 100644 --- a/source3/rpc_server/samr/srv_samr_util.h +++ b/source3/rpc_server/samr/srv_samr_util.h @@ -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);