s4:auth_sam: remove unused 'sam_failtrusts' backend
[Samba.git] / source4 / auth / ntlm / auth.c
blob7e10a554d8c93ada4aded6c54d4af7751ffeac87
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"
35 #include "libds/common/roles.h"
37 static NTSTATUS auth_generate_session_info_wrapper(struct auth4_context *auth_context,
38 TALLOC_CTX *mem_ctx,
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 /***************************************************************************
45 Set a fixed challenge
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);
55 return NT_STATUS_OK;
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);
69 return NT_STATUS_OK;
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));
83 return NT_STATUS_OK;
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,
93 TALLOC_CTX *mem_ctx,
94 const char *principal,
95 struct ldb_dn *user_dn,
96 uint32_t session_info_flags,
97 struct auth_session_info **session_info)
99 NTSTATUS nt_status;
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) {
105 continue;
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)) {
110 continue;
112 if (!NT_STATUS_IS_OK(nt_status)) {
113 return nt_status;
116 nt_status = auth_generate_session_info_wrapper(auth_ctx, mem_ctx,
117 user_info_dc,
118 user_info_dc->info->account_name,
119 session_info_flags, session_info);
120 talloc_free(user_info_dc);
122 return nt_status;
125 return NT_STATUS_NOT_IMPLEMENTED;
129 * Check a user's Plaintext, LM or NTLM password.
130 * (sync version)
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,
156 TALLOC_CTX *mem_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;
163 bool ok;
164 NTSTATUS status;
166 /*TODO: create a new event context here! */
167 ev = auth_ctx->event_ctx;
169 subreq = auth_check_password_send(mem_ctx,
171 auth_ctx,
172 user_info);
173 if (subreq == NULL) {
174 return NT_STATUS_NO_MEMORY;
177 ok = tevent_req_poll(subreq, ev);
178 if (!ok) {
179 return NT_STATUS_INTERNAL_ERROR;
182 status = auth_check_password_recv(subreq, mem_ctx,
183 user_info_dc, pauthoritative);
184 TALLOC_FREE(subreq);
186 return status;
189 struct auth_check_password_state {
190 struct tevent_context *ev;
191 struct auth4_context *auth_ctx;
192 const struct auth_usersupplied_info *user_info;
193 struct auth_user_info_dc *user_info_dc;
194 struct auth_method_context *method;
195 uint8_t authoritative;
198 static void auth_check_password_next(struct tevent_req *req);
201 * Check a user's Plaintext, LM or NTLM password.
202 * async send hook
204 * Check a user's password, as given in the user_info struct and return various
205 * interesting details in the user_info_dc struct.
207 * The return value takes precedence over the contents of the user_info_dc
208 * struct. When the return is other than NT_STATUS_OK the contents
209 * of that structure is undefined.
211 * @param mem_ctx The memory context the request should operate on
213 * @param ev The tevent context the request should operate on
215 * @param auth_ctx Supplies the challenges and some other data.
216 * Must be created with make_auth_context(), and the challenges should be
217 * filled in, either at creation or by calling the challenge geneation
218 * function auth_get_challenge().
220 * @param user_info Contains the user supplied components, including the passwords.
222 * @return The request handle or NULL on no memory error.
226 _PUBLIC_ struct tevent_req *auth_check_password_send(TALLOC_CTX *mem_ctx,
227 struct tevent_context *ev,
228 struct auth4_context *auth_ctx,
229 const struct auth_usersupplied_info *user_info)
231 struct tevent_req *req;
232 struct auth_check_password_state *state;
233 /* if all the modules say 'not for me' this is reasonable */
234 NTSTATUS nt_status;
235 uint8_t chal[8];
237 DEBUG(3,("auth_check_password_send: "
238 "Checking password for unmapped user [%s]\\[%s]@[%s]\n",
239 user_info->client.domain_name, user_info->client.account_name,
240 user_info->workstation_name));
242 req = tevent_req_create(mem_ctx, &state,
243 struct auth_check_password_state);
244 if (req == NULL) {
245 return NULL;
249 * We are authoritative by default.
251 state->ev = ev;
252 state->auth_ctx = auth_ctx;
253 state->user_info = user_info;
254 state->authoritative = 1;
256 if (!user_info->mapped_state) {
257 struct auth_usersupplied_info *user_info_tmp;
260 * We don't really do any mapping here.
262 * So we don't set user_info->mapped_state,
263 * but we set mapped.domain_name and
264 * mapped.account_name to the client
265 * provided values.
267 * It's up to the backends to do mappings
268 * for their authentication.
270 user_info_tmp = talloc_zero(state, struct auth_usersupplied_info);
271 if (tevent_req_nomem(user_info_tmp, req)) {
272 return tevent_req_post(req, ev);;
276 * The lifetime of user_info is longer than
277 * user_info_tmp, so we don't need to copy the
278 * strings.
280 *user_info_tmp = *user_info;
281 user_info_tmp->mapped.domain_name = user_info->client.domain_name;
282 user_info_tmp->mapped.account_name = user_info->client.account_name;
284 user_info = user_info_tmp;
285 state->user_info = user_info_tmp;
288 DEBUGADD(3,("auth_check_password_send: "
289 "user is: [%s]\\[%s]@[%s]\n",
290 user_info->mapped.domain_name,
291 user_info->mapped.account_name,
292 user_info->workstation_name));
294 nt_status = auth_get_challenge(auth_ctx, chal);
295 if (tevent_req_nterror(req, nt_status)) {
296 DEBUG(0,("auth_check_password_send: "
297 "Invalid challenge (length %u) stored for "
298 "this auth context set_by %s - cannot continue: %s\n",
299 (unsigned)auth_ctx->challenge.data.length,
300 auth_ctx->challenge.set_by,
301 nt_errstr(nt_status)));
302 return tevent_req_post(req, ev);
305 if (auth_ctx->challenge.set_by) {
306 DEBUG(10,("auth_check_password_send: "
307 "auth_context challenge created by %s\n",
308 auth_ctx->challenge.set_by));
311 DEBUG(10, ("auth_check_password_send: challenge is: \n"));
312 dump_data(5, auth_ctx->challenge.data.data,
313 auth_ctx->challenge.data.length);
315 state->method = state->auth_ctx->methods;
316 auth_check_password_next(req);
317 if (!tevent_req_is_in_progress(req)) {
318 return tevent_req_post(req, ev);
321 return req;
324 static void auth_check_password_done(struct tevent_req *subreq);
326 static void auth_check_password_next(struct tevent_req *req)
328 struct auth_check_password_state *state =
329 tevent_req_data(req, struct auth_check_password_state);
330 struct tevent_req *subreq = NULL;
331 bool authoritative = true;
332 NTSTATUS status;
334 if (state->method == NULL) {
335 state->authoritative = 0;
336 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
337 return;
340 /* check if the module wants to check the password */
341 status = state->method->ops->want_check(state->method, state,
342 state->user_info);
343 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
344 DEBUG(11,("auth_check_password_send: "
345 "%s doesn't want to check\n",
346 state->method->ops->name));
347 state->method = state->method->next;
348 auth_check_password_next(req);
349 return;
352 if (tevent_req_nterror(req, status)) {
353 return;
356 if (state->method->ops->check_password_send != NULL) {
357 subreq = state->method->ops->check_password_send(state,
358 state->ev,
359 state->method,
360 state->user_info);
361 if (tevent_req_nomem(subreq, req)) {
362 return;
364 tevent_req_set_callback(subreq,
365 auth_check_password_done,
366 req);
367 return;
370 if (state->method->ops->check_password == NULL) {
371 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
372 return;
375 status = state->method->ops->check_password(state->method,
376 state,
377 state->user_info,
378 &state->user_info_dc,
379 &authoritative);
380 if (!authoritative ||
381 NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
382 DEBUG(11,("auth_check_password_send: "
383 "%s passes to the next method\n",
384 state->method->ops->name));
385 state->method = state->method->next;
386 auth_check_password_next(req);
387 return;
390 /* the backend has handled the request */
392 if (tevent_req_nterror(req, status)) {
393 return;
396 tevent_req_done(req);
399 static void auth_check_password_done(struct tevent_req *subreq)
401 struct tevent_req *req =
402 tevent_req_callback_data(subreq,
403 struct tevent_req);
404 struct auth_check_password_state *state =
405 tevent_req_data(req,
406 struct auth_check_password_state);
407 bool authoritative = true;
408 NTSTATUS status;
410 status = state->method->ops->check_password_recv(subreq, state,
411 &state->user_info_dc,
412 &authoritative);
413 TALLOC_FREE(subreq);
414 if (!authoritative ||
415 NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
416 DEBUG(11,("auth_check_password_send: "
417 "%s passes to the next method\n",
418 state->method->ops->name));
419 state->method = state->method->next;
420 auth_check_password_next(req);
421 return;
424 /* the backend has handled the request */
426 if (tevent_req_nterror(req, status)) {
427 return;
430 tevent_req_done(req);
434 * Check a user's Plaintext, LM or NTLM password.
435 * async receive function
437 * The return value takes precedence over the contents of the user_info_dc
438 * struct. When the return is other than NT_STATUS_OK the contents
439 * of that structure is undefined.
442 * @param req The async request state
444 * @param mem_ctx The parent memory context for the user_info_dc structure
446 * @param user_info_dc If successful, contains information about the authentication,
447 * including a SAM_ACCOUNT struct describing the user.
449 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
453 _PUBLIC_ NTSTATUS auth_check_password_recv(struct tevent_req *req,
454 TALLOC_CTX *mem_ctx,
455 struct auth_user_info_dc **user_info_dc,
456 uint8_t *pauthoritative)
458 struct auth_check_password_state *state =
459 tevent_req_data(req, struct auth_check_password_state);
460 NTSTATUS status = NT_STATUS_OK;
462 *pauthoritative = state->authoritative;
464 if (tevent_req_is_nterror(req, &status)) {
466 * Please try not to change this string, it is probably in use
467 * in audit logging tools
469 DEBUG(2,("auth_check_password_recv: "
470 "%s authentication for user [%s\\%s] "
471 "FAILED with error %s, authoritative=%u\n",
472 (state->method ? state->method->ops->name : "NO_METHOD"),
473 state->user_info->mapped.domain_name,
474 state->user_info->mapped.account_name,
475 nt_errstr(status), state->authoritative));
477 log_authentication_event(state->auth_ctx->msg_ctx,
478 state->auth_ctx->lp_ctx,
479 state->user_info, status,
480 NULL, NULL, NULL, NULL);
481 tevent_req_received(req);
482 return status;
485 DEBUG(5,("auth_check_password_recv: "
486 "%s authentication for user [%s\\%s] succeeded\n",
487 state->method->ops->name,
488 state->user_info_dc->info->domain_name,
489 state->user_info_dc->info->account_name));
491 log_authentication_event(state->auth_ctx->msg_ctx,
492 state->auth_ctx->lp_ctx,
493 state->user_info, status,
494 state->user_info_dc->info->domain_name,
495 state->user_info_dc->info->account_name,
496 NULL,
497 &state->user_info_dc->sids[0]);
499 *user_info_dc = talloc_move(mem_ctx, &state->user_info_dc);
501 tevent_req_received(req);
502 return NT_STATUS_OK;
505 struct auth_check_password_wrapper_state {
506 uint8_t authoritative;
507 struct auth_user_info_dc *user_info_dc;
510 static void auth_check_password_wrapper_done(struct tevent_req *subreq);
512 static struct tevent_req *auth_check_password_wrapper_send(TALLOC_CTX *mem_ctx,
513 struct tevent_context *ev,
514 struct auth4_context *auth_ctx,
515 const struct auth_usersupplied_info *user_info)
517 struct tevent_req *req = NULL;
518 struct auth_check_password_wrapper *state = NULL;
519 struct tevent_req *subreq = NULL;
521 req = tevent_req_create(mem_ctx, &state,
522 struct auth_check_password_wrapper_state);
523 if (req == NULL) {
524 return NULL;
527 subreq = auth_check_password_send(state, ev, auth_ctx, user_info);
528 if (tevent_req_nomem(subreq, req)) {
529 return tevent_req_post(req, ev);
531 tevent_req_set_callback(subreq,
532 auth_check_password_wrapper_done,
533 req);
535 return req;
538 static void auth_check_password_wrapper_done(struct tevent_req *subreq)
540 struct tevent_req *req =
541 tevent_req_callback_data(subreq,
542 struct tevent_req);
543 struct auth_check_password_wrapper_state *state =
544 tevent_req_data(req,
545 struct auth_check_password_wrapper_state);
546 NTSTATUS status;
548 status = auth_check_password_recv(subreq, state,
549 &state->user_info_dc,
550 &state->authoritative);
551 TALLOC_FREE(subreq);
552 if (tevent_req_nterror(req, status)) {
553 return;
556 tevent_req_done(req);
559 static NTSTATUS auth_check_password_wrapper_recv(struct tevent_req *req,
560 TALLOC_CTX *mem_ctx,
561 uint8_t *pauthoritative,
562 void **server_returned_info,
563 DATA_BLOB *user_session_key,
564 DATA_BLOB *lm_session_key)
566 struct auth_check_password_wrapper_state *state =
567 tevent_req_data(req,
568 struct auth_check_password_wrapper_state);
569 struct auth_user_info_dc *user_info_dc = state->user_info_dc;
570 NTSTATUS status = NT_STATUS_OK;
572 *pauthoritative = state->authoritative;
574 if (tevent_req_is_nterror(req, &status)) {
575 tevent_req_received(req);
576 return status;
579 talloc_steal(mem_ctx, user_info_dc);
580 *server_returned_info = user_info_dc;
582 if (user_session_key) {
583 DEBUG(10, ("Got NT session key of length %u\n",
584 (unsigned)user_info_dc->user_session_key.length));
585 *user_session_key = user_info_dc->user_session_key;
586 talloc_steal(mem_ctx, user_session_key->data);
587 user_info_dc->user_session_key = data_blob_null;
590 if (lm_session_key) {
591 DEBUG(10, ("Got LM session key of length %u\n",
592 (unsigned)user_info_dc->lm_session_key.length));
593 *lm_session_key = user_info_dc->lm_session_key;
594 talloc_steal(mem_ctx, lm_session_key->data);
595 user_info_dc->lm_session_key = data_blob_null;
598 tevent_req_received(req);
599 return NT_STATUS_OK;
602 /* Wrapper because we don't want to expose all callers to needing to
603 * know that session_info is generated from the main ldb, and because
604 * we need to break a depenency loop between the DCE/RPC layer and the
605 * generation of unix tokens via IRPC */
606 static NTSTATUS auth_generate_session_info_wrapper(struct auth4_context *auth_context,
607 TALLOC_CTX *mem_ctx,
608 void *server_returned_info,
609 const char *original_user_name,
610 uint32_t session_info_flags,
611 struct auth_session_info **session_info)
613 NTSTATUS status;
614 struct auth_user_info_dc *user_info_dc = talloc_get_type_abort(server_returned_info, struct auth_user_info_dc);
616 if (user_info_dc->info->authenticated) {
617 session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
620 status = auth_generate_session_info(mem_ctx, auth_context->lp_ctx,
621 auth_context->sam_ctx, user_info_dc,
622 session_info_flags, session_info);
623 if (!NT_STATUS_IS_OK(status)) {
624 return status;
627 if ((session_info_flags & AUTH_SESSION_INFO_UNIX_TOKEN)
628 && NT_STATUS_IS_OK(status)) {
629 status = auth_session_info_fill_unix(auth_context->lp_ctx,
630 original_user_name,
631 *session_info);
632 if (!NT_STATUS_IS_OK(status)) {
633 TALLOC_FREE(*session_info);
636 return status;
639 /* Wrapper because we don't want to expose all callers to needing to
640 * know anything about the PAC or auth subsystem internal structures
641 * before we output a struct auth session_info */
642 static NTSTATUS auth_generate_session_info_pac(struct auth4_context *auth_ctx,
643 TALLOC_CTX *mem_ctx,
644 struct smb_krb5_context *smb_krb5_context,
645 DATA_BLOB *pac_blob,
646 const char *principal_name,
647 const struct tsocket_address *remote_address,
648 uint32_t session_info_flags,
649 struct auth_session_info **session_info)
651 NTSTATUS status;
652 struct auth_user_info_dc *user_info_dc;
653 TALLOC_CTX *tmp_ctx;
655 if (!pac_blob) {
656 return auth_generate_session_info_principal(auth_ctx, mem_ctx, principal_name,
657 NULL, session_info_flags, session_info);
660 tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gssapi_session_info context");
661 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
663 status = kerberos_pac_blob_to_user_info_dc(tmp_ctx,
664 *pac_blob,
665 smb_krb5_context->krb5_context,
666 &user_info_dc, NULL, NULL);
667 if (!NT_STATUS_IS_OK(status)) {
668 talloc_free(tmp_ctx);
669 return status;
672 if (user_info_dc->info->authenticated) {
673 session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
676 status = auth_generate_session_info_wrapper(auth_ctx, mem_ctx,
677 user_info_dc,
678 user_info_dc->info->account_name,
679 session_info_flags, session_info);
680 talloc_free(tmp_ctx);
681 return status;
684 /***************************************************************************
685 Make a auth_info struct for the auth subsystem
686 - Allow the caller to specify the methods to use, including optionally the SAM to use
687 ***************************************************************************/
688 _PUBLIC_ NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char * const *methods,
689 struct tevent_context *ev,
690 struct imessaging_context *msg,
691 struct loadparm_context *lp_ctx,
692 struct ldb_context *sam_ctx,
693 struct auth4_context **auth_ctx)
695 int i;
696 struct auth4_context *ctx;
698 auth4_init();
700 if (!ev) {
701 DEBUG(0,("auth_context_create: called with out event context\n"));
702 return NT_STATUS_INTERNAL_ERROR;
705 ctx = talloc_zero(mem_ctx, struct auth4_context);
706 NT_STATUS_HAVE_NO_MEMORY(ctx);
707 ctx->challenge.data = data_blob(NULL, 0);
708 ctx->methods = NULL;
709 ctx->event_ctx = ev;
710 ctx->msg_ctx = msg;
711 ctx->lp_ctx = lp_ctx;
713 if (sam_ctx) {
714 ctx->sam_ctx = sam_ctx;
715 } else {
716 ctx->sam_ctx = samdb_connect(ctx, ctx->event_ctx, ctx->lp_ctx, system_session(ctx->lp_ctx), 0);
719 for (i=0; methods && methods[i] ; i++) {
720 struct auth_method_context *method;
722 method = talloc(ctx, struct auth_method_context);
723 NT_STATUS_HAVE_NO_MEMORY(method);
725 method->ops = auth_backend_byname(methods[i]);
726 if (!method->ops) {
727 DEBUG(1,("auth_context_create: failed to find method=%s\n",
728 methods[i]));
729 return NT_STATUS_INTERNAL_ERROR;
731 method->auth_ctx = ctx;
732 method->depth = i;
733 DLIST_ADD_END(ctx->methods, method);
736 ctx->check_ntlm_password_send = auth_check_password_wrapper_send;
737 ctx->check_ntlm_password_recv = auth_check_password_wrapper_recv;
738 ctx->get_ntlm_challenge = auth_get_challenge;
739 ctx->set_ntlm_challenge = auth_context_set_challenge;
740 ctx->generate_session_info = auth_generate_session_info_wrapper;
741 ctx->generate_session_info_pac = auth_generate_session_info_pac;
743 *auth_ctx = ctx;
745 return NT_STATUS_OK;
748 const char **auth_methods_from_lp(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
750 char **auth_methods = NULL;
752 switch (lpcfg_server_role(lp_ctx)) {
753 case ROLE_STANDALONE:
754 auth_methods = str_list_make(mem_ctx, "anonymous sam_ignoredomain", NULL);
755 break;
756 case ROLE_DOMAIN_MEMBER:
757 case ROLE_DOMAIN_BDC:
758 case ROLE_DOMAIN_PDC:
759 case ROLE_ACTIVE_DIRECTORY_DC:
760 auth_methods = str_list_make(mem_ctx, "anonymous sam winbind sam_ignoredomain", NULL);
761 break;
763 return discard_const_p(const char *, auth_methods);
766 /***************************************************************************
767 Make a auth_info struct for the auth subsystem
768 - Uses default auth_methods, depending on server role and smb.conf settings
769 ***************************************************************************/
770 _PUBLIC_ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx,
771 struct tevent_context *ev,
772 struct imessaging_context *msg,
773 struct loadparm_context *lp_ctx,
774 struct auth4_context **auth_ctx)
776 NTSTATUS status;
777 const char **auth_methods;
778 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
779 if (!tmp_ctx) {
780 return NT_STATUS_NO_MEMORY;
783 auth_methods = auth_methods_from_lp(tmp_ctx, lp_ctx);
784 if (!auth_methods) {
785 return NT_STATUS_INVALID_PARAMETER;
787 status = auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, NULL, auth_ctx);
788 talloc_free(tmp_ctx);
789 return status;
792 _PUBLIC_ NTSTATUS auth_context_create_for_netlogon(TALLOC_CTX *mem_ctx,
793 struct tevent_context *ev,
794 struct imessaging_context *msg,
795 struct loadparm_context *lp_ctx,
796 struct auth4_context **auth_ctx)
798 NTSTATUS status;
799 char **_auth_methods = NULL;
800 const char **auth_methods = NULL;
803 * Here we only allow 'sam winbind' instead of
804 * the 'anonymous sam winbind sam_ignoredomain'
805 * we typically use for authentication from clients.
807 _auth_methods = str_list_make(mem_ctx, "sam winbind", NULL);
808 if (_auth_methods == NULL) {
809 return NT_STATUS_NO_MEMORY;
811 auth_methods = discard_const_p(const char *, _auth_methods);
813 status = auth_context_create_methods(mem_ctx, auth_methods, ev, msg,
814 lp_ctx, NULL, auth_ctx);
815 talloc_free(_auth_methods);
816 return status;
819 /* the list of currently registered AUTH backends */
820 static struct auth_backend {
821 const struct auth_operations *ops;
822 } *backends = NULL;
823 static int num_backends;
826 register a AUTH backend.
828 The 'name' can be later used by other backends to find the operations
829 structure for this backend.
831 _PUBLIC_ NTSTATUS auth_register(TALLOC_CTX *mem_ctx,
832 const struct auth_operations *ops)
834 struct auth_operations *new_ops;
836 if (auth_backend_byname(ops->name) != NULL) {
837 /* its already registered! */
838 DEBUG(0,("AUTH backend '%s' already registered\n",
839 ops->name));
840 return NT_STATUS_OBJECT_NAME_COLLISION;
843 backends = talloc_realloc(mem_ctx, backends,
844 struct auth_backend, num_backends+1);
845 NT_STATUS_HAVE_NO_MEMORY(backends);
847 new_ops = (struct auth_operations *)talloc_memdup(backends, ops, sizeof(*ops));
848 NT_STATUS_HAVE_NO_MEMORY(new_ops);
849 new_ops->name = talloc_strdup(new_ops, ops->name);
850 NT_STATUS_HAVE_NO_MEMORY(new_ops->name);
852 backends[num_backends].ops = new_ops;
854 num_backends++;
856 DEBUG(3,("AUTH backend '%s' registered\n",
857 ops->name));
859 return NT_STATUS_OK;
863 return the operations structure for a named backend of the specified type
865 const struct auth_operations *auth_backend_byname(const char *name)
867 int i;
869 for (i=0;i<num_backends;i++) {
870 if (strcmp(backends[i].ops->name, name) == 0) {
871 return backends[i].ops;
875 return NULL;
879 return the AUTH interface version, and the size of some critical types
880 This can be used by backends to either detect compilation errors, or provide
881 multiple implementations for different smbd compilation options in one module
883 const struct auth_critical_sizes *auth_interface_version(void)
885 static const struct auth_critical_sizes critical_sizes = {
886 AUTH4_INTERFACE_VERSION,
887 sizeof(struct auth_operations),
888 sizeof(struct auth_method_context),
889 sizeof(struct auth4_context),
890 sizeof(struct auth_usersupplied_info),
891 sizeof(struct auth_user_info_dc)
894 return &critical_sizes;
897 _PUBLIC_ NTSTATUS auth4_init(void)
899 static bool initialized = false;
900 #define _MODULE_PROTO(init) extern NTSTATUS init(TALLOC_CTX *);
901 STATIC_auth4_MODULES_PROTO;
902 init_module_fn static_init[] = { STATIC_auth4_MODULES };
904 if (initialized) return NT_STATUS_OK;
905 initialized = true;
907 run_init_functions(NULL, static_init);
909 return NT_STATUS_OK;