s3:smb2_sesssetup: add support for SMB 2.24/3.00 signing
[Samba/gebeck_regimport.git] / source4 / auth / ntlm / auth.c
blobd0ff50afc6e9588e957b755bda5d6a6738bfefe9
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 Set a fixed challenge
59 ***************************************************************************/
60 _PUBLIC_ bool auth_challenge_may_be_modified(struct auth4_context *auth_ctx)
62 return auth_ctx->challenge.may_be_modified;
65 /****************************************************************************
66 Try to get a challenge out of the various authentication modules.
67 Returns a const char of length 8 bytes.
68 ****************************************************************************/
69 _PUBLIC_ NTSTATUS auth_get_challenge(struct auth4_context *auth_ctx, uint8_t chal[8])
71 NTSTATUS nt_status;
72 struct auth_method_context *method;
74 if (auth_ctx->challenge.data.length == 8) {
75 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
76 auth_ctx->challenge.set_by));
77 memcpy(chal, auth_ctx->challenge.data.data, 8);
78 return NT_STATUS_OK;
81 for (method = auth_ctx->methods; method; method = method->next) {
82 nt_status = method->ops->get_challenge(method, auth_ctx, chal);
83 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
84 continue;
87 NT_STATUS_NOT_OK_RETURN(nt_status);
89 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
90 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
91 auth_ctx->challenge.set_by = method->ops->name;
93 break;
96 if (!auth_ctx->challenge.set_by) {
97 generate_random_buffer(chal, 8);
99 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
100 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
101 auth_ctx->challenge.set_by = "random";
103 auth_ctx->challenge.may_be_modified = true;
106 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
107 auth_ctx->challenge.set_by));
109 return NT_STATUS_OK;
112 /****************************************************************************
113 Used in the gensec_gssapi and gensec_krb5 server-side code, where the
114 PAC isn't available, and for tokenGroups in the DSDB stack.
116 Supply either a principal or a DN
117 ****************************************************************************/
118 static NTSTATUS auth_generate_session_info_principal(struct auth4_context *auth_ctx,
119 TALLOC_CTX *mem_ctx,
120 const char *principal,
121 struct ldb_dn *user_dn,
122 uint32_t session_info_flags,
123 struct auth_session_info **session_info)
125 NTSTATUS nt_status;
126 struct auth_method_context *method;
127 struct auth_user_info_dc *user_info_dc;
129 for (method = auth_ctx->methods; method; method = method->next) {
130 if (!method->ops->get_user_info_dc_principal) {
131 continue;
134 nt_status = method->ops->get_user_info_dc_principal(mem_ctx, auth_ctx, principal, user_dn, &user_info_dc);
135 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
136 continue;
138 if (!NT_STATUS_IS_OK(nt_status)) {
139 return nt_status;
142 nt_status = auth_generate_session_info_wrapper(auth_ctx, mem_ctx,
143 user_info_dc,
144 user_info_dc->info->account_name,
145 session_info_flags, session_info);
146 talloc_free(user_info_dc);
148 return nt_status;
151 return NT_STATUS_NOT_IMPLEMENTED;
155 * Check a user's Plaintext, LM or NTLM password.
156 * (sync version)
158 * Check a user's password, as given in the user_info struct and return various
159 * interesting details in the user_info_dc struct.
161 * The return value takes precedence over the contents of the user_info_dc
162 * struct. When the return is other than NT_STATUS_OK the contents
163 * of that structure is undefined.
165 * @param auth_ctx Supplies the challenges and some other data.
166 * Must be created with auth_context_create(), and the challenges should be
167 * filled in, either at creation or by calling the challenge geneation
168 * function auth_get_challenge().
170 * @param user_info Contains the user supplied components, including the passwords.
172 * @param mem_ctx The parent memory context for the user_info_dc structure
174 * @param user_info_dc If successful, contains information about the authentication,
175 * including a SAM_ACCOUNT struct describing the user.
177 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
181 _PUBLIC_ NTSTATUS auth_check_password(struct auth4_context *auth_ctx,
182 TALLOC_CTX *mem_ctx,
183 const struct auth_usersupplied_info *user_info,
184 struct auth_user_info_dc **user_info_dc)
186 struct tevent_req *subreq;
187 struct tevent_context *ev;
188 bool ok;
189 NTSTATUS status;
191 /*TODO: create a new event context here! */
192 ev = auth_ctx->event_ctx;
194 subreq = auth_check_password_send(mem_ctx,
196 auth_ctx,
197 user_info);
198 if (subreq == NULL) {
199 return NT_STATUS_NO_MEMORY;
202 ok = tevent_req_poll(subreq, ev);
203 if (!ok) {
204 return NT_STATUS_INTERNAL_ERROR;
207 status = auth_check_password_recv(subreq, mem_ctx, user_info_dc);
208 TALLOC_FREE(subreq);
210 return status;
213 _PUBLIC_ NTSTATUS auth_check_password_wrapper(struct auth4_context *auth_ctx,
214 TALLOC_CTX *mem_ctx,
215 const struct auth_usersupplied_info *user_info,
216 void **server_returned_info,
217 DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
219 struct auth_user_info_dc *user_info_dc;
220 NTSTATUS status = auth_check_password(auth_ctx, mem_ctx, user_info, &user_info_dc);
222 if (NT_STATUS_IS_OK(status)) {
223 *server_returned_info = user_info_dc;
225 if (user_session_key) {
226 DEBUG(10, ("Got NT session key of length %u\n",
227 (unsigned)user_info_dc->user_session_key.length));
228 *user_session_key = user_info_dc->user_session_key;
229 talloc_steal(mem_ctx, user_session_key->data);
230 user_info_dc->user_session_key = data_blob_null;
233 if (lm_session_key) {
234 DEBUG(10, ("Got LM session key of length %u\n",
235 (unsigned)user_info_dc->lm_session_key.length));
236 *lm_session_key = user_info_dc->lm_session_key;
237 talloc_steal(mem_ctx, lm_session_key->data);
238 user_info_dc->lm_session_key = data_blob_null;
242 return status;
245 struct auth_check_password_state {
246 struct auth4_context *auth_ctx;
247 const struct auth_usersupplied_info *user_info;
248 struct auth_user_info_dc *user_info_dc;
249 struct auth_method_context *method;
252 static void auth_check_password_async_trigger(struct tevent_context *ev,
253 struct tevent_immediate *im,
254 void *private_data);
256 * Check a user's Plaintext, LM or NTLM password.
257 * async send hook
259 * Check a user's password, as given in the user_info struct and return various
260 * interesting details in the user_info_dc struct.
262 * The return value takes precedence over the contents of the user_info_dc
263 * struct. When the return is other than NT_STATUS_OK the contents
264 * of that structure is undefined.
266 * @param mem_ctx The memory context the request should operate on
268 * @param ev The tevent context the request should operate on
270 * @param auth_ctx Supplies the challenges and some other data.
271 * Must be created with make_auth_context(), and the challenges should be
272 * filled in, either at creation or by calling the challenge geneation
273 * function auth_get_challenge().
275 * @param user_info Contains the user supplied components, including the passwords.
277 * @return The request handle or NULL on no memory error.
281 _PUBLIC_ struct tevent_req *auth_check_password_send(TALLOC_CTX *mem_ctx,
282 struct tevent_context *ev,
283 struct auth4_context *auth_ctx,
284 const struct auth_usersupplied_info *user_info)
286 struct tevent_req *req;
287 struct auth_check_password_state *state;
288 /* if all the modules say 'not for me' this is reasonable */
289 NTSTATUS nt_status;
290 uint8_t chal[8];
291 struct auth_usersupplied_info *user_info_tmp;
292 struct tevent_immediate *im;
294 DEBUG(3,("auth_check_password_send: "
295 "Checking password for unmapped user [%s]\\[%s]@[%s]\n",
296 user_info->client.domain_name, user_info->client.account_name,
297 user_info->workstation_name));
299 req = tevent_req_create(mem_ctx, &state,
300 struct auth_check_password_state);
301 if (req == NULL) {
302 return NULL;
305 state->auth_ctx = auth_ctx;
306 state->user_info = user_info;
308 if (!user_info->mapped_state) {
309 nt_status = map_user_info(auth_ctx->sam_ctx, req, lpcfg_workgroup(auth_ctx->lp_ctx),
310 user_info, &user_info_tmp);
311 if (tevent_req_nterror(req, nt_status)) {
312 return tevent_req_post(req, ev);
314 user_info = user_info_tmp;
315 state->user_info = user_info_tmp;
318 DEBUGADD(3,("auth_check_password_send: "
319 "mapped user is: [%s]\\[%s]@[%s]\n",
320 user_info->mapped.domain_name,
321 user_info->mapped.account_name,
322 user_info->workstation_name));
324 nt_status = auth_get_challenge(auth_ctx, chal);
325 if (tevent_req_nterror(req, nt_status)) {
326 DEBUG(0,("auth_check_password_send: "
327 "Invalid challenge (length %u) stored for "
328 "this auth context set_by %s - cannot continue: %s\n",
329 (unsigned)auth_ctx->challenge.data.length,
330 auth_ctx->challenge.set_by,
331 nt_errstr(nt_status)));
332 return tevent_req_post(req, ev);
335 if (auth_ctx->challenge.set_by) {
336 DEBUG(10,("auth_check_password_send: "
337 "auth_context challenge created by %s\n",
338 auth_ctx->challenge.set_by));
341 DEBUG(10, ("auth_check_password_send: challenge is: \n"));
342 dump_data(5, auth_ctx->challenge.data.data,
343 auth_ctx->challenge.data.length);
345 im = tevent_create_immediate(state);
346 if (tevent_req_nomem(im, req)) {
347 return tevent_req_post(req, ev);
350 tevent_schedule_immediate(im,
351 auth_ctx->event_ctx,
352 auth_check_password_async_trigger,
353 req);
354 return req;
357 static void auth_check_password_async_trigger(struct tevent_context *ev,
358 struct tevent_immediate *im,
359 void *private_data)
361 struct tevent_req *req =
362 talloc_get_type_abort(private_data, struct tevent_req);
363 struct auth_check_password_state *state =
364 tevent_req_data(req, struct auth_check_password_state);
365 NTSTATUS status;
366 struct auth_method_context *method;
368 status = NT_STATUS_OK;
370 for (method=state->auth_ctx->methods; method; method = method->next) {
372 /* we fill in state->method here so debug messages in
373 the callers know which method failed */
374 state->method = method;
376 /* check if the module wants to check the password */
377 status = method->ops->want_check(method, req, state->user_info);
378 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
379 DEBUG(11,("auth_check_password_send: "
380 "%s had nothing to say\n",
381 method->ops->name));
382 continue;
385 if (tevent_req_nterror(req, status)) {
386 return;
389 status = method->ops->check_password(method,
390 state,
391 state->user_info,
392 &state->user_info_dc);
393 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
394 /* the backend has handled the request */
395 break;
399 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
400 /* don't expose the NT_STATUS_NOT_IMPLEMENTED
401 internals */
402 status = NT_STATUS_NO_SUCH_USER;
405 if (tevent_req_nterror(req, status)) {
406 return;
409 tevent_req_done(req);
413 * Check a user's Plaintext, LM or NTLM password.
414 * async receive function
416 * The return value takes precedence over the contents of the user_info_dc
417 * struct. When the return is other than NT_STATUS_OK the contents
418 * of that structure is undefined.
421 * @param req The async request state
423 * @param mem_ctx The parent memory context for the user_info_dc structure
425 * @param user_info_dc If successful, contains information about the authentication,
426 * including a SAM_ACCOUNT struct describing the user.
428 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
432 _PUBLIC_ NTSTATUS auth_check_password_recv(struct tevent_req *req,
433 TALLOC_CTX *mem_ctx,
434 struct auth_user_info_dc **user_info_dc)
436 struct auth_check_password_state *state =
437 tevent_req_data(req, struct auth_check_password_state);
438 NTSTATUS status;
440 if (tevent_req_is_nterror(req, &status)) {
441 DEBUG(2,("auth_check_password_recv: "
442 "%s authentication for user [%s\\%s] "
443 "FAILED with error %s\n",
444 (state->method ? state->method->ops->name : "NO_METHOD"),
445 state->user_info->mapped.domain_name,
446 state->user_info->mapped.account_name,
447 nt_errstr(status)));
448 tevent_req_received(req);
449 return status;
452 DEBUG(5,("auth_check_password_recv: "
453 "%s authentication for user [%s\\%s] succeeded\n",
454 state->method->ops->name,
455 state->user_info_dc->info->domain_name,
456 state->user_info_dc->info->account_name));
458 *user_info_dc = talloc_move(mem_ctx, &state->user_info_dc);
460 tevent_req_received(req);
461 return NT_STATUS_OK;
464 /* Wrapper because we don't want to expose all callers to needing to
465 * know that session_info is generated from the main ldb, and because
466 * we need to break a depenency loop between the DCE/RPC layer and the
467 * generation of unix tokens via IRPC */
468 static NTSTATUS auth_generate_session_info_wrapper(struct auth4_context *auth_context,
469 TALLOC_CTX *mem_ctx,
470 void *server_returned_info,
471 const char *original_user_name,
472 uint32_t session_info_flags,
473 struct auth_session_info **session_info)
475 NTSTATUS status;
476 struct auth_user_info_dc *user_info_dc = talloc_get_type_abort(server_returned_info, struct auth_user_info_dc);
478 if (user_info_dc->info->authenticated) {
479 session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
482 status = auth_generate_session_info(mem_ctx, auth_context->lp_ctx,
483 auth_context->sam_ctx, user_info_dc,
484 session_info_flags, session_info);
485 if (!NT_STATUS_IS_OK(status)) {
486 return status;
489 if ((session_info_flags & AUTH_SESSION_INFO_UNIX_TOKEN)
490 && NT_STATUS_IS_OK(status)) {
491 struct wbc_context *wbc_ctx = wbc_init(auth_context,
492 auth_context->msg_ctx,
493 auth_context->event_ctx);
494 if (!wbc_ctx) {
495 TALLOC_FREE(*session_info);
496 DEBUG(1, ("Cannot contact winbind to provide unix token\n"));
497 return NT_STATUS_INVALID_SERVER_STATE;
499 status = auth_session_info_fill_unix(wbc_ctx, auth_context->lp_ctx,
500 original_user_name, *session_info);
501 if (!NT_STATUS_IS_OK(status)) {
502 TALLOC_FREE(*session_info);
504 TALLOC_FREE(wbc_ctx);
506 return status;
509 /* Wrapper because we don't want to expose all callers to needing to
510 * know anything about the PAC or auth subsystem internal structures
511 * before we output a struct auth session_info */
512 static NTSTATUS auth_generate_session_info_pac(struct auth4_context *auth_ctx,
513 TALLOC_CTX *mem_ctx,
514 struct smb_krb5_context *smb_krb5_context,
515 DATA_BLOB *pac_blob,
516 const char *principal_name,
517 const struct tsocket_address *remote_address,
518 uint32_t session_info_flags,
519 struct auth_session_info **session_info)
521 NTSTATUS status;
522 struct auth_user_info_dc *user_info_dc;
523 TALLOC_CTX *tmp_ctx;
525 if (!pac_blob) {
526 return auth_generate_session_info_principal(auth_ctx, mem_ctx, principal_name,
527 NULL, session_info_flags, session_info);
530 tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gssapi_session_info context");
531 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
533 status = kerberos_pac_blob_to_user_info_dc(tmp_ctx,
534 *pac_blob,
535 smb_krb5_context->krb5_context,
536 &user_info_dc, NULL, NULL);
537 if (!NT_STATUS_IS_OK(status)) {
538 talloc_free(tmp_ctx);
539 return status;
542 if (user_info_dc->info->authenticated) {
543 session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
546 status = auth_generate_session_info_wrapper(auth_ctx, mem_ctx,
547 user_info_dc,
548 user_info_dc->info->account_name,
549 session_info_flags, session_info);
550 talloc_free(tmp_ctx);
551 return status;
554 /***************************************************************************
555 Make a auth_info struct for the auth subsystem
556 - Allow the caller to specify the methods to use, including optionally the SAM to use
557 ***************************************************************************/
558 _PUBLIC_ NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char **methods,
559 struct tevent_context *ev,
560 struct imessaging_context *msg,
561 struct loadparm_context *lp_ctx,
562 struct ldb_context *sam_ctx,
563 struct auth4_context **auth_ctx)
565 int i;
566 struct auth4_context *ctx;
568 auth4_init();
570 if (!ev) {
571 DEBUG(0,("auth_context_create: called with out event context\n"));
572 return NT_STATUS_INTERNAL_ERROR;
575 ctx = talloc_zero(mem_ctx, struct auth4_context);
576 NT_STATUS_HAVE_NO_MEMORY(ctx);
577 ctx->challenge.set_by = NULL;
578 ctx->challenge.may_be_modified = false;
579 ctx->challenge.data = data_blob(NULL, 0);
580 ctx->methods = NULL;
581 ctx->event_ctx = ev;
582 ctx->msg_ctx = msg;
583 ctx->lp_ctx = lp_ctx;
585 if (sam_ctx) {
586 ctx->sam_ctx = sam_ctx;
587 } else {
588 ctx->sam_ctx = samdb_connect(ctx, ctx->event_ctx, ctx->lp_ctx, system_session(ctx->lp_ctx), 0);
591 for (i=0; methods && methods[i] ; i++) {
592 struct auth_method_context *method;
594 method = talloc(ctx, struct auth_method_context);
595 NT_STATUS_HAVE_NO_MEMORY(method);
597 method->ops = auth_backend_byname(methods[i]);
598 if (!method->ops) {
599 DEBUG(1,("auth_context_create: failed to find method=%s\n",
600 methods[i]));
601 return NT_STATUS_INTERNAL_ERROR;
603 method->auth_ctx = ctx;
604 method->depth = i;
605 DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
608 ctx->check_ntlm_password = auth_check_password_wrapper;
609 ctx->get_ntlm_challenge = auth_get_challenge;
610 ctx->set_ntlm_challenge = auth_context_set_challenge;
611 ctx->challenge_may_be_modified = auth_challenge_may_be_modified;
612 ctx->generate_session_info = auth_generate_session_info_wrapper;
613 ctx->generate_session_info_pac = auth_generate_session_info_pac;
615 *auth_ctx = ctx;
617 return NT_STATUS_OK;
620 const char **auth_methods_from_lp(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
622 char **auth_methods = NULL;
624 switch (lpcfg_server_role(lp_ctx)) {
625 case ROLE_STANDALONE:
626 auth_methods = str_list_make(mem_ctx, "anonymous sam_ignoredomain", NULL);
627 break;
628 case ROLE_DOMAIN_MEMBER:
629 auth_methods = str_list_make(mem_ctx, "anonymous sam winbind", NULL);
630 break;
631 case ROLE_DOMAIN_BDC:
632 case ROLE_DOMAIN_PDC:
633 case ROLE_ACTIVE_DIRECTORY_DC:
634 auth_methods = str_list_make(mem_ctx, "anonymous sam_ignoredomain winbind", NULL);
635 break;
637 return (const char **) auth_methods;
640 /***************************************************************************
641 Make a auth_info struct for the auth subsystem
642 - Uses default auth_methods, depending on server role and smb.conf settings
643 ***************************************************************************/
644 _PUBLIC_ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx,
645 struct tevent_context *ev,
646 struct imessaging_context *msg,
647 struct loadparm_context *lp_ctx,
648 struct auth4_context **auth_ctx)
650 NTSTATUS status;
651 const char **auth_methods;
652 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
653 if (!tmp_ctx) {
654 return NT_STATUS_NO_MEMORY;
657 auth_methods = auth_methods_from_lp(tmp_ctx, lp_ctx);
658 if (!auth_methods) {
659 return NT_STATUS_INVALID_PARAMETER;
661 status = auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, NULL, auth_ctx);
662 talloc_free(tmp_ctx);
663 return status;
666 /* the list of currently registered AUTH backends */
667 static struct auth_backend {
668 const struct auth_operations *ops;
669 } *backends = NULL;
670 static int num_backends;
673 register a AUTH backend.
675 The 'name' can be later used by other backends to find the operations
676 structure for this backend.
678 _PUBLIC_ NTSTATUS auth_register(const struct auth_operations *ops)
680 struct auth_operations *new_ops;
682 if (auth_backend_byname(ops->name) != NULL) {
683 /* its already registered! */
684 DEBUG(0,("AUTH backend '%s' already registered\n",
685 ops->name));
686 return NT_STATUS_OBJECT_NAME_COLLISION;
689 backends = talloc_realloc(talloc_autofree_context(), backends,
690 struct auth_backend, num_backends+1);
691 NT_STATUS_HAVE_NO_MEMORY(backends);
693 new_ops = (struct auth_operations *)talloc_memdup(backends, ops, sizeof(*ops));
694 NT_STATUS_HAVE_NO_MEMORY(new_ops);
695 new_ops->name = talloc_strdup(new_ops, ops->name);
696 NT_STATUS_HAVE_NO_MEMORY(new_ops->name);
698 backends[num_backends].ops = new_ops;
700 num_backends++;
702 DEBUG(3,("AUTH backend '%s' registered\n",
703 ops->name));
705 return NT_STATUS_OK;
709 return the operations structure for a named backend of the specified type
711 const struct auth_operations *auth_backend_byname(const char *name)
713 int i;
715 for (i=0;i<num_backends;i++) {
716 if (strcmp(backends[i].ops->name, name) == 0) {
717 return backends[i].ops;
721 return NULL;
725 return the AUTH interface version, and the size of some critical types
726 This can be used by backends to either detect compilation errors, or provide
727 multiple implementations for different smbd compilation options in one module
729 const struct auth_critical_sizes *auth_interface_version(void)
731 static const struct auth_critical_sizes critical_sizes = {
732 AUTH4_INTERFACE_VERSION,
733 sizeof(struct auth_operations),
734 sizeof(struct auth_method_context),
735 sizeof(struct auth4_context),
736 sizeof(struct auth_usersupplied_info),
737 sizeof(struct auth_user_info_dc)
740 return &critical_sizes;
743 _PUBLIC_ NTSTATUS auth4_init(void)
745 static bool initialized = false;
746 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
747 STATIC_auth4_MODULES_PROTO;
748 init_module_fn static_init[] = { STATIC_auth4_MODULES };
750 if (initialized) return NT_STATUS_OK;
751 initialized = true;
753 run_init_functions(static_init);
755 return NT_STATUS_OK;