]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
smb1: implement WRITE_AND_CLOSE
authorVictor Julien <victor@inliniac.net>
Wed, 28 Feb 2018 17:38:33 +0000 (18:38 +0100)
committerVictor Julien <victor@inliniac.net>
Mon, 12 Mar 2018 14:34:42 +0000 (15:34 +0100)
rust/src/smb/smb1.rs
rust/src/smb/smb1_records.rs

index c738d3a069ccb4865a3aa8c74a40b7d09ed85300..3ebf08373b712901cbc1eed0b03dc9cd46d6b67d 100644 (file)
@@ -60,6 +60,7 @@ pub const SMB1_COMMAND_WRITE_AND_UNLOCK:        u8 = 0x14;
 pub const SMB1_COMMAND_LOCKING_ANDX:            u8 = 0x24;
 pub const SMB1_COMMAND_TRANS:                   u8 = 0x25;
 pub const SMB1_COMMAND_ECHO:                    u8 = 0x2b;
+pub const SMB1_COMMAND_WRITE_AND_CLOSE:         u8 = 0x2c;
 pub const SMB1_COMMAND_READ_ANDX:               u8 = 0x2e;
 pub const SMB1_COMMAND_WRITE_ANDX:              u8 = 0x2f;
 pub const SMB1_COMMAND_TRANS2:                  u8 = 0x32;
