From 46a32687da249174a666d9166fccbe705c8beba0 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sun, 9 Jan 2005 12:55:25 +0000 Subject: r4620: - add interface functions to the auth subsystem so that callers doesn't need to use function pointers anymore - make the module init much easier - a lot of cleanups don't try to read the diff in auth/ better read the new files it passes test_echo.sh and test_rpc.sh abartlet: please fix spelling fixes metze (This used to be commit 3c0d16b8236451f2cfd38fc3db8ae2906106d847) --- source4/auth/auth.c | 403 ++++++++++++++++------------------------------------ 1 file changed, 122 insertions(+), 281 deletions(-) (limited to 'source4/auth/auth.c') diff --git a/source4/auth/auth.c b/source4/auth/auth.c index 33f3020382..674e9a7f46 100644 --- a/source4/auth/auth.c +++ b/source4/auth/auth.c @@ -2,6 +2,7 @@ Unix SMB/CIFS implementation. Password and authentication handling Copyright (C) Andrew Bartlett 2001-2002 + Copyright (C) Stefan Metzmacher 2005 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,111 +23,82 @@ #include "dlinklist.h" #include "auth/auth.h" -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_AUTH +/*************************************************************************** + Set a fixed challenge +***************************************************************************/ +NTSTATUS auth_context_set_challenge(struct auth_context *auth_ctx, const uint8_t chal[8], const char *set_by) +{ + auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by); + NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by); + + auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8); + NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data); + + return NT_STATUS_OK; +} + +/*************************************************************************** + Set a fixed challenge +***************************************************************************/ +BOOL auth_challenge_may_be_modified(struct auth_context *auth_ctx) +{ + return auth_ctx->challenge.may_be_modified; +} /**************************************************************************** Try to get a challenge out of the various authentication modules. Returns a const char of length 8 bytes. ****************************************************************************/ - -static const uint8_t *get_ntlm_challenge(struct auth_context *auth_context) +NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, const uint8_t **_chal) { - DATA_BLOB challenge = data_blob(NULL, 0); - const char *challenge_set_by = NULL; - struct auth_methods *auth_method; - TALLOC_CTX *mem_ctx; - - if (auth_context->challenge.length) { - DEBUG(5, ("get_ntlm_challenge (auth subsystem): returning previous challenge by module %s (normal)\n", - auth_context->challenge_set_by)); - return auth_context->challenge.data; + NTSTATUS nt_status; + struct auth_method_context *method; + + if (auth_ctx->challenge.data.length) { + DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n", + auth_ctx->challenge.set_by)); + *_chal = auth_ctx->challenge.data.data; + return NT_STATUS_OK; } - auth_context->challenge_may_be_modified = False; + for (method = auth_ctx->methods; method; method = method->next) { + DATA_BLOB challenge = data_blob(NULL,0); - for (auth_method = auth_context->auth_method_list; auth_method; auth_method = auth_method->next) { - if (auth_method->get_chal == NULL) { - DEBUG(5, ("auth_get_challenge: module %s did not want to specify a challenge\n", auth_method->name)); + nt_status = method->ops->get_challenge(method, auth_ctx, &challenge); + if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) { continue; } - DEBUG(5, ("auth_get_challenge: getting challenge from module %s\n", auth_method->name)); - if (challenge_set_by != NULL) { - DEBUG(1, ("auth_get_challenge: CONFIGURATION ERROR: authentication method %s has already specified a challenge. Challenge by %s ignored.\n", - challenge_set_by, auth_method->name)); - continue; - } + NT_STATUS_NOT_OK_RETURN(nt_status); - mem_ctx = talloc_init("auth_get_challenge for module %s", auth_method->name); - if (!mem_ctx) { - smb_panic("talloc_init() failed!"); + if (challenge.length != 8) { + DEBUG(0, ("auth_get_challenge: invalid challenge (length %u) by mothod [%s]\n", + challenge.length, method->ops->name)); + return NT_STATUS_INTERNAL_ERROR; } - - challenge = auth_method->get_chal(auth_context, &auth_method->private_data, mem_ctx); - if (!challenge.length) { - DEBUG(3, ("auth_get_challenge: getting challenge from authentication method %s FAILED.\n", - auth_method->name)); - } else { - DEBUG(5, ("auth_get_challenge: sucessfully got challenge from module %s\n", auth_method->name)); - auth_context->challenge = challenge; - challenge_set_by = auth_method->name; - auth_context->challenge_set_method = auth_method; - } - talloc_destroy(mem_ctx); - } - - if (!challenge_set_by) { - uint8_t chal[8]; - - generate_random_buffer(chal, sizeof(chal)); - auth_context->challenge = data_blob_talloc(auth_context, - chal, sizeof(chal)); - - challenge_set_by = "random"; - auth_context->challenge_may_be_modified = True; - } - - DEBUG(5, ("auth_context challenge created by %s\n", challenge_set_by)); - DEBUG(5, ("challenge is: \n")); - dump_data(5, auth_context->challenge.data, auth_context->challenge.length); - - SMB_ASSERT(auth_context->challenge.length == 8); - auth_context->challenge_set_by=challenge_set_by; + auth_ctx->challenge.data = challenge; + auth_ctx->challenge.set_by = method->ops->name; - return auth_context->challenge.data; -} + break; + } + if (!auth_ctx->challenge.set_by) { + uint8_t chal[8]; + generate_random_buffer(chal, 8); -/** - * Check user is in correct domain (if required) - * - * @param user Only used to fill in the debug message - * - * @param domain The domain to be verified - * - * @return True if the user can connect with that domain, - * False otherwise. -**/ + auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8); + NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data); + auth_ctx->challenge.set_by = "random"; -static BOOL check_domain_match(const char *user, const char *domain) -{ - /* - * If we aren't serving to trusted domains, we must make sure that - * the validation request comes from an account in the same domain - * as the Samba server - */ - - if (!lp_allow_trusted_domains() && - !(strequal("", domain) || - strequal(lp_workgroup(), domain) || - is_myname(domain))) { - DEBUG(1, ("check_domain_match: Attempt to connect as user %s from domain %s denied.\n", user, domain)); - return False; - } else { - return True; + auth_ctx->challenge.may_be_modified = True; } + + DEBUG(10,("auth_get_challenge: challenge set by %s\n", + auth_ctx->challenge.set_by)); + + *_chal = auth_ctx->challenge.data.data; + return NT_STATUS_OK; } /** @@ -154,41 +126,38 @@ static BOOL check_domain_match(const char *user, const char *domain) * **/ -static NTSTATUS check_ntlm_password(struct auth_context *auth_context, - const struct auth_usersupplied_info *user_info, - TALLOC_CTX *out_mem_ctx, - struct auth_serversupplied_info **server_info) +NTSTATUS auth_check_password(struct auth_context *auth_ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info, + struct auth_serversupplied_info **server_info) { /* if all the modules say 'not for me' this is reasonable */ NTSTATUS nt_status = NT_STATUS_NO_SUCH_USER; - struct auth_methods *auth_method; - TALLOC_CTX *mem_ctx; + struct auth_method_context *method; + const char *method_name = "NO METHOD"; + const uint8_t *challenge; - if (!user_info || !auth_context || !server_info) - return NT_STATUS_LOGON_FAILURE; + DEBUG(3, ("auth_check_password: Checking password for unmapped user [%s]\\[%s]@[%s]\n", + user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name)); - DEBUG(3, ("check_ntlm_password: Checking password for unmapped user [%s]\\[%s]@[%s] with the new password interface\n", - user_info->client_domain.str, user_info->smb_name.str, user_info->wksta_name.str)); + DEBUGADD(3,("auth_check_password: mapped user is: [%s]\\[%s]@[%s]\n", + user_info->domain_name, user_info->account_name, user_info->workstation_name)); - DEBUG(3, ("check_ntlm_password: mapped user is: [%s]\\[%s]@[%s]\n", - user_info->domain.str, user_info->internal_username.str, user_info->wksta_name.str)); + nt_status = auth_get_challenge(auth_ctx, &challenge); - if (auth_context->challenge.length == 0) { - /* get a challenge, if we have not asked for one yet */ - get_ntlm_challenge(auth_context); + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(0, ("auth_check_password: Invalid challenge (length %u) stored for this auth context set_by %s - cannot continue: %s\n", + auth_ctx->challenge.data.length, auth_ctx->challenge.set_by, nt_errstr(nt_status))); + return nt_status; } - if (auth_context->challenge.length != 8) { - DEBUG(0, ("check_ntlm_password: Invalid challenge stored for this auth context - cannot continue\n")); - return NT_STATUS_LOGON_FAILURE; + if (auth_ctx->challenge.set_by) { + DEBUG(10, ("auth_check_password: auth_context challenge created by %s\n", + auth_ctx->challenge.set_by)); } - if (auth_context->challenge_set_by) - DEBUG(10, ("check_ntlm_password: auth_context challenge created by %s\n", - auth_context->challenge_set_by)); - DEBUG(10, ("challenge is: \n")); - dump_data(5, auth_context->challenge.data, auth_context->challenge.length); + dump_data(5, auth_ctx->challenge.data.data, auth_ctx->challenge.data.length); #ifdef DEBUG_PASSWORD DEBUG(100, ("user_info has passwords of length %d and %d\n", @@ -199,204 +168,78 @@ static NTSTATUS check_ntlm_password(struct auth_context *auth_context, dump_data(100, user_info->nt_resp.data, user_info->nt_resp.length); #endif - /* This needs to be sorted: If it doesn't match, what should we do? */ - if (!check_domain_match(user_info->smb_name.str, user_info->domain.str)) - return NT_STATUS_LOGON_FAILURE; - - for (auth_method = auth_context->auth_method_list;auth_method; auth_method = auth_method->next) { + for (method = auth_ctx->methods; method; method = method->next) { NTSTATUS result; - - mem_ctx = talloc_init("%s authentication for user %s\\%s", auth_method->name, - user_info->domain.str, user_info->smb_name.str); - result = auth_method->auth(auth_context, auth_method->private_data, mem_ctx, user_info, server_info); + result = method->ops->check_password(method, mem_ctx, user_info, server_info); /* check if the module did anything */ - if ( NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_NOT_IMPLEMENTED) ) { - DEBUG(10,("check_ntlm_password: %s had nothing to say\n", auth_method->name)); - talloc_destroy(mem_ctx); - continue; - } - - nt_status = result; - - if (NT_STATUS_IS_OK(nt_status)) { - DEBUG(3, ("check_ntlm_password: %s authentication for user [%s] succeeded\n", - auth_method->name, user_info->smb_name.str)); - - /* Give the server info to the client to hold onto */ - talloc_reference(out_mem_ctx, *server_info); - } else { - DEBUG(5, ("check_ntlm_password: %s authentication for user [%s] FAILED with error %s\n", - auth_method->name, user_info->smb_name.str, nt_errstr(nt_status))); - } - - talloc_destroy(mem_ctx); - - if ( NT_STATUS_IS_OK(nt_status)) - { - break; + if (!NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) { + method_name = method->ops->name; + nt_status = result; + break; } - } - if (NT_STATUS_IS_OK(nt_status)) { - if (NT_STATUS_IS_OK(nt_status)) { - DEBUG((*server_info)->guest ? 5 : 2, - ("check_ntlm_password: %sauthentication for user [%s] -> [%s] succeeded\n", - (*server_info)->guest ? "guest " : "", - user_info->smb_name.str, - user_info->internal_username.str)); - } + DEBUG(11,("auth_check_password: %s had nothing to say\n", method->ops->name)); } if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(2, ("check_ntlm_password: Authentication for user [%s] -> [%s] FAILED with error %s\n", - user_info->smb_name.str, user_info->internal_username.str, - nt_errstr(nt_status))); - ZERO_STRUCTP(server_info); - } - return nt_status; -} - -/*************************************************************************** - Clear out a auth_context, and destroy the attached TALLOC_CTX -***************************************************************************/ - -void free_auth_context(struct auth_context **auth_context) -{ - struct auth_methods *auth_method; - - if (*auth_context) { - /* Free private data of context's authentication methods */ - for (auth_method = (*auth_context)->auth_method_list; auth_method; auth_method = auth_method->next) { - if (auth_method->free_private_data) { - auth_method->free_private_data (&auth_method->private_data); - auth_method->private_data = NULL; - } - } - - talloc_free(*auth_context); - *auth_context = NULL; + DEBUG(2,("auth_check_password: %s authentication for user [%s\\%s] FAILED with error %s\n", + method_name, user_info->domain_name, user_info->account_name, + nt_errstr(nt_status))); + return nt_status; } -} -/*************************************************************************** - Make a auth_info struct -***************************************************************************/ - -static NTSTATUS make_auth_context(TALLOC_CTX *mem_ctx, struct auth_context **auth_context) -{ - *auth_context = talloc_p(mem_ctx, struct auth_context); - if (!*auth_context) { - DEBUG(0,("make_auth_context: talloc failed!\n")); - return NT_STATUS_NO_MEMORY; - } - ZERO_STRUCTP(*auth_context); + DEBUG(5,("auth_check_password: %s authentication for user [%s\\%s] succeeded\n", + method_name, (*server_info)->domain_name, (*server_info)->account_name)); - (*auth_context)->check_ntlm_password = check_ntlm_password; - (*auth_context)->get_ntlm_challenge = get_ntlm_challenge; - - return NT_STATUS_OK; + return nt_status; } /*************************************************************************** Make a auth_info struct for the auth subsystem ***************************************************************************/ - -static NTSTATUS make_auth_context_text_list(TALLOC_CTX *mem_ctx, - struct auth_context **auth_context, char **text_list) +NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx, const char **methods, struct auth_context **auth_ctx) { - struct auth_methods *list = NULL; - struct auth_methods *t = NULL; - NTSTATUS nt_status; + int i; + struct auth_context *ctx; - if (!text_list) { - DEBUG(2,("make_auth_context_text_list: No auth method list!?\n")); - return NT_STATUS_UNSUCCESSFUL; + if (!methods) { + DEBUG(0,("auth_context_create: No auth method list!?\n")); + return NT_STATUS_INTERNAL_ERROR; } - - if (!NT_STATUS_IS_OK(nt_status = make_auth_context(mem_ctx, auth_context))) - return nt_status; - - for (;*text_list; text_list++) { - char *module_name = smb_xstrdup(*text_list); - char *module_params = NULL; - char *p; - const struct auth_operations *ops; - - DEBUG(5,("make_auth_context_text_list: Attempting to find an auth method to match %s\n", - *text_list)); - - p = strchr(module_name, ':'); - if (p) { - *p = 0; - module_params = p+1; - trim_string(module_params, " ", " "); - } - - trim_string(module_name, " ", " "); - - ops = auth_backend_byname(module_name); - if (!ops) { - DEBUG(5,("make_auth_context_text_list: Found auth method %s\n", *text_list)); - SAFE_FREE(module_name); - break; - } - if (NT_STATUS_IS_OK(ops->init(*auth_context, module_params, &t))) { - DEBUG(5,("make_auth_context_text_list: auth method %s has a valid init\n", - *text_list)); - DLIST_ADD_END(list, t, struct auth_methods *); - } else { - DEBUG(0,("make_auth_context_text_list: auth method %s did not correctly init\n", - *text_list)); - } - SAFE_FREE(module_name); - } - - (*auth_context)->auth_method_list = list; - - return nt_status; -} + ctx = talloc(mem_ctx, struct auth_context); + NT_STATUS_HAVE_NO_MEMORY(ctx); + ctx->challenge.set_by = NULL; + ctx->challenge.may_be_modified = False; + ctx->challenge.data = data_blob(NULL, 0); + ctx->methods = NULL; -/*************************************************************************** - Make a auth_context struct for the auth subsystem -***************************************************************************/ + for (i=0; methods[i] ; i++) { + struct auth_method_context *method; -NTSTATUS make_auth_context_subsystem(TALLOC_CTX *mem_ctx, struct auth_context **auth_context) -{ - char **auth_method_list = NULL; - NTSTATUS nt_status; + method = talloc(ctx, struct auth_method_context); + NT_STATUS_HAVE_NO_MEMORY(method); - if (lp_auth_methods() && !str_list_copy(&auth_method_list, lp_auth_methods())) { - return NT_STATUS_NO_MEMORY; + method->ops = auth_backend_byname(methods[i]); + if (!method->ops) { + DEBUG(1,("auth_context_create: failed to find method=%s\n", + methods[i])); + return NT_STATUS_INTERNAL_ERROR; + } + method->auth_ctx = ctx; + method->depth = i; + DLIST_ADD_END(ctx->methods, method, struct auth_method_context *); } - nt_status = make_auth_context_text_list(mem_ctx, auth_context, auth_method_list); - if (!NT_STATUS_IS_OK(nt_status)) { - str_list_free(&auth_method_list); - return nt_status; + if (!ctx->methods) { + return NT_STATUS_INTERNAL_ERROR; } - - str_list_free(&auth_method_list); - return nt_status; -} -/*************************************************************************** - Make a auth_info struct with a fixed challenge -***************************************************************************/ + *auth_ctx = ctx; -NTSTATUS make_auth_context_fixed(TALLOC_CTX *mem_ctx, - struct auth_context **auth_context, uint8_t chal[8]) -{ - NTSTATUS nt_status; - if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(mem_ctx, auth_context))) { - return nt_status; - } - - (*auth_context)->challenge = data_blob_talloc(*auth_context, chal, 8); - (*auth_context)->challenge_set_by = "fixed"; - return nt_status; + return NT_STATUS_OK; } /* the list of currently registered AUTH backends */ @@ -423,7 +266,6 @@ NTSTATUS auth_register(const void *_ops) return NT_STATUS_OBJECT_NAME_COLLISION; } - backends = realloc_p(backends, struct auth_backend, num_backends+1); if (!backends) { smb_panic("out of memory in auth_register"); @@ -468,11 +310,10 @@ const struct auth_critical_sizes *auth_interface_version(void) static const struct auth_critical_sizes critical_sizes = { AUTH_INTERFACE_VERSION, sizeof(struct auth_operations), - sizeof(struct auth_methods), + sizeof(struct auth_method_context), sizeof(struct auth_context), sizeof(struct auth_usersupplied_info), - sizeof(struct auth_serversupplied_info), - sizeof(struct auth_str), + sizeof(struct auth_serversupplied_info) }; return &critical_sizes; -- cgit