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