s4:auth Push check for messaging context into winbind backend
[amitay/samba.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         struct auth_method_context *method;
238         uint8_t chal[8];
239         struct auth_usersupplied_info *user_info_tmp;
240         struct tevent_immediate *im;
241
242         DEBUG(3,("auth_check_password_send: "
243                  "Checking password for unmapped user [%s]\\[%s]@[%s]\n",
244                  user_info->client.domain_name, user_info->client.account_name,
245                  user_info->workstation_name));
246
247         req = tevent_req_create(mem_ctx, &state,
248                                 struct auth_check_password_state);
249         if (req == NULL) {
250                 return NULL;
251         }
252
253         state->auth_ctx         = auth_ctx;
254         state->user_info        = user_info;
255         state->method           = NULL;
256
257         if (!user_info->mapped_state) {
258                 nt_status = map_user_info(req, lp_workgroup(auth_ctx->lp_ctx),
259                                           user_info, &user_info_tmp);
260                 if (tevent_req_nterror(req, nt_status)) {
261                         return tevent_req_post(req, ev);
262                 }
263                 user_info = user_info_tmp;
264                 state->user_info = user_info_tmp;
265         }
266
267         DEBUGADD(3,("auth_check_password_send: "
268                     "mapped user is: [%s]\\[%s]@[%s]\n",
269                     user_info->mapped.domain_name,
270                     user_info->mapped.account_name,
271                     user_info->workstation_name));
272
273         nt_status = auth_get_challenge(auth_ctx, chal);
274         if (tevent_req_nterror(req, nt_status)) {
275                 DEBUG(0,("auth_check_password_send: "
276                          "Invalid challenge (length %u) stored for "
277                          "this auth context set_by %s - cannot continue: %s\n",
278                         (unsigned)auth_ctx->challenge.data.length,
279                         auth_ctx->challenge.set_by,
280                         nt_errstr(nt_status)));
281                 return tevent_req_post(req, ev);
282         }
283
284         if (auth_ctx->challenge.set_by) {
285                 DEBUG(10,("auth_check_password_send: "
286                           "auth_context challenge created by %s\n",
287                           auth_ctx->challenge.set_by));
288         }
289
290         DEBUG(10, ("auth_check_password_send: challenge is: \n"));
291         dump_data(5, auth_ctx->challenge.data.data,
292                   auth_ctx->challenge.data.length);
293
294         im = tevent_create_immediate(state);
295         if (tevent_req_nomem(im, req)) {
296                 return tevent_req_post(req, ev);
297         }
298
299         for (method = auth_ctx->methods; method; method = method->next) {
300                 NTSTATUS result;
301
302                 /* check if the module wants to chek the password */
303                 result = method->ops->want_check(method, req, user_info);
304                 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
305                         DEBUG(11,("auth_check_password_send: "
306                                   "%s had nothing to say\n",
307                                   method->ops->name));
308                         continue;
309                 }
310
311                 state->method = method;
312
313                 if (tevent_req_nterror(req, result)) {
314                         return tevent_req_post(req, ev);
315                 }
316
317                 tevent_schedule_immediate(im,
318                                           auth_ctx->event_ctx,
319                                           auth_check_password_async_trigger,
320                                           req);
321
322                 return req;
323         }
324
325         /* If all the modules say 'not for me', then this is reasonable */
326         tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
327         return tevent_req_post(req, ev);
328 }
329
330 static void auth_check_password_async_trigger(struct tevent_context *ev,
331                                               struct tevent_immediate *im,
332                                               void *private_data)
333 {
334         struct tevent_req *req =
335                 talloc_get_type_abort(private_data, struct tevent_req);
336         struct auth_check_password_state *state =
337                 tevent_req_data(req, struct auth_check_password_state);
338         NTSTATUS status;
339
340         status = state->method->ops->check_password(state->method,
341                                                     state,
342                                                     state->user_info,
343                                                     &state->server_info);
344         if (tevent_req_nterror(req, status)) {
345                 return;
346         }
347
348         tevent_req_done(req);
349 }
350
351 /**
352  * Check a user's Plaintext, LM or NTLM password.
353  * async receive function
354  *
355  * The return value takes precedence over the contents of the server_info 
356  * struct.  When the return is other than NT_STATUS_OK the contents 
357  * of that structure is undefined.
358  *
359  *
360  * @param req The async request state
361  *
362  * @param mem_ctx The parent memory context for the server_info structure
363  *
364  * @param server_info If successful, contains information about the authentication, 
365  *                    including a SAM_ACCOUNT struct describing the user.
366  *
367  * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
368  *
369  **/
370
371 _PUBLIC_ NTSTATUS auth_check_password_recv(struct tevent_req *req,
372                                   TALLOC_CTX *mem_ctx,
373                                   struct auth_serversupplied_info **server_info)
374 {
375         struct auth_check_password_state *state =
376                 tevent_req_data(req, struct auth_check_password_state);
377         NTSTATUS status;
378
379         if (tevent_req_is_nterror(req, &status)) {
380                 DEBUG(2,("auth_check_password_recv: "
381                          "%s authentication for user [%s\\%s]"
382                          "FAILED with error %s\n",
383                          (state->method ? state->method->ops->name : "NO_METHOD"),
384                          state->user_info->mapped.domain_name,
385                          state->user_info->mapped.account_name,
386                          nt_errstr(status)));
387                 tevent_req_received(req);
388                 return status;
389         }
390
391         DEBUG(5,("auth_check_password_recv: "
392                  "%s authentication for user [%s\\%s] succeeded\n",
393                  state->method->ops->name,
394                  state->server_info->domain_name,
395                  state->server_info->account_name));
396
397         *server_info = talloc_move(mem_ctx, &state->server_info);
398
399         tevent_req_received(req);
400         return NT_STATUS_OK;
401 }
402
403 /***************************************************************************
404  Make a auth_info struct for the auth subsystem
405  - Allow the caller to specify the methods to use, including optionally the SAM to use
406 ***************************************************************************/
407 _PUBLIC_ NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char **methods, 
408                                               struct tevent_context *ev,
409                                               struct messaging_context *msg,
410                                               struct loadparm_context *lp_ctx,
411                                               struct ldb_context *sam_ctx,
412                                               struct auth_context **auth_ctx)
413 {
414         int i;
415         struct auth_context *ctx;
416
417         auth_init();
418
419         if (!methods) {
420                 DEBUG(0,("auth_context_create: No auth method list!?\n"));
421                 return NT_STATUS_INTERNAL_ERROR;
422         }
423
424         if (!ev) {
425                 DEBUG(0,("auth_context_create: called with out event context\n"));
426                 return NT_STATUS_INTERNAL_ERROR;
427         }
428
429         ctx = talloc(mem_ctx, struct auth_context);
430         NT_STATUS_HAVE_NO_MEMORY(ctx);
431         ctx->challenge.set_by           = NULL;
432         ctx->challenge.may_be_modified  = false;
433         ctx->challenge.data             = data_blob(NULL, 0);
434         ctx->methods                    = NULL;
435         ctx->event_ctx                  = ev;
436         ctx->msg_ctx                    = msg;
437         ctx->lp_ctx                     = lp_ctx;
438
439         if (sam_ctx) {
440                 ctx->sam_ctx = sam_ctx;
441         } else {
442                 ctx->sam_ctx = samdb_connect(ctx, ctx->event_ctx, ctx->lp_ctx, system_session(ctx->lp_ctx));
443         }
444
445         for (i=0; methods[i] ; i++) {
446                 struct auth_method_context *method;
447
448                 method = talloc(ctx, struct auth_method_context);
449                 NT_STATUS_HAVE_NO_MEMORY(method);
450
451                 method->ops = auth_backend_byname(methods[i]);
452                 if (!method->ops) {
453                         DEBUG(1,("auth_context_create: failed to find method=%s\n",
454                                 methods[i]));
455                         return NT_STATUS_INTERNAL_ERROR;
456                 }
457                 method->auth_ctx        = ctx;
458                 method->depth           = i;
459                 DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
460         }
461
462         if (!ctx->methods) {
463                 return NT_STATUS_INTERNAL_ERROR;
464         }
465
466         ctx->check_password = auth_check_password;
467         ctx->get_challenge = auth_get_challenge;
468         ctx->set_challenge = auth_context_set_challenge;
469         ctx->challenge_may_be_modified = auth_challenge_may_be_modified;
470         ctx->get_server_info_principal = auth_get_server_info_principal;
471         ctx->generate_session_info = auth_generate_session_info;
472
473         *auth_ctx = ctx;
474
475         return NT_STATUS_OK;
476 }
477
478 static const char **auth_methods_from_lp(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
479 {
480         const char **auth_methods = NULL;
481         switch (lp_server_role(lp_ctx)) {
482         case ROLE_STANDALONE:
483                 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "standalone", NULL);
484                 break;
485         case ROLE_DOMAIN_MEMBER:
486                 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "member server", NULL);
487                 break;
488         case ROLE_DOMAIN_CONTROLLER:
489                 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "domain controller", NULL);
490                 break;
491         }
492         return auth_methods;
493 }
494
495 /***************************************************************************
496  Make a auth_info struct for the auth subsystem
497  - Uses default auth_methods, depending on server role and smb.conf settings
498 ***************************************************************************/
499 _PUBLIC_ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx,
500                              struct tevent_context *ev,
501                              struct messaging_context *msg,
502                              struct loadparm_context *lp_ctx,
503                              struct auth_context **auth_ctx)
504 {
505         NTSTATUS status;
506         const char **auth_methods;
507         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
508         if (!tmp_ctx) {
509                 return NT_STATUS_NO_MEMORY;
510         }
511
512         auth_methods = auth_methods_from_lp(tmp_ctx, lp_ctx);
513         if (!auth_methods) {
514                 return NT_STATUS_INVALID_PARAMETER;
515         }
516         status = auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, NULL, auth_ctx);
517         talloc_free(tmp_ctx);
518         return status;
519 }
520
521 /* Create an auth context from an open LDB.
522
523    This allows us not to re-open the LDB when we need to do a some authentication logic (such as tokenGroups)
524
525  */
526 NTSTATUS auth_context_create_from_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, struct auth_context **auth_ctx)
527 {
528         NTSTATUS status;
529         const char **auth_methods;
530         struct loadparm_context *lp_ctx = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"), struct loadparm_context);
531         struct tevent_context *ev = ldb_get_event_context(ldb);
532
533         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
534         if (!tmp_ctx) {
535                 return NT_STATUS_NO_MEMORY;
536         }
537
538         auth_methods = auth_methods_from_lp(tmp_ctx, lp_ctx);
539         if (!auth_methods) {
540                 return NT_STATUS_INVALID_PARAMETER;
541         }
542         status = auth_context_create_methods(mem_ctx, auth_methods, ev, NULL, lp_ctx, ldb, auth_ctx);
543         talloc_free(tmp_ctx);
544         return status;
545 }
546
547 /* the list of currently registered AUTH backends */
548 static struct auth_backend {
549         const struct auth_operations *ops;
550 } *backends = NULL;
551 static int num_backends;
552
553 /*
554   register a AUTH backend. 
555
556   The 'name' can be later used by other backends to find the operations
557   structure for this backend.
558 */
559 _PUBLIC_ NTSTATUS auth_register(const struct auth_operations *ops)
560 {
561         struct auth_operations *new_ops;
562         
563         if (auth_backend_byname(ops->name) != NULL) {
564                 /* its already registered! */
565                 DEBUG(0,("AUTH backend '%s' already registered\n", 
566                          ops->name));
567                 return NT_STATUS_OBJECT_NAME_COLLISION;
568         }
569
570         backends = talloc_realloc(talloc_autofree_context(), backends, 
571                                   struct auth_backend, num_backends+1);
572         NT_STATUS_HAVE_NO_MEMORY(backends);
573
574         new_ops = (struct auth_operations *)talloc_memdup(backends, ops, sizeof(*ops));
575         NT_STATUS_HAVE_NO_MEMORY(new_ops);
576         new_ops->name = talloc_strdup(new_ops, ops->name);
577         NT_STATUS_HAVE_NO_MEMORY(new_ops->name);
578
579         backends[num_backends].ops = new_ops;
580
581         num_backends++;
582
583         DEBUG(3,("AUTH backend '%s' registered\n", 
584                  ops->name));
585
586         return NT_STATUS_OK;
587 }
588
589 /*
590   return the operations structure for a named backend of the specified type
591 */
592 const struct auth_operations *auth_backend_byname(const char *name)
593 {
594         int i;
595
596         for (i=0;i<num_backends;i++) {
597                 if (strcmp(backends[i].ops->name, name) == 0) {
598                         return backends[i].ops;
599                 }
600         }
601
602         return NULL;
603 }
604
605 /*
606   return the AUTH interface version, and the size of some critical types
607   This can be used by backends to either detect compilation errors, or provide
608   multiple implementations for different smbd compilation options in one module
609 */
610 const struct auth_critical_sizes *auth_interface_version(void)
611 {
612         static const struct auth_critical_sizes critical_sizes = {
613                 AUTH_INTERFACE_VERSION,
614                 sizeof(struct auth_operations),
615                 sizeof(struct auth_method_context),
616                 sizeof(struct auth_context),
617                 sizeof(struct auth_usersupplied_info),
618                 sizeof(struct auth_serversupplied_info)
619         };
620
621         return &critical_sizes;
622 }
623
624 _PUBLIC_ NTSTATUS auth_init(void)
625 {
626         static bool initialized = false;
627         extern NTSTATUS auth_developer_init(void);
628         extern NTSTATUS auth_winbind_init(void);
629         extern NTSTATUS auth_anonymous_init(void);
630         extern NTSTATUS auth_unix_init(void);
631         extern NTSTATUS auth_sam_init(void);
632         extern NTSTATUS auth_server_init(void);
633
634         init_module_fn static_init[] = { STATIC_auth_MODULES };
635         
636         if (initialized) return NT_STATUS_OK;
637         initialized = true;
638         
639         run_init_functions(static_init);
640         
641         return NT_STATUS_OK;    
642 }