1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-27 03:21:53 +03:00
samba-mirror/source3/rpc_parse/parse_rpc.c
Andrew Bartlett 456f51bcbe Jeremy requested that I get my NTLMSSP patch into CVS. He didn't request
the schannel code, but I've included that anyway. :-)

This patch revives the client-side NTLMSSP support for RPC named pipes
in Samba, and cleans up the client and server schannel code.  The use of the
new code is enabled by the 'sign', 'seal' and 'schannel' commands in
rpcclient.

The aim was to prove that our separate NTLMSSP client library actually
implements NTLMSSP signing and sealing as per Microsoft's NTLMv1 implementation,
in the hope that knowing this will assist us in correctly implementing
NTLMSSP signing for SMB packets.  (Still not yet functional)

This patch replaces the NTLMSSP implementation in rpc_client/cli_pipe.c with
calls to libsmb/ntlmssp.c.  In the process, we have gained the ability to
use the more secure NT password, and the ability to sign-only, instead of
having to seal the pipe connection.  (Previously we were limited to sealing,
and could only use the LM-password derived key).

Our new client-side NTLMSSP code also needed alteration to cope with our
comparatively simple server-side implementation.  A future step is to replace
it with calls to the same NTLMSSP library.

Also included in this patch is the schannel 'sign only' patch I submitted to
the team earlier.  While not enabled (and not functional, at this stage) the
work in this patch makes the code paths *much* easier to follow.  I have also
included similar hooks in rpccleint to allow the use of schannel on *any* pipe.

rpcclient now defaults to not using schannel (or any other extra per-pipe
authenticiation) for any connection.  The 'schannel' command enables schannel
for all pipes until disabled.

This code is also much more secure than the previous code, as changes to our
cli_pipe routines ensure that the authentication footer cannot be removed
by an attacker, and more error states are correctly handled.

(The same needs to be done to our server)

Andrew Bartlett
(This used to be commit 5472ddc9ea)
2003-07-14 08:46:32 +00:00

1211 lines
37 KiB
C

