s4-auth rework session_info handling not to require an auth context
[sfrench/samba-autobuild/.git] / source4 / auth / ntlm / auth.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Password and authentication handling
4    Copyright (C) Andrew Bartlett         2001-2002
5    Copyright (C) Stefan Metzmacher       2005
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include <tevent.h>
23 #include "../lib/util/tevent_ntstatus.h"
24 #include "../lib/util/dlinklist.h"
25 #include "auth/auth.h"
26 #include "auth/ntlm/auth_proto.h"
27 #include "param/param.h"
28 #include "dsdb/samdb/samdb.h"
29
30
31 /***************************************************************************
32  Set a fixed challenge
33 ***************************************************************************/
34 _PUBLIC_ NTSTATUS auth_context_set_challenge(struct auth_context *auth_ctx, const uint8_t chal[8], const char *set_by) 
35 {
36         auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
37         NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
38
39         auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
40         NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
41
42         return NT_STATUS_OK;
43 }
44
45 /***************************************************************************
46  Set a fixed challenge
47 ***************************************************************************/
48 _PUBLIC_ bool auth_challenge_may_be_modified(struct auth_context *auth_ctx)
49 {
50         return auth_ctx->challenge.may_be_modified;
51 }
52
53 /****************************************************************************
54  Try to get a challenge out of the various authentication modules.
55  Returns a const char of length 8 bytes.
56 ****************************************************************************/
57 _PUBLIC_ NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, uint8_t chal[8])
58 {
59         NTSTATUS nt_status;
60         struct auth_method_context *method;
61
62         if (auth_ctx->challenge.data.length == 8) {
63                 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n", 
64                           auth_ctx->challenge.set_by));
65                 memcpy(chal, auth_ctx->challenge.data.data, 8);
66                 return NT_STATUS_OK;
67         }
68
69         for (method = auth_ctx->methods; method; method = method->next) {
70                 nt_status = method->ops->get_challenge(method, auth_ctx, chal);
71                 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
72                         continue;
73                 }
74
75                 NT_STATUS_NOT_OK_RETURN(nt_status);
76
77                 auth_ctx->challenge.data        = data_blob_talloc(auth_ctx, chal, 8);
78                 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
79                 auth_ctx->challenge.set_by      = method->ops->name;
80
81                 break;
82         }
83
84         if (!auth_ctx->challenge.set_by) {
85                 generate_random_buffer(chal, 8);
86
87                 auth_ctx->challenge.data                = data_blob_talloc(auth_ctx, chal, 8);
88                 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
89                 auth_ctx->challenge.set_by              = "random";
90
91                 auth_ctx->challenge.may_be_modified     = true;
92         }
93
94         DEBUG(10,("auth_get_challenge: challenge set by %s\n",
95                  auth_ctx->challenge.set_by));
96
97         return NT_STATUS_OK;
98 }
99
100 /****************************************************************************
101 Used in the gensec_gssapi and gensec_krb5 server-side code, where the
102 PAC isn't available, and for tokenGroups in the DSDB stack.
103
104  Supply either a principal or a DN
105 ****************************************************************************/
106 _PUBLIC_ NTSTATUS auth_get_server_info_principal(TALLOC_CTX *mem_ctx, 
107                                                  struct auth_context *auth_ctx,
108                                                  const char *principal,
109                                                  struct ldb_dn *user_dn,
110                                                  struct auth_serversupplied_info **server_info)
111 {
112         NTSTATUS nt_status;
113         struct auth_method_context *method;
114
115         for (method = auth_ctx->methods; method; method = method->next) {
116                 if (!method->ops->get_server_info_principal) {
117                         continue;
118                 }
119
120                 nt_status = method->ops->get_server_info_principal(mem_ctx, auth_ctx, principal, user_dn, server_info);
121                 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
122                         continue;
123                 }
124
125                 NT_STATUS_NOT_OK_RETURN(nt_status);
126
127                 break;
128         }
129
130         return NT_STATUS_OK;
131 }
132
133 /**
134  * Check a user's Plaintext, LM or NTLM password.
135  * (sync version)
136  *
137  * Check a user's password, as given in the user_info struct and return various
138  * interesting details in the server_info struct.
139  *
140  * The return value takes precedence over the contents of the server_info 
141  * struct.  When the return is other than NT_STATUS_OK the contents 
142  * of that structure is undefined.
143  *
144  * @param auth_ctx Supplies the challenges and some other data. 
145  *                  Must be created with auth_context_create(), and the challenges should be 
146  *                  filled in, either at creation or by calling the challenge geneation 
147  *                  function auth_get_challenge().  
148  *
149  * @param user_info Contains the user supplied components, including the passwords.
150  *
151  * @param mem_ctx The parent memory context for the server_info structure
152  *
153  * @param server_info If successful, contains information about the authentication, 
154  *                    including a SAM_ACCOUNT struct describing the user.
155  *
156  * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
157  *
158  **/
159
160 _PUBLIC_ NTSTATUS auth_check_password(struct auth_context *auth_ctx,
161                              TALLOC_CTX *mem_ctx,
162                              const struct auth_usersupplied_info *user_info, 
163                              struct auth_serversupplied_info **server_info)
164 {
165         struct tevent_req *subreq;
166         struct tevent_context *ev;
167         bool ok;
168         NTSTATUS status;
169
170         /*TODO: create a new event context here! */
171         ev = auth_ctx->event_ctx;
172
173         subreq = auth_check_password_send(mem_ctx,
174                                           ev,
175                                           auth_ctx,
176                                           user_info);
177         if (subreq == NULL) {
178                 return NT_STATUS_NO_MEMORY;
179         }
180
181         ok = tevent_req_poll(subreq, ev);
182         if (!ok) {
183                 return NT_STATUS_INTERNAL_ERROR;
184         }
185
186         status = auth_check_password_recv(subreq, mem_ctx, server_info);
187         TALLOC_FREE(subreq);
188
189         return status;
190 }
191
192 struct auth_check_password_state {
193         struct auth_context *auth_ctx;
194         const struct auth_usersupplied_info *user_info;
195         struct auth_serversupplied_info *server_info;
196         struct auth_method_context *method;
197 };
198
199 static void auth_check_password_async_trigger(struct tevent_context *ev,
200                                               struct tevent_immediate *im,
201                                               void *private_data);
202 /**
203  * Check a user's Plaintext, LM or NTLM password.
204  * async send hook
205  *
206  * Check a user's password, as given in the user_info struct and return various
207  * interesting details in the server_info struct.
208  *
209  * The return value takes precedence over the contents of the server_info 
210  * struct.  When the return is other than NT_STATUS_OK the contents 
211  * of that structure is undefined.
212  *
213  * @param mem_ctx The memory context the request should operate on
214  *
215  * @param ev The tevent context the request should operate on
216  *
217  * @param auth_ctx Supplies the challenges and some other data. 
218  *                  Must be created with make_auth_context(), and the challenges should be 
219  *                  filled in, either at creation or by calling the challenge geneation 
220  *                  function auth_get_challenge().  
221  *
222  * @param user_info Contains the user supplied components, including the passwords.
223  *
224  * @return The request handle or NULL on no memory error.
225  *
226  **/
227
228 _PUBLIC_ struct tevent_req *auth_check_password_send(TALLOC_CTX *mem_ctx,
229                                 struct tevent_context *ev,
230                                 struct auth_context *auth_ctx,
231                                 const struct auth_usersupplied_info *user_info)
232 {
233         struct tevent_req *req;
234         struct auth_check_password_state *state;
235         /* if all the modules say 'not for me' this is reasonable */
236         NTSTATUS nt_status;
237         uint8_t chal[8];
238         struct auth_usersupplied_info *user_info_tmp;
239         struct tevent_immediate *im;
240
241         DEBUG(3,("auth_check_password_send: "
242                  "Checking password for unmapped user [%s]\\[%s]@[%s]\n",
243                  user_info->client.domain_name, user_info->client.account_name,
244                  user_info->workstation_name));
245
246         req = tevent_req_create(mem_ctx, &state,
247                                 struct auth_check_password_state);
248         if (req == NULL) {
249                 return NULL;
250         }
251
252         state->auth_ctx         = auth_ctx;
253         state->user_info        = user_info;
254
255         if (!user_info->mapped_state) {
256                 nt_status = map_user_info(req, lpcfg_workgroup(auth_ctx->lp_ctx),
257                                           user_info, &user_info_tmp);
258                 if (tevent_req_nterror(req, nt_status)) {
259                         return tevent_req_post(req, ev);
260                 }
261                 user_info = user_info_tmp;
262                 state->user_info = user_info_tmp;
263         }
264
265         DEBUGADD(3,("auth_check_password_send: "
266                     "mapped user is: [%s]\\[%s]@[%s]\n",
267                     user_info->mapped.domain_name,
268                     user_info->mapped.account_name,
269                     user_info->workstation_name));
270
271         nt_status = auth_get_challenge(auth_ctx, chal);
272         if (tevent_req_nterror(req, nt_status)) {
273                 DEBUG(0,("auth_check_password_send: "
274                          "Invalid challenge (length %u) stored for "
275                          "this auth context set_by %s - cannot continue: %s\n",
276                         (unsigned)auth_ctx->challenge.data.length,
277                         auth_ctx->challenge.set_by,
278                         nt_errstr(nt_status)));
279                 return tevent_req_post(req, ev);
280         }
281
282         if (auth_ctx->challenge.set_by) {
283                 DEBUG(10,("auth_check_password_send: "
284                           "auth_context challenge created by %s\n",
285                           auth_ctx->challenge.set_by));
286         }
287
288         DEBUG(10, ("auth_check_password_send: challenge is: \n"));
289         dump_data(5, auth_ctx->challenge.data.data,
290                   auth_ctx->challenge.data.length);
291
292         im = tevent_create_immediate(state);
293         if (tevent_req_nomem(im, req)) {
294                 return tevent_req_post(req, ev);
295         }
296
297         tevent_schedule_immediate(im,
298                                   auth_ctx->event_ctx,
299                                   auth_check_password_async_trigger,
300                                   req);
301         return req;
302 }
303
304 static void auth_check_password_async_trigger(struct tevent_context *ev,
305                                               struct tevent_immediate *im,
306                                               void *private_data)
307 {
308         struct tevent_req *req =
309                 talloc_get_type_abort(private_data, struct tevent_req);
310         struct auth_check_password_state *state =
311                 tevent_req_data(req, struct auth_check_password_state);
312         NTSTATUS status;
313         struct auth_method_context *method;
314
315         status = NT_STATUS_OK;
316
317         for (method=state->auth_ctx->methods; method; method = method->next) {
318
319                 /* we fill in state->method here so debug messages in
320                    the callers know which method failed */
321                 state->method = method;
322
323                 /* check if the module wants to check the password */
324                 status = method->ops->want_check(method, req, state->user_info);
325                 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
326                         DEBUG(11,("auth_check_password_send: "
327                                   "%s had nothing to say\n",
328                                   method->ops->name));
329                         continue;
330                 }
331
332                 if (tevent_req_nterror(req, status)) {
333                         return;
334                 }
335
336                 status = method->ops->check_password(method,
337                                                      state,
338                                                      state->user_info,
339                                                      &state->server_info);
340                 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
341                         /* the backend has handled the request */
342                         break;
343                 }
344         }
345
346         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
347                 /* don't expose the NT_STATUS_NOT_IMPLEMENTED
348                    internals */
349                 status = NT_STATUS_NO_SUCH_USER;
350         }
351
352         if (tevent_req_nterror(req, status)) {
353                 return;
354         }
355
356         tevent_req_done(req);
357 }
358
359 /**
360  * Check a user's Plaintext, LM or NTLM password.
361  * async receive function
362  *
363  * The return value takes precedence over the contents of the server_info 
364  * struct.  When the return is other than NT_STATUS_OK the contents 
365  * of that structure is undefined.
366  *
367  *
368  * @param req The async request state
369  *
370  * @param mem_ctx The parent memory context for the server_info structure
371  *
372  * @param server_info If successful, contains information about the authentication, 
373  *                    including a SAM_ACCOUNT struct describing the user.
374  *
375  * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
376  *
377  **/
378
379 _PUBLIC_ NTSTATUS auth_check_password_recv(struct tevent_req *req,
380                                   TALLOC_CTX *mem_ctx,
381                                   struct auth_serversupplied_info **server_info)
382 {
383         struct auth_check_password_state *state =
384                 tevent_req_data(req, struct auth_check_password_state);
385         NTSTATUS status;
386
387         if (tevent_req_is_nterror(req, &status)) {
388                 DEBUG(2,("auth_check_password_recv: "
389                          "%s authentication for user [%s\\%s] "
390                          "FAILED with error %s\n",
391                          (state->method ? state->method->ops->name : "NO_METHOD"),
392                          state->user_info->mapped.domain_name,
393                          state->user_info->mapped.account_name,
394                          nt_errstr(status)));
395                 tevent_req_received(req);
396                 return status;
397         }
398
399         DEBUG(5,("auth_check_password_recv: "
400                  "%s authentication for user [%s\\%s] succeeded\n",
401                  state->method->ops->name,
402                  state->server_info->domain_name,
403                  state->server_info->account_name));
404
405         *server_info = talloc_move(mem_ctx, &state->server_info);
406
407         tevent_req_received(req);
408         return NT_STATUS_OK;
409 }
410
411 /* Wrapper because we don't want to expose all callers to needing to
412  * know that session_info is generated from the main ldb */
413 static NTSTATUS auth_generate_session_info_wrapper(TALLOC_CTX *mem_ctx,
414                                                    struct auth_context *auth_context,
415                                                    struct auth_serversupplied_info *server_info,
416                                                    uint32_t session_info_flags,
417                                                    struct auth_session_info **session_info)
418 {
419         return auth_generate_session_info(mem_ctx, auth_context->lp_ctx,
420                                           auth_context->sam_ctx, server_info,
421                                           session_info_flags, session_info);
422 }
423
424 /***************************************************************************
425  Make a auth_info struct for the auth subsystem
426  - Allow the caller to specify the methods to use, including optionally the SAM to use
427 ***************************************************************************/
428 _PUBLIC_ NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char **methods, 
429                                               struct tevent_context *ev,
430                                               struct messaging_context *msg,
431                                               struct loadparm_context *lp_ctx,
432                                               struct ldb_context *sam_ctx,
433                                               struct auth_context **auth_ctx)
434 {
435         int i;
436         struct auth_context *ctx;
437
438         auth_init();
439
440         if (!methods) {
441                 DEBUG(0,("auth_context_create: No auth method list!?\n"));
442                 return NT_STATUS_INTERNAL_ERROR;
443         }
444
445         if (!ev) {
446                 DEBUG(0,("auth_context_create: called with out event context\n"));
447                 return NT_STATUS_INTERNAL_ERROR;
448         }
449
450         ctx = talloc(mem_ctx, struct auth_context);
451         NT_STATUS_HAVE_NO_MEMORY(ctx);
452         ctx->challenge.set_by           = NULL;
453         ctx->challenge.may_be_modified  = false;
454         ctx->challenge.data             = data_blob(NULL, 0);
455         ctx->methods                    = NULL;
456         ctx->event_ctx                  = ev;
457         ctx->msg_ctx                    = msg;
458         ctx->lp_ctx                     = lp_ctx;
459
460         if (sam_ctx) {
461                 ctx->sam_ctx = sam_ctx;
462         } else {
463                 ctx->sam_ctx = samdb_connect(ctx, ctx->event_ctx, ctx->lp_ctx, system_session(ctx->lp_ctx), 0);
464         }
465
466         for (i=0; methods[i] ; i++) {
467                 struct auth_method_context *method;
468
469                 method = talloc(ctx, struct auth_method_context);
470                 NT_STATUS_HAVE_NO_MEMORY(method);
471
472                 method->ops = auth_backend_byname(methods[i]);
473                 if (!method->ops) {
474                         DEBUG(1,("auth_context_create: failed to find method=%s\n",
475                                 methods[i]));
476                         return NT_STATUS_INTERNAL_ERROR;
477                 }
478                 method->auth_ctx        = ctx;
479                 method->depth           = i;
480                 DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
481         }
482
483         if (!ctx->methods) {
484                 return NT_STATUS_INTERNAL_ERROR;
485         }
486
487         ctx->check_password = auth_check_password;
488         ctx->get_challenge = auth_get_challenge;
489         ctx->set_challenge = auth_context_set_challenge;
490         ctx->challenge_may_be_modified = auth_challenge_may_be_modified;
491         ctx->get_server_info_principal = auth_get_server_info_principal;
492         ctx->generate_session_info = auth_generate_session_info_wrapper;
493
494         *auth_ctx = ctx;
495
496         return NT_STATUS_OK;
497 }
498
499 static const char **auth_methods_from_lp(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
500 {
501         const char **auth_methods = NULL;
502         switch (lpcfg_server_role(lp_ctx)) {
503         case ROLE_STANDALONE:
504                 auth_methods = lpcfg_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "standalone", NULL);
505                 break;
506         case ROLE_DOMAIN_MEMBER:
507                 auth_methods = lpcfg_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "member server", NULL);
508                 break;
509         case ROLE_DOMAIN_CONTROLLER:
510                 auth_methods = lpcfg_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "domain controller", NULL);
511                 break;
512         }
513         return auth_methods;
514 }
515
516 /***************************************************************************
517  Make a auth_info struct for the auth subsystem
518  - Uses default auth_methods, depending on server role and smb.conf settings
519 ***************************************************************************/
520 _PUBLIC_ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx,
521                              struct tevent_context *ev,
522                              struct messaging_context *msg,
523                              struct loadparm_context *lp_ctx,
524                              struct auth_context **auth_ctx)
525 {
526         NTSTATUS status;
527         const char **auth_methods;
528         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
529         if (!tmp_ctx) {
530                 return NT_STATUS_NO_MEMORY;
531         }
532
533         auth_methods = auth_methods_from_lp(tmp_ctx, lp_ctx);
534         if (!auth_methods) {
535                 return NT_STATUS_INVALID_PARAMETER;
536         }
537         status = auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, NULL, auth_ctx);
538         talloc_free(tmp_ctx);
539         return status;
540 }
541
542 /* Create an auth context from an open LDB.
543
544    This allows us not to re-open the LDB when we need to do a some authentication logic (such as tokenGroups)
545
546  */
547 NTSTATUS auth_context_create_from_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, struct auth_context **auth_ctx)
548 {
549         NTSTATUS status;
550         const char **auth_methods;
551         struct loadparm_context *lp_ctx = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"), struct loadparm_context);
552         struct tevent_context *ev = ldb_get_event_context(ldb);
553
554         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
555         if (!tmp_ctx) {
556                 return NT_STATUS_NO_MEMORY;
557         }
558
559         auth_methods = auth_methods_from_lp(tmp_ctx, lp_ctx);
560         if (!auth_methods) {
561                 return NT_STATUS_INVALID_PARAMETER;
562         }
563         status = auth_context_create_methods(mem_ctx, auth_methods, ev, NULL, lp_ctx, ldb, auth_ctx);
564         talloc_free(tmp_ctx);
565         return status;
566 }
567
568 /* the list of currently registered AUTH backends */
569 static struct auth_backend {
570         const struct auth_operations *ops;
571 } *backends = NULL;
572 static int num_backends;
573
574 /*
575   register a AUTH backend. 
576
577   The 'name' can be later used by other backends to find the operations
578   structure for this backend.
579 */
580 _PUBLIC_ NTSTATUS auth_register(const struct auth_operations *ops)
581 {
582         struct auth_operations *new_ops;
583         
584         if (auth_backend_byname(ops->name) != NULL) {
585                 /* its already registered! */
586                 DEBUG(0,("AUTH backend '%s' already registered\n", 
587                          ops->name));
588                 return NT_STATUS_OBJECT_NAME_COLLISION;
589         }
590
591         backends = talloc_realloc(talloc_autofree_context(), backends, 
592                                   struct auth_backend, num_backends+1);
593         NT_STATUS_HAVE_NO_MEMORY(backends);
594
595         new_ops = (struct auth_operations *)talloc_memdup(backends, ops, sizeof(*ops));
596         NT_STATUS_HAVE_NO_MEMORY(new_ops);
597         new_ops->name = talloc_strdup(new_ops, ops->name);
598         NT_STATUS_HAVE_NO_MEMORY(new_ops->name);
599
600         backends[num_backends].ops = new_ops;
601
602         num_backends++;
603
604         DEBUG(3,("AUTH backend '%s' registered\n", 
605                  ops->name));
606
607         return NT_STATUS_OK;
608 }
609
610 /*
611   return the operations structure for a named backend of the specified type
612 */
613 const struct auth_operations *auth_backend_byname(const char *name)
614 {
615         int i;
616
617         for (i=0;i<num_backends;i++) {
618                 if (strcmp(backends[i].ops->name, name) == 0) {
619                         return backends[i].ops;
620                 }
621         }
622
623         return NULL;
624 }
625
626 /*
627   return the AUTH interface version, and the size of some critical types
628   This can be used by backends to either detect compilation errors, or provide
629   multiple implementations for different smbd compilation options in one module
630 */
631 const struct auth_critical_sizes *auth_interface_version(void)
632 {
633         static const struct auth_critical_sizes critical_sizes = {
634                 AUTH_INTERFACE_VERSION,
635                 sizeof(struct auth_operations),
636                 sizeof(struct auth_method_context),
637                 sizeof(struct auth_context),
638                 sizeof(struct auth_usersupplied_info),
639                 sizeof(struct auth_serversupplied_info)
640         };
641
642         return &critical_sizes;
643 }
644
645 _PUBLIC_ NTSTATUS auth_init(void)
646 {
647         static bool initialized = false;
648 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
649         STATIC_auth_MODULES_PROTO;
650         init_module_fn static_init[] = { STATIC_auth_MODULES };
651         
652         if (initialized) return NT_STATUS_OK;
653         initialized = true;
654         
655         run_init_functions(static_init);
656         
657         return NT_STATUS_OK;    
658 }