addns: Remove unused empty header file
[Samba/gebeck_regimport.git] / source4 / auth / ntlm / auth.c
blob74e97cfd7d4aa04629231e8c67814c99c3dc2a17
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"
31 /***************************************************************************
32 Set a fixed challenge
33 ***************************************************************************/
34 _PUBLIC_ NTSTATUS auth_context_set_challenge(struct auth4_context *auth_ctx, const uint8_t chal[8], const char *set_by)
36 auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
37 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
39 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
40 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
42 return NT_STATUS_OK;
45 /***************************************************************************
46 Set a fixed challenge
47 ***************************************************************************/
48 _PUBLIC_ bool auth_challenge_may_be_modified(struct auth4_context *auth_ctx)
50 return auth_ctx->challenge.may_be_modified;
53 /****************************************************************************
54 Try to get a challenge out of the various authentication modules.
55 Returns a const char of length 8 bytes.
56 ****************************************************************************/
57 _PUBLIC_ NTSTATUS auth_get_challenge(struct auth4_context *auth_ctx, uint8_t chal[8])
59 NTSTATUS nt_status;
60 struct auth_method_context *method;
62 if (auth_ctx->challenge.data.length == 8) {
63 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
64 auth_ctx->challenge.set_by));
65 memcpy(chal, auth_ctx->challenge.data.data, 8);
66 return NT_STATUS_OK;
69 for (method = auth_ctx->methods; method; method = method->next) {
70 nt_status = method->ops->get_challenge(method, auth_ctx, chal);
71 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
72 continue;
75 NT_STATUS_NOT_OK_RETURN(nt_status);
77 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
78 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
79 auth_ctx->challenge.set_by = method->ops->name;
81 break;
84 if (!auth_ctx->challenge.set_by) {
85 generate_random_buffer(chal, 8);
87 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
88 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
89 auth_ctx->challenge.set_by = "random";
91 auth_ctx->challenge.may_be_modified = true;
94 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
95 auth_ctx->challenge.set_by));
97 return NT_STATUS_OK;
100 /****************************************************************************
101 Used in the gensec_gssapi and gensec_krb5 server-side code, where the
102 PAC isn't available, and for tokenGroups in the DSDB stack.
104 Supply either a principal or a DN
105 ****************************************************************************/
106 _PUBLIC_ NTSTATUS auth_get_user_info_dc_principal(TALLOC_CTX *mem_ctx,
107 struct auth4_context *auth_ctx,
108 const char *principal,
109 struct ldb_dn *user_dn,
110 struct auth_user_info_dc **user_info_dc)
112 NTSTATUS nt_status;
113 struct auth_method_context *method;
115 for (method = auth_ctx->methods; method; method = method->next) {
116 if (!method->ops->get_user_info_dc_principal) {
117 continue;
120 nt_status = method->ops->get_user_info_dc_principal(mem_ctx, auth_ctx, principal, user_dn, user_info_dc);
121 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
122 continue;
125 return nt_status;
128 return NT_STATUS_NOT_IMPLEMENTED;
132 * Check a user's Plaintext, LM or NTLM password.
133 * (sync version)
135 * Check a user's password, as given in the user_info struct and return various
136 * interesting details in the user_info_dc struct.
138 * The return value takes precedence over the contents of the user_info_dc
139 * struct. When the return is other than NT_STATUS_OK the contents
140 * of that structure is undefined.
142 * @param auth_ctx Supplies the challenges and some other data.
143 * Must be created with auth_context_create(), and the challenges should be
144 * filled in, either at creation or by calling the challenge geneation
145 * function auth_get_challenge().
147 * @param user_info Contains the user supplied components, including the passwords.
149 * @param mem_ctx The parent memory context for the user_info_dc structure
151 * @param user_info_dc If successful, contains information about the authentication,
152 * including a SAM_ACCOUNT struct describing the user.
154 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
158 _PUBLIC_ NTSTATUS auth_check_password(struct auth4_context *auth_ctx,
159 TALLOC_CTX *mem_ctx,
160 const struct auth_usersupplied_info *user_info,
161 struct auth_user_info_dc **user_info_dc)
163 struct tevent_req *subreq;
164 struct tevent_context *ev;
165 bool ok;
166 NTSTATUS status;
168 /*TODO: create a new event context here! */
169 ev = auth_ctx->event_ctx;
171 subreq = auth_check_password_send(mem_ctx,
173 auth_ctx,
174 user_info);
175 if (subreq == NULL) {
176 return NT_STATUS_NO_MEMORY;
179 ok = tevent_req_poll(subreq, ev);
180 if (!ok) {
181 return NT_STATUS_INTERNAL_ERROR;
184 status = auth_check_password_recv(subreq, mem_ctx, user_info_dc);
185 TALLOC_FREE(subreq);
187 return status;
190 struct auth_check_password_state {
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;
197 static void auth_check_password_async_trigger(struct tevent_context *ev,
198 struct tevent_immediate *im,
199 void *private_data);
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];
236 struct auth_usersupplied_info *user_info_tmp;
237 struct tevent_immediate *im;
239 DEBUG(3,("auth_check_password_send: "
240 "Checking password for unmapped user [%s]\\[%s]@[%s]\n",
241 user_info->client.domain_name, user_info->client.account_name,
242 user_info->workstation_name));
244 req = tevent_req_create(mem_ctx, &state,
245 struct auth_check_password_state);
246 if (req == NULL) {
247 return NULL;
250 state->auth_ctx = auth_ctx;
251 state->user_info = user_info;
253 if (!user_info->mapped_state) {
254 nt_status = map_user_info(req, lpcfg_workgroup(auth_ctx->lp_ctx),
255 user_info, &user_info_tmp);
256 if (tevent_req_nterror(req, nt_status)) {
257 return tevent_req_post(req, ev);
259 user_info = user_info_tmp;
260 state->user_info = user_info_tmp;
263 DEBUGADD(3,("auth_check_password_send: "
264 "mapped user is: [%s]\\[%s]@[%s]\n",
265 user_info->mapped.domain_name,
266 user_info->mapped.account_name,
267 user_info->workstation_name));
269 nt_status = auth_get_challenge(auth_ctx, chal);
270 if (tevent_req_nterror(req, nt_status)) {
271 DEBUG(0,("auth_check_password_send: "
272 "Invalid challenge (length %u) stored for "
273 "this auth context set_by %s - cannot continue: %s\n",
274 (unsigned)auth_ctx->challenge.data.length,
275 auth_ctx->challenge.set_by,
276 nt_errstr(nt_status)));
277 return tevent_req_post(req, ev);
280 if (auth_ctx->challenge.set_by) {
281 DEBUG(10,("auth_check_password_send: "
282 "auth_context challenge created by %s\n",
283 auth_ctx->challenge.set_by));
286 DEBUG(10, ("auth_check_password_send: challenge is: \n"));
287 dump_data(5, auth_ctx->challenge.data.data,
288 auth_ctx->challenge.data.length);
290 im = tevent_create_immediate(state);
291 if (tevent_req_nomem(im, req)) {
292 return tevent_req_post(req, ev);
295 tevent_schedule_immediate(im,
296 auth_ctx->event_ctx,
297 auth_check_password_async_trigger,
298 req);
299 return req;
302 static void auth_check_password_async_trigger(struct tevent_context *ev,
303 struct tevent_immediate *im,
304 void *private_data)
306 struct tevent_req *req =
307 talloc_get_type_abort(private_data, struct tevent_req);
308 struct auth_check_password_state *state =
309 tevent_req_data(req, struct auth_check_password_state);
310 NTSTATUS status;
311 struct auth_method_context *method;
313 status = NT_STATUS_OK;
315 for (method=state->auth_ctx->methods; method; method = method->next) {
317 /* we fill in state->method here so debug messages in
318 the callers know which method failed */
319 state->method = method;
321 /* check if the module wants to check the password */
322 status = method->ops->want_check(method, req, state->user_info);
323 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
324 DEBUG(11,("auth_check_password_send: "
325 "%s had nothing to say\n",
326 method->ops->name));
327 continue;
330 if (tevent_req_nterror(req, status)) {
331 return;
334 status = method->ops->check_password(method,
335 state,
336 state->user_info,
337 &state->user_info_dc);
338 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
339 /* the backend has handled the request */
340 break;
344 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
345 /* don't expose the NT_STATUS_NOT_IMPLEMENTED
346 internals */
347 status = NT_STATUS_NO_SUCH_USER;
350 if (tevent_req_nterror(req, status)) {
351 return;
354 tevent_req_done(req);
358 * Check a user's Plaintext, LM or NTLM password.
359 * async receive function
361 * The return value takes precedence over the contents of the user_info_dc
362 * struct. When the return is other than NT_STATUS_OK the contents
363 * of that structure is undefined.
366 * @param req The async request state
368 * @param mem_ctx The parent memory context for the user_info_dc structure
370 * @param user_info_dc If successful, contains information about the authentication,
371 * including a SAM_ACCOUNT struct describing the user.
373 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
377 _PUBLIC_ NTSTATUS auth_check_password_recv(struct tevent_req *req,
378 TALLOC_CTX *mem_ctx,
379 struct auth_user_info_dc **user_info_dc)
381 struct auth_check_password_state *state =
382 tevent_req_data(req, struct auth_check_password_state);
383 NTSTATUS status;
385 if (tevent_req_is_nterror(req, &status)) {
386 DEBUG(2,("auth_check_password_recv: "
387 "%s authentication for user [%s\\%s] "
388 "FAILED with error %s\n",
389 (state->method ? state->method->ops->name : "NO_METHOD"),
390 state->user_info->mapped.domain_name,
391 state->user_info->mapped.account_name,
392 nt_errstr(status)));
393 tevent_req_received(req);
394 return status;
397 DEBUG(5,("auth_check_password_recv: "
398 "%s authentication for user [%s\\%s] succeeded\n",
399 state->method->ops->name,
400 state->user_info_dc->info->domain_name,
401 state->user_info_dc->info->account_name));
403 *user_info_dc = talloc_move(mem_ctx, &state->user_info_dc);
405 tevent_req_received(req);
406 return NT_STATUS_OK;
409 /* Wrapper because we don't want to expose all callers to needing to
410 * know that session_info is generated from the main ldb, and because
411 * we need to break a depenency loop between the DCE/RPC layer and the
412 * generation of unix tokens via IRPC */
413 static NTSTATUS auth_generate_session_info_wrapper(TALLOC_CTX *mem_ctx,
414 struct auth4_context *auth_context,
415 struct auth_user_info_dc *user_info_dc,
416 uint32_t session_info_flags,
417 struct auth_session_info **session_info)
419 NTSTATUS status = auth_generate_session_info(mem_ctx, auth_context->lp_ctx,
420 auth_context->sam_ctx, user_info_dc,
421 session_info_flags, session_info);
423 if ((session_info_flags & AUTH_SESSION_INFO_UNIX_TOKEN)
424 && NT_STATUS_IS_OK(status)) {
425 struct wbc_context *wbc_ctx = wbc_init(auth_context,
426 auth_context->msg_ctx,
427 auth_context->event_ctx);
428 if (!wbc_ctx) {
429 TALLOC_FREE(*session_info);
430 DEBUG(1, ("Cannot contact winbind to provide unix token\n"));
431 return NT_STATUS_INVALID_SERVER_STATE;
433 status = auth_session_info_fill_unix(wbc_ctx, auth_context->lp_ctx,
434 *session_info);
435 if (!NT_STATUS_IS_OK(status)) {
436 TALLOC_FREE(*session_info);
438 TALLOC_FREE(wbc_ctx);
440 return status;
443 /***************************************************************************
444 Make a auth_info struct for the auth subsystem
445 - Allow the caller to specify the methods to use, including optionally the SAM to use
446 ***************************************************************************/
447 _PUBLIC_ NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char **methods,
448 struct tevent_context *ev,
449 struct imessaging_context *msg,
450 struct loadparm_context *lp_ctx,
451 struct ldb_context *sam_ctx,
452 struct auth4_context **auth_ctx)
454 int i;
455 struct auth4_context *ctx;
457 auth4_init();
459 if (!ev) {
460 DEBUG(0,("auth_context_create: called with out event context\n"));
461 return NT_STATUS_INTERNAL_ERROR;
464 ctx = talloc(mem_ctx, struct auth4_context);
465 NT_STATUS_HAVE_NO_MEMORY(ctx);
466 ctx->challenge.set_by = NULL;
467 ctx->challenge.may_be_modified = false;
468 ctx->challenge.data = data_blob(NULL, 0);
469 ctx->methods = NULL;
470 ctx->event_ctx = ev;
471 ctx->msg_ctx = msg;
472 ctx->lp_ctx = lp_ctx;
474 if (sam_ctx) {
475 ctx->sam_ctx = sam_ctx;
476 } else {
477 ctx->sam_ctx = samdb_connect(ctx, ctx->event_ctx, ctx->lp_ctx, system_session(ctx->lp_ctx), 0);
480 for (i=0; methods && methods[i] ; i++) {
481 struct auth_method_context *method;
483 method = talloc(ctx, struct auth_method_context);
484 NT_STATUS_HAVE_NO_MEMORY(method);
486 method->ops = auth_backend_byname(methods[i]);
487 if (!method->ops) {
488 DEBUG(1,("auth_context_create: failed to find method=%s\n",
489 methods[i]));
490 return NT_STATUS_INTERNAL_ERROR;
492 method->auth_ctx = ctx;
493 method->depth = i;
494 DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
497 ctx->check_password = auth_check_password;
498 ctx->get_challenge = auth_get_challenge;
499 ctx->set_challenge = auth_context_set_challenge;
500 ctx->challenge_may_be_modified = auth_challenge_may_be_modified;
501 ctx->get_user_info_dc_principal = auth_get_user_info_dc_principal;
502 ctx->generate_session_info = auth_generate_session_info_wrapper;
504 *auth_ctx = ctx;
506 return NT_STATUS_OK;
509 const char **auth_methods_from_lp(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
511 char **auth_methods = NULL;
513 switch (lpcfg_server_role(lp_ctx)) {
514 case ROLE_STANDALONE:
515 auth_methods = str_list_make(mem_ctx, "anonymous sam_ignoredomain", NULL);
516 break;
517 case ROLE_DOMAIN_MEMBER:
518 auth_methods = str_list_make(mem_ctx, "anonymous sam winbind", NULL);
519 break;
520 case ROLE_DOMAIN_BDC:
521 case ROLE_DOMAIN_PDC:
522 auth_methods = str_list_make(mem_ctx, "anonymous sam_ignoredomain winbind", NULL);
523 break;
525 return (const char **) auth_methods;
528 /***************************************************************************
529 Make a auth_info struct for the auth subsystem
530 - Uses default auth_methods, depending on server role and smb.conf settings
531 ***************************************************************************/
532 _PUBLIC_ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx,
533 struct tevent_context *ev,
534 struct imessaging_context *msg,
535 struct loadparm_context *lp_ctx,
536 struct auth4_context **auth_ctx)
538 NTSTATUS status;
539 const char **auth_methods;
540 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
541 if (!tmp_ctx) {
542 return NT_STATUS_NO_MEMORY;
545 auth_methods = auth_methods_from_lp(tmp_ctx, lp_ctx);
546 if (!auth_methods) {
547 return NT_STATUS_INVALID_PARAMETER;
549 status = auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, NULL, auth_ctx);
550 talloc_free(tmp_ctx);
551 return status;
554 /* Create an auth context from an open LDB.
556 This allows us not to re-open the LDB when we need to do a some authentication logic (such as tokenGroups)
559 NTSTATUS auth_context_create_from_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, struct auth4_context **auth_ctx)
561 NTSTATUS status;
562 const char **auth_methods;
563 struct loadparm_context *lp_ctx = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"), struct loadparm_context);
564 struct tevent_context *ev = ldb_get_event_context(ldb);
566 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
567 if (!tmp_ctx) {
568 return NT_STATUS_NO_MEMORY;
571 auth_methods = auth_methods_from_lp(tmp_ctx, lp_ctx);
572 if (!auth_methods) {
573 return NT_STATUS_INVALID_PARAMETER;
575 status = auth_context_create_methods(mem_ctx, auth_methods, ev, NULL, lp_ctx, ldb, auth_ctx);
576 talloc_free(tmp_ctx);
577 return status;
580 /* the list of currently registered AUTH backends */
581 static struct auth_backend {
582 const struct auth_operations *ops;
583 } *backends = NULL;
584 static int num_backends;
587 register a AUTH backend.
589 The 'name' can be later used by other backends to find the operations
590 structure for this backend.
592 _PUBLIC_ NTSTATUS auth_register(const struct auth_operations *ops)
594 struct auth_operations *new_ops;
596 if (auth_backend_byname(ops->name) != NULL) {
597 /* its already registered! */
598 DEBUG(0,("AUTH backend '%s' already registered\n",
599 ops->name));
600 return NT_STATUS_OBJECT_NAME_COLLISION;
603 backends = talloc_realloc(talloc_autofree_context(), backends,
604 struct auth_backend, num_backends+1);
605 NT_STATUS_HAVE_NO_MEMORY(backends);
607 new_ops = (struct auth_operations *)talloc_memdup(backends, ops, sizeof(*ops));
608 NT_STATUS_HAVE_NO_MEMORY(new_ops);
609 new_ops->name = talloc_strdup(new_ops, ops->name);
610 NT_STATUS_HAVE_NO_MEMORY(new_ops->name);
612 backends[num_backends].ops = new_ops;
614 num_backends++;
616 DEBUG(3,("AUTH backend '%s' registered\n",
617 ops->name));
619 return NT_STATUS_OK;
623 return the operations structure for a named backend of the specified type
625 const struct auth_operations *auth_backend_byname(const char *name)
627 int i;
629 for (i=0;i<num_backends;i++) {
630 if (strcmp(backends[i].ops->name, name) == 0) {
631 return backends[i].ops;
635 return NULL;
639 return the AUTH interface version, and the size of some critical types
640 This can be used by backends to either detect compilation errors, or provide
641 multiple implementations for different smbd compilation options in one module
643 const struct auth_critical_sizes *auth_interface_version(void)
645 static const struct auth_critical_sizes critical_sizes = {
646 AUTH4_INTERFACE_VERSION,
647 sizeof(struct auth_operations),
648 sizeof(struct auth_method_context),
649 sizeof(struct auth4_context),
650 sizeof(struct auth_usersupplied_info),
651 sizeof(struct auth_user_info_dc)
654 return &critical_sizes;
657 _PUBLIC_ NTSTATUS auth4_init(void)
659 static bool initialized = false;
660 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
661 STATIC_auth4_MODULES_PROTO;
662 init_module_fn static_init[] = { STATIC_auth4_MODULES };
664 if (initialized) return NT_STATUS_OK;
665 initialized = true;
667 run_init_functions(static_init);
669 return NT_STATUS_OK;