diff options
Diffstat (limited to 'source4')
-rw-r--r-- | source4/include/cli_context.h | 16 | ||||
-rw-r--r-- | source4/include/includes.h | 1 | ||||
-rw-r--r-- | source4/include/signing.h | 37 | ||||
-rw-r--r-- | source4/libcli/raw/smb_signing.c | 109 | ||||
-rw-r--r-- | source4/smb_server/negprot.c | 37 | ||||
-rw-r--r-- | source4/smb_server/request.c | 2 | ||||
-rw-r--r-- | source4/smb_server/sesssetup.c | 30 | ||||
-rw-r--r-- | source4/smb_server/signing.c | 139 | ||||
-rw-r--r-- | source4/smb_server/smb_server.c | 2 | ||||
-rw-r--r-- | source4/smb_server/smb_server.h | 6 |
10 files changed, 256 insertions, 123 deletions
diff --git a/source4/include/cli_context.h b/source4/include/cli_context.h index a31bc35b9c..f289d5b546 100644 --- a/source4/include/cli_context.h +++ b/source4/include/cli_context.h @@ -29,22 +29,6 @@ struct smbcli_request; /* forward declare */ struct smbcli_session; /* forward declare */ struct smbcli_transport; /* forward declare */ -enum smb_signing_engine_state { - SMB_SIGNING_ENGINE_OFF, - SMB_SIGNING_ENGINE_BSRSPYL, - SMB_SIGNING_ENGINE_ON -}; - -struct smb_signing_context { - enum smb_signing_engine_state signing_state; - DATA_BLOB mac_key; - uint32_t next_seq_num; - BOOL allow_smb_signing; - BOOL doing_signing; - BOOL mandatory_signing; - BOOL seen_valid; /* Have I ever seen a validly signed packet? */ -}; - /* context that will be and has been negotiated between the client and server */ struct smbcli_negotiate { /* diff --git a/source4/include/includes.h b/source4/include/includes.h index e13175ecb7..f2900697f9 100644 --- a/source4/include/includes.h +++ b/source4/include/includes.h @@ -663,6 +663,7 @@ extern int errno; #include "smbd/service.h" #include "rpc_server/dcerpc_server.h" #include "request.h" +#include "signing.h" #include "smb_server/smb_server.h" #include "ntvfs/ntvfs.h" #include "cli_context.h" diff --git a/source4/include/signing.h b/source4/include/signing.h new file mode 100644 index 0000000000..c290f96788 --- /dev/null +++ b/source4/include/signing.h @@ -0,0 +1,37 @@ +/* + Unix SMB/CIFS implementation. + SMB Signing + + Andrew Bartlett <abartlet@samba.org> 2003-2004 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +enum smb_signing_engine_state { + SMB_SIGNING_ENGINE_OFF, + SMB_SIGNING_ENGINE_BSRSPYL, + SMB_SIGNING_ENGINE_ON +}; + +struct smb_signing_context { + enum smb_signing_engine_state signing_state; + DATA_BLOB mac_key; + uint32_t next_seq_num; + BOOL allow_smb_signing; + BOOL doing_signing; + BOOL mandatory_signing; + BOOL seen_valid; /* Have I ever seen a validly signed packet? */ +}; + diff --git a/source4/libcli/raw/smb_signing.c b/source4/libcli/raw/smb_signing.c index 0b9c2864d3..bd29abe3e6 100644 --- a/source4/libcli/raw/smb_signing.c +++ b/source4/libcli/raw/smb_signing.c @@ -21,26 +21,37 @@ */ #include "includes.h" -static BOOL smbcli_set_signing_off(struct smb_signing_context *sign_info); /*********************************************************** SMB signing - Common code before we set a new signing implementation ************************************************************/ -static BOOL set_smb_signing_common(struct smbcli_transport *transport) +BOOL set_smb_signing_common(struct smb_signing_context *sign_info) { - if (!(transport->negotiate.sec_mode & - (NEGOTIATE_SECURITY_SIGNATURES_REQUIRED|NEGOTIATE_SECURITY_SIGNATURES_ENABLED))) { - DEBUG(5, ("SMB Signing is not negotiated by the peer\n")); + if (sign_info->doing_signing) { + DEBUG(5, ("SMB Signing already in progress, so we don't start it again\n")); return False; } - if (transport->negotiate.sign_info.doing_signing) { - DEBUG(5, ("SMB Signing already in progress, so we don't start it again\n")); + if (!sign_info->allow_smb_signing) { + DEBUG(5, ("SMB Signing has been locally disabled\n")); return False; } - if (!transport->negotiate.sign_info.allow_smb_signing) { - DEBUG(5, ("SMB Signing has been locally disabled\n")); + return True; +} + +/*********************************************************** + SMB signing - Common code before we set a new signing implementation +************************************************************/ +static BOOL smbcli_set_smb_signing_common(struct smbcli_transport *transport) +{ + if (!set_smb_signing_common(&transport->negotiate.sign_info)) { + return False; + } + + if (!(transport->negotiate.sec_mode & + (NEGOTIATE_SECURITY_SIGNATURES_REQUIRED|NEGOTIATE_SECURITY_SIGNATURES_ENABLED))) { + DEBUG(5, ("SMB Signing is not negotiated by the peer\n")); return False; } @@ -51,7 +62,7 @@ static BOOL set_smb_signing_common(struct smbcli_transport *transport) return True; } -static void mark_packet_signed(struct request_buffer *out) +void mark_packet_signed(struct request_buffer *out) { uint16_t flags2; flags2 = SVAL(out->hdr, HDR_FLG2); @@ -59,7 +70,7 @@ static void mark_packet_signed(struct request_buffer *out) SSVAL(out->hdr, HDR_FLG2, flags2); } -static BOOL signing_good(struct smb_signing_context *sign_info, +BOOL signing_good(struct smb_signing_context *sign_info, unsigned int seq, BOOL good) { if (good) { @@ -166,6 +177,19 @@ BOOL check_signed_incoming_message(struct request_buffer *in, DATA_BLOB *mac_key good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0); + if (i == 0) { + if (!good) { + 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, ("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, ("check_signed_incoming_message: GOOD SIG (seq: %d): got SMB signature of\n", seq_num + i)); + dump_data(5, server_sent_mac, 8); + } + } + if (good) break; } @@ -173,17 +197,20 @@ BOOL check_signed_incoming_message(struct request_buffer *in, DATA_BLOB *mac_key DEBUG(0,("SIGNING OFFSET %d (should be %d)\n", i, seq_num)); } - if (!good) { - 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, ("check_signed_incoming_message: BAD SIG (seq: %d): got SMB signature of\n", seq_num + i)); - dump_data(5, server_sent_mac, 8); + return good; +} + +static void smbcli_req_allocate_seq_num(struct smbcli_request *req) +{ + req->seq_num = req->transport->negotiate.sign_info.next_seq_num; + + /* some requests (eg. NTcancel) are one way, and the sequence number + should be increased by 1 not 2 */ + if (req->sign_single_increment) { + req->transport->negotiate.sign_info.next_seq_num += 1; } else { - 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); + req->transport->negotiate.sign_info.next_seq_num += 2; } - return good; } /*********************************************************** @@ -212,16 +239,7 @@ void smbcli_request_calculate_sign_mac(struct smbcli_request *req) case SMB_SIGNING_ENGINE_ON: - req->seq_num = req->transport->negotiate.sign_info.next_seq_num; - - /* some requests (eg. NTcancel) are one way, and the sequence number - should be increased by 1 not 2 */ - if (req->sign_single_increment) { - req->transport->negotiate.sign_info.next_seq_num += 1; - } else { - req->transport->negotiate.sign_info.next_seq_num += 2; - } - + smbcli_req_allocate_seq_num(req); sign_outgoing_message(&req->out, &req->transport->negotiate.sign_info.mac_key, req->seq_num); @@ -237,10 +255,11 @@ void smbcli_request_calculate_sign_mac(struct smbcli_request *req) @note Used as an initialisation only - it will not correctly shut down a real signing mechanism */ -static BOOL smbcli_set_signing_off(struct smb_signing_context *sign_info) +BOOL smbcli_set_signing_off(struct smb_signing_context *sign_info) { DEBUG(5, ("Shutdown SMB signing\n")); sign_info->doing_signing = False; + sign_info->next_seq_num = 0; data_blob_free(&sign_info->mac_key); sign_info->signing_state = SMB_SIGNING_ENGINE_OFF; return True; @@ -252,7 +271,7 @@ static BOOL smbcli_set_signing_off(struct smb_signing_context *sign_info) */ BOOL smbcli_temp_set_signing(struct smbcli_transport *transport) { - if (!set_smb_signing_common(transport)) { + if (!smbcli_set_smb_signing_common(transport)) { return False; } DEBUG(5, ("BSRSPYL SMB signing enabled\n")); @@ -302,9 +321,9 @@ BOOL smbcli_request_check_sign_mac(struct smbcli_request *req) /*********************************************************** SMB signing - Simple implementation - setup the MAC key. ************************************************************/ -static BOOL smbcli_simple_set_signing(struct smb_signing_context *sign_info, - const DATA_BLOB user_session_key, - const DATA_BLOB response) +BOOL smbcli_simple_set_signing(struct smb_signing_context *sign_info, + const DATA_BLOB *user_session_key, + const DATA_BLOB *response) { if (sign_info->mandatory_signing) { DEBUG(5, ("Mandatory SMB signing enabled!\n")); @@ -312,12 +331,16 @@ static BOOL smbcli_simple_set_signing(struct smb_signing_context *sign_info, DEBUG(5, ("SMB signing enabled!\n")); - sign_info->mac_key = data_blob(NULL, response.length + user_session_key.length); - - memcpy(&sign_info->mac_key.data[0], user_session_key.data, user_session_key.length); + if (response && response->length) { + sign_info->mac_key = data_blob(NULL, response->length + user_session_key->length); + } else { + sign_info->mac_key = data_blob(NULL, user_session_key->length); + } + + memcpy(&sign_info->mac_key.data[0], user_session_key->data, user_session_key->length); - if (response.length) { - memcpy(&sign_info->mac_key.data[user_session_key.length],response.data, response.length); + if (response && response->length) { + memcpy(&sign_info->mac_key.data[user_session_key->length],response->data, response->length); } dump_data_pw("Started Signing with key:\n", sign_info->mac_key.data, sign_info->mac_key.length); @@ -338,13 +361,13 @@ BOOL smbcli_transport_simple_set_signing(struct smbcli_transport *transport, const DATA_BLOB user_session_key, const DATA_BLOB response) { - if (!set_smb_signing_common(transport)) { + if (!smbcli_set_smb_signing_common(transport)) { return False; } return smbcli_simple_set_signing(&transport->negotiate.sign_info, - user_session_key, - response); + &user_session_key, + &response); } diff --git a/source4/smb_server/negprot.c b/source4/smb_server/negprot.c index 9e8a8f1f2c..d81900107b 100644 --- a/source4/smb_server/negprot.c +++ b/source4/smb_server/negprot.c @@ -57,6 +57,11 @@ static void reply_corep(struct smbsrv_request *req, uint16_t choice) req->smb_conn->negotiate.protocol = PROTOCOL_CORE; + if (req->smb_conn->signing.mandatory_signing) { + smbsrv_terminate_connection(req->smb_conn, + "CORE does not support SMB signing, and it is mandetory\n"); + } + req_send_reply(req); } @@ -84,6 +89,11 @@ static void reply_coreplus(struct smbsrv_request *req, uint16_t choice) req->smb_conn->negotiate.protocol = PROTOCOL_COREPLUS; + if (req->smb_conn->signing.mandatory_signing) { + smbsrv_terminate_connection(req->smb_conn, + "COREPLUS does not support SMB signing, and it is mandetory\n"); + } + req_send_reply(req); } @@ -128,6 +138,11 @@ static void reply_lanman1(struct smbsrv_request *req, uint16_t choice) get_challenge(req->smb_conn, req->out.data); } + if (req->smb_conn->signing.mandatory_signing) { + smbsrv_terminate_connection(req->smb_conn, + "LANMAN1 does not support SMB signing, and it is mandetory\n"); + } + req_send_reply(req); } @@ -171,6 +186,10 @@ static void reply_lanman2(struct smbsrv_request *req, uint16_t choice) req_push_str(req, NULL, lp_workgroup(), -1, STR_TERMINATE); + if (req->smb_conn->signing.mandatory_signing) { + smbsrv_terminate_connection(req->smb_conn, + "LANMAN2 does not support SMB signing, and it is mandetory\n"); + } req_send_reply(req); } @@ -198,7 +217,7 @@ static void reply_nt1(struct smbsrv_request *req, uint16_t choice) /* do spnego in user level security if the client supports it and we can do encrypted passwords */ - if (0 && req->smb_conn->negotiate.encrypted_passwords && + if (req->smb_conn->negotiate.encrypted_passwords && (lp_security() != SEC_SHARE) && lp_use_spnego() && (req->flags2 & FLAGS2_EXTENDED_SECURITY)) { @@ -241,18 +260,12 @@ static void reply_nt1(struct smbsrv_request *req, uint16_t choice) secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE; } - req->smb_conn->signing.signing_state = lp_server_signing(); - - switch (req->smb_conn->signing.signing_state) { - case SMB_SIGNING_OFF: - break; - case SMB_SIGNING_SUPPORTED: + if (req->smb_conn->signing.allow_smb_signing) { secword |= NEGOTIATE_SECURITY_SIGNATURES_ENABLED; - break; - case SMB_SIGNING_REQUIRED: - secword |= NEGOTIATE_SECURITY_SIGNATURES_ENABLED | - NEGOTIATE_SECURITY_SIGNATURES_REQUIRED; - break; + } + + if (req->smb_conn->signing.mandatory_signing) { + secword |= NEGOTIATE_SECURITY_SIGNATURES_REQUIRED; } req->smb_conn->negotiate.protocol = PROTOCOL_NT1; diff --git a/source4/smb_server/request.c b/source4/smb_server/request.c index f4cdba79cc..e9aeb168bc 100644 --- a/source4/smb_server/request.c +++ b/source4/smb_server/request.c @@ -263,7 +263,7 @@ void req_send_reply_nosign(struct smbsrv_request *req) } if (write_data(req->smb_conn->connection->socket->fde->fd, req->out.buffer, req->out.size) != req->out.size) { - smb_panic("failed to send reply\n"); + smbsrv_terminate_connection(req->smb_conn, "failed to send reply\n"); } req_destroy(req); diff --git a/source4/smb_server/sesssetup.c b/source4/smb_server/sesssetup.c index e1245748a0..a87db0ecc4 100644 --- a/source4/smb_server/sesssetup.c +++ b/source4/smb_server/sesssetup.c @@ -160,9 +160,18 @@ static NTSTATUS sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *s &sess->nt1.out.domain); req->session = smbsrv_session_find(req->smb_conn, sess->nt1.out.vuid); - if (!session_info->server_info->guest) { - srv_setup_signing(req->smb_conn, &session_info->session_key, &sess->nt1.in.password2); + if (session_info->server_info->guest) { + return NT_STATUS_OK; } + if (!srv_setup_signing(req->smb_conn, &session_info->session_key, &sess->nt1.in.password2)) { + /* Already signing, or disabled */ + return NT_STATUS_OK; + } + + /* Force check of the request packet, now we know the session key */ + req_signing_check_incoming(req); + + srv_signing_restart(req->smb_conn, &session_info->session_key, &sess->nt1.in.password2); return NT_STATUS_OK; } @@ -227,7 +236,6 @@ static NTSTATUS sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup if (NT_STATUS_IS_OK(status)) { DATA_BLOB session_key; - DATA_BLOB null_data_blob = data_blob(NULL, 0); status = gensec_session_info(smb_sess->gensec_ctx, &smb_sess->session_info); if (!NT_STATUS_IS_OK(status)) { @@ -235,12 +243,18 @@ static NTSTATUS sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup } status = gensec_session_key(smb_sess->gensec_ctx, - &session_key); - if (NT_STATUS_IS_OK(status)) { - srv_setup_signing(req->smb_conn, &session_key, &null_data_blob); - req->seq_num = 0; - req->smb_conn->signing.next_seq_num = 2; + &session_key); + if (NT_STATUS_IS_OK(status) + && !smb_sess->session_info->server_info->guest + && srv_setup_signing(req->smb_conn, &session_key, NULL)) { + /* Force check of the request packet, now we know the session key */ + req_signing_check_incoming(req); + + srv_signing_restart(req->smb_conn, &session_key, NULL); + } + } else { + status = nt_status_squash(status); } sess->spnego.out.action = 0; diff --git a/source4/smb_server/signing.c b/source4/smb_server/signing.c index 37c1f6f7b1..555a71c0a9 100644 --- a/source4/smb_server/signing.c +++ b/source4/smb_server/signing.c @@ -25,34 +25,93 @@ */ void req_sign_packet(struct smbsrv_request *req) { - /* check if we are doing signing on this connection */ - if (req->smb_conn->signing.signing_state != SMB_SIGNING_REQUIRED) { - return; +#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 + + switch (req->smb_conn->signing.signing_state) { + case SMB_SIGNING_ENGINE_OFF: + break; + + case SMB_SIGNING_ENGINE_BSRSPYL: + /* mark the packet as signed - BEFORE we sign it...*/ + 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); + break; + + case SMB_SIGNING_ENGINE_ON: + + sign_outgoing_message(&req->out, + &req->smb_conn->signing.mac_key, + req->seq_num+1); + break; } - sign_outgoing_message(&req->out, - &req->smb_conn->signing.mac_key, - req->seq_num+1); + return; } + /* setup the signing key for a connection. Called after authentication succeeds in a session setup */ -void srv_setup_signing(struct smbsrv_connection *smb_conn, +BOOL srv_setup_signing(struct smbsrv_connection *smb_conn, DATA_BLOB *session_key, - DATA_BLOB *session_response) + DATA_BLOB *response) { - smb_conn->signing.mac_key = data_blob(NULL, - session_key->length + session_response->length); - memcpy(smb_conn->signing.mac_key.data, session_key->data, session_key->length); - if (session_response->length != 0) { - memcpy(&smb_conn->signing.mac_key.data[session_key->length], - session_response->data, - session_response->length); + if (!set_smb_signing_common(&smb_conn->signing)) { + return False; } + return smbcli_simple_set_signing(&smb_conn->signing, session_key, response); } +void srv_signing_restart(struct smbsrv_connection *smb_conn, + DATA_BLOB *session_key, + DATA_BLOB *response) +{ + if (!smb_conn->signing.seen_valid) { + DEBUG(5, ("Client did not send a valid signature on " + "SPENGO session setup - ignored, expect good next time\n")); + /* force things back on (most clients do not sign this packet)... */ + srv_setup_signing(smb_conn, session_key, response); + smb_conn->signing.next_seq_num = 2; + if (smb_conn->signing.mandatory_signing) { + DEBUG(5, ("Configured for mandetory signing, 'good packet seen' forced on\n")); + /* if this is mandetory, then + * pretend we have seen a + * valid packet, so we don't + * turn it off */ + smb_conn->signing.seen_valid = True; + } + } +} + +BOOL srv_init_signing(struct smbsrv_connection *smb_conn) +{ + smb_conn->signing.mac_key = data_blob(NULL, 0); + if (!smbcli_set_signing_off(&smb_conn->signing)) { + return False; + } + + switch (lp_server_signing()) { + case SMB_SIGNING_OFF: + smb_conn->signing.allow_smb_signing = False; + break; + case SMB_SIGNING_SUPPORTED: + smb_conn->signing.allow_smb_signing = True; + break; + case SMB_SIGNING_REQUIRED: + smb_conn->signing.allow_smb_signing = True; + smb_conn->signing.mandatory_signing = True; + break; + } + return True; +} /* allocate a sequence number to a request @@ -68,34 +127,38 @@ static void req_signing_alloc_seq_num(struct smbsrv_request *req) } } -/* - check the signature of an incoming packet -*/ +/*********************************************************** + SMB signing - Simple implementation - check a MAC sent by client +************************************************************/ +/** + * Check a packet supplied by the server. + * @return False if we had an established signing connection + * which had a back checksum, True otherwise + */ BOOL req_signing_check_incoming(struct smbsrv_request *req) { - uint8_t client_md5_mac[8], signature[8]; - - switch (req->smb_conn->signing.signing_state) { - case SMB_SIGNING_OFF: - return True; - case SMB_SIGNING_SUPPORTED: - if (req->flags2 & FLAGS2_SMB_SECURITY_SIGNATURES) { - req->smb_conn->signing.signing_state = SMB_SIGNING_REQUIRED; - } - break; - case SMB_SIGNING_REQUIRED: - break; - } + BOOL good; req_signing_alloc_seq_num(req); - /* the first packet isn't checked as the key hasn't been established */ - if (req->seq_num == 0) { + switch (req->smb_conn->signing.signing_state) + { + case SMB_SIGNING_ENGINE_OFF: return True; + case SMB_SIGNING_ENGINE_BSRSPYL: + case SMB_SIGNING_ENGINE_ON: + { + if (req->in.size < (HDR_SS_FIELD + 8)) { + return False; + } else { + good = check_signed_incoming_message(&req->in, + &req->smb_conn->signing.mac_key, + req->seq_num); + + return signing_good(&req->smb_conn->signing, + req->seq_num+1, good); + } } - - return check_signed_incoming_message(&req->in, - &req->smb_conn->signing.mac_key, - req->seq_num); - + } + return False; } diff --git a/source4/smb_server/smb_server.c b/source4/smb_server/smb_server.c index ca36dc3aa9..f679a65287 100644 --- a/source4/smb_server/smb_server.c +++ b/source4/smb_server/smb_server.c @@ -850,6 +850,8 @@ void smbsrv_accept(struct server_connection *conn) smb_conn->sessions.next_vuid = VUID_OFFSET; + srv_init_signing(smb_conn); + conn_init(smb_conn); smb_conn->connection = conn; diff --git a/source4/smb_server/smb_server.h b/source4/smb_server/smb_server.h index ae72bb5da4..4ff246c415 100644 --- a/source4/smb_server/smb_server.h +++ b/source4/smb_server/smb_server.h @@ -306,11 +306,7 @@ struct smbsrv_connection { time_t last_smb_conf_reload; } timers; - struct { - DATA_BLOB mac_key; - uint64_t next_seq_num; - enum smb_signing_state signing_state; - } signing; + struct smb_signing_context signing; struct substitute_context substitute; |