s4-auth: Rework memory handling to use a tmp_ctx
[obnox/samba/samba-obnox.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         if (user_sess_key && user_sess_key->data) {
260                 talloc_steal(mem_ctx, user_sess_key->data);
261         }
262         if (lm_sess_key && lm_sess_key->data) {
263                 talloc_steal(mem_ctx, lm_sess_key->data);
264         }
265
266         TALLOC_FREE(tmp_ctx);
267         return nt_status;
268 }
269
270
271
272 static NTSTATUS authsam_check_password_internals(struct auth_method_context *ctx,
273                                                  TALLOC_CTX *mem_ctx,
274                                                  const struct auth_usersupplied_info *user_info, 
275                                                  struct auth_user_info_dc **user_info_dc)
276 {
277         NTSTATUS nt_status;
278         const char *account_name = user_info->mapped.account_name;
279         struct ldb_message *msg;
280         struct ldb_dn *domain_dn;
281         DATA_BLOB user_sess_key, lm_sess_key;
282         TALLOC_CTX *tmp_ctx;
283
284         if (ctx->auth_ctx->sam_ctx == NULL) {
285                 DEBUG(0, ("No SAM available, cannot log in users\n"));
286                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
287         }
288
289         if (!account_name || !*account_name) {
290                 /* 'not for me' */
291                 return NT_STATUS_NOT_IMPLEMENTED;
292         }
293
294         tmp_ctx = talloc_new(mem_ctx);
295         if (!tmp_ctx) {
296                 return NT_STATUS_NO_MEMORY;
297         }
298
299         domain_dn = ldb_get_default_basedn(ctx->auth_ctx->sam_ctx);
300         if (domain_dn == NULL) {
301                 talloc_free(tmp_ctx);
302                 return NT_STATUS_NO_SUCH_DOMAIN;
303         }
304
305         nt_status = authsam_search_account(tmp_ctx, ctx->auth_ctx->sam_ctx, account_name, domain_dn, &msg);
306         if (!NT_STATUS_IS_OK(nt_status)) {
307                 talloc_free(tmp_ctx);
308                 return nt_status;
309         }
310
311         nt_status = authsam_authenticate(ctx->auth_ctx, tmp_ctx, ctx->auth_ctx->sam_ctx, domain_dn, msg, user_info,
312                                          &user_sess_key, &lm_sess_key);
313         if (!NT_STATUS_IS_OK(nt_status)) {
314                 talloc_free(tmp_ctx);
315                 return nt_status;
316         }
317
318         nt_status = authsam_make_user_info_dc(tmp_ctx, ctx->auth_ctx->sam_ctx, lpcfg_netbios_name(ctx->auth_ctx->lp_ctx),
319                                              lpcfg_sam_name(ctx->auth_ctx->lp_ctx),
320                                              domain_dn,
321                                              msg,
322                                              user_sess_key, lm_sess_key,
323                                              user_info_dc);
324         if (!NT_STATUS_IS_OK(nt_status)) {
325                 talloc_free(tmp_ctx);
326                 return nt_status;
327         }
328
329         talloc_steal(mem_ctx, *user_info_dc);
330         talloc_free(tmp_ctx);
331
332         return NT_STATUS_OK;
333 }
334
335 static NTSTATUS authsam_ignoredomain_want_check(struct auth_method_context *ctx,
336                                                 TALLOC_CTX *mem_ctx,
337                                                 const struct auth_usersupplied_info *user_info)
338 {
339         if (!user_info->mapped.account_name || !*user_info->mapped.account_name) {
340                 return NT_STATUS_NOT_IMPLEMENTED;
341         }
342
343         return NT_STATUS_OK;
344 }
345
346 /****************************************************************************
347 Check SAM security (above) but with a few extra checks.
348 ****************************************************************************/
349 static NTSTATUS authsam_want_check(struct auth_method_context *ctx,
350                                    TALLOC_CTX *mem_ctx,
351                                    const struct auth_usersupplied_info *user_info)
352 {
353         bool is_local_name, is_my_domain;
354
355         if (!user_info->mapped.account_name || !*user_info->mapped.account_name) {
356                 return NT_STATUS_NOT_IMPLEMENTED;
357         }
358
359         is_local_name = lpcfg_is_myname(ctx->auth_ctx->lp_ctx,
360                                   user_info->mapped.domain_name);
361         is_my_domain  = lpcfg_is_mydomain(ctx->auth_ctx->lp_ctx,
362                                        user_info->mapped.domain_name); 
363
364         /* check whether or not we service this domain/workgroup name */
365         switch (lpcfg_server_role(ctx->auth_ctx->lp_ctx)) {
366                 case ROLE_STANDALONE:
367                         return NT_STATUS_OK;
368
369                 case ROLE_DOMAIN_MEMBER:
370                         if (!is_local_name) {
371                                 DEBUG(6,("authsam_check_password: %s is not one of my local names (DOMAIN_MEMBER)\n",
372                                         user_info->mapped.domain_name));
373                                 return NT_STATUS_NOT_IMPLEMENTED;
374                         }
375                         return NT_STATUS_OK;
376
377                 case ROLE_ACTIVE_DIRECTORY_DC:
378                         if (!is_local_name && !is_my_domain) {
379                                 DEBUG(6,("authsam_check_password: %s is not one of my local names or domain name (DC)\n",
380                                         user_info->mapped.domain_name));
381                                 return NT_STATUS_NOT_IMPLEMENTED;
382                         }
383                         return NT_STATUS_OK;
384         }
385
386         DEBUG(6,("authsam_check_password: lpcfg_server_role() has an undefined value\n"));
387         return NT_STATUS_NOT_IMPLEMENTED;
388 }
389
390                                    
391 /* Wrapper for the auth subsystem pointer */
392 static NTSTATUS authsam_get_user_info_dc_principal_wrapper(TALLOC_CTX *mem_ctx,
393                                                           struct auth4_context *auth_context,
394                                                           const char *principal,
395                                                           struct ldb_dn *user_dn,
396                                                           struct auth_user_info_dc **user_info_dc)
397 {
398         return authsam_get_user_info_dc_principal(mem_ctx, auth_context->lp_ctx, auth_context->sam_ctx,
399                                                  principal, user_dn, user_info_dc);
400 }
401 static const struct auth_operations sam_ignoredomain_ops = {
402         .name                      = "sam_ignoredomain",
403         .want_check                = authsam_ignoredomain_want_check,
404         .check_password            = authsam_check_password_internals,
405         .get_user_info_dc_principal = authsam_get_user_info_dc_principal_wrapper
406 };
407
408 static const struct auth_operations sam_ops = {
409         .name                      = "sam",
410         .want_check                = authsam_want_check,
411         .check_password            = authsam_check_password_internals,
412         .get_user_info_dc_principal = authsam_get_user_info_dc_principal_wrapper
413 };
414
415 _PUBLIC_ NTSTATUS auth4_sam_init(void);
416 _PUBLIC_ NTSTATUS auth4_sam_init(void)
417 {
418         NTSTATUS ret;
419
420         ret = auth_register(&sam_ops);
421         if (!NT_STATUS_IS_OK(ret)) {
422                 DEBUG(0,("Failed to register 'sam' auth backend!\n"));
423                 return ret;
424         }
425
426         ret = auth_register(&sam_ignoredomain_ops);
427         if (!NT_STATUS_IS_OK(ret)) {
428                 DEBUG(0,("Failed to register 'sam_ignoredomain' auth backend!\n"));
429                 return ret;
430         }
431
432         return ret;
433 }