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