From 1a48d0793b9d3a76aff76580661626e5cd95f427 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sun, 8 Mar 2009 17:47:08 +0100 Subject: s3:libsmb: rename smb_signing.c => clisigning.c This prepares a large simplification of the smb_signing code metze --- source3/libsmb/smb_signing.c | 1006 ------------------------------------------ 1 file changed, 1006 deletions(-) delete mode 100644 source3/libsmb/smb_signing.c (limited to 'source3/libsmb/smb_signing.c') diff --git a/source3/libsmb/smb_signing.c b/source3/libsmb/smb_signing.c deleted file mode 100644 index a3ed0e7572..0000000000 --- a/source3/libsmb/smb_signing.c +++ /dev/null @@ -1,1006 +0,0 @@ -/* - Unix SMB/CIFS implementation. - SMB Signing Code - Copyright (C) Jeremy Allison 2003. - Copyright (C) Andrew Bartlett 2002-2003 - - 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 3 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, see . -*/ - -#include "includes.h" - -/* Lookup a packet's MID (multiplex id) and figure out it's sequence number */ -struct outstanding_packet_lookup { - struct outstanding_packet_lookup *prev, *next; - uint16 mid; - uint32 reply_seq_num; - bool can_delete; /* Set to False in trans state. */ -}; - -struct smb_basic_signing_context { - DATA_BLOB mac_key; - uint32 send_seq_num; - struct outstanding_packet_lookup *outstanding_packet_list; -}; - -static bool store_sequence_for_reply(struct outstanding_packet_lookup **list, - uint16 mid, uint32 reply_seq_num) -{ - struct outstanding_packet_lookup *t; - - /* Ensure we only add a mid once. */ - for (t = *list; t; t = t->next) { - if (t->mid == mid) { - return False; - } - } - - t = SMB_XMALLOC_P(struct outstanding_packet_lookup); - ZERO_STRUCTP(t); - - t->mid = mid; - t->reply_seq_num = reply_seq_num; - t->can_delete = True; - - /* - * Add to the *start* of the list not the end of the list. - * This ensures that the *last* send sequence with this mid - * is returned by preference. - * This can happen if the mid wraps and one of the early - * mid numbers didn't get a reply and is still lurking on - * the list. JRA. Found by Fran Fabrizio . - */ - - DLIST_ADD(*list, t); - DEBUG(10,("store_sequence_for_reply: stored seq = %u mid = %u\n", - (unsigned int)reply_seq_num, (unsigned int)mid )); - return True; -} - -static bool get_sequence_for_reply(struct outstanding_packet_lookup **list, - uint16 mid, uint32 *reply_seq_num) -{ - struct outstanding_packet_lookup *t; - - for (t = *list; t; t = t->next) { - if (t->mid == mid) { - *reply_seq_num = t->reply_seq_num; - DEBUG(10,("get_sequence_for_reply: found seq = %u mid = %u\n", - (unsigned int)t->reply_seq_num, (unsigned int)t->mid )); - if (t->can_delete) { - DLIST_REMOVE(*list, t); - SAFE_FREE(t); - } - return True; - } - } - return False; -} - -static bool set_sequence_can_delete_flag(struct outstanding_packet_lookup **list, uint16 mid, bool can_delete_entry) -{ - struct outstanding_packet_lookup *t; - - for (t = *list; t; t = t->next) { - if (t->mid == mid) { - t->can_delete = can_delete_entry; - return True; - } - } - return False; -} - -/*********************************************************** - SMB signing - Common code before we set a new signing implementation -************************************************************/ - -static bool cli_set_smb_signing_common(struct cli_state *cli) -{ - if (!cli->sign_info.allow_smb_signing) { - return False; - } - - if (!cli->sign_info.negotiated_smb_signing - && !cli->sign_info.mandatory_signing) { - return False; - } - - if (cli->sign_info.doing_signing) { - return False; - } - - if (cli->sign_info.free_signing_context) - cli->sign_info.free_signing_context(&cli->sign_info); - - /* These calls are INCOMPATIBLE with SMB signing */ - cli->readbraw_supported = False; - cli->writebraw_supported = False; - - return True; -} - -/*********************************************************** - SMB signing - Common code for 'real' implementations -************************************************************/ - -static bool set_smb_signing_real_common(struct smb_sign_info *si) -{ - if (si->mandatory_signing) { - DEBUG(5, ("Mandatory SMB signing enabled!\n")); - } - - si->doing_signing = True; - DEBUG(5, ("SMB signing enabled!\n")); - - return True; -} - -static void mark_packet_signed(char *outbuf) -{ - uint16 flags2; - flags2 = SVAL(outbuf,smb_flg2); - flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES; - SSVAL(outbuf,smb_flg2, flags2); -} - -/*********************************************************** - SMB signing - NULL implementation - calculate a MAC to send. -************************************************************/ - -static void null_sign_outgoing_message(char *outbuf, struct smb_sign_info *si) -{ - /* we can't zero out the sig, as we might be trying to send a - session request - which is NBT-level, not SMB level and doesn't - have the field */ - return; -} - -/*********************************************************** - SMB signing - NULL implementation - check a MAC sent by server. -************************************************************/ - -static bool null_check_incoming_message(const char *inbuf, - struct smb_sign_info *si, - bool must_be_ok) -{ - return True; -} - -/*********************************************************** - SMB signing - NULL implementation - free signing context -************************************************************/ - -static void null_free_signing_context(struct smb_sign_info *si) -{ - return; -} - -/** - SMB signing - NULL implementation - setup the MAC key. - - @note Used as an initialisation only - it will not correctly - shut down a real signing mechanism -*/ - -static bool null_set_signing(struct smb_sign_info *si) -{ - si->signing_context = NULL; - - si->sign_outgoing_message = null_sign_outgoing_message; - si->check_incoming_message = null_check_incoming_message; - si->free_signing_context = null_free_signing_context; - - return True; -} - -/** - * Free the signing context - */ - -static void free_signing_context(struct smb_sign_info *si) -{ - if (si->free_signing_context) { - si->free_signing_context(si); - si->signing_context = NULL; - } - - null_set_signing(si); -} - - -static bool signing_good(const char *inbuf, struct smb_sign_info *si, - bool good, uint32 seq, bool must_be_ok) -{ - if (good) { - - if (!si->doing_signing) { - si->doing_signing = True; - } - - if (!si->seen_valid) { - si->seen_valid = True; - } - - } else { - if (!si->mandatory_signing && !si->seen_valid) { - - if (!must_be_ok) { - return True; - } - /* Non-mandatory signing - just turn off if this is the first bad packet.. */ - DEBUG(5, ("srv_check_incoming_message: signing negotiated but not required and peer\n" - "isn't sending correct signatures. Turning off.\n")); - si->negotiated_smb_signing = False; - si->allow_smb_signing = False; - si->doing_signing = False; - free_signing_context(si); - return True; - } else if (!must_be_ok) { - /* This packet is known to be unsigned */ - 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)); - return False; - } - } - return True; -} - -/*********************************************************** - SMB signing - Simple implementation - calculate a MAC on the packet -************************************************************/ - -static void simple_packet_signature(struct smb_basic_signing_context *data, - const uchar *buf, uint32 seq_number, - unsigned char calc_md5_mac[16]) -{ - const size_t offset_end_of_sig = (smb_ss_field + 8); - unsigned char sequence_buf[8]; - struct MD5Context md5_ctx; -#if 0 - /* JRA - apparently this is incorrect. */ - unsigned char key_buf[16]; -#endif - - /* - * Firstly put the sequence number into the first 4 bytes. - * and zero out the next 4 bytes. - * - * We do this here, to avoid modifying the packet. - */ - - DEBUG(10,("simple_packet_signature: sequence number %u\n", seq_number )); - - SIVAL(sequence_buf, 0, seq_number); - SIVAL(sequence_buf, 4, 0); - - /* Calculate the 16 byte MAC - but don't alter the data in the - incoming packet. - - This makes for a bit of fussing about, but it's not too bad. - */ - MD5Init(&md5_ctx); - - /* intialise with the key */ - MD5Update(&md5_ctx, data->mac_key.data, data->mac_key.length); -#if 0 - /* JRA - apparently this is incorrect. */ - /* NB. When making and verifying SMB signatures, Windows apparently - zero-pads the key to 128 bits if it isn't long enough. - From Nalin Dahyabhai */ - if (data->mac_key.length < sizeof(key_buf)) { - memset(key_buf, 0, sizeof(key_buf)); - MD5Update(&md5_ctx, key_buf, sizeof(key_buf) - data->mac_key.length); - } -#endif - - /* copy in the first bit of the SMB header */ - MD5Update(&md5_ctx, buf + 4, smb_ss_field - 4); - - /* copy in the sequence number, instead of the signature */ - MD5Update(&md5_ctx, sequence_buf, sizeof(sequence_buf)); - - /* copy in the rest of the packet in, skipping the signature */ - MD5Update(&md5_ctx, buf + offset_end_of_sig, - smb_len(buf) - (offset_end_of_sig - 4)); - - /* calculate the MD5 sig */ - MD5Final(calc_md5_mac, &md5_ctx); -} - - -/*********************************************************** - SMB signing - Client implementation - send the MAC. -************************************************************/ - -static void client_sign_outgoing_message(char *outbuf, struct smb_sign_info *si) -{ - unsigned char calc_md5_mac[16]; - struct smb_basic_signing_context *data = - (struct smb_basic_signing_context *)si->signing_context; - - if (!si->doing_signing) - return; - - /* JRA Paranioa test - we should be able to get rid of this... */ - if (smb_len(outbuf) < (smb_ss_field + 8 - 4)) { - DEBUG(1, ("client_sign_outgoing_message: Logic error. Can't check signature on short packet! smb_len = %u\n", - smb_len(outbuf) )); - abort(); - } - - /* mark the packet as signed - BEFORE we sign it...*/ - mark_packet_signed(outbuf); - - simple_packet_signature(data, (const unsigned char *)outbuf, - data->send_seq_num, calc_md5_mac); - - DEBUG(10, ("client_sign_outgoing_message: sent SMB signature of\n")); - dump_data(10, calc_md5_mac, 8); - - memcpy(&outbuf[smb_ss_field], calc_md5_mac, 8); - -/* cli->outbuf[smb_ss_field+2]=0; - Uncomment this to test if the remote server actually verifies signatures...*/ - - /* Instead of re-introducing the trans_info_conect we - used to have here, we use the fact that during a - SMBtrans/SMBtrans2/SMBnttrans send that the mid stays - constant. This means that calling store_sequence_for_reply() - will return False for all trans secondaries, as the mid is already - on the stored sequence list. As the send_seqence_number must - remain constant for all primary+secondary trans sends, we - only increment the send sequence number when we successfully - add a new entry to the outstanding sequence list. This means - I can isolate the fix here rather than re-adding the trans - signing on/off calls in libsmb/clitrans2.c JRA. - */ - - if (store_sequence_for_reply(&data->outstanding_packet_list, SVAL(outbuf,smb_mid), data->send_seq_num + 1)) { - data->send_seq_num += 2; - } -} - -/*********************************************************** - SMB signing - Client implementation - check a MAC sent by server. -************************************************************/ - -static bool client_check_incoming_message(const char *inbuf, - struct smb_sign_info *si, - bool must_be_ok) -{ - bool good; - uint32 reply_seq_number; - unsigned char calc_md5_mac[16]; - unsigned char *server_sent_mac; - - struct smb_basic_signing_context *data = - (struct smb_basic_signing_context *)si->signing_context; - - if (!si->doing_signing) - return True; - - if (smb_len(inbuf) < (smb_ss_field + 8 - 4)) { - DEBUG(1, ("client_check_incoming_message: Can't check signature on short packet! smb_len = %u\n", smb_len(inbuf))); - return False; - } - - if (!get_sequence_for_reply(&data->outstanding_packet_list, SVAL(inbuf, smb_mid), &reply_seq_number)) { - DEBUG(1, ("client_check_incoming_message: received message " - "with mid %u with no matching send record.\n", (unsigned int)SVAL(inbuf, smb_mid) )); - return False; - } - - simple_packet_signature(data, (const unsigned char *)inbuf, - reply_seq_number, calc_md5_mac); - - server_sent_mac = (unsigned char *)&inbuf[smb_ss_field]; - good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0); - - if (!good) { - DEBUG(5, ("client_check_incoming_message: BAD SIG: wanted SMB signature of\n")); - dump_data(5, calc_md5_mac, 8); - - DEBUG(5, ("client_check_incoming_message: BAD SIG: got SMB signature of\n")); - dump_data(5, server_sent_mac, 8); -#if 1 /* JRATEST */ - { - int i; - for (i = -5; i < 5; i++) { - simple_packet_signature(data, (const unsigned char *)inbuf, reply_seq_number+i, calc_md5_mac); - if (memcmp(server_sent_mac, calc_md5_mac, 8) == 0) { - DEBUG(0,("client_check_incoming_message: out of seq. seq num %u matches. \ -We were expecting seq %u\n", reply_seq_number+i, reply_seq_number )); - break; - } - } - } -#endif /* JRATEST */ - - } else { - DEBUG(10, ("client_check_incoming_message: seq %u: got good SMB signature of\n", (unsigned int)reply_seq_number)); - dump_data(10, server_sent_mac, 8); - } - return signing_good(inbuf, si, good, reply_seq_number, must_be_ok); -} - -/*********************************************************** - SMB signing - Simple implementation - free signing context -************************************************************/ - -static void simple_free_signing_context(struct smb_sign_info *si) -{ - struct smb_basic_signing_context *data = - (struct smb_basic_signing_context *)si->signing_context; - struct outstanding_packet_lookup *list; - struct outstanding_packet_lookup *next; - - for (list = data->outstanding_packet_list; list; list = next) { - next = list->next; - DLIST_REMOVE(data->outstanding_packet_list, list); - SAFE_FREE(list); - } - - data_blob_free(&data->mac_key); - - SAFE_FREE(si->signing_context); - - return; -} - -/*********************************************************** - SMB signing - Simple implementation - setup the MAC key. -************************************************************/ - -bool cli_simple_set_signing(struct cli_state *cli, - const DATA_BLOB user_session_key, - const DATA_BLOB response) -{ - struct smb_basic_signing_context *data; - - if (!user_session_key.length) - return False; - - if (!cli_set_smb_signing_common(cli)) { - return False; - } - - if (!set_smb_signing_real_common(&cli->sign_info)) { - return False; - } - - data = SMB_XMALLOC_P(struct smb_basic_signing_context); - memset(data, '\0', sizeof(*data)); - - cli->sign_info.signing_context = data; - - data->mac_key = data_blob(NULL, response.length + user_session_key.length); - - memcpy(&data->mac_key.data[0], user_session_key.data, user_session_key.length); - - DEBUG(10, ("cli_simple_set_signing: user_session_key\n")); - dump_data(10, user_session_key.data, user_session_key.length); - - if (response.length) { - memcpy(&data->mac_key.data[user_session_key.length],response.data, response.length); - DEBUG(10, ("cli_simple_set_signing: response_data\n")); - dump_data(10, response.data, response.length); - } else { - DEBUG(10, ("cli_simple_set_signing: NULL response_data\n")); - } - - dump_data_pw("MAC ssession key is:\n", data->mac_key.data, data->mac_key.length); - - /* Initialise the sequence number */ - data->send_seq_num = 0; - - /* Initialise the list of outstanding packets */ - data->outstanding_packet_list = NULL; - - cli->sign_info.sign_outgoing_message = client_sign_outgoing_message; - cli->sign_info.check_incoming_message = client_check_incoming_message; - cli->sign_info.free_signing_context = simple_free_signing_context; - - return True; -} - -/*********************************************************** - SMB signing - TEMP implementation - calculate a MAC to send. -************************************************************/ - -static void temp_sign_outgoing_message(char *outbuf, struct smb_sign_info *si) -{ - /* mark the packet as signed - BEFORE we sign it...*/ - mark_packet_signed(outbuf); - - /* I wonder what BSRSPYL stands for - but this is what MS - actually sends! */ - memcpy(&outbuf[smb_ss_field], "BSRSPYL ", 8); - return; -} - -/*********************************************************** - SMB signing - TEMP implementation - check a MAC sent by server. -************************************************************/ - -static bool temp_check_incoming_message(const char *inbuf, - struct smb_sign_info *si, bool foo) -{ - return True; -} - -/*********************************************************** - SMB signing - TEMP implementation - free signing context -************************************************************/ - -static void temp_free_signing_context(struct smb_sign_info *si) -{ - return; -} - -/*********************************************************** - SMB signing - NULL implementation - setup the MAC key. -************************************************************/ - -bool cli_null_set_signing(struct cli_state *cli) -{ - return null_set_signing(&cli->sign_info); -} - -/*********************************************************** - SMB signing - temp implementation - setup the MAC key. -************************************************************/ - -bool cli_temp_set_signing(struct cli_state *cli) -{ - if (!cli_set_smb_signing_common(cli)) { - return False; - } - - cli->sign_info.signing_context = NULL; - - cli->sign_info.sign_outgoing_message = temp_sign_outgoing_message; - cli->sign_info.check_incoming_message = temp_check_incoming_message; - cli->sign_info.free_signing_context = temp_free_signing_context; - - return True; -} - -void cli_free_signing_context(struct cli_state *cli) -{ - free_signing_context(&cli->sign_info); -} - -/** - * Sign a packet with the current mechanism - */ - -void cli_calculate_sign_mac(struct cli_state *cli, char *buf) -{ - cli->sign_info.sign_outgoing_message(buf, &cli->sign_info); -} - -/** - * Check a packet with the current mechanism - * @return False if we had an established signing connection - * which had a bad checksum, True otherwise. - */ - -bool cli_check_sign_mac(struct cli_state *cli, char *buf) -{ - if (!cli->sign_info.check_incoming_message(buf, &cli->sign_info, True)) { - free_signing_context(&cli->sign_info); - return False; - } - return True; -} - -/*********************************************************** - Enter trans/trans2/nttrans state. -************************************************************/ - -bool client_set_trans_sign_state_on(struct cli_state *cli, uint16 mid) -{ - struct smb_sign_info *si = &cli->sign_info; - struct smb_basic_signing_context *data = (struct smb_basic_signing_context *)si->signing_context; - - if (!si->doing_signing) { - return True; - } - - if (!data) { - return False; - } - - if (!set_sequence_can_delete_flag(&data->outstanding_packet_list, mid, False)) { - return False; - } - - return True; -} - -/*********************************************************** - Leave trans/trans2/nttrans state. -************************************************************/ - -bool client_set_trans_sign_state_off(struct cli_state *cli, uint16 mid) -{ - uint32 reply_seq_num; - struct smb_sign_info *si = &cli->sign_info; - struct smb_basic_signing_context *data = (struct smb_basic_signing_context *)si->signing_context; - - if (!si->doing_signing) { - return True; - } - - if (!data) { - return False; - } - - if (!set_sequence_can_delete_flag(&data->outstanding_packet_list, mid, True)) { - return False; - } - - /* Now delete the stored mid entry. */ - if (!get_sequence_for_reply(&data->outstanding_packet_list, mid, &reply_seq_num)) { - return False; - } - - return True; -} - -/*********************************************************** - Is client signing on ? -************************************************************/ - -bool client_is_signing_on(struct cli_state *cli) -{ - struct smb_sign_info *si = &cli->sign_info; - return si->doing_signing; -} - -/*********************************************************** - SMB signing - Server implementation - send the MAC. -************************************************************/ - -static void srv_sign_outgoing_message(char *outbuf, struct smb_sign_info *si) -{ - unsigned char calc_md5_mac[16]; - struct smb_basic_signing_context *data = - (struct smb_basic_signing_context *)si->signing_context; - uint32 send_seq_number = data->send_seq_num-1; - uint16 mid; - - if (!si->doing_signing) { - return; - } - - /* JRA Paranioa test - we should be able to get rid of this... */ - if (smb_len(outbuf) < (smb_ss_field + 8 - 4)) { - DEBUG(1, ("srv_sign_outgoing_message: Logic error. Can't send signature on short packet! smb_len = %u\n", - smb_len(outbuf) )); - abort(); - } - - /* mark the packet as signed - BEFORE we sign it...*/ - mark_packet_signed(outbuf); - - mid = SVAL(outbuf, smb_mid); - - /* See if this is a reply for a deferred packet. */ - get_sequence_for_reply(&data->outstanding_packet_list, mid, &send_seq_number); - - simple_packet_signature(data, (const unsigned char *)outbuf, send_seq_number, calc_md5_mac); - - DEBUG(10, ("srv_sign_outgoing_message: seq %u: sent SMB signature of\n", (unsigned int)send_seq_number)); - dump_data(10, calc_md5_mac, 8); - - memcpy(&outbuf[smb_ss_field], calc_md5_mac, 8); - -/* cli->outbuf[smb_ss_field+2]=0; - Uncomment this to test if the remote client actually verifies signatures...*/ -} - -/*********************************************************** - SMB signing - Server implementation - check a MAC sent by server. -************************************************************/ - -static bool srv_check_incoming_message(const char *inbuf, - struct smb_sign_info *si, - bool must_be_ok) -{ - bool good; - struct smb_basic_signing_context *data = - (struct smb_basic_signing_context *)si->signing_context; - uint32 reply_seq_number = data->send_seq_num; - uint32 saved_seq; - unsigned char calc_md5_mac[16]; - unsigned char *server_sent_mac; - - if (!si->doing_signing) - return True; - - if (smb_len(inbuf) < (smb_ss_field + 8 - 4)) { - DEBUG(1, ("srv_check_incoming_message: Can't check signature on short packet! smb_len = %u\n", smb_len(inbuf))); - return False; - } - - /* We always increment the sequence number. */ - data->send_seq_num += 2; - - saved_seq = reply_seq_number; - simple_packet_signature(data, (const unsigned char *)inbuf, reply_seq_number, calc_md5_mac); - - server_sent_mac = (unsigned char *)&inbuf[smb_ss_field]; - good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0); - - if (!good) { - - if (saved_seq) { - DEBUG(0, ("srv_check_incoming_message: BAD SIG: seq %u wanted SMB signature of\n", - (unsigned int)saved_seq)); - dump_data(5, calc_md5_mac, 8); - - DEBUG(0, ("srv_check_incoming_message: BAD SIG: seq %u got SMB signature of\n", - (unsigned int)reply_seq_number)); - dump_data(5, server_sent_mac, 8); - } - -#if 1 /* JRATEST */ - { - int i; - reply_seq_number -= 5; - for (i = 0; i < 10; i++, reply_seq_number++) { - simple_packet_signature(data, (const unsigned char *)inbuf, reply_seq_number, calc_md5_mac); - if (memcmp(server_sent_mac, calc_md5_mac, 8) == 0) { - DEBUG(0,("srv_check_incoming_message: out of seq. seq num %u matches. \ -We were expecting seq %u\n", reply_seq_number, saved_seq )); - break; - } - } - } -#endif /* JRATEST */ - - } else { - DEBUG(10, ("srv_check_incoming_message: seq %u: (current is %u) got good SMB signature of\n", (unsigned int)reply_seq_number, (unsigned int)data->send_seq_num)); - dump_data(10, server_sent_mac, 8); - } - - return (signing_good(inbuf, si, good, saved_seq, must_be_ok)); -} - -/*********************************************************** - SMB signing - server API's. -************************************************************/ - -static struct smb_sign_info srv_sign_info = { - null_sign_outgoing_message, - null_check_incoming_message, - null_free_signing_context, - NULL, - False, - False, - False, - False -}; - -/*********************************************************** - Turn signing off or on for oplock break code. -************************************************************/ - -bool srv_oplock_set_signing(bool onoff) -{ - bool ret = srv_sign_info.doing_signing; - srv_sign_info.doing_signing = onoff; - return ret; -} - -/*********************************************************** - Called to validate an incoming packet from the client. -************************************************************/ - -bool srv_check_sign_mac(const char *inbuf, bool must_be_ok) -{ - /* Check if it's a non-session message. */ - if(CVAL(inbuf,0)) { - return True; - } - - return srv_sign_info.check_incoming_message(inbuf, &srv_sign_info, must_be_ok); -} - -/*********************************************************** - Called to sign an outgoing packet to the client. -************************************************************/ - -void srv_calculate_sign_mac(char *outbuf) -{ - /* Check if it's a non-session message. */ - if(CVAL(outbuf,0)) { - return; - } - - srv_sign_info.sign_outgoing_message(outbuf, &srv_sign_info); -} - -/*********************************************************** - Called by server to defer an outgoing packet. -************************************************************/ - -void srv_defer_sign_response(uint16 mid) -{ - struct smb_basic_signing_context *data; - - if (!srv_sign_info.doing_signing) - return; - - data = (struct smb_basic_signing_context *)srv_sign_info.signing_context; - - if (!data) - return; - - /* - * Ensure we only store this mid reply once... - */ - - store_sequence_for_reply(&data->outstanding_packet_list, mid, - data->send_seq_num-1); -} - -/*********************************************************** - Called to remove sequence records when a deferred packet is - cancelled by mid. This should never find one.... -************************************************************/ - -void srv_cancel_sign_response(uint16 mid, bool cancel) -{ - struct smb_basic_signing_context *data; - uint32 dummy_seq; - - if (!srv_sign_info.doing_signing) - return; - - data = (struct smb_basic_signing_context *)srv_sign_info.signing_context; - - if (!data) - return; - - DEBUG(10,("srv_cancel_sign_response: for mid %u\n", (unsigned int)mid )); - - while (get_sequence_for_reply(&data->outstanding_packet_list, mid, &dummy_seq)) - ; - - /* cancel doesn't send a reply so doesn't burn a sequence number. */ - if (cancel) { - data->send_seq_num -= 1; - } -} - -/*********************************************************** - Called by server negprot when signing has been negotiated. -************************************************************/ - -void srv_set_signing_negotiated(void) -{ - srv_sign_info.allow_smb_signing = True; - srv_sign_info.negotiated_smb_signing = True; - if (lp_server_signing() == Required) - srv_sign_info.mandatory_signing = True; - - srv_sign_info.sign_outgoing_message = temp_sign_outgoing_message; - srv_sign_info.check_incoming_message = temp_check_incoming_message; - srv_sign_info.free_signing_context = temp_free_signing_context; -} - -/*********************************************************** - Returns whether signing is active. We can't use sendfile or raw - reads/writes if it is. -************************************************************/ - -bool srv_is_signing_active(void) -{ - return srv_sign_info.doing_signing; -} - - -/*********************************************************** - Returns whether signing is negotiated. We can't use it unless it was - in the negprot. -************************************************************/ - -bool srv_is_signing_negotiated(void) -{ - return srv_sign_info.negotiated_smb_signing; -} - -/*********************************************************** - Returns whether signing is actually happening -************************************************************/ - -bool srv_signing_started(void) -{ - struct smb_basic_signing_context *data; - - if (!srv_sign_info.doing_signing) { - return False; - } - - data = (struct smb_basic_signing_context *)srv_sign_info.signing_context; - if (!data) - return False; - - if (data->send_seq_num == 0) { - return False; - } - - return True; -} - -/*********************************************************** - Turn on signing from this packet onwards. -************************************************************/ - -void srv_set_signing(const DATA_BLOB user_session_key, const DATA_BLOB response) -{ - struct smb_basic_signing_context *data; - - if (!user_session_key.length) - return; - - if (!srv_sign_info.negotiated_smb_signing && !srv_sign_info.mandatory_signing) { - DEBUG(5,("srv_set_signing: signing negotiated = %u, mandatory_signing = %u. Not allowing smb signing.\n", - (unsigned int)srv_sign_info.negotiated_smb_signing, - (unsigned int)srv_sign_info.mandatory_signing )); - return; - } - - /* Once we've turned on, ignore any more sessionsetups. */ - if (srv_sign_info.doing_signing) { - return; - } - - if (srv_sign_info.free_signing_context) - srv_sign_info.free_signing_context(&srv_sign_info); - - srv_sign_info.doing_signing = True; - - data = SMB_XMALLOC_P(struct smb_basic_signing_context); - memset(data, '\0', sizeof(*data)); - - srv_sign_info.signing_context = data; - - data->mac_key = data_blob(NULL, response.length + user_session_key.length); - - memcpy(&data->mac_key.data[0], user_session_key.data, user_session_key.length); - if (response.length) - memcpy(&data->mac_key.data[user_session_key.length],response.data, response.length); - - dump_data_pw("MAC ssession key is:\n", data->mac_key.data, data->mac_key.length); - - DEBUG(3,("srv_set_signing: turning on SMB signing: signing negotiated = %s, mandatory_signing = %s.\n", - BOOLSTR(srv_sign_info.negotiated_smb_signing), - BOOLSTR(srv_sign_info.mandatory_signing) )); - - /* Initialise the sequence number */ - data->send_seq_num = 0; - - /* Initialise the list of outstanding packets */ - data->outstanding_packet_list = NULL; - - srv_sign_info.sign_outgoing_message = srv_sign_outgoing_message; - srv_sign_info.check_incoming_message = srv_check_incoming_message; - srv_sign_info.free_signing_context = simple_free_signing_context; -} -- cgit From 2654653f55ed5744cc9fca6a79127386f55425e1 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 9 Mar 2009 08:42:05 +0100 Subject: s3:libsmb: add a much simplified smb_siging infrastructure It's the job of the caller to maintain the seqnum/mid mapping. Hopefully we can use this code in s4 later too. metze --- source3/libsmb/smb_signing.c | 370 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 370 insertions(+) create mode 100644 source3/libsmb/smb_signing.c (limited to 'source3/libsmb/smb_signing.c') diff --git a/source3/libsmb/smb_signing.c b/source3/libsmb/smb_signing.c new file mode 100644 index 0000000000..32d2883965 --- /dev/null +++ b/source3/libsmb/smb_signing.c @@ -0,0 +1,370 @@ +/* + Unix SMB/CIFS implementation. + SMB Signing Code + Copyright (C) Jeremy Allison 2003. + Copyright (C) Andrew Bartlett 2002-2003 + Copyright (C) Stefan Metzmacher 2009 + + 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 3 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, see . +*/ + +#include "includes.h" + +/* Used by the SMB signing functions. */ + +struct smb_signing_state { + /* is signing localy allowed */ + bool allowed; + + /* is signing localy mandatory */ + bool mandatory; + + /* is signing negotiated by the peer */ + bool negotiated; + + /* send BSRSPYL signatures */ + bool bsrspyl; + + bool active; /* Have I ever seen a validly signed packet? */ + + /* mac_key.length > 0 means signing is started */ + DATA_BLOB mac_key; + + /* the next expected seqnum */ + uint32_t seqnum; +}; + +static void smb_signing_reset_info(struct smb_signing_state *si) +{ + si->active = false; + si->bsrspyl = false; + data_blob_free(&si->mac_key); + si->seqnum = 0; +} + +struct smb_signing_state *smb_signing_init(TALLOC_CTX *mem_ctx, + bool allowed, + bool mandatory) +{ + struct smb_signing_state *si; + + si = talloc_zero(mem_ctx, struct smb_signing_state); + if (si == NULL) { + return NULL; + } + + if (mandatory) { + allowed = true; + } + + si->allowed = allowed; + si->mandatory = mandatory; + + return si; +} + +static bool smb_signing_good(struct smb_signing_state *si, + bool good, uint32_t seq) +{ + if (good) { + if (!si->active) { + si->active = true; + } + return true; + } + + if (!si->mandatory && !si->active) { + /* Non-mandatory signing - just turn off if this is the first bad packet.. */ + DEBUG(5, ("smb_signing_good: signing negotiated but not required and peer\n" + "isn't sending correct signatures. Turning off.\n")); + smb_signing_reset_info(si); + return true; + } + + /* Mandatory signing or bad packet after signing started - fail and disconnect. */ + DEBUG(0, ("smb_signing_good: BAD SIG: seq %u\n", (unsigned int)seq)); + return false; +} + +static void smb_signing_md5(const DATA_BLOB *mac_key, + const uint8_t *buf, uint32_t seq_number, + uint8_t calc_md5_mac[16]) +{ + const size_t offset_end_of_sig = (smb_ss_field + 8); + uint8_t sequence_buf[8]; + struct MD5Context md5_ctx; + + /* + * Firstly put the sequence number into the first 4 bytes. + * and zero out the next 4 bytes. + * + * We do this here, to avoid modifying the packet. + */ + + DEBUG(10,("smb_signing_md5: sequence number %u\n", seq_number )); + + SIVAL(sequence_buf, 0, seq_number); + SIVAL(sequence_buf, 4, 0); + + /* Calculate the 16 byte MAC - but don't alter the data in the + incoming packet. + + This makes for a bit of fussing about, but it's not too bad. + */ + MD5Init(&md5_ctx); + + /* intialise with the key */ + MD5Update(&md5_ctx, mac_key->data, mac_key->length); + + /* copy in the first bit of the SMB header */ + MD5Update(&md5_ctx, buf + 4, smb_ss_field - 4); + + /* copy in the sequence number, instead of the signature */ + MD5Update(&md5_ctx, sequence_buf, sizeof(sequence_buf)); + + /* copy in the rest of the packet in, skipping the signature */ + MD5Update(&md5_ctx, buf + offset_end_of_sig, + smb_len(buf) - (offset_end_of_sig - 4)); + + /* calculate the MD5 sig */ + MD5Final(calc_md5_mac, &md5_ctx); +} + +uint32_t smb_signing_next_seqnum(struct smb_signing_state *si, bool oneway) +{ + uint32_t seqnum; + + if (si->mac_key.length == 0) { + return 0; + } + + seqnum = si->seqnum; + if (oneway) { + si->seqnum += 1; + } else { + si->seqnum += 2; + } + + return seqnum; +} + +void smb_signing_cancel_reply(struct smb_signing_state *si, bool oneway) +{ + if (si->mac_key.length == 0) { + return; + } + + if (oneway) { + si->seqnum -= 1; + } else { + si->seqnum -= 2; + } +} + +void smb_signing_sign_pdu(struct smb_signing_state *si, + uint8_t *outbuf, uint32_t seqnum) +{ + uint8_t calc_md5_mac[16]; + uint16_t flags2; + + if (si->mac_key.length == 0) { + if (!si->bsrspyl) { + return; + } + } + + /* JRA Paranioa test - we should be able to get rid of this... */ + if (smb_len(outbuf) < (smb_ss_field + 8 - 4)) { + DEBUG(1,("smb_signing_sign_pdu: Logic error. " + "Can't check signature on short packet! smb_len = %u\n", + smb_len(outbuf))); + abort(); + } + + /* mark the packet as signed - BEFORE we sign it...*/ + flags2 = SVAL(outbuf,smb_flg2); + flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES; + SSVAL(outbuf, smb_flg2, flags2); + + if (si->bsrspyl) { + /* I wonder what BSRSPYL stands for - but this is what MS + actually sends! */ + memcpy(calc_md5_mac, "BSRSPYL ", 8); + } else { + smb_signing_md5(&si->mac_key, outbuf, + seqnum, calc_md5_mac); + } + + DEBUG(10, ("smb_signing_sign_pdu: sent SMB signature of\n")); + dump_data(10, calc_md5_mac, 8); + + memcpy(&outbuf[smb_ss_field], calc_md5_mac, 8); + +/* outbuf[smb_ss_field+2]=0; + Uncomment this to test if the remote server actually verifies signatures...*/ +} + +bool smb_signing_check_pdu(struct smb_signing_state *si, + const uint8_t *inbuf, uint32_t seqnum) +{ + bool good; + uint8_t calc_md5_mac[16]; + const uint8_t *reply_sent_mac; + + if (si->mac_key.length == 0) { + return true; + } + + if (smb_len(inbuf) < (smb_ss_field + 8 - 4)) { + DEBUG(1,("smb_signing_check_pdu: Can't check signature " + "on short packet! smb_len = %u\n", + smb_len(inbuf))); + return False; + } + + smb_signing_md5(&si->mac_key, inbuf, + seqnum, calc_md5_mac); + + reply_sent_mac = &inbuf[smb_ss_field]; + good = (memcmp(reply_sent_mac, calc_md5_mac, 8) == 0); + + if (!good) { + int i; + const int sign_range = 5; + + DEBUG(5, ("smb_signing_check_pdu: BAD SIG: wanted SMB signature of\n")); + dump_data(5, calc_md5_mac, 8); + + DEBUG(5, ("smb_signing_check_pdu: BAD SIG: got SMB signature of\n")); + dump_data(5, reply_sent_mac, 8); + + for (i = -sign_range; i < sign_range; i++) { + smb_signing_md5(&si->mac_key, inbuf, + seqnum+i, calc_md5_mac); + if (memcmp(reply_sent_mac, calc_md5_mac, 8) == 0) { + DEBUG(0,("smb_signing_check_pdu: " + "out of seq. seq num %u matches. " + "We were expecting seq %u\n", + (unsigned int)seqnum+i, + (unsigned int)seqnum)); + break; + } + } + } else { + DEBUG(10, ("smb_signing_check_pdu: seq %u: " + "got good SMB signature of\n", + (unsigned int)seqnum)); + dump_data(10, reply_sent_mac, 8); + } + + return smb_signing_good(si, good, seqnum); +} + +bool smb_signing_set_bsrspyl(struct smb_signing_state *si) +{ + if (!si->negotiated) { + return false; + } + + if (si->active) { + return false; + } + + si->bsrspyl = true; + + return true; +} + +bool smb_signing_activate(struct smb_signing_state *si, + const DATA_BLOB user_session_key, + const DATA_BLOB response) +{ + size_t len; + off_t ofs; + + if (!user_session_key.length) { + return false; + } + + if (!si->negotiated) { + return false; + } + + if (si->active) { + return false; + } + + if (si->mac_key.length > 0) { + return false; + } + + smb_signing_reset_info(si); + + len = response.length + user_session_key.length; + si->mac_key = data_blob_talloc(si, NULL, len); + + ofs = 0; + memcpy(&si->mac_key.data[ofs], user_session_key.data, user_session_key.length); + + DEBUG(10, ("smb_signing_activate: user_session_key\n")); + dump_data(10, user_session_key.data, user_session_key.length); + + if (response.length) { + ofs = user_session_key.length; + memcpy(&si->mac_key.data[ofs], response.data, response.length); + DEBUG(10, ("smb_signing_activate: response_data\n")); + dump_data(10, response.data, response.length); + } else { + DEBUG(10, ("smb_signing_activate: NULL response_data\n")); + } + + dump_data_pw("smb_signing_activate: mac key is:\n", + si->mac_key.data, si->mac_key.length); + + /* Initialise the sequence number */ + si->seqnum = 2; + + return true; +} + +bool smb_signing_is_active(struct smb_signing_state *si) +{ + return si->active; +} + +bool smb_signing_is_allowed(struct smb_signing_state *si) +{ + return si->allowed; +} + +bool smb_signing_is_mandatory(struct smb_signing_state *si) +{ + return si->mandatory; +} + +bool smb_signing_set_negotiated(struct smb_signing_state *si) +{ + if (!si->allowed) { + return false; + } + + si->negotiated = true; + + return true; +} + +bool smb_signing_is_negotiated(struct smb_signing_state *si) +{ + return si->negotiated; +} -- cgit