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