libcli: Speed up sddl_decode_ace()
[samba4-gss.git] / source4 / rpc_server / samr / samr_password.c
blob8af79182e4b8c84798cbeb746a5f72673de44fd6
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,
85 NULL /* client_audit_info */,
86 NULL /* server_audit_info */);
89 samr_ChangePasswordUser
91 So old it is just not worth implementing
92 because it does not supply a plaintext and so we can't do password
93 complexity checking and cannot update all the other password hashes.
96 NTSTATUS dcesrv_samr_ChangePasswordUser(struct dcesrv_call_state *dce_call,
97 TALLOC_CTX *mem_ctx,
98 struct samr_ChangePasswordUser *r)
100 return NT_STATUS_NOT_IMPLEMENTED;
104 samr_OemChangePasswordUser2
106 No longer implemented as it requires the LM hash
108 NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call,
109 TALLOC_CTX *mem_ctx,
110 struct samr_OemChangePasswordUser2 *r)
112 return NT_STATUS_NOT_IMPLEMENTED;
116 samr_ChangePasswordUser4
118 NTSTATUS dcesrv_samr_ChangePasswordUser4(struct dcesrv_call_state *dce_call,
119 TALLOC_CTX *mem_ctx,
120 struct samr_ChangePasswordUser4 *r)
122 struct ldb_context *sam_ctx = NULL;
123 struct ldb_message *msg = NULL;
124 struct ldb_dn *dn = NULL;
125 const char *samAccountName = NULL;
126 struct dom_sid *objectSid = NULL;
127 struct samr_Password *nt_pwd = NULL;
128 gnutls_datum_t nt_key;
129 gnutls_datum_t salt = {
130 .data = r->in.password->salt,
131 .size = sizeof(r->in.password->salt),
133 uint8_t cdk_data[16] = {0};
134 DATA_BLOB cdk = {
135 .data = cdk_data,
136 .length = sizeof(cdk_data),
138 struct auth_session_info *call_session_info = NULL;
139 struct auth_session_info *old_session_info = NULL;
140 NTSTATUS status = NT_STATUS_WRONG_PASSWORD;
141 int rc;
143 r->out.result = NT_STATUS_WRONG_PASSWORD;
145 if (r->in.password == NULL) {
146 return NT_STATUS_INVALID_PARAMETER;
149 if (r->in.password->PBKDF2Iterations < 5000 ||
150 r->in.password->PBKDF2Iterations > 1000000) {
151 return NT_STATUS_INVALID_PARAMETER;
154 * Connect to a SAMDB with system privileges for fetching the old
155 * password hashes.
157 sam_ctx = samdb_connect(mem_ctx,
158 dce_call->event_ctx,
159 dce_call->conn->dce_ctx->lp_ctx,
160 system_session(dce_call->conn->dce_ctx->lp_ctx),
161 dce_call->conn->remote_address,
163 if (sam_ctx == NULL) {
164 return NT_STATUS_INVALID_SYSTEM_SERVICE;
167 rc = ldb_transaction_start(sam_ctx);
168 if (rc != LDB_SUCCESS) {
169 DBG_WARNING("Failed to start transaction: %s\n",
170 ldb_errstring(sam_ctx));
171 return NT_STATUS_TRANSACTION_ABORTED;
175 * We use authsam_search_account() to be consistent with the
176 * other callers in the bad password and audit log handling
177 * systems. It ensures we get DSDB_SEARCH_SHOW_EXTENDED_DN.
179 status = authsam_search_account(mem_ctx,
180 sam_ctx,
181 r->in.account->string,
182 ldb_get_default_basedn(sam_ctx),
183 &msg);
184 if (!NT_STATUS_IS_OK(status)) {
185 ldb_transaction_cancel(sam_ctx);
186 goto done;
189 dn = msg->dn;
190 samAccountName = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL);
191 objectSid = samdb_result_dom_sid(msg, msg, "objectSid");
193 status = samdb_result_passwords(mem_ctx,
194 dce_call->conn->dce_ctx->lp_ctx,
195 msg,
196 &nt_pwd);
197 if (!NT_STATUS_IS_OK(status)) {
198 ldb_transaction_cancel(sam_ctx);
199 goto done;
202 if (nt_pwd == NULL) {
203 ldb_transaction_cancel(sam_ctx);
204 status = NT_STATUS_WRONG_PASSWORD;
205 goto done;
208 nt_key = (gnutls_datum_t){
209 .data = nt_pwd->hash,
210 .size = sizeof(nt_pwd->hash),
213 rc = gnutls_pbkdf2(GNUTLS_MAC_SHA512,
214 &nt_key,
215 &salt,
216 r->in.password->PBKDF2Iterations,
217 cdk.data,
218 cdk.length);
219 if (rc < 0) {
220 ldb_transaction_cancel(sam_ctx);
221 status = NT_STATUS_WRONG_PASSWORD;
222 goto done;
225 /* Drop to user privileges for the password change */
227 old_session_info = ldb_get_opaque(sam_ctx, DSDB_SESSION_INFO);
228 call_session_info = dcesrv_call_session_info(dce_call);
230 rc = ldb_set_opaque(sam_ctx, DSDB_SESSION_INFO, call_session_info);
231 if (rc != LDB_SUCCESS) {
232 ldb_transaction_cancel(sam_ctx);
233 status = NT_STATUS_INVALID_SYSTEM_SERVICE;
234 goto done;
237 status = samr_set_password_aes(dce_call,
238 mem_ctx,
239 &cdk,
240 sam_ctx,
242 r->in.password,
243 DSDB_PASSWORD_CHECKED_AND_CORRECT);
244 BURN_DATA(cdk_data);
246 /* Restore our privileges to system level */
247 if (old_session_info != NULL) {
248 ldb_set_opaque(sam_ctx, DSDB_SESSION_INFO, old_session_info);
251 if (!NT_STATUS_IS_OK(status)) {
252 ldb_transaction_cancel(sam_ctx);
253 goto done;
256 /* And this confirms it in a transaction commit */
257 rc = ldb_transaction_commit(sam_ctx);
258 if (rc != LDB_SUCCESS) {
259 DBG_WARNING("Failed to commit transaction to change password "
260 "on %s: %s\n",
261 ldb_dn_get_linearized(dn),
262 ldb_errstring(sam_ctx));
263 status = NT_STATUS_TRANSACTION_ABORTED;
264 goto done;
267 status = NT_STATUS_OK;
268 done:
270 struct imessaging_context *imsg_ctx =
271 dcesrv_imessaging_context(dce_call->conn);
273 log_password_change_event(imsg_ctx,
274 dce_call->conn->dce_ctx->lp_ctx,
275 dce_call->conn->remote_address,
276 dce_call->conn->local_address,
277 "samr_ChangePasswordUser4",
278 "AES using NTLM-hash",
279 r->in.account->string,
280 samAccountName,
281 status,
282 objectSid);
285 /* Only update the badPwdCount if we found the user */
286 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
287 authsam_update_bad_pwd_count(sam_ctx,
288 msg,
289 ldb_get_default_basedn(sam_ctx));
290 } else if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
292 * Don't give the game away: (don't allow anonymous users to
293 * prove the existence of usernames)
295 status = NT_STATUS_WRONG_PASSWORD;
298 return status;
301 static NTSTATUS dcesrv_samr_ChangePasswordUser_impl(struct dcesrv_call_state *dce_call,
302 TALLOC_CTX *mem_ctx,
303 struct samr_ChangePasswordUser3 *r,
304 const char *function_name)
306 struct imessaging_context *imsg_ctx =
307 dcesrv_imessaging_context(dce_call->conn);
308 NTSTATUS status = NT_STATUS_WRONG_PASSWORD;
309 DATA_BLOB new_password;
310 struct ldb_context *sam_ctx = NULL;
311 struct ldb_dn *user_dn = NULL;
312 int ret;
313 struct ldb_message *msg = NULL;
314 struct samr_Password *nt_pwd;
315 struct samr_DomInfo1 *dominfo = NULL;
316 struct userPwdChangeFailureInformation *reject = NULL;
317 enum samPwdChangeReason reason = SAM_PWD_CHANGE_NO_ERROR;
318 uint8_t new_nt_hash[16];
319 struct samr_Password nt_verifier;
320 const char *user_samAccountName = NULL;
321 struct dom_sid *user_objectSid = NULL;
322 struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
323 enum ntlm_auth_level ntlm_auth_level
324 = lpcfg_ntlm_auth(lp_ctx);
325 gnutls_cipher_hd_t cipher_hnd = NULL;
326 gnutls_datum_t nt_session_key;
327 struct auth_session_info *call_session_info = NULL;
328 struct auth_session_info *old_session_info = NULL;
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;
353 ret = ldb_transaction_start(sam_ctx);
354 if (ret != LDB_SUCCESS) {
355 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
356 return NT_STATUS_TRANSACTION_ABORTED;
360 * We use authsam_search_account() to be consistent with the
361 * other callers in the bad password and audit log handling
362 * systems. It ensures we get DSDB_SEARCH_SHOW_EXTENDED_DN.
364 status = authsam_search_account(mem_ctx,
365 sam_ctx,
366 r->in.account->string,
367 ldb_get_default_basedn(sam_ctx),
368 &msg);
369 if (!NT_STATUS_IS_OK(status)) {
370 ldb_transaction_cancel(sam_ctx);
371 goto failed;
374 user_dn = msg->dn;
375 user_samAccountName = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL);
376 user_objectSid = samdb_result_dom_sid(mem_ctx, msg, "objectSid");
378 status = samdb_result_passwords(mem_ctx, lp_ctx,
379 msg, &nt_pwd);
380 if (!NT_STATUS_IS_OK(status) ) {
381 ldb_transaction_cancel(sam_ctx);
382 goto failed;
385 if (!nt_pwd) {
386 status = NT_STATUS_WRONG_PASSWORD;
387 ldb_transaction_cancel(sam_ctx);
388 goto failed;
391 /* decrypt the password we have been given */
392 nt_session_key = (gnutls_datum_t) {
393 .data = nt_pwd->hash,
394 .size = sizeof(nt_pwd->hash),
397 rc = gnutls_cipher_init(&cipher_hnd,
398 GNUTLS_CIPHER_ARCFOUR_128,
399 &nt_session_key,
400 NULL);
401 if (rc < 0) {
402 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
403 ldb_transaction_cancel(sam_ctx);
404 goto failed;
407 rc = gnutls_cipher_decrypt(cipher_hnd,
408 r->in.nt_password->data,
409 516);
410 gnutls_cipher_deinit(cipher_hnd);
411 if (rc < 0) {
412 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
413 ldb_transaction_cancel(sam_ctx);
414 goto failed;
417 if (!extract_pw_from_buffer(mem_ctx, r->in.nt_password->data, &new_password)) {
418 DEBUG(3,("samr: failed to decode password buffer\n"));
419 status = NT_STATUS_WRONG_PASSWORD;
420 ldb_transaction_cancel(sam_ctx);
421 goto failed;
424 if (r->in.nt_verifier == NULL) {
425 status = NT_STATUS_WRONG_PASSWORD;
426 ldb_transaction_cancel(sam_ctx);
427 goto failed;
430 /* check NT verifier */
431 mdfour(new_nt_hash, new_password.data, new_password.length);
433 rc = E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash);
434 if (rc != 0) {
435 status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
436 ldb_transaction_cancel(sam_ctx);
437 goto failed;
439 if (!mem_equal_const_time(nt_verifier.hash, r->in.nt_verifier->hash, 16)) {
440 status = NT_STATUS_WRONG_PASSWORD;
441 ldb_transaction_cancel(sam_ctx);
442 goto failed;
445 /* Drop to user privileges for the password change */
447 old_session_info = ldb_get_opaque(sam_ctx, DSDB_SESSION_INFO);
448 call_session_info = dcesrv_call_session_info(dce_call);
450 ret = ldb_set_opaque(sam_ctx, DSDB_SESSION_INFO, call_session_info);
451 if (ret != LDB_SUCCESS) {
452 status = NT_STATUS_INVALID_SYSTEM_SERVICE;
453 ldb_transaction_cancel(sam_ctx);
454 goto failed;
457 /* Performs the password modification. We pass the old hashes read out
458 * from the database since they were already checked against the user-
459 * provided ones. */
460 status = samdb_set_password(sam_ctx, mem_ctx,
461 user_dn,
462 &new_password,
463 NULL,
464 DSDB_PASSWORD_CHECKED_AND_CORRECT,
465 &reason,
466 &dominfo);
468 /* Restore our privileges to system level */
469 if (old_session_info != NULL) {
470 ldb_set_opaque(sam_ctx, DSDB_SESSION_INFO, old_session_info);
473 if (!NT_STATUS_IS_OK(status)) {
474 ldb_transaction_cancel(sam_ctx);
475 goto failed;
478 /* And this confirms it in a transaction commit */
479 ret = ldb_transaction_commit(sam_ctx);
480 if (ret != LDB_SUCCESS) {
481 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
482 ldb_dn_get_linearized(user_dn),
483 ldb_errstring(sam_ctx)));
484 status = NT_STATUS_TRANSACTION_ABORTED;
485 goto failed;
488 status = NT_STATUS_OK;
490 failed:
492 log_password_change_event(imsg_ctx,
493 lp_ctx,
494 dce_call->conn->remote_address,
495 dce_call->conn->local_address,
496 function_name,
497 "RC4/DES using NTLM-hash",
498 r->in.account->string,
499 user_samAccountName,
500 status,
501 user_objectSid);
502 if (NT_STATUS_IS_OK(status)) {
503 return NT_STATUS_OK;
506 /* Only update the badPwdCount if we found the user */
507 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
508 NTSTATUS bad_pwd_status;
510 bad_pwd_status = authsam_update_bad_pwd_count(
511 sam_ctx, msg, ldb_get_default_basedn(sam_ctx));
512 if (NT_STATUS_EQUAL(bad_pwd_status, NT_STATUS_ACCOUNT_LOCKED_OUT)) {
513 status = bad_pwd_status;
515 } else if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
516 /* Don't give the game away: (don't allow anonymous users to prove the existence of usernames) */
517 status = NT_STATUS_WRONG_PASSWORD;
520 reject = talloc_zero(mem_ctx, struct userPwdChangeFailureInformation);
521 if (reject != NULL) {
522 reject->extendedFailureReason = reason;
524 *r->out.reject = reject;
527 *r->out.dominfo = dominfo;
529 return status;
533 samr_ChangePasswordUser3
535 NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
536 TALLOC_CTX *mem_ctx,
537 struct samr_ChangePasswordUser3 *r)
539 return dcesrv_samr_ChangePasswordUser_impl(dce_call, mem_ctx, r,
540 "samr_ChangePasswordUser3");
544 samr_ChangePasswordUser2
546 easy - just a subset of samr_ChangePasswordUser3
548 NTSTATUS dcesrv_samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call,
549 TALLOC_CTX *mem_ctx,
550 struct samr_ChangePasswordUser2 *r)
552 struct samr_ChangePasswordUser3 r2;
553 struct samr_DomInfo1 *dominfo = NULL;
554 struct userPwdChangeFailureInformation *reject = NULL;
556 r2.in.server = r->in.server;
557 r2.in.account = r->in.account;
558 r2.in.nt_password = r->in.nt_password;
559 r2.in.nt_verifier = r->in.nt_verifier;
560 r2.in.lm_change = r->in.lm_change;
561 r2.in.lm_password = r->in.lm_password;
562 r2.in.lm_verifier = r->in.lm_verifier;
563 r2.in.password3 = NULL;
564 r2.out.dominfo = &dominfo;
565 r2.out.reject = &reject;
567 return dcesrv_samr_ChangePasswordUser_impl(dce_call, mem_ctx, &r2,
568 "samr_ChangePasswordUser2");
573 set password via a samr_CryptPassword buffer
575 NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
576 struct ldb_context *sam_ctx,
577 struct ldb_dn *account_dn,
578 TALLOC_CTX *mem_ctx,
579 struct samr_CryptPassword *pwbuf)
581 NTSTATUS nt_status;
582 DATA_BLOB new_password;
583 DATA_BLOB session_key = data_blob(NULL, 0);
584 gnutls_cipher_hd_t cipher_hnd = NULL;
585 gnutls_datum_t _session_key;
586 struct auth_session_info *session_info =
587 dcesrv_call_session_info(dce_call);
588 struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
589 int rc;
590 bool encrypted;
592 encrypted = dcerpc_is_transport_encrypted(session_info);
593 if (lpcfg_weak_crypto(lp_ctx) == SAMBA_WEAK_CRYPTO_DISALLOWED &&
594 !encrypted) {
595 return NT_STATUS_ACCESS_DENIED;
598 nt_status = dcesrv_transport_session_key(dce_call, &session_key);
599 if (!NT_STATUS_IS_OK(nt_status)) {
600 DBG_NOTICE("samr: failed to get session key: %s\n",
601 nt_errstr(nt_status));
602 return nt_status;
605 _session_key = (gnutls_datum_t) {
606 .data = session_key.data,
607 .size = session_key.length,
611 * This is safe to support as we only have a session key
612 * over a SMB connection which we force to be encrypted.
614 GNUTLS_FIPS140_SET_LAX_MODE();
615 rc = gnutls_cipher_init(&cipher_hnd,
616 GNUTLS_CIPHER_ARCFOUR_128,
617 &_session_key,
618 NULL);
619 if (rc < 0) {
620 GNUTLS_FIPS140_SET_STRICT_MODE();
621 nt_status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
622 goto out;
625 rc = gnutls_cipher_decrypt(cipher_hnd,
626 pwbuf->data,
627 516);
628 gnutls_cipher_deinit(cipher_hnd);
629 GNUTLS_FIPS140_SET_STRICT_MODE();
630 if (rc < 0) {
631 nt_status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
632 goto out;
635 if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
636 DEBUG(3,("samr: failed to decode password buffer\n"));
637 return NT_STATUS_WRONG_PASSWORD;
640 /* set the password - samdb needs to know both the domain and user DNs,
641 so the domain password policy can be used */
642 nt_status = samdb_set_password(sam_ctx,
643 mem_ctx,
644 account_dn,
645 &new_password,
646 NULL,
647 DSDB_PASSWORD_RESET,
648 NULL,
649 NULL);
650 out:
651 return nt_status;
656 set password via a samr_CryptPasswordEx buffer
658 NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call,
659 struct ldb_context *sam_ctx,
660 struct ldb_dn *account_dn,
661 TALLOC_CTX *mem_ctx,
662 struct samr_CryptPasswordEx *pwbuf)
664 struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
665 struct auth_session_info *session_info =
666 dcesrv_call_session_info(dce_call);
667 NTSTATUS nt_status;
668 DATA_BLOB new_password;
670 /* The confounder is in the last 16 bytes of the buffer */
671 DATA_BLOB confounder = data_blob_const(&pwbuf->data[516], 16);
672 DATA_BLOB pw_data = data_blob_const(pwbuf->data, 516);
673 DATA_BLOB session_key = data_blob(NULL, 0);
674 int rc;
675 bool encrypted;
677 nt_status = dcesrv_transport_session_key(dce_call, &session_key);
678 if (!NT_STATUS_IS_OK(nt_status)) {
679 DEBUG(3,("samr: failed to get session key: %s "
680 "=> NT_STATUS_WRONG_PASSWORD\n",
681 nt_errstr(nt_status)));
682 return NT_STATUS_WRONG_PASSWORD;
685 encrypted = dcerpc_is_transport_encrypted(session_info);
686 if (lpcfg_weak_crypto(lp_ctx) == SAMBA_WEAK_CRYPTO_DISALLOWED &&
687 !encrypted) {
688 return NT_STATUS_ACCESS_DENIED;
691 GNUTLS_FIPS140_SET_LAX_MODE();
692 rc = samba_gnutls_arcfour_confounded_md5(&confounder,
693 &session_key,
694 &pw_data,
695 SAMBA_GNUTLS_DECRYPT);
696 GNUTLS_FIPS140_SET_STRICT_MODE();
697 if (rc < 0) {
698 nt_status = gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
699 goto out;
702 if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
703 DEBUG(3,("samr: failed to decode password buffer\n"));
704 nt_status = NT_STATUS_WRONG_PASSWORD;
705 goto out;
708 /* set the password - samdb needs to know both the domain and user DNs,
709 so the domain password policy can be used */
710 nt_status = samdb_set_password(sam_ctx,
711 mem_ctx,
712 account_dn,
713 &new_password,
714 NULL,
715 DSDB_PASSWORD_RESET,
716 NULL,
717 NULL);
718 ZERO_ARRAY_LEN(new_password.data,
719 new_password.length);
721 out:
722 return nt_status;
726 set password via encrypted NT and LM hash buffers
728 NTSTATUS samr_set_password_buffers(struct dcesrv_call_state *dce_call,
729 struct ldb_context *sam_ctx,
730 struct ldb_dn *account_dn,
731 TALLOC_CTX *mem_ctx,
732 const uint8_t *lm_pwd_hash,
733 const uint8_t *nt_pwd_hash)
735 struct samr_Password *d_lm_pwd_hash = NULL, *d_nt_pwd_hash = NULL;
736 uint8_t random_session_key[16] = { 0, };
737 DATA_BLOB session_key = data_blob(NULL, 0);
738 DATA_BLOB in, out;
739 NTSTATUS nt_status = NT_STATUS_OK;
740 int rc;
742 nt_status = dcesrv_transport_session_key(dce_call, &session_key);
743 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_USER_SESSION_KEY)) {
744 DEBUG(3,("samr: failed to get session key: %s "
745 "=> use a random session key\n",
746 nt_errstr(nt_status)));
749 * Windows just uses a random key
751 generate_random_buffer(random_session_key,
752 sizeof(random_session_key));
753 session_key = data_blob_const(random_session_key,
754 sizeof(random_session_key));
755 nt_status = NT_STATUS_OK;
757 if (!NT_STATUS_IS_OK(nt_status)) {
758 return nt_status;
761 if (nt_pwd_hash != NULL) {
762 in = data_blob_const(nt_pwd_hash, 16);
763 out = data_blob_talloc_zero(mem_ctx, 16);
765 rc = sess_crypt_blob(&out, &in, &session_key, SAMBA_GNUTLS_DECRYPT);
766 if (rc != 0) {
767 return gnutls_error_to_ntstatus(rc,
768 NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
771 d_nt_pwd_hash = (struct samr_Password *) out.data;
774 if ((d_lm_pwd_hash != NULL) || (d_nt_pwd_hash != NULL)) {
775 nt_status = samdb_set_password(sam_ctx, mem_ctx, account_dn,
776 NULL,
777 d_nt_pwd_hash,
778 DSDB_PASSWORD_RESET,
779 NULL, NULL);
782 return nt_status;
785 NTSTATUS samr_set_password_aes(struct dcesrv_call_state *dce_call,
786 TALLOC_CTX *mem_ctx,
787 const DATA_BLOB *cdk,
788 struct ldb_context *sam_ctx,
789 struct ldb_dn *account_dn,
790 struct samr_EncryptedPasswordAES *pwbuf,
791 enum dsdb_password_checked old_password_checked)
793 DATA_BLOB pw_data = data_blob_null;
794 DATA_BLOB new_password = data_blob_null;
795 const DATA_BLOB ciphertext =
796 data_blob_const(pwbuf->cipher, pwbuf->cipher_len);
797 DATA_BLOB iv = data_blob_const(pwbuf->salt, sizeof(pwbuf->salt));
798 NTSTATUS nt_status = NT_STATUS_OK;
799 bool ok;
801 nt_status = samba_gnutls_aead_aes_256_cbc_hmac_sha512_decrypt(
802 mem_ctx,
803 &ciphertext,
804 cdk,
805 &samr_aes256_enc_key_salt,
806 &samr_aes256_mac_key_salt,
807 &iv,
808 pwbuf->auth_data,
809 &pw_data);
810 if (!NT_STATUS_IS_OK(nt_status)) {
811 return NT_STATUS_WRONG_PASSWORD;
814 ok = extract_pwd_blob_from_buffer514(mem_ctx,
815 pw_data.data,
816 &new_password);
817 TALLOC_FREE(pw_data.data);
818 if (!ok) {
819 DBG_NOTICE("samr: failed to decode password buffer\n");
820 return NT_STATUS_WRONG_PASSWORD;
823 nt_status = samdb_set_password(sam_ctx,
824 mem_ctx,
825 account_dn,
826 &new_password,
827 NULL,
828 old_password_checked,
829 NULL,
830 NULL);
831 TALLOC_FREE(new_password.data);
833 return nt_status;