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