s4-auth: Add authsam_zero_bad_pwd_count to zero out badPwdCount and lockoutTime on...
[samba.git] / source4 / auth / ntlm / auth_sam.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Password and authentication handling
4    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2009
5    Copyright (C) Gerald Carter                             2003
6    Copyright (C) Stefan Metzmacher                         2005
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "system/time.h"
24 #include <ldb.h>
25 #include "libcli/ldap/ldap_ndr.h"
26 #include "libcli/security/security.h"
27 #include "auth/auth.h"
28 #include "../libcli/auth/ntlm_check.h"
29 #include "auth/ntlm/auth_proto.h"
30 #include "auth/auth_sam.h"
31 #include "dsdb/samdb/samdb.h"
32 #include "dsdb/common/util.h"
33 #include "param/param.h"
34 #include "librpc/gen_ndr/ndr_irpc_c.h"
35 #include "lib/messaging/irpc.h"
36
37 NTSTATUS auth_sam_init(void);
38
39 extern const char *user_attrs[];
40 extern const char *domain_ref_attrs[];
41
42 /****************************************************************************
43  Look for the specified user in the sam, return ldb result structures
44 ****************************************************************************/
45
46 static NTSTATUS authsam_search_account(TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx,
47                                        const char *account_name,
48                                        struct ldb_dn *domain_dn,
49                                        struct ldb_message **ret_msg)
50 {
51         int ret;
52
53         /* pull the user attributes */
54         ret = dsdb_search_one(sam_ctx, mem_ctx, ret_msg, domain_dn, LDB_SCOPE_SUBTREE,
55                               user_attrs,
56                               DSDB_SEARCH_SHOW_EXTENDED_DN,
57                               "(&(sAMAccountName=%s)(objectclass=user))",
58                               ldb_binary_encode_string(mem_ctx, account_name));
59         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
60                 DEBUG(3,("sam_search_user: Couldn't find user [%s] in samdb, under %s\n", 
61                          account_name, ldb_dn_get_linearized(domain_dn)));
62                 return NT_STATUS_NO_SUCH_USER;          
63         }
64         if (ret != LDB_SUCCESS) {
65                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
66         }
67         
68         return NT_STATUS_OK;
69 }
70
71 /****************************************************************************
72  Do a specific test for an smb password being correct, given a smb_password and
73  the lanman and NT responses.
74 ****************************************************************************/
75 static NTSTATUS authsam_password_ok(struct auth4_context *auth_context,
76                                     TALLOC_CTX *mem_ctx,
77                                     uint16_t acct_flags,
78                                     const struct samr_Password *lm_pwd, 
79                                     const struct samr_Password *nt_pwd,
80                                     const struct auth_usersupplied_info *user_info, 
81                                     DATA_BLOB *user_sess_key, 
82                                     DATA_BLOB *lm_sess_key)
83 {
84         NTSTATUS status;
85
86         switch (user_info->password_state) {
87         case AUTH_PASSWORD_PLAIN: 
88         {
89                 const struct auth_usersupplied_info *user_info_temp;    
90                 status = encrypt_user_info(mem_ctx, auth_context, 
91                                            AUTH_PASSWORD_HASH, 
92                                            user_info, &user_info_temp);
93                 if (!NT_STATUS_IS_OK(status)) {
94                         DEBUG(1, ("Failed to convert plaintext password to password HASH: %s\n", nt_errstr(status)));
95                         return status;
96                 }
97                 user_info = user_info_temp;
98
99                 /*fall through*/
100         }
101         case AUTH_PASSWORD_HASH:
102                 *lm_sess_key = data_blob(NULL, 0);
103                 *user_sess_key = data_blob(NULL, 0);
104                 status = hash_password_check(mem_ctx, 
105                                              lpcfg_lanman_auth(auth_context->lp_ctx),
106                                              user_info->password.hash.lanman,
107                                              user_info->password.hash.nt,
108                                              user_info->mapped.account_name,
109                                              lm_pwd, nt_pwd);
110                 NT_STATUS_NOT_OK_RETURN(status);
111                 break;
112                 
113         case AUTH_PASSWORD_RESPONSE:
114                 status = ntlm_password_check(mem_ctx, 
115                                              lpcfg_lanman_auth(auth_context->lp_ctx),
116                                                  lpcfg_ntlm_auth(auth_context->lp_ctx),
117                                              user_info->logon_parameters, 
118                                              &auth_context->challenge.data, 
119                                              &user_info->password.response.lanman, 
120                                              &user_info->password.response.nt,
121                                              user_info->mapped.account_name,
122                                              user_info->client.account_name, 
123                                              user_info->client.domain_name, 
124                                              lm_pwd, nt_pwd,
125                                              user_sess_key, lm_sess_key);
126                 NT_STATUS_NOT_OK_RETURN(status);
127                 break;
128         }
129
130         return NT_STATUS_OK;
131 }
132
133
134 /*
135   send a message to the drepl server telling it to initiate a
136   REPL_SECRET getncchanges extended op to fetch the users secrets
137  */
138 static void auth_sam_trigger_repl_secret(struct auth4_context *auth_context,
139                                          struct ldb_dn *user_dn)
140 {
141         struct dcerpc_binding_handle *irpc_handle;
142         struct drepl_trigger_repl_secret r;
143         struct tevent_req *req;
144         TALLOC_CTX *tmp_ctx;
145
146         tmp_ctx = talloc_new(auth_context);
147         if (tmp_ctx == NULL) {
148                 return;
149         }
150
151         irpc_handle = irpc_binding_handle_by_name(tmp_ctx, auth_context->msg_ctx,
152                                                   "dreplsrv",
153                                                   &ndr_table_irpc);
154         if (irpc_handle == NULL) {
155                 DEBUG(1,(__location__ ": Unable to get binding handle for dreplsrv\n"));
156                 TALLOC_FREE(tmp_ctx);
157                 return;
158         }
159
160         r.in.user_dn = ldb_dn_get_linearized(user_dn);
161
162         /*
163          * This seem to rely on the current IRPC implementation,
164          * which delivers the message in the _send function.
165          *
166          * TODO: we need a ONE_WAY IRPC handle and register
167          * a callback and wait for it to be triggered!
168          */
169         req = dcerpc_drepl_trigger_repl_secret_r_send(tmp_ctx,
170                                                       auth_context->event_ctx,
171                                                       irpc_handle,
172                                                       &r);
173
174         /* we aren't interested in a reply */
175         talloc_free(req);
176         TALLOC_FREE(tmp_ctx);
177 }
178
179
180 static NTSTATUS authsam_authenticate(struct auth4_context *auth_context, 
181                                      TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx, 
182                                      struct ldb_dn *domain_dn,
183                                      struct ldb_message *msg,
184                                      const struct auth_usersupplied_info *user_info, 
185                                      DATA_BLOB *user_sess_key, DATA_BLOB *lm_sess_key) 
186 {
187         struct samr_Password *lm_pwd, *nt_pwd;
188         NTSTATUS nt_status;
189         TALLOC_CTX *tmp_ctx;
190         uint16_t acct_flags = samdb_result_acct_flags(msg, NULL);
191
192         tmp_ctx = talloc_new(mem_ctx);
193         if (tmp_ctx == NULL) {
194                 return NT_STATUS_NO_MEMORY;
195         }
196
197         /* You can only do an interactive login to normal accounts */
198         if (user_info->flags & USER_INFO_INTERACTIVE_LOGON) {
199                 if (!(acct_flags & ACB_NORMAL)) {
200                         TALLOC_FREE(tmp_ctx);
201                         return NT_STATUS_NO_SUCH_USER;
202                 }
203         }
204
205         nt_status = samdb_result_passwords(tmp_ctx, auth_context->lp_ctx, msg, &lm_pwd, &nt_pwd);
206         if (!NT_STATUS_IS_OK(nt_status)) {
207                 TALLOC_FREE(tmp_ctx);
208                 return nt_status;
209         }
210
211         if (lm_pwd == NULL && nt_pwd == NULL) {
212                 bool am_rodc;
213                 if (samdb_rodc(auth_context->sam_ctx, &am_rodc) == LDB_SUCCESS && am_rodc) {
214                         /* we don't have passwords for this
215                          * account. We are an RODC, and this account
216                          * may be one for which we either are denied
217                          * REPL_SECRET replication or we haven't yet
218                          * done the replication. We return
219                          * NT_STATUS_NOT_IMPLEMENTED which tells the
220                          * auth code to try the next authentication
221                          * mechanism. We also send a message to our
222                          * drepl server to tell it to try and
223                          * replicate the secrets for this account.
224                          */
225                         auth_sam_trigger_repl_secret(auth_context, msg->dn);
226                         TALLOC_FREE(tmp_ctx);
227                         return NT_STATUS_NOT_IMPLEMENTED;
228                 }
229         }
230
231         nt_status = authsam_password_ok(auth_context, tmp_ctx,
232                                         acct_flags, lm_pwd, nt_pwd,
233                                         user_info, user_sess_key, lm_sess_key);
234         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
235                 NTSTATUS update_bad_pwd_count_status = authsam_update_bad_pwd_count(auth_context->sam_ctx, msg, domain_dn);
236                 if (!NT_STATUS_IS_OK(update_bad_pwd_count_status)) {
237                         /* bo! (what can we do here? */
238                 }
239         }
240
241         if (!NT_STATUS_IS_OK(nt_status)) {
242                 TALLOC_FREE(tmp_ctx);
243                 return nt_status;
244         }
245
246         nt_status = authsam_account_ok(tmp_ctx, auth_context->sam_ctx,
247                                        user_info->logon_parameters,
248                                        domain_dn,
249                                        msg,
250                                        user_info->workstation_name,
251                                        user_info->mapped.account_name,
252                                        false, false);
253
254         if (!NT_STATUS_IS_OK(nt_status)) {
255                 TALLOC_FREE(tmp_ctx);
256                 return nt_status;
257         }
258
259         nt_status = authsam_zero_bad_pwd_count(auth_context->sam_ctx, msg);
260         if (!NT_STATUS_IS_OK(nt_status)) {
261                 TALLOC_FREE(tmp_ctx);
262                 return nt_status;
263         }
264
265         if (user_sess_key && user_sess_key->data) {
266                 talloc_steal(mem_ctx, user_sess_key->data);
267         }
268         if (lm_sess_key && lm_sess_key->data) {
269                 talloc_steal(mem_ctx, lm_sess_key->data);
270         }
271
272         TALLOC_FREE(tmp_ctx);
273         return nt_status;
274 }
275
276
277
278 static NTSTATUS authsam_check_password_internals(struct auth_method_context *ctx,
279                                                  TALLOC_CTX *mem_ctx,
280                                                  const struct auth_usersupplied_info *user_info, 
281                                                  struct auth_user_info_dc **user_info_dc)
282 {
283         NTSTATUS nt_status;
284         const char *account_name = user_info->mapped.account_name;
285         struct ldb_message *msg;
286         struct ldb_dn *domain_dn;
287         DATA_BLOB user_sess_key, lm_sess_key;
288         TALLOC_CTX *tmp_ctx;
289
290         if (ctx->auth_ctx->sam_ctx == NULL) {
291                 DEBUG(0, ("No SAM available, cannot log in users\n"));
292                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
293         }
294
295         if (!account_name || !*account_name) {
296                 /* 'not for me' */
297                 return NT_STATUS_NOT_IMPLEMENTED;
298         }
299
300         tmp_ctx = talloc_new(mem_ctx);
301         if (!tmp_ctx) {
302                 return NT_STATUS_NO_MEMORY;
303         }
304
305         domain_dn = ldb_get_default_basedn(ctx->auth_ctx->sam_ctx);
306         if (domain_dn == NULL) {
307                 talloc_free(tmp_ctx);
308                 return NT_STATUS_NO_SUCH_DOMAIN;
309         }
310
311         nt_status = authsam_search_account(tmp_ctx, ctx->auth_ctx->sam_ctx, account_name, domain_dn, &msg);
312         if (!NT_STATUS_IS_OK(nt_status)) {
313                 talloc_free(tmp_ctx);
314                 return nt_status;
315         }
316
317         nt_status = authsam_authenticate(ctx->auth_ctx, tmp_ctx, ctx->auth_ctx->sam_ctx, domain_dn, msg, user_info,
318                                          &user_sess_key, &lm_sess_key);
319         if (!NT_STATUS_IS_OK(nt_status)) {
320                 talloc_free(tmp_ctx);
321                 return nt_status;
322         }
323
324         nt_status = authsam_make_user_info_dc(tmp_ctx, ctx->auth_ctx->sam_ctx, lpcfg_netbios_name(ctx->auth_ctx->lp_ctx),
325                                              lpcfg_sam_name(ctx->auth_ctx->lp_ctx),
326                                              domain_dn,
327                                              msg,
328                                              user_sess_key, lm_sess_key,
329                                              user_info_dc);
330         if (!NT_STATUS_IS_OK(nt_status)) {
331                 talloc_free(tmp_ctx);
332                 return nt_status;
333         }
334
335         talloc_steal(mem_ctx, *user_info_dc);
336         talloc_free(tmp_ctx);
337
338         return NT_STATUS_OK;
339 }
340
341 static NTSTATUS authsam_ignoredomain_want_check(struct auth_method_context *ctx,
342                                                 TALLOC_CTX *mem_ctx,
343                                                 const struct auth_usersupplied_info *user_info)
344 {
345         if (!user_info->mapped.account_name || !*user_info->mapped.account_name) {
346                 return NT_STATUS_NOT_IMPLEMENTED;
347         }
348
349         return NT_STATUS_OK;
350 }
351
352 /****************************************************************************
353 Check SAM security (above) but with a few extra checks.
354 ****************************************************************************/
355 static NTSTATUS authsam_want_check(struct auth_method_context *ctx,
356                                    TALLOC_CTX *mem_ctx,
357                                    const struct auth_usersupplied_info *user_info)
358 {
359         bool is_local_name, is_my_domain;
360
361         if (!user_info->mapped.account_name || !*user_info->mapped.account_name) {
362                 return NT_STATUS_NOT_IMPLEMENTED;
363         }
364
365         is_local_name = lpcfg_is_myname(ctx->auth_ctx->lp_ctx,
366                                   user_info->mapped.domain_name);
367         is_my_domain  = lpcfg_is_mydomain(ctx->auth_ctx->lp_ctx,
368                                        user_info->mapped.domain_name); 
369
370         /* check whether or not we service this domain/workgroup name */
371         switch (lpcfg_server_role(ctx->auth_ctx->lp_ctx)) {
372                 case ROLE_STANDALONE:
373                         return NT_STATUS_OK;
374
375                 case ROLE_DOMAIN_MEMBER:
376                         if (!is_local_name) {
377                                 DEBUG(6,("authsam_check_password: %s is not one of my local names (DOMAIN_MEMBER)\n",
378                                         user_info->mapped.domain_name));
379                                 return NT_STATUS_NOT_IMPLEMENTED;
380                         }
381                         return NT_STATUS_OK;
382
383                 case ROLE_ACTIVE_DIRECTORY_DC:
384                         if (!is_local_name && !is_my_domain) {
385                                 DEBUG(6,("authsam_check_password: %s is not one of my local names or domain name (DC)\n",
386                                         user_info->mapped.domain_name));
387                                 return NT_STATUS_NOT_IMPLEMENTED;
388                         }
389                         return NT_STATUS_OK;
390         }
391
392         DEBUG(6,("authsam_check_password: lpcfg_server_role() has an undefined value\n"));
393         return NT_STATUS_NOT_IMPLEMENTED;
394 }
395
396                                    
397 /* Wrapper for the auth subsystem pointer */
398 static NTSTATUS authsam_get_user_info_dc_principal_wrapper(TALLOC_CTX *mem_ctx,
399                                                           struct auth4_context *auth_context,
400                                                           const char *principal,
401                                                           struct ldb_dn *user_dn,
402                                                           struct auth_user_info_dc **user_info_dc)
403 {
404         return authsam_get_user_info_dc_principal(mem_ctx, auth_context->lp_ctx, auth_context->sam_ctx,
405                                                  principal, user_dn, user_info_dc);
406 }
407 static const struct auth_operations sam_ignoredomain_ops = {
408         .name                      = "sam_ignoredomain",
409         .want_check                = authsam_ignoredomain_want_check,
410         .check_password            = authsam_check_password_internals,
411         .get_user_info_dc_principal = authsam_get_user_info_dc_principal_wrapper
412 };
413
414 static const struct auth_operations sam_ops = {
415         .name                      = "sam",
416         .want_check                = authsam_want_check,
417         .check_password            = authsam_check_password_internals,
418         .get_user_info_dc_principal = authsam_get_user_info_dc_principal_wrapper
419 };
420
421 _PUBLIC_ NTSTATUS auth4_sam_init(void);
422 _PUBLIC_ NTSTATUS auth4_sam_init(void)
423 {
424         NTSTATUS ret;
425
426         ret = auth_register(&sam_ops);
427         if (!NT_STATUS_IS_OK(ret)) {
428                 DEBUG(0,("Failed to register 'sam' auth backend!\n"));
429                 return ret;
430         }
431
432         ret = auth_register(&sam_ignoredomain_ops);
433         if (!NT_STATUS_IS_OK(ret)) {
434                 DEBUG(0,("Failed to register 'sam_ignoredomain' auth backend!\n"));
435                 return ret;
436         }
437
438         return ret;
439 }