#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>
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;
+}
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 */