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/>.
23 #include "../lib/util/tevent_ntstatus.h"
24 #include "../lib/util/dlinklist.h"
25 #include "auth/auth.h"
26 #include "auth/ntlm/auth_proto.h"
27 #include "param/param.h"
28 #include "dsdb/samdb/samdb.h"
29 #include "libcli/wbclient/wbclient.h"
30 #include "lib/util/samba_modules.h"
31 #include "auth/credentials/credentials.h"
32 #include "system/kerberos.h"
33 #include "auth/kerberos/kerberos.h"
34 #include "auth/kerberos/kerberos_util.h"
35 #include "libds/common/roles.h"
37 static NTSTATUS auth_generate_session_info_wrapper(struct auth4_context *auth_context,
39 void *server_returned_info,
40 const char *original_user_name,
41 uint32_t session_info_flags,
42 struct auth_session_info **session_info);
44 /***************************************************************************
46 ***************************************************************************/
47 _PUBLIC_ NTSTATUS auth_context_set_challenge(struct auth4_context *auth_ctx, const uint8_t chal[8], const char *set_by)
49 auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
50 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
52 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
53 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
58 /****************************************************************************
59 Try to get a challenge out of the various authentication modules.
60 Returns a const char of length 8 bytes.
61 ****************************************************************************/
62 _PUBLIC_ NTSTATUS auth_get_challenge(struct auth4_context *auth_ctx, uint8_t chal[8])
65 if (auth_ctx->challenge.data.length == 8) {
66 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
67 auth_ctx->challenge.set_by));
68 memcpy(chal, auth_ctx->challenge.data.data, 8);
72 if (!auth_ctx->challenge.set_by) {
73 generate_random_buffer(chal, 8);
75 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
76 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
77 auth_ctx->challenge.set_by = "random";
80 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
81 auth_ctx->challenge.set_by));
86 /****************************************************************************
87 Used in the gensec_gssapi and gensec_krb5 server-side code, where the
88 PAC isn't available, and for tokenGroups in the DSDB stack.
90 Supply either a principal or a DN
91 ****************************************************************************/
92 static NTSTATUS auth_generate_session_info_principal(struct auth4_context *auth_ctx,
94 const char *principal,
95 struct ldb_dn *user_dn,
96 uint32_t session_info_flags,
97 struct auth_session_info **session_info)
100 struct auth_method_context *method;
101 struct auth_user_info_dc *user_info_dc;
103 for (method = auth_ctx->methods; method; method = method->next) {
104 if (!method->ops->get_user_info_dc_principal) {
108 nt_status = method->ops->get_user_info_dc_principal(mem_ctx, auth_ctx, principal, user_dn, &user_info_dc);
109 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
112 if (!NT_STATUS_IS_OK(nt_status)) {
116 nt_status = auth_generate_session_info_wrapper(auth_ctx, mem_ctx,
118 user_info_dc->info->account_name,
119 session_info_flags, session_info);
120 talloc_free(user_info_dc);
125 return NT_STATUS_NOT_IMPLEMENTED;
129 * Check a user's Plaintext, LM or NTLM password.
132 * Check a user's password, as given in the user_info struct and return various
133 * interesting details in the user_info_dc struct.
135 * The return value takes precedence over the contents of the user_info_dc
136 * struct. When the return is other than NT_STATUS_OK the contents
137 * of that structure is undefined.
139 * @param auth_ctx Supplies the challenges and some other data.
140 * Must be created with auth_context_create(), and the challenges should be
141 * filled in, either at creation or by calling the challenge geneation
142 * function auth_get_challenge().
144 * @param user_info Contains the user supplied components, including the passwords.
146 * @param mem_ctx The parent memory context for the user_info_dc structure
148 * @param user_info_dc If successful, contains information about the authentication,
149 * including a SAM_ACCOUNT struct describing the user.
151 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
155 _PUBLIC_ NTSTATUS auth_check_password(struct auth4_context *auth_ctx,
157 const struct auth_usersupplied_info *user_info,
158 struct auth_user_info_dc **user_info_dc,
159 uint8_t *pauthoritative)
161 struct tevent_req *subreq;
162 struct tevent_context *ev;
166 /*TODO: create a new event context here! */
167 ev = auth_ctx->event_ctx;
169 subreq = auth_check_password_send(mem_ctx,
173 if (subreq == NULL) {
174 return NT_STATUS_NO_MEMORY;
177 ok = tevent_req_poll(subreq, ev);
179 return NT_STATUS_INTERNAL_ERROR;
182 status = auth_check_password_recv(subreq, mem_ctx,
183 user_info_dc, pauthoritative);
189 static NTSTATUS auth_check_password_wrapper(struct auth4_context *auth_ctx,
191 const struct auth_usersupplied_info *user_info,
192 uint8_t *pauthoritative,
193 void **server_returned_info,
194 DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
196 struct auth_user_info_dc *user_info_dc;
199 status = auth_check_password(auth_ctx, mem_ctx, user_info,
200 &user_info_dc, pauthoritative);
201 if (!NT_STATUS_IS_OK(status)) {
205 *server_returned_info = user_info_dc;
207 if (user_session_key) {
208 DEBUG(10, ("Got NT session key of length %u\n",
209 (unsigned)user_info_dc->user_session_key.length));
210 *user_session_key = user_info_dc->user_session_key;
211 talloc_steal(mem_ctx, user_session_key->data);
212 user_info_dc->user_session_key = data_blob_null;
215 if (lm_session_key) {
216 DEBUG(10, ("Got LM session key of length %u\n",
217 (unsigned)user_info_dc->lm_session_key.length));
218 *lm_session_key = user_info_dc->lm_session_key;
219 talloc_steal(mem_ctx, lm_session_key->data);
220 user_info_dc->lm_session_key = data_blob_null;
226 struct auth_check_password_state {
227 struct auth4_context *auth_ctx;
228 const struct auth_usersupplied_info *user_info;
229 struct auth_user_info_dc *user_info_dc;
230 struct auth_method_context *method;
231 uint8_t authoritative;
234 static void auth_check_password_async_trigger(struct tevent_context *ev,
235 struct tevent_immediate *im,
238 * Check a user's Plaintext, LM or NTLM password.
241 * Check a user's password, as given in the user_info struct and return various
242 * interesting details in the user_info_dc struct.
244 * The return value takes precedence over the contents of the user_info_dc
245 * struct. When the return is other than NT_STATUS_OK the contents
246 * of that structure is undefined.
248 * @param mem_ctx The memory context the request should operate on
250 * @param ev The tevent context the request should operate on
252 * @param auth_ctx Supplies the challenges and some other data.
253 * Must be created with make_auth_context(), and the challenges should be
254 * filled in, either at creation or by calling the challenge geneation
255 * function auth_get_challenge().
257 * @param user_info Contains the user supplied components, including the passwords.
259 * @return The request handle or NULL on no memory error.
263 _PUBLIC_ struct tevent_req *auth_check_password_send(TALLOC_CTX *mem_ctx,
264 struct tevent_context *ev,
265 struct auth4_context *auth_ctx,
266 const struct auth_usersupplied_info *user_info)
268 struct tevent_req *req;
269 struct auth_check_password_state *state;
270 /* if all the modules say 'not for me' this is reasonable */
273 struct tevent_immediate *im;
275 DEBUG(3,("auth_check_password_send: "
276 "Checking password for unmapped user [%s]\\[%s]@[%s]\n",
277 user_info->client.domain_name, user_info->client.account_name,
278 user_info->workstation_name));
280 req = tevent_req_create(mem_ctx, &state,
281 struct auth_check_password_state);
287 * We are authoritative by default.
289 state->authoritative = 1;
290 state->auth_ctx = auth_ctx;
291 state->user_info = user_info;
293 if (!user_info->mapped_state) {
294 struct auth_usersupplied_info *user_info_tmp;
297 * We don't really do any mapping here.
299 * So we don't set user_info->mapped_state,
300 * but we set mapped.domain_name and
301 * mapped.account_name to the client
304 * It's up to the backends to do mappings
305 * for their authentication.
307 user_info_tmp = talloc_zero(state, struct auth_usersupplied_info);
308 if (tevent_req_nomem(user_info_tmp, req)) {
309 return tevent_req_post(req, ev);;
313 * The lifetime of user_info is longer than
314 * user_info_tmp, so we don't need to copy the
317 *user_info_tmp = *user_info;
318 user_info_tmp->mapped.domain_name = user_info->client.domain_name;
319 user_info_tmp->mapped.account_name = user_info->client.account_name;
321 user_info = user_info_tmp;
322 state->user_info = user_info_tmp;
325 DEBUGADD(3,("auth_check_password_send: "
326 "user is: [%s]\\[%s]@[%s]\n",
327 user_info->mapped.domain_name,
328 user_info->mapped.account_name,
329 user_info->workstation_name));
331 nt_status = auth_get_challenge(auth_ctx, chal);
332 if (tevent_req_nterror(req, nt_status)) {
333 DEBUG(0,("auth_check_password_send: "
334 "Invalid challenge (length %u) stored for "
335 "this auth context set_by %s - cannot continue: %s\n",
336 (unsigned)auth_ctx->challenge.data.length,
337 auth_ctx->challenge.set_by,
338 nt_errstr(nt_status)));
339 return tevent_req_post(req, ev);
342 if (auth_ctx->challenge.set_by) {
343 DEBUG(10,("auth_check_password_send: "
344 "auth_context challenge created by %s\n",
345 auth_ctx->challenge.set_by));
348 DEBUG(10, ("auth_check_password_send: challenge is: \n"));
349 dump_data(5, auth_ctx->challenge.data.data,
350 auth_ctx->challenge.data.length);
352 im = tevent_create_immediate(state);
353 if (tevent_req_nomem(im, req)) {
354 return tevent_req_post(req, ev);
357 tevent_schedule_immediate(im,
359 auth_check_password_async_trigger,
364 static void auth_check_password_async_trigger(struct tevent_context *ev,
365 struct tevent_immediate *im,
368 struct tevent_req *req =
369 talloc_get_type_abort(private_data, struct tevent_req);
370 struct auth_check_password_state *state =
371 tevent_req_data(req, struct auth_check_password_state);
373 struct auth_method_context *method;
375 status = NT_STATUS_OK;
377 for (method=state->auth_ctx->methods; method; method = method->next) {
379 /* we fill in state->method here so debug messages in
380 the callers know which method failed */
381 state->method = method;
383 /* check if the module wants to check the password */
384 status = method->ops->want_check(method, req, state->user_info);
385 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
386 DEBUG(11,("auth_check_password_send: "
387 "%s doesn't want to check\n",
392 if (tevent_req_nterror(req, status)) {
396 status = method->ops->check_password(method,
399 &state->user_info_dc);
400 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
401 DEBUG(11,("auth_check_password_send: "
402 "%s passes to the next method\n",
407 /* the backend has handled the request */
411 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
412 state->authoritative = 0;
413 status = NT_STATUS_NO_SUCH_USER;
416 if (tevent_req_nterror(req, status)) {
420 tevent_req_done(req);
424 * Check a user's Plaintext, LM or NTLM password.
425 * async receive function
427 * The return value takes precedence over the contents of the user_info_dc
428 * struct. When the return is other than NT_STATUS_OK the contents
429 * of that structure is undefined.
432 * @param req The async request state
434 * @param mem_ctx The parent memory context for the user_info_dc structure
436 * @param user_info_dc If successful, contains information about the authentication,
437 * including a SAM_ACCOUNT struct describing the user.
439 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
443 _PUBLIC_ NTSTATUS auth_check_password_recv(struct tevent_req *req,
445 struct auth_user_info_dc **user_info_dc,
446 uint8_t *pauthoritative)
448 struct auth_check_password_state *state =
449 tevent_req_data(req, struct auth_check_password_state);
450 NTSTATUS status = NT_STATUS_OK;
452 *pauthoritative = state->authoritative;
454 if (tevent_req_is_nterror(req, &status)) {
456 * Please try not to change this string, it is probably in use
457 * in audit logging tools
459 DEBUG(2,("auth_check_password_recv: "
460 "%s authentication for user [%s\\%s] "
461 "FAILED with error %s, authoritative=%u\n",
462 (state->method ? state->method->ops->name : "NO_METHOD"),
463 state->user_info->mapped.domain_name,
464 state->user_info->mapped.account_name,
465 nt_errstr(status), state->authoritative));
467 log_authentication_event(state->auth_ctx->msg_ctx,
468 state->auth_ctx->lp_ctx,
469 state->user_info, status,
470 NULL, NULL, NULL, NULL);
471 tevent_req_received(req);
475 DEBUG(5,("auth_check_password_recv: "
476 "%s authentication for user [%s\\%s] succeeded\n",
477 state->method->ops->name,
478 state->user_info_dc->info->domain_name,
479 state->user_info_dc->info->account_name));
481 log_authentication_event(state->auth_ctx->msg_ctx,
482 state->auth_ctx->lp_ctx,
483 state->user_info, status,
484 state->user_info_dc->info->domain_name,
485 state->user_info_dc->info->account_name,
487 &state->user_info_dc->sids[0]);
489 *user_info_dc = talloc_move(mem_ctx, &state->user_info_dc);
491 tevent_req_received(req);
495 /* Wrapper because we don't want to expose all callers to needing to
496 * know that session_info is generated from the main ldb, and because
497 * we need to break a depenency loop between the DCE/RPC layer and the
498 * generation of unix tokens via IRPC */
499 static NTSTATUS auth_generate_session_info_wrapper(struct auth4_context *auth_context,
501 void *server_returned_info,
502 const char *original_user_name,
503 uint32_t session_info_flags,
504 struct auth_session_info **session_info)
507 struct auth_user_info_dc *user_info_dc = talloc_get_type_abort(server_returned_info, struct auth_user_info_dc);
509 if (user_info_dc->info->authenticated) {
510 session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
513 status = auth_generate_session_info(mem_ctx, auth_context->lp_ctx,
514 auth_context->sam_ctx, user_info_dc,
515 session_info_flags, session_info);
516 if (!NT_STATUS_IS_OK(status)) {
520 if ((session_info_flags & AUTH_SESSION_INFO_UNIX_TOKEN)
521 && NT_STATUS_IS_OK(status)) {
522 status = auth_session_info_fill_unix(auth_context->event_ctx,
523 auth_context->lp_ctx,
524 original_user_name, *session_info);
525 if (!NT_STATUS_IS_OK(status)) {
526 TALLOC_FREE(*session_info);
532 /* Wrapper because we don't want to expose all callers to needing to
533 * know anything about the PAC or auth subsystem internal structures
534 * before we output a struct auth session_info */
535 static NTSTATUS auth_generate_session_info_pac(struct auth4_context *auth_ctx,
537 struct smb_krb5_context *smb_krb5_context,
539 const char *principal_name,
540 const struct tsocket_address *remote_address,
541 uint32_t session_info_flags,
542 struct auth_session_info **session_info)
545 struct auth_user_info_dc *user_info_dc;
549 return auth_generate_session_info_principal(auth_ctx, mem_ctx, principal_name,
550 NULL, session_info_flags, session_info);
553 tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gssapi_session_info context");
554 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
556 status = kerberos_pac_blob_to_user_info_dc(tmp_ctx,
558 smb_krb5_context->krb5_context,
559 &user_info_dc, NULL, NULL);
560 if (!NT_STATUS_IS_OK(status)) {
561 talloc_free(tmp_ctx);
565 if (user_info_dc->info->authenticated) {
566 session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
569 status = auth_generate_session_info_wrapper(auth_ctx, mem_ctx,
571 user_info_dc->info->account_name,
572 session_info_flags, session_info);
573 talloc_free(tmp_ctx);
577 /***************************************************************************
578 Make a auth_info struct for the auth subsystem
579 - Allow the caller to specify the methods to use, including optionally the SAM to use
580 ***************************************************************************/
581 _PUBLIC_ NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char * const *methods,
582 struct tevent_context *ev,
583 struct imessaging_context *msg,
584 struct loadparm_context *lp_ctx,
585 struct ldb_context *sam_ctx,
586 struct auth4_context **auth_ctx)
589 struct auth4_context *ctx;
594 DEBUG(0,("auth_context_create: called with out event context\n"));
595 return NT_STATUS_INTERNAL_ERROR;
598 ctx = talloc_zero(mem_ctx, struct auth4_context);
599 NT_STATUS_HAVE_NO_MEMORY(ctx);
600 ctx->challenge.data = data_blob(NULL, 0);
604 ctx->lp_ctx = lp_ctx;
607 ctx->sam_ctx = sam_ctx;
609 ctx->sam_ctx = samdb_connect(ctx, ctx->event_ctx, ctx->lp_ctx, system_session(ctx->lp_ctx), 0);
612 for (i=0; methods && methods[i] ; i++) {
613 struct auth_method_context *method;
615 method = talloc(ctx, struct auth_method_context);
616 NT_STATUS_HAVE_NO_MEMORY(method);
618 method->ops = auth_backend_byname(methods[i]);
620 DEBUG(1,("auth_context_create: failed to find method=%s\n",
622 return NT_STATUS_INTERNAL_ERROR;
624 method->auth_ctx = ctx;
626 DLIST_ADD_END(ctx->methods, method);
629 ctx->check_ntlm_password = auth_check_password_wrapper;
630 ctx->get_ntlm_challenge = auth_get_challenge;
631 ctx->set_ntlm_challenge = auth_context_set_challenge;
632 ctx->generate_session_info = auth_generate_session_info_wrapper;
633 ctx->generate_session_info_pac = auth_generate_session_info_pac;
640 const char **auth_methods_from_lp(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
642 char **auth_methods = NULL;
643 const char **const_auth_methods = NULL;
646 * As 'auth methods' is deprecated it will be removed
647 * in future releases again, but for now give
648 * admins the flexibility to configure, the behavior
649 * from Samba 4.6: "auth methods = anonymous sam_ignoredomain",
652 const_auth_methods = lpcfg_auth_methods(lp_ctx);
653 if (const_auth_methods != NULL) {
654 DBG_NOTICE("using deprecated 'auth methods' values.\n");
655 return const_auth_methods;
658 switch (lpcfg_server_role(lp_ctx)) {
659 case ROLE_STANDALONE:
660 auth_methods = str_list_make(mem_ctx, "anonymous sam_ignoredomain", NULL);
662 case ROLE_DOMAIN_MEMBER:
663 auth_methods = str_list_make(mem_ctx, "anonymous sam winbind sam_ignoredomain", NULL);
665 case ROLE_DOMAIN_BDC:
666 case ROLE_DOMAIN_PDC:
667 case ROLE_ACTIVE_DIRECTORY_DC:
669 * TODO: we should replace "winbind_rodc sam_failtrusts" with "winbind"
670 * if everything (gensec/auth4) is fully async without nested
673 * But for now we'll fail authentications for trusted
674 * domain consistently with NT_STATUS_NO_TRUST_LSA_SECRET,
675 * instead of silently mapping to local users.
677 auth_methods = str_list_make(mem_ctx,
679 "winbind_rodc sam_failtrusts "
684 return discard_const_p(const char *, auth_methods);
687 /***************************************************************************
688 Make a auth_info struct for the auth subsystem
689 - Uses default auth_methods, depending on server role and smb.conf settings
690 ***************************************************************************/
691 _PUBLIC_ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx,
692 struct tevent_context *ev,
693 struct imessaging_context *msg,
694 struct loadparm_context *lp_ctx,
695 struct auth4_context **auth_ctx)
698 const char **auth_methods;
699 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
701 return NT_STATUS_NO_MEMORY;
704 auth_methods = auth_methods_from_lp(tmp_ctx, lp_ctx);
706 return NT_STATUS_INVALID_PARAMETER;
708 status = auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, NULL, auth_ctx);
709 talloc_free(tmp_ctx);
713 _PUBLIC_ NTSTATUS auth_context_create_for_netlogon(TALLOC_CTX *mem_ctx,
714 struct tevent_context *ev,
715 struct imessaging_context *msg,
716 struct loadparm_context *lp_ctx,
717 struct auth4_context **auth_ctx)
720 char **_auth_methods = NULL;
721 const char **auth_methods = NULL;
724 * As 'auth methods' is deprecated it will be removed
725 * in future releases again, but for now give
726 * admins the flexibility to configure, the behavior
727 * from Samba 4.6: "auth methods = anonymous sam_ignoredomain",
730 auth_methods = lpcfg_auth_methods(lp_ctx);
731 if (auth_methods != NULL) {
732 DBG_NOTICE("using deprecated 'auth methods' values.\n");
735 * We can remove "winbind_rodc sam_failtrusts",
736 * when we made the netlogon retries to
737 * to contact winbind via irpc.
739 _auth_methods = str_list_make(mem_ctx,
741 "winbind_rodc sam_failtrusts",
743 if (_auth_methods == NULL) {
744 return NT_STATUS_NO_MEMORY;
746 auth_methods = discard_const_p(const char *, _auth_methods);
749 status = auth_context_create_methods(mem_ctx, auth_methods, ev, msg,
750 lp_ctx, NULL, auth_ctx);
751 talloc_free(_auth_methods);
755 /* the list of currently registered AUTH backends */
756 static struct auth_backend {
757 const struct auth_operations *ops;
759 static int num_backends;
762 register a AUTH backend.
764 The 'name' can be later used by other backends to find the operations
765 structure for this backend.
767 _PUBLIC_ NTSTATUS auth_register(const struct auth_operations *ops)
769 struct auth_operations *new_ops;
771 if (auth_backend_byname(ops->name) != NULL) {
772 /* its already registered! */
773 DEBUG(0,("AUTH backend '%s' already registered\n",
775 return NT_STATUS_OBJECT_NAME_COLLISION;
778 backends = talloc_realloc(talloc_autofree_context(), backends,
779 struct auth_backend, num_backends+1);
780 NT_STATUS_HAVE_NO_MEMORY(backends);
782 new_ops = (struct auth_operations *)talloc_memdup(backends, ops, sizeof(*ops));
783 NT_STATUS_HAVE_NO_MEMORY(new_ops);
784 new_ops->name = talloc_strdup(new_ops, ops->name);
785 NT_STATUS_HAVE_NO_MEMORY(new_ops->name);
787 backends[num_backends].ops = new_ops;
791 DEBUG(3,("AUTH backend '%s' registered\n",
798 return the operations structure for a named backend of the specified type
800 const struct auth_operations *auth_backend_byname(const char *name)
804 for (i=0;i<num_backends;i++) {
805 if (strcmp(backends[i].ops->name, name) == 0) {
806 return backends[i].ops;
814 return the AUTH interface version, and the size of some critical types
815 This can be used by backends to either detect compilation errors, or provide
816 multiple implementations for different smbd compilation options in one module
818 const struct auth_critical_sizes *auth_interface_version(void)
820 static const struct auth_critical_sizes critical_sizes = {
821 AUTH4_INTERFACE_VERSION,
822 sizeof(struct auth_operations),
823 sizeof(struct auth_method_context),
824 sizeof(struct auth4_context),
825 sizeof(struct auth_usersupplied_info),
826 sizeof(struct auth_user_info_dc)
829 return &critical_sizes;
832 _PUBLIC_ NTSTATUS auth4_init(void)
834 static bool initialized = false;
835 #define _MODULE_PROTO(init) extern NTSTATUS init(TALLOC_CTX *);
836 STATIC_auth4_MODULES_PROTO;
837 init_module_fn static_init[] = { STATIC_auth4_MODULES };
839 if (initialized) return NT_STATUS_OK;
842 run_init_functions(NULL, static_init);