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/>.
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
,
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
= {
63 .account_name
= original_client_name
,
64 .domain_name
= lpcfg_sam_name(lp_ctx
),
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
,
82 ui
.mapped
.domain_name
,
83 ui
.mapped
.account_name
,
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
,
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
,
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
,
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};
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
;
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
157 sam_ctx
= samdb_connect(mem_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
,
181 r
->in
.account
->string
,
182 ldb_get_default_basedn(sam_ctx
),
184 if (!NT_STATUS_IS_OK(status
)) {
185 ldb_transaction_cancel(sam_ctx
);
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
,
197 if (!NT_STATUS_IS_OK(status
)) {
198 ldb_transaction_cancel(sam_ctx
);
202 if (nt_pwd
== NULL
) {
203 ldb_transaction_cancel(sam_ctx
);
204 status
= NT_STATUS_WRONG_PASSWORD
;
208 nt_key
= (gnutls_datum_t
){
209 .data
= nt_pwd
->hash
,
210 .size
= sizeof(nt_pwd
->hash
),
213 rc
= gnutls_pbkdf2(GNUTLS_MAC_SHA512
,
216 r
->in
.password
->PBKDF2Iterations
,
220 ldb_transaction_cancel(sam_ctx
);
221 status
= NT_STATUS_WRONG_PASSWORD
;
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
;
237 status
= samr_set_password_aes(dce_call
,
243 DSDB_PASSWORD_CHECKED_AND_CORRECT
);
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
);
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 "
261 ldb_dn_get_linearized(dn
),
262 ldb_errstring(sam_ctx
));
263 status
= NT_STATUS_TRANSACTION_ABORTED
;
267 status
= NT_STATUS_OK
;
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
,
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
,
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
;
301 static NTSTATUS
dcesrv_samr_ChangePasswordUser_impl(struct dcesrv_call_state
*dce_call
,
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
;
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
;
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
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
,
366 r
->in
.account
->string
,
367 ldb_get_default_basedn(sam_ctx
),
369 if (!NT_STATUS_IS_OK(status
)) {
370 ldb_transaction_cancel(sam_ctx
);
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
,
380 if (!NT_STATUS_IS_OK(status
) ) {
381 ldb_transaction_cancel(sam_ctx
);
386 status
= NT_STATUS_WRONG_PASSWORD
;
387 ldb_transaction_cancel(sam_ctx
);
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
,
402 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_CRYPTO_SYSTEM_INVALID
);
403 ldb_transaction_cancel(sam_ctx
);
407 rc
= gnutls_cipher_decrypt(cipher_hnd
,
408 r
->in
.nt_password
->data
,
410 gnutls_cipher_deinit(cipher_hnd
);
412 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_CRYPTO_SYSTEM_INVALID
);
413 ldb_transaction_cancel(sam_ctx
);
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
);
424 if (r
->in
.nt_verifier
== NULL
) {
425 status
= NT_STATUS_WRONG_PASSWORD
;
426 ldb_transaction_cancel(sam_ctx
);
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
);
435 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
436 ldb_transaction_cancel(sam_ctx
);
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
);
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
);
457 /* Performs the password modification. We pass the old hashes read out
458 * from the database since they were already checked against the user-
460 status
= samdb_set_password(sam_ctx
, mem_ctx
,
464 DSDB_PASSWORD_CHECKED_AND_CORRECT
,
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
);
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
;
488 status
= NT_STATUS_OK
;
492 log_password_change_event(imsg_ctx
,
494 dce_call
->conn
->remote_address
,
495 dce_call
->conn
->local_address
,
497 "RC4/DES using NTLM-hash",
498 r
->in
.account
->string
,
502 if (NT_STATUS_IS_OK(status
)) {
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
;
533 samr_ChangePasswordUser3
535 NTSTATUS
dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state
*dce_call
,
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
,
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
,
579 struct samr_CryptPassword
*pwbuf
)
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
;
592 encrypted
= dcerpc_is_transport_encrypted(session_info
);
593 if (lpcfg_weak_crypto(lp_ctx
) == SAMBA_WEAK_CRYPTO_DISALLOWED
&&
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
));
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
,
620 GNUTLS_FIPS140_SET_STRICT_MODE();
621 nt_status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_CRYPTO_SYSTEM_INVALID
);
625 rc
= gnutls_cipher_decrypt(cipher_hnd
,
628 gnutls_cipher_deinit(cipher_hnd
);
629 GNUTLS_FIPS140_SET_STRICT_MODE();
631 nt_status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_CRYPTO_SYSTEM_INVALID
);
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
,
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
,
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
);
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);
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
&&
688 return NT_STATUS_ACCESS_DENIED
;
691 GNUTLS_FIPS140_SET_LAX_MODE();
692 rc
= samba_gnutls_arcfour_confounded_md5(&confounder
,
695 SAMBA_GNUTLS_DECRYPT
);
696 GNUTLS_FIPS140_SET_STRICT_MODE();
698 nt_status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_HASH_NOT_SUPPORTED
);
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
;
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
,
718 ZERO_ARRAY_LEN(new_password
.data
,
719 new_password
.length
);
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
,
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);
739 NTSTATUS nt_status
= NT_STATUS_OK
;
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
)) {
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
);
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
,
785 NTSTATUS
samr_set_password_aes(struct dcesrv_call_state
*dce_call
,
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
;
801 nt_status
= samba_gnutls_aead_aes_256_cbc_hmac_sha512_decrypt(
805 &samr_aes256_enc_key_salt
,
806 &samr_aes256_mac_key_salt
,
810 if (!NT_STATUS_IS_OK(nt_status
)) {
811 return NT_STATUS_WRONG_PASSWORD
;
814 ok
= extract_pwd_blob_from_buffer514(mem_ctx
,
817 TALLOC_FREE(pw_data
.data
);
819 DBG_NOTICE("samr: failed to decode password buffer\n");
820 return NT_STATUS_WRONG_PASSWORD
;
823 nt_status
= samdb_set_password(sam_ctx
,
828 old_password_checked
,
831 TALLOC_FREE(new_password
.data
);