r23784: use the GPLv3 boilerplate as recommended by the FSF and the license text
[tprouty/samba.git] / source / libsmb / smb_signing.c
index 2a53638d17603874a96bdcfe40ddad5624fe66fe..3964bfa534d42ffc140b2c38bad789baf0646e87 100644 (file)
@@ -6,7 +6,7 @@
    
    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
+   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,
    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.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 
 /* Lookup a packet's MID (multiplex id) and figure out it's sequence number */
 struct outstanding_packet_lookup {
-       uint16 mid;
-       uint32 reply_seq_num;
        struct outstanding_packet_lookup *prev, *next;
-};
-
-/* Store the data for an ongoing trans/trans2/nttrans operation. */
-struct trans_info_context {
        uint16 mid;
-       uint32 send_seq_num;
        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 trans_info_context *trans_info;
        struct outstanding_packet_lookup *outstanding_packet_list;
 };
 
-static void store_sequence_for_reply(struct outstanding_packet_lookup **list, 
+static BOOL store_sequence_for_reply(struct outstanding_packet_lookup **list, 
                                     uint16 mid, uint32 reply_seq_num)
 {
        struct outstanding_packet_lookup *t;
-       struct outstanding_packet_lookup *tmp;
-       
-       t = smb_xmalloc(sizeof(*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);
 
-       DLIST_ADD_END(*list, t, tmp);
        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 <fran@cis.uab.edu>.
+        */
+
+       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,
@@ -69,8 +78,23 @@ static BOOL get_sequence_for_reply(struct outstanding_packet_lookup **list,
                        *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 ));
-                       DLIST_REMOVE(*list, t);
-                       SAFE_FREE(t);
+                       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;
                }
        }
@@ -83,6 +107,10 @@ static BOOL get_sequence_for_reply(struct outstanding_packet_lookup **list,
 
 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;
@@ -142,7 +170,7 @@ static void null_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
  SMB signing - NULL implementation - check a MAC sent by server.
 ************************************************************/
 
-static BOOL null_check_incoming_message(char *inbuf, struct smb_sign_info *si)
+static BOOL null_check_incoming_message(char *inbuf, struct smb_sign_info *si, BOOL must_be_ok)
 {
        return True;
 }
@@ -189,25 +217,39 @@ static void free_signing_context(struct smb_sign_info *si)
 }
 
 
