s4:auth Add dependency from the operational module onto auth
[nivanova/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         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         if (!msg) {
430                 DEBUG(0,("auth_context_create: called with out messaging context\n"));
431                 return NT_STATUS_INTERNAL_ERROR;
432         }
433
434         ctx = talloc(mem_ctx, struct auth_context);
435         NT_STATUS_HAVE_NO_MEMORY(ctx);
436         ctx->challenge.set_by           = NULL;
437         ctx->challenge.may_be_modified  = false;
438         ctx->challenge.data             = data_blob(NULL, 0);
439         ctx->methods                    = NULL;
440         ctx->event_ctx                  = ev;
441         ctx->msg_ctx                    = msg;
442         ctx->lp_ctx                     = lp_ctx;
443
444         if (sam_ctx) {
445                 ctx->sam_ctx = sam_ctx;
446         } else {
447                 ctx->sam_ctx = samdb_connect(ctx, ctx->event_ctx, ctx->lp_ctx, system_session(ctx->lp_ctx));
448         }
449
450         for (i=0; methods[i] ; i++) {
451                 struct auth_method_context *method;
452
453                 method = talloc(ctx, struct auth_method_context);
454                 NT_STATUS_HAVE_NO_MEMORY(method);
455
456                 method->ops = auth_backend_byname(methods[i]);
457                 if (!method->ops) {
458                         DEBUG(1,("auth_context_create: failed to find method=%s\n",
459                                 methods[i]));
460                         return NT_STATUS_INTERNAL_ERROR;
461                 }
462                 method->auth_ctx        = ctx;
463                 method->depth           = i;
464                 DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
465         }
466
467         if (!ctx->methods) {
468                 return NT_STATUS_INTERNAL_ERROR;
469         }
470
471         ctx->check_password = auth_check_password;
472         ctx->get_challenge = auth_get_challenge;
473         ctx->set_challenge = auth_context_set_challenge;
474         ctx->challenge_may_be_modified = auth_challenge_may_be_modified;
475         ctx->get_server_info_principal = auth_get_server_info_principal;
476         ctx->generate_session_info = auth_generate_session_info;
477
478         *auth_ctx = ctx;
479
480         return NT_STATUS_OK;
481 }
482
483 static const char **auth_methods_from_lp(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
484 {
485         const char **auth_methods = NULL;
486         switch (lp_server_role(lp_ctx)) {
487         case ROLE_STANDALONE:
488                 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "standalone", NULL);
489                 break;
490         case ROLE_DOMAIN_MEMBER:
491                 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "member server", NULL);
492                 break;
493         case ROLE_DOMAIN_CONTROLLER:
494                 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "domain controller", NULL);
495                 break;
496         }
497         return auth_methods;
498 }
499
500 /***************************************************************************
501  Make a auth_info struct for the auth subsystem
502  - Uses default auth_methods, depending on server role and smb.conf settings
503 ***************************************************************************/
504 _PUBLIC_ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx,
505                              struct tevent_context *ev,
506                              struct messaging_context *msg,
507                              struct loadparm_context *lp_ctx,
508                              struct auth_context **auth_ctx)
509 {
510         NTSTATUS status;
511         const char **auth_methods;
512         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
513         if (!tmp_ctx) {
514                 return NT_STATUS_NO_MEMORY;
515         }
516
517         auth_methods = auth_methods_from_lp(tmp_ctx, lp_ctx);
518         if (!auth_methods) {
519                 return NT_STATUS_INVALID_PARAMETER;
520         }
521         status = auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, NULL, auth_ctx);
522         talloc_free(tmp_ctx);
523         return status;
524 }
525
526 /* Create an auth context from an open LDB.
527
528    This allows us not to re-open the LDB when we need to do a some authentication logic (such as tokenGroups)
529
530  */
531 NTSTATUS auth_context_create_from_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, struct auth_context **auth_ctx)
532 {
533         NTSTATUS status;
534         const char **auth_methods;
535         struct loadparm_context *lp_ctx = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"), struct loadparm_context);
536         struct tevent_context *ev = ldb_get_event_context(ldb);
537
538         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
539         if (!tmp_ctx) {
540                 return NT_STATUS_NO_MEMORY;
541         }
542
543         auth_methods = auth_methods_from_lp(tmp_ctx, lp_ctx);
544         if (!auth_methods) {
545                 return NT_STATUS_INVALID_PARAMETER;
546         }
547         status = auth_context_create_methods(mem_ctx, auth_methods, ev, NULL, lp_ctx, ldb, auth_ctx);
548         talloc_free(tmp_ctx);
549         return status;
550 }
551
552 /* the list of currently registered AUTH backends */
553 static struct auth_backend {
554         const struct auth_operations *ops;
555 } *backends = NULL;
556 static int num_backends;
557
558 /*
559   register a AUTH backend. 
560
561   The 'name' can be later used by other backends to find the operations
562   structure for this backend.
563 */
564 _PUBLIC_ NTSTATUS auth_register(const struct auth_operations *ops)
565 {
566         struct auth_operations *new_ops;
567         
568         if (auth_backend_byname(ops->name) != NULL) {
569                 /* its already registered! */
570                 DEBUG(0,("AUTH backend '%s' already registered\n", 
571                          ops->name));
572                 return NT_STATUS_OBJECT_NAME_COLLISION;
573         }
574
575         backends = talloc_realloc(talloc_autofree_context(), backends, 
576                                   struct auth_backend, num_backends+1);
577         NT_STATUS_HAVE_NO_MEMORY(backends);
578
579         new_ops = (struct auth_operations *)talloc_memdup(backends, ops, sizeof(*ops));
580         NT_STATUS_HAVE_NO_MEMORY(new_ops);
581         new_ops->name = talloc_strdup(new_ops, ops->name);
582         NT_STATUS_HAVE_NO_MEMORY(new_ops->name);
583
584         backends[num_backends].ops = new_ops;
585
586         num_backends++;
587
588         DEBUG(3,("AUTH backend '%s' registered\n", 
589                  ops->name));
590
591         return NT_STATUS_OK;
592 }
593
594 /*
595   return the operations structure for a named backend of the specified type
596 */
597 const struct auth_operations *auth_backend_byname(const char *name)
598 {
599         int i;
600
601         for (i=0;i<num_backends;i++) {
602                 if (strcmp(backends[i].ops->name, name) == 0) {
603                         return backends[i].ops;
604                 }
605         }
606
607         return NULL;
608 }
609
610 /*
611   return the AUTH interface version, and the size of some critical types
612   This can be used by backends to either detect compilation errors, or provide
613   multiple implementations for different smbd compilation options in one module
614 */
615 const struct auth_critical_sizes *auth_interface_version(void)
616 {
617         static const struct auth_critical_sizes critical_sizes = {
618                 AUTH_INTERFACE_VERSION,
619                 sizeof(struct auth_operations),
620                 sizeof(struct auth_method_context),
621                 sizeof(struct auth_context),
622                 sizeof(struct auth_usersupplied_info),
623                 sizeof(struct auth_serversupplied_info)
624         };
625
626         return &critical_sizes;
627 }
628
629 _PUBLIC_ NTSTATUS auth_init(void)
630 {
631         static bool initialized = false;
632         extern NTSTATUS auth_developer_init(void);
633         extern NTSTATUS auth_winbind_init(void);
634         extern NTSTATUS auth_anonymous_init(void);
635         extern NTSTATUS auth_unix_init(void);
636         extern NTSTATUS auth_sam_init(void);
637         extern NTSTATUS auth_server_init(void);
638
639         init_module_fn static_init[] = { STATIC_auth_MODULES };
640         
641         if (initialized) return NT_STATUS_OK;
642         initialized = true;
643         
644         run_init_functions(static_init);
645         
646         return NT_STATUS_OK;    
647 }