mirror of
https://github.com/samba-team/samba.git
synced 2024-12-24 21:34:56 +03:00
Merge the TNG netlogon schannel from HEAD.
No more XP requiresignorseal anymore!
Thanks again to Luke :-)
Volker
(This used to be commit 6b2b55901d
)
This commit is contained in:
parent
3a9b54261f
commit
b4d0f208fb
@ -744,6 +744,7 @@
|
||||
<listitem><para><link linkend="ROOTDIR"><parameter>root dir</parameter></link></para></listitem>
|
||||
<listitem><para><link linkend="ROOTDIRECTORY"><parameter>root directory</parameter></link></para></listitem>
|
||||
<listitem><para><link linkend="SECURITY"><parameter>security</parameter></link></para></listitem>
|
||||
<listitem><para><link linkend="SERVERSCHANNEL"><parameter>server schannel</parameter></link></para></listitem>
|
||||
<listitem><para><link linkend="SERVERSTRING"><parameter>server string</parameter></link></para></listitem>
|
||||
<listitem><para><link linkend="SETPRIMARYGROUPSCRIPT"><parameter>set primary group script</parameter></link></para></listitem>
|
||||
<listitem><para><link linkend="SHOWADDPRINTERWIZARD"><parameter>show add printer wizard</parameter></link></para></listitem>
|
||||
@ -7008,6 +7009,31 @@
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry>
|
||||
<term><anchor id="SERVERSCHANNEL"/>server schannel (G)</term>
|
||||
<listitem>
|
||||
|
||||
<para>This controls whether the server offers or even
|
||||
demands the use of the netlogon schannel.
|
||||
<parameter>server schannel = no</parameter> does not
|
||||
offer the schannel, <parameter>server schannel =
|
||||
auto</parameter> offers the schannel but does not
|
||||
enforce it, and <parameter>server schannel =
|
||||
yes</parameter> denies access if the client is not
|
||||
able to speak netlogon schannel. This is only the case
|
||||
for Windows NT4 before SP4.</para>
|
||||
|
||||
<para>Please note that with this set to
|
||||
<parameter>no</parameter> you will have to apply the
|
||||
WindowsXP requireSignOrSeal-Registry patch found in
|
||||
the docs/Registry subdirectory.</para
|
||||
|
||||
<para>Default: <command>server schannel = auto</command></para>
|
||||
|
||||
<para>Example: <command>server schannel = yes</command>/para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><anchor id="SERVERSTRING">server string (G)</term>
|
||||
<listitem><para>This controls what string will show up in the
|
||||
|
@ -192,6 +192,13 @@ typedef struct pipes_struct
|
||||
uint32 ntlmssp_seq_num;
|
||||
struct dcinfo dc; /* Keeps the creds data. */
|
||||
|
||||
/* Hmm. In my understanding the authentication happens
|
||||
implicitly later, so there are no two stages for
|
||||
schannel. */
|
||||
|
||||
BOOL netsec_auth_validated;
|
||||
struct netsec_auth_struct netsec_auth;
|
||||
|
||||
/*
|
||||
* Windows user info.
|
||||
*/
|
||||
|
@ -55,6 +55,13 @@ enum RPC_PKT_TYPE
|
||||
#define NTLMSSP_AUTH_TYPE 0xa
|
||||
#define NTLMSSP_AUTH_LEVEL 0x6
|
||||
|
||||
/* Netlogon schannel auth type and level */
|
||||
#define NETSEC_AUTH_TYPE 0x44
|
||||
#define NETSEC_AUTH_LEVEL 0x6
|
||||
#define NETSEC_SIGNATURE { 0x77, 0x00, 0x7a, 0x00, 0xff, 0xff, 0x00, 0x00 }
|
||||
#define RPC_AUTH_NETSEC_CHK_LEN 0x20
|
||||
#define NETLOGON_NEG_SCHANNEL 0x40000000
|
||||
|
||||
/* Maximum PDU fragment size. */
|
||||
#define MAX_PDU_FRAG_LEN 0x1630
|
||||
/* #define MAX_PDU_FRAG_LEN 0x10b8 this is what w2k sets */
|
||||
@ -199,6 +206,34 @@ typedef struct rpc_hdr_auth_info
|
||||
|
||||
#define RPC_HDR_AUTH_LEN 8
|
||||
|
||||
/* this is TEMPORARILY coded up as a specific structure */
|
||||
/* this structure comes after the bind request */
|
||||
/* RPC_AUTH_NETSEC_NEG */
|
||||
typedef struct rpc_auth_netsec_neg_info
|
||||
{
|
||||
uint32 unknown1;
|
||||
uint32 unknown2;
|
||||
fstring domain; /* calling workstations's domain */
|
||||
fstring myname; /* calling workstation's name */
|
||||
} RPC_AUTH_NETSEC_NEG;
|
||||
|
||||
/* attached to the end of encrypted rpc requests and responses */
|
||||
/* RPC_AUTH_NETSEC_CHK */
|
||||
typedef struct rpc_auth_netsec_chk_info
|
||||
{
|
||||
uint8 sig [8]; /* 77 00 7a 00 ff ff 00 00 */
|
||||
uint8 data1[8];
|
||||
uint8 data3[8]; /* verifier, seq num */
|
||||
uint8 data8[8]; /* random 8-byte nonce */
|
||||
} RPC_AUTH_NETSEC_CHK;
|
||||
|
||||
struct netsec_auth_struct
|
||||
{
|
||||
RPC_AUTH_NETSEC_NEG netsec_neg;
|
||||
uchar sess_key[16];
|
||||
uint32 seq_num;
|
||||
};
|
||||
|
||||
/* RPC_BIND_REQ - ms req bind */
|
||||
typedef struct rpc_bind_req_info
|
||||
{
|
||||
@ -248,8 +283,8 @@ typedef struct rpc_hdr_ba_info
|
||||
/* RPC_AUTH_VERIFIER */
|
||||
typedef struct rpc_auth_verif_info
|
||||
{
|
||||
fstring signature; /* "NTLMSSP" */
|
||||
uint32 msg_type; /* NTLMSSP_MESSAGE_TYPE (1,2,3) */
|
||||
fstring signature; /* "NTLMSSP".. Ok, not quite anymore */
|
||||
uint32 msg_type; /* NTLMSSP_MESSAGE_TYPE (1,2,3) and 5 for schannel */
|
||||
|
||||
} RPC_AUTH_VERIFIER;
|
||||
|
||||
|
@ -230,6 +230,7 @@ typedef struct
|
||||
BOOL bDomainLogons;
|
||||
BOOL bEncryptPasswords;
|
||||
BOOL bUpdateEncrypt;
|
||||
int serverSchannel;
|
||||
BOOL bStripDot;
|
||||
BOOL bNullPasswords;
|
||||
BOOL bObeyPamRestrictions;
|
||||
@ -735,6 +736,7 @@ static struct parm_struct parm_table[] = {
|
||||
{"auth methods", P_LIST, P_GLOBAL, &Globals.AuthMethods, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
|
||||
{"encrypt passwords", P_BOOL, P_GLOBAL, &Globals.bEncryptPasswords, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
|
||||
{"update encrypted", P_BOOL, P_GLOBAL, &Globals.bUpdateEncrypt, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_DEVELOPER},
|
||||
{"server schannel", P_ENUM, P_GLOBAL, &Globals.serverSchannel, NULL, enum_bool_auto, FLAG_BASIC},
|
||||
{"allow trusted domains", P_BOOL, P_GLOBAL, &Globals.bAllowTrustedDomains, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
|
||||
{"hosts equiv", P_STRING, P_GLOBAL, &Globals.szHostsEquiv, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
|
||||
{"min passwd length", P_INTEGER, P_GLOBAL, &Globals.min_passwd_length, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
|
||||
@ -1331,6 +1333,7 @@ static void init_globals(void)
|
||||
Globals.paranoid_server_security = True;
|
||||
Globals.bEncryptPasswords = True;
|
||||
Globals.bUpdateEncrypt = False;
|
||||
Globals.serverSchannel = Auto;
|
||||
Globals.bReadRaw = True;
|
||||
Globals.bWriteRaw = True;
|
||||
Globals.bReadPrediction = False;
|
||||
@ -1659,6 +1662,7 @@ FN_GLOBAL_BOOL(lp_obey_pam_restrictions, &Globals.bObeyPamRestrictions)
|
||||
FN_GLOBAL_BOOL(lp_strip_dot, &Globals.bStripDot)
|
||||
FN_GLOBAL_BOOL(lp_encrypted_passwords, &Globals.bEncryptPasswords)
|
||||
FN_GLOBAL_BOOL(lp_update_encrypted, &Globals.bUpdateEncrypt)
|
||||
FN_GLOBAL_INTEGER(lp_server_schannel, &Globals.serverSchannel)
|
||||
FN_GLOBAL_BOOL(lp_syslog_only, &Globals.bSyslogOnly)
|
||||
FN_GLOBAL_BOOL(lp_timestamp_logs, &Globals.bTimestampLogs)
|
||||
FN_GLOBAL_BOOL(lp_debug_hires_timestamp, &Globals.bDebugHiresTimestamp)
|
||||
|
@ -691,6 +691,30 @@ BOOL smb_io_rpc_auth_verifier(const char *desc, RPC_AUTH_VERIFIER *rav, prs_stru
|
||||
return True;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
This parses an RPC_AUTH_VERIFIER for NETLOGON schannel. I thing
|
||||
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++;
|
||||
|
||||
/* "NTLMSSP" */
|
||||
if(!prs_string("signature", ps, depth, rav->signature, strlen(rav->signature),
|
||||
sizeof(rav->signature)))
|
||||
return False;
|
||||
if(!prs_uint32("msg_type ", ps, depth, &rav->msg_type)) /* NTLMSSP_MESSAGE_TYPE */
|
||||
return False;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
Inits an RPC_AUTH_NTLMSSP_NEG structure.
|
||||
********************************************************************/
|
||||
@ -1104,3 +1128,74 @@ BOOL smb_io_rpc_auth_ntlmssp_chk(const char *desc, RPC_AUTH_NTLMSSP_CHK *chk, pr
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
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("unknown1", ps, depth, &neg->unknown1))
|
||||
return False;
|
||||
if(!prs_uint32("unknown2", ps, depth, &neg->unknown2))
|
||||
return False;
|
||||
if(!prs_string("domain ", ps, depth, neg->domain,
|
||||
strlen(&ps->data_p[ps->data_offset]), sizeof(neg->domain)))
|
||||
return False;
|
||||
if(!prs_string("myname ", ps, depth, neg->myname,
|
||||
strlen(&ps->data_p[ps->data_offset]), 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 data1[8],
|
||||
const uchar data3[8], const uchar data8[8])
|
||||
{
|
||||
if (chk == NULL)
|
||||
return False;
|
||||
|
||||
memcpy(chk->sig, sig, sizeof(chk->sig));
|
||||
memcpy(chk->data1, data1, sizeof(chk->data1));
|
||||
memcpy(chk->data3, data3, sizeof(chk->data3));
|
||||
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, "data3", ps, depth, chk->data3, sizeof(chk->data3));
|
||||
prs_uint8s(False, "data1", ps, depth, chk->data1, sizeof(chk->data1));
|
||||
prs_uint8s(False, "data8", ps, depth, chk->data8, sizeof(chk->data8));
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
|
@ -334,6 +334,13 @@ NTSTATUS _net_auth_2(pipes_struct *p, NET_Q_AUTH_2 *q_u, NET_R_AUTH_2 *r_u)
|
||||
|
||||
srv_time.time = 0;
|
||||
|
||||
if ( (lp_server_schannel() == True) &&
|
||||
((q_u->clnt_flgs.neg_flags & NETLOGON_NEG_SCHANNEL) == 0) ) {
|
||||
|
||||
/* schannel must be used, but client did not offer it. */
|
||||
status = NT_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
rpcstr_pull(mach_acct, q_u->clnt_id.uni_acct_name.buffer,sizeof(fstring),q_u->clnt_id.uni_acct_name.uni_str_len*2,0);
|
||||
|
||||
if (p->dc.challenge_sent && get_md4pw((char *)p->dc.md4pw, mach_acct)) {
|
||||
@ -366,9 +373,18 @@ NTSTATUS _net_auth_2(pipes_struct *p, NET_Q_AUTH_2 *q_u, NET_R_AUTH_2 *r_u)
|
||||
|
||||
srv_flgs.neg_flags = 0x000001ff;
|
||||
|
||||
if (lp_server_schannel() != False) {
|
||||
srv_flgs.neg_flags |= NETLOGON_NEG_SCHANNEL;
|
||||
}
|
||||
|
||||
/* set up the LSA AUTH 2 response */
|
||||
init_net_r_auth_2(r_u, &srv_cred, &srv_flgs, status);
|
||||
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
extern struct dcinfo last_dcinfo;
|
||||
last_dcinfo = p->dc;
|
||||
}
|
||||
|
||||
return r_u->status;
|
||||
}
|
||||
|
||||
@ -523,7 +539,23 @@ NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *
|
||||
|
||||
if (!get_valid_user_struct(p->vuid))
|
||||
return NT_STATUS_NO_SUCH_USER;
|
||||
|
||||
|
||||
|
||||
if ( (lp_server_schannel() == True) && (!p->netsec_auth_validated) ) {
|
||||
/* 'server schannel = yes' should enforce use of
|
||||
schannel, the client did offer it in auth2, but
|
||||
obviously did not use it. */
|
||||
return NT_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
if (p->netsec_auth_validated) {
|
||||
/* The client opens a second RPC NETLOGON pipe without
|
||||
doing a auth2. The session key for the schannel is
|
||||
re-used from the auth2 the client did before. */
|
||||
extern struct dcinfo last_dcinfo;
|
||||
p->dc = last_dcinfo;
|
||||
}
|
||||
|
||||
/* checks and updates credentials. creates reply credentials */
|
||||
if (!(p->dc.authenticated && deal_with_creds(p->dc.sess_key, &p->dc.clnt_cred, &q_u->sam_id.client.cred, &srv_cred)))
|
||||
return NT_STATUS_INVALID_HANDLE;
|
||||
|
@ -43,6 +43,13 @@
|
||||
#undef DBGC_CLASS
|
||||
#define DBGC_CLASS DBGC_RPC_SRV
|
||||
|
||||
/*************************************************************
|
||||
HACK Alert!
|
||||
We need to transfer the session key from one rpc bind to the
|
||||
next. This is the way the netlogon schannel works.
|
||||
**************************************************************/
|
||||
struct dcinfo last_dcinfo;
|
||||
|
||||
static void NTLMSSPcalc_p( pipes_struct *p, unsigned char *data, int len)
|
||||
{
|
||||
unsigned char *hash = p->ntlmssp_hash;
|
||||
@ -115,6 +122,9 @@ BOOL create_next_pdu(pipes_struct *p)
|
||||
if(p->ntlmssp_auth_validated)
|
||||
data_space_available -= (RPC_HDR_AUTH_LEN + RPC_AUTH_NTLMSSP_CHK_LEN);
|
||||
|
||||
if(p->netsec_auth_validated)
|
||||
data_space_available -= (RPC_HDR_AUTH_LEN + RPC_AUTH_NETSEC_CHK_LEN);
|
||||
|
||||
/*
|
||||
* The amount we send is the minimum of the available
|
||||
* space and the amount left to send.
|
||||
@ -148,6 +158,10 @@ BOOL create_next_pdu(pipes_struct *p)
|
||||
p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len +
|
||||
RPC_HDR_AUTH_LEN + RPC_AUTH_NTLMSSP_CHK_LEN;
|
||||
p->hdr.auth_len = RPC_AUTH_NTLMSSP_CHK_LEN;
|
||||
} else if (p->netsec_auth_validated) {
|
||||
p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len +
|
||||
RPC_HDR_AUTH_LEN + RPC_AUTH_NETSEC_CHK_LEN;
|
||||
p->hdr.auth_len = RPC_AUTH_NETSEC_CHK_LEN;
|
||||
} else {
|
||||
p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len;
|
||||
p->hdr.auth_len = 0;
|
||||
@ -192,7 +206,7 @@ BOOL create_next_pdu(pipes_struct *p)
|
||||
return False;
|
||||
}
|
||||
|
||||
if (p->hdr.auth_len > 0) {
|
||||
if (p->ntlmssp_auth_validated) {
|
||||
uint32 crc32 = 0;
|
||||
char *data;
|
||||
|
||||
@ -239,6 +253,47 @@ BOOL create_next_pdu(pipes_struct *p)
|
||||
}
|
||||
}
|
||||
|
||||
if (p->netsec_auth_validated) {
|
||||
char *data;
|
||||
RPC_HDR_AUTH auth_info;
|
||||
static const uchar netsec_sig[8] = NETSEC_SIGNATURE;
|
||||
static const uchar nullbytes[8] = { 0,0,0,0,0,0,0,0 };
|
||||
|
||||
RPC_AUTH_NETSEC_CHK verf;
|
||||
prs_struct rverf;
|
||||
prs_struct rauth;
|
||||
|
||||
uchar sign[8];
|
||||
|
||||
data = prs_data_p(&outgoing_pdu) + data_pos;
|
||||
|
||||
init_rpc_hdr_auth(&auth_info, NETSEC_AUTH_TYPE, NETSEC_AUTH_LEVEL,
|
||||
RPC_HDR_AUTH_LEN, 1);
|
||||
|
||||
if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, &outgoing_pdu, 0)) {
|
||||
DEBUG(0,("create_next_pdu: failed to marshall RPC_HDR_AUTH.\n"));
|
||||
prs_mem_free(&outgoing_pdu);
|
||||
return False;
|
||||
}
|
||||
|
||||
prs_init(&rverf, 0, p->mem_ctx, MARSHALL);
|
||||
prs_init(&rauth, 0, p->mem_ctx, MARSHALL);
|
||||
|
||||
memset(sign, 0, sizeof(sign));
|
||||
sign[3] = 0x01;
|
||||
|
||||
init_rpc_auth_netsec_chk(&verf, netsec_sig, nullbytes, sign, nullbytes);
|
||||
|
||||
if (!netsec_encode(&p->netsec_auth, &verf, data, data_len)) {
|
||||
DEBUG(0,("create_next_pdu: failed encode data.\n"));
|
||||
prs_mem_free(&outgoing_pdu);
|
||||
return False;
|
||||
}
|
||||
|
||||
smb_io_rpc_auth_netsec_chk("", &verf, &outgoing_pdu, 0);
|
||||
p->netsec_auth.seq_num++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup the counts for this PDU.
|
||||
*/
|
||||
@ -851,6 +906,7 @@ BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
|
||||
enum RPC_PKT_TYPE reply_pkt_type;
|
||||
|
||||
p->ntlmssp_auth_requested = False;
|
||||
p->netsec_auth_validated = False;
|
||||
|
||||
DEBUG(5,("api_pipe_bind_req: decode request. %d\n", __LINE__));
|
||||
|
||||
@ -918,39 +974,62 @@ BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
|
||||
return False;
|
||||
}
|
||||
|
||||
/*
|
||||
* We only support NTLMSSP_AUTH_TYPE requests.
|
||||
*/
|
||||
if(auth_info.auth_type == NTLMSSP_AUTH_TYPE) {
|
||||
|
||||
if(auth_info.auth_type != NTLMSSP_AUTH_TYPE) {
|
||||
if(!smb_io_rpc_auth_verifier("", &auth_verifier, rpc_in_p, 0)) {
|
||||
DEBUG(0,("api_pipe_bind_req: unable to "
|
||||
"unmarshall RPC_HDR_AUTH struct.\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
if(!strequal(auth_verifier.signature, "NTLMSSP")) {
|
||||
DEBUG(0,("api_pipe_bind_req: "
|
||||
"auth_verifier.signature != NTLMSSP\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
if(auth_verifier.msg_type != NTLMSSP_NEGOTIATE) {
|
||||
DEBUG(0,("api_pipe_bind_req: "
|
||||
"auth_verifier.msg_type (%d) != NTLMSSP_NEGOTIATE\n",
|
||||
auth_verifier.msg_type));
|
||||
return False;
|
||||
}
|
||||
|
||||
if(!smb_io_rpc_auth_ntlmssp_neg("", &ntlmssp_neg, rpc_in_p, 0)) {
|
||||
DEBUG(0,("api_pipe_bind_req: "
|
||||
"Failed to unmarshall RPC_AUTH_NTLMSSP_NEG.\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
p->ntlmssp_chal_flags = SMBD_NTLMSSP_NEG_FLAGS;
|
||||
p->ntlmssp_auth_requested = True;
|
||||
|
||||
} else if (auth_info.auth_type == NETSEC_AUTH_TYPE) {
|
||||
|
||||
RPC_AUTH_NETSEC_NEG neg;
|
||||
struct netsec_auth_struct *a = &(p->netsec_auth);
|
||||
|
||||
if (!smb_io_rpc_auth_netsec_neg("", &neg, rpc_in_p, 0)) {
|
||||
DEBUG(0,("api_pipe_bind_req: "
|
||||
"Could not unmarshal SCHANNEL auth neg\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
p->netsec_auth_validated = True;
|
||||
|
||||
memset(a->sess_key, 0, sizeof(a->sess_key));
|
||||
memcpy(a->sess_key, last_dcinfo.sess_key, sizeof(last_dcinfo.sess_key));
|
||||
|
||||
a->seq_num = 0;
|
||||
|
||||
DEBUG(10,("schannel auth: domain [%s] myname [%s]\n",
|
||||
neg.domain, neg.myname));
|
||||
|
||||
} else {
|
||||
DEBUG(0,("api_pipe_bind_req: unknown auth type %x requested.\n",
|
||||
auth_info.auth_type ));
|
||||
auth_info.auth_type ));
|
||||
return False;
|
||||
}
|
||||
|
||||
if(!smb_io_rpc_auth_verifier("", &auth_verifier, rpc_in_p, 0)) {
|
||||
DEBUG(0,("api_pipe_bind_req: unable to unmarshall RPC_HDR_AUTH struct.\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
if(!strequal(auth_verifier.signature, "NTLMSSP")) {
|
||||
DEBUG(0,("api_pipe_bind_req: auth_verifier.signature != NTLMSSP\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
if(auth_verifier.msg_type != NTLMSSP_NEGOTIATE) {
|
||||
DEBUG(0,("api_pipe_bind_req: auth_verifier.msg_type (%d) != NTLMSSP_NEGOTIATE\n",
|
||||
auth_verifier.msg_type));
|
||||
return False;
|
||||
}
|
||||
|
||||
if(!smb_io_rpc_auth_ntlmssp_neg("", &ntlmssp_neg, rpc_in_p, 0)) {
|
||||
DEBUG(0,("api_pipe_bind_req: Failed to unmarshall RPC_AUTH_NTLMSSP_NEG.\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
p->ntlmssp_chal_flags = SMBD_NTLMSSP_NEG_FLAGS;
|
||||
p->ntlmssp_auth_requested = True;
|
||||
}
|
||||
|
||||
switch(p->hdr.pkt_type) {
|
||||
@ -1081,6 +1160,33 @@ BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
|
||||
auth_len = prs_offset(&out_auth) - RPC_HDR_AUTH_LEN;
|
||||
}
|
||||
|
||||
if (p->netsec_auth_validated) {
|
||||
RPC_AUTH_VERIFIER auth_verifier;
|
||||
uint32 flags;
|
||||
|
||||
init_rpc_hdr_auth(&auth_info, NETSEC_AUTH_TYPE, NETSEC_AUTH_LEVEL, RPC_HDR_AUTH_LEN, 1);
|
||||
if(!smb_io_rpc_hdr_auth("", &auth_info, &out_auth, 0)) {
|
||||
DEBUG(0,("api_pipe_bind_req: marshalling of RPC_HDR_AUTH failed.\n"));
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
/*** NETSEC verifier ***/
|
||||
|
||||
init_rpc_auth_verifier(&auth_verifier, "\001", 0x0);
|
||||
if(!smb_io_rpc_netsec_verifier("", &auth_verifier, &out_auth, 0)) {
|
||||
DEBUG(0,("api_pipe_bind_req: marshalling of RPC_AUTH_VERIFIER failed.\n"));
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
prs_align(&out_auth);
|
||||
|
||||
flags = 5;
|
||||
if(!prs_uint32("flags ", &out_auth, 0, &flags))
|
||||
goto err_exit;
|
||||
|
||||
auth_len = prs_offset(&out_auth) - RPC_HDR_AUTH_LEN;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the header, now we know the length.
|
||||
*/
|
||||
@ -1108,7 +1214,8 @@ BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
if(p->ntlmssp_auth_requested && !prs_append_prs_data( &outgoing_rpc, &out_auth)) {
|
||||
if((p->ntlmssp_auth_requested|p->netsec_auth_validated) &&
|
||||
!prs_append_prs_data( &outgoing_rpc, &out_auth)) {
|
||||
DEBUG(0,("api_pipe_bind_req: append of auth info failed.\n"));
|
||||
goto err_exit;
|
||||
}
|
||||
@ -1240,6 +1347,265 @@ BOOL api_pipe_auth_process(pipes_struct *p, prs_struct *rpc_in)
|
||||
return True;
|
||||
}
|
||||
|
||||
static void netsechash(uchar * key, uchar * data, int data_len)
|
||||
{
|
||||
uchar hash[256];
|
||||
uchar index_i = 0;
|
||||
uchar index_j = 0;
|
||||
uchar j = 0;
|
||||
int ind;
|
||||
|
||||
for (ind = 0; ind < 256; ind++)
|
||||
{
|
||||
hash[ind] = (uchar) ind;
|
||||
}
|
||||
|
||||
for (ind = 0; ind < 256; ind++)
|
||||
{
|
||||
uchar tc;
|
||||
|
||||
j += (hash[ind] + key[ind % 16]);
|
||||
|
||||
tc = hash[ind];
|
||||
hash[ind] = hash[j];
|
||||
hash[j] = tc;
|
||||
}
|
||||
|
||||
for (ind = 0; ind < data_len; ind++)
|
||||
{
|
||||
uchar tc;
|
||||
uchar t;
|
||||
|
||||
index_i++;
|
||||
index_j += hash[index_i];
|
||||
|
||||
tc = hash[index_i];
|
||||
hash[index_i] = hash[index_j];
|
||||
hash[index_j] = tc;
|
||||
|
||||
t = hash[index_i] + hash[index_j];
|
||||
data[ind] ^= hash[t];
|
||||
}
|
||||
}
|
||||
|
||||
void dump_data_pw(const char *msg, const uchar * data, size_t len)
|
||||
{
|
||||
#ifdef DEBUG_PASSWORD
|
||||
DEBUG(11, ("%s", msg));
|
||||
if (data != NULL && len > 0)
|
||||
{
|
||||
dump_data(11, data, len);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOL netsec_encode(struct netsec_auth_struct *a,
|
||||
RPC_AUTH_NETSEC_CHK * verf, char *data, size_t data_len)
|
||||
{
|
||||
uchar dataN[4];
|
||||
uchar digest1[16];
|
||||
struct MD5Context ctx3;
|
||||
uchar sess_kf0[16];
|
||||
int i;
|
||||
|
||||
/* store the sequence number */
|
||||
SIVAL(dataN, 0, a->seq_num);
|
||||
|
||||
for (i = 0; i < sizeof(sess_kf0); i++)
|
||||
{
|
||||
sess_kf0[i] = a->sess_key[i] ^ 0xf0;
|
||||
}
|
||||
|
||||
dump_data_pw("a->sess_key:\n", a->sess_key, sizeof(a->sess_key));
|
||||
dump_data_pw("a->seq_num :\n", dataN, sizeof(dataN));
|
||||
|
||||
MD5Init(&ctx3);
|
||||
MD5Update(&ctx3, dataN, 0x4);
|
||||
MD5Update(&ctx3, verf->sig, 8);
|
||||
|
||||
MD5Update(&ctx3, verf->data8, 8);
|
||||
|
||||
dump_data_pw("verf->data8:\n", verf->data8, sizeof(verf->data8));
|
||||
dump_data_pw("sess_kf0:\n", sess_kf0, sizeof(sess_kf0));
|
||||
|
||||
hmac_md5(sess_kf0, dataN, 0x4, digest1);
|
||||
dump_data_pw("digest1 (ebp-8):\n", digest1, sizeof(digest1));
|
||||
hmac_md5(digest1, verf->data3, 8, digest1);
|
||||
dump_data_pw("netsechashkey:\n", digest1, sizeof(digest1));
|
||||
netsechash(digest1, verf->data8, 8);
|
||||
|
||||
dump_data_pw("verf->data8:\n", verf->data8, sizeof(verf->data8));
|
||||
|
||||
dump_data_pw("data :\n", data, data_len);
|
||||
MD5Update(&ctx3, data, data_len);
|
||||
|
||||
{
|
||||
char digest_tmp[16];
|
||||
char digest2[16];
|
||||
MD5Final(digest_tmp, &ctx3);
|
||||
hmac_md5(a->sess_key, digest_tmp, 16, digest2);
|
||||
dump_data_pw("digest_tmp:\n", digest_tmp, sizeof(digest_tmp));
|
||||
dump_data_pw("digest:\n", digest2, sizeof(digest2));
|
||||
memcpy(verf->data1, digest2, sizeof(verf->data1));
|
||||
}
|
||||
|
||||
netsechash(digest1, data, data_len);
|
||||
dump_data_pw("data:\n", data, data_len);
|
||||
|
||||
hmac_md5(a->sess_key, dataN, 0x4, digest1);
|
||||
dump_data_pw("ctx:\n", digest1, sizeof(digest1));
|
||||
|
||||
hmac_md5(digest1, verf->data1, 8, digest1);
|
||||
|
||||
dump_data_pw("netsechashkey:\n", digest1, sizeof(digest1));
|
||||
|
||||
dump_data_pw("verf->data3:\n", verf->data3, sizeof(verf->data3));
|
||||
netsechash(digest1, verf->data3, 8);
|
||||
dump_data_pw("verf->data3:\n", verf->data3, sizeof(verf->data3));
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
BOOL netsec_decode(struct netsec_auth_struct *a,
|
||||
RPC_AUTH_NETSEC_CHK * verf, char *data, size_t data_len)
|
||||
{
|
||||
uchar dataN[4];
|
||||
uchar digest1[16];
|
||||
struct MD5Context ctx3;
|
||||
uchar sess_kf0[16];
|
||||
int i;
|
||||
|
||||
/* store the sequence number */
|
||||
SIVAL(dataN, 0, a->seq_num);
|
||||
|
||||
for (i = 0; i < sizeof(sess_kf0); i++)
|
||||
{
|
||||
sess_kf0[i] = a->sess_key[i] ^ 0xf0;
|
||||
}
|
||||
|
||||
dump_data_pw("a->sess_key:\n", a->sess_key, sizeof(a->sess_key));
|
||||
dump_data_pw("a->seq_num :\n", dataN, sizeof(dataN));
|
||||
hmac_md5(a->sess_key, dataN, 0x4, digest1);
|
||||
dump_data_pw("ctx:\n", digest1, sizeof(digest1));
|
||||
|
||||
hmac_md5(digest1, verf->data1, 8, digest1);
|
||||
|
||||
dump_data_pw("netsechashkey:\n", digest1, sizeof(digest1));
|
||||
dump_data_pw("verf->data3:\n", verf->data3, sizeof(verf->data3));
|
||||
netsechash(digest1, verf->data3, 8);
|
||||
dump_data_pw("verf->data3_dec:\n", verf->data3, sizeof(verf->data3));
|
||||
|
||||
MD5Init(&ctx3);
|
||||
MD5Update(&ctx3, dataN, 0x4);
|
||||
MD5Update(&ctx3, verf->sig, 8);
|
||||
|
||||
dump_data_pw("sess_kf0:\n", sess_kf0, sizeof(sess_kf0));
|
||||
|
||||
hmac_md5(sess_kf0, dataN, 0x4, digest1);
|
||||
dump_data_pw("digest1 (ebp-8):\n", digest1, sizeof(digest1));
|
||||
hmac_md5(digest1, verf->data3, 8, digest1);
|
||||
dump_data_pw("netsechashkey:\n", digest1, sizeof(digest1));
|
||||
|
||||
dump_data_pw("verf->data8:\n", verf->data8, sizeof(verf->data8));
|
||||
netsechash(digest1, verf->data8, 8);
|
||||
dump_data_pw("verf->data8_dec:\n", verf->data8, sizeof(verf->data8));
|
||||
MD5Update(&ctx3, verf->data8, 8);
|
||||
|
||||
dump_data_pw("data :\n", data, data_len);
|
||||
netsechash(digest1, data, data_len);
|
||||
dump_data_pw("datadec:\n", data, data_len);
|
||||
|
||||
MD5Update(&ctx3, data, data_len);
|
||||
{
|
||||
uchar digest_tmp[16];
|
||||
MD5Final(digest_tmp, &ctx3);
|
||||
hmac_md5(a->sess_key, digest_tmp, 16, digest1);
|
||||
dump_data_pw("digest_tmp:\n", digest_tmp, sizeof(digest_tmp));
|
||||
}
|
||||
|
||||
dump_data_pw("digest:\n", digest1, sizeof(digest1));
|
||||
dump_data_pw("verf->data1:\n", verf->data1, sizeof(verf->data1));
|
||||
|
||||
return memcmp(digest1, verf->data1, sizeof(verf->data1)) == 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Deal with schannel processing on an RPC request.
|
||||
****************************************************************************/
|
||||
BOOL api_pipe_netsec_process(pipes_struct *p, prs_struct *rpc_in)
|
||||
{
|
||||
/*
|
||||
* We always negotiate the following two bits....
|
||||
*/
|
||||
int data_len;
|
||||
int auth_len;
|
||||
uint32 old_offset;
|
||||
RPC_HDR_AUTH auth_info;
|
||||
RPC_AUTH_NETSEC_CHK netsec_chk;
|
||||
|
||||
|
||||
auth_len = p->hdr.auth_len;
|
||||
|
||||
if (auth_len != RPC_AUTH_NETSEC_CHK_LEN) {
|
||||
DEBUG(0,("Incorrect auth_len %d.\n", auth_len ));
|
||||
return False;
|
||||
}
|
||||
|
||||
/*
|
||||
* The following is that length of the data we must verify or unseal.
|
||||
* This doesn't include the RPC headers or the auth_len or the RPC_HDR_AUTH_LEN
|
||||
* preceeding the auth_data.
|
||||
*/
|
||||
|
||||
data_len = p->hdr.frag_len - RPC_HEADER_LEN - RPC_HDR_REQ_LEN -
|
||||
RPC_HDR_AUTH_LEN - auth_len;
|
||||
|
||||
DEBUG(5,("data %d auth %d\n", data_len, auth_len));
|
||||
|
||||
old_offset = prs_offset(rpc_in);
|
||||
|
||||
if(!prs_set_offset(rpc_in, old_offset + data_len)) {
|
||||
DEBUG(0,("cannot move offset to %u.\n",
|
||||
(unsigned int)old_offset + data_len ));
|
||||
return False;
|
||||
}
|
||||
|
||||
if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, rpc_in, 0)) {
|
||||
DEBUG(0,("failed to unmarshall RPC_HDR_AUTH.\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
if ((auth_info.auth_type != NETSEC_AUTH_TYPE) ||
|
||||
(auth_info.auth_level != NETSEC_AUTH_LEVEL)) {
|
||||
DEBUG(0,("Invalid auth info %d or level %d on schannel\n",
|
||||
auth_info.auth_type, auth_info.auth_level));
|
||||
return False;
|
||||
}
|
||||
|
||||
if(!smb_io_rpc_auth_netsec_chk("", &netsec_chk, rpc_in, 0)) {
|
||||
DEBUG(0,("failed to unmarshal RPC_AUTH_NETSEC_CHK.\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
if (!netsec_decode(&p->netsec_auth, &netsec_chk,
|
||||
prs_data_p(rpc_in)+old_offset, data_len)) {
|
||||
DEBUG(0,("failed to decode PDU\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the current pointer to the data offset.
|
||||
*/
|
||||
|
||||
if(!prs_set_offset(rpc_in, old_offset)) {
|
||||
DEBUG(0,("failed to set offset back to %u\n",
|
||||
(unsigned int)old_offset ));
|
||||
return False;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Return a user struct for a pipe user.
|
||||
****************************************************************************/
|
||||
|
@ -594,11 +594,18 @@ static BOOL process_request_pdu(pipes_struct *p, prs_struct *rpc_in_p)
|
||||
* Authentication _was_ requested and it already failed.
|
||||
*/
|
||||
|
||||
DEBUG(0,("process_request_pdu: RPC request received on pipe %s where \
|
||||
authentication failed. Denying the request.\n", p->name));
|
||||
DEBUG(0,("process_request_pdu: RPC request received on pipe %s "
|
||||
"where authentication failed. Denying the request.\n",
|
||||
p->name));
|
||||
set_incoming_fault(p);
|
||||
return False;
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
if (p->netsec_auth_validated && !api_pipe_netsec_process(p, rpc_in_p)) {
|
||||
DEBUG(0,("process_request_pdu: failed to do schannel processing.\n"));
|
||||
set_incoming_fault(p);
|
||||
return False;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the data length doesn't go over the 15Mb limit.
|
||||
|
Loading…
Reference in New Issue
Block a user