-static BOOL signing_good(char *inbuf, struct smb_sign_info *si, BOOL good, uint32 seq) 
+static BOOL signing_good(char *inbuf, struct smb_sign_info *si, BOOL good, uint32 seq, BOOL must_be_ok
 {
-       if (good && !si->doing_signing) {
-               si->doing_signing = True;
-       }
+       if (good) {
 
-       if (!good) {
-               if (si->doing_signing) {
-                       struct smb_basic_signing_context *data = si->signing_context;
+               if (!si->doing_signing) {
+                       si->doing_signing = True;
+               }
+               
+               if (!si->seen_valid) {
+                       si->seen_valid = True;
+               }
 
-                       /* W2K sends a bad first signature but the sign engine is on.... JRA. */
-                       if (data->send_seq_num > 1)
-                               DEBUG(1, ("signing_good: SMB signature check failed on seq %u!\n",
-                                                       (unsigned int)seq ));
+       } else {
+               if (!si->mandatory_signing && !si->seen_valid) {
 
-                       return False;
-               } else {
-                       DEBUG(3, ("signing_good: Peer did not sign reply correctly\n"));
+                       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;
                }
        }
@@ -225,6 +267,10 @@ static void simple_packet_signature(struct smb_basic_signing_context *data,
        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.
@@ -246,8 +292,17 @@ static void simple_packet_signature(struct smb_basic_signing_context *data,
        MD5Init(&md5_ctx);
 
        /* intialise with the key */
-       MD5Update(&md5_ctx, data->mac_key.data, 
-                 data->mac_key.length); 
+       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 <nalin@redhat.com> */
+       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);
@@ -271,8 +326,8 @@ static void simple_packet_signature(struct smb_basic_signing_context *data,
 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 = si->signing_context;
-       uint32 send_seq_num;
+       struct smb_basic_signing_context *data =
+               (struct smb_basic_signing_context *)si->signing_context;
 
        if (!si->doing_signing)
                return;
@@ -287,43 +342,48 @@ static void client_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
        /* mark the packet as signed - BEFORE we sign it...*/
        mark_packet_signed(outbuf);
 
-       if (data->trans_info)
-               send_seq_num = data->trans_info->send_seq_num;
-       else
-               send_seq_num = data->send_seq_num;
-
-       simple_packet_signature(data, (const unsigned char *)outbuf, send_seq_num, calc_md5_mac);
+       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, (const char *)calc_md5_mac, 8);
+       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...*/
 
-       if (data->trans_info)
-               return;
-
-       data->send_seq_num++;
-       store_sequence_for_reply(&data->outstanding_packet_list, 
-                                SVAL(outbuf,smb_mid), data->send_seq_num);
-       data->send_seq_num++;
+       /* 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(char *inbuf, struct smb_sign_info *si)
+static BOOL client_check_incoming_message(char *inbuf, struct smb_sign_info *si, BOOL must_be_ok)
 {
        BOOL good;
        uint32 reply_seq_number;
-       uint32 saved_seq;
        unsigned char calc_md5_mac[16];
        unsigned char *server_sent_mac;
 
-       struct smb_basic_signing_context *data = si->signing_context;
+       struct smb_basic_signing_context *data =
+               (struct smb_basic_signing_context *)si->signing_context;
 
        if (!si->doing_signing)
                return True;
@@ -333,36 +393,32 @@ static BOOL client_check_incoming_message(char *inbuf, struct smb_sign_info *si)
                return False;
        }
 
-       if (data->trans_info) {
-               reply_seq_number = data->trans_info->reply_seq_num;
-       } else if (!get_sequence_for_reply(&data->outstanding_packet_list, 
-                                   SVAL(inbuf, smb_mid), &reply_seq_number)) {
-               DEBUG(1, ("client_check_incoming_message: failed to get sequence number %u for reply.\n",
-                                       (unsigned int) SVAL(inbuf, smb_mid) ));
+       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;
        }
 
-       saved_seq = reply_seq_number;
-       simple_packet_signature(data, (const unsigned char *)inbuf, reply_seq_number, calc_md5_mac);
+       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, (const char *)calc_md5_mac, 8);
+               dump_data(5, calc_md5_mac, 8);
                
                DEBUG(5, ("client_check_incoming_message: BAD SIG: got SMB signature of\n"));
-               dump_data(5, (const char *)server_sent_mac, 8);
+               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);
+                       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, saved_seq ));
+We were expecting seq %u\n", reply_seq_number+i, reply_seq_number ));
                                        break;
                                }
                        }
@@ -371,9 +427,9 @@ We were expecting seq %u\n", reply_seq_number, saved_seq ));
 
        } else {
                DEBUG(10, ("client_check_incoming_message: seq %u: got good SMB signature of\n", (unsigned int)reply_seq_number));
-               dump_data(10, (const char *)server_sent_mac, 8);
+               dump_data(10, server_sent_mac, 8);
        }
-       return signing_good(inbuf, si, good, saved_seq);
+       return signing_good(inbuf, si, good, reply_seq_number, must_be_ok);
 }
 
 /***********************************************************
@@ -382,20 +438,19 @@ We were expecting seq %u\n", reply_seq_number, saved_seq ));
 
 static void simple_free_signing_context(struct smb_sign_info *si)
 {
-       struct smb_basic_signing_context *data = si->signing_context;
-       struct outstanding_packet_lookup *list = data->outstanding_packet_list;
+       struct smb_basic_signing_context *data =
+               (struct smb_basic_signing_context *)si->signing_context;
+       struct outstanding_packet_lookup *list;
+       struct outstanding_packet_lookup *next;
        
-       while (list) {
-               struct outstanding_packet_lookup *old_head = list;
-               DLIST_REMOVE(list, list);
-               SAFE_FREE(old_head);
+       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);
 
-       if (data->trans_info)
-               SAFE_FREE(data->trans_info);
-
        SAFE_FREE(si->signing_context);
 
        return;
@@ -405,7 +460,9 @@ static void simple_free_signing_context(struct smb_sign_info *si)
  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)
+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;
 
@@ -420,7 +477,7 @@ BOOL cli_simple_set_signing(struct cli_state *cli, const DATA_BLOB user_session_
                return False;
        }
 
-       data = smb_xmalloc(sizeof(*data));
+       data = SMB_XMALLOC_P(struct smb_basic_signing_context);
        memset(data, '\0', sizeof(*data));
 
        cli->sign_info.signing_context = data;
@@ -430,12 +487,12 @@ BOOL cli_simple_set_signing(struct cli_state *cli, const DATA_BLOB user_session_
        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, (const char *)user_session_key.data, user_session_key.length);
+       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, (const char *)response.data, response.length);
+               dump_data(10, response.data, response.length);
        } else {
                DEBUG(10, ("cli_simple_set_signing: NULL response_data\n"));
        }
@@ -455,49 +512,6 @@ BOOL cli_simple_set_signing(struct cli_state *cli, const DATA_BLOB user_session_
        return True;
 }
 
-/***********************************************************
- Tell client code we are in a multiple trans reply state.
-************************************************************/
-
-void cli_signing_trans_start(struct cli_state *cli)
-{
-       struct smb_basic_signing_context *data = cli->sign_info.signing_context;
-
-       if (!cli->sign_info.doing_signing || !data)
-               return;
-
-       data->trans_info = smb_xmalloc(sizeof(struct trans_info_context));
-       ZERO_STRUCTP(data->trans_info);
-
-       data->trans_info->send_seq_num = data->send_seq_num;
-       data->trans_info->mid = SVAL(cli->outbuf,smb_mid);
-       data->trans_info->reply_seq_num = data->send_seq_num+1;
-
-       DEBUG(10,("cli_signing_trans_start: storing mid = %u, reply_seq_num = %u, send_seq_num = %u \
-data->send_seq_num = %u\n",
-                       (unsigned int)data->trans_info->mid,
-                       (unsigned int)data->trans_info->reply_seq_num,
-                       (unsigned int)data->trans_info->send_seq_num,
-                       (unsigned int)data->send_seq_num ));
-}
-
-/***********************************************************
- Tell client code we are out of a multiple trans reply state.
-************************************************************/
-
-void cli_signing_trans_stop(struct cli_state *cli)
-{
-       struct smb_basic_signing_context *data = cli->sign_info.signing_context;
-
-       if (!cli->sign_info.doing_signing || !data)
-               return;
-
-       SAFE_FREE(data->trans_info);
-       data->trans_info = NULL;
-
-       data->send_seq_num += 2;
-}
-
 /***********************************************************
  SMB signing - TEMP implementation - calculate a MAC to send.
 ************************************************************/
@@ -517,7 +531,7 @@ static void temp_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
  SMB signing - TEMP implementation - check a MAC sent by server.
 ************************************************************/
 
-static BOOL temp_check_incoming_message(char *inbuf, struct smb_sign_info *si)
+static BOOL temp_check_incoming_message(char *inbuf, struct smb_sign_info *si, BOOL foo)
 {
        return True;
 }
@@ -581,13 +595,77 @@ void cli_calculate_sign_mac(struct cli_state *cli)
  
 BOOL cli_check_sign_mac(struct cli_state *cli) 
 {
-       if (!cli->sign_info.check_incoming_message(cli->inbuf, &cli->sign_info)) {
+       if (!cli->sign_info.check_incoming_message(cli->inbuf, &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.
 ************************************************************/
@@ -595,9 +673,9 @@ BOOL cli_check_sign_mac(struct cli_state *cli)
 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 = si->signing_context;
-       uint32 send_seq_number = data->send_seq_num;
-       BOOL was_deferred_packet = False;
+       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) {
@@ -617,68 +695,32 @@ static void srv_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
        mid = SVAL(outbuf, smb_mid);
 
        /* See if this is a reply for a deferred packet. */
-       was_deferred_packet = get_sequence_for_reply(&data->outstanding_packet_list, mid, &send_seq_number);
-
-       if (data->trans_info && (data->trans_info->mid == mid)) {
-               /* This is a reply in a trans stream. Use the sequence
-                * number associated with the stream mid. */
-               send_seq_number = data->trans_info->send_seq_num;
-       }
+       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, (const char *)calc_md5_mac, 8);
+       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...*/
-
-       /* Don't mess with the sequence number for a deferred packet. */
-       if (was_deferred_packet) {
-               return;
-       }
-
-       if (!data->trans_info) {
-               /* Always increment if not in a trans stream. */
-               data->send_seq_num++;
-       } else if ((data->trans_info->send_seq_num == data->send_seq_num) || (data->trans_info->mid != mid)) {
-               /* Increment if this is the first reply in a trans stream or a
-                * packet that doesn't belong to this stream (different mid). */
-               data->send_seq_num++;
-       }
-}
-
-/***********************************************************
- Is an incoming packet an oplock break reply ?
-************************************************************/
-
-static BOOL is_oplock_break(char *inbuf)
-{
-       if (CVAL(inbuf,smb_com) != SMBlockingX)
-               return False;
-
-       if (!(CVAL(inbuf,smb_vwv3) & LOCKING_ANDX_OPLOCK_RELEASE))
-               return False;
-
-       DEBUG(10,("is_oplock_break: Packet is oplock break\n"));
-       return True;
 }
 
 /***********************************************************
  SMB signing - Server implementation - check a MAC sent by server.
 ************************************************************/
 
-static BOOL srv_check_incoming_message(char *inbuf, struct smb_sign_info *si)
+static BOOL srv_check_incoming_message(char *inbuf, struct smb_sign_info *si, BOOL must_be_ok)
 {
        BOOL good;
-       struct smb_basic_signing_context *data = si->signing_context;
+       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;
-       uint mid;
 
        if (!si->doing_signing)
                return True;
@@ -688,25 +730,8 @@ static BOOL srv_check_incoming_message(char *inbuf, struct smb_sign_info *si)
                return False;
        }
 
-       mid = SVAL(inbuf, smb_mid);
-
-       /* Is this part of a trans stream ? */
-       if (data->trans_info && (data->trans_info->mid == mid)) {
-               /* If so we don't increment the sequence. */
-               reply_seq_number = data->trans_info->reply_seq_num;
-       } else {
-               /* We always increment the sequence number. */
-               data->send_seq_num++;
-
-               /* If we get an asynchronous oplock break reply and there
-                * isn't a reply pending we need to re-sync the sequence
-                * number.
-                */
-               if (is_oplock_break(inbuf)) {
-                       DEBUG(10,("srv_check_incoming_message: oplock break at seq num %u\n", data->send_seq_num));
-                       data->send_seq_num++;
-               }
-       }
+       /* 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);
@@ -716,14 +741,16 @@ static BOOL srv_check_incoming_message(char *inbuf, struct smb_sign_info *si)
        
        if (!good) {
 
-               DEBUG(5, ("srv_check_incoming_message: BAD SIG: seq %u wanted SMB signature of\n",
+               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, (const char *)calc_md5_mac, 8);
-               
-               DEBUG(5, ("srv_check_incoming_message: BAD SIG: seq %u got SMB signature of\n",
-                                       (unsigned int)saved_seq));
-               dump_data(5, (const char *)server_sent_mac, 8);
+                       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;
@@ -741,26 +768,10 @@ We were expecting seq %u\n", reply_seq_number, saved_seq ));
 
        } 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, (const char *)server_sent_mac, 8);
+               dump_data(10, server_sent_mac, 8);
        }
 
-       if (!signing_good(inbuf, si, good, saved_seq)) {
-               if (si->mandatory_signing) {
-                       /* Mandatory signing - fail and disconnect. */
-                       return False;
-               } else {
-                       /* Non-mandatory signing - just turn off. */
-                       DEBUG(5, ("srv_check_incoming_message: signing negotiated but not required and client \
-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 {
-               return True;
-       }
+       return (signing_good(inbuf, si, good, saved_seq, must_be_ok));
 }
 
 /***********************************************************
@@ -793,13 +804,14 @@ BOOL srv_oplock_set_signing(BOOL onoff)
  Called to validate an incoming packet from the client.
 ************************************************************/
 
-BOOL srv_check_sign_mac(char *inbuf)
+BOOL srv_check_sign_mac(char *inbuf, BOOL must_be_ok)
 {
        /* Check if it's a session keepalive. */
-       if(CVAL(inbuf,0) == SMBkeepalive)
+       if(CVAL(inbuf,0) == SMBkeepalive) {
                return True;
+       }
 
-       return srv_sign_info.check_incoming_message(inbuf, &srv_sign_info);
+       return srv_sign_info.check_incoming_message(inbuf, &srv_sign_info, must_be_ok);
 }
 
 /***********************************************************
@@ -809,9 +821,9 @@ BOOL srv_check_sign_mac(char *inbuf)
 void srv_calculate_sign_mac(char *outbuf)
 {
        /* Check if it's a session keepalive. */
-       /* JRA Paranioa test - do we ever generate these in the server ? */
-       if(CVAL(outbuf,0) == SMBkeepalive)
+       if(CVAL(outbuf,0) == SMBkeepalive) {
                return;
+       }
 
        srv_sign_info.sign_outgoing_message(outbuf, &srv_sign_info);
 }
@@ -832,9 +844,12 @@ void srv_defer_sign_response(uint16 mid)
        if (!data)
                return;
 
-       store_sequence_for_reply(&data->outstanding_packet_list, 
-                                mid, data->send_seq_num);
-       data->send_seq_num++;
+       /*
+        * Ensure we only store this mid reply once...
+        */
+
+       store_sequence_for_reply(&data->outstanding_packet_list, mid,
+                                data->send_seq_num-1);
 }
 
 /***********************************************************
@@ -859,6 +874,9 @@ void srv_cancel_sign_response(uint16 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. */
+       data->send_seq_num -= 1;
 }
 
 /***********************************************************
@@ -887,60 +905,38 @@ BOOL srv_is_signing_active(void)
        return srv_sign_info.doing_signing;
 }
 
+
 /***********************************************************
- Tell server code we are in a multiple trans reply state.
+ Returns whether signing is negotiated. We can't use it unless it was
+ in the negprot.  
 ************************************************************/
 
-void srv_signing_trans_start(uint16 mid)
+BOOL srv_is_signing_negotiated(void)
 {
-       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;
-
-       data->trans_info = smb_xmalloc(sizeof(struct trans_info_context));
-       ZERO_STRUCTP(data->trans_info);
-
-       data->trans_info->reply_seq_num = data->send_seq_num-1;
-       data->trans_info->mid = mid;
-       data->trans_info->send_seq_num = data->send_seq_num;
-
-       DEBUG(10,("srv_signing_trans_start: storing mid = %u, reply_seq_num = %u, send_seq_num = %u \
-data->send_seq_num = %u\n",
-                       (unsigned int)mid,
-                       (unsigned int)data->trans_info->reply_seq_num,
-                       (unsigned int)data->trans_info->send_seq_num,
-                       (unsigned int)data->send_seq_num ));
+       return srv_sign_info.negotiated_smb_signing;
 }
 
 /***********************************************************
- Tell server code we are out of a multiple trans reply state.
+ Returns whether signing is actually happening
 ************************************************************/
 
-void srv_signing_trans_stop(void)
+BOOL srv_signing_started(void)
 {
        struct smb_basic_signing_context *data;
 
-       if (!srv_sign_info.doing_signing)
-               return;
+       if (!srv_sign_info.doing_signing) {
+               return False;
+       }
 
        data = (struct smb_basic_signing_context *)srv_sign_info.signing_context;
-       if (!data || !data->trans_info)
-               return;
+       if (!data)
+               return False;
 
-       DEBUG(10,("srv_signing_trans_stop: removing mid = %u, reply_seq_num = %u, send_seq_num = %u \
-data->send_seq_num = %u\n",
-                       (unsigned int)data->trans_info->mid,
-                       (unsigned int)data->trans_info->reply_seq_num,
-                       (unsigned int)data->trans_info->send_seq_num,
-                       (unsigned int)data->send_seq_num ));
+       if (data->send_seq_num == 0) {
+               return False;
+       }
 
-       SAFE_FREE(data->trans_info);
-       data->trans_info = NULL;
+       return True;
 }
 
 /***********************************************************
@@ -971,7 +967,7 @@ void srv_set_signing(const DATA_BLOB user_session_key, const DATA_BLOB response)
        
        srv_sign_info.doing_signing = True;
 
-       data = smb_xmalloc(sizeof(*data));
+       data = SMB_XMALLOC_P(struct smb_basic_signing_context);
        memset(data, '\0', sizeof(*data));
 
        srv_sign_info.signing_context = data;