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