Correct fix (removed the earlier band-aid) for what I thought was a signing
authorJeremy Allison <jra@samba.org>
Sat, 2 Aug 2003 00:29:45 +0000 (00:29 +0000)
committerJeremy Allison <jra@samba.org>
Sat, 2 Aug 2003 00:29:45 +0000 (00:29 +0000)
bug with w2k. Turns out that when we're doing a trans/trans2/nttrans call
the MID and send_sequence_number and reply_sequence_number must remain constant.
This was something we got very wrong in earlier versions of Samba. I can now
get a directory listing from WINNT\SYSTEM32 with the older earlier parameters
for clilist.c
This still needs to be fixed for the server side of Samba, client appears to
be working happily now (I'm doing a signed smbtar download of an entire W2K3
image to test this :-).
Jeremy.

source/libsmb/clientgen.c
source/libsmb/clilist.c
source/libsmb/clitrans.c
source/libsmb/smb_signing.c

index cdda2eb22476a2deba7b20d7d2a7768c0361d67a..bc5f1462cc248bfaf1039142bab8f96852812412 100644 (file)
@@ -157,6 +157,10 @@ BOOL cli_send_smb(struct cli_state *cli)
                }
                nwritten += ret;
        }
+       /* Increment the mid so we can tell between responses. */
+       cli->mid++;
+       if (!cli->mid)
+               cli->mid++;
        return True;
 }
 
index 2b5658270016097ab5b8f1f8403e3cbf578f4013..7822987ada80e21ebfb98c137fd248f3dd5f806d 100644 (file)
@@ -145,7 +145,11 @@ static int interpret_long_filename(struct cli_state *cli,
 int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute, 
                 void (*fn)(file_info *, const char *, void *), void *state)
 {
+#if 0
        int max_matches = 1366; /* Match W2k - was 512. */
+#else
+       int max_matches = 512;
+#endif
        int info_level;
        char *p, *p2;
        pstring mask;
@@ -207,8 +211,12 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
                                    &setup, 1, 0,           /* setup, length, max */
                                    param, param_len, 10,   /* param, length, max */
                                    NULL, 0, 
-                                   MIN(16384,cli->max_xmit) /* data, length, max. W2K server signing
-                                                               has a bug unless this matches what W2K uses. */
+#if 0
+                                   /* w2k value. */
+                                   MIN(16384,cli->max_xmit) /* data, length, max. */
+#else
+                                   cli->max_xmit           /* data, length, max. */
+#endif
                                    )) {
                        break;
                }
