smb1: implement WRITE_AND_CLOSE

pull/3281/head
Victor Julien 8 years ago
parent 595557eb8d
commit 98b926bf72

@ -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);

@ -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,

Loading…
Cancel
Save