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