s4:rpc_server/samr: Simplify lp_ctx expression
[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/common/common.h"
26 #include "rpc_server/samr/dcesrv_samr.h"
27 #include "system/time.h"
28 #include "lib/crypto/md4.h"
29 #include "dsdb/samdb/samdb.h"
30 #include "auth/auth.h"
31 #include "libcli/auth/libcli_auth.h"
32 #include "../lib/util/util_ldb.h"
33 #include "rpc_server/samr/proto.h"
34 #include "auth/auth_sam.h"
35 #include "lib/param/loadparm.h"
36 #include "librpc/rpc/dcerpc_helper.h"
37
38 #include "lib/crypto/gnutls_helpers.h"
39 #include <gnutls/gnutls.h>
40 #include <gnutls/crypto.h>
41
42 static void log_password_change_event(struct imessaging_context *msg_ctx,
43                                       struct loadparm_context *lp_ctx,
44                                       const struct tsocket_address *remote_client_address,
45                                       const struct tsocket_address *local_server_address,
46                                       const char *auth_description,
47                                       const char *password_type,
48                                       const char *original_client_name,
49                                       const char *account_name_from_db,
50                                       NTSTATUS status,
51                                       struct dom_sid *sid)
52 {
53         /*
54          * Forcing this via the NTLM auth structure is not ideal, but
55          * it is the most practical option right now, and ensures the
56          * logs are consistent, even if some elements are always NULL.
57          */
58         struct auth_usersupplied_info ui = {
59                 .was_mapped = true,
60                 .client = {
61                         .account_name = original_client_name,
62                         .domain_name = lpcfg_sam_name(lp_ctx),
63                 },
64                 .mapped = {
65                         .account_name = account_name_from_db,
66                         .domain_name = lpcfg_sam_name(lp_ctx),
67                 },
68                 .remote_host = remote_client_address,
69                 .local_host = local_server_address,
70                 .service_description = "SAMR Password Change",
71                 .auth_description = auth_description,
72                 .password_type = password_type,
73         };
74
75         log_authentication_event(msg_ctx,
76                                  lp_ctx,
77                                  NULL,
78                                  &ui,
79                                  status,
80                                  ui.mapped.domain_name,
81                                  ui.mapped.account_name,
82                                  sid);
83 }
84 /*
85   samr_ChangePasswordUser
86
87   So old it is just not worth implementing
88   because it does not supply a plaintext and so we can't do password
89   complexity checking and cannot update all the other password hashes.
90
91 */
92 NTSTATUS dcesrv_samr_ChangePasswordUser(struct dcesrv_call_state *dce_call,
93                                         TALLOC_CTX *mem_ctx,
94                                         struct samr_ChangePasswordUser *r)
95 {
96         return NT_STATUS_NOT_IMPLEMENTED;
97 }
98
99 /*
100   samr_OemChangePasswordUser2
101
102   No longer implemented as it requires the LM hash
103 */
104 NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call,
105                                             TALLOC_CTX *mem_ctx,
106                                             struct samr_OemChangePasswordUser2 *r)
107 {
108         return NT_STATUS_NOT_IMPLEMENTED;
109 }
110
111
112 /*
113   samr_ChangePasswordUser3
114 */
115 NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
116                                          TALLOC_CTX *mem_ctx,
117                                          struct samr_ChangePasswordUser3 *r)
118 {
119         struct imessaging_context *imsg_ctx =
120                 dcesrv_imessaging_context(dce_call->conn);
121         NTSTATUS status = NT_STATUS_WRONG_PASSWORD;
122         DATA_BLOB new_password;
123         struct ldb_context *sam_ctx = NULL;
124         struct ldb_dn *user_dn = NULL;
125         int ret;
126         struct ldb_message **res;
127         const char * const attrs[] = { "unicodePwd", "dBCSPwd",
128                                        "userAccountControl",
129                                        "msDS-ResultantPSO",
130                                        "msDS-User-Account-Control-Computed",
131                                        "badPwdCount", "badPasswordTime",
132                                        "objectSid", NULL };
133         struct samr_Password *nt_pwd;
134         struct samr_DomInfo1 *dominfo = NULL;
135         struct userPwdChangeFailureInformation *reject = NULL;
136         enum samPwdChangeReason reason = SAM_PWD_CHANGE_NO_ERROR;
137         uint8_t new_nt_hash[16];
138         struct samr_Password nt_verifier;
139         const char *user_samAccountName = NULL;
140         struct dom_sid *user_objectSid = NULL;
141         struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
142         enum ntlm_auth_level ntlm_auth_level
143                 = lpcfg_ntlm_auth(lp_ctx);
144         gnutls_cipher_hd_t cipher_hnd = NULL;
145         gnutls_datum_t nt_session_key;
146         int rc;
147
148         *r->out.dominfo = NULL;
149         *r->out.reject = NULL;
150
151         /* this call should be disabled without NTLM auth */
152         if (ntlm_auth_level == NTLM_AUTH_DISABLED) {
153                 DBG_WARNING("NTLM password changes not"
154                             "permitted by configuration.\n");
155                 return NT_STATUS_NTLM_BLOCKED;
156         }
157
158         if (r->in.nt_password == NULL ||
159             r->in.nt_verifier == NULL) {
160                 return NT_STATUS_INVALID_PARAMETER;
161         }
162
163         /* Connect to a SAMDB with system privileges for fetching the old pw
164          * hashes. */
165         sam_ctx = dcesrv_samdb_connect_as_system(mem_ctx, dce_call);
166         if (sam_ctx == NULL) {
167                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
168         }
169
170         /* we need the users dn and the domain dn (derived from the
171            user SID). We also need the current lm and nt password hashes
172            in order to decrypt the incoming passwords */
173         ret = gendb_search(sam_ctx,
174                            mem_ctx, NULL, &res, attrs,
175                            "(&(sAMAccountName=%s)(objectclass=user))",
176                            ldb_binary_encode_string(mem_ctx, r->in.account->string));
177         if (ret != 1) {
178                 status = NT_STATUS_NO_SUCH_USER; /* Converted to WRONG_PASSWORD below */
179                 goto failed;
180         }
181
182         user_dn = res[0]->dn;
183         user_samAccountName = ldb_msg_find_attr_as_string(res[0], "samAccountName", NULL);
184         user_objectSid = samdb_result_dom_sid(res, res[0], "objectSid");
185
186         status = samdb_result_passwords(mem_ctx, lp_ctx,
187                                         res[0], &nt_pwd);
188         if (!NT_STATUS_IS_OK(status) ) {
189                 goto failed;
190         }
191
192         if (!nt_pwd) {
193                 status = NT_STATUS_WRONG_PASSWORD;
194                 goto failed;
195         }
196
197         /* decrypt the password we have been given */
198         nt_session_key = (gnutls_datum_t) {
199                 .data = nt_pwd->hash,
200                 .size = sizeof(nt_pwd->hash),
201         };
202
203         rc = gnutls_cipher_init(&cipher_hnd,
204                                 GNUTLS_CIPHER_ARCFOUR_128,
205                                 &nt_session_key,
206                                 NULL);
207         if (rc < 0) {
208                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
209                 goto failed;
210         }
211
212         rc = gnutls_cipher_decrypt(cipher_hnd,
213                                    r->in.nt_password->data,
214                                    516);
215         gnutls_cipher_deinit(cipher_hnd);
216         if (rc < 0) {
217                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
218                 goto failed;
219         }
220
221         if (!extract_pw_from_buffer(mem_ctx, r->in.nt_password->data, &new_password)) {
222                 DEBUG(3,("samr: failed to decode password buffer\n"));
223                 status =  NT_STATUS_WRONG_PASSWORD;
224                 goto failed;
225         }
226
227         if (r->in.nt_verifier == NULL) {
228                 status = NT_STATUS_WRONG_PASSWORD;
229                 goto failed;
230         }
231
232         /* check NT verifier */
233         mdfour(new_nt_hash, new_password.data, new_password.length);
234
235         E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash);
236         if (rc != 0) {
237                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
238                 goto failed;
239         }
240         if (memcmp(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) {
241                 status = NT_STATUS_WRONG_PASSWORD;
242                 goto failed;
243         }
244
245         /* Connect to a SAMDB with user privileges for the password change */
246         sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call);
247         if (sam_ctx == NULL) {
248                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
249         }
250
251         ret = ldb_transaction_start(sam_ctx);
252         if (ret != LDB_SUCCESS) {
253                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
254                 return NT_STATUS_TRANSACTION_ABORTED;
255         }
256
257         /* Performs the password modification. We pass the old hashes read out
258          * from the database since they were already checked against the user-
259          * provided ones. */
260         status = samdb_set_password(sam_ctx, mem_ctx,
261                                     user_dn, NULL,
262                                     &new_password,
263                                     NULL,
264                                     DSDB_PASSWORD_CHECKED_AND_CORRECT,
265                                     &reason,
266                                     &dominfo);
267
268         if (!NT_STATUS_IS_OK(status)) {
269                 ldb_transaction_cancel(sam_ctx);
270                 goto failed;
271         }
272
273         /* And this confirms it in a transaction commit */
274         ret = ldb_transaction_commit(sam_ctx);
275         if (ret != LDB_SUCCESS) {
276                 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
277                          ldb_dn_get_linearized(user_dn),
278                          ldb_errstring(sam_ctx)));
279                 status = NT_STATUS_TRANSACTION_ABORTED;
280                 goto failed;
281         }
282
283         status = NT_STATUS_OK;
284
285 failed:
286
287         log_password_change_event(imsg_ctx,
288                                   lp_ctx,
289                                   dce_call->conn->remote_address,
290                                   dce_call->conn->local_address,
291                                   "samr_ChangePasswordUser3",
292                                   "RC4/DES using NTLM-hash",
293                                   r->in.account->string,
294                                   user_samAccountName,
295                                   status,
296                                   user_objectSid);
297         if (NT_STATUS_IS_OK(status)) {
298                 return NT_STATUS_OK;
299         }
300
301         /* Only update the badPwdCount if we found the user */
302         if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
303                 authsam_update_bad_pwd_count(sam_ctx, res[0], ldb_get_default_basedn(sam_ctx));
304         } else if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
305                 /* Don't give the game away:  (don't allow anonymous users to prove the existence of usernames) */
306                 status = NT_STATUS_WRONG_PASSWORD;
307         }
308
309         reject = talloc_zero(mem_ctx, struct userPwdChangeFailureInformation);
310         if (reject != NULL) {
311                 reject->extendedFailureReason = reason;
312
313                 *r->out.reject = reject;
314         }
315
316         *r->out.dominfo = dominfo;
317
318         return status;
319 }
320
321 /*
322   samr_ChangePasswordUser2
323
324   easy - just a subset of samr_ChangePasswordUser3
325 */
326 NTSTATUS dcesrv_samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call,
327                                          TALLOC_CTX *mem_ctx,
328                                          struct samr_ChangePasswordUser2 *r)
329 {
330         struct samr_ChangePasswordUser3 r2;
331         struct samr_DomInfo1 *dominfo = NULL;
332         struct userPwdChangeFailureInformation *reject = NULL;
333
334         r2.in.server = r->in.server;
335         r2.in.account = r->in.account;
336         r2.in.nt_password = r->in.nt_password;
337         r2.in.nt_verifier = r->in.nt_verifier;
338         r2.in.lm_change = r->in.lm_change;
339         r2.in.lm_password = r->in.lm_password;
340         r2.in.lm_verifier = r->in.lm_verifier;
341         r2.in.password3 = NULL;
342         r2.out.dominfo = &dominfo;
343         r2.out.reject = &reject;
344
345         return dcesrv_samr_ChangePasswordUser3(dce_call, mem_ctx, &r2);
346 }
347
348
349 /*
350   set password via a samr_CryptPassword buffer
351 */
352 NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
353                            struct ldb_context *sam_ctx,
354                            struct ldb_dn *account_dn, struct ldb_dn *domain_dn,
355                            TALLOC_CTX *mem_ctx,
356                            struct samr_CryptPassword *pwbuf)
357 {
358         NTSTATUS nt_status;
359         DATA_BLOB new_password;
360         DATA_BLOB session_key = data_blob(NULL, 0);
361         gnutls_cipher_hd_t cipher_hnd = NULL;
362         gnutls_datum_t _session_key;
363         struct auth_session_info *session_info =
364                 dcesrv_call_session_info(dce_call);
365         struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
366         int rc;
367         bool encrypted;
368
369         encrypted = dcerpc_is_transport_encrypted(session_info);
370         if (lpcfg_weak_crypto(lp_ctx) == SAMBA_WEAK_CRYPTO_DISALLOWED &&
371             !encrypted) {
372                 return NT_STATUS_ACCESS_DENIED;
373         }
374
375         nt_status = dcesrv_transport_session_key(dce_call, &session_key);
376         if (!NT_STATUS_IS_OK(nt_status)) {
377                 DBG_NOTICE("samr: failed to get session key: %s\n",
378                            nt_errstr(nt_status));
379                 return nt_status;
380         }
381
382         _session_key = (gnutls_datum_t) {
383                 .data = session_key.data,
384                 .size = session_key.length,
385         };
386
387         /*
388          * This is safe to support as we only have a session key
389          * over a SMB connection which we force to be encrypted.
390          */
391         GNUTLS_FIPS140_SET_LAX_MODE();
392         rc = gnutls_cipher_init(&cipher_hnd,
393                                 GNUTLS_CIPHER_ARCFOUR_128,
394                                 &_session_key,
395                                 NULL);
396         if (rc < 0) {
397                 GNUTLS_FIPS140_SET_STRICT_MODE();
398                 nt_status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
399                 goto out;
400         }
401
402         rc = gnutls_cipher_decrypt(cipher_hnd,
403                                    pwbuf->data,
404                                    516);
405         gnutls_cipher_deinit(cipher_hnd);
406         GNUTLS_FIPS140_SET_STRICT_MODE();
407         if (rc < 0) {
408                 nt_status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
409                 goto out;
410         }
411
412         if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
413                 DEBUG(3,("samr: failed to decode password buffer\n"));
414                 return NT_STATUS_WRONG_PASSWORD;
415         }
416
417         /* set the password - samdb needs to know both the domain and user DNs,
418            so the domain password policy can be used */
419         nt_status = samdb_set_password(sam_ctx,
420                                        mem_ctx,
421                                        account_dn,
422                                        domain_dn,
423                                        &new_password,
424                                        NULL,
425                                        DSDB_PASSWORD_RESET,
426                                        NULL,
427                                        NULL);
428 out:
429         return nt_status;
430 }
431
432
433 /*
434   set password via a samr_CryptPasswordEx buffer
435 */
436 NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call,
437                               struct ldb_context *sam_ctx,
438                               struct ldb_dn *account_dn,
439                               struct ldb_dn *domain_dn,
440                               TALLOC_CTX *mem_ctx,
441                               struct samr_CryptPasswordEx *pwbuf)
442 {
443         struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
444         struct auth_session_info *session_info =
445                 dcesrv_call_session_info(dce_call);
446         NTSTATUS nt_status;
447         DATA_BLOB new_password;
448
449         /* The confounder is in the last 16 bytes of the buffer */
450         DATA_BLOB confounder = data_blob_const(&pwbuf->data[516], 16);
451         DATA_BLOB pw_data = data_blob_const(pwbuf->data, 516);
452         DATA_BLOB session_key = data_blob(NULL, 0);
453         int rc;
454         bool encrypted;
455
456         nt_status = dcesrv_transport_session_key(dce_call, &session_key);
457         if (!NT_STATUS_IS_OK(nt_status)) {
458                 DEBUG(3,("samr: failed to get session key: %s "
459                          "=> NT_STATUS_WRONG_PASSWORD\n",
460                         nt_errstr(nt_status)));
461                 return NT_STATUS_WRONG_PASSWORD;
462         }
463
464         encrypted = dcerpc_is_transport_encrypted(session_info);
465         if (lpcfg_weak_crypto(lp_ctx) == SAMBA_WEAK_CRYPTO_DISALLOWED &&
466             !encrypted) {
467                 return NT_STATUS_ACCESS_DENIED;
468         }
469
470         GNUTLS_FIPS140_SET_LAX_MODE();
471         rc = samba_gnutls_arcfour_confounded_md5(&confounder,
472                                                  &session_key,
473                                                  &pw_data,
474                                                  SAMBA_GNUTLS_DECRYPT);
475         GNUTLS_FIPS140_SET_STRICT_MODE();
476         if (rc < 0) {
477                 nt_status = gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
478                 goto out;
479         }
480
481         if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
482                 DEBUG(3,("samr: failed to decode password buffer\n"));
483                 nt_status = NT_STATUS_WRONG_PASSWORD;
484                 goto out;
485         }
486
487         /* set the password - samdb needs to know both the domain and user DNs,
488            so the domain password policy can be used */
489         nt_status = samdb_set_password(sam_ctx,
490                                        mem_ctx,
491                                        account_dn,
492                                        domain_dn,
493                                        &new_password,
494                                        NULL,
495                                        DSDB_PASSWORD_RESET,
496                                        NULL,
497                                        NULL);
498         ZERO_ARRAY_LEN(new_password.data,
499                        new_password.length);
500
501 out:
502         return nt_status;
503 }
504
505 /*
506   set password via encrypted NT and LM hash buffers
507 */
508 NTSTATUS samr_set_password_buffers(struct dcesrv_call_state *dce_call,
509                                    struct ldb_context *sam_ctx,
510                                    struct ldb_dn *account_dn,
511                                    struct ldb_dn *domain_dn,
512                                    TALLOC_CTX *mem_ctx,
513                                    const uint8_t *lm_pwd_hash,
514                                    const uint8_t *nt_pwd_hash)
515 {
516         struct samr_Password *d_lm_pwd_hash = NULL, *d_nt_pwd_hash = NULL;
517         uint8_t random_session_key[16] = { 0, };
518         DATA_BLOB session_key = data_blob(NULL, 0);
519         DATA_BLOB in, out;
520         NTSTATUS nt_status = NT_STATUS_OK;
521         int rc;
522
523         nt_status = dcesrv_transport_session_key(dce_call, &session_key);
524         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_USER_SESSION_KEY)) {
525                 DEBUG(3,("samr: failed to get session key: %s "
526                          "=> use a random session key\n",
527                          nt_errstr(nt_status)));
528
529                 /*
530                  * Windows just uses a random key
531                  */
532                 generate_random_buffer(random_session_key,
533                                        sizeof(random_session_key));
534                 session_key = data_blob_const(random_session_key,
535                                               sizeof(random_session_key));
536                 nt_status = NT_STATUS_OK;
537         }
538         if (!NT_STATUS_IS_OK(nt_status)) {
539                 return nt_status;
540         }
541
542         if (nt_pwd_hash != NULL) {
543                 in = data_blob_const(nt_pwd_hash, 16);
544                 out = data_blob_talloc_zero(mem_ctx, 16);
545
546                 rc = sess_crypt_blob(&out, &in, &session_key, SAMBA_GNUTLS_DECRYPT);
547                 if (rc != 0) {
548                         return gnutls_error_to_ntstatus(rc,
549                                                         NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
550                 }
551
552                 d_nt_pwd_hash = (struct samr_Password *) out.data;
553         }
554
555         if ((d_lm_pwd_hash != NULL) || (d_nt_pwd_hash != NULL)) {
556                 nt_status = samdb_set_password(sam_ctx, mem_ctx, account_dn,
557                                                domain_dn, NULL,
558                                                d_nt_pwd_hash,
559                                                DSDB_PASSWORD_RESET,
560                                                NULL, NULL);
561         }
562
563         return nt_status;
564 }