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