mirror of
https://github.com/samba-team/samba.git
synced 2025-01-13 13:18:06 +03:00
Refactor the NTLMSSP code again - this time we use function pointers to
eliminate the dependency on the auth subsystem. The next step is to add
the required code to 'ntlm_auth', for export to Squid etc.
Andrew Bartlett
(This used to be commit 9e48ab86da
)
This commit is contained in:
parent
3095cbd635
commit
58fe4d9c20
@ -189,7 +189,8 @@ LIBSMB_OBJ = libsmb/clientgen.o libsmb/cliconnect.o libsmb/clifile.o \
|
||||
libsmb/smberr.o libsmb/credentials.o libsmb/pwd_cache.o \
|
||||
libsmb/clioplock.o libsmb/errormap.o libsmb/clirap2.o \
|
||||
libsmb/passchange.o libsmb/unexpected.o libsmb/doserr.o \
|
||||
libsmb/namecache.o libsmb/trustdom_cache.o $(RPC_PARSE_OBJ1)
|
||||
libsmb/namecache.o libsmb/trustdom_cache.o libsmb/ntlmssp.o \
|
||||
$(RPC_PARSE_OBJ1)
|
||||
|
||||
LIBMSRPC_OBJ = rpc_client/cli_lsarpc.o rpc_client/cli_samr.o \
|
||||
rpc_client/cli_netlogon.o rpc_client/cli_srvsvc.o \
|
||||
|
@ -149,4 +149,13 @@ struct auth_init_function_entry {
|
||||
|
||||
auth_init_function init;
|
||||
};
|
||||
|
||||
typedef struct auth_ntlmssp_state
|
||||
{
|
||||
TALLOC_CTX *mem_ctx;
|
||||
struct auth_context *auth_context;
|
||||
struct auth_serversupplied_info *server_info;
|
||||
struct ntlmssp_state *ntlmssp_state;
|
||||
} AUTH_NTLMSSP_STATE;
|
||||
|
||||
#endif /* _SMBAUTH_H_ */
|
||||
|
@ -71,9 +71,18 @@ typedef struct ntlmssp_state
|
||||
{
|
||||
TALLOC_CTX *mem_ctx;
|
||||
enum NTLMSSP_ROLE role;
|
||||
struct auth_context *auth_context;
|
||||
struct auth_serversupplied_info *server_info;
|
||||
BOOL unicode;
|
||||
char *orig_user;
|
||||
char *orig_domain;
|
||||
char *user;
|
||||
char *domain;
|
||||
char *workstation;
|
||||
DATA_BLOB lm_resp;
|
||||
DATA_BLOB nt_resp;
|
||||
DATA_BLOB chal;
|
||||
void *auth_context;
|
||||
const uint8 *(*get_challenge)(void *auth_context);
|
||||
NTSTATUS (*check_password)(void *auth_context);
|
||||
|
||||
const char *(*get_global_myname)(void);
|
||||
const char *(*get_domain)(void);
|
||||
} NTLMSSP_STATE;
|
||||
|
||||
|
@ -465,7 +465,8 @@ static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, const char *user,
|
||||
|
||||
neg_flags = NTLMSSP_NEGOTIATE_UNICODE |
|
||||
NTLMSSP_NEGOTIATE_128 |
|
||||
NTLMSSP_NEGOTIATE_NTLM;
|
||||
NTLMSSP_NEGOTIATE_NTLM |
|
||||
NTLMSSP_REQUEST_TARGET;
|
||||
|
||||
memset(sess_key, 0, 16);
|
||||
|
||||
|
278
source3/libsmb/ntlmssp.c
Normal file
278
source3/libsmb/ntlmssp.c
Normal file
@ -0,0 +1,278 @@
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
Version 3.0
|
||||
handle NLTMSSP, server side
|
||||
|
||||
Copyright (C) Andrew Tridgell 2001
|
||||
Copyright (C) Andrew Bartlett 2001-2003
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
/**
|
||||
* Default challange generation code.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
static const uint8 *get_challenge(void *cookie)
|
||||
{
|
||||
static uchar chal[8];
|
||||
generate_random_buffer(chal, sizeof(chal), False);
|
||||
|
||||
return chal;
|
||||
}
|
||||
|
||||
NTSTATUS ntlmssp_server_start(NTLMSSP_STATE **ntlmssp_state)
|
||||
{
|
||||
TALLOC_CTX *mem_ctx;
|
||||
|
||||
mem_ctx = talloc_init("NTLMSSP context");
|
||||
|
||||
*ntlmssp_state = talloc_zero(mem_ctx, sizeof(**ntlmssp_state));
|
||||
if (!*ntlmssp_state) {
|
||||
DEBUG(0,("ntlmssp_start: talloc failed!\n"));
|
||||
talloc_destroy(mem_ctx);
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
ZERO_STRUCTP(*ntlmssp_state);
|
||||
|
||||
(*ntlmssp_state)->mem_ctx = mem_ctx;
|
||||
(*ntlmssp_state)->get_challenge = get_challenge;
|
||||
|
||||
(*ntlmssp_state)->get_global_myname = global_myname;
|
||||
(*ntlmssp_state)->get_domain = lp_workgroup;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
NTSTATUS ntlmssp_server_end(NTLMSSP_STATE **ntlmssp_state)
|
||||
{
|
||||
TALLOC_CTX *mem_ctx = (*ntlmssp_state)->mem_ctx;
|
||||
|
||||
data_blob_free(&(*ntlmssp_state)->lm_resp);
|
||||
data_blob_free(&(*ntlmssp_state)->nt_resp);
|
||||
|
||||
SAFE_FREE((*ntlmssp_state)->user);
|
||||
SAFE_FREE((*ntlmssp_state)->domain);
|
||||
SAFE_FREE((*ntlmssp_state)->workstation);
|
||||
|
||||
talloc_destroy(mem_ctx);
|
||||
*ntlmssp_state = NULL;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
NTSTATUS ntlmssp_server_update(NTLMSSP_STATE *ntlmssp_state,
|
||||
DATA_BLOB request, DATA_BLOB *reply)
|
||||
{
|
||||
uint32 ntlmssp_command;
|
||||
|
||||
if (!msrpc_parse(&request, "Cd",
|
||||
"NTLMSSP",
|
||||
&ntlmssp_command)) {
|
||||
return NT_STATUS_LOGON_FAILURE;
|
||||
}
|
||||
|
||||
if (ntlmssp_command == NTLMSSP_NEGOTIATE) {
|
||||
return ntlmssp_negotiate(ntlmssp_state, request, reply);
|
||||
} else if (ntlmssp_command == NTLMSSP_AUTH) {
|
||||
return ntlmssp_auth(ntlmssp_state, request, reply);
|
||||
} else {
|
||||
return NT_STATUS_LOGON_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *ntlmssp_target_name(NTLMSSP_STATE *ntlmssp_state,
|
||||
uint32 neg_flags, uint32 *chal_flags)
|
||||
{
|
||||
if (neg_flags & NTLMSSP_REQUEST_TARGET) {
|
||||
*chal_flags |= NTLMSSP_CHAL_TARGET_INFO;
|
||||
*chal_flags |= NTLMSSP_REQUEST_TARGET;
|
||||
if (lp_server_role() == ROLE_STANDALONE) {
|
||||
*chal_flags |= NTLMSSP_TARGET_TYPE_SERVER;
|
||||
return ntlmssp_state->get_global_myname();
|
||||
} else {
|
||||
*chal_flags |= NTLMSSP_TARGET_TYPE_DOMAIN;
|
||||
return ntlmssp_state->get_domain();
|
||||
};
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
NTSTATUS ntlmssp_negotiate(NTLMSSP_STATE *ntlmssp_state,
|
||||
DATA_BLOB request, DATA_BLOB *reply)
|
||||
{
|
||||
DATA_BLOB struct_blob;
|
||||
fstring dnsname, dnsdomname;
|
||||
uint32 ntlmssp_command, neg_flags, chal_flags;
|
||||
char *cliname=NULL, *domname=NULL;
|
||||
const uint8 *cryptkey;
|
||||
const char *target_name;
|
||||
|
||||
/* parse the NTLMSSP packet */
|
||||
#if 0
|
||||
file_save("ntlmssp_negotiate.dat", request.data, request.length);
|
||||
#endif
|
||||
|
||||
if (!msrpc_parse(&request, "CddAA",
|
||||
"NTLMSSP",
|
||||
&ntlmssp_command,
|
||||
&neg_flags,
|
||||
&cliname,
|
||||
&domname)) {
|
||||
return NT_STATUS_LOGON_FAILURE;
|
||||
}
|
||||
|
||||
SAFE_FREE(cliname);
|
||||
SAFE_FREE(domname);
|
||||
|
||||
debug_ntlmssp_flags(neg_flags);
|
||||
|
||||
cryptkey = ntlmssp_state->get_challenge(ntlmssp_state->auth_context);
|
||||
|
||||
/* Give them the challenge. For now, ignore neg_flags and just
|
||||
return the flags we want. Obviously this is not correct */
|
||||
|
||||
chal_flags =
|
||||
NTLMSSP_NEGOTIATE_128 |
|
||||
NTLMSSP_NEGOTIATE_NTLM;
|
||||
|
||||
if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) {
|
||||
chal_flags |= NTLMSSP_NEGOTIATE_UNICODE;
|
||||
ntlmssp_state->unicode = True;
|
||||
} else {
|
||||
chal_flags |= NTLMSSP_NEGOTIATE_OEM;
|
||||
}
|
||||
|
||||
target_name = ntlmssp_target_name(ntlmssp_state,
|
||||
neg_flags, &chal_flags);
|
||||
|
||||
/* This should be a 'netbios domain -> DNS domain' mapping */
|
||||
dnsdomname[0] = '\0';
|
||||
get_mydomname(dnsdomname);
|
||||
strlower(dnsdomname);
|
||||
|
||||
dnsname[0] = '\0';
|
||||
get_myfullname(dnsname);
|
||||
strlower(dnsname);
|
||||
|
||||
if (chal_flags & NTLMSSP_CHAL_TARGET_INFO)
|
||||
{
|
||||
const char *target_name_dns = "";
|
||||
if (chal_flags |= NTLMSSP_TARGET_TYPE_DOMAIN) {
|
||||
target_name_dns = dnsdomname;
|
||||
} else if (chal_flags |= NTLMSSP_TARGET_TYPE_SERVER) {
|
||||
target_name_dns = dnsname;
|
||||
}
|
||||
|
||||
/* the numbers here are the string type flags */
|
||||
msrpc_gen(&struct_blob, "aaaaa",
|
||||
ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_DOMAIN, target_name,
|
||||
ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_SERVER, ntlmssp_state->get_global_myname(),
|
||||
ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_DOMAIN_DNS, target_name_dns,
|
||||
ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_SERVER_DNS, dnsdomname,
|
||||
ntlmssp_state->unicode, 0, "");
|
||||
} else {
|
||||
struct_blob = data_blob(NULL, 0);
|
||||
}
|
||||
|
||||
{
|
||||
const char *gen_string;
|
||||
if (ntlmssp_state->unicode) {
|
||||
gen_string = "CdUdbddB";
|
||||
} else {
|
||||
gen_string = "CdAdbddB";
|
||||
}
|
||||
|
||||
msrpc_gen(reply, gen_string,
|
||||
"NTLMSSP",
|
||||
NTLMSSP_CHALLENGE,
|
||||
target_name,
|
||||
chal_flags,
|
||||
cryptkey, 8,
|
||||
0, 0,
|
||||
struct_blob.data, struct_blob.length);
|
||||
}
|
||||
|
||||
data_blob_free(&struct_blob);
|
||||
|
||||
return NT_STATUS_MORE_PROCESSING_REQUIRED;
|
||||
}
|
||||
|
||||
NTSTATUS ntlmssp_auth(NTLMSSP_STATE *ntlmssp_state,
|
||||
DATA_BLOB request, DATA_BLOB *reply)
|
||||
{
|
||||
DATA_BLOB sess_key;
|
||||
uint32 ntlmssp_command, neg_flags;
|
||||
NTSTATUS nt_status;
|
||||
|
||||
const char *parse_string;
|
||||
|
||||
/* parse the NTLMSSP packet */
|
||||
#if 0
|
||||
file_save("ntlmssp_auth.dat", request.data, request.length);
|
||||
#endif
|
||||
|
||||
if (ntlmssp_state->unicode) {
|
||||
parse_string = "CdBBUUUBd";
|
||||
} else {
|
||||
parse_string = "CdBBAAABd";
|
||||
}
|
||||
|
||||
data_blob_free(&ntlmssp_state->lm_resp);
|
||||
data_blob_free(&ntlmssp_state->nt_resp);
|
||||
|
||||
SAFE_FREE(ntlmssp_state->user);
|
||||
SAFE_FREE(ntlmssp_state->domain);
|
||||
SAFE_FREE(ntlmssp_state->workstation);
|
||||
|
||||
/* now the NTLMSSP encoded auth hashes */
|
||||
if (!msrpc_parse(&request, parse_string,
|
||||
"NTLMSSP",
|
||||
&ntlmssp_command,
|
||||
&ntlmssp_state->lm_resp,
|
||||
&ntlmssp_state->nt_resp,
|
||||
&ntlmssp_state->domain,
|
||||
&ntlmssp_state->user,
|
||||
&ntlmssp_state->workstation,
|
||||
&sess_key,
|
||||
&neg_flags)) {
|
||||
return NT_STATUS_LOGON_FAILURE;
|
||||
}
|
||||
|
||||
data_blob_free(&sess_key);
|
||||
|
||||
DEBUG(3,("Got user=[%s] domain=[%s] workstation=[%s] len1=%d len2=%d\n",
|
||||
ntlmssp_state->user, ntlmssp_state->domain, ntlmssp_state->workstation, ntlmssp_state->lm_resp.length, ntlmssp_state->nt_resp.length));
|
||||
|
||||
#if 0
|
||||
file_save("nthash1.dat", &ntlmssp_state->nt_resp.data, &ntlmssp_state->nt_resp.length);
|
||||
file_save("lmhash1.dat", &ntlmssp_state->lm_resp.data, &ntlmssp_state->lm_resp.length);
|
||||
#endif
|
||||
|
||||
nt_status = ntlmssp_state->check_password(ntlmssp_state->auth_context);
|
||||
|
||||
if (!NT_STATUS_IS_OK(nt_status)) {
|
||||
return nt_status;
|
||||
}
|
||||
|
||||
*reply = data_blob(NULL, 0);
|
||||
|
||||
return nt_status;
|
||||
}
|
@ -24,7 +24,7 @@
|
||||
|
||||
uint32 global_client_caps = 0;
|
||||
|
||||
static struct ntlmssp_state *global_ntlmssp_state;
|
||||
static struct auth_ntlmssp_state *global_ntlmssp_state;
|
||||
|
||||
/*
|
||||
on a logon error possibly map the error to success if "map to guest"
|
||||
@ -236,6 +236,9 @@ static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
|
||||
return send_smb(smbd_server_fd(),outbuf);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
send an NTLMSSP blob via a session setup reply, wrapped in SPNEGO
|
||||
****************************************************************************/
|
||||
static BOOL reply_spnego_ntlmssp_blob(connection_struct *conn, char *outbuf,
|
||||
DATA_BLOB *ntlmssp_blob, NTSTATUS errcode)
|
||||
{
|
||||
@ -246,13 +249,18 @@ static BOOL reply_spnego_ntlmssp_blob(connection_struct *conn, char *outbuf,
|
||||
return True;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
send an OK via a session setup reply, wrapped in SPNEGO.
|
||||
get vuid and check first.
|
||||
****************************************************************************/
|
||||
static BOOL reply_spnego_ntlmssp_ok(connection_struct *conn, char *outbuf,
|
||||
NTLMSSP_STATE *ntlmssp_state)
|
||||
AUTH_NTLMSSP_STATE *auth_ntlmssp_state)
|
||||
{
|
||||
int sess_vuid;
|
||||
pstring user;
|
||||
DATA_BLOB null_blob = data_blob(NULL, 0);
|
||||
|
||||
sess_vuid = register_vuid(ntlmssp_state->server_info, ntlmssp_state->orig_user /* check this for weird */);
|
||||
sess_vuid = register_vuid(auth_ntlmssp_state->server_info, auth_ntlmssp_state->ntlmssp_state->user /* check this for weird */);
|
||||
|
||||
if (sess_vuid == -1) {
|
||||
return ERROR_NT(NT_STATUS_LOGON_FAILURE);
|
||||
@ -261,7 +269,7 @@ static BOOL reply_spnego_ntlmssp_ok(connection_struct *conn, char *outbuf,
|
||||
set_message(outbuf,4,0,True);
|
||||
SSVAL(outbuf, smb_vwv3, 0);
|
||||
|
||||
if (ntlmssp_state->server_info->guest) {
|
||||
if (auth_ntlmssp_state->server_info->guest) {
|
||||
SSVAL(outbuf,smb_vwv2,1);
|
||||
}
|
||||
|
||||
@ -313,24 +321,24 @@ static int reply_spnego_negotiate(connection_struct *conn,
|
||||
#endif
|
||||
|
||||
if (global_ntlmssp_state) {
|
||||
ntlmssp_server_end(&global_ntlmssp_state);
|
||||
auth_ntlmssp_end(&global_ntlmssp_state);
|
||||
}
|
||||
|
||||
nt_status = ntlmssp_server_start(&global_ntlmssp_state);
|
||||
nt_status = auth_ntlmssp_start(&global_ntlmssp_state);
|
||||
if (!NT_STATUS_IS_OK(nt_status)) {
|
||||
return ERROR_NT(nt_status);
|
||||
}
|
||||
|
||||
nt_status = ntlmssp_server_update(global_ntlmssp_state,
|
||||
secblob, &chal);
|
||||
nt_status = auth_ntlmssp_update(global_ntlmssp_state,
|
||||
secblob, &chal);
|
||||
|
||||
data_blob_free(&secblob);
|
||||
|
||||
if (!NT_STATUS_IS_OK(nt_status)) {
|
||||
nt_status = do_map_to_guest(nt_status,
|
||||
&global_ntlmssp_state->server_info,
|
||||
global_ntlmssp_state->orig_user,
|
||||
global_ntlmssp_state->orig_domain);
|
||||
global_ntlmssp_state->ntlmssp_state->user,
|
||||
global_ntlmssp_state->ntlmssp_state->domain);
|
||||
}
|
||||
|
||||
if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
|
||||
@ -352,13 +360,16 @@ static int reply_spnego_negotiate(connection_struct *conn,
|
||||
} else if (NT_STATUS_IS_OK(nt_status)) {
|
||||
reply_spnego_ntlmssp_ok(conn, outbuf,
|
||||
global_ntlmssp_state);
|
||||
ntlmssp_server_end(&global_ntlmssp_state);
|
||||
|
||||
auth_ntlmssp_end(&global_ntlmssp_state);
|
||||
data_blob_free(&chal);
|
||||
|
||||
/* and tell smbd that we have already replied to this packet */
|
||||
return -1;
|
||||
}
|
||||
|
||||
auth_ntlmssp_end(&global_ntlmssp_state);
|
||||
data_blob_free(&chal);
|
||||
|
||||
return ERROR_NT(nt_status_squash(nt_status));
|
||||
}
|
||||
|
||||
@ -380,7 +391,7 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
|
||||
return ERROR_NT(NT_STATUS_LOGON_FAILURE);
|
||||
}
|
||||
|
||||
nt_status = ntlmssp_server_update(global_ntlmssp_state,
|
||||
nt_status = auth_ntlmssp_update(global_ntlmssp_state,
|
||||
auth, &auth_reply);
|
||||
|
||||
data_blob_free(&auth);
|
||||
@ -389,9 +400,10 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
|
||||
if (NT_STATUS_IS_OK(nt_status)) {
|
||||
reply_spnego_ntlmssp_ok(conn, outbuf,
|
||||
global_ntlmssp_state);
|
||||
ntlmssp_server_end(&global_ntlmssp_state);
|
||||
auth_ntlmssp_end(&global_ntlmssp_state);
|
||||
|
||||
} else { /* !NT_STATUS_IS_OK(nt_status) */
|
||||
auth_ntlmssp_end(&global_ntlmssp_state);
|
||||
return ERROR_NT(nt_status_squash(nt_status));
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user