source: vendor/current/source4/auth/ntlm/auth.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 22.6 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 Password and authentication handling
4 Copyright (C) Andrew Bartlett 2001-2002
5 Copyright (C) Stefan Metzmacher 2005
6
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.
11
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.
16
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/>.
19*/
20
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"
36
37static 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);
43
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)
48{
49 auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
50 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
51
52 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
53 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
54
55 return NT_STATUS_OK;
56}
57
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])
63{
64
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;
70 }
71
72 if (!auth_ctx->challenge.set_by) {
73 generate_random_buffer(chal, 8);
74
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";
78 }
79
80 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
81 auth_ctx->challenge.set_by));
82
83 return NT_STATUS_OK;
84}
85
86/****************************************************************************
87Used in the gensec_gssapi and gensec_krb5 server-side code, where the
88PAC isn't available, and for tokenGroups in the DSDB stack.
89
90 Supply either a principal or a DN
91****************************************************************************/
92static 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)
98{
99 NTSTATUS nt_status;
100 struct auth_method_context *method;
101 struct auth_user_info_dc *user_info_dc;
102
103 for (method = auth_ctx->methods; method; method = method->next) {
104 if (!method->ops->get_user_info_dc_principal) {
105 continue;
106 }
107
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;
111 }
112 if (!NT_STATUS_IS_OK(nt_status)) {
113 return nt_status;
114 }
115
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);
121
122 return nt_status;
123 }
124
125 return NT_STATUS_NOT_IMPLEMENTED;
126}
127
128/**
129 * Check a user's Plaintext, LM or NTLM password.
130 * (sync version)
131 *
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.
134 *
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.
138 *
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().
143 *
144 * @param user_info Contains the user supplied components, including the passwords.
145 *
146 * @param mem_ctx The parent memory context for the user_info_dc structure
147 *
148 * @param user_info_dc If successful, contains information about the authentication,
149 * including a SAM_ACCOUNT struct describing the user.
150 *
151 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
152 *
153 **/
154
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{
160 struct tevent_req *subreq;
161 struct tevent_context *ev;
162 bool ok;
163 NTSTATUS status;
164
165 /*TODO: create a new event context here! */
166 ev = auth_ctx->event_ctx;
167
168 subreq = auth_check_password_send(mem_ctx,
169 ev,
170 auth_ctx,
171 user_info);
172 if (subreq == NULL) {
173 return NT_STATUS_NO_MEMORY;
174 }
175
176 ok = tevent_req_poll(subreq, ev);
177 if (!ok) {
178 return NT_STATUS_INTERNAL_ERROR;
179 }
180
181 status = auth_check_password_recv(subreq, mem_ctx, user_info_dc);
182 TALLOC_FREE(subreq);
183
184 return status;
185}
186
187_PUBLIC_ NTSTATUS auth_check_password_wrapper(struct auth4_context *auth_ctx,
188 TALLOC_CTX *mem_ctx,
189 const struct auth_usersupplied_info *user_info,
190 void **server_returned_info,
191 DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
192{
193 struct auth_user_info_dc *user_info_dc;
194 NTSTATUS status = auth_check_password(auth_ctx, mem_ctx, user_info, &user_info_dc);
195
196 if (NT_STATUS_IS_OK(status)) {
197 *server_returned_info = user_info_dc;
198
199 if (user_session_key) {
200 DEBUG(10, ("Got NT session key of length %u\n",
201 (unsigned)user_info_dc->user_session_key.length));
202 *user_session_key = user_info_dc->user_session_key;
203 talloc_steal(mem_ctx, user_session_key->data);
204 user_info_dc->user_session_key = data_blob_null;
205 }
206
207 if (lm_session_key) {
208 DEBUG(10, ("Got LM session key of length %u\n",
209 (unsigned)user_info_dc->lm_session_key.length));
210 *lm_session_key = user_info_dc->lm_session_key;
211 talloc_steal(mem_ctx, lm_session_key->data);
212 user_info_dc->lm_session_key = data_blob_null;
213 }
214 }
215
216 return status;
217}
218
219struct auth_check_password_state {
220 struct auth4_context *auth_ctx;
221 const struct auth_usersupplied_info *user_info;
222 struct auth_user_info_dc *user_info_dc;
223 struct auth_method_context *method;
224};
225
226static void auth_check_password_async_trigger(struct tevent_context *ev,
227 struct tevent_immediate *im,
228 void *private_data);
229/**
230 * Check a user's Plaintext, LM or NTLM password.
231 * async send hook
232 *
233 * Check a user's password, as given in the user_info struct and return various
234 * interesting details in the user_info_dc struct.
235 *
236 * The return value takes precedence over the contents of the user_info_dc
237 * struct. When the return is other than NT_STATUS_OK the contents
238 * of that structure is undefined.
239 *
240 * @param mem_ctx The memory context the request should operate on
241 *
242 * @param ev The tevent context the request should operate on
243 *
244 * @param auth_ctx Supplies the challenges and some other data.
245 * Must be created with make_auth_context(), and the challenges should be
246 * filled in, either at creation or by calling the challenge geneation
247 * function auth_get_challenge().
248 *
249 * @param user_info Contains the user supplied components, including the passwords.
250 *
251 * @return The request handle or NULL on no memory error.
252 *
253 **/
254
255_PUBLIC_ struct tevent_req *auth_check_password_send(TALLOC_CTX *mem_ctx,
256 struct tevent_context *ev,
257 struct auth4_context *auth_ctx,
258 const struct auth_usersupplied_info *user_info)
259{
260 struct tevent_req *req;
261 struct auth_check_password_state *state;
262 /* if all the modules say 'not for me' this is reasonable */
263 NTSTATUS nt_status;
264 uint8_t chal[8];
265 struct auth_usersupplied_info *user_info_tmp;
266 struct tevent_immediate *im;
267
268 DEBUG(3,("auth_check_password_send: "
269 "Checking password for unmapped user [%s]\\[%s]@[%s]\n",
270 user_info->client.domain_name, user_info->client.account_name,
271 user_info->workstation_name));
272
273 req = tevent_req_create(mem_ctx, &state,
274 struct auth_check_password_state);
275 if (req == NULL) {
276 return NULL;
277 }
278
279 state->auth_ctx = auth_ctx;
280 state->user_info = user_info;
281
282 if (!user_info->mapped_state) {
283 nt_status = map_user_info(auth_ctx->sam_ctx, req, lpcfg_workgroup(auth_ctx->lp_ctx),
284 user_info, &user_info_tmp);
285 if (tevent_req_nterror(req, nt_status)) {
286 return tevent_req_post(req, ev);
287 }
288 user_info = user_info_tmp;
289 state->user_info = user_info_tmp;
290 }
291
292 DEBUGADD(3,("auth_check_password_send: "
293 "mapped user is: [%s]\\[%s]@[%s]\n",
294 user_info->mapped.domain_name,
295 user_info->mapped.account_name,
296 user_info->workstation_name));
297
298 nt_status = auth_get_challenge(auth_ctx, chal);
299 if (tevent_req_nterror(req, nt_status)) {
300 DEBUG(0,("auth_check_password_send: "
301 "Invalid challenge (length %u) stored for "
302 "this auth context set_by %s - cannot continue: %s\n",
303 (unsigned)auth_ctx->challenge.data.length,
304 auth_ctx->challenge.set_by,
305 nt_errstr(nt_status)));
306 return tevent_req_post(req, ev);
307 }
308
309 if (auth_ctx->challenge.set_by) {
310 DEBUG(10,("auth_check_password_send: "
311 "auth_context challenge created by %s\n",
312 auth_ctx->challenge.set_by));
313 }
314
315 DEBUG(10, ("auth_check_password_send: challenge is: \n"));
316 dump_data(5, auth_ctx->challenge.data.data,
317 auth_ctx->challenge.data.length);
318
319 im = tevent_create_immediate(state);
320 if (tevent_req_nomem(im, req)) {
321 return tevent_req_post(req, ev);
322 }
323
324 tevent_schedule_immediate(im,
325 auth_ctx->event_ctx,
326 auth_check_password_async_trigger,
327 req);
328 return req;
329}
330
331static void auth_check_password_async_trigger(struct tevent_context *ev,
332 struct tevent_immediate *im,
333 void *private_data)
334{
335 struct tevent_req *req =
336 talloc_get_type_abort(private_data, struct tevent_req);
337 struct auth_check_password_state *state =
338 tevent_req_data(req, struct auth_check_password_state);
339 NTSTATUS status;
340 struct auth_method_context *method;
341
342 status = NT_STATUS_OK;
343
344 for (method=state->auth_ctx->methods; method; method = method->next) {
345
346 if (state->user_info->flags & USER_INFO_LOCAL_SAM_ONLY
347 && !(method->ops->flags & AUTH_METHOD_LOCAL_SAM)) {
348 continue;
349 }
350
351 /* we fill in state->method here so debug messages in
352 the callers know which method failed */
353 state->method = method;
354
355 /* check if the module wants to check the password */
356 status = method->ops->want_check(method, req, state->user_info);
357 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
358 DEBUG(11,("auth_check_password_send: "
359 "%s had nothing to say\n",
360 method->ops->name));
361 continue;
362 }
363
364 if (tevent_req_nterror(req, status)) {
365 return;
366 }
367
368 status = method->ops->check_password(method,
369 state,
370 state->user_info,
371 &state->user_info_dc);
372 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
373 /* the backend has handled the request */
374 break;
375 }
376 }
377
378 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
379 if (!(state->user_info->flags & USER_INFO_LOCAL_SAM_ONLY)) {
380 /* don't expose the NT_STATUS_NOT_IMPLEMENTED
381 * internals, except when the caller is only probing
382 * one method, as they may do the fallback
383 */
384 status = NT_STATUS_NO_SUCH_USER;
385 }
386 }
387
388 if (tevent_req_nterror(req, status)) {
389 return;
390 }
391
392 tevent_req_done(req);
393}
394
395/**
396 * Check a user's Plaintext, LM or NTLM password.
397 * async receive function
398 *
399 * The return value takes precedence over the contents of the user_info_dc
400 * struct. When the return is other than NT_STATUS_OK the contents
401 * of that structure is undefined.
402 *
403 *
404 * @param req The async request state
405 *
406 * @param mem_ctx The parent memory context for the user_info_dc structure
407 *
408 * @param user_info_dc If successful, contains information about the authentication,
409 * including a SAM_ACCOUNT struct describing the user.
410 *
411 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
412 *
413 **/
414
415_PUBLIC_ NTSTATUS auth_check_password_recv(struct tevent_req *req,
416 TALLOC_CTX *mem_ctx,
417 struct auth_user_info_dc **user_info_dc)
418{
419 struct auth_check_password_state *state =
420 tevent_req_data(req, struct auth_check_password_state);
421 NTSTATUS status;
422
423 if (tevent_req_is_nterror(req, &status)) {
424 DEBUG(2,("auth_check_password_recv: "
425 "%s authentication for user [%s\\%s] "
426 "FAILED with error %s\n",
427 (state->method ? state->method->ops->name : "NO_METHOD"),
428 state->user_info->mapped.domain_name,
429 state->user_info->mapped.account_name,
430 nt_errstr(status)));
431 tevent_req_received(req);
432 return status;
433 }
434
435 DEBUG(5,("auth_check_password_recv: "
436 "%s authentication for user [%s\\%s] succeeded\n",
437 state->method->ops->name,
438 state->user_info_dc->info->domain_name,
439 state->user_info_dc->info->account_name));
440
441 *user_info_dc = talloc_move(mem_ctx, &state->user_info_dc);
442
443 tevent_req_received(req);
444 return NT_STATUS_OK;
445}
446
447 /* Wrapper because we don't want to expose all callers to needing to
448 * know that session_info is generated from the main ldb, and because
449 * we need to break a depenency loop between the DCE/RPC layer and the
450 * generation of unix tokens via IRPC */
451static NTSTATUS auth_generate_session_info_wrapper(struct auth4_context *auth_context,
452 TALLOC_CTX *mem_ctx,
453 void *server_returned_info,
454 const char *original_user_name,
455 uint32_t session_info_flags,
456 struct auth_session_info **session_info)
457{
458 NTSTATUS status;
459 struct auth_user_info_dc *user_info_dc = talloc_get_type_abort(server_returned_info, struct auth_user_info_dc);
460
461 if (user_info_dc->info->authenticated) {
462 session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
463 }
464
465 status = auth_generate_session_info(mem_ctx, auth_context->lp_ctx,
466 auth_context->sam_ctx, user_info_dc,
467 session_info_flags, session_info);
468 if (!NT_STATUS_IS_OK(status)) {
469 return status;
470 }
471
472 if ((session_info_flags & AUTH_SESSION_INFO_UNIX_TOKEN)
473 && NT_STATUS_IS_OK(status)) {
474 status = auth_session_info_fill_unix(auth_context->event_ctx,
475 auth_context->lp_ctx,
476 original_user_name, *session_info);
477 if (!NT_STATUS_IS_OK(status)) {
478 TALLOC_FREE(*session_info);
479 }
480 }
481 return status;
482}
483
484/* Wrapper because we don't want to expose all callers to needing to
485 * know anything about the PAC or auth subsystem internal structures
486 * before we output a struct auth session_info */
487static NTSTATUS auth_generate_session_info_pac(struct auth4_context *auth_ctx,
488 TALLOC_CTX *mem_ctx,
489 struct smb_krb5_context *smb_krb5_context,
490 DATA_BLOB *pac_blob,
491 const char *principal_name,
492 const struct tsocket_address *remote_address,
493 uint32_t session_info_flags,
494 struct auth_session_info **session_info)
495{
496 NTSTATUS status;
497 struct auth_user_info_dc *user_info_dc;
498 TALLOC_CTX *tmp_ctx;
499
500 if (!pac_blob) {
501 return auth_generate_session_info_principal(auth_ctx, mem_ctx, principal_name,
502 NULL, session_info_flags, session_info);
503 }
504
505 tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gssapi_session_info context");
506 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
507
508 status = kerberos_pac_blob_to_user_info_dc(tmp_ctx,
509 *pac_blob,
510 smb_krb5_context->krb5_context,
511 &user_info_dc, NULL, NULL);
512 if (!NT_STATUS_IS_OK(status)) {
513 talloc_free(tmp_ctx);
514 return status;
515 }
516
517 if (user_info_dc->info->authenticated) {
518 session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
519 }
520
521 status = auth_generate_session_info_wrapper(auth_ctx, mem_ctx,
522 user_info_dc,
523 user_info_dc->info->account_name,
524 session_info_flags, session_info);
525 talloc_free(tmp_ctx);
526 return status;
527}
528
529/***************************************************************************
530 Make a auth_info struct for the auth subsystem
531 - Allow the caller to specify the methods to use, including optionally the SAM to use
532***************************************************************************/
533_PUBLIC_ NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char * const *methods,
534 struct tevent_context *ev,
535 struct imessaging_context *msg,
536 struct loadparm_context *lp_ctx,
537 struct ldb_context *sam_ctx,
538 struct auth4_context **auth_ctx)
539{
540 int i;
541 struct auth4_context *ctx;
542
543 auth4_init();
544
545 if (!ev) {
546 DEBUG(0,("auth_context_create: called with out event context\n"));
547 return NT_STATUS_INTERNAL_ERROR;
548 }
549
550 ctx = talloc_zero(mem_ctx, struct auth4_context);
551 NT_STATUS_HAVE_NO_MEMORY(ctx);
552 ctx->challenge.data = data_blob(NULL, 0);
553 ctx->methods = NULL;
554 ctx->event_ctx = ev;
555 ctx->msg_ctx = msg;
556 ctx->lp_ctx = lp_ctx;
557
558 if (sam_ctx) {
559 ctx->sam_ctx = sam_ctx;
560 } else {
561 ctx->sam_ctx = samdb_connect(ctx, ctx->event_ctx, ctx->lp_ctx, system_session(ctx->lp_ctx), 0);
562 }
563
564 for (i=0; methods && methods[i] ; i++) {
565 struct auth_method_context *method;
566
567 method = talloc(ctx, struct auth_method_context);
568 NT_STATUS_HAVE_NO_MEMORY(method);
569
570 method->ops = auth_backend_byname(methods[i]);
571 if (!method->ops) {
572 DEBUG(1,("auth_context_create: failed to find method=%s\n",
573 methods[i]));
574 return NT_STATUS_INTERNAL_ERROR;
575 }
576 method->auth_ctx = ctx;
577 method->depth = i;
578 DLIST_ADD_END(ctx->methods, method);
579 }
580
581 ctx->check_ntlm_password = auth_check_password_wrapper;
582 ctx->get_ntlm_challenge = auth_get_challenge;
583 ctx->set_ntlm_challenge = auth_context_set_challenge;
584 ctx->generate_session_info = auth_generate_session_info_wrapper;
585 ctx->generate_session_info_pac = auth_generate_session_info_pac;
586
587 *auth_ctx = ctx;
588
589 return NT_STATUS_OK;
590}
591
592const char **auth_methods_from_lp(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
593{
594 char **auth_methods = NULL;
595
596 switch (lpcfg_server_role(lp_ctx)) {
597 case ROLE_STANDALONE:
598 auth_methods = str_list_make(mem_ctx, "anonymous sam_ignoredomain", NULL);
599 break;
600 case ROLE_DOMAIN_MEMBER:
601 auth_methods = str_list_make(mem_ctx, "anonymous sam winbind", NULL);
602 break;
603 case ROLE_DOMAIN_BDC:
604 case ROLE_DOMAIN_PDC:
605 case ROLE_ACTIVE_DIRECTORY_DC:
606 auth_methods = str_list_make(mem_ctx, "anonymous sam_ignoredomain winbind", NULL);
607 break;
608 }
609 return discard_const_p(const char *, auth_methods);
610}
611
612/***************************************************************************
613 Make a auth_info struct for the auth subsystem
614 - Uses default auth_methods, depending on server role and smb.conf settings
615***************************************************************************/
616_PUBLIC_ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx,
617 struct tevent_context *ev,
618 struct imessaging_context *msg,
619 struct loadparm_context *lp_ctx,
620 struct auth4_context **auth_ctx)
621{
622 NTSTATUS status;
623 const char **auth_methods;
624 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
625 if (!tmp_ctx) {
626 return NT_STATUS_NO_MEMORY;
627 }
628
629 auth_methods = auth_methods_from_lp(tmp_ctx, lp_ctx);
630 if (!auth_methods) {
631 return NT_STATUS_INVALID_PARAMETER;
632 }
633 status = auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, NULL, auth_ctx);
634 talloc_free(tmp_ctx);
635 return status;
636}
637
638/* the list of currently registered AUTH backends */
639static struct auth_backend {
640 const struct auth_operations *ops;
641} *backends = NULL;
642static int num_backends;
643
644/*
645 register a AUTH backend.
646
647 The 'name' can be later used by other backends to find the operations
648 structure for this backend.
649*/
650_PUBLIC_ NTSTATUS auth_register(const struct auth_operations *ops)
651{
652 struct auth_operations *new_ops;
653
654 if (auth_backend_byname(ops->name) != NULL) {
655 /* its already registered! */
656 DEBUG(0,("AUTH backend '%s' already registered\n",
657 ops->name));
658 return NT_STATUS_OBJECT_NAME_COLLISION;
659 }
660
661 backends = talloc_realloc(talloc_autofree_context(), backends,
662 struct auth_backend, num_backends+1);
663 NT_STATUS_HAVE_NO_MEMORY(backends);
664
665 new_ops = (struct auth_operations *)talloc_memdup(backends, ops, sizeof(*ops));
666 NT_STATUS_HAVE_NO_MEMORY(new_ops);
667 new_ops->name = talloc_strdup(new_ops, ops->name);
668 NT_STATUS_HAVE_NO_MEMORY(new_ops->name);
669
670 backends[num_backends].ops = new_ops;
671
672 num_backends++;
673
674 DEBUG(3,("AUTH backend '%s' registered\n",
675 ops->name));
676
677 return NT_STATUS_OK;
678}
679
680/*
681 return the operations structure for a named backend of the specified type
682*/
683const struct auth_operations *auth_backend_byname(const char *name)
684{
685 int i;
686
687 for (i=0;i<num_backends;i++) {
688 if (strcmp(backends[i].ops->name, name) == 0) {
689 return backends[i].ops;
690 }
691 }
692
693 return NULL;
694}
695
696/*
697 return the AUTH interface version, and the size of some critical types
698 This can be used by backends to either detect compilation errors, or provide
699 multiple implementations for different smbd compilation options in one module
700*/
701const struct auth_critical_sizes *auth_interface_version(void)
702{
703 static const struct auth_critical_sizes critical_sizes = {
704 AUTH4_INTERFACE_VERSION,
705 sizeof(struct auth_operations),
706 sizeof(struct auth_method_context),
707 sizeof(struct auth4_context),
708 sizeof(struct auth_usersupplied_info),
709 sizeof(struct auth_user_info_dc)
710 };
711
712 return &critical_sizes;
713}
714
715_PUBLIC_ NTSTATUS auth4_init(void)
716{
717 static bool initialized = false;
718#define _MODULE_PROTO(init) extern NTSTATUS init(void);
719 STATIC_auth4_MODULES_PROTO;
720 init_module_fn static_init[] = { STATIC_auth4_MODULES };
721
722 if (initialized) return NT_STATUS_OK;
723 initialized = true;
724
725 run_init_functions(static_init);
726
727 return NT_STATUS_OK;
728}
Note: See TracBrowser for help on using the repository browser.