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"
38 #define DBGC_CLASS DBGC_AUTH
40 static NTSTATUS auth_generate_session_info_wrapper(struct auth4_context *auth_context,
42 void *server_returned_info,
43 const char *original_user_name,
44 uint32_t session_info_flags,
45 struct auth_session_info **session_info);
47 /***************************************************************************
49 ***************************************************************************/
50 _PUBLIC_ NTSTATUS auth_context_set_challenge(struct auth4_context *auth_ctx, const uint8_t chal[8], const char *set_by)
52 auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
53 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
55 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
56 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
61 /****************************************************************************
62 Try to get a challenge out of the various authentication modules.
63 Returns a const char of length 8 bytes.
64 ****************************************************************************/
65 _PUBLIC_ NTSTATUS auth_get_challenge(struct auth4_context *auth_ctx, uint8_t chal[8])
68 if (auth_ctx->challenge.data.length == 8) {
69 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
70 auth_ctx->challenge.set_by));
71 memcpy(chal, auth_ctx->challenge.data.data, 8);
75 if (!auth_ctx->challenge.set_by) {
76 generate_random_buffer(chal, 8);
78 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
79 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
80 auth_ctx->challenge.set_by = "random";
83 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
84 auth_ctx->challenge.set_by));
90 * Check a user's Plaintext, LM or NTLM password.
93 * Check a user's password, as given in the user_info struct and return various
94 * interesting details in the user_info_dc struct.
96 * The return value takes precedence over the contents of the user_info_dc
97 * struct. When the return is other than NT_STATUS_OK the contents
98 * of that structure is undefined.
100 * @param auth_ctx Supplies the challenges and some other data.
101 * Must be created with auth_context_create(), and the challenges should be
102 * filled in, either at creation or by calling the challenge generation
103 * function auth_get_challenge().
105 * @param user_info Contains the user supplied components, including the passwords.
107 * @param mem_ctx The parent memory context for the user_info_dc structure
109 * @param user_info_dc If successful, contains information about the authentication,
110 * including a SAM_ACCOUNT struct describing the user.
112 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
116 _PUBLIC_ NTSTATUS auth_check_password(struct auth4_context *auth_ctx,
118 const struct auth_usersupplied_info *user_info,
119 struct auth_user_info_dc **user_info_dc,
120 uint8_t *pauthoritative)
122 struct tevent_req *subreq;
123 struct tevent_context *ev;
127 /*TODO: create a new event context here! */
128 ev = auth_ctx->event_ctx;
131 * We are authoritative by default
135 subreq = auth_check_password_send(mem_ctx,
139 if (subreq == NULL) {
140 return NT_STATUS_NO_MEMORY;
143 ok = tevent_req_poll(subreq, ev);
145 return NT_STATUS_INTERNAL_ERROR;
148 status = auth_check_password_recv(subreq, mem_ctx,
149 user_info_dc, pauthoritative);
155 struct auth_check_password_state {
156 struct tevent_context *ev;
157 struct auth4_context *auth_ctx;
158 const struct auth_usersupplied_info *user_info;
159 struct auth_user_info_dc *user_info_dc;
160 struct auth_method_context *method;
161 const struct authn_audit_info *client_audit_info;
162 const struct authn_audit_info *server_audit_info;
163 uint8_t authoritative;
166 static void auth_check_password_next(struct tevent_req *req);
169 * Check a user's Plaintext, LM or NTLM password.
172 * Check a user's password, as given in the user_info struct and return various
173 * interesting details in the user_info_dc struct.
175 * The return value takes precedence over the contents of the user_info_dc
176 * struct. When the return is other than NT_STATUS_OK the contents
177 * of that structure is undefined.
179 * @param mem_ctx The memory context the request should operate on
181 * @param ev The tevent context the request should operate on
183 * @param auth_ctx Supplies the challenges and some other data. Must
184 * be created with make_auth_context(), and the
185 * challenges should be filled in, either at creation
186 * or by calling the challenge generation function
187 * auth_get_challenge().
189 * @param user_info Contains the user supplied components, including the passwords.
191 * @return The request handle or NULL on no memory error.
195 _PUBLIC_ struct tevent_req *auth_check_password_send(TALLOC_CTX *mem_ctx,
196 struct tevent_context *ev,
197 struct auth4_context *auth_ctx,
198 const struct auth_usersupplied_info *user_info)
200 struct tevent_req *req;
201 struct auth_check_password_state *state;
202 /* if all the modules say 'not for me' this is reasonable */
206 DEBUG(3,("auth_check_password_send: "
207 "Checking password for unmapped user [%s]\\[%s]@[%s]\n",
208 user_info->client.domain_name, user_info->client.account_name,
209 user_info->workstation_name));
211 req = tevent_req_create(mem_ctx, &state,
212 struct auth_check_password_state);
218 * We are authoritative by default.
221 state->auth_ctx = auth_ctx;
222 state->user_info = user_info;
223 state->authoritative = 1;
225 if (user_info->mapped.account_name == NULL) {
226 struct auth_usersupplied_info *user_info_tmp;
229 * We don't really do any mapping here.
231 * It's up to the backends to do mappings
232 * for their authentication.
234 user_info_tmp = talloc_zero(state, struct auth_usersupplied_info);
235 if (tevent_req_nomem(user_info_tmp, req)) {
236 return tevent_req_post(req, ev);
240 * The lifetime of user_info is longer than
241 * user_info_tmp, so we don't need to copy the
244 *user_info_tmp = *user_info;
245 user_info_tmp->mapped.domain_name = user_info->client.domain_name;
246 user_info_tmp->mapped.account_name = user_info->client.account_name;
248 user_info = user_info_tmp;
249 state->user_info = user_info_tmp;
252 DEBUGADD(3,("auth_check_password_send: "
253 "user is: [%s]\\[%s]@[%s]\n",
254 user_info->mapped.domain_name,
255 user_info->mapped.account_name,
256 user_info->workstation_name));
258 nt_status = auth_get_challenge(auth_ctx, chal);
259 if (tevent_req_nterror(req, nt_status)) {
260 DEBUG(0,("auth_check_password_send: "
261 "Invalid challenge (length %u) stored for "
262 "this auth context set_by %s - cannot continue: %s\n",
263 (unsigned)auth_ctx->challenge.data.length,
264 auth_ctx->challenge.set_by,
265 nt_errstr(nt_status)));
266 return tevent_req_post(req, ev);
269 if (auth_ctx->challenge.set_by) {
270 DEBUG(10,("auth_check_password_send: "
271 "auth_context challenge created by %s\n",
272 auth_ctx->challenge.set_by));
275 DEBUG(10, ("auth_check_password_send: challenge is: \n"));
276 dump_data(5, auth_ctx->challenge.data.data,
277 auth_ctx->challenge.data.length);
279 state->method = state->auth_ctx->methods;
280 auth_check_password_next(req);
281 if (!tevent_req_is_in_progress(req)) {
282 return tevent_req_post(req, ev);
288 static void auth_check_password_done(struct tevent_req *subreq);
290 static void auth_check_password_next(struct tevent_req *req)
292 struct auth_check_password_state *state =
293 tevent_req_data(req, struct auth_check_password_state);
294 struct tevent_req *subreq = NULL;
297 if (state->method == NULL) {
298 state->authoritative = 0;
299 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
303 /* check if the module wants to check the password */
304 status = state->method->ops->want_check(state->method, state,
306 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
307 DEBUG(11,("auth_check_password_send: "
308 "%s doesn't want to check\n",
309 state->method->ops->name));
310 state->method = state->method->next;
311 auth_check_password_next(req);
315 if (tevent_req_nterror(req, status)) {
319 subreq = state->method->ops->check_password_send(
320 state, state->ev, state->method, state->user_info);
321 if (tevent_req_nomem(subreq, req)) {
324 tevent_req_set_callback(subreq, auth_check_password_done, req);
327 static void auth_check_password_done(struct tevent_req *subreq)
329 struct tevent_req *req =
330 tevent_req_callback_data(subreq,
332 struct auth_check_password_state *state =
334 struct auth_check_password_state);
335 bool authoritative = true;
338 status = state->method->ops->check_password_recv(subreq, state,
339 &state->user_info_dc,
340 &state->client_audit_info,
341 &state->server_audit_info,
344 if (!authoritative ||
345 NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
346 DEBUG(11,("auth_check_password_send: "
347 "%s passes to the next method\n",
348 state->method->ops->name));
349 state->method = state->method->next;
350 auth_check_password_next(req);
354 /* the backend has handled the request */
356 if (tevent_req_nterror(req, status)) {
360 tevent_req_done(req);
364 * Check a user's Plaintext, LM or NTLM password.
365 * async receive function
367 * The return value takes precedence over the contents of the user_info_dc
368 * struct. When the return is other than NT_STATUS_OK the contents
369 * of that structure is undefined.
372 * @param req The async request state
374 * @param mem_ctx The parent memory context for the user_info_dc structure
376 * @param user_info_dc If successful, contains information about the authentication,
377 * including a SAM_ACCOUNT struct describing the user.
379 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
383 _PUBLIC_ NTSTATUS auth_check_password_recv(struct tevent_req *req,
385 struct auth_user_info_dc **user_info_dc,
386 uint8_t *pauthoritative)
388 struct auth_check_password_state *state =
389 tevent_req_data(req, struct auth_check_password_state);
390 NTSTATUS status = NT_STATUS_OK;
392 *pauthoritative = state->authoritative;
394 if (tevent_req_is_nterror(req, &status)) {
396 * Please try not to change this string, it is probably in use
397 * in audit logging tools
399 DEBUG(2,("auth_check_password_recv: "
400 "%s authentication for user [%s\\%s] "
401 "FAILED with error %s, authoritative=%u\n",
402 (state->method ? state->method->ops->name : "NO_METHOD"),
403 state->user_info->mapped.domain_name,
404 state->user_info->mapped.account_name,
405 nt_errstr(status), state->authoritative));
407 log_authentication_event(state->auth_ctx->msg_ctx,
408 state->auth_ctx->lp_ctx,
409 &state->auth_ctx->start_time,
410 state->user_info, status,
412 state->client_audit_info,
413 state->server_audit_info);
414 tevent_req_received(req);
418 DEBUG(5,("auth_check_password_recv: "
419 "%s authentication for user [%s\\%s] succeeded\n",
420 state->method->ops->name,
421 state->user_info_dc->info->domain_name,
422 state->user_info_dc->info->account_name));
424 log_authentication_event(state->auth_ctx->msg_ctx,
425 state->auth_ctx->lp_ctx,
426 &state->auth_ctx->start_time,
427 state->user_info, status,
428 state->user_info_dc->info->domain_name,
429 state->user_info_dc->info->account_name,
430 &state->user_info_dc->sids[PRIMARY_USER_SID_INDEX].sid,
431 state->client_audit_info,
432 state->server_audit_info);
435 * Release our handle to state->user_info_dc.
436 * state->{client,server}_audit_info, if non-NULL, becomes the new
439 *user_info_dc = talloc_reparent(state, mem_ctx, state->user_info_dc);
440 state->user_info_dc = NULL;
442 tevent_req_received(req);
446 struct auth_check_password_wrapper_state {
447 uint8_t authoritative;
448 struct auth_user_info_dc *user_info_dc;
451 static void auth_check_password_wrapper_done(struct tevent_req *subreq);
453 static struct tevent_req *auth_check_password_wrapper_send(TALLOC_CTX *mem_ctx,
454 struct tevent_context *ev,
455 struct auth4_context *auth_ctx,
456 const struct auth_usersupplied_info *user_info)
458 struct tevent_req *req = NULL;
459 struct auth_check_password_wrapper *state = NULL;
460 struct tevent_req *subreq = NULL;
462 req = tevent_req_create(mem_ctx, &state,
463 struct auth_check_password_wrapper_state);
468 subreq = auth_check_password_send(state, ev, auth_ctx, user_info);
469 if (tevent_req_nomem(subreq, req)) {
470 return tevent_req_post(req, ev);
472 tevent_req_set_callback(subreq,
473 auth_check_password_wrapper_done,
479 static void auth_check_password_wrapper_done(struct tevent_req *subreq)
481 struct tevent_req *req =
482 tevent_req_callback_data(subreq,
484 struct auth_check_password_wrapper_state *state =
486 struct auth_check_password_wrapper_state);
489 status = auth_check_password_recv(subreq, state,
490 &state->user_info_dc,
491 &state->authoritative);
493 if (tevent_req_nterror(req, status)) {
497 tevent_req_done(req);
500 static NTSTATUS auth_check_password_wrapper_recv(struct tevent_req *req,
502 uint8_t *pauthoritative,
503 void **server_returned_info,
504 DATA_BLOB *user_session_key,
505 DATA_BLOB *lm_session_key)
507 struct auth_check_password_wrapper_state *state =
509 struct auth_check_password_wrapper_state);
510 struct auth_user_info_dc *user_info_dc = state->user_info_dc;
511 NTSTATUS status = NT_STATUS_OK;
513 *pauthoritative = state->authoritative;
515 if (tevent_req_is_nterror(req, &status)) {
516 tevent_req_received(req);
520 talloc_steal(mem_ctx, user_info_dc);
521 *server_returned_info = user_info_dc;
523 if (user_session_key) {
524 DEBUG(10, ("Got NT session key of length %u\n",
525 (unsigned)user_info_dc->user_session_key.length));
526 *user_session_key = user_info_dc->user_session_key;
527 talloc_steal(mem_ctx, user_session_key->data);
528 user_info_dc->user_session_key = data_blob_null;
531 if (lm_session_key) {
532 DEBUG(10, ("Got LM session key of length %u\n",
533 (unsigned)user_info_dc->lm_session_key.length));
534 *lm_session_key = user_info_dc->lm_session_key;
535 talloc_steal(mem_ctx, lm_session_key->data);
536 user_info_dc->lm_session_key = data_blob_null;
539 tevent_req_received(req);
543 /* Wrapper because we don't want to expose all callers to needing to
544 * know that session_info is generated from the main ldb, and because
545 * we need to break a dependency loop between the DCE/RPC layer and the
546 * generation of unix tokens via IRPC */
547 static NTSTATUS auth_generate_session_info_wrapper(struct auth4_context *auth_context,
549 void *server_returned_info,
550 const char *original_user_name,
551 uint32_t session_info_flags,
552 struct auth_session_info **session_info)
555 struct auth_user_info_dc *user_info_dc = talloc_get_type_abort(server_returned_info, struct auth_user_info_dc);
557 if (!(user_info_dc->info->user_flags & NETLOGON_GUEST)) {
558 session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
561 status = auth_generate_session_info(mem_ctx,
562 auth_context->lp_ctx,
563 auth_context->sam_ctx,
567 if (!NT_STATUS_IS_OK(status)) {
571 if ((session_info_flags & AUTH_SESSION_INFO_UNIX_TOKEN)
572 && NT_STATUS_IS_OK(status)) {
573 status = auth_session_info_fill_unix(auth_context->lp_ctx,
576 if (!NT_STATUS_IS_OK(status)) {
577 TALLOC_FREE(*session_info);
583 /* Wrapper because we don't want to expose all callers to needing to
584 * know anything about the PAC or auth subsystem internal structures
585 * before we output a struct auth session_info */
586 static NTSTATUS auth_generate_session_info_pac(struct auth4_context *auth_ctx,
588 struct smb_krb5_context *smb_krb5_context,
590 const char *principal_name,
591 const struct tsocket_address *remote_address,
592 uint32_t session_info_flags,
593 struct auth_session_info **session_info)
596 struct auth_user_info_dc *user_info_dc;
601 * This should already have been caught at the main
602 * gensec layer, but better check twice
604 return NT_STATUS_INTERNAL_ERROR;
607 tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gssapi_session_info context");
608 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
611 * FIXME: To correctly create the security token, we also need to get the
612 * claims info, device info, and device claims info from the PAC. For now,
613 * we support claims only in the KDC.
615 status = kerberos_pac_blob_to_user_info_dc(tmp_ctx,
617 smb_krb5_context->krb5_context,
618 &user_info_dc, NULL, NULL);
619 if (!NT_STATUS_IS_OK(status)) {
620 talloc_free(tmp_ctx);
624 if (!(user_info_dc->info->user_flags & NETLOGON_GUEST)) {
625 session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
628 status = auth_generate_session_info_wrapper(auth_ctx, mem_ctx,
630 user_info_dc->info->account_name,
631 session_info_flags, session_info);
632 talloc_free(tmp_ctx);
636 /***************************************************************************
637 Make a auth_info struct for the auth subsystem
638 - Allow the caller to specify the methods to use, including optionally the SAM to use
639 ***************************************************************************/
640 _PUBLIC_ NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char * const *methods,
641 struct tevent_context *ev,
642 struct imessaging_context *msg,
643 struct loadparm_context *lp_ctx,
644 struct ldb_context *sam_ctx,
645 struct auth4_context **auth_ctx)
648 struct auth4_context *ctx;
653 DEBUG(0,("auth_context_create: called with out event context\n"));
654 return NT_STATUS_INTERNAL_ERROR;
657 ctx = talloc_zero(mem_ctx, struct auth4_context);
658 NT_STATUS_HAVE_NO_MEMORY(ctx);
659 ctx->challenge.data = data_blob(NULL, 0);
663 ctx->lp_ctx = lp_ctx;
664 ctx->start_time = timeval_current();
667 ctx->sam_ctx = sam_ctx;
669 ctx->sam_ctx = samdb_connect(ctx,
672 system_session(ctx->lp_ctx),
677 for (i=0; methods && methods[i] ; i++) {
678 struct auth_method_context *method;
680 method = talloc(ctx, struct auth_method_context);
681 NT_STATUS_HAVE_NO_MEMORY(method);
683 method->ops = auth_backend_byname(methods[i]);
685 DEBUG(1,("auth_context_create: failed to find method=%s\n",
687 return NT_STATUS_INTERNAL_ERROR;
689 method->auth_ctx = ctx;
691 DLIST_ADD_END(ctx->methods, method);
694 ctx->check_ntlm_password_send = auth_check_password_wrapper_send;
695 ctx->check_ntlm_password_recv = auth_check_password_wrapper_recv;
696 ctx->get_ntlm_challenge = auth_get_challenge;
697 ctx->set_ntlm_challenge = auth_context_set_challenge;
698 ctx->generate_session_info = auth_generate_session_info_wrapper;
699 ctx->generate_session_info_pac = auth_generate_session_info_pac;
706 const char **auth_methods_from_lp(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
708 char **auth_methods = NULL;
710 switch (lpcfg_server_role(lp_ctx)) {
711 case ROLE_STANDALONE:
712 auth_methods = str_list_make(mem_ctx, "anonymous sam_ignoredomain", NULL);
714 case ROLE_DOMAIN_MEMBER:
715 case ROLE_DOMAIN_BDC:
716 case ROLE_DOMAIN_PDC:
717 case ROLE_ACTIVE_DIRECTORY_DC:
719 auth_methods = str_list_make(mem_ctx, "anonymous sam winbind sam_ignoredomain", NULL);
722 return discard_const_p(const char *, auth_methods);
725 /***************************************************************************
726 Make a auth_info struct for the auth subsystem
727 - Uses default auth_methods, depending on server role and smb.conf settings
728 ***************************************************************************/
729 _PUBLIC_ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx,
730 struct tevent_context *ev,
731 struct imessaging_context *msg,
732 struct loadparm_context *lp_ctx,
733 struct auth4_context **auth_ctx)
736 const char **auth_methods;
737 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
739 return NT_STATUS_NO_MEMORY;
742 auth_methods = auth_methods_from_lp(tmp_ctx, lp_ctx);
744 return NT_STATUS_INVALID_PARAMETER;
746 status = auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, NULL, auth_ctx);
747 talloc_free(tmp_ctx);
751 _PUBLIC_ NTSTATUS auth_context_create_for_netlogon(TALLOC_CTX *mem_ctx,
752 struct tevent_context *ev,
753 struct imessaging_context *msg,
754 struct loadparm_context *lp_ctx,
755 struct auth4_context **auth_ctx)
758 char **_auth_methods = NULL;
759 const char **auth_methods = NULL;
762 * Here we only allow 'sam winbind' instead of
763 * the 'anonymous sam winbind sam_ignoredomain'
764 * we typically use for authentication from clients.
766 _auth_methods = str_list_make(mem_ctx, "sam winbind", NULL);
767 if (_auth_methods == NULL) {
768 return NT_STATUS_NO_MEMORY;
770 auth_methods = discard_const_p(const char *, _auth_methods);
772 status = auth_context_create_methods(mem_ctx, auth_methods, ev, msg,
773 lp_ctx, NULL, auth_ctx);
774 talloc_free(_auth_methods);
778 /* the list of currently registered AUTH backends */
779 static struct auth_backend {
780 const struct auth_operations *ops;
782 static int num_backends;
785 register a AUTH backend.
787 The 'name' can be later used by other backends to find the operations
788 structure for this backend.
790 _PUBLIC_ NTSTATUS auth_register(TALLOC_CTX *mem_ctx,
791 const struct auth_operations *ops)
793 struct auth_operations *new_ops;
795 if (auth_backend_byname(ops->name) != NULL) {
796 /* its already registered! */
797 DEBUG(0,("AUTH backend '%s' already registered\n",
799 return NT_STATUS_OBJECT_NAME_COLLISION;
802 backends = talloc_realloc(mem_ctx, backends,
803 struct auth_backend, num_backends+1);
804 NT_STATUS_HAVE_NO_MEMORY(backends);
806 new_ops = (struct auth_operations *)talloc_memdup(backends, ops, sizeof(*ops));
807 NT_STATUS_HAVE_NO_MEMORY(new_ops);
808 new_ops->name = talloc_strdup(new_ops, ops->name);
809 NT_STATUS_HAVE_NO_MEMORY(new_ops->name);
811 backends[num_backends].ops = new_ops;
815 DEBUG(3,("AUTH backend '%s' registered\n",
822 return the operations structure for a named backend of the specified type
824 const struct auth_operations *auth_backend_byname(const char *name)
828 for (i=0;i<num_backends;i++) {
829 if (strcmp(backends[i].ops->name, name) == 0) {
830 return backends[i].ops;
838 return the AUTH interface version, and the size of some critical types
839 This can be used by backends to either detect compilation errors, or provide
840 multiple implementations for different smbd compilation options in one module
842 const struct auth_critical_sizes *auth_interface_version(void)
844 static const struct auth_critical_sizes critical_sizes = {
845 AUTH4_INTERFACE_VERSION,
846 sizeof(struct auth_operations),
847 sizeof(struct auth_method_context),
848 sizeof(struct auth4_context),
849 sizeof(struct auth_usersupplied_info),
850 sizeof(struct auth_user_info_dc)
853 return &critical_sizes;
856 _PUBLIC_ NTSTATUS auth4_init(void)
858 static bool initialized = false;
859 #define _MODULE_PROTO(init) extern NTSTATUS init(TALLOC_CTX *);
860 STATIC_auth4_MODULES_PROTO;
861 init_module_fn static_init[] = { STATIC_auth4_MODULES };
863 if (initialized) return NT_STATUS_OK;
866 run_init_functions(NULL, static_init);