dsdb-acl: make use of acl_check_access_on_objectclass() for the object in acl_delete()
[Samba/gebeck_regimport.git] / source4 / auth / ntlm / auth.c
blob263dc8031d020889a7e6abac91994d1167c8851d
1 /*
2 Unix SMB/CIFS implementation.
3 Password and authentication handling
4 Copyright (C) Andrew Bartlett 2001-2002
5 Copyright (C) Stefan Metzmacher 2005
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.
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.
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/>.
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"
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);
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)
48 auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
49 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
51 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
52 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
54 return NT_STATUS_OK;
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])
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;
71 if (!auth_ctx->challenge.set_by) {
72 generate_random_buffer(chal, 8);
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";
79 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
80 auth_ctx->challenge.set_by));
82 return NT_STATUS_OK;
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.
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)
98 NTSTATUS nt_status;
99 struct auth_method_context *method;
100 struct auth_user_info_dc *user_info_dc;
102 for (method = auth_ctx->methods; method; method = method->next) {
103 if (!method->ops->get_user_info_dc_principal) {
104 continue;
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;
111 if (!NT_STATUS_IS_OK(nt_status)) {
112 return nt_status;
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);
121 return nt_status;
124 return NT_STATUS_NOT_IMPLEMENTED;
128 * Check a user's Plaintext, LM or NTLM password.
129 * (sync version)
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.
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.
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().
143 * @param user_info Contains the user supplied components, including the passwords.
145 * @param mem_ctx The parent memory context for the user_info_dc structure
147 * @param user_info_dc If successful, contains information about the authentication,
148 * including a SAM_ACCOUNT struct describing the user.
150 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
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)
159 struct tevent_req *subreq;
160 struct tevent_context *ev;
161 bool ok;
162 NTSTATUS status;
164 /*TODO: create a new event context here! */
165 ev = auth_ctx->event_ctx;
167 subreq = auth_check_password_send(mem_ctx,
169 auth_ctx,
170 user_info);
171 if (subreq == NULL) {
172 return NT_STATUS_NO_MEMORY;
175 ok = tevent_req_poll(subreq, ev);
176 if (!ok) {
177 return NT_STATUS_INTERNAL_ERROR;
180 status = auth_check_password_recv(subreq, mem_ctx, user_info_dc);
181 TALLOC_FREE(subreq);
183 return status;
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)
192 struct auth_user_info_dc *user_info_dc;
193 NTSTATUS status = auth_check_password(auth_ctx, mem_ctx, user_info, &user_info_dc);
195 if (NT_STATUS_IS_OK(status)) {
196 *server_returned_info = user_info_dc;
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;
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;
215 return status;
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;
225 static void auth_check_password_async_trigger(struct tevent_context *ev,
226 struct tevent_immediate *im,
227 void *private_data);
229 * Check a user's Plaintext, LM or NTLM password.
230 * async send hook
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.
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.
239 * @param mem_ctx The memory context the request should operate on
241 * @param ev The tevent context the request should operate on
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().
248 * @param user_info Contains the user supplied components, including the passwords.
250 * @return The request handle or NULL on no memory error.
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)
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;
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));
272 req = tevent_req_create(mem_ctx, &state,
273 struct auth_check_password_state);
274 if (req == NULL) {
275 return NULL;
278 state->auth_ctx = auth_ctx;
279 state->user_info = user_info;
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);
287 user_info = user_info_tmp;
288 state->user_info = user_info_tmp;
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));
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);
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));
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);
318 im = tevent_create_immediate(state);
319 if (tevent_req_nomem(im, req)) {
320 return tevent_req_post(req, ev);
323 tevent_schedule_immediate(im,
324 auth_ctx->event_ctx,
325 auth_check_password_async_trigger,
326 req);
327 return req;
330 static void auth_check_password_async_trigger(struct tevent_context *ev,
331 struct tevent_immediate *im,
332 void *private_data)
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;
341 status = NT_STATUS_OK;
343 for (method=state->auth_ctx->methods; method; method = method->next) {
345 /* we fill in state->method here so debug messages in
346 the callers know which method failed */
347 state->method = method;
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;
358 if (tevent_req_nterror(req, status)) {
359 return;
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;
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;
378 if (tevent_req_nterror(req, status)) {
379 return;
382 tevent_req_done(req);
386 * Check a user's Plaintext, LM or NTLM password.
387 * async receive function
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.
394 * @param req The async request state
396 * @param mem_ctx The parent memory context for the user_info_dc structure
398 * @param user_info_dc If successful, contains information about the authentication,
399 * including a SAM_ACCOUNT struct describing the user.
401 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
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)
409 struct auth_check_password_state *state =
410 tevent_req_data(req, struct auth_check_password_state);
411 NTSTATUS status;
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;
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));
431 *user_info_dc = talloc_move(mem_ctx, &state->user_info_dc);
433 tevent_req_received(req);
434 return NT_STATUS_OK;
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)
448 NTSTATUS status;
449 struct auth_user_info_dc *user_info_dc = talloc_get_type_abort(server_returned_info, struct auth_user_info_dc);
451 if (user_info_dc->info->authenticated) {
452 session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
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;
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;
472 status = auth_session_info_fill_unix(wbc_ctx, auth_context->lp_ctx,
473 original_user_name, *session_info);
474 if (!NT_STATUS_IS_OK(status)) {
475 TALLOC_FREE(*session_info);
477 TALLOC_FREE(wbc_ctx);
479 return status;
482 /* Wrapper because we don't want to expose all callers to needing to
483 * know anything about the PAC or auth subsystem internal structures
484 * before we output a struct auth session_info */
485 static NTSTATUS auth_generate_session_info_pac(struct auth4_context *auth_ctx,
486 TALLOC_CTX *mem_ctx,
487 struct smb_krb5_context *smb_krb5_context,
488 DATA_BLOB *pac_blob,
489 const char *principal_name,
490 const struct tsocket_address *remote_address,
491 uint32_t session_info_flags,
492 struct auth_session_info **session_info)
494 NTSTATUS status;
495 struct auth_user_info_dc *user_info_dc;
496 TALLOC_CTX *tmp_ctx;
498 if (!pac_blob) {
499 return auth_generate_session_info_principal(auth_ctx, mem_ctx, principal_name,
500 NULL, session_info_flags, session_info);
503 tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gssapi_session_info context");
504 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
506 status = kerberos_pac_blob_to_user_info_dc(tmp_ctx,
507 *pac_blob,
508 smb_krb5_context->krb5_context,
509 &user_info_dc, NULL, NULL);
510 if (!NT_STATUS_IS_OK(status)) {
511 talloc_free(tmp_ctx);
512 return status;
515 if (user_info_dc->info->authenticated) {
516 session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
519 status = auth_generate_session_info_wrapper(auth_ctx, mem_ctx,
520 user_info_dc,
521 user_info_dc->info->account_name,
522 session_info_flags, session_info);
523 talloc_free(tmp_ctx);
524 return status;
527 /***************************************************************************
528 Make a auth_info struct for the auth subsystem
529 - Allow the caller to specify the methods to use, including optionally the SAM to use
530 ***************************************************************************/
531 _PUBLIC_ NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char **methods,
532 struct tevent_context *ev,
533 struct imessaging_context *msg,
534 struct loadparm_context *lp_ctx,
535 struct ldb_context *sam_ctx,
536 struct auth4_context **auth_ctx)
538 int i;
539 struct auth4_context *ctx;
541 auth4_init();
543 if (!ev) {
544 DEBUG(0,("auth_context_create: called with out event context\n"));
545 return NT_STATUS_INTERNAL_ERROR;
548 ctx = talloc_zero(mem_ctx, struct auth4_context);
549 NT_STATUS_HAVE_NO_MEMORY(ctx);
550 ctx->challenge.data = data_blob(NULL, 0);
551 ctx->methods = NULL;
552 ctx->event_ctx = ev;
553 ctx->msg_ctx = msg;
554 ctx->lp_ctx = lp_ctx;
556 if (sam_ctx) {
557 ctx->sam_ctx = sam_ctx;
558 } else {
559 ctx->sam_ctx = samdb_connect(ctx, ctx->event_ctx, ctx->lp_ctx, system_session(ctx->lp_ctx), 0);
562 for (i=0; methods && methods[i] ; i++) {
563 struct auth_method_context *method;
565 method = talloc(ctx, struct auth_method_context);
566 NT_STATUS_HAVE_NO_MEMORY(method);
568 method->ops = auth_backend_byname(methods[i]);
569 if (!method->ops) {
570 DEBUG(1,("auth_context_create: failed to find method=%s\n",
571 methods[i]));
572 return NT_STATUS_INTERNAL_ERROR;
574 method->auth_ctx = ctx;
575 method->depth = i;
576 DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
579 ctx->check_ntlm_password = auth_check_password_wrapper;
580 ctx->get_ntlm_challenge = auth_get_challenge;
581 ctx->set_ntlm_challenge = auth_context_set_challenge;
582 ctx->generate_session_info = auth_generate_session_info_wrapper;
583 ctx->generate_session_info_pac = auth_generate_session_info_pac;
585 *auth_ctx = ctx;
587 return NT_STATUS_OK;
590 const char **auth_methods_from_lp(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
592 char **auth_methods = NULL;
594 switch (lpcfg_server_role(lp_ctx)) {
595 case ROLE_STANDALONE:
596 auth_methods = str_list_make(mem_ctx, "anonymous sam_ignoredomain", NULL);
597 break;
598 case ROLE_DOMAIN_MEMBER:
599 auth_methods = str_list_make(mem_ctx, "anonymous sam winbind", NULL);
600 break;
601 case ROLE_DOMAIN_BDC:
602 case ROLE_DOMAIN_PDC:
603 case ROLE_ACTIVE_DIRECTORY_DC:
604 auth_methods = str_list_make(mem_ctx, "anonymous sam_ignoredomain winbind", NULL);
605 break;
607 return (const char **) auth_methods;
610 /***************************************************************************
611 Make a auth_info struct for the auth subsystem
612 - Uses default auth_methods, depending on server role and smb.conf settings
613 ***************************************************************************/
614 _PUBLIC_ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx,
615 struct tevent_context *ev,
616 struct imessaging_context *msg,
617 struct loadparm_context *lp_ctx,
618 struct auth4_context **auth_ctx)
620 NTSTATUS status;
621 const char **auth_methods;
622 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
623 if (!tmp_ctx) {
624 return NT_STATUS_NO_MEMORY;
627 auth_methods = auth_methods_from_lp(tmp_ctx, lp_ctx);
628 if (!auth_methods) {
629 return NT_STATUS_INVALID_PARAMETER;
631 status = auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, NULL, auth_ctx);
632 talloc_free(tmp_ctx);
633 return status;
636 /* the list of currently registered AUTH backends */
637 static struct auth_backend {
638 const struct auth_operations *ops;
639 } *backends = NULL;
640 static int num_backends;
643 register a AUTH backend.
645 The 'name' can be later used by other backends to find the operations
646 structure for this backend.
648 _PUBLIC_ NTSTATUS auth_register(const struct auth_operations *ops)
650 struct auth_operations *new_ops;
652 if (auth_backend_byname(ops->name) != NULL) {
653 /* its already registered! */
654 DEBUG(0,("AUTH backend '%s' already registered\n",
655 ops->name));
656 return NT_STATUS_OBJECT_NAME_COLLISION;
659 backends = talloc_realloc(talloc_autofree_context(), backends,
660 struct auth_backend, num_backends+1);
661 NT_STATUS_HAVE_NO_MEMORY(backends);
663 new_ops = (struct auth_operations *)talloc_memdup(backends, ops, sizeof(*ops));
664 NT_STATUS_HAVE_NO_MEMORY(new_ops);
665 new_ops->name = talloc_strdup(new_ops, ops->name);
666 NT_STATUS_HAVE_NO_MEMORY(new_ops->name);
668 backends[num_backends].ops = new_ops;
670 num_backends++;
672 DEBUG(3,("AUTH backend '%s' registered\n",
673 ops->name));
675 return NT_STATUS_OK;
679 return the operations structure for a named backend of the specified type
681 const struct auth_operations *auth_backend_byname(const char *name)
683 int i;
685 for (i=0;i<num_backends;i++) {
686 if (strcmp(backends[i].ops->name, name) == 0) {
687 return backends[i].ops;
691 return NULL;
695 return the AUTH interface version, and the size of some critical types
696 This can be used by backends to either detect compilation errors, or provide
697 multiple implementations for different smbd compilation options in one module
699 const struct auth_critical_sizes *auth_interface_version(void)
701 static const struct auth_critical_sizes critical_sizes = {
702 AUTH4_INTERFACE_VERSION,
703 sizeof(struct auth_operations),
704 sizeof(struct auth_method_context),
705 sizeof(struct auth4_context),
706 sizeof(struct auth_usersupplied_info),
707 sizeof(struct auth_user_info_dc)
710 return &critical_sizes;
713 _PUBLIC_ NTSTATUS auth4_init(void)
715 static bool initialized = false;
716 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
717 STATIC_auth4_MODULES_PROTO;
718 init_module_fn static_init[] = { STATIC_auth4_MODULES };
720 if (initialized) return NT_STATUS_OK;
721 initialized = true;
723 run_init_functions(static_init);
725 return NT_STATUS_OK;