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