CVE-2021-20251 s4-rpc_server: Check badPwdCount update return status
[Samba.git] / source4 / rpc_server / samr / samr_password.c
blobe55d5c28b5c3d41d59a7338b17e12d870ec51b51
1 /*
2 Unix SMB/CIFS implementation.
4 samr server password set/change handling
6 Copyright (C) Andrew Tridgell 2004
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "rpc_server/dcerpc_server.h"
25 #include "rpc_server/common/common.h"
26 #include "rpc_server/samr/dcesrv_samr.h"
27 #include "system/time.h"
28 #include "lib/crypto/md4.h"
29 #include "dsdb/common/util.h"
30 #include "dsdb/samdb/samdb.h"
31 #include "auth/auth.h"
32 #include "libcli/auth/libcli_auth.h"
33 #include "../lib/util/util_ldb.h"
34 #include "rpc_server/samr/proto.h"
35 #include "auth/auth_sam.h"
36 #include "lib/param/loadparm.h"
37 #include "librpc/rpc/dcerpc_helper.h"
38 #include "librpc/rpc/dcerpc_samr.h"
40 #include "lib/crypto/gnutls_helpers.h"
41 #include <gnutls/gnutls.h>
42 #include <gnutls/crypto.h>
44 static void log_password_change_event(struct imessaging_context *msg_ctx,
45 struct loadparm_context *lp_ctx,
46 const struct tsocket_address *remote_client_address,
47 const struct tsocket_address *local_server_address,
48 const char *auth_description,
49 const char *password_type,
50 const char *original_client_name,
51 const char *account_name_from_db,
52 NTSTATUS status,
53 struct dom_sid *sid)
56 * Forcing this via the NTLM auth structure is not ideal, but
57 * it is the most practical option right now, and ensures the
58 * logs are consistent, even if some elements are always NULL.
60 struct auth_usersupplied_info ui = {
61 .was_mapped = true,
62 .client = {
63 .account_name = original_client_name,
64 .domain_name = lpcfg_sam_name(lp_ctx),
66 .mapped = {
67 .account_name = account_name_from_db,
68 .domain_name = lpcfg_sam_name(lp_ctx),
70 .remote_host = remote_client_address,
71 .local_host = local_server_address,
72 .service_description = "SAMR Password Change",
73 .auth_description = auth_description,
74 .password_type = password_type,
77 log_authentication_event(msg_ctx,
78 lp_ctx,
79 NULL,
80 &ui,
81 status,
82 ui.mapped.domain_name,
83 ui.mapped.account_name,
84 sid);
87 samr_ChangePasswordUser
89 So old it is just not worth implementing
90 because it does not supply a plaintext and so we can't do password
91 complexity checking and cannot update all the other password hashes.
94 NTSTATUS dcesrv_samr_ChangePasswordUser(struct dcesrv_call_state *dce_call,
95 TALLOC_CTX *mem_ctx,
96 struct samr_ChangePasswordUser *r)
98 return NT_STATUS_NOT_IMPLEMENTED;
102 samr_OemChangePasswordUser2
104 No longer implemented as it requires the LM hash
106 NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call,
107 TALLOC_CTX *mem_ctx,
108 struct samr_OemChangePasswordUser2 *r)
110 return NT_STATUS_NOT_IMPLEMENTED;
114 samr_ChangePasswordUser4
116 NTSTATUS dcesrv_samr_ChangePasswordUser4(struct dcesrv_call_state *dce_call,
117 TALLOC_CTX *mem_ctx,
118 struct samr_ChangePasswordUser4 *r)
120 #ifdef HAVE_GNUTLS_PBKDF2
121 struct ldb_context *sam_ctx = NULL;
122 struct ldb_message **ldb_res = NULL;
123 const char *const attrs[] = {"unicodePwd",
124 "dBCSPwd",
125 "userAccountControl",
126 "msDS-ResultantPSO",
127 "msDS-User-Account-Control-Computed",
128 "badPwdCount",
129 "badPasswordTime",
130 "objectSid",
131 NULL};
132 struct ldb_dn *dn = NULL;
133 const char *samAccountName = NULL;
134 struct dom_sid *objectSid = NULL;
135 struct samr_Password *nt_pwd = NULL;
136 gnutls_datum_t nt_key;
137 gnutls_datum_t salt = {
138 .data = r->in.password->salt,
139 .size = sizeof(r->in.password->salt),
141 uint8_t cdk_data[16] = {0};
142 DATA_BLOB cdk = {
143 .data = cdk_data,
144 .length = sizeof(cdk_data),
146 NTSTATUS status = NT_STATUS_WRONG_PASSWORD;
147 int rc;
149 r->out.result = NT_STATUS_WRONG_PASSWORD;
151 if (r->in.password == NULL) {
152 return NT_STATUS_INVALID_PARAMETER;
155 if (r->in.password->PBKDF2Iterations < 5000 ||
156 r->in.password->PBKDF2Iterations > 1000000) {
157 return NT_STATUS_INVALID_PARAMETER;
160 * Connect to a SAMDB with system privileges for fetching the old
161 * password hashes.
163 sam_ctx = samdb_connect(mem_ctx,
164 dce_call->event_ctx,
165 dce_call->conn->dce_ctx->lp_ctx,
166 system_session(dce_call->conn->dce_ctx->lp_ctx),
167 dce_call->conn->remote_address,
169 if (sam_ctx == NULL) {
170 return NT_STATUS_INVALID_SYSTEM_SERVICE;
173 rc = ldb_transaction_start(sam_ctx);
174 if (rc != LDB_SUCCESS) {
175 DBG_WARNING("Failed to start transaction: %s\n",
176 ldb_errstring(sam_ctx));
177 return NT_STATUS_TRANSACTION_ABORTED;
181 * We need the users dn and the domain dn (derived from the user SID).
182 * We also need the current lm and nt password hashes in order to
183 * decrypt the incoming passwords.
185 rc = gendb_search(
186 sam_ctx,
187 mem_ctx,
188 NULL,
189 &ldb_res,
190 attrs,
191 "(&(sAMAccountName=%s)(objectclass=user))",
192 ldb_binary_encode_string(mem_ctx, r->in.account->string));
193 if (rc != 1) {
194 /* Will be converted to WRONG_PASSWORD below */
195 ldb_transaction_cancel(sam_ctx);
196 DBG_WARNING("Unable to find account: %s",
197 r->in.account->string);
198 status = NT_STATUS_NO_SUCH_USER;
199 goto done;
202 dn = ldb_res[0]->dn;
203 samAccountName =
204 ldb_msg_find_attr_as_string(ldb_res[0], "samAccountName", NULL);
205 objectSid = samdb_result_dom_sid(ldb_res, ldb_res[0], "objectSid");
207 status = samdb_result_passwords(mem_ctx,
208 dce_call->conn->dce_ctx->lp_ctx,
209 ldb_res[0],
210 &nt_pwd);
211 if (!NT_STATUS_IS_OK(status)) {
212 ldb_transaction_cancel(sam_ctx);
213 goto done;
216 if (nt_pwd == NULL) {
217 ldb_transaction_cancel(sam_ctx);
218 status = NT_STATUS_WRONG_PASSWORD;
219 goto done;
222 nt_key = (gnutls_datum_t){
223 .data = nt_pwd->hash,
224 .size = sizeof(nt_pwd->hash),
227 rc = gnutls_pbkdf2(GNUTLS_MAC_SHA512,
228 &nt_key,
229 &salt,
230 r->in.password->PBKDF2Iterations,
231 cdk.data,
232 cdk.length);
233 if (rc < 0) {
234 ldb_transaction_cancel(sam_ctx);
235 status = NT_STATUS_WRONG_PASSWORD;
236 goto done;
239 status = samr_set_password_aes(dce_call,
240 mem_ctx,
241 &cdk,
242 sam_ctx,
244 NULL,
245 r->in.password);
246 BURN_DATA(cdk_data);
247 if (!NT_STATUS_IS_OK(status)) {
248 ldb_transaction_cancel(sam_ctx);
249 status = NT_STATUS_WRONG_PASSWORD;
250 goto done;
253 /* And this confirms it in a transaction commit */
254 rc = ldb_transaction_commit(sam_ctx);
255 if (rc != LDB_SUCCESS) {
256 DBG_WARNING("Failed to commit transaction to change password "
257 "on %s: %s\n",
258 ldb_dn_get_linearized(dn),
259 ldb_errstring(sam_ctx));
260 status = NT_STATUS_TRANSACTION_ABORTED;
261 goto done;
264 status = NT_STATUS_OK;
265 done:
267 struct imessaging_context *imsg_ctx =
268 dcesrv_imessaging_context(dce_call->conn);
270 log_password_change_event(imsg_ctx,
271 dce_call->conn->dce_ctx->lp_ctx,
272 dce_call->conn->remote_address,
273 dce_call->conn->local_address,
274 "samr_ChangePasswordUser4",
275 "AES using NTLM-hash",
276 r->in.account->string,
277 samAccountName,
278 status,
279 objectSid);
282 /* Only update the badPwdCount if we found the user */
283 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
284 authsam_update_bad_pwd_count(sam_ctx,
285 ldb_res[0],
286 ldb_get_default_basedn(sam_ctx));
287 } else if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
289 * Don't give the game away: (don't allow anonymous users to
290 * prove the existence of usernames)
292 status = NT_STATUS_WRONG_PASSWORD;
295 return status;
296 #else /* HAVE_GNUTLS_PBKDF2 */
297 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
298 #endif /* HAVE_GNUTLS_PBKDF2 */
302 samr_ChangePasswordUser3
304 NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
305 TALLOC_CTX *mem_ctx,
306 struct samr_ChangePasswordUser3 *r)
308 struct imessaging_context *imsg_ctx =
309 dcesrv_imessaging_context(dce_call->conn);
310 NTSTATUS status = NT_STATUS_WRONG_PASSWORD;
311 DATA_BLOB new_password;
312 struct ldb_context *sam_ctx = NULL;
313 struct ldb_dn *user_dn = NULL;
314 int ret;
315 struct ldb_message *msg = NULL;
316 struct samr_Password *nt_pwd;
317 struct samr_DomInfo1 *dominfo = NULL;
318 struct userPwdChangeFailureInformation *reject = NULL;
319 enum samPwdChangeReason reason = SAM_PWD_CHANGE_NO_ERROR;
320 uint8_t new_nt_hash[16];
321 struct samr_Password nt_verifier;
322 const char *user_samAccountName = NULL;
323 struct dom_sid *user_objectSid = NULL;
324 struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
325 enum ntlm_auth_level ntlm_auth_level
326 = lpcfg_ntlm_auth(lp_ctx);
327 gnutls_cipher_hd_t cipher_hnd = NULL;
328 gnutls_datum_t nt_session_key;
329 int rc;
331 *r->out.dominfo = NULL;
332 *r->out.reject = NULL;
334 /* this call should be disabled without NTLM auth */
335 if (ntlm_auth_level == NTLM_AUTH_DISABLED) {
336 DBG_WARNING("NTLM password changes not"
337 "permitted by configuration.\n");
338 return NT_STATUS_NTLM_BLOCKED;
341 if (r->in.nt_password == NULL ||
342 r->in.nt_verifier == NULL) {
343 return NT_STATUS_INVALID_PARAMETER;
346 /* Connect to a SAMDB with system privileges for fetching the old pw
347 * hashes. */
348 sam_ctx = dcesrv_samdb_connect_as_system(mem_ctx, dce_call);
349 if (sam_ctx == NULL) {
350 return NT_STATUS_INVALID_SYSTEM_SERVICE;
354 * We use authsam_search_account() to be consistent with the
355 * other callers in the bad password and audit log handling
356 * systems. It ensures we get DSDB_SEARCH_SHOW_EXTENDED_DN.
358 status = authsam_search_account(mem_ctx,
359 sam_ctx,
360 r->in.account->string,
361 ldb_get_default_basedn(sam_ctx),
362 &msg);
363 if (!NT_STATUS_IS_OK(status)) {
364 goto failed;
367 user_dn = msg->dn;
368 user_samAccountName = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL);
369 user_objectSid = samdb_result_dom_sid(mem_ctx, msg, "objectSid");
371 status = samdb_result_passwords(mem_ctx, lp_ctx,
372 msg, &nt_pwd);
373 if (!NT_STATUS_IS_OK(status) ) {
374 goto failed;
377 if (!nt_pwd) {
378 status = NT_STATUS_WRONG_PASSWORD;
379 goto failed;
382 /* decrypt the password we have been given */
383 nt_session_key = (gnutls_datum_t) {
384 .data = nt_pwd->hash,
385 .size = sizeof(nt_pwd->hash),
388 rc = gnutls_cipher_init(&cipher_hnd,
389 GNUTLS_CIPHER_ARCFOUR_128,
390 &nt_session_key,
391 NULL);
392 if (rc < 0) {
393 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
394 goto failed;
397 rc = gnutls_cipher_decrypt(cipher_hnd,
398 r->in.nt_password->data,
399 516);
400 gnutls_cipher_deinit(cipher_hnd);
401 if (rc < 0) {
402 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
403 goto failed;
406 if (!extract_pw_from_buffer(mem_ctx, r->in.nt_password->data, &new_password)) {
407 DEBUG(3,("samr: failed to decode password buffer\n"));
408 status = NT_STATUS_WRONG_PASSWORD;
409 goto failed;
412 if (r->in.nt_verifier == NULL) {
413 status = NT_STATUS_WRONG_PASSWORD;
414 goto failed;
417 /* check NT verifier */
418 mdfour(new_nt_hash, new_password.data, new_password.length);
420 rc = E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash);
421 if (rc != 0) {
422 status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
423 goto failed;
425 if (!mem_equal_const_time(nt_verifier.hash, r->in.nt_verifier->hash, 16)) {
426 status = NT_STATUS_WRONG_PASSWORD;
427 goto failed;
430 /* Connect to a SAMDB with user privileges for the password change */
431 sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call);
432 if (sam_ctx == NULL) {
433 return NT_STATUS_INVALID_SYSTEM_SERVICE;
436 ret = ldb_transaction_start(sam_ctx);
437 if (ret != LDB_SUCCESS) {
438 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
439 return NT_STATUS_TRANSACTION_ABORTED;
442 /* Performs the password modification. We pass the old hashes read out
443 * from the database since they were already checked against the user-
444 * provided ones. */
445 status = samdb_set_password(sam_ctx, mem_ctx,
446 user_dn, NULL,
447 &new_password,
448 NULL,
449 DSDB_PASSWORD_CHECKED_AND_CORRECT,
450 &reason,
451 &dominfo);
453 if (!NT_STATUS_IS_OK(status)) {
454 ldb_transaction_cancel(sam_ctx);
455 goto failed;
458 /* And this confirms it in a transaction commit */
459 ret = ldb_transaction_commit(sam_ctx);
460 if (ret != LDB_SUCCESS) {
461 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
462 ldb_dn_get_linearized(user_dn),
463 ldb_errstring(sam_ctx)));
464 status = NT_STATUS_TRANSACTION_ABORTED;
465 goto failed;
468 status = NT_STATUS_OK;
470 failed:
472 log_password_change_event(imsg_ctx,
473 lp_ctx,
474 dce_call->conn->remote_address,
475 dce_call->conn->local_address,
476 "samr_ChangePasswordUser3",
477 "RC4/DES using NTLM-hash",
478 r->in.account->string,
479 user_samAccountName,
480 status,
481 user_objectSid);
482 if (NT_STATUS_IS_OK(status)) {
483 return NT_STATUS_OK;
486 /* Only update the badPwdCount if we found the user */
487 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
488 NTSTATUS bad_pwd_status = authsam_update_bad_pwd_count(
489 sam_ctx, msg, ldb_get_default_basedn(sam_ctx));
490 if (NT_STATUS_EQUAL(bad_pwd_status, NT_STATUS_ACCOUNT_LOCKED_OUT)) {
491 status = bad_pwd_status;
493 } else if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
494 /* Don't give the game away: (don't allow anonymous users to prove the existence of usernames) */
495 status = NT_STATUS_WRONG_PASSWORD;
498 reject = talloc_zero(mem_ctx, struct userPwdChangeFailureInformation);
499 if (reject != NULL) {
500 reject->extendedFailureReason = reason;
502 *r->out.reject = reject;
505 *r->out.dominfo = dominfo;
507 return status;
511 samr_ChangePasswordUser2
513 easy - just a subset of samr_ChangePasswordUser3
515 NTSTATUS dcesrv_samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call,
516 TALLOC_CTX *mem_ctx,
517 struct samr_ChangePasswordUser2 *r)
519 struct samr_ChangePasswordUser3 r2;
520 struct samr_DomInfo1 *dominfo = NULL;
521 struct userPwdChangeFailureInformation *reject = NULL;
523 r2.in.server = r->in.server;
524 r2.in.account = r->in.account;
525 r2.in.nt_password = r->in.nt_password;
526 r2.in.nt_verifier = r->in.nt_verifier;
527 r2.in.lm_change = r->in.lm_change;
528 r2.in.lm_password = r->in.lm_password;
529 r2.in.lm_verifier = r->in.lm_verifier;
530 r2.in.password3 = NULL;
531 r2.out.dominfo = &dominfo;
532 r2.out.reject = &reject;
534 return dcesrv_samr_ChangePasswordUser3(dce_call, mem_ctx, &r2);
539 set password via a samr_CryptPassword buffer
541 NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
542 struct ldb_context *sam_ctx,
543 struct ldb_dn *account_dn, struct ldb_dn *domain_dn,
544 TALLOC_CTX *mem_ctx,
545 struct samr_CryptPassword *pwbuf)
547 NTSTATUS nt_status;
548 DATA_BLOB new_password;
549 DATA_BLOB session_key = data_blob(NULL, 0);
550 gnutls_cipher_hd_t cipher_hnd = NULL;
551 gnutls_datum_t _session_key;
552 struct auth_session_info *session_info =
553 dcesrv_call_session_info(dce_call);
554 struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
555 int rc;
556 bool encrypted;
558 encrypted = dcerpc_is_transport_encrypted(session_info);
559 if (lpcfg_weak_crypto(lp_ctx) == SAMBA_WEAK_CRYPTO_DISALLOWED &&
560 !encrypted) {
561 return NT_STATUS_ACCESS_DENIED;
564 nt_status = dcesrv_transport_session_key(dce_call, &session_key);
565 if (!NT_STATUS_IS_OK(nt_status)) {
566 DBG_NOTICE("samr: failed to get session key: %s\n",
567 nt_errstr(nt_status));
568 return nt_status;
571 _session_key = (gnutls_datum_t) {
572 .data = session_key.data,
573 .size = session_key.length,
577 * This is safe to support as we only have a session key
578 * over a SMB connection which we force to be encrypted.
580 GNUTLS_FIPS140_SET_LAX_MODE();
581 rc = gnutls_cipher_init(&cipher_hnd,
582 GNUTLS_CIPHER_ARCFOUR_128,
583 &_session_key,
584 NULL);
585 if (rc < 0) {
586 GNUTLS_FIPS140_SET_STRICT_MODE();
587 nt_status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
588 goto out;
591 rc = gnutls_cipher_decrypt(cipher_hnd,
592 pwbuf->data,
593 516);
594 gnutls_cipher_deinit(cipher_hnd);
595 GNUTLS_FIPS140_SET_STRICT_MODE();
596 if (rc < 0) {
597 nt_status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
598 goto out;
601 if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
602 DEBUG(3,("samr: failed to decode password buffer\n"));
603 return NT_STATUS_WRONG_PASSWORD;
606 /* set the password - samdb needs to know both the domain and user DNs,
607 so the domain password policy can be used */
608 nt_status = samdb_set_password(sam_ctx,
609 mem_ctx,
610 account_dn,
611 domain_dn,
612 &new_password,
613 NULL,
614 DSDB_PASSWORD_RESET,
615 NULL,
616 NULL);
617 out:
618 return nt_status;
623 set password via a samr_CryptPasswordEx buffer
625 NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call,
626 struct ldb_context *sam_ctx,
627 struct ldb_dn *account_dn,
628 struct ldb_dn *domain_dn,
629 TALLOC_CTX *mem_ctx,
630 struct samr_CryptPasswordEx *pwbuf)
632 struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
633 struct auth_session_info *session_info =
634 dcesrv_call_session_info(dce_call);
635 NTSTATUS nt_status;
636 DATA_BLOB new_password;
638 /* The confounder is in the last 16 bytes of the buffer */
639 DATA_BLOB confounder = data_blob_const(&pwbuf->data[516], 16);
640 DATA_BLOB pw_data = data_blob_const(pwbuf->data, 516);
641 DATA_BLOB session_key = data_blob(NULL, 0);
642 int rc;
643 bool encrypted;
645 nt_status = dcesrv_transport_session_key(dce_call, &session_key);
646 if (!NT_STATUS_IS_OK(nt_status)) {
647 DEBUG(3,("samr: failed to get session key: %s "
648 "=> NT_STATUS_WRONG_PASSWORD\n",
649 nt_errstr(nt_status)));
650 return NT_STATUS_WRONG_PASSWORD;
653 encrypted = dcerpc_is_transport_encrypted(session_info);
654 if (lpcfg_weak_crypto(lp_ctx) == SAMBA_WEAK_CRYPTO_DISALLOWED &&
655 !encrypted) {
656 return NT_STATUS_ACCESS_DENIED;
659 GNUTLS_FIPS140_SET_LAX_MODE();
660 rc = samba_gnutls_arcfour_confounded_md5(&confounder,
661 &session_key,
662 &pw_data,
663 SAMBA_GNUTLS_DECRYPT);
664 GNUTLS_FIPS140_SET_STRICT_MODE();
665 if (rc < 0) {
666 nt_status = gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
667 goto out;
670 if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
671 DEBUG(3,("samr: failed to decode password buffer\n"));
672 nt_status = NT_STATUS_WRONG_PASSWORD;
673 goto out;
676 /* set the password - samdb needs to know both the domain and user DNs,
677 so the domain password policy can be used */
678 nt_status = samdb_set_password(sam_ctx,
679 mem_ctx,
680 account_dn,
681 domain_dn,
682 &new_password,
683 NULL,
684 DSDB_PASSWORD_RESET,
685 NULL,
686 NULL);
687 ZERO_ARRAY_LEN(new_password.data,
688 new_password.length);
690 out:
691 return nt_status;
695 set password via encrypted NT and LM hash buffers
697 NTSTATUS samr_set_password_buffers(struct dcesrv_call_state *dce_call,
698 struct ldb_context *sam_ctx,
699 struct ldb_dn *account_dn,
700 struct ldb_dn *domain_dn,
701 TALLOC_CTX *mem_ctx,
702 const uint8_t *lm_pwd_hash,
703 const uint8_t *nt_pwd_hash)
705 struct samr_Password *d_lm_pwd_hash = NULL, *d_nt_pwd_hash = NULL;
706 uint8_t random_session_key[16] = { 0, };
707 DATA_BLOB session_key = data_blob(NULL, 0);
708 DATA_BLOB in, out;
709 NTSTATUS nt_status = NT_STATUS_OK;
710 int rc;
712 nt_status = dcesrv_transport_session_key(dce_call, &session_key);
713 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_USER_SESSION_KEY)) {
714 DEBUG(3,("samr: failed to get session key: %s "
715 "=> use a random session key\n",
716 nt_errstr(nt_status)));
719 * Windows just uses a random key
721 generate_random_buffer(random_session_key,
722 sizeof(random_session_key));
723 session_key = data_blob_const(random_session_key,
724 sizeof(random_session_key));
725 nt_status = NT_STATUS_OK;
727 if (!NT_STATUS_IS_OK(nt_status)) {
728 return nt_status;
731 if (nt_pwd_hash != NULL) {
732 in = data_blob_const(nt_pwd_hash, 16);
733 out = data_blob_talloc_zero(mem_ctx, 16);
735 rc = sess_crypt_blob(&out, &in, &session_key, SAMBA_GNUTLS_DECRYPT);
736 if (rc != 0) {
737 return gnutls_error_to_ntstatus(rc,
738 NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
741 d_nt_pwd_hash = (struct samr_Password *) out.data;
744 if ((d_lm_pwd_hash != NULL) || (d_nt_pwd_hash != NULL)) {
745 nt_status = samdb_set_password(sam_ctx, mem_ctx, account_dn,
746 domain_dn, NULL,
747 d_nt_pwd_hash,
748 DSDB_PASSWORD_RESET,
749 NULL, NULL);
752 return nt_status;
755 NTSTATUS samr_set_password_aes(struct dcesrv_call_state *dce_call,
756 TALLOC_CTX *mem_ctx,
757 const DATA_BLOB *cdk,
758 struct ldb_context *sam_ctx,
759 struct ldb_dn *account_dn,
760 struct ldb_dn *domain_dn,
761 struct samr_EncryptedPasswordAES *pwbuf)
763 DATA_BLOB pw_data = data_blob_null;
764 DATA_BLOB new_password = data_blob_null;
765 const DATA_BLOB ciphertext =
766 data_blob_const(pwbuf->cipher, pwbuf->cipher_len);
767 DATA_BLOB iv = data_blob_const(pwbuf->salt, sizeof(pwbuf->salt));
768 NTSTATUS nt_status = NT_STATUS_OK;
769 bool ok;
771 nt_status = samba_gnutls_aead_aes_256_cbc_hmac_sha512_decrypt(
772 mem_ctx,
773 &ciphertext,
774 cdk,
775 &samr_aes256_enc_key_salt,
776 &samr_aes256_mac_key_salt,
777 &iv,
778 pwbuf->auth_data,
779 &pw_data);
780 if (!NT_STATUS_IS_OK(nt_status)) {
781 return NT_STATUS_WRONG_PASSWORD;
784 ok = extract_pwd_blob_from_buffer514(mem_ctx,
785 pw_data.data,
786 &new_password);
787 TALLOC_FREE(pw_data.data);
788 if (!ok) {
789 DBG_NOTICE("samr: failed to decode password buffer\n");
790 return NT_STATUS_WRONG_PASSWORD;
793 nt_status = samdb_set_password(sam_ctx,
794 mem_ctx,
795 account_dn,
796 domain_dn,
797 &new_password,
798 NULL,
799 DSDB_PASSWORD_RESET,
800 NULL,
801 NULL);
802 TALLOC_FREE(new_password.data);
804 return nt_status;