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