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:
committed by
Gerald (Jerry) Carter
parent
95e849bf94
commit
3c0d16b823
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user