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