1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-25 17:57:42 +03:00
Andrew Bartlett 85e9c060ea (only for HEAD at the moment).
Add NTLMv2 support to our client, used when so configured ('client use NTLMv2 =
yes') and only when 'client use spengo = no'.  (A new option to allow the
client and server ends to chose spnego seperatly).

NTLMv2 signing doesn't yet work, and NTLMv2 is not done for NTLMSSP yet.

Also some parinoia checks in our input parsing.

Andrew Bartlett
-

283 lines
7.3 KiB
C

/*
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(struct ntlmssp_state *ntlmssp_state)
{
static uchar chal[8];
generate_random_buffer(chal, sizeof(chal), False);
return chal;
}
static const char *ntlmssp_target_name(struct 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 (ntlmssp_state->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 "";
}
}
static NTSTATUS ntlmssp_server_negotiate(struct 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);
data_blob_free(&ntlmssp_state->chal);
ntlmssp_state->chal = data_blob(cryptkey, 8);
/* 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;
}
static NTSTATUS ntlmssp_server_auth(struct 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);
*reply = data_blob(NULL, 0);
return nt_status;
}
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;
(*ntlmssp_state)->server_role = ROLE_DOMAIN_MEMBER; /* a good default */
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)->chal);
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;
*reply = data_blob(NULL, 0);
if (!msrpc_parse(&request, "Cd",
"NTLMSSP",
&ntlmssp_command)) {
return NT_STATUS_LOGON_FAILURE;
}
if (ntlmssp_command == NTLMSSP_NEGOTIATE) {
return ntlmssp_server_negotiate(ntlmssp_state, request, reply);
} else if (ntlmssp_command == NTLMSSP_AUTH) {
return ntlmssp_server_auth(ntlmssp_state, request, reply);
} else {
return NT_STATUS_LOGON_FAILURE;
}
}