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