summaryrefslogtreecommitdiff
path: root/source4/libcli
diff options
context:
space:
mode:
Diffstat (limited to 'source4/libcli')
-rw-r--r--source4/libcli/auth/gensec_krb5.c4
-rw-r--r--source4/libcli/auth/spnego.c43
-rw-r--r--source4/libcli/raw/clisession.c43
-rw-r--r--source4/libcli/raw/smb_signing.c152
4 files changed, 141 insertions, 101 deletions
diff --git a/source4/libcli/auth/gensec_krb5.c b/source4/libcli/auth/gensec_krb5.c
index 8268eb6051..c7c1a18d24 100644
--- a/source4/libcli/auth/gensec_krb5.c
+++ b/source4/libcli/auth/gensec_krb5.c
@@ -304,6 +304,8 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security, TALL
DATA_BLOB unwrapped_in;
if (!gensec_gssapi_parse_krb5_wrap(out_mem_ctx, &in, &unwrapped_in, tok_id)) {
+ DEBUG(1,("gensec_gssapi_parse_krb5_wrap(mutual authentication) failed to parse\n"));
+ dump_data_pw("Mutual authentication message:\n", in.data, in.length);
return NT_STATUS_INVALID_PARAMETER;
}
/* TODO: check the tok_id */
@@ -316,7 +318,7 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security, TALL
if (ret) {
DEBUG(1,("krb5_rd_rep (mutual authentication) failed (%s)\n",
error_message(ret)));
- dump_data_pw("Mutual authentication message:\n", in.data, in.length);
+ dump_data_pw("Mutual authentication message:\n", inbuf.data, inbuf.length);
nt_status = NT_STATUS_ACCESS_DENIED;
} else {
*out = data_blob(NULL, 0);
diff --git a/source4/libcli/auth/spnego.c b/source4/libcli/auth/spnego.c
index d4910eb92f..c16d77dad9 100644
--- a/source4/libcli/auth/spnego.c
+++ b/source4/libcli/auth/spnego.c
@@ -41,7 +41,6 @@ struct spnego_state {
uint_t ref_count;
enum spnego_message_type expected_packet;
enum spnego_state_position state_position;
- enum spnego_negResult result;
struct gensec_security *sub_sec_security;
};
@@ -60,7 +59,6 @@ static NTSTATUS gensec_spnego_client_start(struct gensec_security *gensec_securi
spnego_state->expected_packet = SPNEGO_NEG_TOKEN_INIT;
spnego_state->state_position = SPNEGO_CLIENT_START;
- spnego_state->result = SPNEGO_ACCEPT_INCOMPLETE;
spnego_state->mem_ctx = mem_ctx;
spnego_state->sub_sec_security = NULL;
@@ -140,8 +138,7 @@ static NTSTATUS gensec_spnego_session_key(struct gensec_security *gensec_securit
DATA_BLOB *session_key)
{
struct spnego_state *spnego_state = gensec_security->private_data;
- if (spnego_state->state_position != SPNEGO_DONE
- && spnego_state->state_position != SPNEGO_FALLBACK) {
+ if (!spnego_state->sub_sec_security) {
return NT_STATUS_INVALID_PARAMETER;
}
@@ -450,7 +447,6 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
spnego.negTokenTarg.responseToken,
&unwrapped_out);
- spnego_state->result = spnego.negTokenTarg.negResult;
spnego_free_data(&spnego);
/* compose reply */
@@ -514,38 +510,45 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
spnego.negTokenTarg.responseToken,
&unwrapped_out);
- if (NT_STATUS_IS_OK(nt_status)
- && (spnego.negTokenTarg.negResult != SPNEGO_ACCEPT_COMPLETED)) {
+
+ if ((spnego.negTokenTarg.negResult == SPNEGO_ACCEPT_COMPLETED)
+ && !NT_STATUS_IS_OK(nt_status)) {
DEBUG(1,("gensec_update ok but not accepted\n"));
nt_status = NT_STATUS_INVALID_PARAMETER;
- }
+ }
- spnego_state->result = spnego.negTokenTarg.negResult;
spnego_free_data(&spnego);
-
- spnego_out.type = SPNEGO_NEG_TOKEN_TARG;
- spnego_out.negTokenTarg.negResult = SPNEGO_NONE_RESULT;
- spnego_out.negTokenTarg.supportedMech = NULL;
- spnego_out.negTokenTarg.responseToken = unwrapped_out;
- spnego_out.negTokenTarg.mechListMIC = null_data_blob;
+
+ if (unwrapped_out.length) {
+ spnego_out.type = SPNEGO_NEG_TOKEN_TARG;
+ spnego_out.negTokenTarg.negResult = SPNEGO_NONE_RESULT;
+ spnego_out.negTokenTarg.supportedMech = NULL;
+ spnego_out.negTokenTarg.responseToken = unwrapped_out;
+ spnego_out.negTokenTarg.mechListMIC = null_data_blob;
+
+ if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
+ DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_TARG\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ } else {
+ *out = null_data_blob;
+ }
if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
/* compose reply */
+
spnego_state->state_position = SPNEGO_CLIENT_TARG;
} else if (NT_STATUS_IS_OK(nt_status)) {
+ /* all done - server has accepted, and we agree */
spnego_state->state_position = SPNEGO_DONE;
+ return NT_STATUS_OK;
} else {
DEBUG(1, ("SPNEGO(%s) login failed: %s\n",
spnego_state->sub_sec_security->ops->name,
nt_errstr(nt_status)));
return nt_status;
}
- if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
- DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_TARG\n"));
- return NT_STATUS_INVALID_PARAMETER;
- }
-
return nt_status;
}
case SPNEGO_DONE:
diff --git a/source4/libcli/raw/clisession.c b/source4/libcli/raw/clisession.c
index e31cf07bf8..c6d7f800a4 100644
--- a/source4/libcli/raw/clisession.c
+++ b/source4/libcli/raw/clisession.c
@@ -260,7 +260,7 @@ static void use_nt1_session_keys(struct cli_session *session,
E_md4hash(password, nt_hash);
SMBsesskeygen_ntv1(nt_hash, session_key.data);
- cli_transport_simple_set_signing(transport, session_key, *nt_response, 0);
+ cli_transport_simple_set_signing(transport, session_key, *nt_response);
cli_session_set_user_session_key(session, &session_key);
data_blob_free(&session_key);
@@ -380,6 +380,7 @@ static NTSTATUS smb_raw_session_setup_generic_spnego(struct cli_session *session
union smb_sesssetup *parms)
{
NTSTATUS status;
+ NTSTATUS session_key_err = NT_STATUS_NO_USER_SESSION_KEY;
union smb_sesssetup s2;
DATA_BLOB session_key = data_blob(NULL, 0);
DATA_BLOB null_data_blob = data_blob(NULL, 0);
@@ -443,15 +444,20 @@ static NTSTATUS smb_raw_session_setup_generic_spnego(struct cli_session *session
&s2.spnego.in.secblob);
while(1) {
+ if (NT_STATUS_IS_OK(status) && s2.spnego.in.secblob.length == 0) {
+ break;
+ }
if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
break;
}
- status = gensec_session_key(session->gensec, &session_key);
- if (NT_STATUS_IS_OK(status)) {
- cli_transport_simple_set_signing(session->transport, session_key, null_data_blob, 0);
+ if (!NT_STATUS_IS_OK(session_key_err)) {
+ session_key_err = gensec_session_key(session->gensec, &session_key);
}
-
+ if (NT_STATUS_IS_OK(session_key_err)) {
+ cli_transport_simple_set_signing(session->transport, session_key, null_data_blob);
+ }
+
session->vuid = s2.spnego.out.vuid;
status = smb_raw_session_setup(session, mem_ctx, &s2);
session->vuid = UID_FIELD_INVALID;
@@ -464,19 +470,14 @@ static NTSTATUS smb_raw_session_setup_generic_spnego(struct cli_session *session
s2.spnego.out.secblob,
&s2.spnego.in.secblob);
- if (NT_STATUS_IS_OK(status)) {
- break;
- }
}
done:
if (NT_STATUS_IS_OK(status)) {
- status = gensec_session_key(session->gensec, &session_key);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
+ if (!NT_STATUS_IS_OK(session_key_err)) {
+ DEBUG(1, ("Failed to get user session key: %s\n", nt_errstr(session_key_err)));
+ return session_key_err;
}
-
- cli_transport_simple_set_signing(session->transport, session_key, null_data_blob, 2 /* two legs on last packet */);
cli_session_set_user_session_key(session, &session_key);
@@ -484,6 +485,9 @@ done:
parms->generic.out.os = s2.spnego.out.os;
parms->generic.out.lanman = s2.spnego.out.lanman;
parms->generic.out.domain = s2.spnego.out.domain;
+ } else {
+ DEBUG(1, ("Failed to login with SPNEGO: %s\n", nt_errstr(status)));
+ return status;
}
return status;
@@ -528,7 +532,18 @@ NTSTATUS smb_raw_session_setup(struct cli_session *session, TALLOC_CTX *mem_ctx,
struct cli_request *req;
if (parms->generic.level == RAW_SESSSETUP_GENERIC) {
- return smb_raw_session_setup_generic(session, mem_ctx, parms);
+ NTSTATUS ret = smb_raw_session_setup_generic(session, mem_ctx, parms);
+
+ if (NT_STATUS_IS_OK(ret)
+ && parms->generic.in.user
+ && *parms->generic.in.user) {
+ if (!session->transport->negotiate.sign_info.doing_signing
+ && session->transport->negotiate.sign_info.mandatory_signing) {
+ DEBUG(0, ("SMB signing required, but server does not support it\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+ return ret;
}
req = smb_raw_session_setup_send(session, parms);
diff --git a/source4/libcli/raw/smb_signing.c b/source4/libcli/raw/smb_signing.c
index fc10413108..20f8921acb 100644
--- a/source4/libcli/raw/smb_signing.c
+++ b/source4/libcli/raw/smb_signing.c
@@ -69,15 +69,15 @@ static BOOL set_smb_signing_real_common(struct cli_transport *transport)
return True;
}
-static void mark_packet_signed(struct cli_request *req)
+static void mark_packet_signed(struct request_buffer *out)
{
uint16_t flags2;
- flags2 = SVAL(req->out.hdr, HDR_FLG2);
+ flags2 = SVAL(out->hdr, HDR_FLG2);
flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES;
- SSVAL(req->out.hdr, HDR_FLG2, flags2);
+ SSVAL(out->hdr, HDR_FLG2, flags2);
}
-static BOOL signing_good(struct cli_request *req, int seq, BOOL good)
+static BOOL signing_good(struct cli_request *req, unsigned int seq, BOOL good)
{
if (good) {
if (!req->transport->negotiate.sign_info.doing_signing) {
@@ -87,9 +87,8 @@ static BOOL signing_good(struct cli_request *req, int seq, BOOL good)
req->transport->negotiate.sign_info.seen_valid = True;
}
} else {
- if (!req->transport->negotiate.sign_info.mandatory_signing && !req->transport->negotiate.sign_info.seen_valid) {
-
- /* Non-mandatory signing - just turn off if this is the first bad packet.. */
+ if (!req->transport->negotiate.sign_info.seen_valid) {
+ /* If we have never seen a good packet, just turn it off */
DEBUG(5, ("signing_good: signing negotiated but not required and peer\n"
"isn't sending correct signatures. Turning off.\n"));
req->transport->negotiate.sign_info.negotiated_smb_signing = False;
@@ -100,119 +99,97 @@ static BOOL signing_good(struct cli_request *req, int seq, BOOL good)
cli_null_set_signing(req->transport);
return True;
} else {
- /* Mandatory signing or bad packet after signing started - fail and disconnect. */
- if (seq)
- DEBUG(0, ("signing_good: BAD SIG: seq %u\n", (unsigned int)seq));
+ /* bad packet after signing started - fail and disconnect. */
+ DEBUG(0, ("signing_good: BAD SIG: seq %u\n", seq));
return False;
}
}
return True;
}
-/***********************************************************
- SMB signing - Simple implementation - calculate a MAC to send.
-************************************************************/
-static void cli_request_simple_sign_outgoing_message(struct cli_request *req)
+void sign_outgoing_message(struct request_buffer *out, DATA_BLOB *mac_key, uint_t seq_num)
{
uint8_t calc_md5_mac[16];
struct MD5Context md5_ctx;
- struct smb_basic_signing_context *data = req->transport->negotiate.sign_info.signing_context;
-
-#if 0
- /* enable this when packet signing is preventing you working out why valgrind
- says that data is uninitialised */
- file_save("pkt.dat", req->out.buffer, req->out.size);
-#endif
-
- req->seq_num = data->next_seq_num;
-
- /* some requests (eg. NTcancel) are one way, and the sequence number
- should be increased by 1 not 2 */
- if (req->one_way_request) {
- data->next_seq_num += 1;
- } else {
- data->next_seq_num += 2;
- }
-
/*
* Firstly put the sequence number into the first 4 bytes.
* and zero out the next 4 bytes.
*/
- SIVAL(req->out.hdr, HDR_SS_FIELD, req->seq_num);
- SIVAL(req->out.hdr, HDR_SS_FIELD + 4, 0);
+ SIVAL(out->hdr, HDR_SS_FIELD, seq_num);
+ SIVAL(out->hdr, HDR_SS_FIELD + 4, 0);
/* mark the packet as signed - BEFORE we sign it...*/
- mark_packet_signed(req);
+ mark_packet_signed(out);
/* Calculate the 16 byte MAC and place first 8 bytes into the field. */
MD5Init(&md5_ctx);
- MD5Update(&md5_ctx, data->mac_key.data,
- data->mac_key.length);
+ MD5Update(&md5_ctx, mac_key->data,
+ mac_key->length);
MD5Update(&md5_ctx,
- req->out.buffer + NBT_HDR_SIZE,
- req->out.size - NBT_HDR_SIZE);
+ out->buffer + NBT_HDR_SIZE,
+ out->size - NBT_HDR_SIZE);
MD5Final(calc_md5_mac, &md5_ctx);
- memcpy(&req->out.hdr[HDR_SS_FIELD], calc_md5_mac, 8);
+ memcpy(&out->hdr[HDR_SS_FIELD], calc_md5_mac, 8);
- DEBUG(5, ("cli_request_simple_sign_outgoing_message: SENT SIG (seq: %d, next %d): sent SMB signature of\n",
- req->seq_num, data->next_seq_num));
+ DEBUG(5, ("sign_outgoing_message: SENT SIG (seq: %d): sent SMB signature of\n",
+ seq_num));
dump_data(5, calc_md5_mac, 8);
/* req->out.hdr[HDR_SS_FIELD+2]=0;
Uncomment this to test if the remote server actually verifies signitures...*/
}
-
-/***********************************************************
- SMB signing - Simple implementation - check a MAC sent by server.
-************************************************************/
-static BOOL cli_request_simple_check_incoming_message(struct cli_request *req)
+BOOL check_signed_incoming_message(struct request_buffer *in, DATA_BLOB *mac_key, uint_t seq_num)
{
BOOL good;
uint8_t calc_md5_mac[16];
uint8_t server_sent_mac[8];
uint8_t sequence_buf[8];
struct MD5Context md5_ctx;
- struct smb_basic_signing_context *data = req->transport->negotiate.sign_info.signing_context;
const size_t offset_end_of_sig = (HDR_SS_FIELD + 8);
int i;
const int sign_range = 0;
+ /* room enough for the signature? */
+ if (in->size < NBT_HDR_SIZE + HDR_SS_FIELD + 8) {
+ return False;
+ }
+
/* its quite bogus to be guessing sequence numbers, but very useful
when debugging signing implementations */
- for (i = 1-sign_range; i <= 1+sign_range; i++) {
+ for (i = 0-sign_range; i <= 0+sign_range; i++) {
/*
* Firstly put the sequence number into the first 4 bytes.
* and zero out the next 4 bytes.
*/
- SIVAL(sequence_buf, 0, req->seq_num+i);
+ SIVAL(sequence_buf, 0, seq_num + i);
SIVAL(sequence_buf, 4, 0);
/* get a copy of the server-sent mac */
- memcpy(server_sent_mac, &req->in.hdr[HDR_SS_FIELD], sizeof(server_sent_mac));
+ memcpy(server_sent_mac, &in->hdr[HDR_SS_FIELD], sizeof(server_sent_mac));
/* Calculate the 16 byte MAC and place first 8 bytes into the field. */
MD5Init(&md5_ctx);
- MD5Update(&md5_ctx, data->mac_key.data,
- data->mac_key.length);
- MD5Update(&md5_ctx, req->in.hdr, HDR_SS_FIELD);
+ MD5Update(&md5_ctx, mac_key->data,
+ mac_key->length);
+ MD5Update(&md5_ctx, in->hdr, HDR_SS_FIELD);
MD5Update(&md5_ctx, sequence_buf, sizeof(sequence_buf));
- MD5Update(&md5_ctx, req->in.hdr + offset_end_of_sig,
- req->in.size - NBT_HDR_SIZE - (offset_end_of_sig));
+ MD5Update(&md5_ctx, in->hdr + offset_end_of_sig,
+ in->size - NBT_HDR_SIZE - (offset_end_of_sig));
MD5Final(calc_md5_mac, &md5_ctx);
good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0);
- if (i == 1) {
+ if (i == 0) {
if (!good) {
- DEBUG(5, ("cli_request_simple_check_incoming_message: BAD SIG (seq: %d): wanted SMB signature of\n", req->seq_num + i));
+ DEBUG(5, ("check_signed_incoming_message: BAD SIG (seq: %d): wanted SMB signature of\n", seq_num + i));
dump_data(5, calc_md5_mac, 8);
- DEBUG(5, ("cli_request_simple_check_incoming_message: BAD SIG (seq: %d): got SMB signature of\n", req->seq_num + i));
+ DEBUG(5, ("check_signed_incoming_message: BAD SIG (seq: %d): got SMB signature of\n", seq_num + i));
dump_data(5, server_sent_mac, 8);
} else {
- DEBUG(15, ("cli_request_simple_check_incoming_message: GOOD SIG (seq: %d): got SMB signature of\n", req->seq_num + i));
+ DEBUG(15, ("check_signed_incoming_message: GOOD SIG (seq: %d): got SMB signature of\n", seq_num + i));
dump_data(5, server_sent_mac, 8);
}
}
@@ -220,10 +197,51 @@ static BOOL cli_request_simple_check_incoming_message(struct cli_request *req)
if (good) break;
}
- if (good && i != 1) {
- DEBUG(0,("SIGNING OFFSET %d (should be %d)\n", i, req->seq_num+1));
+ if (good && i != 0) {
+ DEBUG(0,("SIGNING OFFSET %d (should be %d)\n", i, seq_num));
+ }
+ return good;
+}
+
+/***********************************************************
+ SMB signing - Simple implementation - calculate a MAC to send.
+************************************************************/
+static void cli_request_simple_sign_outgoing_message(struct cli_request *req)
+{
+ struct smb_basic_signing_context *data = req->transport->negotiate.sign_info.signing_context;
+
+#if 0
+ /* enable this when packet signing is preventing you working out why valgrind
+ says that data is uninitialised */
+ file_save("pkt.dat", req->out.buffer, req->out.size);
+#endif
+
+ req->seq_num = data->next_seq_num;
+
+ /* some requests (eg. NTcancel) are one way, and the sequence number
+ should be increased by 1 not 2 */
+ if (req->one_way_request) {
+ data->next_seq_num += 1;
+ } else {
+ data->next_seq_num += 2;
}
+
+ sign_outgoing_message(&req->out, &data->mac_key, req->seq_num);
+}
+
+/***********************************************************
+ SMB signing - Simple implementation - check a MAC sent by server.
+************************************************************/
+static BOOL cli_request_simple_check_incoming_message(struct cli_request *req)
+{
+ struct smb_basic_signing_context *data
+ = req->transport->negotiate.sign_info.signing_context;
+
+ BOOL good = check_signed_incoming_message(&req->in,
+ &data->mac_key,
+ req->seq_num+1);
+
return signing_good(req, req->seq_num+1, good);
}
@@ -247,8 +265,7 @@ static void cli_transport_simple_free_signing_context(struct cli_transport *tran
************************************************************/
BOOL cli_transport_simple_set_signing(struct cli_transport *transport,
const DATA_BLOB user_session_key,
- const DATA_BLOB response,
- int seq_num)
+ const DATA_BLOB response)
{
struct smb_basic_signing_context *data;
@@ -271,8 +288,10 @@ BOOL cli_transport_simple_set_signing(struct cli_transport *transport,
memcpy(&data->mac_key.data[user_session_key.length],response.data, response.length);
}
+ dump_data_pw("Started Signing with key:\n", data->mac_key.data, data->mac_key.length);
+
/* Initialise the sequence number */
- data->next_seq_num = seq_num;
+ data->next_seq_num = 0;
transport->negotiate.sign_info.sign_outgoing_message = cli_request_simple_sign_outgoing_message;
transport->negotiate.sign_info.check_incoming_message = cli_request_simple_check_incoming_message;
@@ -332,11 +351,12 @@ BOOL cli_null_set_signing(struct cli_transport *transport)
static void cli_request_temp_sign_outgoing_message(struct cli_request *req)
{
/* mark the packet as signed - BEFORE we sign it...*/
- mark_packet_signed(req);
+ mark_packet_signed(&req->out);
/* I wonder what BSRSPYL stands for - but this is what MS
actually sends! */
memcpy((req->out.hdr + HDR_SS_FIELD), "BSRSPYL ", 8);
+
return;
}