@@ -99,6 +100,7 @@ pub fn smb1_command_string(c: u8) -> String {
         SMB1_COMMAND_WRITE_AND_UNLOCK   => "SMB1_COMMAND_WRITE_AND_UNLOCK",
         SMB1_COMMAND_LOCKING_ANDX       => "SMB1_COMMAND_LOCKING_ANDX",
         SMB1_COMMAND_ECHO               => "SMB1_COMMAND_ECHO",
+        SMB1_COMMAND_WRITE_AND_CLOSE    => "SMB1_COMMAND_WRITE_AND_CLOSE",
         SMB1_COMMAND_READ_ANDX          => "SMB1_COMMAND_READ_ANDX",
         SMB1_COMMAND_WRITE_ANDX         => "SMB1_COMMAND_WRITE_ANDX",
         SMB1_COMMAND_TRANS              => "SMB1_COMMAND_TRANS",
@@ -127,6 +129,46 @@ pub fn smb1_create_new_tx(_cmd: u8) -> bool {
 //    }
 }
 
+fn smb1_close_file(state: &mut SMBState, fid: &Vec<u8>)
+{
+    // we can have created 2 txs for a FID: one for reads
+    // and one for writes. So close both.
+    match state.get_file_tx_by_guid(&fid, STREAM_TOSERVER) {
+        Some((tx, files, flags)) => {
+            SCLogDebug!("found tx {}", tx.id);
+            if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data {
+                if !tx.request_done {
+                    SCLogDebug!("closing file tx {} FID {:?}", tx.id, fid);
+                    tdf.file_tracker.close(files, flags);
+                    tx.request_done = true;
+                    tx.response_done = true;
+                    SCLogDebug!("tx {} is done", tx.id);
+                }
+                // as a precaution, reset guid so it can be reused
+                tdf.guid.clear(); // TODO review
+            }
+        },
+        None => { },
+    }
+    match state.get_file_tx_by_guid(&fid, STREAM_TOCLIENT) {
+        Some((tx, files, flags)) => {
+            SCLogDebug!("found tx {}", tx.id);
+            if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data {
+                if !tx.request_done {
+                    SCLogDebug!("closing file tx {} FID {:?}", tx.id, fid);
+                    tdf.file_tracker.close(files, flags);
+                    tx.request_done = true;
+                    tx.response_done = true;
+                    SCLogDebug!("tx {} is done", tx.id);
+                }
+                // as a precaution, reset guid so it can be reused
+                tdf.guid.clear(); // TODO review now that fid is improved
+            }
+        },
+        None => { },
+    }
+}
+
 pub fn smb1_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32 {
     SCLogDebug!("record: {:?} command {}", r.greeter, r.command);
 
@@ -152,11 +194,9 @@ pub fn smb1_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32 {
             }
             false
         },
-        SMB1_COMMAND_WRITE_ANDX => {
-            smb1_write_request_record(state, r);
-            true // tx handling in func
-        },
-        SMB1_COMMAND_WRITE => {
+        SMB1_COMMAND_WRITE_ANDX |
+        SMB1_COMMAND_WRITE |
+        SMB1_COMMAND_WRITE_AND_CLOSE => {
             smb1_write_request_record(state, r);
             true // tx handling in func
         },
@@ -265,43 +305,7 @@ pub fn smb1_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32 {
                     let mut fid = cd.fid.to_vec();
                     fid.extend_from_slice(&u32_as_bytes(r.ssn_id));
                     SCLogDebug!("closing FID {:?}/{:?}", cd.fid, fid);
-
-                    // we can have created 2 txs for a FID: one for reads
-                    // and one for writes. So close both.
-                    match state.get_file_tx_by_guid(&fid, STREAM_TOSERVER) {
-                        Some((tx, files, flags)) => {
-                            SCLogDebug!("found tx {}", tx.id);
-                            if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data {
-                                if !tx.request_done {
-                                    SCLogDebug!("closing file tx {} FID {:?}/{:?}", tx.id, cd.fid, fid);
-                                    tdf.file_tracker.close(files, flags);
-                                    tx.request_done = true;
-                                    tx.response_done = true;
-                                    SCLogDebug!("tx {} is done", tx.id);
-                                }
-                                // as a precaution, reset guid so it can be reused
-                                tdf.guid.clear(); // TODO review
-                            }
-                        },
-                        None => { },
-                    }
-                    match state.get_file_tx_by_guid(&fid, STREAM_TOCLIENT) {
-                        Some((tx, files, flags)) => {
-                            SCLogDebug!("found tx {}", tx.id);
-                            if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data {
-                                if !tx.request_done {
-                                    SCLogDebug!("closing file tx {} FID {:?}/{:?}", tx.id, cd.fid, fid);
-                                    tdf.file_tracker.close(files, flags);
-                                    tx.request_done = true;
-                                    tx.response_done = true;
-                                    SCLogDebug!("tx {} is done", tx.id);
-                                }
-                                // as a precaution, reset guid so it can be reused
-                                tdf.guid.clear(); // TODO review now that fid is improved
-                            }
-                        },
-                        None => { },
-                    }
+                    smb1_close_file(state, &fid);
                 },
                 _ => {
                     events.push(SMBEvent::MalformedData);
@@ -656,8 +660,10 @@ pub fn smb1_write_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>)
 {
     let result = if r.command == SMB1_COMMAND_WRITE_ANDX {
         parse_smb1_write_andx_request_record(r.data)
-    } else {
+    } else if r.command == SMB1_COMMAND_WRITE {
         parse_smb1_write_request_record(r.data)
+    } else {
+        parse_smb1_write_and_close_request_record(r.data)
     };
     match result {
         IResult::Done(_, rd) => {
@@ -712,6 +718,11 @@ pub fn smb1_write_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>)
             state.file_ts_left = rd.len - rd.data.len() as u32;
             state.file_ts_guid = file_fid.to_vec();
             SCLogDebug!("SMBv1 WRITE RESPONSE: {} bytes left", state.file_tc_left);
+
+            if r.command == SMB1_COMMAND_WRITE_AND_CLOSE {
+                SCLogDebug!("closing FID {:?}", file_fid);
+                smb1_close_file(state, &file_fid);
+            }
         },
         _ => {
             state.set_event(SMBEvent::MalformedData);
index 81864c75d58e4e4590aa73c501a882965d93530a..90afedec0dbd16ac0bde6083dcc25521bc99708b 100644 (file)
@@ -72,6 +72,24 @@ named!(pub parse_smb1_write_andx_request_record<Smb1WriteRequestRecord>,
             }))
 );
 
+named!(pub parse_smb1_write_and_close_request_record<Smb1WriteRequestRecord>,
+    do_parse!(
+            wct: le_u8
+        >>  fid: take!(2)
+        >>  count: le_u16
+        >>  offset: le_u32
+        >>  last_write: take!(4)
+        >>  bcc: le_u16
+        >>  padding: cond!(bcc > count, take!(bcc - count))
+        >>  file_data: take!(count)
+        >> (Smb1WriteRequestRecord {
+                offset: offset as u64,
+                len: count as u32,
+                fid:fid,
+                data:file_data,
+            }))
+);
+
 #[derive(Debug,PartialEq)]
 pub struct Smb1NegotiateProtocolResponseRecord<> {
     pub dialect_idx: u16,