auth4: add auth_context_create_for_netlogon()
[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 #include "libcli/wbclient/wbclient.h"
30 #include "lib/util/samba_modules.h"
31 #include "auth/credentials/credentials.h"
32 #include "system/kerberos.h"
33 #include "auth/kerberos/kerberos.h"
34 #include "auth/kerberos/kerberos_util.h"
35 #include "libds/common/roles.h"
36
37 static NTSTATUS auth_generate_session_info_wrapper(struct auth4_context *auth_context,
38                                                    TALLOC_CTX *mem_ctx,
39                                                   void *server_returned_info,
40                                                    const char *original_user_name,
41                                                    uint32_t session_info_flags,
42                                                    struct auth_session_info **session_info);
43
44 /***************************************************************************
45  Set a fixed challenge
46 ***************************************************************************/
47 _PUBLIC_ NTSTATUS auth_context_set_challenge(struct auth4_context *auth_ctx, const uint8_t chal[8], const char *set_by) 
48 {
49         auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
50         NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
51
52         auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
53         NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
54
55         return NT_STATUS_OK;
56 }
57
58 /****************************************************************************
59  Try to get a challenge out of the various authentication modules.
60  Returns a const char of length 8 bytes.
61 ****************************************************************************/
62 _PUBLIC_ NTSTATUS auth_get_challenge(struct auth4_context *auth_ctx, uint8_t chal[8])
63 {
64
65         if (auth_ctx->challenge.data.length == 8) {
66                 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n", 
67                           auth_ctx->challenge.set_by));
68                 memcpy(chal, auth_ctx->challenge.data.data, 8);
69                 return NT_STATUS_OK;
70         }
71
72         if (!auth_ctx->challenge.set_by) {
73                 generate_random_buffer(chal, 8);
74
75                 auth_ctx->challenge.data                = data_blob_talloc(auth_ctx, chal, 8);
76                 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
77                 auth_ctx->challenge.set_by              = "random";
78         }
79
80         DEBUG(10,("auth_get_challenge: challenge set by %s\n",
81                  auth_ctx->challenge.set_by));
82
83         return NT_STATUS_OK;
84 }
85
86 /****************************************************************************
87 Used in the gensec_gssapi and gensec_krb5 server-side code, where the
88 PAC isn't available, and for tokenGroups in the DSDB stack.
89
90  Supply either a principal or a DN
91 ****************************************************************************/
92 static NTSTATUS auth_generate_session_info_principal(struct auth4_context *auth_ctx,
93                                                   TALLOC_CTX *mem_ctx,
94                                                   const char *principal,
95                                                   struct ldb_dn *user_dn,
96                                                   uint32_t session_info_flags,
97                                                   struct auth_session_info **session_info)
98 {
99         NTSTATUS nt_status;
100         struct auth_method_context *method;
101         struct auth_user_info_dc *user_info_dc;
102
103         for (method = auth_ctx->methods; method; method = method->next) {
104                 if (!method->ops->get_user_info_dc_principal) {
105                         continue;
106                 }
107
108                 nt_status = method->ops->get_user_info_dc_principal(mem_ctx, auth_ctx, principal, user_dn, &user_info_dc);
109                 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
110                         continue;
111                 }
112                 if (!NT_STATUS_IS_OK(nt_status)) {
113                         return nt_status;
114                 }
115
116                 nt_status = auth_generate_session_info_wrapper(auth_ctx, mem_ctx, 
117                                                                user_info_dc,
118                                                                user_info_dc->info->account_name,
119                                                                session_info_flags, session_info);
120                 talloc_free(user_info_dc);
121
122                 return nt_status;
123         }
124
125         return NT_STATUS_NOT_IMPLEMENTED;
126 }
127
128 /**
129  * Check a user's Plaintext, LM or NTLM password.
130  * (sync version)
131  *
132  * Check a user's password, as given in the user_info struct and return various
133  * interesting details in the user_info_dc struct.
134  *
135  * The return value takes precedence over the contents of the user_info_dc
136  * struct.  When the return is other than NT_STATUS_OK the contents 
137  * of that structure is undefined.
138  *
139  * @param auth_ctx Supplies the challenges and some other data. 
140  *                  Must be created with auth_context_create(), and the challenges should be 
141  *                  filled in, either at creation or by calling the challenge geneation 
142  *                  function auth_get_challenge().  
143  *
144  * @param user_info Contains the user supplied components, including the passwords.
145  *
146  * @param mem_ctx The parent memory context for the user_info_dc structure
147  *
148  * @param user_info_dc If successful, contains information about the authentication,
149  *                    including a SAM_ACCOUNT struct describing the user.
150  *
151  * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
152  *
153  **/
154
155 _PUBLIC_ NTSTATUS auth_check_password(struct auth4_context *auth_ctx,
156                              TALLOC_CTX *mem_ctx,
157                              const struct auth_usersupplied_info *user_info, 
158                              struct auth_user_info_dc **user_info_dc)
159 {
160         struct tevent_req *subreq;
161         struct tevent_context *ev;
162         bool ok;
163         NTSTATUS status;
164
165         /*TODO: create a new event context here! */
166         ev = auth_ctx->event_ctx;
167
168         subreq = auth_check_password_send(mem_ctx,
169                                           ev,
170                                           auth_ctx,
171                                           user_info);
172         if (subreq == NULL) {
173                 return NT_STATUS_NO_MEMORY;
174         }
175
176         ok = tevent_req_poll(subreq, ev);
177         if (!ok) {
178                 return NT_STATUS_INTERNAL_ERROR;
179         }
180
181         status = auth_check_password_recv(subreq, mem_ctx, user_info_dc);
182         TALLOC_FREE(subreq);
183
184         return status;
185 }
186
187 static NTSTATUS auth_check_password_wrapper(struct auth4_context *auth_ctx,
188                                             TALLOC_CTX *mem_ctx,
189                                             const struct auth_usersupplied_info *user_info,
190                                             void **server_returned_info,
191                                             DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
192 {
193         struct auth_user_info_dc *user_info_dc;
194         NTSTATUS status;
195
196         status = auth_check_password(auth_ctx, mem_ctx, user_info,
197                                      &user_info_dc);
198         if (!NT_STATUS_IS_OK(status)) {
199                 return status;
200         }
201
202         *server_returned_info = user_info_dc;
203
204         if (user_session_key) {
205                 DEBUG(10, ("Got NT session key of length %u\n",
206                            (unsigned)user_info_dc->user_session_key.length));
207                 *user_session_key = user_info_dc->user_session_key;
208                 talloc_steal(mem_ctx, user_session_key->data);
209                 user_info_dc->user_session_key = data_blob_null;
210         }
211
212         if (lm_session_key) {
213                 DEBUG(10, ("Got LM session key of length %u\n",
214                            (unsigned)user_info_dc->lm_session_key.length));
215                 *lm_session_key = user_info_dc->lm_session_key;
216                 talloc_steal(mem_ctx, lm_session_key->data);
217                 user_info_dc->lm_session_key = data_blob_null;
218         }
219
220         return NT_STATUS_OK;
221 }
222
223 struct auth_check_password_state {
224         struct auth4_context *auth_ctx;
225         const struct auth_usersupplied_info *user_info;
226         struct auth_user_info_dc *user_info_dc;
227         struct auth_method_context *method;
228 };
229
230 static void auth_check_password_async_trigger(struct tevent_context *ev,
231                                               struct tevent_immediate *im,
232                                               void *private_data);
233 /**
234  * Check a user's Plaintext, LM or NTLM password.
235  * async send hook
236  *
237  * Check a user's password, as given in the user_info struct and return various
238  * interesting details in the user_info_dc struct.
239  *
240  * The return value takes precedence over the contents of the user_info_dc
241  * struct.  When the return is other than NT_STATUS_OK the contents 
242  * of that structure is undefined.
243  *
244  * @param mem_ctx The memory context the request should operate on
245  *
246  * @param ev The tevent context the request should operate on
247  *
248  * @param auth_ctx Supplies the challenges and some other data. 
249  *                  Must be created with make_auth_context(), and the challenges should be 
250  *                  filled in, either at creation or by calling the challenge geneation 
251  *                  function auth_get_challenge().  
252  *
253  * @param user_info Contains the user supplied components, including the passwords.
254  *
255  * @return The request handle or NULL on no memory error.
256  *
257  **/
258
259 _PUBLIC_ struct tevent_req *auth_check_password_send(TALLOC_CTX *mem_ctx,
260                                 struct tevent_context *ev,
261                                 struct auth4_context *auth_ctx,
262                                 const struct auth_usersupplied_info *user_info)
263 {
264         struct tevent_req *req;
265         struct auth_check_password_state *state;
266         /* if all the modules say 'not for me' this is reasonable */
267         NTSTATUS nt_status;
268         uint8_t chal[8];
269         struct tevent_immediate *im;
270
271         DEBUG(3,("auth_check_password_send: "
272                  "Checking password for unmapped user [%s]\\[%s]@[%s]\n",
273                  user_info->client.domain_name, user_info->client.account_name,
274                  user_info->workstation_name));
275
276         req = tevent_req_create(mem_ctx, &state,
277                                 struct auth_check_password_state);
278         if (req == NULL) {
279                 return NULL;
280         }
281
282         state->auth_ctx         = auth_ctx;
283         state->user_info        = user_info;
284
285         if (!user_info->mapped_state) {
286                 int server_role = lpcfg_server_role(auth_ctx->lp_ctx);
287                 struct auth_usersupplied_info *user_info_tmp;
288
289                 nt_status = map_user_info(
290                         auth_ctx->sam_ctx, req,
291                         server_role == ROLE_ACTIVE_DIRECTORY_DC,
292                         lpcfg_workgroup(auth_ctx->lp_ctx),
293                         user_info, &user_info_tmp);
294
295                 if (tevent_req_nterror(req, nt_status)) {
296                         return tevent_req_post(req, ev);
297                 }
298                 user_info = user_info_tmp;
299                 state->user_info = user_info_tmp;
300         }
301
302         DEBUGADD(3,("auth_check_password_send: "
303                     "mapped user is: [%s]\\[%s]@[%s]\n",
304                     user_info->mapped.domain_name,
305                     user_info->mapped.account_name,
306                     user_info->workstation_name));
307
308         nt_status = auth_get_challenge(auth_ctx, chal);
309         if (tevent_req_nterror(req, nt_status)) {
310                 DEBUG(0,("auth_check_password_send: "
311                          "Invalid challenge (length %u) stored for "
312                          "this auth context set_by %s - cannot continue: %s\n",
313                         (unsigned)auth_ctx->challenge.data.length,
314                         auth_ctx->challenge.set_by,
315                         nt_errstr(nt_status)));
316                 return tevent_req_post(req, ev);
317         }
318
319         if (auth_ctx->challenge.set_by) {
320                 DEBUG(10,("auth_check_password_send: "
321                           "auth_context challenge created by %s\n",
322                           auth_ctx->challenge.set_by));
323         }
324
325         DEBUG(10, ("auth_check_password_send: challenge is: \n"));
326         dump_data(5, auth_ctx->challenge.data.data,
327                   auth_ctx->challenge.data.length);
328
329         im = tevent_create_immediate(state);
330         if (tevent_req_nomem(im, req)) {
331                 return tevent_req_post(req, ev);
332         }
333
334         tevent_schedule_immediate(im,
335                                   auth_ctx->event_ctx,
336                                   auth_check_password_async_trigger,
337                                   req);
338         return req;
339 }
340
341 static void auth_check_password_async_trigger(struct tevent_context *ev,
342                                               struct tevent_immediate *im,
343                                               void *private_data)
344 {
345         struct tevent_req *req =
346                 talloc_get_type_abort(private_data, struct tevent_req);
347         struct auth_check_password_state *state =
348                 tevent_req_data(req, struct auth_check_password_state);
349         NTSTATUS status;
350         struct auth_method_context *method;
351
352         status = NT_STATUS_OK;
353
354         for (method=state->auth_ctx->methods; method; method = method->next) {
355
356                 if (state->user_info->flags & USER_INFO_LOCAL_SAM_ONLY
357                     && !(method->ops->flags & AUTH_METHOD_LOCAL_SAM)) {
358                         continue;
359                 }
360
361                 /* we fill in state->method here so debug messages in
362                    the callers know which method failed */
363                 state->method = method;
364
365                 /* check if the module wants to check the password */
366                 status = method->ops->want_check(method, req, state->user_info);
367                 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
368                         DEBUG(11,("auth_check_password_send: "
369                                   "%s had nothing to say\n",
370                                   method->ops->name));
371                         continue;
372                 }
373
374                 if (tevent_req_nterror(req, status)) {
375                         return;
376                 }
377
378                 status = method->ops->check_password(method,
379                                                      state,
380                                                      state->user_info,
381                                                      &state->user_info_dc);
382                 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
383                         /* the backend has handled the request */
384                         break;
385                 }
386         }
387
388         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
389                 if (!(state->user_info->flags & USER_INFO_LOCAL_SAM_ONLY)) {
390                         /* don't expose the NT_STATUS_NOT_IMPLEMENTED
391                          * internals, except when the caller is only probing
392                          * one method, as they may do the fallback 
393                          */
394                         status = NT_STATUS_NO_SUCH_USER;
395                 }
396         }
397
398         if (tevent_req_nterror(req, status)) {
399                 return;
400         }
401
402         tevent_req_done(req);
403 }
404
405 /**
406  * Check a user's Plaintext, LM or NTLM password.
407  * async receive function
408  *
409  * The return value takes precedence over the contents of the user_info_dc
410  * struct.  When the return is other than NT_STATUS_OK the contents 
411  * of that structure is undefined.
412  *
413  *
414  * @param req The async request state
415  *
416  * @param mem_ctx The parent memory context for the user_info_dc structure
417  *
418  * @param user_info_dc If successful, contains information about the authentication,
419  *                    including a SAM_ACCOUNT struct describing the user.
420  *
421  * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
422  *
423  **/
424
425 _PUBLIC_ NTSTATUS auth_check_password_recv(struct tevent_req *req,
426                                   TALLOC_CTX *mem_ctx,
427                                   struct auth_user_info_dc **user_info_dc)
428 {
429         struct auth_check_password_state *state =
430                 tevent_req_data(req, struct auth_check_password_state);
431         NTSTATUS status;
432
433         if (tevent_req_is_nterror(req, &status)) {
434                 DEBUG(2,("auth_check_password_recv: "
435                          "%s authentication for user [%s\\%s] "
436                          "FAILED with error %s\n",
437                          (state->method ? state->method->ops->name : "NO_METHOD"),
438                          state->user_info->mapped.domain_name,
439                          state->user_info->mapped.account_name,
440                          nt_errstr(status)));
441                 tevent_req_received(req);
442                 return status;
443         }
444
445         DEBUG(5,("auth_check_password_recv: "
446                  "%s authentication for user [%s\\%s] succeeded\n",
447                  state->method->ops->name,
448                  state->user_info_dc->info->domain_name,
449                  state->user_info_dc->info->account_name));
450
451         *user_info_dc = talloc_move(mem_ctx, &state->user_info_dc);
452
453         tevent_req_received(req);
454         return NT_STATUS_OK;
455 }
456
457  /* Wrapper because we don't want to expose all callers to needing to
458   * know that session_info is generated from the main ldb, and because
459   * we need to break a depenency loop between the DCE/RPC layer and the
460   * generation of unix tokens via IRPC */
461 static NTSTATUS auth_generate_session_info_wrapper(struct auth4_context *auth_context,
462                                                    TALLOC_CTX *mem_ctx,
463                                                    void *server_returned_info,
464                                                    const char *original_user_name,
465                                                   uint32_t session_info_flags,
466                                                   struct auth_session_info **session_info)
467 {
468         NTSTATUS status;
469         struct auth_user_info_dc *user_info_dc = talloc_get_type_abort(server_returned_info, struct auth_user_info_dc);
470
471         if (user_info_dc->info->authenticated) {
472                 session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
473         }
474
475         status = auth_generate_session_info(mem_ctx, auth_context->lp_ctx,
476                                             auth_context->sam_ctx, user_info_dc,
477                                             session_info_flags, session_info);
478         if (!NT_STATUS_IS_OK(status)) {
479                 return status;
480         }
481
482         if ((session_info_flags & AUTH_SESSION_INFO_UNIX_TOKEN)
483             && NT_STATUS_IS_OK(status)) {
484                 status = auth_session_info_fill_unix(auth_context->event_ctx,
485                                                      auth_context->lp_ctx,
486                                                      original_user_name, *session_info);
487                 if (!NT_STATUS_IS_OK(status)) {
488                         TALLOC_FREE(*session_info);
489                 }
490         }
491         return status;
492 }
493
494 /* Wrapper because we don't want to expose all callers to needing to
495  * know anything about the PAC or auth subsystem internal structures
496  * before we output a struct auth session_info */
497 static NTSTATUS auth_generate_session_info_pac(struct auth4_context *auth_ctx,
498                                                TALLOC_CTX *mem_ctx,
499                                                struct smb_krb5_context *smb_krb5_context,
500                                                DATA_BLOB *pac_blob,
501                                                const char *principal_name,
502                                                const struct tsocket_address *remote_address,
503                                                uint32_t session_info_flags,
504                                                struct auth_session_info **session_info)
505 {
506         NTSTATUS status;
507         struct auth_user_info_dc *user_info_dc;
508         TALLOC_CTX *tmp_ctx;
509
510         if (!pac_blob) {
511                 return auth_generate_session_info_principal(auth_ctx, mem_ctx, principal_name,
512                                                        NULL, session_info_flags, session_info);
513         }
514
515         tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gssapi_session_info context");
516         NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
517
518         status = kerberos_pac_blob_to_user_info_dc(tmp_ctx,
519                                                    *pac_blob,
520                                                    smb_krb5_context->krb5_context,
521                                                    &user_info_dc, NULL, NULL);
522         if (!NT_STATUS_IS_OK(status)) {
523                 talloc_free(tmp_ctx);
524                 return status;
525         }
526
527         if (user_info_dc->info->authenticated) {
528                 session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
529         }
530
531         status = auth_generate_session_info_wrapper(auth_ctx, mem_ctx, 
532                                                     user_info_dc,
533                                                     user_info_dc->info->account_name,
534                                                     session_info_flags, session_info);
535         talloc_free(tmp_ctx);
536         return status;
537 }
538
539 /***************************************************************************
540  Make a auth_info struct for the auth subsystem
541  - Allow the caller to specify the methods to use, including optionally the SAM to use
542 ***************************************************************************/
543 _PUBLIC_ NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char * const *methods, 
544                                               struct tevent_context *ev,
545                                               struct imessaging_context *msg,
546                                               struct loadparm_context *lp_ctx,
547                                               struct ldb_context *sam_ctx,
548                                               struct auth4_context **auth_ctx)
549 {
550         int i;
551         struct auth4_context *ctx;
552
553         auth4_init();
554
555         if (!ev) {
556                 DEBUG(0,("auth_context_create: called with out event context\n"));
557                 return NT_STATUS_INTERNAL_ERROR;
558         }
559
560         ctx = talloc_zero(mem_ctx, struct auth4_context);
561         NT_STATUS_HAVE_NO_MEMORY(ctx);
562         ctx->challenge.data             = data_blob(NULL, 0);
563         ctx->methods                    = NULL;
564         ctx->event_ctx                  = ev;
565         ctx->msg_ctx                    = msg;
566         ctx->lp_ctx                     = lp_ctx;
567
568         if (sam_ctx) {
569                 ctx->sam_ctx = sam_ctx;
570         } else {
571                 ctx->sam_ctx = samdb_connect(ctx, ctx->event_ctx, ctx->lp_ctx, system_session(ctx->lp_ctx), 0);
572         }
573
574         for (i=0; methods && methods[i] ; i++) {
575                 struct auth_method_context *method;
576
577                 method = talloc(ctx, struct auth_method_context);
578                 NT_STATUS_HAVE_NO_MEMORY(method);
579
580                 method->ops = auth_backend_byname(methods[i]);
581                 if (!method->ops) {
582                         DEBUG(1,("auth_context_create: failed to find method=%s\n",
583                                 methods[i]));
584                         return NT_STATUS_INTERNAL_ERROR;
585                 }
586                 method->auth_ctx        = ctx;
587                 method->depth           = i;
588                 DLIST_ADD_END(ctx->methods, method);
589         }
590
591         ctx->check_ntlm_password = auth_check_password_wrapper;
592         ctx->get_ntlm_challenge = auth_get_challenge;
593         ctx->set_ntlm_challenge = auth_context_set_challenge;
594         ctx->generate_session_info = auth_generate_session_info_wrapper;
595         ctx->generate_session_info_pac = auth_generate_session_info_pac;
596
597         *auth_ctx = ctx;
598
599         return NT_STATUS_OK;
600 }
601
602 const char **auth_methods_from_lp(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
603 {
604         char **auth_methods = NULL;
605
606         switch (lpcfg_server_role(lp_ctx)) {
607         case ROLE_STANDALONE:
608                 auth_methods = str_list_make(mem_ctx, "anonymous sam_ignoredomain", NULL);
609                 break;
610         case ROLE_DOMAIN_MEMBER:
611                 auth_methods = str_list_make(mem_ctx, "anonymous sam winbind", NULL);
612                 break;
613         case ROLE_DOMAIN_BDC:
614         case ROLE_DOMAIN_PDC:
615         case ROLE_ACTIVE_DIRECTORY_DC:
616                 auth_methods = str_list_make(mem_ctx, "anonymous sam_ignoredomain winbind", NULL);
617                 break;
618         }
619         return discard_const_p(const char *, auth_methods);
620 }
621
622 /***************************************************************************
623  Make a auth_info struct for the auth subsystem
624  - Uses default auth_methods, depending on server role and smb.conf settings
625 ***************************************************************************/
626 _PUBLIC_ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx,
627                              struct tevent_context *ev,
628                              struct imessaging_context *msg,
629                              struct loadparm_context *lp_ctx,
630                              struct auth4_context **auth_ctx)
631 {
632         NTSTATUS status;
633         const char **auth_methods;
634         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
635         if (!tmp_ctx) {
636                 return NT_STATUS_NO_MEMORY;
637         }
638
639         auth_methods = auth_methods_from_lp(tmp_ctx, lp_ctx);
640         if (!auth_methods) {
641                 return NT_STATUS_INVALID_PARAMETER;
642         }
643         status = auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, NULL, auth_ctx);
644         talloc_free(tmp_ctx);
645         return status;
646 }
647
648 _PUBLIC_ NTSTATUS auth_context_create_for_netlogon(TALLOC_CTX *mem_ctx,
649                                                    struct tevent_context *ev,
650                                                    struct imessaging_context *msg,
651                                                    struct loadparm_context *lp_ctx,
652                                                    struct auth4_context **auth_ctx)
653 {
654         return auth_context_create(mem_ctx, ev, msg, lp_ctx, auth_ctx);
655 }
656
657 /* the list of currently registered AUTH backends */
658 static struct auth_backend {
659         const struct auth_operations *ops;
660 } *backends = NULL;
661 static int num_backends;
662
663 /*
664   register a AUTH backend. 
665
666   The 'name' can be later used by other backends to find the operations
667   structure for this backend.
668 */
669 _PUBLIC_ NTSTATUS auth_register(const struct auth_operations *ops)
670 {
671         struct auth_operations *new_ops;
672         
673         if (auth_backend_byname(ops->name) != NULL) {
674                 /* its already registered! */
675                 DEBUG(0,("AUTH backend '%s' already registered\n", 
676                          ops->name));
677                 return NT_STATUS_OBJECT_NAME_COLLISION;
678         }
679
680         backends = talloc_realloc(talloc_autofree_context(), backends, 
681                                   struct auth_backend, num_backends+1);
682         NT_STATUS_HAVE_NO_MEMORY(backends);
683
684         new_ops = (struct auth_operations *)talloc_memdup(backends, ops, sizeof(*ops));
685         NT_STATUS_HAVE_NO_MEMORY(new_ops);
686         new_ops->name = talloc_strdup(new_ops, ops->name);
687         NT_STATUS_HAVE_NO_MEMORY(new_ops->name);
688
689         backends[num_backends].ops = new_ops;
690
691         num_backends++;
692
693         DEBUG(3,("AUTH backend '%s' registered\n", 
694                  ops->name));
695
696         return NT_STATUS_OK;
697 }
698
699 /*
700   return the operations structure for a named backend of the specified type
701 */
702 const struct auth_operations *auth_backend_byname(const char *name)
703 {
704         int i;
705
706         for (i=0;i<num_backends;i++) {
707                 if (strcmp(backends[i].ops->name, name) == 0) {
708                         return backends[i].ops;
709                 }
710         }
711
712         return NULL;
713 }
714
715 /*
716   return the AUTH interface version, and the size of some critical types
717   This can be used by backends to either detect compilation errors, or provide
718   multiple implementations for different smbd compilation options in one module
719 */
720 const struct auth_critical_sizes *auth_interface_version(void)
721 {
722         static const struct auth_critical_sizes critical_sizes = {
723                 AUTH4_INTERFACE_VERSION,
724                 sizeof(struct auth_operations),
725                 sizeof(struct auth_method_context),
726                 sizeof(struct auth4_context),
727                 sizeof(struct auth_usersupplied_info),
728                 sizeof(struct auth_user_info_dc)
729         };
730
731         return &critical_sizes;
732 }
733
734 _PUBLIC_ NTSTATUS auth4_init(void)
735 {
736         static bool initialized = false;
737 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
738         STATIC_auth4_MODULES_PROTO;
739         init_module_fn static_init[] = { STATIC_auth4_MODULES };
740         
741         if (initialized) return NT_STATUS_OK;
742         initialized = true;
743         
744         run_init_functions(static_init);
745         
746         return NT_STATUS_OK;    
747 }