mirror of
https://github.com/samba-team/samba.git
synced 2024-12-23 17:34:34 +03:00
r2284: Thanks to some great detective work by tridge, NTLM2 signing now works.
This means that 'require NTLMv2 session security' now works for RPC
pipe signing. We don't yet have sealing, but it can't be much further.
This is almost all tridge's code, munged into a form that can work
with the GENSEC API.
This commit also includes more lsakey fixes - that key is used for all
DCE-RPC level authenticated connections, even over CIFS/ncacn_np.
No doubt I missed something, but I'm going to get some sleep :-)
Andrew Bartlett
(This used to be commit a1fe175eec
)
This commit is contained in:
parent
4490c816a9
commit
909c9b681a
@ -248,8 +248,6 @@ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
|
||||
gensec_want_feature(gensec_security, GENSEC_WANT_SEAL);
|
||||
}
|
||||
|
||||
gensec_want_feature(gensec_security, GENSEC_WANT_SESSION_KEY);
|
||||
|
||||
return gensec_start_mech(gensec_security);
|
||||
}
|
||||
|
||||
@ -303,17 +301,23 @@ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
|
||||
*/
|
||||
NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
uint8_t *data, size_t length, DATA_BLOB *sig)
|
||||
uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
DATA_BLOB *sig)
|
||||
{
|
||||
if (!gensec_security->ops->unseal_packet) {
|
||||
return NT_STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
return gensec_security->ops->unseal_packet(gensec_security, mem_ctx, data, length, sig);
|
||||
return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
|
||||
data, length,
|
||||
whole_pdu, pdu_length,
|
||||
sig);
|
||||
}
|
||||
|
||||
NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
const DATA_BLOB *sig)
|
||||
{
|
||||
if (!gensec_security->ops->check_packet) {
|
||||
@ -323,12 +327,13 @@ NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
|
||||
return NT_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, sig);
|
||||
return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
|
||||
}
|
||||
|
||||
NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
DATA_BLOB *sig)
|
||||
{
|
||||
if (!gensec_security->ops->seal_packet) {
|
||||
@ -338,12 +343,13 @@ NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
|
||||
return NT_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, sig);
|
||||
return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
|
||||
}
|
||||
|
||||
NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
DATA_BLOB *sig)
|
||||
{
|
||||
if (!gensec_security->ops->sign_packet) {
|
||||
@ -353,7 +359,19 @@ NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
|
||||
return NT_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, sig);
|
||||
return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
|
||||
}
|
||||
|
||||
size_t gensec_sig_size(struct gensec_security *gensec_security)
|
||||
{
|
||||
if (!gensec_security->ops->sig_size) {
|
||||
return 0;
|
||||
}
|
||||
if (!(gensec_security->want_features & GENSEC_WANT_SIGN)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return gensec_security->ops->sig_size(gensec_security);
|
||||
}
|
||||
|
||||
NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
|
||||
|
@ -60,13 +60,22 @@ struct gensec_security_ops {
|
||||
NTSTATUS (*update)(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
|
||||
const DATA_BLOB in, DATA_BLOB *out);
|
||||
NTSTATUS (*seal_packet)(struct gensec_security *gensec_security, TALLOC_CTX *sig_mem_ctx,
|
||||
uint8_t *data, size_t length, DATA_BLOB *sig);
|
||||
uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
DATA_BLOB *sig);
|
||||
NTSTATUS (*sign_packet)(struct gensec_security *gensec_security, TALLOC_CTX *sig_mem_ctx,
|
||||
const uint8_t *data, size_t length, DATA_BLOB *sig);
|
||||
const uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
DATA_BLOB *sig);
|
||||
size_t (*sig_size)(struct gensec_security *gensec_security);
|
||||
NTSTATUS (*check_packet)(struct gensec_security *gensec_security, TALLOC_CTX *sig_mem_ctx,
|
||||
const uint8_t *data, size_t length, const DATA_BLOB *sig);
|
||||
const uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
const DATA_BLOB *sig);
|
||||
NTSTATUS (*unseal_packet)(struct gensec_security *gensec_security, TALLOC_CTX *sig_mem_ctx,
|
||||
uint8_t *data, size_t length, DATA_BLOB *sig);
|
||||
uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
DATA_BLOB *sig);
|
||||
NTSTATUS (*session_key)(struct gensec_security *gensec_security, DATA_BLOB *session_key);
|
||||
NTSTATUS (*session_info)(struct gensec_security *gensec_security,
|
||||
struct auth_session_info **session_info);
|
||||
|
@ -287,42 +287,52 @@ static NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_secur
|
||||
wrappers for the ntlmssp_*() functions
|
||||
*/
|
||||
static NTSTATUS gensec_ntlmssp_unseal_packet(struct gensec_security *gensec_security,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
uint8_t *data, size_t length, DATA_BLOB *sig)
|
||||
TALLOC_CTX *mem_ctx,
|
||||
uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
DATA_BLOB *sig)
|
||||
{
|
||||
struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
|
||||
|
||||
return ntlmssp_unseal_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, sig);
|
||||
return ntlmssp_unseal_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, whole_pdu, pdu_length, sig);
|
||||
}
|
||||
|
||||
static NTSTATUS gensec_ntlmssp_check_packet(struct gensec_security *gensec_security,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const uint8_t *data, size_t length,
|
||||
const DATA_BLOB *sig)
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
const DATA_BLOB *sig)
|
||||
{
|
||||
struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
|
||||
|
||||
return ntlmssp_check_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, sig);
|
||||
return ntlmssp_check_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, whole_pdu, pdu_length, sig);
|
||||
}
|
||||
|
||||
static NTSTATUS gensec_ntlmssp_seal_packet(struct gensec_security *gensec_security,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
uint8_t *data, size_t length,
|
||||
DATA_BLOB *sig)
|
||||
TALLOC_CTX *mem_ctx,
|
||||
uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
DATA_BLOB *sig)
|
||||
{
|
||||
struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
|
||||
|
||||
return ntlmssp_seal_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, sig);
|
||||
return ntlmssp_seal_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, whole_pdu, pdu_length, sig);
|
||||
}
|
||||
|
||||
static NTSTATUS gensec_ntlmssp_sign_packet(struct gensec_security *gensec_security,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const uint8_t *data, size_t length,
|
||||
DATA_BLOB *sig)
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
DATA_BLOB *sig)
|
||||
{
|
||||
struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
|
||||
|
||||
return ntlmssp_sign_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, sig);
|
||||
return ntlmssp_sign_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, whole_pdu, pdu_length, sig);
|
||||
}
|
||||
|
||||
static size_t gensec_ntlmssp_sig_size(struct gensec_security *gensec_security)
|
||||
{
|
||||
return NTLMSSP_SIG_SIZE;
|
||||
}
|
||||
|
||||
static NTSTATUS gensec_ntlmssp_session_key(struct gensec_security *gensec_security,
|
||||
@ -413,6 +423,7 @@ static const struct gensec_security_ops gensec_ntlmssp_security_ops = {
|
||||
.server_start = gensec_ntlmssp_server_start,
|
||||
.update = gensec_ntlmssp_update,
|
||||
.seal_packet = gensec_ntlmssp_seal_packet,
|
||||
.sig_size = gensec_ntlmssp_sig_size,
|
||||
.sign_packet = gensec_ntlmssp_sign_packet,
|
||||
.check_packet = gensec_ntlmssp_check_packet,
|
||||
.unseal_packet = gensec_ntlmssp_unseal_packet,
|
||||
|
@ -940,7 +940,7 @@ NTSTATUS ntlmssp_server_start(struct ntlmssp_state **ntlmssp_state)
|
||||
(*ntlmssp_state)->neg_flags =
|
||||
NTLMSSP_NEGOTIATE_128 |
|
||||
NTLMSSP_NEGOTIATE_NTLM |
|
||||
/* NTLMSSP_NEGOTIATE_NTLM2 | */
|
||||
NTLMSSP_NEGOTIATE_NTLM2 |
|
||||
NTLMSSP_NEGOTIATE_KEY_EXCH;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
@ -971,7 +971,7 @@ static NTSTATUS ntlmssp_client_initial(struct ntlmssp_state *ntlmssp_state,
|
||||
}
|
||||
|
||||
if (ntlmssp_state->use_ntlmv2) {
|
||||
/* ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2;*/
|
||||
ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2;
|
||||
}
|
||||
|
||||
/* generate the ntlmssp negotiate packet */
|
||||
@ -1293,7 +1293,7 @@ NTSTATUS ntlmssp_client_start(struct ntlmssp_state **ntlmssp_state)
|
||||
(*ntlmssp_state)->neg_flags =
|
||||
NTLMSSP_NEGOTIATE_128 |
|
||||
NTLMSSP_NEGOTIATE_NTLM |
|
||||
/* NTLMSSP_NEGOTIATE_NTLM2 |*/
|
||||
NTLMSSP_NEGOTIATE_NTLM2 |
|
||||
NTLMSSP_NEGOTIATE_KEY_EXCH |
|
||||
NTLMSSP_REQUEST_TARGET;
|
||||
|
||||
|
@ -71,6 +71,8 @@ enum ntlmssp_message_type
|
||||
|
||||
#define NTLMSSP_SIGN_VERSION 1
|
||||
|
||||
#define NTLMSSP_SIG_SIZE 16
|
||||
|
||||
struct ntlmssp_state
|
||||
{
|
||||
TALLOC_CTX *mem_ctx;
|
||||
@ -162,8 +164,9 @@ struct ntlmssp_state
|
||||
const char *(*get_domain)(void);
|
||||
|
||||
/* SMB Signing */
|
||||
|
||||
uint32_t ntlmssp_seq_num;
|
||||
uint32_t ntlm_seq_num;
|
||||
uint32_t ntlm2_send_seq_num;
|
||||
uint32_t ntlm2_recv_seq_num;
|
||||
|
||||
/* ntlmv2 */
|
||||
DATA_BLOB send_sign_key;
|
||||
|
@ -64,31 +64,40 @@ enum ntlmssp_direction {
|
||||
static NTSTATUS ntlmssp_make_packet_signature(struct ntlmssp_state *ntlmssp_state,
|
||||
TALLOC_CTX *sig_mem_ctx,
|
||||
const uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
enum ntlmssp_direction direction,
|
||||
DATA_BLOB *sig)
|
||||
DATA_BLOB *sig, BOOL encrypt_sig)
|
||||
{
|
||||
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
|
||||
|
||||
HMACMD5Context ctx;
|
||||
uint8_t digest[16];
|
||||
uint8_t seq_num[4];
|
||||
SIVAL(seq_num, 0, ntlmssp_state->ntlmssp_seq_num);
|
||||
|
||||
*sig = data_blob_talloc(sig_mem_ctx, NULL, NTLMSSP_SIG_SIZE);
|
||||
if (!sig->data) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
switch (direction) {
|
||||
case NTLMSSP_SEND:
|
||||
SIVAL(seq_num, 0, ntlmssp_state->ntlm2_send_seq_num);
|
||||
ntlmssp_state->ntlm2_send_seq_num++;
|
||||
hmac_md5_init_limK_to_64(ntlmssp_state->send_sign_key.data,
|
||||
ntlmssp_state->send_sign_key.length, &ctx);
|
||||
break;
|
||||
case NTLMSSP_RECEIVE:
|
||||
SIVAL(seq_num, 0, ntlmssp_state->ntlm2_recv_seq_num);
|
||||
ntlmssp_state->ntlm2_recv_seq_num++;
|
||||
hmac_md5_init_limK_to_64(ntlmssp_state->recv_sign_key.data,
|
||||
ntlmssp_state->recv_sign_key.length, &ctx);
|
||||
break;
|
||||
}
|
||||
hmac_md5_update(seq_num, sizeof(seq_num), &ctx);
|
||||
hmac_md5_update(data, length, &ctx);
|
||||
hmac_md5_update(whole_pdu, pdu_length, &ctx);
|
||||
hmac_md5_final(digest, &ctx);
|
||||
|
||||
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
|
||||
if (encrypt_sig && ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
|
||||
switch (direction) {
|
||||
case NTLMSSP_SEND:
|
||||
arcfour_crypt_sbox(ntlmssp_state->send_seal_hash, digest, 8);
|
||||
@ -98,7 +107,7 @@ static NTSTATUS ntlmssp_make_packet_signature(struct ntlmssp_state *ntlmssp_stat
|
||||
break;
|
||||
}
|
||||
}
|
||||
*sig = data_blob_talloc(sig_mem_ctx, NULL, 16);
|
||||
|
||||
SIVAL(sig->data, 0, NTLMSSP_SIGN_VERSION);
|
||||
memcpy(sig->data + 4, digest, 8);
|
||||
memcpy(sig->data + 12, seq_num, 4);
|
||||
@ -106,11 +115,14 @@ static NTSTATUS ntlmssp_make_packet_signature(struct ntlmssp_state *ntlmssp_stat
|
||||
} else {
|
||||
uint32_t crc;
|
||||
crc = crc32_calc_buffer((const char *)data, length);
|
||||
if (!msrpc_gen(sig_mem_ctx, sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
|
||||
if (!msrpc_gen(sig_mem_ctx, sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlm_seq_num)) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
arcfour_crypt_sbox(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4);
|
||||
ntlmssp_state->ntlm_seq_num++;
|
||||
|
||||
if (encrypt_sig) {
|
||||
arcfour_crypt_sbox(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4);
|
||||
}
|
||||
}
|
||||
dump_data_pw("calculated ntlmssp signature\n", sig->data, sig->length);
|
||||
return NT_STATUS_OK;
|
||||
@ -119,26 +131,23 @@ static NTSTATUS ntlmssp_make_packet_signature(struct ntlmssp_state *ntlmssp_stat
|
||||
NTSTATUS ntlmssp_sign_packet(struct ntlmssp_state *ntlmssp_state,
|
||||
TALLOC_CTX *sig_mem_ctx,
|
||||
const uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
DATA_BLOB *sig)
|
||||
{
|
||||
NTSTATUS nt_status;
|
||||
|
||||
if (!ntlmssp_state->session_key.length) {
|
||||
DEBUG(3, ("NO session key, cannot check sign packet\n"));
|
||||
return NT_STATUS_NO_USER_SESSION_KEY;
|
||||
}
|
||||
|
||||
|
||||
if (!ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN) {
|
||||
DEBUG(3, ("NTLMSSP Signing not negotiated - cannot sign packet!\n"));
|
||||
return NT_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
nt_status = ntlmssp_make_packet_signature(ntlmssp_state, sig_mem_ctx,
|
||||
data, length, NTLMSSP_SEND, sig);
|
||||
|
||||
/* increment counter on send */
|
||||
ntlmssp_state->ntlmssp_seq_num++;
|
||||
return nt_status;
|
||||
|
||||
return ntlmssp_make_packet_signature(ntlmssp_state, sig_mem_ctx,
|
||||
data, length,
|
||||
whole_pdu, pdu_length,
|
||||
NTLMSSP_SEND, sig, True);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -149,6 +158,7 @@ NTSTATUS ntlmssp_sign_packet(struct ntlmssp_state *ntlmssp_state,
|
||||
NTSTATUS ntlmssp_check_packet(struct ntlmssp_state *ntlmssp_state,
|
||||
TALLOC_CTX *sig_mem_ctx,
|
||||
const uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
const DATA_BLOB *sig)
|
||||
{
|
||||
DATA_BLOB local_sig;
|
||||
@ -164,17 +174,16 @@ NTSTATUS ntlmssp_check_packet(struct ntlmssp_state *ntlmssp_state,
|
||||
(unsigned long)sig->length));
|
||||
}
|
||||
|
||||
nt_status = ntlmssp_make_packet_signature(ntlmssp_state, sig_mem_ctx, data,
|
||||
length, NTLMSSP_RECEIVE, &local_sig);
|
||||
nt_status = ntlmssp_make_packet_signature(ntlmssp_state, sig_mem_ctx,
|
||||
data, length,
|
||||
whole_pdu, pdu_length,
|
||||
NTLMSSP_RECEIVE, &local_sig, True);
|
||||
|
||||
if (!NT_STATUS_IS_OK(nt_status)) {
|
||||
DEBUG(0, ("NTLMSSP packet check failed with %s\n", nt_errstr(nt_status)));
|
||||
return nt_status;
|
||||
}
|
||||
|
||||
/* increment counter on recv */
|
||||
ntlmssp_state->ntlmssp_seq_num++;
|
||||
|
||||
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
|
||||
if (local_sig.length != sig->length ||
|
||||
memcmp(local_sig.data,
|
||||
@ -216,8 +225,10 @@ NTSTATUS ntlmssp_check_packet(struct ntlmssp_state *ntlmssp_state,
|
||||
NTSTATUS ntlmssp_seal_packet(struct ntlmssp_state *ntlmssp_state,
|
||||
TALLOC_CTX *sig_mem_ctx,
|
||||
uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
DATA_BLOB *sig)
|
||||
{
|
||||
NTSTATUS nt_status;
|
||||
if (!ntlmssp_state->session_key.length) {
|
||||
DEBUG(3, ("NO session key, cannot seal packet\n"));
|
||||
return NT_STATUS_NO_USER_SESSION_KEY;
|
||||
@ -231,35 +242,20 @@ NTSTATUS ntlmssp_seal_packet(struct ntlmssp_state *ntlmssp_state,
|
||||
DEBUG(10,("ntlmssp_seal_data: seal\n"));
|
||||
dump_data_pw("ntlmssp clear data\n", data, length);
|
||||
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
|
||||
HMACMD5Context ctx;
|
||||
uint8_t seq_num[4];
|
||||
uint8_t digest[16];
|
||||
SIVAL(seq_num, 0, ntlmssp_state->ntlmssp_seq_num);
|
||||
|
||||
hmac_md5_init_limK_to_64(ntlmssp_state->send_sign_key.data,
|
||||
ntlmssp_state->send_sign_key.length, &ctx);
|
||||
hmac_md5_update(seq_num, 4, &ctx);
|
||||
hmac_md5_update(data, length, &ctx);
|
||||
hmac_md5_final(digest, &ctx);
|
||||
|
||||
/* The order of these two operations matters - we must first seal the packet,
|
||||
then seal the sequence number - this is becouse the send_seal_hash is not
|
||||
constant, but is is rather updated with each iteration */
|
||||
|
||||
arcfour_crypt_sbox(ntlmssp_state->send_seal_hash, data, length);
|
||||
|
||||
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
|
||||
arcfour_crypt_sbox(ntlmssp_state->send_seal_hash, digest, 8);
|
||||
}
|
||||
|
||||
*sig = data_blob_talloc(sig_mem_ctx, NULL, 16);
|
||||
SIVAL(sig->data, 0, NTLMSSP_SIGN_VERSION);
|
||||
memcpy(sig->data + 4, digest, 8);
|
||||
memcpy(sig->data + 12, seq_num, 4);
|
||||
nt_status = ntlmssp_make_packet_signature(ntlmssp_state, sig_mem_ctx,
|
||||
data, length,
|
||||
whole_pdu, pdu_length,
|
||||
NTLMSSP_SEND, sig, True);
|
||||
} else {
|
||||
uint32_t crc;
|
||||
crc = crc32_calc_buffer((const char *)data, length);
|
||||
if (!msrpc_gen(sig_mem_ctx, sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
|
||||
if (!msrpc_gen(sig_mem_ctx, sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlm_seq_num)) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
@ -270,14 +266,15 @@ NTSTATUS ntlmssp_seal_packet(struct ntlmssp_state *ntlmssp_state,
|
||||
arcfour_crypt_sbox(ntlmssp_state->ntlmssp_hash, data, length);
|
||||
|
||||
arcfour_crypt_sbox(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4);
|
||||
/* increment counter on send */
|
||||
ntlmssp_state->ntlm_seq_num++;
|
||||
nt_status = NT_STATUS_OK;
|
||||
}
|
||||
dump_data_pw("ntlmssp signature\n", sig->data, sig->length);
|
||||
dump_data_pw("ntlmssp sealed data\n", data, length);
|
||||
|
||||
/* increment counter on send */
|
||||
ntlmssp_state->ntlmssp_seq_num++;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
return nt_status;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -288,8 +285,11 @@ NTSTATUS ntlmssp_seal_packet(struct ntlmssp_state *ntlmssp_state,
|
||||
NTSTATUS ntlmssp_unseal_packet(struct ntlmssp_state *ntlmssp_state,
|
||||
TALLOC_CTX *sig_mem_ctx,
|
||||
uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
DATA_BLOB *sig)
|
||||
{
|
||||
DATA_BLOB local_sig;
|
||||
NTSTATUS nt_status;
|
||||
if (!ntlmssp_state->session_key.length) {
|
||||
DEBUG(3, ("NO session key, cannot unseal packet\n"));
|
||||
return NT_STATUS_NO_USER_SESSION_KEY;
|
||||
@ -297,13 +297,46 @@ NTSTATUS ntlmssp_unseal_packet(struct ntlmssp_state *ntlmssp_state,
|
||||
|
||||
dump_data_pw("ntlmssp sealed data\n", data, length);
|
||||
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
|
||||
|
||||
/* We have to pass the data past the arcfour pad in
|
||||
* the correct order, so we must encrypt the signature
|
||||
* after we decrypt the main body. however, the
|
||||
* signature is calculated over the encrypted data */
|
||||
|
||||
nt_status = ntlmssp_make_packet_signature(ntlmssp_state, sig_mem_ctx,
|
||||
data, length,
|
||||
whole_pdu, pdu_length,
|
||||
NTLMSSP_RECEIVE, &local_sig, False);
|
||||
if (!NT_STATUS_IS_OK(nt_status)) {
|
||||
return nt_status;
|
||||
}
|
||||
|
||||
arcfour_crypt_sbox(ntlmssp_state->recv_seal_hash, data, length);
|
||||
|
||||
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
|
||||
arcfour_crypt_sbox(ntlmssp_state->send_seal_hash, local_sig.data + 4, 8);
|
||||
}
|
||||
|
||||
if (local_sig.length != sig->length ||
|
||||
memcmp(local_sig.data,
|
||||
sig->data, sig->length) != 0) {
|
||||
DEBUG(5, ("BAD SIG NTLM2: wanted signature of\n"));
|
||||
dump_data(5, local_sig.data, local_sig.length);
|
||||
|
||||
DEBUG(5, ("BAD SIG: got signature of\n"));
|
||||
dump_data(5, sig->data, sig->length);
|
||||
|
||||
DEBUG(0, ("NTLMSSP NTLM2 packet check failed due to invalid signature!\n"));
|
||||
return NT_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
dump_data_pw("ntlmssp clear data\n", data, length);
|
||||
return NT_STATUS_OK;
|
||||
} else {
|
||||
arcfour_crypt_sbox(ntlmssp_state->ntlmssp_hash, data, length);
|
||||
dump_data_pw("ntlmssp clear data\n", data, length);
|
||||
return ntlmssp_check_packet(ntlmssp_state, sig_mem_ctx, data, length, whole_pdu, pdu_length, sig);
|
||||
}
|
||||
dump_data_pw("ntlmssp clear data\n", data, length);
|
||||
|
||||
return ntlmssp_check_packet(ntlmssp_state, sig_mem_ctx, data, length, sig);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -414,7 +447,9 @@ NTSTATUS ntlmssp_sign_init(struct ntlmssp_state *ntlmssp_state)
|
||||
sizeof(ntlmssp_state->ntlmssp_hash));
|
||||
}
|
||||
|
||||
ntlmssp_state->ntlmssp_seq_num = 0;
|
||||
ntlmssp_state->ntlm_seq_num = 0;
|
||||
ntlmssp_state->ntlm2_send_seq_num = 0;
|
||||
ntlmssp_state->ntlm2_recv_seq_num = 0;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
@ -92,8 +92,10 @@ static NTSTATUS gensec_spnego_server_start(struct gensec_security *gensec_securi
|
||||
wrappers for the spnego_*() functions
|
||||
*/
|
||||
static NTSTATUS gensec_spnego_unseal_packet(struct gensec_security *gensec_security,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
uint8_t *data, size_t length, DATA_BLOB *sig)
|
||||
TALLOC_CTX *mem_ctx,
|
||||
uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
DATA_BLOB *sig)
|
||||
{
|
||||
struct spnego_state *spnego_state = gensec_security->private_data;
|
||||
|
||||
@ -103,13 +105,17 @@ static NTSTATUS gensec_spnego_unseal_packet(struct gensec_security *gensec_secur
|
||||
}
|
||||
|
||||
return gensec_unseal_packet(spnego_state->sub_sec_security,
|
||||
mem_ctx, data, length, sig);
|
||||
mem_ctx,
|
||||
data, length,
|
||||
whole_pdu, pdu_length,
|
||||
sig);
|
||||
}
|
||||
|
||||
static NTSTATUS gensec_spnego_check_packet(struct gensec_security *gensec_security,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const uint8_t *data, size_t length,
|
||||
const DATA_BLOB *sig)
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
const DATA_BLOB *sig)
|
||||
{
|
||||
struct spnego_state *spnego_state = gensec_security->private_data;
|
||||
|
||||
@ -120,13 +126,17 @@ static NTSTATUS gensec_spnego_check_packet(struct gensec_security *gensec_securi
|
||||
}
|
||||
|
||||
return gensec_check_packet(spnego_state->sub_sec_security,
|
||||
mem_ctx, data, length, sig);
|
||||
mem_ctx,
|
||||
data, length,
|
||||
whole_pdu, pdu_length,
|
||||
sig);
|
||||
}
|
||||
|
||||
static NTSTATUS gensec_spnego_seal_packet(struct gensec_security *gensec_security,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
uint8_t *data, size_t length,
|
||||
DATA_BLOB *sig)
|
||||
TALLOC_CTX *mem_ctx,
|
||||
uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
DATA_BLOB *sig)
|
||||
{
|
||||
struct spnego_state *spnego_state = gensec_security->private_data;
|
||||
|
||||
@ -137,13 +147,17 @@ static NTSTATUS gensec_spnego_seal_packet(struct gensec_security *gensec_securit
|
||||
}
|
||||
|
||||
return gensec_seal_packet(spnego_state->sub_sec_security,
|
||||
mem_ctx, data, length, sig);
|
||||
mem_ctx,
|
||||
data, length,
|
||||
whole_pdu, pdu_length,
|
||||
sig);
|
||||
}
|
||||
|
||||
static NTSTATUS gensec_spnego_sign_packet(struct gensec_security *gensec_security,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const uint8_t *data, size_t length,
|
||||
DATA_BLOB *sig)
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
DATA_BLOB *sig)
|
||||
{
|
||||
struct spnego_state *spnego_state = gensec_security->private_data;
|
||||
|
||||
@ -153,11 +167,26 @@ static NTSTATUS gensec_spnego_sign_packet(struct gensec_security *gensec_securit
|
||||
}
|
||||
|
||||
return gensec_sign_packet(spnego_state->sub_sec_security,
|
||||
mem_ctx, data, length, sig);
|
||||
mem_ctx,
|
||||
data, length,
|
||||
whole_pdu, pdu_length,
|
||||
sig);
|
||||
}
|
||||
|
||||
static size_t gensec_spnego_sig_size(struct gensec_security *gensec_security)
|
||||
{
|
||||
struct spnego_state *spnego_state = gensec_security->private_data;
|
||||
|
||||
if (spnego_state->state_position != SPNEGO_DONE
|
||||
&& spnego_state->state_position != SPNEGO_FALLBACK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return gensec_sig_size(spnego_state->sub_sec_security);
|
||||
}
|
||||
|
||||
static NTSTATUS gensec_spnego_session_key(struct gensec_security *gensec_security,
|
||||
DATA_BLOB *session_key)
|
||||
DATA_BLOB *session_key)
|
||||
{
|
||||
struct spnego_state *spnego_state = gensec_security->private_data;
|
||||
if (!spnego_state->sub_sec_security) {
|
||||
@ -684,6 +713,7 @@ static const struct gensec_security_ops gensec_spnego_security_ops = {
|
||||
.update = gensec_spnego_update,
|
||||
.seal_packet = gensec_spnego_seal_packet,
|
||||
.sign_packet = gensec_spnego_sign_packet,
|
||||
.sig_size = gensec_spnego_sig_size,
|
||||
.check_packet = gensec_spnego_check_packet,
|
||||
.unseal_packet = gensec_spnego_unseal_packet,
|
||||
.session_key = gensec_spnego_session_key,
|
||||
|
@ -36,6 +36,7 @@ struct dcerpc_pipe *dcerpc_pipe_init(void)
|
||||
p->reference_count = 0;
|
||||
p->call_id = 1;
|
||||
p->security_state.auth_info = NULL;
|
||||
p->security_state.session_key = dcerpc_generic_session_key;
|
||||
p->security_state.generic_state = NULL;
|
||||
p->binding_string = NULL;
|
||||
p->flags = 0;
|
||||
@ -206,8 +207,8 @@ static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p,
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* check signature or unseal the packet */
|
||||
switch (p->security_state.auth_info->auth_level) {
|
||||
case DCERPC_AUTH_LEVEL_PRIVACY:
|
||||
@ -215,6 +216,8 @@ static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p,
|
||||
mem_ctx,
|
||||
pkt->u.response.stub_and_verifier.data,
|
||||
pkt->u.response.stub_and_verifier.length,
|
||||
blob->data,
|
||||
blob->length - auth.credentials.length,
|
||||
&auth.credentials);
|
||||
break;
|
||||
|
||||
@ -223,9 +226,11 @@ static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p,
|
||||
mem_ctx,
|
||||
pkt->u.response.stub_and_verifier.data,
|
||||
pkt->u.response.stub_and_verifier.length,
|
||||
blob->data,
|
||||
blob->length - auth.credentials.length,
|
||||
&auth.credentials);
|
||||
break;
|
||||
|
||||
|
||||
case DCERPC_AUTH_LEVEL_NONE:
|
||||
break;
|
||||
|
||||
@ -233,7 +238,7 @@ static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p,
|
||||
status = NT_STATUS_INVALID_LEVEL;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* remove the indicated amount of paddiing */
|
||||
if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
|
||||
return NT_STATUS_INFO_LENGTH_MISMATCH;
|
||||
@ -253,6 +258,7 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p,
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct ndr_push *ndr;
|
||||
DATA_BLOB creds2;
|
||||
|
||||
/* non-signed packets are simpler */
|
||||
if (!p->security_state.auth_info || !p->security_state.generic_state) {
|
||||
@ -282,30 +288,21 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p,
|
||||
/* sign or seal the packet */
|
||||
switch (p->security_state.auth_info->auth_level) {
|
||||
case DCERPC_AUTH_LEVEL_PRIVACY:
|
||||
status = gensec_seal_packet(p->security_state.generic_state,
|
||||
mem_ctx,
|
||||
ndr->data + DCERPC_REQUEST_LENGTH,
|
||||
ndr->offset - DCERPC_REQUEST_LENGTH,
|
||||
&p->security_state.auth_info->credentials);
|
||||
break;
|
||||
|
||||
case DCERPC_AUTH_LEVEL_INTEGRITY:
|
||||
status = gensec_sign_packet(p->security_state.generic_state,
|
||||
mem_ctx,
|
||||
ndr->data + DCERPC_REQUEST_LENGTH,
|
||||
ndr->offset - DCERPC_REQUEST_LENGTH,
|
||||
&p->security_state.auth_info->credentials);
|
||||
p->security_state.auth_info->credentials
|
||||
= data_blob_talloc(mem_ctx, NULL, gensec_sig_size(p->security_state.generic_state));
|
||||
data_blob_clear(&p->security_state.auth_info->credentials);
|
||||
break;
|
||||
|
||||
case DCERPC_AUTH_LEVEL_NONE:
|
||||
p->security_state.auth_info->credentials = data_blob(NULL, 0);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
status = NT_STATUS_INVALID_LEVEL;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
@ -325,6 +322,41 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p,
|
||||
dcerpc_set_frag_length(blob, blob->length);
|
||||
dcerpc_set_auth_length(blob, p->security_state.auth_info->credentials.length);
|
||||
|
||||
/* sign or seal the packet */
|
||||
switch (p->security_state.auth_info->auth_level) {
|
||||
case DCERPC_AUTH_LEVEL_PRIVACY:
|
||||
status = gensec_seal_packet(p->security_state.generic_state,
|
||||
mem_ctx,
|
||||
ndr->data + DCERPC_REQUEST_LENGTH,
|
||||
ndr->offset - DCERPC_REQUEST_LENGTH,
|
||||
blob->data,
|
||||
blob->length -
|
||||
p->security_state.auth_info->credentials.length,
|
||||
&creds2);
|
||||
memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
|
||||
break;
|
||||
|
||||
case DCERPC_AUTH_LEVEL_INTEGRITY:
|
||||
status = gensec_sign_packet(p->security_state.generic_state,
|
||||
mem_ctx,
|
||||
ndr->data + DCERPC_REQUEST_LENGTH,
|
||||
ndr->offset - DCERPC_REQUEST_LENGTH,
|
||||
blob->data,
|
||||
blob->length -
|
||||
p->security_state.auth_info->credentials.length,
|
||||
&creds2);
|
||||
memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
|
||||
break;
|
||||
|
||||
case DCERPC_AUTH_LEVEL_NONE:
|
||||
p->security_state.auth_info->credentials = data_blob(NULL, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
status = NT_STATUS_INVALID_LEVEL;
|
||||
break;
|
||||
}
|
||||
|
||||
data_blob_free(&p->security_state.auth_info->credentials);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
@ -433,8 +465,8 @@ NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
|
||||
pkt.call_id = p->call_id;
|
||||
pkt.auth_length = 0;
|
||||
|
||||
pkt.u.bind.max_xmit_frag = 0x2000;
|
||||
pkt.u.bind.max_recv_frag = 0x2000;
|
||||
pkt.u.bind.max_xmit_frag = 5840;
|
||||
pkt.u.bind.max_recv_frag = 5840;
|
||||
pkt.u.bind.assoc_group_id = 0;
|
||||
pkt.u.bind.num_contexts = 1;
|
||||
pkt.u.bind.ctx_list = talloc(mem_ctx, sizeof(pkt.u.bind.ctx_list[0]));
|
||||
@ -782,60 +814,44 @@ struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
|
||||
pkt.u.request.context_id = 0;
|
||||
pkt.u.request.opnum = opnum;
|
||||
|
||||
/* we send a series of pdus without waiting for a reply until
|
||||
the last pdu */
|
||||
while (remaining > chunk_size) {
|
||||
DLIST_ADD(p->pending, req);
|
||||
|
||||
/* we send a series of pdus without waiting for a reply */
|
||||
while (remaining > 0) {
|
||||
uint32_t chunk = MIN(chunk_size, remaining);
|
||||
BOOL last_frag = False;
|
||||
|
||||
pkt.pfc_flags = 0;
|
||||
|
||||
if (remaining == stub_data->length) {
|
||||
pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST;
|
||||
} else {
|
||||
pkt.pfc_flags = 0;
|
||||
pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
|
||||
}
|
||||
if (chunk == remaining) {
|
||||
pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
|
||||
last_frag = True;
|
||||
}
|
||||
|
||||
pkt.u.request.stub_and_verifier.data = stub_data->data +
|
||||
(stub_data->length - remaining);
|
||||
pkt.u.request.stub_and_verifier.length = chunk_size;
|
||||
pkt.u.request.stub_and_verifier.length = chunk;
|
||||
|
||||
req->status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt);
|
||||
if (!NT_STATUS_IS_OK(req->status)) {
|
||||
req->state = RPC_REQUEST_DONE;
|
||||
DLIST_REMOVE(p->pending, req);
|
||||
return req;
|
||||
}
|
||||
|
||||
req->status = p->transport.send_request(p, &blob, False);
|
||||
req->status = p->transport.send_request(p, &blob, last_frag);
|
||||
if (!NT_STATUS_IS_OK(req->status)) {
|
||||
req->state = RPC_REQUEST_DONE;
|
||||
DLIST_REMOVE(p->pending, req);
|
||||
return req;
|
||||
}
|
||||
|
||||
remaining -= chunk_size;
|
||||
remaining -= chunk;
|
||||
}
|
||||
|
||||
/* now we send a pdu with LAST_FRAG sent and get the first
|
||||
part of the reply */
|
||||
if (remaining == stub_data->length) {
|
||||
pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
|
||||
} else {
|
||||
pkt.pfc_flags = DCERPC_PFC_FLAG_LAST;
|
||||
}
|
||||
pkt.u.request.stub_and_verifier.data = stub_data->data +
|
||||
(stub_data->length - remaining);
|
||||
pkt.u.request.stub_and_verifier.length = remaining;
|
||||
|
||||
req->status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt);
|
||||
if (!NT_STATUS_IS_OK(req->status)) {
|
||||
req->state = RPC_REQUEST_DONE;
|
||||
return req;
|
||||
}
|
||||
|
||||
/* send the final pdu */
|
||||
req->status = p->transport.send_request(p, &blob, True);
|
||||
|
||||
if (!NT_STATUS_IS_OK(req->status)) {
|
||||
req->state = RPC_REQUEST_DONE;
|
||||
}
|
||||
|
||||
DLIST_ADD(p->pending, req);
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,9 @@ struct dcerpc_pipe;
|
||||
struct dcerpc_security {
|
||||
struct dcerpc_auth *auth_info;
|
||||
struct gensec_security *generic_state;
|
||||
|
||||
/* get the session key */
|
||||
NTSTATUS (*session_key)(struct dcerpc_pipe *, DATA_BLOB *);
|
||||
};
|
||||
|
||||
struct dcerpc_pipe {
|
||||
@ -64,8 +67,6 @@ struct dcerpc_pipe {
|
||||
has been received */
|
||||
void (*recv_data)(struct dcerpc_pipe *, DATA_BLOB *, NTSTATUS status);
|
||||
|
||||
/* get the transport level session key */
|
||||
NTSTATUS (*session_key)(struct dcerpc_pipe *, DATA_BLOB *);
|
||||
} transport;
|
||||
|
||||
/* the last fault code from a DCERPC fault */
|
||||
|
@ -107,13 +107,16 @@ NTSTATUS dcerpc_bind_auth3(struct dcerpc_pipe *p, uint8_t auth_type, uint8_t aut
|
||||
}
|
||||
|
||||
p->security_state.auth_info->credentials = credentials;
|
||||
|
||||
|
||||
status = dcerpc_auth3(p, mem_ctx);
|
||||
done:
|
||||
talloc_destroy(mem_ctx);
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
ZERO_STRUCT(p->security_state);
|
||||
} else {
|
||||
/* Authenticated connections use the generic session key */
|
||||
p->security_state.session_key = dcerpc_generic_session_key;
|
||||
}
|
||||
|
||||
return status;
|
||||
@ -196,6 +199,9 @@ done:
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
ZERO_STRUCT(p->security_state);
|
||||
} else {
|
||||
/* Authenticated connections use the generic session key */
|
||||
p->security_state.session_key = dcerpc_generic_session_key;
|
||||
}
|
||||
|
||||
return status;
|
||||
|
@ -50,7 +50,9 @@ static NTSTATUS dcerpc_schannel_key(struct dcerpc_pipe *p,
|
||||
*/
|
||||
static NTSTATUS dcerpc_schannel_unseal_packet(struct gensec_security *gensec_security,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
uint8_t *data, size_t length, DATA_BLOB *sig)
|
||||
uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
DATA_BLOB *sig)
|
||||
{
|
||||
struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data;
|
||||
|
||||
@ -60,6 +62,7 @@ static NTSTATUS dcerpc_schannel_unseal_packet(struct gensec_security *gensec_sec
|
||||
static NTSTATUS dcerpc_schannel_check_packet(struct gensec_security *gensec_security,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
const DATA_BLOB *sig)
|
||||
{
|
||||
struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data;
|
||||
@ -70,6 +73,7 @@ static NTSTATUS dcerpc_schannel_check_packet(struct gensec_security *gensec_secu
|
||||
static NTSTATUS dcerpc_schannel_seal_packet(struct gensec_security *gensec_security,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
DATA_BLOB *sig)
|
||||
{
|
||||
struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data;
|
||||
@ -80,6 +84,7 @@ static NTSTATUS dcerpc_schannel_seal_packet(struct gensec_security *gensec_secur
|
||||
static NTSTATUS dcerpc_schannel_sign_packet(struct gensec_security *gensec_security,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
DATA_BLOB *sig)
|
||||
{
|
||||
struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data;
|
||||
|
@ -359,7 +359,6 @@ NTSTATUS smb_session_key(struct dcerpc_pipe *p, DATA_BLOB *session_key)
|
||||
*session_key = smb->tree->session->user_session_key;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
return NT_STATUS_NO_USER_SESSION_KEY;
|
||||
}
|
||||
|
||||
@ -425,13 +424,15 @@ NTSTATUS dcerpc_pipe_open_smb(struct dcerpc_pipe **p,
|
||||
(*p)->transport.private = NULL;
|
||||
(*p)->transport.shutdown_pipe = smb_shutdown_pipe;
|
||||
(*p)->transport.peer_name = smb_peer_name;
|
||||
(*p)->transport.session_key = smb_session_key;
|
||||
|
||||
(*p)->transport.send_request = smb_send_request;
|
||||
(*p)->transport.send_read = send_read_request;
|
||||
(*p)->transport.event_context = smb_event_context;
|
||||
(*p)->transport.recv_data = NULL;
|
||||
|
||||
/* Over-ride the default session key with the SMB session key */
|
||||
(*p)->security_state.session_key = smb_session_key;
|
||||
|
||||
smb = talloc((*p), sizeof(*smb));
|
||||
if (!smb) {
|
||||
dcerpc_pipe_close(*p);
|
||||
|
@ -87,6 +87,10 @@ static void tcp_process_send(struct dcerpc_pipe *p)
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (ret == 0) {
|
||||
tcp_sock_dead(p, NT_STATUS_NET_WRITE_FAULT);
|
||||
break;
|
||||
}
|
||||
|
||||
blob->data.data += ret;
|
||||
blob->data.length -= ret;
|
||||
@ -271,19 +275,6 @@ static const char *tcp_peer_name(struct dcerpc_pipe *p)
|
||||
return tcp->server_name;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
fetch the user session key
|
||||
*/
|
||||
NTSTATUS tcp_session_key(struct dcerpc_pipe *p, DATA_BLOB *session_key)
|
||||
{
|
||||
/* this took quite a few CPU cycles to find ... */
|
||||
session_key->data = "SystemLibraryDTC";
|
||||
session_key->length = 16;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
open a rpc connection to a named pipe
|
||||
*/
|
||||
@ -331,7 +322,6 @@ NTSTATUS dcerpc_pipe_open_tcp(struct dcerpc_pipe **p,
|
||||
|
||||
(*p)->transport.shutdown_pipe = tcp_shutdown_pipe;
|
||||
(*p)->transport.peer_name = tcp_peer_name;
|
||||
(*p)->transport.session_key = tcp_session_key;
|
||||
|
||||
tcp = talloc((*p), sizeof(*tcp));
|
||||
if (!tcp) {
|
||||
@ -356,5 +346,8 @@ NTSTATUS dcerpc_pipe_open_tcp(struct dcerpc_pipe **p,
|
||||
|
||||
(*p)->transport.private = tcp;
|
||||
|
||||
/* ensure we don't get SIGPIPE */
|
||||
BlockSignals(True,SIGPIPE);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
@ -458,8 +458,7 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_np(struct dcerpc_pipe **p,
|
||||
pipe_name += 6;
|
||||
}
|
||||
|
||||
if ((binding->flags & (DCERPC_SCHANNEL_ANY | DCERPC_SIGN | DCERPC_SEAL))
|
||||
|| !username || !username[0]) {
|
||||
if (!username || !username[0]) {
|
||||
status = smbcli_full_connection(&cli, lp_netbios_name(),
|
||||
binding->host, NULL,
|
||||
"ipc$", "?????",
|
||||
@ -500,6 +499,7 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_np(struct dcerpc_pipe **p,
|
||||
status = dcerpc_bind_auth_ntlm(*p, pipe_uuid, pipe_version, domain, username, password);
|
||||
} else {
|
||||
status = dcerpc_bind_auth_none(*p, pipe_uuid, pipe_version);
|
||||
|
||||
}
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
@ -691,15 +691,22 @@ NTSTATUS dcerpc_secondary_connection(struct dcerpc_pipe *p, struct dcerpc_pipe *
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
NTSTATUS dcerpc_generic_session_key(struct dcerpc_pipe *p,
|
||||
DATA_BLOB *session_key)
|
||||
{
|
||||
/* this took quite a few CPU cycles to find ... */
|
||||
session_key->data = "SystemLibraryDTC";
|
||||
session_key->length = 16;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
fetch the user session key for the underlying transport. Currently
|
||||
only works for the ncacn_np transport
|
||||
fetch the user session key - may be default (above) or the SMB session key
|
||||
*/
|
||||
NTSTATUS dcerpc_fetch_session_key(struct dcerpc_pipe *p,
|
||||
DATA_BLOB *session_key)
|
||||
{
|
||||
return p->transport.session_key(p, session_key);
|
||||
return p->security_state.session_key(p, session_key);
|
||||
}
|
||||
|
||||
|
||||
|
@ -186,11 +186,10 @@ BOOL dcesrv_auth_auth3(struct dcesrv_call_state *call)
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
check credentials on a request
|
||||
*/
|
||||
BOOL dcesrv_auth_request(struct dcesrv_call_state *call)
|
||||
BOOL dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet)
|
||||
{
|
||||
struct dcerpc_packet *pkt = &call->pkt;
|
||||
struct dcesrv_connection *dce_conn = call->conn;
|
||||
@ -238,6 +237,8 @@ BOOL dcesrv_auth_request(struct dcesrv_call_state *call)
|
||||
call->mem_ctx,
|
||||
pkt->u.request.stub_and_verifier.data,
|
||||
pkt->u.request.stub_and_verifier.length,
|
||||
full_packet->data,
|
||||
full_packet->length-auth.credentials.length,
|
||||
&auth.credentials);
|
||||
break;
|
||||
|
||||
@ -246,6 +247,8 @@ BOOL dcesrv_auth_request(struct dcesrv_call_state *call)
|
||||
call->mem_ctx,
|
||||
pkt->u.request.stub_and_verifier.data,
|
||||
pkt->u.request.stub_and_verifier.length,
|
||||
full_packet->data,
|
||||
full_packet->length-auth.credentials.length,
|
||||
&auth.credentials);
|
||||
break;
|
||||
|
||||
@ -254,7 +257,7 @@ BOOL dcesrv_auth_request(struct dcesrv_call_state *call)
|
||||
break;
|
||||
}
|
||||
|
||||
/* remove the indicated amount of paddiing */
|
||||
/* remove the indicated amount of padding */
|
||||
if (pkt->u.request.stub_and_verifier.length < auth.auth_pad_length) {
|
||||
return False;
|
||||
}
|
||||
@ -298,31 +301,10 @@ BOOL dcesrv_auth_response(struct dcesrv_call_state *call,
|
||||
dce_conn->auth_state.auth_info->auth_pad_length = NDR_ALIGN(ndr, 8);
|
||||
ndr_push_zero(ndr, dce_conn->auth_state.auth_info->auth_pad_length);
|
||||
|
||||
/* sign or seal the packet */
|
||||
switch (dce_conn->auth_state.auth_info->auth_level) {
|
||||
case DCERPC_AUTH_LEVEL_PRIVACY:
|
||||
status = gensec_seal_packet(dce_conn->auth_state.gensec_security,
|
||||
call->mem_ctx,
|
||||
ndr->data + DCERPC_REQUEST_LENGTH,
|
||||
ndr->offset - DCERPC_REQUEST_LENGTH,
|
||||
&dce_conn->auth_state.auth_info->credentials);
|
||||
break;
|
||||
|
||||
case DCERPC_AUTH_LEVEL_INTEGRITY:
|
||||
status = gensec_sign_packet(dce_conn->auth_state.gensec_security,
|
||||
call->mem_ctx,
|
||||
ndr->data + DCERPC_REQUEST_LENGTH,
|
||||
ndr->offset - DCERPC_REQUEST_LENGTH,
|
||||
&dce_conn->auth_state.auth_info->credentials);
|
||||
break;
|
||||
default:
|
||||
status = NT_STATUS_INVALID_LEVEL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
dce_conn->auth_state.auth_info->credentials
|
||||
= data_blob_talloc(call->mem_ctx, NULL,
|
||||
gensec_sig_size(dce_conn->auth_state.gensec_security));
|
||||
|
||||
/* add the auth verifier */
|
||||
status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, dce_conn->auth_state.auth_info);
|
||||
@ -339,6 +321,40 @@ BOOL dcesrv_auth_response(struct dcesrv_call_state *call,
|
||||
dcerpc_set_frag_length(blob, blob->length);
|
||||
dcerpc_set_auth_length(blob, dce_conn->auth_state.auth_info->credentials.length);
|
||||
|
||||
/* sign or seal the packet */
|
||||
switch (dce_conn->auth_state.auth_info->auth_level) {
|
||||
case DCERPC_AUTH_LEVEL_PRIVACY:
|
||||
status = gensec_seal_packet(dce_conn->auth_state.gensec_security,
|
||||
call->mem_ctx,
|
||||
ndr->data + DCERPC_REQUEST_LENGTH,
|
||||
ndr->offset - DCERPC_REQUEST_LENGTH,
|
||||
blob->data,
|
||||
blob->length - dce_conn->auth_state.auth_info->credentials.length,
|
||||
&dce_conn->auth_state.auth_info->credentials);
|
||||
break;
|
||||
|
||||
case DCERPC_AUTH_LEVEL_INTEGRITY:
|
||||
status = gensec_sign_packet(dce_conn->auth_state.gensec_security,
|
||||
call->mem_ctx,
|
||||
ndr->data + DCERPC_REQUEST_LENGTH,
|
||||
ndr->offset - DCERPC_REQUEST_LENGTH,
|
||||
blob->data,
|
||||
blob->length - dce_conn->auth_state.auth_info->credentials.length,
|
||||
&dce_conn->auth_state.auth_info->credentials);
|
||||
|
||||
break;
|
||||
default:
|
||||
status = NT_STATUS_INVALID_LEVEL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
memcpy(blob->data + blob->length - dce_conn->auth_state.auth_info->credentials.length,
|
||||
dce_conn->auth_state.auth_info->credentials.data, dce_conn->auth_state.auth_info->credentials.length);
|
||||
|
||||
data_blob_free(&dce_conn->auth_state.auth_info->credentials);
|
||||
|
||||
return True;
|
||||
|
@ -46,7 +46,7 @@ BOOL torture_ntlmssp_self_check(int dummy)
|
||||
|
||||
data = strhex_to_data_blob("6a43494653");
|
||||
ntlmssp_sign_packet(ntlmssp_state, ntlmssp_state->mem_ctx,
|
||||
data.data, data.length, &sig);
|
||||
data.data, data.length, data.data, data.length, &sig);
|
||||
|
||||
expected_sig = strhex_to_data_blob("01000000e37f97f2544f4d7e00000000");
|
||||
|
||||
@ -83,7 +83,7 @@ BOOL torture_ntlmssp_self_check(int dummy)
|
||||
|
||||
data = strhex_to_data_blob("6a43494653");
|
||||
ntlmssp_sign_packet(ntlmssp_state, ntlmssp_state->mem_ctx,
|
||||
data.data, data.length, &sig);
|
||||
data.data, data.length, data.data, data.length, &sig);
|
||||
|
||||
expected_sig = strhex_to_data_blob("0100000078010900397420fe0e5a0f89");
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user