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/samr/dcesrv_samr.h"
26 #include "system/time.h"
27 #include "lib/crypto/md4.h"
28 #include "dsdb/samdb/samdb.h"
29 #include "auth/auth.h"
30 #include "libcli/auth/libcli_auth.h"
31 #include "../lib/util/util_ldb.h"
32 #include "rpc_server/samr/proto.h"
33 #include "auth/auth_sam.h"
35 #include "lib/crypto/gnutls_helpers.h"
36 #include <gnutls/gnutls.h>
37 #include <gnutls/crypto.h>
39 static void log_password_change_event(struct imessaging_context *msg_ctx,
40 struct loadparm_context *lp_ctx,
41 const struct tsocket_address *remote_client_address,
42 const struct tsocket_address *local_server_address,
43 const char *auth_description,
44 const char *password_type,
45 const char *original_client_name,
46 const char *account_name_from_db,
51 * Forcing this via the NTLM auth structure is not ideal, but
52 * it is the most practical option right now, and ensures the
53 * logs are consistent, even if some elements are always NULL.
55 struct auth_usersupplied_info ui = {
59 .account_name = original_client_name,
60 .domain_name = lpcfg_sam_name(lp_ctx),
63 .account_name = account_name_from_db,
64 .domain_name = lpcfg_sam_name(lp_ctx),
66 .remote_host = remote_client_address,
67 .local_host = local_server_address,
68 .service_description = "SAMR Password Change",
69 .auth_description = auth_description,
70 .password_type = password_type,
73 log_authentication_event(msg_ctx,
78 ui.mapped.domain_name,
79 ui.mapped.account_name,
83 samr_ChangePasswordUser
85 So old it is just not worth implementing
86 because it does not supply a plaintext and so we can't do password
87 complexity checking and cannot update all the other password hashes.
90 NTSTATUS dcesrv_samr_ChangePasswordUser(struct dcesrv_call_state *dce_call,
92 struct samr_ChangePasswordUser *r)
94 return NT_STATUS_NOT_IMPLEMENTED;
98 samr_OemChangePasswordUser2
100 NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call,
102 struct samr_OemChangePasswordUser2 *r)
104 struct auth_session_info *session_info =
105 dcesrv_call_session_info(dce_call);
106 struct imessaging_context *imsg_ctx =
107 dcesrv_imessaging_context(dce_call->conn);
108 NTSTATUS status = NT_STATUS_WRONG_PASSWORD;
109 DATA_BLOB new_password, new_unicode_password;
111 struct samr_CryptPassword *pwbuf = r->in.password;
112 struct ldb_context *sam_ctx;
113 struct ldb_dn *user_dn;
115 struct ldb_message **res;
116 const char * const attrs[] = { "objectSid", "dBCSPwd",
117 "userAccountControl",
119 "msDS-User-Account-Control-Computed",
120 "badPwdCount", "badPasswordTime",
123 struct samr_Password *lm_pwd;
124 uint8_t new_lm_hash[16];
125 struct samr_Password lm_verifier;
126 size_t unicode_pw_len;
127 size_t converted_size = 0;
128 const char *user_samAccountName = NULL;
129 struct dom_sid *user_objectSid = NULL;
130 gnutls_cipher_hd_t cipher_hnd = NULL;
131 gnutls_datum_t lm_session_key;
135 return NT_STATUS_INVALID_PARAMETER;
138 if (r->in.hash == NULL) {
139 return NT_STATUS_INVALID_PARAMETER;
142 /* this call can only work with lanman auth */
143 if (!lpcfg_lanman_auth(dce_call->conn->dce_ctx->lp_ctx)) {
144 return NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER;
147 /* Connect to a SAMDB with system privileges for fetching the old pw
149 sam_ctx = samdb_connect(mem_ctx,
151 dce_call->conn->dce_ctx->lp_ctx,
152 system_session(dce_call->conn->dce_ctx->lp_ctx),
153 dce_call->conn->remote_address,
155 if (sam_ctx == NULL) {
156 return NT_STATUS_INVALID_SYSTEM_SERVICE;
159 /* we need the users dn and the domain dn (derived from the
160 user SID). We also need the current lm password hash in
161 order to decrypt the incoming password */
162 ret = gendb_search(sam_ctx,
163 mem_ctx, NULL, &res, attrs,
164 "(&(sAMAccountName=%s)(objectclass=user))",
165 ldb_binary_encode_string(mem_ctx, r->in.account->string));
167 status = NT_STATUS_NO_SUCH_USER; /* Converted to WRONG_PASSWORD below */
171 user_dn = res[0]->dn;
173 user_samAccountName = ldb_msg_find_attr_as_string(res[0], "samAccountName", NULL);
174 user_objectSid = samdb_result_dom_sid(res, res[0], "objectSid");
176 status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx,
177 res[0], &lm_pwd, NULL);
178 if (!NT_STATUS_IS_OK(status)) {
180 } else if (!lm_pwd) {
181 status = NT_STATUS_WRONG_PASSWORD;
185 /* decrypt the password we have been given */
186 lm_session_key = (gnutls_datum_t) {
187 .data = lm_pwd->hash,
188 .size = sizeof(lm_pwd->hash),
191 rc = gnutls_cipher_init(&cipher_hnd,
192 GNUTLS_CIPHER_ARCFOUR_128,
196 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
200 rc = gnutls_cipher_decrypt(cipher_hnd,
203 gnutls_cipher_deinit(cipher_hnd);
205 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
209 if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
210 DEBUG(3,("samr: failed to decode password buffer\n"));
211 authsam_update_bad_pwd_count(sam_ctx, res[0], ldb_get_default_basedn(sam_ctx));
212 status = NT_STATUS_WRONG_PASSWORD;
216 if (!convert_string_talloc_handle(mem_ctx, lpcfg_iconv_handle(dce_call->conn->dce_ctx->lp_ctx),
218 (const char *)new_password.data,
220 (void **)&new_pass, &converted_size)) {
221 DEBUG(3,("samr: failed to convert incoming password buffer to unix charset\n"));
222 authsam_update_bad_pwd_count(sam_ctx, res[0], ldb_get_default_basedn(sam_ctx));
223 status = NT_STATUS_WRONG_PASSWORD;
227 if (!convert_string_talloc_handle(mem_ctx, lpcfg_iconv_handle(dce_call->conn->dce_ctx->lp_ctx),
229 (const char *)new_password.data,
231 (void **)&new_unicode_password.data, &unicode_pw_len)) {
232 DEBUG(3,("samr: failed to convert incoming password buffer to UTF16 charset\n"));
233 authsam_update_bad_pwd_count(sam_ctx, res[0], ldb_get_default_basedn(sam_ctx));
234 status = NT_STATUS_WRONG_PASSWORD;
237 new_unicode_password.length = unicode_pw_len;
239 E_deshash(new_pass, new_lm_hash);
240 E_old_pw_hash(new_lm_hash, lm_pwd->hash, lm_verifier.hash);
241 if (memcmp(lm_verifier.hash, r->in.hash->hash, 16) != 0) {
242 authsam_update_bad_pwd_count(sam_ctx, res[0], ldb_get_default_basedn(sam_ctx));
243 status = NT_STATUS_WRONG_PASSWORD;
247 /* Connect to a SAMDB with user privileges for the password change */
248 sam_ctx = samdb_connect(mem_ctx,
250 dce_call->conn->dce_ctx->lp_ctx,
252 dce_call->conn->remote_address,
254 if (sam_ctx == NULL) {
255 return NT_STATUS_INVALID_SYSTEM_SERVICE;
258 /* Start transaction */
259 ret = ldb_transaction_start(sam_ctx);
260 if (ret != LDB_SUCCESS) {
261 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
262 return NT_STATUS_TRANSACTION_ABORTED;
265 /* Performs the password modification. We pass the old hashes read out
266 * from the database since they were already checked against the user-
268 status = samdb_set_password(sam_ctx, mem_ctx,
270 &new_unicode_password,
272 lm_pwd, NULL, /* this is a user password change */
275 if (!NT_STATUS_IS_OK(status)) {
276 ldb_transaction_cancel(sam_ctx);
280 /* And this confirms it in a transaction commit */
281 ret = ldb_transaction_commit(sam_ctx);
282 if (ret != LDB_SUCCESS) {
283 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
284 ldb_dn_get_linearized(user_dn),
285 ldb_errstring(sam_ctx)));
286 status = NT_STATUS_TRANSACTION_ABORTED;
290 status = NT_STATUS_OK;
294 log_password_change_event(imsg_ctx,
295 dce_call->conn->dce_ctx->lp_ctx,
296 dce_call->conn->remote_address,
297 dce_call->conn->local_address,
298 "OemChangePasswordUser2",
299 "RC4/DES using LanMan-hash",
300 r->in.account->string,
304 if (NT_STATUS_IS_OK(status)) {
307 /* Only update the badPwdCount if we found the user */
308 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
309 authsam_update_bad_pwd_count(sam_ctx, res[0], ldb_get_default_basedn(sam_ctx));
310 } else if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
311 /* Don't give the game away: (don't allow anonymous users to prove the existence of usernames) */
312 status = NT_STATUS_WRONG_PASSWORD;
320 samr_ChangePasswordUser3
322 NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
324 struct samr_ChangePasswordUser3 *r)
326 struct auth_session_info *session_info =
327 dcesrv_call_session_info(dce_call);
328 struct imessaging_context *imsg_ctx =
329 dcesrv_imessaging_context(dce_call->conn);
330 NTSTATUS status = NT_STATUS_WRONG_PASSWORD;
331 DATA_BLOB new_password;
332 struct ldb_context *sam_ctx = NULL;
333 struct ldb_dn *user_dn = NULL;
335 struct ldb_message **res;
336 const char * const attrs[] = { "unicodePwd", "dBCSPwd",
337 "userAccountControl",
339 "msDS-User-Account-Control-Computed",
340 "badPwdCount", "badPasswordTime",
342 struct samr_Password *nt_pwd, *lm_pwd;
343 struct samr_DomInfo1 *dominfo = NULL;
344 struct userPwdChangeFailureInformation *reject = NULL;
345 enum samPwdChangeReason reason = SAM_PWD_CHANGE_NO_ERROR;
346 uint8_t new_nt_hash[16], new_lm_hash[16];
347 struct samr_Password nt_verifier, lm_verifier;
348 const char *user_samAccountName = NULL;
349 struct dom_sid *user_objectSid = NULL;
350 enum ntlm_auth_level ntlm_auth_level
351 = lpcfg_ntlm_auth(dce_call->conn->dce_ctx->lp_ctx);
352 gnutls_cipher_hd_t cipher_hnd = NULL;
353 gnutls_datum_t nt_session_key;
356 *r->out.dominfo = NULL;
357 *r->out.reject = NULL;
359 /* this call should be disabled without NTLM auth */
360 if (ntlm_auth_level == NTLM_AUTH_DISABLED) {
361 DBG_WARNING("NTLM password changes not"
362 "permitted by configuration.\n");
363 return NT_STATUS_NTLM_BLOCKED;
366 if (r->in.nt_password == NULL ||
367 r->in.nt_verifier == NULL) {
368 return NT_STATUS_INVALID_PARAMETER;
371 /* Connect to a SAMDB with system privileges for fetching the old pw
373 sam_ctx = samdb_connect(mem_ctx,
375 dce_call->conn->dce_ctx->lp_ctx,
376 system_session(dce_call->conn->dce_ctx->lp_ctx),
377 dce_call->conn->remote_address,
379 if (sam_ctx == NULL) {
380 return NT_STATUS_INVALID_SYSTEM_SERVICE;
383 /* we need the users dn and the domain dn (derived from the
384 user SID). We also need the current lm and nt password hashes
385 in order to decrypt the incoming passwords */
386 ret = gendb_search(sam_ctx,
387 mem_ctx, NULL, &res, attrs,
388 "(&(sAMAccountName=%s)(objectclass=user))",
389 ldb_binary_encode_string(mem_ctx, r->in.account->string));
391 status = NT_STATUS_NO_SUCH_USER; /* Converted to WRONG_PASSWORD below */
395 user_dn = res[0]->dn;
396 user_samAccountName = ldb_msg_find_attr_as_string(res[0], "samAccountName", NULL);
397 user_objectSid = samdb_result_dom_sid(res, res[0], "objectSid");
399 status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx,
400 res[0], &lm_pwd, &nt_pwd);
401 if (!NT_STATUS_IS_OK(status) ) {
406 status = NT_STATUS_WRONG_PASSWORD;
410 /* decrypt the password we have been given */
411 nt_session_key = (gnutls_datum_t) {
412 .data = nt_pwd->hash,
413 .size = sizeof(nt_pwd->hash),
416 rc = gnutls_cipher_init(&cipher_hnd,
417 GNUTLS_CIPHER_ARCFOUR_128,
421 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
425 rc = gnutls_cipher_decrypt(cipher_hnd,
426 r->in.nt_password->data,
428 gnutls_cipher_deinit(cipher_hnd);
430 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
434 if (!extract_pw_from_buffer(mem_ctx, r->in.nt_password->data, &new_password)) {
435 DEBUG(3,("samr: failed to decode password buffer\n"));
436 status = NT_STATUS_WRONG_PASSWORD;
440 if (r->in.nt_verifier == NULL) {
441 status = NT_STATUS_WRONG_PASSWORD;
445 /* check NT verifier */
446 mdfour(new_nt_hash, new_password.data, new_password.length);
448 E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash);
449 if (memcmp(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) {
450 status = NT_STATUS_WRONG_PASSWORD;
454 /* check LM verifier (really not needed as we just checked the
455 * much stronger NT hash, but the RPC-SAMR test checks for
457 if (lm_pwd && r->in.lm_verifier != NULL) {
459 size_t converted_size = 0;
461 if (!convert_string_talloc_handle(mem_ctx, lpcfg_iconv_handle(dce_call->conn->dce_ctx->lp_ctx),
463 (const char *)new_password.data,
465 (void **)&new_pass, &converted_size)) {
466 E_deshash(new_pass, new_lm_hash);
467 E_old_pw_hash(new_nt_hash, lm_pwd->hash, lm_verifier.hash);
468 if (memcmp(lm_verifier.hash, r->in.lm_verifier->hash, 16) != 0) {
469 status = NT_STATUS_WRONG_PASSWORD;
475 /* Connect to a SAMDB with user privileges for the password change */
476 sam_ctx = samdb_connect(mem_ctx,
478 dce_call->conn->dce_ctx->lp_ctx,
480 dce_call->conn->remote_address,
482 if (sam_ctx == NULL) {
483 return NT_STATUS_INVALID_SYSTEM_SERVICE;
486 ret = ldb_transaction_start(sam_ctx);
487 if (ret != LDB_SUCCESS) {
488 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
489 return NT_STATUS_TRANSACTION_ABORTED;
492 /* Performs the password modification. We pass the old hashes read out
493 * from the database since they were already checked against the user-
495 status = samdb_set_password(sam_ctx, mem_ctx,
499 lm_pwd, nt_pwd, /* this is a user password change */
503 if (!NT_STATUS_IS_OK(status)) {
504 ldb_transaction_cancel(sam_ctx);
508 /* And this confirms it in a transaction commit */
509 ret = ldb_transaction_commit(sam_ctx);
510 if (ret != LDB_SUCCESS) {
511 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
512 ldb_dn_get_linearized(user_dn),
513 ldb_errstring(sam_ctx)));
514 status = NT_STATUS_TRANSACTION_ABORTED;
518 status = NT_STATUS_OK;
522 log_password_change_event(imsg_ctx,
523 dce_call->conn->dce_ctx->lp_ctx,
524 dce_call->conn->remote_address,
525 dce_call->conn->local_address,
526 "samr_ChangePasswordUser3",
527 "RC4/DES using NTLM-hash",
528 r->in.account->string,
532 if (NT_STATUS_IS_OK(status)) {
536 /* Only update the badPwdCount if we found the user */
537 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
538 authsam_update_bad_pwd_count(sam_ctx, res[0], ldb_get_default_basedn(sam_ctx));
539 } else if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
540 /* Don't give the game away: (don't allow anonymous users to prove the existence of usernames) */
541 status = NT_STATUS_WRONG_PASSWORD;
544 reject = talloc_zero(mem_ctx, struct userPwdChangeFailureInformation);
545 if (reject != NULL) {
546 reject->extendedFailureReason = reason;
548 *r->out.reject = reject;
551 *r->out.dominfo = dominfo;
557 samr_ChangePasswordUser2
559 easy - just a subset of samr_ChangePasswordUser3
561 NTSTATUS dcesrv_samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call,
563 struct samr_ChangePasswordUser2 *r)
565 struct samr_ChangePasswordUser3 r2;
566 struct samr_DomInfo1 *dominfo = NULL;
567 struct userPwdChangeFailureInformation *reject = NULL;
569 r2.in.server = r->in.server;
570 r2.in.account = r->in.account;
571 r2.in.nt_password = r->in.nt_password;
572 r2.in.nt_verifier = r->in.nt_verifier;
573 r2.in.lm_change = r->in.lm_change;
574 r2.in.lm_password = r->in.lm_password;
575 r2.in.lm_verifier = r->in.lm_verifier;
576 r2.in.password3 = NULL;
577 r2.out.dominfo = &dominfo;
578 r2.out.reject = &reject;
580 return dcesrv_samr_ChangePasswordUser3(dce_call, mem_ctx, &r2);
585 set password via a samr_CryptPassword buffer
587 NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
588 struct ldb_context *sam_ctx,
589 struct ldb_dn *account_dn, struct ldb_dn *domain_dn,
591 struct samr_CryptPassword *pwbuf)
594 DATA_BLOB new_password;
595 DATA_BLOB session_key = data_blob(NULL, 0);
596 gnutls_cipher_hd_t cipher_hnd = NULL;
597 gnutls_datum_t _session_key;
600 nt_status = dcesrv_transport_session_key(dce_call, &session_key);
601 if (!NT_STATUS_IS_OK(nt_status)) {
602 DEBUG(3,("samr: failed to get session key: %s "
603 "=> NT_STATUS_WRONG_PASSWORD\n",
604 nt_errstr(nt_status)));
605 return NT_STATUS_WRONG_PASSWORD;
608 _session_key = (gnutls_datum_t) {
609 .data = session_key.data,
610 .size = session_key.length,
613 rc = gnutls_cipher_init(&cipher_hnd,
614 GNUTLS_CIPHER_ARCFOUR_128,
618 nt_status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
622 rc = gnutls_cipher_decrypt(cipher_hnd,
625 gnutls_cipher_deinit(cipher_hnd);
627 nt_status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
631 if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
632 DEBUG(3,("samr: failed to decode password buffer\n"));
633 return NT_STATUS_WRONG_PASSWORD;
636 /* set the password - samdb needs to know both the domain and user DNs,
637 so the domain password policy can be used */
638 nt_status = samdb_set_password(sam_ctx,
646 NULL, /* This is a password set, not change */
655 set password via a samr_CryptPasswordEx buffer
657 NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call,
658 struct ldb_context *sam_ctx,
659 struct ldb_dn *account_dn,
660 struct ldb_dn *domain_dn,
662 struct samr_CryptPasswordEx *pwbuf)
665 DATA_BLOB new_password;
667 /* The confounder is in the last 16 bytes of the buffer */
668 DATA_BLOB confounder = data_blob_const(&pwbuf->data[516], 16);
669 DATA_BLOB pw_data = data_blob_const(pwbuf->data, 516);
670 DATA_BLOB session_key = data_blob(NULL, 0);
673 nt_status = dcesrv_transport_session_key(dce_call, &session_key);
674 if (!NT_STATUS_IS_OK(nt_status)) {
675 DEBUG(3,("samr: failed to get session key: %s "
676 "=> NT_STATUS_WRONG_PASSWORD\n",
677 nt_errstr(nt_status)));
678 return NT_STATUS_WRONG_PASSWORD;
681 rc = samba_gnutls_arcfour_confounded_md5(&confounder,
684 SAMBA_GNUTLS_DECRYPT);
686 nt_status = gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
690 if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
691 DEBUG(3,("samr: failed to decode password buffer\n"));
692 nt_status = NT_STATUS_WRONG_PASSWORD;
696 /* set the password - samdb needs to know both the domain and user DNs,
697 so the domain password policy can be used */
698 nt_status = samdb_set_password(sam_ctx,
706 NULL, /* This is a password set, not change */
709 ZERO_ARRAY_LEN(new_password.data,
710 new_password.length);
717 set password via encrypted NT and LM hash buffers
719 NTSTATUS samr_set_password_buffers(struct dcesrv_call_state *dce_call,
720 struct ldb_context *sam_ctx,
721 struct ldb_dn *account_dn,
722 struct ldb_dn *domain_dn,
724 const uint8_t *lm_pwd_hash,
725 const uint8_t *nt_pwd_hash)
727 struct samr_Password *d_lm_pwd_hash = NULL, *d_nt_pwd_hash = NULL;
728 uint8_t random_session_key[16] = { 0, };
729 DATA_BLOB session_key = data_blob(NULL, 0);
731 NTSTATUS nt_status = NT_STATUS_OK;
733 nt_status = dcesrv_transport_session_key(dce_call, &session_key);
734 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_USER_SESSION_KEY)) {
735 DEBUG(3,("samr: failed to get session key: %s "
736 "=> use a random session key\n",
737 nt_errstr(nt_status)));
740 * Windows just uses a random key
742 generate_random_buffer(random_session_key,
743 sizeof(random_session_key));
744 session_key = data_blob_const(random_session_key,
745 sizeof(random_session_key));
746 nt_status = NT_STATUS_OK;
748 if (!NT_STATUS_IS_OK(nt_status)) {
752 if (lm_pwd_hash != NULL) {
753 in = data_blob_const(lm_pwd_hash, 16);
754 out = data_blob_talloc_zero(mem_ctx, 16);
756 sess_crypt_blob(&out, &in, &session_key, false);
758 d_lm_pwd_hash = (struct samr_Password *) out.data;
760 if (nt_pwd_hash != NULL) {
761 in = data_blob_const(nt_pwd_hash, 16);
762 out = data_blob_talloc_zero(mem_ctx, 16);
764 sess_crypt_blob(&out, &in, &session_key, false);
766 d_nt_pwd_hash = (struct samr_Password *) out.data;
769 if ((d_lm_pwd_hash != NULL) || (d_nt_pwd_hash != NULL)) {
770 nt_status = samdb_set_password(sam_ctx, mem_ctx, account_dn,
772 d_lm_pwd_hash, d_nt_pwd_hash,
773 NULL, NULL, /* this is a password set */