/*
* Unix SMB/CIFS implementation.
* RPC Pipe client / server routines
* Copyright (C) Andrew Tridgell 1992-1997,
* Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
* Copyright (C) Paul Ashton 1997.
* Copyright (C) Jeremy Allison 1999.
*
* 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"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_RPC_PARSE
/*******************************************************************
interface/version dce/rpc pipe identification
********************************************************************/
#define TRANS_SYNT_V2 \
{ \
{ \
0x8a885d04, 0x1ceb, 0x11c9, \
{ 0x9f, 0xe8, 0x08, 0x00, \
0x2b, 0x10, 0x48, 0x60 } \
}, 0x02 \
}
#define SYNT_NETLOGON_V2 \
{ \
{ \
0x8a885d04, 0x1ceb, 0x11c9, \
{ 0x9f, 0xe8, 0x08, 0x00, \
0x2b, 0x10, 0x48, 0x60 } \
}, 0x02 \
}
#define SYNT_WKSSVC_V1 \
{ \
{ \
0x6bffd098, 0xa112, 0x3610, \
{ 0x98, 0x33, 0x46, 0xc3, \
0xf8, 0x7e, 0x34, 0x5a } \
}, 0x01 \
}
#define SYNT_SRVSVC_V3 \
{ \
{ \
0x4b324fc8, 0x1670, 0x01d3, \
{ 0x12, 0x78, 0x5a, 0x47, \
0xbf, 0x6e, 0xe1, 0x88 } \
}, 0x03 \
}
#define SYNT_LSARPC_V0 \
{ \
{ \
0x12345778, 0x1234, 0xabcd, \
{ 0xef, 0x00, 0x01, 0x23, \
0x45, 0x67, 0x89, 0xab } \
}, 0x00 \
}
#define SYNT_LSARPC_V0_DS \
{ \
{ \
0x3919286a, 0xb10c, 0x11d0, \
{ 0x9b, 0xa8, 0x00, 0xc0, \
0x4f, 0xd9, 0x2e, 0xf5 } \
}, 0x00 \
}
#define SYNT_SAMR_V1 \
{ \
{ \
0x12345778, 0x1234, 0xabcd, \
{ 0xef, 0x00, 0x01, 0x23, \
0x45, 0x67, 0x89, 0xac } \
}, 0x01 \
}
#define SYNT_NETLOGON_V1 \
{ \
{ \
0x12345678, 0x1234, 0xabcd, \
{ 0xef, 0x00, 0x01, 0x23, \
0x45, 0x67, 0xcf, 0xfb } \
}, 0x01 \
}
#define SYNT_WINREG_V1 \
{ \
{ \
0x338cd001, 0x2244, 0x31f1, \
{ 0xaa, 0xaa, 0x90, 0x00, \
0x38, 0x00, 0x10, 0x03 } \
}, 0x01 \
}
#define SYNT_SPOOLSS_V1 \
{ \
{ \
0x12345678, 0x1234, 0xabcd, \
{ 0xef, 0x00, 0x01, 0x23, \
0x45, 0x67, 0x89, 0xab } \
}, 0x01 \
}
#define SYNT_NONE_V0 \
{ \
{ \
0x0, 0x0, 0x0, \
{ 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00 } \
}, 0x00 \
}
#define SYNT_NETDFS_V3 \
{ \
{ \
0x4fc742e0, 0x4a10, 0x11cf, \
{ 0x82, 0x73, 0x00, 0xaa, \
0x00, 0x4a, 0xe6, 0x73 } \
}, 0x03 \
}
#define SYNT_ECHO_V1 \
{ \
{ \
0x60a15ec5, 0x4de8, 0x11d7, \
{ 0xa6, 0x37, 0x00, 0x50, \
0x56, 0xa2, 0x01, 0x82 } \
}, 0x01 \
}
/*
* IMPORTANT!! If you update this structure, make sure to
* update the index #defines in smb.h.
*/
const struct pipe_id_info pipe_names [] =
{
/* client pipe , abstract syntax , server pipe , transfer syntax */
{ PIPE_LSARPC , SYNT_LSARPC_V0 , PIPE_LSASS , TRANS_SYNT_V2 },
{ PIPE_LSARPC , SYNT_LSARPC_V0_DS , PIPE_LSASS , TRANS_SYNT_V2 },
{ PIPE_SAMR , SYNT_SAMR_V1 , PIPE_LSASS , TRANS_SYNT_V2 },
{ PIPE_NETLOGON, SYNT_NETLOGON_V1 , PIPE_LSASS , TRANS_SYNT_V2 },
{ PIPE_SRVSVC , SYNT_SRVSVC_V3 , PIPE_NTSVCS , TRANS_SYNT_V2 },
{ PIPE_WKSSVC , SYNT_WKSSVC_V1 , PIPE_NTSVCS , TRANS_SYNT_V2 },
{ PIPE_WINREG , SYNT_WINREG_V1 , PIPE_WINREG , TRANS_SYNT_V2 },
{ PIPE_SPOOLSS , SYNT_SPOOLSS_V1 , PIPE_SPOOLSS , TRANS_SYNT_V2 },
{ PIPE_NETDFS , SYNT_NETDFS_V3 , PIPE_NETDFS , TRANS_SYNT_V2 },
{ PIPE_ECHO , SYNT_ECHO_V1 , PIPE_ECHO , TRANS_SYNT_V2 },
{ NULL , SYNT_NONE_V0 , NULL , SYNT_NONE_V0 }
};
/*******************************************************************
Inits an RPC_HDR structure.
********************************************************************/
void init_rpc_hdr(RPC_HDR *hdr, enum RPC_PKT_TYPE pkt_type, uint8 flags,
uint32 call_id, int data_len, int auth_len)
{
hdr->major = 5; /* RPC version 5 */
hdr->minor = 0; /* minor version 0 */
hdr->pkt_type = pkt_type; /* RPC packet type */
hdr->flags = flags; /* dce/rpc flags */
hdr->pack_type[0] = 0x10; /* little-endian data representation */
hdr->pack_type[1] = 0; /* packed data representation */
hdr->pack_type[2] = 0; /* packed data representation */
hdr->pack_type[3] = 0; /* packed data representation */
hdr->frag_len = data_len; /* fragment length, fill in later */
hdr->auth_len = auth_len; /* authentication length */
hdr->call_id = call_id; /* call identifier - match incoming RPC */
}
/*******************************************************************
Reads or writes an RPC_HDR structure.
********************************************************************/
BOOL smb_io_rpc_hdr(const char *desc, RPC_HDR *rpc, prs_struct *ps, int depth)
{
if (rpc == NULL)
return False;
prs_debug(ps, depth, desc, "smb_io_rpc_hdr");
depth++;
if(!prs_uint8 ("major ", ps, depth, &rpc->major))
return False;
if(!prs_uint8 ("minor ", ps, depth, &rpc->minor))
return False;
if(!prs_uint8 ("pkt_type ", ps, depth, &rpc->pkt_type))
return False;
if(!prs_uint8 ("flags ", ps, depth, &rpc->flags))
return False;
/* We always marshall in little endian format. */
if (MARSHALLING(ps))
rpc->pack_type[0] = 0x10;
if(!prs_uint8("pack_type0", ps, depth, &rpc->pack_type[0]))
return False;
if(!prs_uint8("pack_type1", ps, depth, &rpc->pack_type[1]))
return False;
if(!prs_uint8("pack_type2", ps, depth, &rpc->pack_type[2]))
return False;
if(!prs_uint8("pack_type3", ps, depth, &rpc->pack_type[3]))
return False;
/*
* If reading and pack_type[0] == 0 then the data is in big-endian
* format. Set the flag in the prs_struct to specify reverse-endainness.
*/
if (UNMARSHALLING(ps) && rpc->pack_type[0] == 0) {
DEBUG(10,("smb_io_rpc_hdr: PDU data format is big-endian. Setting flag.\n"));
prs_set_endian_data(ps, RPC_BIG_ENDIAN);
}
if(!prs_uint16("frag_len ", ps, depth, &rpc->frag_len))
return False;
if(!prs_uint16("auth_len ", ps, depth, &rpc->auth_len))
return False;
if(!prs_uint32("call_id ", ps, depth, &rpc->call_id))
return False;
return True;
}
/*******************************************************************
Reads or writes an RPC_IFACE structure.
********************************************************************/
static BOOL smb_io_rpc_iface(const char *desc, RPC_IFACE *ifc, prs_struct *ps, int depth)
{
if (ifc == NULL)
return False;
prs_debug(ps, depth, desc, "smb_io_rpc_iface");
depth++;
if(!prs_align(ps))
return False;
if(!prs_uint32 ("data ", ps, depth, &ifc->uuid.time_low))
return False;
if(!prs_uint16 ("data ", ps, depth, &ifc->uuid.time_mid))
return False;
if(!prs_uint16 ("data ", ps, depth, &ifc->uuid.time_hi_and_version))
return False;
if(!prs_uint8s (False, "data ", ps, depth, ifc->uuid.remaining, sizeof(ifc->uuid.remaining)))
return False;
if(!prs_uint32 ( "version", ps, depth, &ifc->version))
return False;
return True;
}
/*******************************************************************
Inits an RPC_ADDR_STR structure.
********************************************************************/
static void init_rpc_addr_str(RPC_ADDR_STR *str, const char *name)
{
str->len = strlen(name) + 1;
fstrcpy(str->str, name);
}
/*******************************************************************
Reads or writes an RPC_ADDR_STR structure.
********************************************************************/
static BOOL smb_io_rpc_addr_str(const char *desc, RPC_ADDR_STR *str, prs_struct *ps, int depth)
{
if (str == NULL)
return False;
prs_debug(ps, depth, desc, "smb_io_rpc_addr_str");
depth++;
if(!prs_align(ps))
return False;
if(!prs_uint16 ( "len", ps, depth, &str->len))
return False;
if(!prs_uint8s (True, "str", ps, depth, (uchar*)str->str, MIN(str->len, sizeof(str->str)) ))
return False;
return True;
}
/*******************************************************************
Inits an RPC_HDR_BBA structure.
********************************************************************/
static void init_rpc_hdr_bba(RPC_HDR_BBA *bba, uint16 max_tsize, uint16 max_rsize, uint32 assoc_gid)
{
bba->max_tsize = max_tsize; /* maximum transmission fragment size (0x1630) */
bba->max_rsize = max_rsize; /* max receive fragment size (0x1630) */
bba->assoc_gid = assoc_gid; /* associated group id (0x0) */
}
/*******************************************************************
Reads or writes an RPC_HDR_BBA structure.
********************************************************************/
static BOOL smb_io_rpc_hdr_bba(const char *desc, RPC_HDR_BBA *rpc, prs_struct *ps, int depth)
{
if (rpc == NULL)
return False;
prs_debug(ps, depth, desc, "smb_io_rpc_hdr_bba");
depth++;
if(!prs_uint16("max_tsize", ps, depth, &rpc->max_tsize))
return False;
if(!prs_uint16("max_rsize", ps, depth, &rpc->max_rsize))
return False;
if(!prs_uint32("assoc_gid", ps, depth, &rpc->assoc_gid))
return False;
return True;
}
/*******************************************************************
Inits an RPC_HDR_RB structure.
********************************************************************/
void init_rpc_hdr_rb(RPC_HDR_RB *rpc,
uint16 max_tsize, uint16 max_rsize, uint32 assoc_gid,
uint32 num_elements, uint16 context_id, uint8 num_syntaxes,
RPC_IFACE *abstract, RPC_IFACE *transfer)
{
init_rpc_hdr_bba(&rpc->bba, max_tsize, max_rsize, assoc_gid);
rpc->num_elements = num_elements ; /* the number of elements (0x1) */
rpc->context_id = context_id ; /* presentation context identifier (0x0) */
rpc->num_syntaxes = num_syntaxes ; /* the number of syntaxes (has always been 1?)(0x1) */
/* num and vers. of interface client is using */
rpc->abstract = *abstract;
/* num and vers. of interface to use for replies */
rpc->transfer = *transfer;
}
/*******************************************************************
Reads or writes an RPC_HDR_RB structure.
********************************************************************/
BOOL smb_io_rpc_hdr_rb(const char *desc, RPC_HDR_RB *rpc, prs_struct *ps, int depth)
{
if (rpc == NULL)
return False;
prs_debug(ps, depth, desc, "smb_io_rpc_hdr_rb");
depth++;
if(!smb_io_rpc_hdr_bba("", &rpc->bba, ps, depth))
return False;
if(!prs_uint32("num_elements", ps, depth, &rpc->num_elements))
return False;
if(!prs_uint16("context_id ", ps, depth, &rpc->context_id ))
return False;
if(!prs_uint8 ("num_syntaxes", ps, depth, &rpc->num_syntaxes))
return False;
if(!smb_io_rpc_iface("", &rpc->abstract, ps, depth))
return False;
if(!smb_io_rpc_iface("", &rpc->transfer, ps, depth))
return False;
return True;
}
/*******************************************************************
Inits an RPC_RESULTS structure.
lkclXXXX only one reason at the moment!
********************************************************************/
static void init_rpc_results(RPC_RESULTS *res,
uint8 num_results, uint16 result, uint16 reason)
{
res->num_results = num_results; /* the number of results (0x01) */
res->result = result ; /* result (0x00 = accept) */
res->reason = reason ; /* reason (0x00 = no reason specified) */
}
/*******************************************************************
Reads or writes an RPC_RESULTS structure.
lkclXXXX only one reason at the moment!
********************************************************************/
static BOOL smb_io_rpc_results(const char *desc, RPC_RESULTS *res, prs_struct *ps, int depth)
{
if (res == NULL)
return False;
prs_debug(ps, depth, desc, "smb_io_rpc_results");
depth++;
if(!prs_align(ps))
return False;
if(!prs_uint8 ("num_results", ps, depth, &res->num_results))
return False;
if(!prs_align(ps))
return False;
if(!prs_uint16("result ", ps, depth, &res->result))
return False;
if(!prs_uint16("reason ", ps, depth, &res->reason))
return False;
return True;
}
/*******************************************************************
Init an RPC_HDR_BA structure.
lkclXXXX only one reason at the moment!
********************************************************************/
void init_rpc_hdr_ba(RPC_HDR_BA *rpc,
uint16 max_tsize, uint16 max_rsize, uint32 assoc_gid,
const char *pipe_addr,
uint8 num_results, uint16 result, uint16 reason,
RPC_IFACE *transfer)
{
init_rpc_hdr_bba (&rpc->bba, max_tsize, max_rsize, assoc_gid);
init_rpc_addr_str(&rpc->addr, pipe_addr);
init_rpc_results (&rpc->res, num_results, result, reason);
/* the transfer syntax from the request */
memcpy(&rpc->transfer, transfer, sizeof(rpc->transfer));
}
/*******************************************************************
Reads or writes an RPC_HDR_BA structure.
********************************************************************/
BOOL smb_io_rpc_hdr_ba(const char *desc, RPC_HDR_BA *rpc, prs_struct *ps, int depth)
{
if (rpc == NULL)
return False;
prs_debug(ps, depth, desc, "smb_io_rpc_hdr_ba");
depth++;
if(!smb_io_rpc_hdr_bba("", &rpc->bba, ps, depth))
return False;
if(!smb_io_rpc_addr_str("", &rpc->addr, ps, depth))
return False;
if(!smb_io_rpc_results("", &rpc->res, ps, depth))
return False;
if(!smb_io_rpc_iface("", &rpc->transfer, ps, depth))
return False;
return True;
}
/*******************************************************************
Init an RPC_HDR_REQ structure.
********************************************************************/
void init_rpc_hdr_req(RPC_HDR_REQ *hdr, uint32 alloc_hint, uint16 opnum)
{
hdr->alloc_hint = alloc_hint; /* allocation hint */
hdr->context_id = 0; /* presentation context identifier */
hdr->opnum = opnum; /* opnum */
}
/*******************************************************************
Reads or writes an RPC_HDR_REQ structure.
********************************************************************/
BOOL smb_io_rpc_hdr_req(const char *desc, RPC_HDR_REQ *rpc, prs_struct *ps, int depth)
{
if (rpc == NULL)
return False;
prs_debug(ps, depth, desc, "smb_io_rpc_hdr_req");
depth++;
if(!prs_uint32("alloc_hint", ps, depth, &rpc->alloc_hint))
return False;
if(!prs_uint16("context_id", ps, depth, &rpc->context_id))
return False;
if(!prs_uint16("opnum ", ps, depth, &rpc->opnum))
return False;
return True;
}
/*******************************************************************
Reads or writes an RPC_HDR_RESP structure.
********************************************************************/
BOOL smb_io_rpc_hdr_resp(const char *desc, RPC_HDR_RESP *rpc, prs_struct *ps, int depth)
{
if (rpc == NULL)
return False;
prs_debug(ps, depth, desc, "smb_io_rpc_hdr_resp");
depth++;
if(!prs_uint32("alloc_hint", ps, depth, &rpc->alloc_hint))
return False;
if(!prs_uint16("context_id", ps, depth, &rpc->context_id))
return False;
if(!prs_uint8 ("cancel_ct ", ps, depth, &rpc->cancel_count))
return False;
if(!prs_uint8 ("reserved ", ps, depth, &rpc->reserved))
return False;
return True;
}
/*******************************************************************
Reads or writes an RPC_HDR_FAULT structure.
********************************************************************/
BOOL smb_io_rpc_hdr_fault(const char *desc, RPC_HDR_FAULT *rpc, prs_struct *ps, int depth)
{
if (rpc == NULL)
return False;
prs_debug(ps, depth, desc, "smb_io_rpc_hdr_fault");
depth++;
if(!prs_ntstatus("status ", ps, depth, &rpc->status))
return False;
if(!prs_uint32("reserved", ps, depth, &rpc->reserved))
return False;
return True;
}
/*******************************************************************
Init an RPC_HDR_AUTHA structure.
********************************************************************/
void init_rpc_hdr_autha(RPC_HDR_AUTHA *rai,
uint16 max_tsize, uint16 max_rsize,
uint8 auth_type, uint8 auth_level,
uint8 stub_type_len)
{
rai->max_tsize = max_tsize; /* maximum transmission fragment size (0x1630) */
rai->max_rsize = max_rsize; /* max receive fragment size (0x1630) */
rai->auth_type = auth_type; /* nt lm ssp 0x0a */
rai->auth_level = auth_level; /* 0x06 */
rai->stub_type_len = stub_type_len; /* 0x00 */
rai->padding = 0; /* padding 0x00 */
rai->unknown = 0x0014a0c0; /* non-zero pointer to something */
}
/*******************************************************************
Reads or writes an RPC_HDR_AUTHA structure.
********************************************************************/
BOOL smb_io_rpc_hdr_autha(const char *desc, RPC_HDR_AUTHA *rai, prs_struct *ps, int depth)
{
if (rai == NULL)
return False;
prs_debug(ps, depth, desc, "smb_io_rpc_hdr_autha");
depth++;
if(!prs_uint16("max_tsize ", ps, depth, &rai->max_tsize))
return False;
if(!prs_uint16("max_rsize ", ps, depth, &rai->max_rsize))
return False;
if(!prs_uint8 ("auth_type ", ps, depth, &rai->auth_type)) /* 0x0a nt lm ssp */
return False;
if(!prs_uint8 ("auth_level ", ps, depth, &rai->auth_level)) /* 0x06 */
return False;
if(!prs_uint8 ("stub_type_len", ps, depth, &rai->stub_type_len))
return False;
if(!prs_uint8 ("padding ", ps, depth, &rai->padding))
return False;
if(!prs_uint32("unknown ", ps, depth, &rai->unknown)) /* 0x0014a0c0 */
return False;
return True;
}
/*******************************************************************
Inits an RPC_HDR_AUTH structure.
********************************************************************/
void init_rpc_hdr_auth(RPC_HDR_AUTH *rai,
uint8 auth_type, uint8 auth_level,
uint8 padding,
uint32 ptr)
{
rai->auth_type = auth_type; /* nt lm ssp 0x0a */
rai->auth_level = auth_level; /* 0x06 */
rai->padding = padding;
rai->reserved = 0;
rai->auth_context = ptr; /* non-zero pointer to something */
}
/*******************************************************************
Reads or writes an RPC_HDR_AUTH structure.
********************************************************************/
BOOL smb_io_rpc_hdr_auth(const char *desc, RPC_HDR_AUTH *rai, prs_struct *ps, int depth)
{
if (rai == NULL)
return False;
prs_debug(ps, depth, desc, "smb_io_rpc_hdr_auth");
depth++;
if(!prs_align(ps))
return False;
if(!prs_uint8 ("auth_type ", ps, depth, &rai->auth_type)) /* 0x0a nt lm ssp */
return False;
if(!prs_uint8 ("auth_level ", ps, depth, &rai->auth_level)) /* 0x06 */
return False;
if(!prs_uint8 ("padding ", ps, depth, &rai->padding))
return False;
if(!prs_uint8 ("reserved ", ps, depth, &rai->reserved))
return False;
if(!prs_uint32("auth_context ", ps, depth, &rai->auth_context))
return False;
return True;
}
/*******************************************************************
Checks an RPC_AUTH_VERIFIER structure.
********************************************************************/
BOOL rpc_auth_verifier_chk(RPC_AUTH_VERIFIER *rav,
const char *signature, uint32 msg_type)
{
return (strequal(rav->signature, signature) && rav->msg_type == msg_type);
}
/*******************************************************************
Inits an RPC_AUTH_VERIFIER structure.
********************************************************************/
void init_rpc_auth_verifier(RPC_AUTH_VERIFIER *rav,
const char *signature, uint32 msg_type)
{
fstrcpy(rav->signature, signature); /* "NTLMSSP" */
rav->msg_type = msg_type; /* NTLMSSP_MESSAGE_TYPE */
}
/*******************************************************************
Reads or writes an RPC_AUTH_VERIFIER structure.
********************************************************************/
BOOL smb_io_rpc_auth_verifier(const char *desc, RPC_AUTH_VERIFIER *rav, prs_struct *ps, int depth)
{
if (rav == NULL)
return False;
prs_debug(ps, depth, desc, "smb_io_rpc_auth_verifier");
depth++;
/* "NTLMSSP" */
if(!prs_string("signature", ps, depth, rav->signature,
sizeof(rav->signature)))
return False;
if(!prs_uint32("msg_type ", ps, depth, &rav->msg_type)) /* NTLMSSP_MESSAGE_TYPE */
return False;
return True;
}
/*******************************************************************
This parses an RPC_AUTH_VERIFIER for NETLOGON schannel. I think
assuming "NTLMSSP" in sm_io_rpc_auth_verifier is somewhat wrong.
I have to look at that later...
********************************************************************/
BOOL smb_io_rpc_netsec_verifier(const char *desc, RPC_AUTH_VERIFIER *rav, prs_struct *ps, int depth)
{
if (rav == NULL)
return False;
prs_debug(ps, depth, desc, "smb_io_rpc_auth_verifier");
depth++;
if(!prs_string("signature", ps, depth, rav->signature, sizeof(rav->signature)))
return False;
if(!prs_uint32("msg_type ", ps, depth, &rav->msg_type))
return False;
return True;
}
/*******************************************************************
Inits an RPC_AUTH_NTLMSSP_NEG structure.
********************************************************************/
void init_rpc_auth_ntlmssp_neg(RPC_AUTH_NTLMSSP_NEG *neg,
uint32 neg_flgs,
const char *myname, const char *domain)
{
int len_myname = strlen(myname);
int len_domain = strlen(domain);
neg->neg_flgs = neg_flgs ; /* 0x00b2b3 */
init_str_hdr(&neg->hdr_domain, len_domain, len_domain, 0x20 + len_myname);
init_str_hdr(&neg->hdr_myname, len_myname, len_myname, 0x20);
fstrcpy(neg->myname, myname);
fstrcpy(neg->domain, domain);
}
/*******************************************************************
Reads or writes an RPC_AUTH_NTLMSSP_NEG structure.
*** lkclXXXX HACK ALERT! ***
********************************************************************/
BOOL smb_io_rpc_auth_ntlmssp_neg(const char *desc, RPC_AUTH_NTLMSSP_NEG *neg, prs_struct *ps, int depth)
{
uint32 start_offset = prs_offset(ps);
if (neg == NULL)
return False;
prs_debug(ps, depth, desc, "smb_io_rpc_auth_ntlmssp_neg");
depth++;
if(!prs_uint32("neg_flgs ", ps, depth, &neg->neg_flgs))
return False;
if (ps->io) {
uint32 old_offset;
uint32 old_neg_flags = neg->neg_flgs;
/* reading */
ZERO_STRUCTP(neg);
neg->neg_flgs = old_neg_flags;
if(!smb_io_strhdr("hdr_domain", &neg->hdr_domain, ps, depth))
return False;
if(!smb_io_strhdr("hdr_myname", &neg->hdr_myname, ps, depth))
return False;
old_offset = prs_offset(ps);
if(!prs_set_offset(ps, neg->hdr_myname.buffer + start_offset - 12))
return False;
if(!prs_uint8s(True, "myname", ps, depth, (uint8*)neg->myname,
MIN(neg->hdr_myname.str_str_len, sizeof(neg->myname))))
return False;
old_offset += neg->hdr_myname.str_str_len;
if(!prs_set_offset(ps, neg->hdr_domain.buffer + start_offset - 12))
return False;
if(!prs_uint8s(True, "domain", ps, depth, (uint8*)neg->domain,
MIN(neg->hdr_domain.str_str_len, sizeof(neg->domain ))))
return False;
old_offset += neg->hdr_domain .str_str_len;
if(!prs_set_offset(ps, old_offset))
return False;
} else {
/* writing */
if(!smb_io_strhdr("hdr_domain", &neg->hdr_domain, ps, depth))
return False;
if(!smb_io_strhdr("hdr_myname", &neg->hdr_myname, ps, depth))
return False;
if(!prs_uint8s(True, "myname", ps, depth, (uint8*)neg->myname,
MIN(neg->hdr_myname.str_str_len, sizeof(neg->myname))))
return False;
if(!prs_uint8s(True, "domain", ps, depth, (uint8*)neg->domain,
MIN(neg->hdr_domain.str_str_len, sizeof(neg->domain ))))
return False;
}
return True;
}
/*******************************************************************
creates an RPC_AUTH_NTLMSSP_CHAL structure.
********************************************************************/
void init_rpc_auth_ntlmssp_chal(RPC_AUTH_NTLMSSP_CHAL *chl,
uint32 neg_flags,
uint8 challenge[8])
{
chl->unknown_1 = 0x0;
chl->unknown_2 = 0x00000028;
chl->neg_flags = neg_flags; /* 0x0082b1 */
memcpy(chl->challenge, challenge, sizeof(chl->challenge));
memset((char *)chl->reserved , '\0', sizeof(chl->reserved));
}
/*******************************************************************
Reads or writes an RPC_AUTH_NTLMSSP_CHAL structure.
********************************************************************/
BOOL smb_io_rpc_auth_ntlmssp_chal(const char *desc, RPC_AUTH_NTLMSSP_CHAL *chl, prs_struct *ps, int depth)
{
if (chl == NULL)
return False;
prs_debug(ps, depth, desc, "smb_io_rpc_auth_ntlmssp_chal");
depth++;
if(!prs_uint32("unknown_1", ps, depth, &chl->unknown_1)) /* 0x0000 0000 */
return False;
if(!prs_uint32("unknown_2", ps, depth, &chl->unknown_2)) /* 0x0000 b2b3 */
return False;
if(!prs_uint32("neg_flags", ps, depth, &chl->neg_flags)) /* 0x0000 82b1 */
return False;
if(!prs_uint8s (False, "challenge", ps, depth, chl->challenge, sizeof(chl->challenge)))
return False;
if(!prs_uint8s (False, "reserved ", ps, depth, chl->reserved , sizeof(chl->reserved )))
return False;
return True;
}
/*******************************************************************
Inits an RPC_AUTH_NTLMSSP_RESP structure.
*** lkclXXXX FUDGE! HAVE TO MANUALLY SPECIFY OFFSET HERE (0x1c bytes) ***
*** lkclXXXX the actual offset is at the start of the auth verifier ***
********************************************************************/
void init_rpc_auth_ntlmssp_resp(RPC_AUTH_NTLMSSP_RESP *rsp,
uchar lm_resp[24], uchar nt_resp[24],
const char *domain, const char *user, const char *wks,
uint32 neg_flags)
{
uint32 offset;
int dom_len = strlen(domain);
int wks_len = strlen(wks);
int usr_len = strlen(user);
int lm_len = (lm_resp != NULL) ? 24 : 0;
int nt_len = (nt_resp != NULL) ? 24 : 0;
DEBUG(5,("make_rpc_auth_ntlmssp_resp\n"));
#ifdef DEBUG_PASSWORD
DEBUG(100,("lm_resp\n"));
dump_data(100, (char *)lm_resp, 24);
DEBUG(100,("nt_resp\n"));
dump_data(100, (char *)nt_resp, 24);
#endif
DEBUG(6,("dom: %s user: %s wks: %s neg_flgs: 0x%x\n",
domain, user, wks, neg_flags));
offset = 0x40;
if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) {
dom_len *= 2;
wks_len *= 2;
usr_len *= 2;
}
init_str_hdr(&rsp->hdr_domain, dom_len, dom_len, offset);
offset += dom_len;
init_str_hdr(&rsp->hdr_usr, usr_len, usr_len, offset);
offset += usr_len;
init_str_hdr(&rsp->hdr_wks, wks_len, wks_len, offset);
offset += wks_len;
init_str_hdr(&rsp->hdr_lm_resp, lm_len, lm_len, offset);
offset += lm_len;
init_str_hdr(&rsp->hdr_nt_resp, nt_len, nt_len, offset);
offset += nt_len;
init_str_hdr(&rsp->hdr_sess_key, 0, 0, offset);
rsp->neg_flags = neg_flags;
memcpy(rsp->lm_resp, lm_resp, 24);
memcpy(rsp->nt_resp, nt_resp, 24);
if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) {
rpcstr_push(rsp->domain, domain, sizeof(rsp->domain), 0);
rpcstr_push(rsp->user, user, sizeof(rsp->user), 0);
rpcstr_push(rsp->wks, wks, sizeof(rsp->wks), 0);
} else {
fstrcpy(rsp->domain, domain);
fstrcpy(rsp->user, user);
fstrcpy(rsp->wks, wks);
}
rsp->sess_key[0] = 0;
}
/*******************************************************************
Reads or writes an RPC_AUTH_NTLMSSP_RESP structure.
*** lkclXXXX FUDGE! HAVE TO MANUALLY SPECIFY OFFSET HERE (0x1c bytes) ***
*** lkclXXXX the actual offset is at the start of the auth verifier ***
********************************************************************/
BOOL smb_io_rpc_auth_ntlmssp_resp(const char *desc, RPC_AUTH_NTLMSSP_RESP *rsp, prs_struct *ps, int depth)
{
if (rsp == NULL)
return False;
prs_debug(ps, depth, desc, "smb_io_rpc_auth_ntlmssp_resp");
depth++;
if (ps->io) {
uint32 old_offset;
/* reading */
ZERO_STRUCTP(rsp);
if(!smb_io_strhdr("hdr_lm_resp ", &rsp->hdr_lm_resp, ps, depth))
return False;
if(!smb_io_strhdr("hdr_nt_resp ", &rsp->hdr_nt_resp, ps, depth))
return False;
if(!smb_io_strhdr("hdr_domain ", &rsp->hdr_domain, ps, depth))
return False;
if(!smb_io_strhdr("hdr_user ", &rsp->hdr_usr, ps, depth))
return False;
if(!smb_io_strhdr("hdr_wks ", &rsp->hdr_wks, ps, depth))
return False;
if(!smb_io_strhdr("hdr_sess_key", &rsp->hdr_sess_key, ps, depth))
return False;
if(!prs_uint32("neg_flags", ps, depth, &rsp->neg_flags)) /* 0x0000 82b1 */
return False;
old_offset = prs_offset(ps);
if(!prs_set_offset(ps, rsp->hdr_domain.buffer + 0xc))
return False;
if(!prs_uint8s(True , "domain ", ps, depth, (uint8*)rsp->domain,
MIN(rsp->hdr_domain.str_str_len, sizeof(rsp->domain))))
return False;
old_offset += rsp->hdr_domain.str_str_len;
if(!prs_set_offset(ps, rsp->hdr_usr.buffer + 0xc))
return False;
if(!prs_uint8s(True , "user ", ps, depth, (uint8*)rsp->user,
MIN(rsp->hdr_usr.str_str_len, sizeof(rsp->user))))
return False;
old_offset += rsp->hdr_usr.str_str_len;
if(!prs_set_offset(ps, rsp->hdr_wks.buffer + 0xc))
return False;
if(!prs_uint8s(True, "wks ", ps, depth, (uint8*)rsp->wks,
MIN(rsp->hdr_wks.str_str_len, sizeof(rsp->wks))))
return False;
old_offset += rsp->hdr_wks.str_str_len;
if(!prs_set_offset(ps, rsp->hdr_lm_resp.buffer + 0xc))
return False;
if(!prs_uint8s(False, "lm_resp ", ps, depth, (uint8*)rsp->lm_resp,
MIN(rsp->hdr_lm_resp.str_str_len, sizeof(rsp->lm_resp ))))
return False;
old_offset += rsp->hdr_lm_resp.str_str_len;
if(!prs_set_offset(ps, rsp->hdr_nt_resp.buffer + 0xc))
return False;
if(!prs_uint8s(False, "nt_resp ", ps, depth, (uint8*)rsp->nt_resp,
MIN(rsp->hdr_nt_resp.str_str_len, sizeof(rsp->nt_resp ))))
return False;
old_offset += rsp->hdr_nt_resp.str_str_len;
if (rsp->hdr_sess_key.str_str_len != 0) {
if(!prs_set_offset(ps, rsp->hdr_sess_key.buffer + 0x10))
return False;
old_offset += rsp->hdr_sess_key.str_str_len;
if(!prs_uint8s(False, "sess_key", ps, depth, (uint8*)rsp->sess_key,
MIN(rsp->hdr_sess_key.str_str_len, sizeof(rsp->sess_key))))
return False;
}
if(!prs_set_offset(ps, old_offset))
return False;
} else {
/* writing */
if(!smb_io_strhdr("hdr_lm_resp ", &rsp->hdr_lm_resp, ps, depth))
return False;
if(!smb_io_strhdr("hdr_nt_resp ", &rsp->hdr_nt_resp, ps, depth))
return False;
if(!smb_io_strhdr("hdr_domain ", &rsp->hdr_domain, ps, depth))
return False;
if(!smb_io_strhdr("hdr_user ", &rsp->hdr_usr, ps, depth))
return False;
if(!smb_io_strhdr("hdr_wks ", &rsp->hdr_wks, ps, depth))
return False;
if(!smb_io_strhdr("hdr_sess_key", &rsp->hdr_sess_key, ps, depth))
return False;
if(!prs_uint32("neg_flags", ps, depth, &rsp->neg_flags)) /* 0x0000 82b1 */
return False;
if(!prs_uint8s(True , "domain ", ps, depth, (uint8*)rsp->domain,
MIN(rsp->hdr_domain.str_str_len, sizeof(rsp->domain))))
return False;
if(!prs_uint8s(True , "user ", ps, depth, (uint8*)rsp->user,
MIN(rsp->hdr_usr.str_str_len, sizeof(rsp->user))))
return False;
if(!prs_uint8s(True , "wks ", ps, depth, (uint8*)rsp->wks,
MIN(rsp->hdr_wks.str_str_len, sizeof(rsp->wks))))
return False;
if(!prs_uint8s(False, "lm_resp ", ps, depth, (uint8*)rsp->lm_resp,
MIN(rsp->hdr_lm_resp .str_str_len, sizeof(rsp->lm_resp))))
return False;
if(!prs_uint8s(False, "nt_resp ", ps, depth, (uint8*)rsp->nt_resp,
MIN(rsp->hdr_nt_resp .str_str_len, sizeof(rsp->nt_resp ))))
return False;
if(!prs_uint8s(False, "sess_key", ps, depth, (uint8*)rsp->sess_key,
MIN(rsp->hdr_sess_key.str_str_len, sizeof(rsp->sess_key))))
return False;
}
return True;
}
/*******************************************************************
Checks an RPC_AUTH_NTLMSSP_CHK structure.
********************************************************************/
BOOL rpc_auth_ntlmssp_chk(RPC_AUTH_NTLMSSP_CHK *chk, uint32 crc32, uint32 seq_num)
{
if (chk == NULL)
return False;
if (chk->crc32 != crc32 ||
chk->ver != NTLMSSP_SIGN_VERSION ||
chk->seq_num != seq_num)
{
DEBUG(5,("verify failed - crc %x ver %x seq %d\n",
chk->crc32, chk->ver, chk->seq_num));
DEBUG(5,("verify expect - crc %x ver %x seq %d\n",
crc32, NTLMSSP_SIGN_VERSION, seq_num));
return False;
}
return True;
}
/*******************************************************************
Inits an RPC_AUTH_NTLMSSP_CHK structure.
********************************************************************/
void init_rpc_auth_ntlmssp_chk(RPC_AUTH_NTLMSSP_CHK *chk,
uint32 ver, uint32 crc32, uint32 seq_num)
{
chk->ver = ver;
chk->reserved = 0x0;
chk->crc32 = crc32;
chk->seq_num = seq_num;
}
/*******************************************************************
Reads or writes an RPC_AUTH_NTLMSSP_CHK structure.
********************************************************************/
BOOL smb_io_rpc_auth_ntlmssp_chk(const char *desc, RPC_AUTH_NTLMSSP_CHK *chk, prs_struct *ps, int depth)
{
if (chk == NULL)
return False;
prs_debug(ps, depth, desc, "smb_io_rpc_auth_ntlmssp_chk");
depth++;
if(!prs_align(ps))
return False;
if(!prs_uint32("ver ", ps, depth, &chk->ver))
return False;
if(!prs_uint32("reserved", ps, depth, &chk->reserved))
return False;
if(!prs_uint32("crc32 ", ps, depth, &chk->crc32))
return False;
if(!prs_uint32("seq_num ", ps, depth, &chk->seq_num))
return False;
return True;
}
/*******************************************************************
creates an RPC_AUTH_NETSEC_NEG structure.
********************************************************************/
void init_rpc_auth_netsec_neg(RPC_AUTH_NETSEC_NEG *neg,
const char *domain, const char *myname)
{
neg->type1 = 0;
neg->type2 = 0x3;
fstrcpy(neg->domain, domain);
fstrcpy(neg->myname, myname);
}
/*******************************************************************
Reads or writes an RPC_AUTH_NETSEC_NEG structure.
********************************************************************/
BOOL smb_io_rpc_auth_netsec_neg(const char *desc, RPC_AUTH_NETSEC_NEG *neg,
prs_struct *ps, int depth)
{
if (neg == NULL)
return False;
prs_debug(ps, depth, desc, "smb_io_rpc_auth_netsec_neg");
depth++;
if(!prs_align(ps))
return False;
if(!prs_uint32("type1", ps, depth, &neg->type1))
return False;
if(!prs_uint32("type2", ps, depth, &neg->type2))
return False;
if(!prs_string("domain ", ps, depth, neg->domain, sizeof(neg->domain)))
return False;
if(!prs_string("myname ", ps, depth, neg->myname, sizeof(neg->myname)))
return False;
return True;
}
/*******************************************************************
creates an RPC_AUTH_NETSEC_CHK structure.
********************************************************************/
BOOL init_rpc_auth_netsec_chk(RPC_AUTH_NETSEC_CHK * chk,
const uchar sig[8],
const uchar packet_digest[8],
const uchar seq_num[8], const uchar data8[8])
{
if (chk == NULL)
return False;
memcpy(chk->sig, sig, sizeof(chk->sig));
memcpy(chk->packet_digest, packet_digest, sizeof(chk->packet_digest));
memcpy(chk->seq_num, seq_num, sizeof(chk->seq_num));
memcpy(chk->data8, data8, sizeof(chk->data8));
return True;
}
/*******************************************************************
reads or writes an RPC_AUTH_NETSEC_CHK structure.
********************************************************************/
BOOL smb_io_rpc_auth_netsec_chk(const char *desc, RPC_AUTH_NETSEC_CHK * chk,
prs_struct *ps, int depth)
{
if (chk == NULL)
return False;
prs_debug(ps, depth, desc, "smb_io_rpc_auth_netsec_chk");
depth++;
prs_uint8s(False, "sig ", ps, depth, chk->sig, sizeof(chk->sig));
prs_uint8s(False, "seq_num", ps, depth, chk->seq_num, sizeof(chk->seq_num));
prs_uint8s(False, "packet_digest", ps, depth, chk->packet_digest, sizeof(chk->packet_digest));
prs_uint8s(False, "data8", ps, depth, chk->data8, sizeof(chk->data8));
return True;
}