index 3d3cd427d7608f71d5514d175f2b5cdb0480e7f0..49897d0bb0a9423eb1c79113a0fcc83cc9ef1b90 100644 (file)
@@ -40,6 +40,7 @@ BOOL cli_send_trans(struct cli_state *cli, int trans,
        char *outdata,*outparam;
        char *p;
        int pipe_name_len=0;
+       uint16 mid;
 
        this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
        this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
@@ -49,6 +50,7 @@ BOOL cli_send_trans(struct cli_state *cli, int trans,
        SCVAL(cli->outbuf,smb_com,trans);
        SSVAL(cli->outbuf,smb_tid, cli->cnum);
        cli_setup_packet(cli);
+       mid = cli->mid;
 
        if (pipe_name) {
                pipe_name_len = clistr_push(cli, smb_buf(cli->outbuf), pipe_name, -1, STR_TERMINATE);
@@ -84,6 +86,8 @@ BOOL cli_send_trans(struct cli_state *cli, int trans,
        cli_setup_bcc(cli, outdata+this_ldata);
 
        show_msg(cli->outbuf);
+
+       cli_signing_trans_start(cli);
        if (!cli_send_smb(cli))
                return False;
 
@@ -122,6 +126,10 @@ BOOL cli_send_trans(struct cli_state *cli, int trans,
                                memcpy(outdata,data+tot_data,this_ldata);
                        cli_setup_bcc(cli, outdata+this_ldata);
                        
+                       /* Ensure this packet has the same MID as
+                        * the primary. Important in signing. JRA. */
+                       cli->mid = mid;
+
                        show_msg(cli->outbuf);
                        if (!cli_send_smb(cli))
                                return False;
@@ -292,6 +300,7 @@ BOOL cli_receive_trans(struct cli_state *cli,int trans,
                
        }
        
+       cli_signing_trans_stop(cli);
        return(True);
 }
 
@@ -309,6 +318,7 @@ BOOL cli_send_nt_trans(struct cli_state *cli,
        unsigned int i;
        unsigned int this_ldata,this_lparam;
        unsigned int tot_data=0,tot_param=0;
+       uint16 mid;
        char *outdata,*outparam;
 
        this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
@@ -319,6 +329,7 @@ BOOL cli_send_nt_trans(struct cli_state *cli,
        SCVAL(cli->outbuf,smb_com,SMBnttrans);
        SSVAL(cli->outbuf,smb_tid, cli->cnum);
        cli_setup_packet(cli);
+       mid = cli->mid;
 
        outparam = smb_buf(cli->outbuf)+3;
        outdata = outparam+this_lparam;
@@ -347,6 +358,7 @@ BOOL cli_send_nt_trans(struct cli_state *cli,
        cli_setup_bcc(cli, outdata+this_ldata);
 
        show_msg(cli->outbuf);
+       cli_signing_trans_start(cli);
        if (!cli_send_smb(cli))
                return False;
 
@@ -384,7 +396,12 @@ BOOL cli_send_nt_trans(struct cli_state *cli,
                                memcpy(outdata,data+tot_data,this_ldata);
                        cli_setup_bcc(cli, outdata+this_ldata);
                        
+                       /* Ensure this packet has the same MID as
+                        * the primary. Important in signing. JRA. */
+                       cli->mid = mid;
+
                        show_msg(cli->outbuf);
+
                        if (!cli_send_smb(cli))
                                return False;
                        
@@ -559,5 +576,6 @@ BOOL cli_receive_nt_trans(struct cli_state *cli,
                        break;
        }
        
+       cli_signing_trans_stop(cli);
        return(True);
 }
index 3feffe4c961a221484ff9891afdbe682c7d46d70..81e25cb67c8378262165204497a278c811810e59 100644 (file)
@@ -28,9 +28,17 @@ struct outstanding_packet_lookup {
        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;
+};
+
 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;
 };
 
@@ -261,6 +269,7 @@ 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;
 
        if (!si->doing_signing)
                return;
@@ -275,7 +284,12 @@ 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);
 
-       simple_packet_signature(data, outbuf, data->send_seq_num, calc_md5_mac);
+       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, outbuf, send_seq_num, calc_md5_mac);
 
        DEBUG(10, ("client_sign_outgoing_message: sent SMB signature of\n"));
        dump_data(10, calc_md5_mac, 8);
@@ -285,6 +299,9 @@ static void client_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
 /*     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),
@@ -313,9 +330,13 @@ static BOOL client_check_incoming_message(char *inbuf, struct smb_sign_info *si)
                return False;
        }
 
-       if (!get_sequence_for_reply(&data->outstanding_packet_list, 
+       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) ));
                return False;
        }
 
@@ -365,6 +386,10 @@ static void simple_free_signing_context(struct smb_sign_info *si)
        }
 
        data_blob_free(&data->mac_key);
+
+       if (data->trans_info)
+               SAFE_FREE(data->trans_info);
+
        SAFE_FREE(si->signing_context);
 
        return;
@@ -390,6 +415,7 @@ BOOL cli_simple_set_signing(struct cli_state *cli, const uchar user_session_key[
        }
 
        data = smb_xmalloc(sizeof(*data));
+       memset(data, '\0', sizeof(*data));
 
        cli->sign_info.signing_context = data;
        
@@ -421,6 +447,42 @@ BOOL cli_simple_set_signing(struct cli_state *cli, const uchar user_session_key[
        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)
+               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;
+}
+
+/***********************************************************
+ 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)
+               return;
+
+       if (data->trans_info)
+               SAFE_FREE(data->trans_info);
+
+       data->send_seq_num += 2;
+}
+
 /***********************************************************
  SMB signing - TEMP implementation - calculate a MAC to send.
 ************************************************************/
@@ -776,6 +838,7 @@ void srv_set_signing(const uchar user_session_key[16], const DATA_BLOB response)
        srv_sign_info.doing_signing = True;
 
        data = smb_xmalloc(sizeof(*data));
+       memset(data, '\0', sizeof(*data));
 
        srv_sign_info.signing_context = data;