s4-loadparm: 2nd half of lp_ to lpcfg_ conversion
[sfrench/samba-autobuild/.git] / source4 / rpc_server / samr / samr_password.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    samr server password set/change handling
5
6    Copyright (C) Andrew Tridgell 2004
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
8    
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.
13    
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.
18    
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/>.
21 */
22
23 #include "includes.h"
24 #include "rpc_server/dcerpc_server.h"
25 #include "rpc_server/samr/dcesrv_samr.h"
26 #include "system/time.h"
27 #include "../lib/crypto/crypto.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
33 /* 
34   samr_ChangePasswordUser 
35 */
36 NTSTATUS dcesrv_samr_ChangePasswordUser(struct dcesrv_call_state *dce_call, 
37                                         TALLOC_CTX *mem_ctx,
38                                         struct samr_ChangePasswordUser *r)
39 {
40         struct dcesrv_handle *h;
41         struct samr_account_state *a_state;
42         struct ldb_context *sam_ctx;
43         struct ldb_message **res;
44         int ret;
45         struct samr_Password new_lmPwdHash, new_ntPwdHash, checkHash;
46         struct samr_Password *lm_pwd, *nt_pwd;
47         NTSTATUS status = NT_STATUS_OK;
48         const char * const attrs[] = { "dBCSPwd", "unicodePwd" , NULL };
49
50         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
51
52         a_state = h->data;
53
54         /* basic sanity checking on parameters.  Do this before any database ops */
55         if (!r->in.lm_present || !r->in.nt_present ||
56             !r->in.old_lm_crypted || !r->in.new_lm_crypted ||
57             !r->in.old_nt_crypted || !r->in.new_nt_crypted) {
58                 /* we should really handle a change with lm not
59                    present */
60                 return NT_STATUS_INVALID_PARAMETER_MIX;
61         }
62
63         /* To change a password we need to open as system */
64         sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(dce_call->conn->dce_ctx->lp_ctx));
65         if (sam_ctx == NULL) {
66                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
67         }
68
69         ret = ldb_transaction_start(sam_ctx);
70         if (ret != LDB_SUCCESS) {
71                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
72                 return NT_STATUS_TRANSACTION_ABORTED;
73         }
74
75         /* fetch the old hashes */
76         ret = gendb_search_dn(sam_ctx, mem_ctx,
77                               a_state->account_dn, &res, attrs);
78         if (ret != 1) {
79                 ldb_transaction_cancel(sam_ctx);
80                 return NT_STATUS_WRONG_PASSWORD;
81         }
82
83         status = samdb_result_passwords(mem_ctx,
84                                         dce_call->conn->dce_ctx->lp_ctx,
85                                         res[0], &lm_pwd, &nt_pwd);
86         if (!NT_STATUS_IS_OK(status) || !nt_pwd) {
87                 ldb_transaction_cancel(sam_ctx);
88                 return NT_STATUS_WRONG_PASSWORD;
89         }
90
91         /* decrypt and check the new lm hash */
92         if (lm_pwd) {
93                 D_P16(lm_pwd->hash, r->in.new_lm_crypted->hash, new_lmPwdHash.hash);
94                 D_P16(new_lmPwdHash.hash, r->in.old_lm_crypted->hash, checkHash.hash);
95                 if (memcmp(checkHash.hash, lm_pwd, 16) != 0) {
96                         ldb_transaction_cancel(sam_ctx);
97                         return NT_STATUS_WRONG_PASSWORD;
98                 }
99         }
100
101         /* decrypt and check the new nt hash */
102         D_P16(nt_pwd->hash, r->in.new_nt_crypted->hash, new_ntPwdHash.hash);
103         D_P16(new_ntPwdHash.hash, r->in.old_nt_crypted->hash, checkHash.hash);
104         if (memcmp(checkHash.hash, nt_pwd, 16) != 0) {
105                 ldb_transaction_cancel(sam_ctx);
106                 return NT_STATUS_WRONG_PASSWORD;
107         }
108         
109         /* The NT Cross is not required by Win2k3 R2, but if present
110            check the nt cross hash */
111         if (r->in.cross1_present && r->in.nt_cross && lm_pwd) {
112                 D_P16(lm_pwd->hash, r->in.nt_cross->hash, checkHash.hash);
113                 if (memcmp(checkHash.hash, new_ntPwdHash.hash, 16) != 0) {
114                         ldb_transaction_cancel(sam_ctx);
115                         return NT_STATUS_WRONG_PASSWORD;
116                 }
117         }
118
119         /* The LM Cross is not required by Win2k3 R2, but if present
120            check the lm cross hash */
121         if (r->in.cross2_present && r->in.lm_cross && lm_pwd) {
122                 D_P16(nt_pwd->hash, r->in.lm_cross->hash, checkHash.hash);
123                 if (memcmp(checkHash.hash, new_lmPwdHash.hash, 16) != 0) {
124                         ldb_transaction_cancel(sam_ctx);
125                         return NT_STATUS_WRONG_PASSWORD;
126                 }
127         }
128
129         /* setup password modify mods on the user DN specified.  This may fail
130          * due to password policies.  */
131         status = samdb_set_password(sam_ctx, mem_ctx,
132                                     a_state->account_dn,
133                                     a_state->domain_state->domain_dn,
134                                     NULL, &new_lmPwdHash, &new_ntPwdHash,
135                                     true, /* this is a user password change */
136                                     NULL,
137                                     NULL);
138         if (!NT_STATUS_IS_OK(status)) {
139                 ldb_transaction_cancel(sam_ctx);
140                 return status;
141         }
142
143         /* And this confirms it in a transaction commit */
144         ret = ldb_transaction_commit(sam_ctx);
145         if (ret != LDB_SUCCESS) {
146                 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
147                          ldb_dn_get_linearized(a_state->account_dn),
148                          ldb_errstring(sam_ctx)));
149                 return NT_STATUS_TRANSACTION_ABORTED;
150         }
151
152         return NT_STATUS_OK;
153 }
154
155 /* 
156   samr_OemChangePasswordUser2 
157 */
158 NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call,
159                                             TALLOC_CTX *mem_ctx,
160                                             struct samr_OemChangePasswordUser2 *r)
161 {
162         NTSTATUS status;
163         DATA_BLOB new_password, new_unicode_password;
164         char *new_pass;
165         struct samr_CryptPassword *pwbuf = r->in.password;
166         struct ldb_context *sam_ctx;
167         struct ldb_dn *user_dn;
168         int ret;
169         struct ldb_message **res;
170         const char * const attrs[] = { "objectSid", "dBCSPwd", NULL };
171         struct samr_Password *lm_pwd;
172         DATA_BLOB lm_pwd_blob;
173         uint8_t new_lm_hash[16];
174         struct samr_Password lm_verifier;
175         size_t unicode_pw_len;
176
177         if (pwbuf == NULL) {
178                 return NT_STATUS_INVALID_PARAMETER;
179         }
180
181         if (r->in.hash == NULL) {
182                 return NT_STATUS_INVALID_PARAMETER;
183         }
184
185         /* this call can only work with lanman auth */
186         if (!lpcfg_lanman_auth(dce_call->conn->dce_ctx->lp_ctx)) {
187                 return NT_STATUS_WRONG_PASSWORD;
188         }
189
190         /* To change a password we need to open as system */
191         sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(dce_call->conn->dce_ctx->lp_ctx));
192         if (sam_ctx == NULL) {
193                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
194         }
195
196         ret = ldb_transaction_start(sam_ctx);
197         if (ret != LDB_SUCCESS) {
198                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
199                 return NT_STATUS_TRANSACTION_ABORTED;
200         }
201
202         /* we need the users dn and the domain dn (derived from the
203            user SID). We also need the current lm password hash in
204            order to decrypt the incoming password */
205         ret = gendb_search(sam_ctx, 
206                            mem_ctx, NULL, &res, attrs,
207                            "(&(sAMAccountName=%s)(objectclass=user))",
208                            r->in.account->string);
209         if (ret != 1) {
210                 ldb_transaction_cancel(sam_ctx);
211                 /* Don't give the game away:  (don't allow anonymous users to prove the existance of usernames) */
212                 return NT_STATUS_WRONG_PASSWORD;
213         }
214
215         user_dn = res[0]->dn;
216
217         status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx,
218                                         res[0], &lm_pwd, NULL);
219         if (!NT_STATUS_IS_OK(status) || !lm_pwd) {
220                 ldb_transaction_cancel(sam_ctx);
221                 return NT_STATUS_WRONG_PASSWORD;
222         }
223
224         /* decrypt the password we have been given */
225         lm_pwd_blob = data_blob(lm_pwd->hash, sizeof(lm_pwd->hash)); 
226         arcfour_crypt_blob(pwbuf->data, 516, &lm_pwd_blob);
227         data_blob_free(&lm_pwd_blob);
228         
229         if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
230                 ldb_transaction_cancel(sam_ctx);
231                 DEBUG(3,("samr: failed to decode password buffer\n"));
232                 return NT_STATUS_WRONG_PASSWORD;
233         }
234                 
235         if (!convert_string_talloc_convenience(mem_ctx, lpcfg_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx),
236                                   CH_DOS, CH_UNIX, 
237                                   (const char *)new_password.data, 
238                                   new_password.length,
239                                   (void **)&new_pass, NULL, false)) {
240                 DEBUG(3,("samr: failed to convert incoming password buffer to unix charset\n"));
241                 ldb_transaction_cancel(sam_ctx);
242                 return NT_STATUS_WRONG_PASSWORD;
243         }
244
245         if (!convert_string_talloc_convenience(mem_ctx, lpcfg_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx),
246                                                CH_DOS, CH_UTF16, 
247                                                (const char *)new_password.data, 
248                                                new_password.length,
249                                                (void **)&new_unicode_password.data, &unicode_pw_len, false)) {
250                 DEBUG(3,("samr: failed to convert incoming password buffer to UTF16 charset\n"));
251                 ldb_transaction_cancel(sam_ctx);
252                 return NT_STATUS_WRONG_PASSWORD;
253         }
254         new_unicode_password.length = unicode_pw_len;
255
256         E_deshash(new_pass, new_lm_hash);
257         E_old_pw_hash(new_lm_hash, lm_pwd->hash, lm_verifier.hash);
258         if (memcmp(lm_verifier.hash, r->in.hash->hash, 16) != 0) {
259                 ldb_transaction_cancel(sam_ctx);
260                 return NT_STATUS_WRONG_PASSWORD;
261         }
262
263         /* set the password on the user DN specified.  This may fail
264          * due to password policies */
265         status = samdb_set_password(sam_ctx, mem_ctx,
266                                     user_dn, NULL, 
267                                     &new_unicode_password,
268                                     NULL, NULL,
269                                     true, /* this is a user password change */
270                                     NULL, 
271                                     NULL);
272         if (!NT_STATUS_IS_OK(status)) {
273                 ldb_transaction_cancel(sam_ctx);
274                 return status;
275         }
276
277         /* And this confirms it in a transaction commit */
278         ret = ldb_transaction_commit(sam_ctx);
279         if (ret != LDB_SUCCESS) {
280                 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
281                          ldb_dn_get_linearized(user_dn),
282                          ldb_errstring(sam_ctx)));
283                 return NT_STATUS_TRANSACTION_ABORTED;
284         }
285
286         return NT_STATUS_OK;
287 }
288
289
290 /* 
291   samr_ChangePasswordUser3 
292 */
293 NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call, 
294                                          TALLOC_CTX *mem_ctx,
295                                          struct samr_ChangePasswordUser3 *r)
296 {       
297         NTSTATUS status;
298         DATA_BLOB new_password;
299         struct ldb_context *sam_ctx = NULL;
300         struct ldb_dn *user_dn;
301         int ret;
302         struct ldb_message **res;
303         const char * const attrs[] = { "unicodePwd", "dBCSPwd", NULL };
304         struct samr_Password *nt_pwd, *lm_pwd;
305         DATA_BLOB nt_pwd_blob;
306         struct samr_DomInfo1 *dominfo = NULL;
307         struct userPwdChangeFailureInformation *reject = NULL;
308         enum samPwdChangeReason reason = SAM_PWD_CHANGE_NO_ERROR;
309         uint8_t new_nt_hash[16], new_lm_hash[16];
310         struct samr_Password nt_verifier, lm_verifier;
311
312         *r->out.dominfo = NULL;
313         *r->out.reject = NULL;
314
315         if (r->in.nt_password == NULL ||
316             r->in.nt_verifier == NULL) {
317                 return NT_STATUS_INVALID_PARAMETER;
318         }
319
320         /* To change a password we need to open as system */
321         sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(dce_call->conn->dce_ctx->lp_ctx));
322         if (sam_ctx == NULL) {
323                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
324         }
325
326         ret = ldb_transaction_start(sam_ctx);
327         if (ret != LDB_SUCCESS) {
328                 talloc_free(sam_ctx);
329                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
330                 return NT_STATUS_TRANSACTION_ABORTED;
331         }
332
333         /* we need the users dn and the domain dn (derived from the
334            user SID). We also need the current lm and nt password hashes
335            in order to decrypt the incoming passwords */
336         ret = gendb_search(sam_ctx, 
337                            mem_ctx, NULL, &res, attrs,
338                            "(&(sAMAccountName=%s)(objectclass=user))",
339                            r->in.account->string);
340         if (ret != 1) {
341                 /* Don't give the game away:  (don't allow anonymous users to prove the existance of usernames) */
342                 status = NT_STATUS_WRONG_PASSWORD;
343                 goto failed;
344         }
345
346         user_dn = res[0]->dn;
347
348         status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx,
349                                         res[0], &lm_pwd, &nt_pwd);
350         if (!NT_STATUS_IS_OK(status) ) {
351                 goto failed;
352         }
353
354         if (!nt_pwd) {
355                 status = NT_STATUS_WRONG_PASSWORD;
356                 goto failed;
357         }
358
359         /* decrypt the password we have been given */
360         nt_pwd_blob = data_blob(nt_pwd->hash, sizeof(nt_pwd->hash));
361         arcfour_crypt_blob(r->in.nt_password->data, 516, &nt_pwd_blob);
362         data_blob_free(&nt_pwd_blob);
363
364         if (!extract_pw_from_buffer(mem_ctx, r->in.nt_password->data, &new_password)) {
365                 ldb_transaction_cancel(sam_ctx);
366                 DEBUG(3,("samr: failed to decode password buffer\n"));
367                 return NT_STATUS_WRONG_PASSWORD;
368         }
369                 
370         if (r->in.nt_verifier == NULL) {
371                 status = NT_STATUS_WRONG_PASSWORD;
372                 goto failed;
373         }
374
375         /* check NT verifier */
376         mdfour(new_nt_hash, new_password.data, new_password.length);
377
378         E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash);
379         if (memcmp(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) {
380                 status = NT_STATUS_WRONG_PASSWORD;
381                 goto failed;
382         }
383
384         /* check LM verifier (really not needed as we just checked the
385          * much stronger NT hash, but the RPC-SAMR test checks for
386          * this) */
387         if (lm_pwd && r->in.lm_verifier != NULL) {
388                 char *new_pass;
389                 if (!convert_string_talloc_convenience(mem_ctx, lpcfg_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx),
390                                           CH_UTF16, CH_UNIX, 
391                                           (const char *)new_password.data, 
392                                           new_password.length,
393                                           (void **)&new_pass, NULL, false)) {
394                         E_deshash(new_pass, new_lm_hash);
395                         E_old_pw_hash(new_nt_hash, lm_pwd->hash, lm_verifier.hash);
396                         if (memcmp(lm_verifier.hash, r->in.lm_verifier->hash, 16) != 0) {
397                                 status = NT_STATUS_WRONG_PASSWORD;
398                                 goto failed;
399                         }
400                 }
401         }
402
403         /* set the password on the user DN specified.  This may fail
404          * due to password policies */
405         status = samdb_set_password(sam_ctx, mem_ctx,
406                                     user_dn, NULL, 
407                                     &new_password,
408                                     NULL, NULL,
409                                     true, /* this is a user password change */
410                                     &reason, 
411                                     &dominfo);
412
413         if (!NT_STATUS_IS_OK(status)) {
414                 goto failed;
415         }
416
417         /* And this confirms it in a transaction commit */
418         ret = ldb_transaction_commit(sam_ctx);
419         if (ret != LDB_SUCCESS) {
420                 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
421                          ldb_dn_get_linearized(user_dn),
422                          ldb_errstring(sam_ctx)));
423                 status = NT_STATUS_TRANSACTION_ABORTED;
424                 goto failed;
425         }
426
427         return NT_STATUS_OK;
428
429 failed:
430         ldb_transaction_cancel(sam_ctx);
431
432         reject = talloc_zero(mem_ctx, struct userPwdChangeFailureInformation);
433         if (reject != NULL) {
434                 reject->extendedFailureReason = reason;
435
436                 *r->out.reject = reject;
437         }
438
439         *r->out.dominfo = dominfo;
440
441         return status;
442 }
443
444
445 /* 
446   samr_ChangePasswordUser2 
447
448   easy - just a subset of samr_ChangePasswordUser3
449 */
450 NTSTATUS dcesrv_samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call,
451                                          TALLOC_CTX *mem_ctx,
452                                          struct samr_ChangePasswordUser2 *r)
453 {
454         struct samr_ChangePasswordUser3 r2;
455         struct samr_DomInfo1 *dominfo = NULL;
456         struct userPwdChangeFailureInformation *reject = NULL;
457
458         r2.in.server = r->in.server;
459         r2.in.account = r->in.account;
460         r2.in.nt_password = r->in.nt_password;
461         r2.in.nt_verifier = r->in.nt_verifier;
462         r2.in.lm_change = r->in.lm_change;
463         r2.in.lm_password = r->in.lm_password;
464         r2.in.lm_verifier = r->in.lm_verifier;
465         r2.in.password3 = NULL;
466         r2.out.dominfo = &dominfo;
467         r2.out.reject = &reject;
468
469         return dcesrv_samr_ChangePasswordUser3(dce_call, mem_ctx, &r2);
470 }
471
472
473 /*
474   set password via a samr_CryptPassword buffer
475 */
476 NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
477                            struct ldb_context *sam_ctx,
478                            struct ldb_dn *account_dn, struct ldb_dn *domain_dn,
479                            TALLOC_CTX *mem_ctx,
480                            struct samr_CryptPassword *pwbuf)
481 {
482         NTSTATUS nt_status;
483         DATA_BLOB new_password;
484         DATA_BLOB session_key = data_blob(NULL, 0);
485
486         nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
487         if (!NT_STATUS_IS_OK(nt_status)) {
488                 return nt_status;
489         }
490
491         arcfour_crypt_blob(pwbuf->data, 516, &session_key);
492
493         if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
494                 DEBUG(3,("samr: failed to decode password buffer\n"));
495                 return NT_STATUS_WRONG_PASSWORD;
496         }
497                 
498         /* set the password - samdb needs to know both the domain and user DNs,
499            so the domain password policy can be used */
500         return samdb_set_password(sam_ctx, mem_ctx,
501                                   account_dn, domain_dn, 
502                                   &new_password,
503                                   NULL, NULL,
504                                   false, /* This is a password set, not change */
505                                   NULL, NULL);
506 }
507
508
509 /*
510   set password via a samr_CryptPasswordEx buffer
511 */
512 NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call,
513                               struct ldb_context *sam_ctx,
514                               struct ldb_dn *account_dn,
515                               struct ldb_dn *domain_dn,
516                               TALLOC_CTX *mem_ctx,
517                               struct samr_CryptPasswordEx *pwbuf)
518 {
519         NTSTATUS nt_status;
520         DATA_BLOB new_password;
521         DATA_BLOB co_session_key;
522         DATA_BLOB session_key = data_blob(NULL, 0);
523         struct MD5Context ctx;
524
525         nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
526         if (!NT_STATUS_IS_OK(nt_status)) {
527                 return nt_status;
528         }
529
530         co_session_key = data_blob_talloc(mem_ctx, NULL, 16);
531         if (!co_session_key.data) {
532                 return NT_STATUS_NO_MEMORY;
533         }
534
535         MD5Init(&ctx);
536         MD5Update(&ctx, &pwbuf->data[516], 16);
537         MD5Update(&ctx, session_key.data, session_key.length);
538         MD5Final(co_session_key.data, &ctx);
539         
540         arcfour_crypt_blob(pwbuf->data, 516, &co_session_key);
541
542         if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
543                 DEBUG(3,("samr: failed to decode password buffer\n"));
544                 return NT_STATUS_WRONG_PASSWORD;
545         }
546                 
547         /* set the password - samdb needs to know both the domain and user DNs,
548            so the domain password policy can be used */
549         return samdb_set_password(sam_ctx, mem_ctx,
550                                   account_dn, domain_dn, 
551                                   &new_password,
552                                   NULL, NULL,
553                                   false, /* This is a password set, not change */
554                                   NULL, NULL);
555 }
556
557 /*
558   set password via encrypted NT and LM hash buffers
559 */
560 NTSTATUS samr_set_password_buffers(struct dcesrv_call_state *dce_call,
561                                    struct ldb_context *sam_ctx,
562                                    struct ldb_dn *account_dn,
563                                    struct ldb_dn *domain_dn,
564                                    TALLOC_CTX *mem_ctx,
565                                    const uint8_t *lm_pwd_hash,
566                                    const uint8_t *nt_pwd_hash)
567 {
568         struct samr_Password *d_lm_pwd_hash = NULL, *d_nt_pwd_hash = NULL;
569         DATA_BLOB session_key = data_blob(NULL, 0);
570         DATA_BLOB in, out;
571         NTSTATUS nt_status = NT_STATUS_OK;
572
573         nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
574         if (!NT_STATUS_IS_OK(nt_status)) {
575                 return nt_status;
576         }
577
578         if (lm_pwd_hash != NULL) {
579                 in = data_blob_const(lm_pwd_hash, 16);
580                 out = data_blob_talloc_zero(mem_ctx, 16);
581
582                 sess_crypt_blob(&out, &in, &session_key, false);
583
584                 d_lm_pwd_hash = (struct samr_Password *) out.data;
585         }
586         if (nt_pwd_hash != NULL) {
587                 in = data_blob_const(nt_pwd_hash, 16);
588                 out = data_blob_talloc_zero(mem_ctx, 16);
589
590                 sess_crypt_blob(&out, &in, &session_key, false);
591
592                 d_nt_pwd_hash = (struct samr_Password *) out.data;
593         }
594
595         if ((d_lm_pwd_hash != NULL) || (d_nt_pwd_hash != NULL)) {
596                 nt_status = samdb_set_password(sam_ctx, mem_ctx, account_dn,
597                                                domain_dn, NULL,
598                                                d_lm_pwd_hash, d_nt_pwd_hash,
599                                                false, /* this is a password set */
600                                                NULL, NULL);
601         }
602
603         return nt_status;
604 }