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