1
0
mirror of https://github.com/samba-team/samba.git synced 2025-11-05 04:23:51 +03:00

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 commit is contained in:
Stefan Metzmacher
2005-01-09 12:55:25 +00:00
committed by Gerald (Jerry) Carter
parent 95e849bf94
commit 3c0d16b823
20 changed files with 1260 additions and 1630 deletions

View File

@@ -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;
NTSTATUS nt_status;
struct auth_method_context *method;
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;
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);
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;
}
mem_ctx = talloc_init("auth_get_challenge for module %s", auth_method->name);
if (!mem_ctx) {
smb_panic("talloc_init() failed!");
}
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);
auth_ctx->challenge.data = challenge;
auth_ctx->challenge.set_by = method->ops->name;
break;
}
if (!challenge_set_by) {
if (!auth_ctx->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);
generate_random_buffer(chal, 8);
auth_context->challenge_set_by=challenge_set_by;
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";
return auth_context->challenge.data;
}
/**
* 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.
**/
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;
if (!NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
method_name = method->ops->name;
nt_status = result;
break;
}
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_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);
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;
}
DEBUG(5,("auth_check_password: %s authentication for user [%s\\%s] succeeded\n",
method_name, (*server_info)->domain_name, (*server_info)->account_name));
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;
}
}
/***************************************************************************
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);
(*auth_context)->check_ntlm_password = check_ntlm_password;
(*auth_context)->get_ntlm_challenge = get_ntlm_challenge;
return NT_STATUS_OK;
}
/***************************************************************************
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));
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;
p = strchr(module_name, ':');
if (p) {
*p = 0;
module_params = p+1;
trim_string(module_params, " ", " ");
for (i=0; methods[i] ; i++) {
struct auth_method_context *method;
method = talloc(ctx, struct auth_method_context);
NT_STATUS_HAVE_NO_MEMORY(method);
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;
}
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;
}
/***************************************************************************
Make a auth_context struct for the auth subsystem
***************************************************************************/
NTSTATUS make_auth_context_subsystem(TALLOC_CTX *mem_ctx, struct auth_context **auth_context)
{
char **auth_method_list = NULL;
NTSTATUS nt_status;
if (lp_auth_methods() && !str_list_copy(&auth_method_list, lp_auth_methods())) {
return NT_STATUS_NO_MEMORY;
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;