From ca34fba00c1c7edeec279dd1649b0b3a01784900 Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Wed, 17 Jun 2026 17:32:49 +0200 Subject: [PATCH] rust: format smb files Ticket: 3836 --- rust/src/smb/auth.rs | 161 +-- rust/src/smb/dcerpc.rs | 322 +++--- rust/src/smb/dcerpc_records.rs | 80 +- rust/src/smb/debug.rs | 42 +- rust/src/smb/detect.rs | 8 +- rust/src/smb/files.rs | 94 +- rust/src/smb/funcs.rs | 13 +- rust/src/smb/log.rs | 145 +-- rust/src/smb/mod.rs | 27 +- rust/src/smb/nbss_records.rs | 98 +- rust/src/smb/ntlmssp_records.rs | 2 +- rust/src/smb/session.rs | 26 +- rust/src/smb/smb.rs | 1655 ++++++++++++++++++++----------- rust/src/smb/smb1.rs | 933 +++++++++-------- rust/src/smb/smb1_records.rs | 637 ++++++------ rust/src/smb/smb1_session.rs | 96 +- rust/src/smb/smb2.rs | 560 ++++++----- rust/src/smb/smb2_ioctl.rs | 61 +- rust/src/smb/smb2_records.rs | 15 +- rust/src/smb/smb2_session.rs | 46 +- rust/src/smb/smb3.rs | 10 +- rust/src/smb/smb_records.rs | 10 +- scripts/rustfmt.sh | 3 + 23 files changed, 3019 insertions(+), 2025 deletions(-) diff --git a/rust/src/smb/auth.rs b/rust/src/smb/auth.rs index 61f420587c..df71563f50 100644 --- a/rust/src/smb/auth.rs +++ b/rust/src/smb/auth.rs @@ -20,16 +20,18 @@ use crate::kerberos::*; use crate::smb::ntlmssp_records::*; use crate::smb::smb::*; -use nom8::{Err, IResult}; use der_parser::ber::BerObjectContent; use der_parser::der::{parse_der_oid, parse_der_sequence}; +use nom8::{Err, IResult}; -fn parse_secblob_get_spnego(blob: &[u8]) -> IResult<&[u8], &[u8], SecBlobError> -{ - let (rem, base_o) = der_parser::parse_der(blob).map_err(|_| Err::Error(SecBlobError::NotSpNego))?; +fn parse_secblob_get_spnego(blob: &[u8]) -> IResult<&[u8], &[u8], SecBlobError> { + let (rem, base_o) = + der_parser::parse_der(blob).map_err(|_| Err::Error(SecBlobError::NotSpNego))?; SCLogDebug!("parse_secblob_get_spnego: base_o {:?}", base_o); let d = match base_o.content.as_slice() { - Err(_) => { return Err(Err::Error(SecBlobError::NotSpNego)); }, + Err(_) => { + return Err(Err::Error(SecBlobError::NotSpNego)); + } Ok(d) => d, }; let (next, o) = parse_der_oid(d).map_err(|_| Err::Error(SecBlobError::NotSpNego))?; @@ -39,17 +41,17 @@ fn parse_secblob_get_spnego(blob: &[u8]) -> IResult<&[u8], &[u8], SecBlobError> Ok(oid) => oid, Err(_) => { return Err(Err::Error(SecBlobError::NotSpNego)); - }, + } }; SCLogDebug!("oid {}", oid.to_string()); match oid.to_string().as_str() { "1.3.6.1.5.5.2" => { SCLogDebug!("SPNEGO {}", oid); - }, + } _ => { return Err(Err::Error(SecBlobError::NotSpNego)); - }, + } } SCLogDebug!("parse_secblob_get_spnego: next {:?}", next); @@ -57,17 +59,16 @@ fn parse_secblob_get_spnego(blob: &[u8]) -> IResult<&[u8], &[u8], SecBlobError> Ok((rem, next)) } -fn parse_secblob_spnego_start(blob: &[u8]) -> IResult<&[u8], &[u8], SecBlobError> -{ +fn parse_secblob_spnego_start(blob: &[u8]) -> IResult<&[u8], &[u8], SecBlobError> { let (rem, o) = der_parser::parse_der(blob).map_err(|_| Err::Error(SecBlobError::NotSpNego))?; let d = match o.content.as_slice() { Ok(d) => { - SCLogDebug!("d: next data len {}",d.len()); + SCLogDebug!("d: next data len {}", d.len()); d - }, + } _ => { return Err(Err::Error(SecBlobError::NotSpNego)); - }, + } }; Ok((rem, d)) } @@ -78,27 +79,32 @@ pub struct SpnegoRequest { pub ntlmssp: Option, } -fn parse_secblob_spnego(blob: &[u8]) -> Option -{ +fn parse_secblob_spnego(blob: &[u8]) -> Option { let mut have_ntlmssp = false; let mut have_kerberos = false; - let mut kticket : Option = None; - let mut ntlmssp : Option = None; + let mut kticket: Option = None; + let mut ntlmssp: Option = None; let o = match parse_der_sequence(blob) { Ok((_, o)) => o, - _ => { return None; }, + _ => { + return None; + } }; for s in o { SCLogDebug!("s {:?}", s); let n = match s.content.as_slice() { Ok(s) => s, - _ => { continue; }, + _ => { + continue; + } }; let o = match der_parser::parse_der(n) { - Ok((_,x)) => x, - _ => { continue; }, + Ok((_, x)) => x, + _ => { + continue; + } }; SCLogDebug!("o {:?}", o); match o.content { @@ -108,20 +114,38 @@ fn parse_secblob_spnego(blob: &[u8]) -> Option if let BerObjectContent::OID(ref oid) = se.content { SCLogDebug!("OID {:?}", oid); match oid.to_string().as_str() { - "1.2.840.48018.1.2.2" => { SCLogDebug!("Microsoft Kerberos 5"); }, - "1.2.840.113554.1.2.2" => { SCLogDebug!("Kerberos 5"); have_kerberos = true; }, - "1.2.840.113554.1.2.2.1" => { SCLogDebug!("krb5-name"); }, - "1.2.840.113554.1.2.2.2" => { SCLogDebug!("krb5-principal"); }, - "1.2.840.113554.1.2.2.3" => { SCLogDebug!("krb5-user-to-user-mech"); }, - "1.3.6.1.4.1.311.2.2.10" => { SCLogDebug!("NTLMSSP"); have_ntlmssp = true; }, - "1.3.6.1.4.1.311.2.2.30" => { SCLogDebug!("NegoEx"); }, - _ => { SCLogDebug!("unexpected OID {:?}", oid); }, + "1.2.840.48018.1.2.2" => { + SCLogDebug!("Microsoft Kerberos 5"); + } + "1.2.840.113554.1.2.2" => { + SCLogDebug!("Kerberos 5"); + have_kerberos = true; + } + "1.2.840.113554.1.2.2.1" => { + SCLogDebug!("krb5-name"); + } + "1.2.840.113554.1.2.2.2" => { + SCLogDebug!("krb5-principal"); + } + "1.2.840.113554.1.2.2.3" => { + SCLogDebug!("krb5-user-to-user-mech"); + } + "1.3.6.1.4.1.311.2.2.10" => { + SCLogDebug!("NTLMSSP"); + have_ntlmssp = true; + } + "1.3.6.1.4.1.311.2.2.30" => { + SCLogDebug!("NegoEx"); + } + _ => { + SCLogDebug!("unexpected OID {:?}", oid); + } } } else { SCLogDebug!("expected OID, got {:?}", se); } } - }, + } BerObjectContent::OctetString(os) => { if have_kerberos { if let Ok((_, t)) = parse_kerberos5_request(os) { @@ -133,8 +157,8 @@ fn parse_secblob_spnego(blob: &[u8]) -> Option SCLogDebug!("parsing expected NTLMSSP"); ntlmssp = parse_ntlmssp_blob(os); } - }, - _ => {}, + } + _ => {} } } @@ -145,7 +169,7 @@ fn parse_secblob_spnego(blob: &[u8]) -> Option Some(s) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct NtlmsspData { pub host: Vec, pub user: Vec, @@ -155,27 +179,29 @@ pub struct NtlmsspData { } /// take in blob, search for the header and parse it -fn parse_ntlmssp_blob(blob: &[u8]) -> Option -{ - let mut ntlmssp_data : Option = None; +fn parse_ntlmssp_blob(blob: &[u8]) -> Option { + let mut ntlmssp_data: Option = None; SCLogDebug!("NTLMSSP {:?}", blob); if let Ok((_, nd)) = parse_ntlmssp(blob) { - SCLogDebug!("NTLMSSP TYPE {}/{} nd {:?}", - nd.msg_type, &ntlmssp_type_string(nd.msg_type), nd); + SCLogDebug!( + "NTLMSSP TYPE {}/{} nd {:?}", + nd.msg_type, + &ntlmssp_type_string(nd.msg_type), + nd + ); match nd.msg_type { - NTLMSSP_NEGOTIATE => { - }, + NTLMSSP_NEGOTIATE => {} NTLMSSP_AUTH => { if let Ok((_, ad)) = parse_ntlm_auth_record(nd.data) { SCLogDebug!("auth data {:?}", ad); let mut host = ad.host.to_vec(); - host.retain(|&i|i != 0x00); + host.retain(|&i| i != 0x00); let mut user = ad.user.to_vec(); - user.retain(|&i|i != 0x00); + user.retain(|&i| i != 0x00); let mut domain = ad.domain.to_vec(); - domain.retain(|&i|i != 0x00); - + domain.retain(|&i| i != 0x00); + let d = NtlmsspData { host, user, @@ -185,47 +211,38 @@ fn parse_ntlmssp_blob(blob: &[u8]) -> Option }; ntlmssp_data = Some(d); } - }, - _ => {}, + } + _ => {} } } return ntlmssp_data; } // if spnego parsing fails try to fall back to ntlmssp -pub fn parse_secblob(blob: &[u8]) -> Option -{ +pub fn parse_secblob(blob: &[u8]) -> Option { match parse_secblob_get_spnego(blob) { - Ok((_, spnego)) => { - match parse_secblob_spnego_start(spnego) { - Ok((_, spnego_start)) => { - parse_secblob_spnego(spnego_start) - }, - _ => { - match parse_ntlmssp_blob(blob) { - Some(n) => { - let s = SpnegoRequest { - krb: None, - ntlmssp: Some(n), - }; - Some(s) - }, - None => { None }, - } - }, - } - }, - _ => { - match parse_ntlmssp_blob(blob) { + Ok((_, spnego)) => match parse_secblob_spnego_start(spnego) { + Ok((_, spnego_start)) => parse_secblob_spnego(spnego_start), + _ => match parse_ntlmssp_blob(blob) { Some(n) => { let s = SpnegoRequest { krb: None, - ntlmssp: Some(n), + ntlmssp: Some(n), }; Some(s) - }, - None => { None }, + } + None => None, + }, + }, + _ => match parse_ntlmssp_blob(blob) { + Some(n) => { + let s = SpnegoRequest { + krb: None, + ntlmssp: Some(n), + }; + Some(s) } + None => None, }, } } diff --git a/rust/src/smb/dcerpc.rs b/rust/src/smb/dcerpc.rs index 6b47aad5be..818aaa3a1f 100644 --- a/rust/src/smb/dcerpc.rs +++ b/rust/src/smb/dcerpc.rs @@ -17,13 +17,13 @@ // written by Victor Julien -use uuid; -use crate::smb::smb::{cfg_max_stub_size, *}; -use crate::smb::smb2::*; +use crate::dcerpc::dcerpc::*; use crate::smb::dcerpc_records::*; use crate::smb::events::*; -use crate::dcerpc::dcerpc::*; +use crate::smb::smb::{cfg_max_stub_size, *}; +use crate::smb::smb2::*; use crate::smb::smb_status::*; +use uuid; impl SMBCommonHdr { /// helper for DCERPC tx tracking. Check if we need @@ -37,21 +37,21 @@ impl SMBCommonHdr { 2 => { let (_, cmd2) = vercmd.get_smb2_cmd(); let x = match cmd2 { - SMB2_COMMAND_READ => { 0 }, - SMB2_COMMAND_WRITE => { 0 }, - SMB2_COMMAND_IOCTL => { self.msg_id }, - _ => { self.msg_id }, + SMB2_COMMAND_READ => 0, + SMB2_COMMAND_WRITE => 0, + SMB2_COMMAND_IOCTL => self.msg_id, + _ => self.msg_id, }; use_msg_id = x; - }, + } 1 => { SCLogDebug!("FIXME TODO"); //let (_, cmd1) = vercmd.get_smb1_cmd(); //if cmd1 != SMB1_COMMAND_IOCTL { use_msg_id = 0; //} - }, - _ => { }, + } + _ => {} } SMBCommonHdr { ssn_id: self.ssn_id, @@ -109,10 +109,10 @@ impl SMBTransactionDCERPC { req_set: true, call_id, ..Default::default() - } + }; } fn new_response(call_id: u32) -> Self { - return Self { + return Self { call_id, ..Default::default() }; @@ -124,14 +124,15 @@ impl SMBTransactionDCERPC { } impl SMBState { - fn new_dcerpc_tx(&mut self, hdr: SMBCommonHdr, vercmd: SMBVerCmdStat, cmd: u8, call_id: u32) - -> &mut SMBTransaction - { + fn new_dcerpc_tx( + &mut self, hdr: SMBCommonHdr, vercmd: SMBVerCmdStat, cmd: u8, call_id: u32, + ) -> &mut SMBTransaction { let mut tx = self.new_tx(); tx.hdr = hdr; tx.vercmd = vercmd; tx.type_data = Some(SMBTransactionTypeData::DCERPC( - SMBTransactionDCERPC::new_request(cmd, call_id))); + SMBTransactionDCERPC::new_request(cmd, call_id), + )); SCLogDebug!("SMB: TX DCERPC created: ID {} hdr {:?}", tx.id, tx.hdr); self.transactions.push_back(tx); @@ -139,14 +140,15 @@ impl SMBState { return tx_ref.unwrap(); } - fn new_dcerpc_tx_for_response(&mut self, hdr: SMBCommonHdr, vercmd: SMBVerCmdStat, call_id: u32) - -> &mut SMBTransaction - { + fn new_dcerpc_tx_for_response( + &mut self, hdr: SMBCommonHdr, vercmd: SMBVerCmdStat, call_id: u32, + ) -> &mut SMBTransaction { let mut tx = self.new_tx(); tx.hdr = hdr; tx.vercmd = vercmd; tx.type_data = Some(SMBTransactionTypeData::DCERPC( - SMBTransactionDCERPC::new_response(call_id))); + SMBTransactionDCERPC::new_response(call_id), + )); SCLogDebug!("SMB: TX DCERPC created: ID {} hdr {:?}", tx.id, tx.hdr); self.transactions.push_back(tx); @@ -154,20 +156,18 @@ impl SMBState { return tx_ref.unwrap(); } - fn get_dcerpc_tx(&mut self, hdr: &SMBCommonHdr, vercmd: &SMBVerCmdStat, call_id: u32) - -> Option<&mut SMBTransaction> - { + fn get_dcerpc_tx( + &mut self, hdr: &SMBCommonHdr, vercmd: &SMBVerCmdStat, call_id: u32, + ) -> Option<&mut SMBTransaction> { let dce_hdr = hdr.to_dcerpc(vercmd); SCLogDebug!("looking for {:?}", dce_hdr); for tx in &mut self.transactions { - let found = dce_hdr.compare(&tx.hdr.to_dcerpc(vercmd)) && - match tx.type_data { - Some(SMBTransactionTypeData::DCERPC(ref x)) => { - x.call_id == call_id - }, - _ => { false }, - }; + let found = dce_hdr.compare(&tx.hdr.to_dcerpc(vercmd)) + && match tx.type_data { + Some(SMBTransactionTypeData::DCERPC(ref x)) => x.call_id == call_id, + _ => false, + }; if found { tx.tx_data.0.updated_tc = true; tx.tx_data.0.updated_ts = true; @@ -181,19 +181,22 @@ impl SMBState { /// Handle DCERPC request data from a WRITE, IOCTL or TRANS record. /// return bool indicating whether an tx has been created/updated. /// -pub fn smb_write_dcerpc_record(state: &mut SMBState, - vercmd: SMBVerCmdStat, - hdr: SMBCommonHdr, - data: &[u8]) -> bool -{ - let mut bind_ifaces : Option> = None; +pub fn smb_write_dcerpc_record( + state: &mut SMBState, vercmd: SMBVerCmdStat, hdr: SMBCommonHdr, data: &[u8], +) -> bool { + let mut bind_ifaces: Option> = None; let mut is_bind = false; SCLogDebug!("called for {} bytes of data", data.len()); match parse_dcerpc_record(data) { Ok((_, dcer)) => { - SCLogDebug!("DCERPC: version {}.{} write data {} => {:?}", - dcer.version_major, dcer.version_minor, dcer.data.len(), dcer); + SCLogDebug!( + "DCERPC: version {}.{} write data {} => {:?}", + dcer.version_major, + dcer.version_minor, + dcer.data.len(), + dcer + ); /* if this isn't the first frag, simply update the existing * tx with the additional stub data */ @@ -203,9 +206,15 @@ pub fn smb_write_dcerpc_record(state: &mut SMBState, Ok((_, recr)) => { let found = match state.get_dcerpc_tx(&hdr, &vercmd, dcer.call_id) { Some(tx) => { - SCLogDebug!("previous CMD {} found at tx {} => {:?}", - dcer.packet_type, tx.id, tx); - if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data { + SCLogDebug!( + "previous CMD {} found at tx {} => {:?}", + dcer.packet_type, + tx.id, + tx + ); + if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = + tx.type_data + { tdn.frag_cnt_ts = tdn.frag_cnt_ts.saturating_add(1); let max_size = cfg_max_stub_size() as usize; if recr.data.len() + tdn.stub_data_ts.len() < max_size { @@ -213,38 +222,44 @@ pub fn smb_write_dcerpc_record(state: &mut SMBState, tdn.stub_data_ts.extend_from_slice(recr.data); SCLogDebug!("stub_data now {}", tdn.stub_data_ts.len()); } else if tdn.stub_data_ts.len() < max_size { - tdn.stub_data_ts.extend_from_slice(&recr.data[..max_size - tdn.stub_data_ts.len()]); + tdn.stub_data_ts.extend_from_slice( + &recr.data[..max_size - tdn.stub_data_ts.len()], + ); } } if dcer.last_frag { SCLogDebug!("last frag set, so request side of DCERPC closed"); tx.request_done = true; } else { - SCLogDebug!("NOT last frag, so request side of DCERPC remains open"); + SCLogDebug!( + "NOT last frag, so request side of DCERPC remains open" + ); } true - }, + } None => { SCLogDebug!("NO previous CMD {} found", dcer.packet_type); false - }, + } }; return found; - }, + } _ => { state.set_event(SMBEvent::MalformedData); return false; - }, + } } } let tx = state.new_dcerpc_tx(hdr, vercmd, dcer.packet_type, dcer.call_id); match dcer.packet_type { DCERPC_TYPE_REQUEST => { - match parse_dcerpc_request_record(dcer.data, dcer.frag_len, dcer.little_endian) { + match parse_dcerpc_request_record(dcer.data, dcer.frag_len, dcer.little_endian) + { Ok((_, recr)) => { SCLogDebug!("DCERPC: REQUEST {:?}", recr); - if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data { + if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data + { SCLogDebug!("first frag size {}", recr.data.len()); tdn.opnum = recr.opnum; tdn.context_id = recr.context_id; @@ -252,24 +267,31 @@ pub fn smb_write_dcerpc_record(state: &mut SMBState, let max_size = cfg_max_stub_size() as usize; if tdn.stub_data_ts.len() + recr.data.len() < max_size { tdn.stub_data_ts.extend_from_slice(recr.data); - SCLogDebug!("DCERPC: REQUEST opnum {} stub data len {}", - tdn.opnum, tdn.stub_data_ts.len()); + SCLogDebug!( + "DCERPC: REQUEST opnum {} stub data len {}", + tdn.opnum, + tdn.stub_data_ts.len() + ); } else if tdn.stub_data_ts.len() < max_size { - tdn.stub_data_ts.extend_from_slice(&recr.data[..max_size - tdn.stub_data_ts.len()]); + tdn.stub_data_ts.extend_from_slice( + &recr.data[..max_size - tdn.stub_data_ts.len()], + ); } } if dcer.last_frag { tx.request_done = true; } else { - SCLogDebug!("NOT last frag, so request side of DCERPC remains open"); + SCLogDebug!( + "NOT last frag, so request side of DCERPC remains open" + ); } - }, + } _ => { tx.set_event(SMBEvent::MalformedData); tx.request_done = true; - }, + } } - }, + } DCERPC_TYPE_BIND => { let brec = if dcer.little_endian { parse_dcerpc_bind_record(dcer.data) @@ -285,43 +307,63 @@ pub fn smb_write_dcerpc_record(state: &mut SMBState, let mut ifaces: Vec = Vec::new(); for i in bindr.ifaces { let x = if dcer.little_endian { - vec![i.iface[3], i.iface[2], i.iface[1], i.iface[0], - i.iface[5], i.iface[4], i.iface[7], i.iface[6], - i.iface[8], i.iface[9], i.iface[10], i.iface[11], - i.iface[12], i.iface[13], i.iface[14], i.iface[15]] + vec![ + i.iface[3], + i.iface[2], + i.iface[1], + i.iface[0], + i.iface[5], + i.iface[4], + i.iface[7], + i.iface[6], + i.iface[8], + i.iface[9], + i.iface[10], + i.iface[11], + i.iface[12], + i.iface[13], + i.iface[14], + i.iface[15], + ] } else { i.iface.to_vec() }; let uuid_str = uuid::Uuid::from_slice(&x.clone()); - let _uuid_str = uuid_str.map(|uuid_str| uuid_str.to_hyphenated().to_string()).unwrap(); - let d = DCERPCIface::new(x,i.ver,i.ver_min,i.ctx_id); - SCLogDebug!("UUID {} version {}/{} bytes {:?}", - _uuid_str, - i.ver, i.ver_min,i.iface); + let _uuid_str = uuid_str + .map(|uuid_str| uuid_str.to_hyphenated().to_string()) + .unwrap(); + let d = DCERPCIface::new(x, i.ver, i.ver_min, i.ctx_id); + SCLogDebug!( + "UUID {} version {}/{} bytes {:?}", + _uuid_str, + i.ver, + i.ver_min, + i.iface + ); ifaces.push(d); } bind_ifaces = Some(ifaces); } - }, + } _ => { tx.set_event(SMBEvent::MalformedData); - }, + } } tx.request_done = true; } 21..=255 => { tx.set_event(SMBEvent::MalformedData); tx.request_done = true; - }, + } _ => { // valid type w/o special processing tx.request_done = true; - }, + } } - }, + } _ => { state.set_event(SMBEvent::MalformedData); - }, + } } if is_bind { @@ -337,12 +379,9 @@ pub fn smb_write_dcerpc_record(state: &mut SMBState, /// Update TX for bind ack. Needs to update both tx and state. /// fn smb_dcerpc_response_bindack( - state: &mut SMBState, - vercmd: SMBVerCmdStat, - hdr: SMBCommonHdr, - dcer: &DceRpcRecord, - ntstatus: u32) -{ + state: &mut SMBState, vercmd: SMBVerCmdStat, hdr: SMBCommonHdr, dcer: &DceRpcRecord, + ntstatus: u32, +) { match parse_dcerpc_bindack_record(dcer.data) { Ok((_, bindackr)) => { SCLogDebug!("SMB READ BINDACK {:?}", bindackr); @@ -355,7 +394,7 @@ fn smb_dcerpc_response_bindack( tx.vercmd.set_ntstatus(ntstatus); tx.response_done = true; true - }, + } None => false, }; if found { @@ -370,17 +409,16 @@ fn smb_dcerpc_response_bindack( } } } - }, + } _ => { state.set_event(SMBEvent::MalformedData); - }, + } } } -fn smb_read_dcerpc_record_error(state: &mut SMBState, - hdr: SMBCommonHdr, vercmd: SMBVerCmdStat, ntstatus: u32) - -> bool -{ +fn smb_read_dcerpc_record_error( + state: &mut SMBState, hdr: SMBCommonHdr, vercmd: SMBVerCmdStat, ntstatus: u32, +) -> bool { let ver = vercmd.get_version(); let cmd = if ver == 2 { let (_, c) = vercmd.get_smb2_cmd(); @@ -396,47 +434,43 @@ fn smb_read_dcerpc_record_error(state: &mut SMBState, tx.set_status(ntstatus, false); tx.response_done = true; true - }, + } None => { SCLogDebug!("NOT found"); false - }, + } }; return found; } -fn dcerpc_response_handle(tx: &mut SMBTransaction, - vercmd: SMBVerCmdStat, - dcer: &DceRpcRecord) -{ +fn dcerpc_response_handle(tx: &mut SMBTransaction, vercmd: SMBVerCmdStat, dcer: &DceRpcRecord) { let (_, ntstatus) = vercmd.get_ntstatus(); match dcer.packet_type { - DCERPC_TYPE_RESPONSE => { - match parse_dcerpc_response_record(dcer.data, dcer.frag_len) { - Ok((_, respr)) => { - SCLogDebug!("SMBv1 READ RESPONSE {:?}", respr); - if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data { - SCLogDebug!("CMD 11 found at tx {}", tx.id); - tdn.set_result(DCERPC_TYPE_RESPONSE); - let max_size = cfg_max_stub_size() as usize; - tdn.frag_cnt_tc = tdn.frag_cnt_tc.saturating_add(1); - if tdn.stub_data_tc.len() + respr.data.len() < max_size { - tdn.stub_data_tc.extend_from_slice(respr.data); - } else if tdn.stub_data_tc.len() < max_size { - tdn.stub_data_tc.extend_from_slice(&respr.data[..max_size - tdn.stub_data_tc.len()]); - } + DCERPC_TYPE_RESPONSE => match parse_dcerpc_response_record(dcer.data, dcer.frag_len) { + Ok((_, respr)) => { + SCLogDebug!("SMBv1 READ RESPONSE {:?}", respr); + if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data { + SCLogDebug!("CMD 11 found at tx {}", tx.id); + tdn.set_result(DCERPC_TYPE_RESPONSE); + let max_size = cfg_max_stub_size() as usize; + tdn.frag_cnt_tc = tdn.frag_cnt_tc.saturating_add(1); + if tdn.stub_data_tc.len() + respr.data.len() < max_size { + tdn.stub_data_tc.extend_from_slice(respr.data); + } else if tdn.stub_data_tc.len() < max_size { + tdn.stub_data_tc + .extend_from_slice(&respr.data[..max_size - tdn.stub_data_tc.len()]); } - tx.vercmd.set_ntstatus(ntstatus); - tx.response_done = dcer.last_frag; - }, - _ => { - tx.set_event(SMBEvent::MalformedData); - }, + } + tx.vercmd.set_ntstatus(ntstatus); + tx.response_done = dcer.last_frag; + } + _ => { + tx.set_event(SMBEvent::MalformedData); } }, DCERPC_TYPE_BINDACK => { // handled elsewhere - }, + } 21..=255 => { if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data { tdn.set_result(dcer.packet_type); @@ -445,24 +479,22 @@ fn dcerpc_response_handle(tx: &mut SMBTransaction, tx.response_done = true; tx.set_event(SMBEvent::MalformedData); } - _ => { // valid type w/o special processing + _ => { + // valid type w/o special processing if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data { tdn.set_result(dcer.packet_type); } tx.vercmd.set_ntstatus(ntstatus); tx.response_done = true; - }, + } } } /// Handle DCERPC reply record. Called for READ, TRANS, IOCTL /// -pub fn smb_read_dcerpc_record(state: &mut SMBState, - vercmd: SMBVerCmdStat, - hdr: SMBCommonHdr, - guid: &[u8], - indata: &[u8]) -> bool -{ +pub fn smb_read_dcerpc_record( + state: &mut SMBState, vercmd: SMBVerCmdStat, hdr: SMBCommonHdr, guid: &[u8], indata: &[u8], +) -> bool { let (_, ntstatus) = vercmd.get_ntstatus(); if ntstatus != SMB_NTSTATUS_SUCCESS && ntstatus != SMB_NTSTATUS_BUFFER_OVERFLOW { @@ -471,8 +503,10 @@ pub fn smb_read_dcerpc_record(state: &mut SMBState, SCLogDebug!("lets first see if we have prior data"); // msg_id 0 as this data crosses cmd/reply pairs - let ehdr = SMBHashKeyHdrGuid::new(SMBCommonHdr::new(SMBHDR_TYPE_TRANS_FRAG, - hdr.ssn_id, hdr.tree_id, 0_u64), guid.to_vec()); + let ehdr = SMBHashKeyHdrGuid::new( + SMBCommonHdr::new(SMBHDR_TYPE_TRANS_FRAG, hdr.ssn_id, hdr.tree_id, 0_u64), + guid.to_vec(), + ); let mut prevdata = state.dcerpc_rec_frag_cache.pop(&ehdr).unwrap_or_default(); SCLogDebug!("indata {} prevdata {}", indata.len(), prevdata.len()); prevdata.extend_from_slice(indata); @@ -482,18 +516,25 @@ pub fn smb_read_dcerpc_record(state: &mut SMBState, if data.is_empty() { SCLogDebug!("weird: no DCERPC data"); // TODO - // TODO set event? + // TODO set event? return false; - } else { match parse_dcerpc_record(&data) { Ok((_, dcer)) => { - SCLogDebug!("DCERPC: version {}.{} read data {} => {:?}", - dcer.version_major, dcer.version_minor, dcer.data.len(), dcer); + SCLogDebug!( + "DCERPC: version {}.{} read data {} => {:?}", + dcer.version_major, + dcer.version_minor, + dcer.data.len(), + dcer + ); if ntstatus == SMB_NTSTATUS_BUFFER_OVERFLOW && data.len() < dcer.frag_len as usize { - SCLogDebug!("short record {} < {}: storing partial data in state", - data.len(), dcer.frag_len); + SCLogDebug!( + "short record {} < {}: storing partial data in state", + data.len(), + dcer.frag_len + ); state.dcerpc_rec_frag_cache.put(ehdr, data.to_vec()); return true; // TODO review } @@ -507,21 +548,21 @@ pub fn smb_read_dcerpc_record(state: &mut SMBState, Some(tx) => { dcerpc_response_handle(tx, vercmd.clone(), &dcer); true - }, + } None => { SCLogDebug!("no tx"); false - }, + } }; if !found { // pick up DCERPC tx even if we missed the request let tx = state.new_dcerpc_tx_for_response(hdr, vercmd.clone(), dcer.call_id); dcerpc_response_handle(tx, vercmd, &dcer); } - }, + } _ => { malformed = true; - }, + } } } @@ -533,16 +574,17 @@ pub fn smb_read_dcerpc_record(state: &mut SMBState, } /// Try to find out if the input data looks like DCERPC -pub fn smb_dcerpc_probe(data: &[u8]) -> bool -{ +pub fn smb_dcerpc_probe(data: &[u8]) -> bool { if let Ok((_, recr)) = parse_dcerpc_record(data) { SCLogDebug!("SMB: could be DCERPC {:?}", recr); - if recr.version_major == 5 && recr.version_minor < 3 && - recr.frag_len > 0 && recr.packet_type <= 20 - { - SCLogDebug!("SMB: looks like we have dcerpc"); - return true; - } + if recr.version_major == 5 + && recr.version_minor < 3 + && recr.frag_len > 0 + && recr.packet_type <= 20 + { + SCLogDebug!("SMB: looks like we have dcerpc"); + return true; + } } return false; } diff --git a/rust/src/smb/dcerpc_records.rs b/rust/src/smb/dcerpc_records.rs index 348f4cb0f2..5e2a659e81 100644 --- a/rust/src/smb/dcerpc_records.rs +++ b/rust/src/smb/dcerpc_records.rs @@ -15,27 +15,27 @@ * 02110-1301, USA. */ -use nom8::bits::bits; use crate::smb::error::SmbError; +use nom8::bits::bits; use nom8::bits::streaming::take as take_bits; use nom8::bytes::streaming::take; use nom8::combinator::{cond, rest}; use nom8::multi::count; +use nom8::number::streaming::{be_u16, le_u16, le_u32, le_u8, u16, u32}; use nom8::number::Endianness; -use nom8::number::streaming::{be_u16, le_u8, le_u16, le_u32, u16, u32}; use nom8::Parser; use nom8::{Err, IResult}; -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct DceRpcResponseRecord<'a> { - pub data: &'a[u8], + pub data: &'a [u8], } /// parse a packet type 'response' DCERPC record. Implemented /// as function to be able to pass the fraglen in. -pub fn parse_dcerpc_response_record(i:&[u8], frag_len: u16 ) - -> IResult<&[u8], DceRpcResponseRecord<'_>, SmbError> -{ +pub fn parse_dcerpc_response_record( + i: &[u8], frag_len: u16, +) -> IResult<&[u8], DceRpcResponseRecord<'_>, SmbError> { if frag_len < 24 { return Err(Err::Error(SmbError::RecordTooSmall)); } @@ -45,34 +45,42 @@ pub fn parse_dcerpc_response_record(i:&[u8], frag_len: u16 ) Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct DceRpcRequestRecord<'a> { pub opnum: u16, pub context_id: u16, - pub data: &'a[u8], + pub data: &'a [u8], } /// parse a packet type 'request' DCERPC record. Implemented /// as function to be able to pass the fraglen in. -pub fn parse_dcerpc_request_record(i:&[u8], frag_len: u16, little: bool) - -> IResult<&[u8], DceRpcRequestRecord<'_>, SmbError> -{ +pub fn parse_dcerpc_request_record( + i: &[u8], frag_len: u16, little: bool, +) -> IResult<&[u8], DceRpcRequestRecord<'_>, SmbError> { if frag_len < 24 { return Err(Err::Error(SmbError::RecordTooSmall)); } let (i, _) = take(4_usize).parse(i)?; - let endian = if little { Endianness::Little } else { Endianness::Big }; + let endian = if little { + Endianness::Little + } else { + Endianness::Big + }; let (i, context_id) = u16(endian).parse(i)?; let (i, opnum) = u16(endian).parse(i)?; let (i, data) = take(frag_len - 24).parse(i)?; - let record = DceRpcRequestRecord { opnum, context_id, data }; + let record = DceRpcRequestRecord { + opnum, + context_id, + data, + }; Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct DceRpcBindIface<'a> { pub ctx_id: u16, - pub iface: &'a[u8], + pub iface: &'a [u8], pub ver: u16, pub ver_min: u16, } @@ -87,7 +95,7 @@ pub fn parse_dcerpc_bind_iface(i: &[u8]) -> IResult<&[u8], DceRpcBindIface<'_>> let (i, _) = take(20_usize).parse(i)?; let res = DceRpcBindIface { ctx_id, - iface:interface, + iface: interface, ver, ver_min, }; @@ -104,14 +112,14 @@ pub fn parse_dcerpc_bind_iface_big(i: &[u8]) -> IResult<&[u8], DceRpcBindIface<' let (i, _) = take(20_usize).parse(i)?; let res = DceRpcBindIface { ctx_id, - iface:interface, + iface: interface, ver, ver_min, }; Ok((i, res)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct DceRpcBindRecord<'a> { pub num_ctx_items: u8, pub ifaces: Vec>, @@ -145,11 +153,11 @@ pub fn parse_dcerpc_bind_record_big(i: &[u8]) -> IResult<&[u8], DceRpcBindRecord Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct DceRpcBindAckResult<'a> { pub ack_result: u16, pub ack_reason: u16, - pub transfer_syntax: &'a[u8], + pub transfer_syntax: &'a [u8], pub syntax_version: u32, } @@ -167,7 +175,7 @@ pub fn parse_dcerpc_bindack_result(i: &[u8]) -> IResult<&[u8], DceRpcBindAckResu Ok((i, res)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct DceRpcBindAckRecord<'a> { pub num_results: u8, pub results: Vec>, @@ -191,7 +199,7 @@ pub fn parse_dcerpc_bindack_record(i: &[u8]) -> IResult<&[u8], DceRpcBindAckReco Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct DceRpcRecord<'a> { pub version_major: u8, pub version_minor: u8, @@ -206,25 +214,27 @@ pub struct DceRpcRecord<'a> { pub packet_type: u8, pub call_id: u32, - pub data: &'a[u8], + pub data: &'a [u8], } -fn parse_dcerpc_flags1(i:&[u8]) -> IResult<&[u8],(u8,u8,u8)> { +fn parse_dcerpc_flags1(i: &[u8]) -> IResult<&[u8], (u8, u8, u8)> { use nom8::error::Error; bits::<_, _, Error<_>, _, _>(( take_bits(6u8), - take_bits(1u8), // last (1) + take_bits(1u8), // last (1) take_bits(1u8), - )).parse(i) + )) + .parse(i) } -fn parse_dcerpc_flags2(i:&[u8]) -> IResult<&[u8],(u32,u32,u32)> { +fn parse_dcerpc_flags2(i: &[u8]) -> IResult<&[u8], (u32, u32, u32)> { use nom8::error::Error; bits::<_, _, Error<_>, _, _>(( - take_bits(3u32), - take_bits(1u32), // endianness - take_bits(28u32), - )).parse(i) + take_bits(3u32), + take_bits(1u32), // endianness + take_bits(28u32), + )) + .parse(i) } pub fn parse_dcerpc_record(i: &[u8]) -> IResult<&[u8], DceRpcRecord<'_>> { @@ -233,7 +243,11 @@ pub fn parse_dcerpc_record(i: &[u8]) -> IResult<&[u8], DceRpcRecord<'_>> { let (i, packet_type) = le_u8.parse(i)?; let (i, packet_flags) = parse_dcerpc_flags1(i)?; let (i, data_rep) = parse_dcerpc_flags2(i)?; - let endian = if data_rep.1 == 0 { Endianness::Big } else { Endianness::Little }; + let endian = if data_rep.1 == 0 { + Endianness::Big + } else { + Endianness::Little + }; let (i, frag_len) = u16(endian).parse(i)?; let (i, _auth) = u16(endian).parse(i)?; let (i, call_id) = u32(endian).parse(i)?; diff --git a/rust/src/smb/debug.rs b/rust/src/smb/debug.rs index 0c19a2c58d..b26c6ec0eb 100644 --- a/rust/src/smb/debug.rs +++ b/rust/src/smb/debug.rs @@ -19,7 +19,7 @@ use crate::smb::smb::*; impl SMBState { #[cfg(not(feature = "debug"))] - pub fn _debug_tx_stats(&self) { } + pub fn _debug_tx_stats(&self) {} #[cfg(feature = "debug")] pub fn _debug_tx_stats(&self) { @@ -27,7 +27,12 @@ impl SMBState { let txf = self.transactions.front().unwrap(); let txl = self.transactions.back().unwrap(); - SCLogDebug!("TXs {} MIN {} MAX {}", self.transactions.len(), txf.id, txl.id); + SCLogDebug!( + "TXs {} MIN {} MAX {}", + self.transactions.len(), + txf.id, + txl.id + ); SCLogDebug!("- OLD tx.id {}: {:?}", txf.id, txf); SCLogDebug!("- NEW tx.id {}: {:?}", txl.id, txl); self._dump_txs(); @@ -35,7 +40,7 @@ impl SMBState { } #[cfg(not(feature = "debug"))] - pub fn _dump_txs(&self) { } + pub fn _dump_txs(&self) {} #[cfg(feature = "debug")] pub fn _dump_txs(&self) { let len = self.transactions.len(); @@ -52,20 +57,35 @@ impl SMBState { match tx.type_data { Some(SMBTransactionTypeData::FILE(ref d)) => { - SCLogDebug!("idx {} tx id {} progress {}/{} filename {} type_data {:?}", - i, tx.id, tx.request_done, tx.response_done, - String::from_utf8_lossy(&d.file_name), tx.type_data); - }, + SCLogDebug!( + "idx {} tx id {} progress {}/{} filename {} type_data {:?}", + i, + tx.id, + tx.request_done, + tx.response_done, + String::from_utf8_lossy(&d.file_name), + tx.type_data + ); + } _ => { - SCLogDebug!("idx {} tx id {} ver:{} cmd:{} progress {}/{} type_data {:?} tx {:?}", - i, tx.id, ver, _smbcmd, tx.request_done, tx.response_done, tx.type_data, tx); - }, + SCLogDebug!( + "idx {} tx id {} ver:{} cmd:{} progress {}/{} type_data {:?} tx {:?}", + i, + tx.id, + ver, + _smbcmd, + tx.request_done, + tx.response_done, + tx.type_data, + tx + ); + } } } } #[cfg(not(feature = "debug"))] - pub fn _debug_state_stats(&self) { } + pub fn _debug_state_stats(&self) {} #[cfg(feature = "debug")] pub fn _debug_state_stats(&self) { diff --git a/rust/src/smb/detect.rs b/rust/src/smb/detect.rs index 564e242f8d..dcb16bc4d5 100644 --- a/rust/src/smb/detect.rs +++ b/rust/src/smb/detect.rs @@ -28,10 +28,10 @@ use std::os::raw::{c_char, c_int, c_uint, c_void}; use std::ptr; use suricata_sys::sys::{ DetectEngineCtx, DetectEngineThreadCtx, Flow, SCDetectBufferSetActiveList, - SCDetectGetLastSMFromLists, SCDetectHelperBufferMpmRegister, SCDetectHelperBufferProgressRegister, - SCDetectHelperKeywordAliasRegister, SCDetectHelperKeywordRegister, - SCDetectSignatureSetAppProto, SCSigMatchAppendSMToList, SCSigTableAppLiteElmt, SigMatchCtx, - Signature, + SCDetectGetLastSMFromLists, SCDetectHelperBufferMpmRegister, + SCDetectHelperBufferProgressRegister, SCDetectHelperKeywordAliasRegister, + SCDetectHelperKeywordRegister, SCDetectSignatureSetAppProto, SCSigMatchAppendSMToList, + SCSigTableAppLiteElmt, SigMatchCtx, Signature, }; unsafe extern "C" fn smb_tx_get_share( diff --git a/rust/src/smb/files.rs b/rust/src/smb/files.rs index 3d91c801e9..8615a9a4a3 100644 --- a/rust/src/smb/files.rs +++ b/rust/src/smb/files.rs @@ -15,11 +15,11 @@ * 02110-1301, USA. */ -use std; use crate::applayer::AppLayerGetFileStateRust; use crate::core::*; use crate::direction::Direction; use crate::filetracker::*; +use std; use crate::smb::smb::*; use suricata_sys::sys::SCFileFlowFlagsToFlags; @@ -43,41 +43,42 @@ impl SMBTransactionFile { return Self { file_tracker: FileTransferTracker::new(), ..Default::default() - } + }; } pub fn update_file_flags(&mut self, flow_file_flags: u16) { - let dir_flag = if self.direction == Direction::ToServer { STREAM_TOSERVER } else { STREAM_TOCLIENT }; + let dir_flag = if self.direction == Direction::ToServer { + STREAM_TOSERVER + } else { + STREAM_TOCLIENT + }; self.file_tracker.file_flags = unsafe { SCFileFlowFlagsToFlags(flow_file_flags, dir_flag) }; } } /// little wrapper around the FileTransferTracker::new_chunk method -pub fn filetracker_newchunk(ft: &mut FileTransferTracker, name: &[u8], data: &[u8], - chunk_offset: u64, chunk_size: u32, is_last: bool, xid: &u32) -{ +pub fn filetracker_newchunk( + ft: &mut FileTransferTracker, name: &[u8], data: &[u8], chunk_offset: u64, chunk_size: u32, + is_last: bool, xid: &u32, +) { if let Some(sfcm) = unsafe { SURICATA_SMB_FILE_CONFIG } { - ft.new_chunk(sfcm, name, data, chunk_offset, - chunk_size, 0, is_last, xid); + ft.new_chunk(sfcm, name, data, chunk_offset, chunk_size, 0, is_last, xid); } } -pub fn filetracker_trunc(ft: &mut FileTransferTracker) -{ +pub fn filetracker_trunc(ft: &mut FileTransferTracker) { if let Some(sfcm) = unsafe { SURICATA_SMB_FILE_CONFIG } { ft.trunc(sfcm); } } -pub fn filetracker_close(ft: &mut FileTransferTracker) -{ +pub fn filetracker_close(ft: &mut FileTransferTracker) { if let Some(sfcm) = unsafe { SURICATA_SMB_FILE_CONFIG } { ft.close(sfcm); } } -fn filetracker_update(ft: &mut FileTransferTracker, data: &[u8], gap_size: u32) -> u32 -{ +fn filetracker_update(ft: &mut FileTransferTracker, data: &[u8], gap_size: u32) -> u32 { if let Some(sfcm) = unsafe { SURICATA_SMB_FILE_CONFIG } { ft.update(sfcm, data, gap_size) } else { @@ -86,9 +87,9 @@ fn filetracker_update(ft: &mut FileTransferTracker, data: &[u8], gap_size: u32) } impl SMBState { - pub fn new_file_tx(&mut self, fuid: &[u8], file_name: &[u8], direction: Direction) - -> &mut SMBTransaction - { + pub fn new_file_tx( + &mut self, fuid: &[u8], file_name: &[u8], direction: Direction, + ) -> &mut SMBTransaction { let mut tx = self.new_tx(); tx.type_data = Some(SMBTransactionTypeData::FILE(SMBTransactionFile::new())); if let Some(SMBTransactionTypeData::FILE(ref mut d)) = tx.type_data { @@ -100,9 +101,16 @@ impl SMBState { d.update_file_flags(tx.tx_data.0.file_flags); } tx.tx_data.init_files_opened(); - tx.tx_data.0.file_tx = if direction == Direction::ToServer { STREAM_TOSERVER } else { STREAM_TOCLIENT }; // TODO direction to flag func? - SCLogDebug!("SMB: new_file_tx: TX FILE created: ID {} NAME {}", - tx.id, String::from_utf8_lossy(file_name)); + tx.tx_data.0.file_tx = if direction == Direction::ToServer { + STREAM_TOSERVER + } else { + STREAM_TOCLIENT + }; // TODO direction to flag func? + SCLogDebug!( + "SMB: new_file_tx: TX FILE created: ID {} NAME {}", + tx.id, + String::from_utf8_lossy(file_name) + ); self.transactions.push_back(tx); let tx_ref = self.transactions.back_mut(); return tx_ref.unwrap(); @@ -110,16 +118,16 @@ impl SMBState { /// get file tx for a open file. Returns None if a file for the fuid exists, /// but has already been closed. - pub fn get_file_tx_by_fuid_with_open_file(&mut self, fuid: &[u8], direction: Direction) - -> Option<&mut SMBTransaction> - { + pub fn get_file_tx_by_fuid_with_open_file( + &mut self, fuid: &[u8], direction: Direction, + ) -> Option<&mut SMBTransaction> { let f = fuid.to_vec(); for tx in &mut self.transactions { let found = match tx.type_data { Some(SMBTransactionTypeData::FILE(ref mut d)) => { direction == d.direction && f == d.fuid && !d.file_tracker.is_done() - }, - _ => { false }, + } + _ => false, }; if found { @@ -138,16 +146,16 @@ impl SMBState { } /// get file tx for a fuid. File may already have been closed. - pub fn get_file_tx_by_fuid(&mut self, fuid: &[u8], direction: Direction) - -> Option<&mut SMBTransaction> - { + pub fn get_file_tx_by_fuid( + &mut self, fuid: &[u8], direction: Direction, + ) -> Option<&mut SMBTransaction> { let f = fuid.to_vec(); for tx in &mut self.transactions { let found = match tx.type_data { Some(SMBTransactionTypeData::FILE(ref mut d)) => { direction == d.direction && f == d.fuid - }, - _ => { false }, + } + _ => false, }; if found { @@ -174,7 +182,7 @@ impl SMBState { self.file_tc_left }; if chunk_left == 0 { - return 0 + return 0; } SCLogDebug!("chunk_left {} data {}", chunk_left, data.len()); let file_handle = if direction == Direction::ToServer { @@ -208,8 +216,12 @@ impl SMBState { if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { if ssn_gap { let queued_data = tdf.file_tracker.get_queued_size(); - if queued_data > 2000000 { // TODO should probably be configurable - SCLogDebug!("QUEUED size {} while we've seen GAPs. Truncating file.", queued_data); + if queued_data > 2000000 { + // TODO should probably be configurable + SCLogDebug!( + "QUEUED size {} while we've seen GAPs. Truncating file.", + queued_data + ); filetracker_trunc(&mut tdf.file_tracker); } } @@ -224,10 +236,11 @@ impl SMBState { } else { 0 } - }, + } None => { SCLogDebug!("not found for handle {:?}", file_handle); - 0 }, + 0 + } }; return consumed; @@ -236,13 +249,18 @@ impl SMBState { use crate::applayer::AppLayerGetFileState; -pub(super) unsafe extern "C" fn smb_gettxfiles(tx: *mut std::ffi::c_void, direction: u8) -> AppLayerGetFileState { +pub(super) unsafe extern "C" fn smb_gettxfiles( + tx: *mut std::ffi::c_void, direction: u8, +) -> AppLayerGetFileState { let tx = cast_pointer!(tx, SMBTransaction); if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { - let tx_dir : u8 = tdf.direction.into(); + let tx_dir: u8 = tdf.direction.into(); if direction & tx_dir != 0 { if let Some(sfcm) = { SURICATA_SMB_FILE_CONFIG } { - return AppLayerGetFileState { fc: &mut tdf.file_tracker.file, cfg: sfcm.files_sbcfg } + return AppLayerGetFileState { + fc: &mut tdf.file_tracker.file, + cfg: sfcm.files_sbcfg, + }; } } } diff --git a/rust/src/smb/funcs.rs b/rust/src/smb/funcs.rs index afab69d967..43410418be 100644 --- a/rust/src/smb/funcs.rs +++ b/rust/src/smb/funcs.rs @@ -23,7 +23,7 @@ pub fn fsctl_func_to_string(f: u32) -> String { 0x00060194 => "FSCTL_DFS_GET_REFERRALS", 0x000601B0 => "FSCTL_DFS_GET_REFERRALS_EX", 0x00090000 => "FSCTL_REQUEST_OPLOCK_LEVEL_1", - 0x00090004 => "FSCTL_REQUEST_OPLOCK_LEVEL_2", + 0x00090004 => "FSCTL_REQUEST_OPLOCK_LEVEL_2", 0x00090008 => "FSCTL_REQUEST_BATCH_OPLOCK", 0x0009000C => "FSCTL_OPLOCK_BREAK_ACKNOWLEDGE", 0x00090010 => "FSCTL_OPBATCH_ACK_CLOSE_PENDING", @@ -38,7 +38,7 @@ pub fn fsctl_func_to_string(f: u32) -> String { 0x0009003C => "FSCTL_GET_COMPRESSION", 0x0009004F => "FSCTL_MARK_AS_SYSTEM_HIVE", 0x00090050 => "FSCTL_OPLOCK_BREAK_ACK_NO_2", - 0x00090054 => "FSCTL_INVALIDATE_VOLUMES", + 0x00090054 => "FSCTL_INVALIDATE_VOLUMES", 0x00090058 => "FSCTL_QUERY_FAT_BPB", 0x0009005C => "FSCTL_REQUEST_FILTER_OPLOCK", 0x00090060 => "FSCTL_FILESYSTEM_GET_STATISTICS", @@ -48,7 +48,7 @@ pub fn fsctl_func_to_string(f: u32) -> String { 0x00090073 => "FSCTL_GET_RETRIEVAL_POINTERS", 0x00090074 => "FSCTL_MOVE_FILE", 0x00090078 => "FSCTL_IS_VOLUME_DIRTY", - 0x0009007C => "FSCTL_GET_HFS_INFORMATION", + 0x0009007C => "FSCTL_GET_HFS_INFORMATION", 0x00090083 => "FSCTL_ALLOW_EXTENDED_DASD_IO", 0x00090087 => "FSCTL_READ_PROPERTY_DATA", 0x0009008B => "FSCTL_WRITE_PROPERTY_DATA", @@ -109,6 +109,9 @@ pub fn fsctl_func_to_string(f: u32) -> String { 0x001440F2 => "FSCTL_SRV_COPYCHUNK", 0x001441bb => "FSCTL_SRV_READ_HASH", 0x001480F2 => "FSCTL_SRV_COPYCHUNK_WRITE", - _ => { return (f).to_string(); }, - }.to_string() + _ => { + return (f).to_string(); + } + } + .to_string() } diff --git a/rust/src/smb/log.rs b/rust/src/smb/log.rs index 5cb8ea5762..10f520db10 100644 --- a/rust/src/smb/log.rs +++ b/rust/src/smb/log.rs @@ -15,23 +15,25 @@ * 02110-1301, USA. */ -use std::str; -use std::string::String; -use uuid; -use suricata_sys::sys::SCConfNode; use crate::conf::ConfNode; +use crate::dcerpc::dcerpc::*; use crate::jsonbuilder::{JsonBuilder, JsonError}; +use crate::smb::funcs::*; use crate::smb::smb::*; use crate::smb::smb1::*; use crate::smb::smb2::*; -use crate::dcerpc::dcerpc::*; -use crate::smb::funcs::*; use crate::smb::smb_status::*; use std::error::Error; use std::fmt; +use std::str; +use std::string::String; +use suricata_sys::sys::SCConfNode; +use uuid; #[cfg(not(feature = "debug"))] -fn debug_add_progress(_js: &mut JsonBuilder, _tx: &SMBTransaction) -> Result<(), JsonError> { Ok(()) } +fn debug_add_progress(_js: &mut JsonBuilder, _tx: &SMBTransaction) -> Result<(), JsonError> { + Ok(()) +} #[cfg(feature = "debug")] fn debug_add_progress(jsb: &mut JsonBuilder, tx: &SMBTransaction) -> Result<(), JsonError> { @@ -107,7 +109,7 @@ fn smb_common_header( } else { let dialect = match state.dialect_vec { Some(ref d) => str::from_utf8(d).unwrap_or("invalid"), - None => "unknown", + None => "unknown", }; jsb.set_string("dialect", dialect)?; } @@ -118,14 +120,14 @@ fn smb_common_header( if ok { jsb.set_string("command", &smb1_command_string(cmd))?; } - }, + } 2 => { let (ok, cmd) = tx.vercmd.get_smb2_cmd(); if ok { jsb.set_string("command", &smb2_command_string(cmd))?; } - }, - _ => { }, + } + _ => {} } match tx.vercmd.get_ntstatus() { @@ -136,39 +138,39 @@ fn smb_common_header( None => { let status_str = format!("{}", ntstatus); jsb.set_string("status", &status_str)? - }, + } }; let status_hex = format!("0x{:x}", ntstatus); jsb.set_string("status_code", &status_hex)?; - }, + } (false, _) => { #[allow(clippy::single_match)] match tx.vercmd.get_dos_error() { (true, errclass, errcode) => { match errclass { - 1 => { // DOSERR + 1 => { + // DOSERR let status = smb_dos_error_string(errcode); jsb.set_string("status", &status)?; - }, - 2 => { // SRVERR + } + 2 => { + // SRVERR let status = smb_srv_error_string(errcode); jsb.set_string("status", &status)?; } _ => { let s = format!("UNKNOWN_{:02x}_{:04x}", errclass, errcode); jsb.set_string("status", &s)?; - }, + } } let status_hex = format!("0x{:04x}", errcode); jsb.set_string("status_code", &status_hex)?; - }, - (_, _, _) => { - }, + } + (_, _, _) => {} } - }, + } } - jsb.set_uint("session_id", tx.hdr.ssn_id)?; jsb.set_uint("tree_id", tx.hdr.tree_id as u64)?; @@ -224,13 +226,13 @@ fn smb_common_header( jsb.set_string("native_lm", &lm)?; jsb.close()?; } - }, + } Some(SMBTransactionTypeData::CREATE(ref x)) => { if flags != SMB_LOG_DEFAULT_ALL && (flags & SMB_LOG_TYPE_CREATE) == 0 { return Err(SmbLogError::SkippedByConf); } let mut name_raw = x.filename.to_vec(); - name_raw.retain(|&i|i != 0x00); + name_raw.retain(|&i| i != 0x00); if !name_raw.is_empty() { let name = String::from_utf8_lossy(&name_raw); if x.directory { @@ -243,13 +245,27 @@ fn smb_common_header( jsb.set_string("filename", "")?; } match x.disposition { - 0 => { jsb.set_string("disposition", "FILE_SUPERSEDE")?; }, - 1 => { jsb.set_string("disposition", "FILE_OPEN")?; }, - 2 => { jsb.set_string("disposition", "FILE_CREATE")?; }, - 3 => { jsb.set_string("disposition", "FILE_OPEN_IF")?; }, - 4 => { jsb.set_string("disposition", "FILE_OVERWRITE")?; }, - 5 => { jsb.set_string("disposition", "FILE_OVERWRITE_IF")?; }, - _ => { jsb.set_string("disposition", "UNKNOWN")?; }, + 0 => { + jsb.set_string("disposition", "FILE_SUPERSEDE")?; + } + 1 => { + jsb.set_string("disposition", "FILE_OPEN")?; + } + 2 => { + jsb.set_string("disposition", "FILE_CREATE")?; + } + 3 => { + jsb.set_string("disposition", "FILE_OPEN_IF")?; + } + 4 => { + jsb.set_string("disposition", "FILE_OVERWRITE")?; + } + 5 => { + jsb.set_string("disposition", "FILE_OVERWRITE_IF")?; + } + _ => { + jsb.set_string("disposition", "UNKNOWN")?; + } } if x.delete_on_close { jsb.set_string("access", "delete on close")?; @@ -266,7 +282,7 @@ fn smb_common_header( let gs = fuid_to_string(&x.guid); jsb.set_string("fuid", &gs)?; - }, + } Some(SMBTransactionTypeData::NEGOTIATE(ref x)) => { if flags != SMB_LOG_DEFAULT_ALL && (flags & SMB_LOG_TYPE_NEGOTIATE) == 0 { return Err(SmbLogError::SkippedByConf); @@ -299,7 +315,7 @@ fn smb_common_header( if state.max_write_size > 0 { jsb.set_uint("max_write_size", state.max_write_size)?; } - }, + } Some(SMBTransactionTypeData::TREECONNECT(ref x)) => { if flags != SMB_LOG_DEFAULT_ALL && (flags & SMB_LOG_TYPE_TREECONNECT) == 0 { return Err(SmbLogError::SkippedByConf); @@ -328,13 +344,21 @@ fn smb_common_header( // share type only for SMB2 } else { match x.share_type { - 1 => { jsb.set_string("share_type", "FILE")?; }, - 2 => { jsb.set_string("share_type", "PIPE")?; }, - 3 => { jsb.set_string("share_type", "PRINT")?; }, - _ => { jsb.set_string("share_type", "UNKNOWN")?; }, + 1 => { + jsb.set_string("share_type", "FILE")?; + } + 2 => { + jsb.set_string("share_type", "PIPE")?; + } + 3 => { + jsb.set_string("share_type", "PRINT")?; + } + _ => { + jsb.set_string("share_type", "UNKNOWN")?; + } } } - }, + } Some(SMBTransactionTypeData::FILE(ref x)) => { if flags != SMB_LOG_DEFAULT_ALL && (flags & SMB_LOG_TYPE_FILE) == 0 { return Err(SmbLogError::SkippedByConf); @@ -345,7 +369,7 @@ fn smb_common_header( jsb.set_string("share", &share_name)?; let gs = fuid_to_string(&x.fuid); jsb.set_string("fuid", &gs)?; - }, + } Some(SMBTransactionTypeData::RENAME(ref x)) => { if flags != SMB_LOG_DEFAULT_ALL && (flags & SMB_LOG_TYPE_RENAME) == 0 { return Err(SmbLogError::SkippedByConf); @@ -365,7 +389,7 @@ fn smb_common_header( jsb.close()?; let gs = fuid_to_string(&x.fuid); jsb.set_string("fuid", &gs)?; - }, + } Some(SMBTransactionTypeData::DCERPC(ref x)) => { if flags != SMB_LOG_DEFAULT_ALL && (flags & SMB_LOG_TYPE_DCERPC) == 0 { return Err(SmbLogError::SkippedByConf); @@ -403,7 +427,9 @@ fn smb_common_header( for i in ifaces { jsb.start_object()?; let ifstr = uuid::Uuid::from_slice(&i.uuid); - let ifstr = ifstr.map(|ifstr| ifstr.to_hyphenated().to_string()).unwrap(); + let ifstr = ifstr + .map(|ifstr| ifstr.to_hyphenated().to_string()) + .unwrap(); jsb.set_string("uuid", &ifstr)?; let vstr = format!("{}.{}", i.ver, i.ver_min); jsb.set_string("version", &vstr)?; @@ -412,18 +438,20 @@ fn smb_common_header( jsb.close()?; } } - }, + } DCERPC_TYPE_BIND => { if let Some(ref ifaces) = state.dcerpc_ifaces { jsb.open_array("interfaces")?; for i in ifaces { jsb.start_object()?; let ifstr = uuid::Uuid::from_slice(&i.uuid); - let ifstr = ifstr.map(|ifstr| ifstr.to_hyphenated().to_string()).unwrap(); + let ifstr = ifstr + .map(|ifstr| ifstr.to_hyphenated().to_string()) + .unwrap(); jsb.set_string("uuid", &ifstr)?; let vstr = format!("{}.{}", i.ver, i.ver_min); jsb.set_string("version", &vstr)?; - + if i.acked { jsb.set_uint("ack_result", i.ack_result as u64)?; jsb.set_uint("ack_reason", i.ack_reason as u64)?; @@ -432,8 +460,8 @@ fn smb_common_header( } jsb.close()?; } - }, - _ => {}, + } + _ => {} } } if x.res_set { @@ -444,9 +472,9 @@ fn smb_common_header( jsb.set_uint("frag_cnt", x.frag_cnt_tc as u64)?; jsb.set_uint("stub_data_size", x.stub_data_tc.len() as u64)?; jsb.close()?; - }, + } // we don't handle BINDACK w/o BIND - _ => {}, + _ => {} } } jsb.set_uint("call_id", x.call_id as u64)?; @@ -457,13 +485,13 @@ fn smb_common_header( return Err(SmbLogError::SkippedByConf); } jsb.set_string("function", &fsctl_func_to_string(x.func))?; - }, + } Some(SMBTransactionTypeData::SETFILEPATHINFO(ref x)) => { if flags != SMB_LOG_DEFAULT_ALL && (flags & SMB_LOG_TYPE_SETFILEPATHINFO) == 0 { return Err(SmbLogError::SkippedByConf); } let mut name_raw = x.filename.to_vec(); - name_raw.retain(|&i|i != 0x00); + name_raw.retain(|&i| i != 0x00); if !name_raw.is_empty() { let name = String::from_utf8_lossy(&name_raw); jsb.set_string("filename", &name)?; @@ -480,29 +508,30 @@ fn smb_common_header( match x.subcmd { 8 => { jsb.set_string("subcmd", "SET_FILE_INFO")?; - }, + } 6 => { jsb.set_string("subcmd", "SET_PATH_INFO")?; - }, - _ => { }, + } + _ => {} } #[allow(clippy::single_match)] match x.loi { - 1013 => { // Set Disposition Information + 1013 => { + // Set Disposition Information jsb.set_string("level_of_interest", "Set Disposition Information")?; - }, - _ => { }, + } + _ => {} } let gs = fuid_to_string(&x.fid); jsb.set_string("fuid", &gs)?; - }, + } None => { if flags != SMB_LOG_DEFAULT_ALL && (flags & SMB_LOG_TYPE_GENERIC) == 0 { return Err(SmbLogError::SkippedByConf); } - }, + } } return Ok(()); } diff --git a/rust/src/smb/mod.rs b/rust/src/smb/mod.rs index 18ceef5bd9..f5da6ba4fc 100644 --- a/rust/src/smb/mod.rs +++ b/rust/src/smb/mod.rs @@ -19,26 +19,27 @@ pub mod error; pub mod smb_records; +#[rustfmt::skip] pub mod smb_status; -pub mod smb1_records; -pub mod smb2_records; -pub mod nbss_records; pub mod dcerpc_records; +pub mod nbss_records; pub mod ntlmssp_records; +pub mod smb1_records; +pub mod smb2_records; +pub mod auth; +pub mod dcerpc; +pub mod debug; +pub mod detect; +pub mod events; +pub mod files; +pub mod funcs; +pub mod log; +pub mod session; pub mod smb; pub mod smb1; pub mod smb1_session; pub mod smb2; -pub mod smb2_session; pub mod smb2_ioctl; +pub mod smb2_session; pub mod smb3; -pub mod dcerpc; -pub mod session; -pub mod log; -pub mod detect; -pub mod debug; -pub mod events; -pub mod auth; -pub mod files; -pub mod funcs; diff --git a/rust/src/smb/nbss_records.rs b/rust/src/smb/nbss_records.rs index d450d65eed..c2dd8e0f96 100644 --- a/rust/src/smb/nbss_records.rs +++ b/rust/src/smb/nbss_records.rs @@ -18,32 +18,32 @@ use nom8::bytes::streaming::take; use nom8::combinator::rest; use nom8::number::streaming::be_u32; -use nom8::Parser; use nom8::IResult; +use nom8::Parser; -pub const NBSS_MSGTYPE_SESSION_MESSAGE: u8 = 0x00; -pub const NBSS_MSGTYPE_SESSION_REQUEST: u8 = 0x81; -pub const NBSS_MSGTYPE_POSITIVE_SSN_RESPONSE: u8 = 0x82; -pub const NBSS_MSGTYPE_NEGATIVE_SSN_RESPONSE: u8 = 0x83; -pub const NBSS_MSGTYPE_RETARG_RESPONSE: u8 = 0x84; -pub const NBSS_MSGTYPE_KEEP_ALIVE: u8 = 0x85; +pub const NBSS_MSGTYPE_SESSION_MESSAGE: u8 = 0x00; +pub const NBSS_MSGTYPE_SESSION_REQUEST: u8 = 0x81; +pub const NBSS_MSGTYPE_POSITIVE_SSN_RESPONSE: u8 = 0x82; +pub const NBSS_MSGTYPE_NEGATIVE_SSN_RESPONSE: u8 = 0x83; +pub const NBSS_MSGTYPE_RETARG_RESPONSE: u8 = 0x84; +pub const NBSS_MSGTYPE_KEEP_ALIVE: u8 = 0x85; -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct NbssRecord<'a> { pub message_type: u8, pub length: u32, - pub data: &'a[u8], + pub data: &'a [u8], } impl NbssRecord<'_> { pub fn is_valid(&self) -> bool { let valid = match self.message_type { - NBSS_MSGTYPE_SESSION_MESSAGE | - NBSS_MSGTYPE_SESSION_REQUEST | - NBSS_MSGTYPE_POSITIVE_SSN_RESPONSE | - NBSS_MSGTYPE_NEGATIVE_SSN_RESPONSE | - NBSS_MSGTYPE_RETARG_RESPONSE | - NBSS_MSGTYPE_KEEP_ALIVE => true, + NBSS_MSGTYPE_SESSION_MESSAGE + | NBSS_MSGTYPE_SESSION_REQUEST + | NBSS_MSGTYPE_POSITIVE_SSN_RESPONSE + | NBSS_MSGTYPE_NEGATIVE_SSN_RESPONSE + | NBSS_MSGTYPE_RETARG_RESPONSE + | NBSS_MSGTYPE_KEEP_ALIVE => true, _ => false, }; valid @@ -53,8 +53,11 @@ impl NbssRecord<'_> { } pub fn is_smb(&self) -> bool { let valid = self.is_valid(); - let smb = self.data.len() >= 4 && - self.data[1] == b'S' && self.data[2] == b'M' && self.data[3] == b'B' && (self.data[0] == b'\xFE' || self.data[0] == b'\xFF' || self.data[0] == b'\xFD'); + let smb = self.data.len() >= 4 + && self.data[1] == b'S' + && self.data[2] == b'M' + && self.data[3] == b'B' + && (self.data[0] == b'\xFE' || self.data[0] == b'\xFF' || self.data[0] == b'\xFD'); valid && smb } @@ -94,19 +97,15 @@ mod tests { #[test] fn test_parse_nbss_record() { - let buff:&[u8] = &[ - /* message type */ 0x00, - /* length */ 0x00, 0x00, 0x55, - /* data */ 0xff, 0x53, 0x4d, 0x42, 0x72, 0x00, 0x00, 0x00, 0x00, - 0x98, 0x53, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xfe, 0x00, 0x00, 0x00, 0x00, 0x11, 0x05, 0x00, 0x03, - 0x0a, 0x00, 0x01, 0x00, 0x04, 0x11, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xe3, - 0x00, 0x80, 0x2a, 0x55, 0xc4, 0x38, 0x89, 0x03, 0xcd, - 0x01, 0x2c, 0x01, 0x00, 0x10, 0x00, 0xfe, 0x82, 0xf1, - 0x64, 0x0b, 0x66, 0xba, 0x4a, 0xbb, 0x81, 0xe1, 0xea, - 0x54, 0xae, 0xb8, 0x66]; + let buff: &[u8] = &[ + /* message type */ 0x00, /* length */ 0x00, 0x00, 0x55, /* data */ 0xff, + 0x53, 0x4d, 0x42, 0x72, 0x00, 0x00, 0x00, 0x00, 0x98, 0x53, 0xc8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfe, 0x00, + 0x00, 0x00, 0x00, 0x11, 0x05, 0x00, 0x03, 0x0a, 0x00, 0x01, 0x00, 0x04, 0x11, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xe3, 0x00, 0x80, 0x2a, + 0x55, 0xc4, 0x38, 0x89, 0x03, 0xcd, 0x01, 0x2c, 0x01, 0x00, 0x10, 0x00, 0xfe, 0x82, + 0xf1, 0x64, 0x0b, 0x66, 0xba, 0x4a, 0xbb, 0x81, 0xe1, 0xea, 0x54, 0xae, 0xb8, 0x66, + ]; let result = parse_nbss_record(buff); match result { @@ -137,19 +136,16 @@ mod tests { } // Non-SMB packet scenario - let buff_not_smb:&[u8] = &[ - /* message type */ 0x00, - /* length */ 0x00, 0x00, 0x55, - /* data !SMB */ 0xff, 0x52, 0x4e, 0x41, 0x72, 0x00, 0x00, 0x00, 0x00, - 0x98, 0x53, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xfe, 0x00, 0x00, 0x00, 0x00, 0x11, 0x05, 0x00, 0x03, - 0x0a, 0x00, 0x01, 0x00, 0x04, 0x11, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xe3, - 0x00, 0x80, 0x2a, 0x55, 0xc4, 0x38, 0x89, 0x03, 0xcd, - 0x01, 0x2c, 0x01, 0x00, 0x10, 0x00, 0xfe, 0x82, 0xf1, - 0x64, 0x0b, 0x66, 0xba, 0x4a, 0xbb, 0x81, 0xe1, 0xea, - 0x54, 0xae, 0xb8, 0x66]; + let buff_not_smb: &[u8] = &[ + /* message type */ 0x00, /* length */ 0x00, 0x00, 0x55, + /* data !SMB */ 0xff, 0x52, 0x4e, 0x41, 0x72, 0x00, 0x00, 0x00, 0x00, 0x98, 0x53, + 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x11, 0x05, 0x00, 0x03, 0x0a, 0x00, 0x01, + 0x00, 0x04, 0x11, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, + 0xe3, 0x00, 0x80, 0x2a, 0x55, 0xc4, 0x38, 0x89, 0x03, 0xcd, 0x01, 0x2c, 0x01, 0x00, + 0x10, 0x00, 0xfe, 0x82, 0xf1, 0x64, 0x0b, 0x66, 0xba, 0x4a, 0xbb, 0x81, 0xe1, 0xea, + 0x54, 0xae, 0xb8, 0x66, + ]; let result_not_smb = parse_nbss_record(buff_not_smb); match result_not_smb { @@ -183,14 +179,13 @@ mod tests { #[test] fn test_parse_nbss_record_partial() { - let buff:&[u8] = &[ - /* message type */ 0x00, - /* length */ 0x00, 0x00, 0x29, - /* data < length*/ 0xff, 0x53, 0x4d, 0x42, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x18, 0x43, 0xc8, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x08, 0xbd, 0x20, 0x02, 0x08, 0x06, 0x00, - 0x02, 0x40, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00]; + let buff: &[u8] = &[ + /* message type */ 0x00, /* length */ 0x00, 0x00, 0x29, + /* data < length*/ 0xff, 0x53, 0x4d, 0x42, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x43, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x08, 0xbd, 0x20, 0x02, 0x08, 0x06, 0x00, 0x02, 0x40, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, + ]; let result = parse_nbss_record_partial(buff); match result { @@ -219,6 +214,5 @@ mod tests { panic!("Unexpected behavior!"); } } - } } diff --git a/rust/src/smb/ntlmssp_records.rs b/rust/src/smb/ntlmssp_records.rs index f7824a9207..5ebee57e60 100644 --- a/rust/src/smb/ntlmssp_records.rs +++ b/rust/src/smb/ntlmssp_records.rs @@ -20,9 +20,9 @@ use nom8::bytes::streaming::take; use nom8::combinator::{cond, rest, verify}; use nom8::error::{make_error, ErrorKind}; use nom8::number::streaming::{le_u16, le_u32, le_u8}; -use nom8::Parser; use nom8::Err; use nom8::IResult; +use nom8::Parser; use std::fmt; #[derive(Debug, PartialEq, Eq)] diff --git a/rust/src/smb/session.rs b/rust/src/smb/session.rs index 5b65a55451..f20f45b2ce 100644 --- a/rust/src/smb/session.rs +++ b/rust/src/smb/session.rs @@ -16,10 +16,10 @@ */ use crate::kerberos::*; +use crate::smb::auth::*; use crate::smb::smb::*; -use crate::smb::smb1_session::*; use crate::smb::smb1_records::SessionSetupRequest; -use crate::smb::auth::*; +use crate::smb::smb1_session::*; #[derive(Default, Debug)] pub struct SMBTransactionSessionSetup { @@ -31,19 +31,18 @@ pub struct SMBTransactionSessionSetup { impl SMBTransactionSessionSetup { pub fn new() -> Self { - return Default::default() + return Default::default(); } } impl SMBState { - pub fn new_sessionsetup_tx(&mut self, hdr: SMBCommonHdr) - -> &mut SMBTransaction - { + pub fn new_sessionsetup_tx(&mut self, hdr: SMBCommonHdr) -> &mut SMBTransaction { let mut tx = self.new_tx(); tx.hdr = hdr; tx.type_data = Some(SMBTransactionTypeData::SESSIONSETUP( - SMBTransactionSessionSetup::new())); + SMBTransactionSessionSetup::new(), + )); tx.request_done = true; tx.response_done = self.tc_trunc; // no response expected if tc is truncated @@ -53,14 +52,13 @@ impl SMBState { return tx_ref.unwrap(); } - pub fn get_sessionsetup_tx(&mut self, hdr: SMBCommonHdr) - -> Option<&mut SMBTransaction> - { + pub fn get_sessionsetup_tx(&mut self, hdr: SMBCommonHdr) -> Option<&mut SMBTransaction> { for tx in &mut self.transactions { - let hit = tx.hdr.compare(&hdr) && match tx.type_data { - Some(SMBTransactionTypeData::SESSIONSETUP(_)) => { true }, - _ => { false }, - }; + let hit = tx.hdr.compare(&hdr) + && match tx.type_data { + Some(SMBTransactionTypeData::SESSIONSETUP(_)) => true, + _ => false, + }; if hit { tx.tx_data.0.updated_tc = true; tx.tx_data.0.updated_ts = true; diff --git a/rust/src/smb/smb.rs b/rust/src/smb/smb.rs index 6851aa799b..3f9d0d374a 100644 --- a/rust/src/smb/smb.rs +++ b/rust/src/smb/smb.rs @@ -26,44 +26,44 @@ // written by Victor Julien use std; -use std::str; -use std::ffi::{self, CString}; use std::collections::VecDeque; - -use nom8::{Err, Needed}; +use std::ffi::{self, CString}; +use std::str; + use nom8::error::{make_error, ErrorKind}; +use nom8::{Err, Needed}; use lru::LruCache; +use std::num::NonZeroUsize; use suricata_sys::sys::{ AppLayerParserState, AppProto, SCAppLayerParserConfParserEnabled, SCAppLayerParserSetStreamDepth, SCAppLayerProtoDetectConfProtoDetectionEnabled, SCAppLayerProtoDetectPMRegisterPatternCSwPP, SCAppLayerProtoDetectPPParseConfPorts, SCAppLayerProtoDetectPPRegister, }; -use std::num::NonZeroUsize; -use crate::core::*; use crate::applayer; use crate::applayer::*; -use crate::direction::Direction; -use crate::flow::{Flow, FLOW_DIR_REVERSED, flow_get_flags, flow_get_last_time, flow_get_ports}; -use crate::frames::*; +use crate::applayer::{AppLayerEvent, AppLayerResult, AppLayerTxData}; use crate::conf::*; -use crate::applayer::{AppLayerResult, AppLayerTxData, AppLayerEvent}; +use crate::core::*; +use crate::direction::Direction; use crate::filecontainer::FileContainerWrapper; +use crate::flow::{flow_get_flags, flow_get_last_time, flow_get_ports, Flow, FLOW_DIR_REVERSED}; +use crate::frames::*; use crate::smb::nbss_records::*; use crate::smb::smb1_records::*; use crate::smb::smb2_records::*; -use crate::smb::smb1::*; -use crate::smb::smb2::*; -use crate::smb::smb3::*; use crate::smb::dcerpc::*; -use crate::smb::session::*; use crate::smb::events::*; use crate::smb::files::*; +use crate::smb::session::*; +use crate::smb::smb1::*; +use crate::smb::smb2::*; use crate::smb::smb2_ioctl::*; +use crate::smb::smb3::*; #[derive(AppLayerFrameType)] pub enum SMBFrameType { @@ -110,62 +110,70 @@ static mut SMB_MAX_TX: usize = 1024; pub static mut SURICATA_SMB_FILE_CONFIG: Option<&'static SuricataFileContext> = None; #[no_mangle] -pub extern "C" fn SCSmbInit(context: &'static mut SuricataFileContext) -{ +pub extern "C" fn SCSmbInit(context: &'static mut SuricataFileContext) { unsafe { SURICATA_SMB_FILE_CONFIG = Some(context); } } -pub const SMB_SRV_ERROR: u16 = 1; -pub const SMB_SRV_BADPW: u16 = 2; -pub const SMB_SRV_BADTYPE: u16 = 3; -pub const SMB_SRV_ACCESS: u16 = 4; -pub const SMB_SRV_BADUID: u16 = 91; +pub const SMB_SRV_ERROR: u16 = 1; +pub const SMB_SRV_BADPW: u16 = 2; +pub const SMB_SRV_BADTYPE: u16 = 3; +pub const SMB_SRV_ACCESS: u16 = 4; +pub const SMB_SRV_BADUID: u16 = 91; pub fn smb_srv_error_string(c: u16) -> String { match c { - SMB_SRV_ERROR => "SRV_ERROR", - SMB_SRV_BADPW => "SRV_BADPW", - SMB_SRV_BADTYPE => "SRV_BADTYPE", - SMB_SRV_ACCESS => "SRV_ACCESS", - SMB_SRV_BADUID => "SRV_BADUID", - _ => { return (c).to_string(); }, - }.to_string() -} - -pub const SMB_DOS_SUCCESS: u16 = 0; -pub const SMB_DOS_BAD_FUNC: u16 = 1; -pub const SMB_DOS_BAD_FILE: u16 = 2; -pub const SMB_DOS_BAD_PATH: u16 = 3; -pub const SMB_DOS_TOO_MANY_OPEN_FILES: u16 = 4; -pub const SMB_DOS_ACCESS_DENIED: u16 = 5; + SMB_SRV_ERROR => "SRV_ERROR", + SMB_SRV_BADPW => "SRV_BADPW", + SMB_SRV_BADTYPE => "SRV_BADTYPE", + SMB_SRV_ACCESS => "SRV_ACCESS", + SMB_SRV_BADUID => "SRV_BADUID", + _ => { + return (c).to_string(); + } + } + .to_string() +} + +pub const SMB_DOS_SUCCESS: u16 = 0; +pub const SMB_DOS_BAD_FUNC: u16 = 1; +pub const SMB_DOS_BAD_FILE: u16 = 2; +pub const SMB_DOS_BAD_PATH: u16 = 3; +pub const SMB_DOS_TOO_MANY_OPEN_FILES: u16 = 4; +pub const SMB_DOS_ACCESS_DENIED: u16 = 5; pub fn smb_dos_error_string(c: u16) -> String { match c { - SMB_DOS_SUCCESS => "DOS_SUCCESS", - SMB_DOS_BAD_FUNC => "DOS_BAD_FUNC", - SMB_DOS_BAD_FILE => "DOS_BAD_FILE", - SMB_DOS_BAD_PATH => "DOS_BAD_PATH", + SMB_DOS_SUCCESS => "DOS_SUCCESS", + SMB_DOS_BAD_FUNC => "DOS_BAD_FUNC", + SMB_DOS_BAD_FILE => "DOS_BAD_FILE", + SMB_DOS_BAD_PATH => "DOS_BAD_PATH", SMB_DOS_TOO_MANY_OPEN_FILES => "DOS_TOO_MANY_OPEN_FILES", - SMB_DOS_ACCESS_DENIED => "DOS_ACCESS_DENIED", - _ => { return (c).to_string(); }, - }.to_string() + SMB_DOS_ACCESS_DENIED => "DOS_ACCESS_DENIED", + _ => { + return (c).to_string(); + } + } + .to_string() } -pub const NTLMSSP_NEGOTIATE: u32 = 1; +pub const NTLMSSP_NEGOTIATE: u32 = 1; #[cfg(feature = "debug")] -pub const NTLMSSP_CHALLENGE: u32 = 2; -pub const NTLMSSP_AUTH: u32 = 3; +pub const NTLMSSP_CHALLENGE: u32 = 2; +pub const NTLMSSP_AUTH: u32 = 3; #[cfg(feature = "debug")] pub fn ntlmssp_type_string(c: u32) -> String { match c { - NTLMSSP_NEGOTIATE => "NTLMSSP_NEGOTIATE", - NTLMSSP_CHALLENGE => "NTLMSSP_CHALLENGE", - NTLMSSP_AUTH => "NTLMSSP_AUTH", - _ => { return (c).to_string(); }, - }.to_string() + NTLMSSP_NEGOTIATE => "NTLMSSP_NEGOTIATE", + NTLMSSP_CHALLENGE => "NTLMSSP_CHALLENGE", + NTLMSSP_AUTH => "NTLMSSP_AUTH", + _ => { + return (c).to_string(); + } + } + .to_string() } #[derive(Default, Eq, PartialEq, Debug, Clone)] @@ -189,7 +197,7 @@ impl SMBVerCmdStat { smb_ver: 1, smb1_cmd: cmd, ..Default::default() - } + }; } pub fn new1_with_ntstatus(cmd: u8, status: u32) -> Self { return Self { @@ -198,14 +206,14 @@ impl SMBVerCmdStat { status_set: true, status, ..Default::default() - } + }; } pub fn new2(cmd: u16) -> Self { return Self { smb_ver: 2, smb2_cmd: cmd, ..Default::default() - } + }; } pub fn new2_with_ntstatus(cmd: u16, status: u32) -> Self { @@ -215,7 +223,7 @@ impl SMBVerCmdStat { status_set: true, status, ..Default::default() - } + }; } pub fn set_smb1_cmd(&mut self, cmd: u8) -> bool { @@ -259,11 +267,14 @@ impl SMBVerCmdStat { } pub fn get_dos_error(&self) -> (bool, u8, u16) { - (self.status_set && self.status_is_dos_error, self.status_error_class, self.status as u16) + ( + self.status_set && self.status_is_dos_error, + self.status_error_class, + self.status as u16, + ) } - fn set_status(&mut self, status: u32, is_dos_error: bool) - { + fn set_status(&mut self, status: u32, is_dos_error: bool) { if is_dos_error { self.status_is_dos_error = true; self.status_error_class = (status & 0x0000_00ff) as u8; @@ -274,13 +285,11 @@ impl SMBVerCmdStat { self.status_set = true; } - pub fn set_ntstatus(&mut self, status: u32) - { + pub fn set_ntstatus(&mut self, status: u32) { self.set_status(status, false) } - pub fn set_status_dos_error(&mut self, status: u32) - { + pub fn set_status_dos_error(&mut self, status: u32) { self.set_status(status, true) } } @@ -290,14 +299,12 @@ impl SMBVerCmdStat { /// Coordinated Universal Time (UTC)." #[derive(Eq, PartialEq, Debug, Clone)] pub struct SMBFiletime { - ts: u64, + ts: u64, } impl SMBFiletime { pub fn new(raw: u64) -> Self { - Self { - ts: raw, - } + Self { ts: raw } } /// inspired by Bro, convert FILETIME to secs since unix epoch @@ -335,11 +342,12 @@ pub struct SMBTransactionSetFilePathInfo { } impl SMBTransactionSetFilePathInfo { - pub fn new(filename: Vec, fid: Vec, subcmd: u16, loi: u16, delete_on_close: bool) - -> Self - { + pub fn new( + filename: Vec, fid: Vec, subcmd: u16, loi: u16, delete_on_close: bool, + ) -> Self { return Self { - filename, fid, + filename, + fid, subcmd, loi, delete_on_close, @@ -348,15 +356,14 @@ impl SMBTransactionSetFilePathInfo { } impl SMBState { - pub fn new_setfileinfo_tx(&mut self, filename: Vec, fid: Vec, - subcmd: u16, loi: u16, delete_on_close: bool) - -> &mut SMBTransaction - { + pub fn new_setfileinfo_tx( + &mut self, filename: Vec, fid: Vec, subcmd: u16, loi: u16, delete_on_close: bool, + ) -> &mut SMBTransaction { let mut tx = self.new_tx(); tx.type_data = Some(SMBTransactionTypeData::SETFILEPATHINFO( - SMBTransactionSetFilePathInfo::new( - filename, fid, subcmd, loi, delete_on_close))); + SMBTransactionSetFilePathInfo::new(filename, fid, subcmd, loi, delete_on_close), + )); tx.request_done = true; tx.response_done = self.tc_trunc; // no response expected if tc is truncated @@ -366,16 +373,15 @@ impl SMBState { return tx_ref.unwrap(); } - pub fn new_setpathinfo_tx(&mut self, filename: Vec, - subcmd: u16, loi: u16, delete_on_close: bool) - -> &mut SMBTransaction - { + pub fn new_setpathinfo_tx( + &mut self, filename: Vec, subcmd: u16, loi: u16, delete_on_close: bool, + ) -> &mut SMBTransaction { let mut tx = self.new_tx(); - let fid : Vec = Vec::new(); + let fid: Vec = Vec::new(); tx.type_data = Some(SMBTransactionTypeData::SETFILEPATHINFO( - SMBTransactionSetFilePathInfo::new(filename, fid, - subcmd, loi, delete_on_close))); + SMBTransactionSetFilePathInfo::new(filename, fid, subcmd, loi, delete_on_close), + )); tx.request_done = true; tx.response_done = self.tc_trunc; // no response expected if tc is truncated @@ -396,19 +402,22 @@ pub struct SMBTransactionRename { impl SMBTransactionRename { pub fn new(fuid: Vec, oldname: Vec, newname: Vec) -> Self { return Self { - fuid, oldname, newname, + fuid, + oldname, + newname, }; } } impl SMBState { - pub fn new_rename_tx(&mut self, fuid: Vec, oldname: Vec, newname: Vec) - -> &mut SMBTransaction - { + pub fn new_rename_tx( + &mut self, fuid: Vec, oldname: Vec, newname: Vec, + ) -> &mut SMBTransaction { let mut tx = self.new_tx(); - tx.type_data = Some(SMBTransactionTypeData::RENAME( - SMBTransactionRename::new(fuid, oldname, newname))); + tx.type_data = Some(SMBTransactionTypeData::RENAME(SMBTransactionRename::new( + fuid, oldname, newname, + ))); tx.request_done = true; tx.response_done = self.tc_trunc; // no response expected if tc is truncated @@ -443,7 +452,7 @@ impl SMBTransactionCreate { directory: dir, filename, ..Default::default() - } + }; } } @@ -525,18 +534,17 @@ impl Default for SMBTransaction { impl SMBTransaction { pub fn new() -> Self { return Self { - id: 0, - vercmd: SMBVerCmdStat::new(), - hdr: SMBCommonHdr::default(), - request_done: false, - response_done: false, - type_data: None, - tx_data: AppLayerTxData::new(), - } + id: 0, + vercmd: SMBVerCmdStat::new(), + hdr: SMBCommonHdr::default(), + request_done: false, + response_done: false, + type_data: None, + tx_data: AppLayerTxData::new(), + }; } - pub fn set_status(&mut self, status: u32, is_dos_error: bool) - { + pub fn set_status(&mut self, status: u32, is_dos_error: bool) { if is_dos_error { self.vercmd.set_status_dos_error(status); } else { @@ -570,25 +578,22 @@ pub struct SMBFileGUIDOffset { impl SMBFileGUIDOffset { pub fn new(guid: Vec, offset: u64) -> Self { - Self { - guid, - offset, - } + Self { guid, offset } } } /// type values to make sure we're not mixing things /// up in hashmap lookups -pub const SMBHDR_TYPE_GUID: u32 = 1; -pub const SMBHDR_TYPE_SHARE: u32 = 2; -pub const SMBHDR_TYPE_FILENAME: u32 = 3; -pub const SMBHDR_TYPE_OFFSET: u32 = 4; -pub const SMBHDR_TYPE_GENERICTX: u32 = 5; -pub const SMBHDR_TYPE_HEADER: u32 = 6; +pub const SMBHDR_TYPE_GUID: u32 = 1; +pub const SMBHDR_TYPE_SHARE: u32 = 2; +pub const SMBHDR_TYPE_FILENAME: u32 = 3; +pub const SMBHDR_TYPE_OFFSET: u32 = 4; +pub const SMBHDR_TYPE_GENERICTX: u32 = 5; +pub const SMBHDR_TYPE_HEADER: u32 = 6; //unused pub const SMBHDR_TYPE_MAX_SIZE: u32 = 7; // max resp size for SMB1_COMMAND_TRANS -pub const SMBHDR_TYPE_TRANS_FRAG: u32 = 8; -pub const SMBHDR_TYPE_TREE: u32 = 9; -pub const SMBHDR_TYPE_DCERPCTX: u32 = 10; +pub const SMBHDR_TYPE_TRANS_FRAG: u32 = 8; +pub const SMBHDR_TYPE_TREE: u32 = 9; +pub const SMBHDR_TYPE_DCERPCTX: u32 = 10; #[derive(Default, Hash, Eq, PartialEq, Debug)] pub struct SMBCommonHdr { @@ -609,21 +614,20 @@ impl SMBCommonHdr { } pub fn from2(r: &Smb2Record, rec_type: u32) -> SMBCommonHdr { let tree_id = match rec_type { - SMBHDR_TYPE_TREE => { 0 }, + SMBHDR_TYPE_TREE => 0, _ => r.tree_id, }; let msg_id = match rec_type { - SMBHDR_TYPE_TRANS_FRAG | SMBHDR_TYPE_SHARE => { 0 }, - _ => { r.message_id }, + SMBHDR_TYPE_TRANS_FRAG | SMBHDR_TYPE_SHARE => 0, + _ => r.message_id, }; SMBCommonHdr { rec_type, - ssn_id : r.session_id, + ssn_id: r.session_id, tree_id, msg_id, } - } pub fn from2_notree(r: &Smb2Record, rec_type: u32) -> SMBCommonHdr { // async responses do not have a tree id (even if the request has it) @@ -632,30 +636,30 @@ impl SMBCommonHdr { // across all messages that are sent on the same SMB2 Protocol transport connection. // cf https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/ea4560b7-90da-4803-82b5-344754b92a79 let msg_id = match rec_type { - SMBHDR_TYPE_TRANS_FRAG | SMBHDR_TYPE_SHARE => { 0 }, - _ => { r.message_id }, + SMBHDR_TYPE_TRANS_FRAG | SMBHDR_TYPE_SHARE => 0, + _ => r.message_id, }; SMBCommonHdr { rec_type, - ssn_id : r.session_id, - tree_id : 0, + ssn_id: r.session_id, + tree_id: 0, msg_id, } } pub fn from1(r: &SmbRecord, rec_type: u32) -> SMBCommonHdr { let tree_id = match rec_type { - SMBHDR_TYPE_TREE => { 0 }, + SMBHDR_TYPE_TREE => 0, _ => r.tree_id as u32, }; let msg_id = match rec_type { - SMBHDR_TYPE_TRANS_FRAG | SMBHDR_TYPE_SHARE => { 0 }, - _ => { r.multiplex_id as u64 }, + SMBHDR_TYPE_TRANS_FRAG | SMBHDR_TYPE_SHARE => 0, + _ => r.multiplex_id as u64, }; SMBCommonHdr { rec_type, - ssn_id : r.ssn_id as u64, + ssn_id: r.ssn_id as u64, tree_id, msg_id, } @@ -663,8 +667,7 @@ impl SMBCommonHdr { // don't include tree id pub fn compare(&self, hdr: &SMBCommonHdr) -> bool { - self.rec_type == hdr.rec_type && self.ssn_id == hdr.ssn_id && - self.msg_id == hdr.msg_id + self.rec_type == hdr.rec_type && self.ssn_id == hdr.ssn_id && self.msg_id == hdr.msg_id } } @@ -676,9 +679,7 @@ pub struct SMBHashKeyHdrGuid { impl SMBHashKeyHdrGuid { pub fn new(hdr: SMBCommonHdr, guid: Vec) -> Self { - Self { - hdr, guid, - } + Self { hdr, guid } } } @@ -690,15 +691,12 @@ pub struct SMBTree { impl SMBTree { pub fn new(name: Vec, is_pipe: bool) -> Self { - Self { - name, - is_pipe, - } + Self { name, is_pipe } } } #[derive(Debug)] -pub struct SMBState<> { +pub struct SMBState { pub state_data: AppLayerStateData, /// map ssn/tree/msgid to vec (guid/name/share) @@ -726,10 +724,10 @@ pub struct SMBState<> { skip_ts: u32, skip_tc: u32, - pub file_ts_left : u32, - pub file_tc_left : u32, - pub file_ts_guid : Vec, - pub file_tc_guid : Vec, + pub file_ts_left: u32, + pub file_tc_left: u32, + pub file_ts_guid: Vec, + pub file_tc_guid: Vec, pub ts_ssn_gap: bool, pub tc_ssn_gap: bool, @@ -789,18 +787,28 @@ impl SMBState { /// Allocation function for a new TLS parser instance pub fn new() -> Self { Self { - state_data:AppLayerStateData::default(), - ssn2vec_cache:LruCache::new(NonZeroUsize::new(unsafe { SMB_CFG_MAX_SSN2VEC_CACHE_SIZE }).unwrap()), - guid2name_cache:LruCache::new(NonZeroUsize::new(unsafe { SMB_CFG_MAX_GUID_CACHE_SIZE }).unwrap()), - read_offset_cache:LruCache::new(NonZeroUsize::new(unsafe { SMB_CFG_MAX_READ_OFFSET_CACHE_SIZE }).unwrap()), - ssn2tree_cache:LruCache::new(NonZeroUsize::new(unsafe { SMB_CFG_MAX_TREE_CACHE_SIZE }).unwrap()), - dcerpc_rec_frag_cache:LruCache::new(NonZeroUsize::new(unsafe { SMB_CFG_MAX_FRAG_CACHE_SIZE }).unwrap()), - skip_ts:0, - skip_tc:0, - file_ts_left:0, - file_tc_left:0, - file_ts_guid:Vec::new(), - file_tc_guid:Vec::new(), + state_data: AppLayerStateData::default(), + ssn2vec_cache: LruCache::new( + NonZeroUsize::new(unsafe { SMB_CFG_MAX_SSN2VEC_CACHE_SIZE }).unwrap(), + ), + guid2name_cache: LruCache::new( + NonZeroUsize::new(unsafe { SMB_CFG_MAX_GUID_CACHE_SIZE }).unwrap(), + ), + read_offset_cache: LruCache::new( + NonZeroUsize::new(unsafe { SMB_CFG_MAX_READ_OFFSET_CACHE_SIZE }).unwrap(), + ), + ssn2tree_cache: LruCache::new( + NonZeroUsize::new(unsafe { SMB_CFG_MAX_TREE_CACHE_SIZE }).unwrap(), + ), + dcerpc_rec_frag_cache: LruCache::new( + NonZeroUsize::new(unsafe { SMB_CFG_MAX_FRAG_CACHE_SIZE }).unwrap(), + ), + skip_ts: 0, + skip_tc: 0, + file_ts_left: 0, + file_tc_left: 0, + file_ts_guid: Vec::new(), + file_tc_guid: Vec::new(), ts_ssn_gap: false, tc_ssn_gap: false, ts_gap: false, @@ -811,8 +819,8 @@ impl SMBState { post_gap_files_checked: false, transactions: VecDeque::new(), tx_index_completed: 0, - tx_id:0, - dialect:0, + tx_id: 0, + dialect: 0, dialect_vec: None, dcerpc_ifaces: None, max_read_size: 0, @@ -845,13 +853,12 @@ impl SMBState { } } self.tx_index_completed = index; - } return tx; } pub fn free_tx(&mut self, tx_id: u64) { - SCLogDebug!("Freeing TX with ID {} TX.ID {}", tx_id, tx_id+1); + SCLogDebug!("Freeing TX with ID {} TX.ID {}", tx_id, tx_id + 1); let len = self.transactions.len(); let mut found = false; let mut index = 0; @@ -860,26 +867,37 @@ impl SMBState { if tx.id == tx_id + 1 { found = true; index = i; - SCLogDebug!("tx {} progress {}/{}", tx.id, tx.request_done, tx.response_done); + SCLogDebug!( + "tx {} progress {}/{}", + tx.id, + tx.request_done, + tx.response_done + ); break; } } if found { - SCLogDebug!("freeing TX with ID {} TX.ID {} at index {} left: {} max id: {}", - tx_id, tx_id+1, index, self.transactions.len(), self.tx_id); + SCLogDebug!( + "freeing TX with ID {} TX.ID {} at index {} left: {} max id: {}", + tx_id, + tx_id + 1, + index, + self.transactions.len(), + self.tx_id + ); self.tx_index_completed = 0; self.transactions.remove(index); } } pub fn get_tx_by_id(&mut self, tx_id: u64) -> Option<&SMBTransaction> { -/* - if self.transactions.len() > 100 { - SCLogNotice!("get_tx_by_id: tx_id={} in list={}", tx_id, self.transactions.len()); - self._dump_txs(); - panic!("txs exploded"); - } -*/ + /* + if self.transactions.len() > 100 { + SCLogNotice!("get_tx_by_id: tx_id={} in list={}", tx_id, self.transactions.len()); + self._dump_txs(); + panic!("txs exploded"); + } + */ for tx in &mut self.transactions { if tx.id == tx_id + 1 { let ver = tx.vercmd.get_version(); @@ -891,8 +909,15 @@ impl SMBState { let (_, cmd) = tx.vercmd.get_smb1_cmd(); _smbcmd = cmd as u16; } - SCLogDebug!("Found SMB TX: id {} ver:{} cmd:{} progress {}/{} type_data {:?}", - tx.id, ver, _smbcmd, tx.request_done, tx.response_done, tx.type_data); + SCLogDebug!( + "Found SMB TX: id {} ver:{} cmd:{} progress {}/{} type_data {:?}", + tx.id, + ver, + _smbcmd, + tx.request_done, + tx.response_done, + tx.type_data + ); /* hack: apply flow file flags to file tx here to make sure its propagated */ if let Some(SMBTransactionTypeData::FILE(ref mut d)) = tx.type_data { tx.tx_data.update_file_flags(self.state_data.file_flags); @@ -915,9 +940,9 @@ impl SMBState { /* generic TX has no type_data and is only used to * track a single cmd request/reply pair. */ - pub fn new_generic_tx(&mut self, smb_ver: u8, smb_cmd: u16, key: SMBCommonHdr) - -> &mut SMBTransaction - { + pub fn new_generic_tx( + &mut self, smb_ver: u8, smb_cmd: u16, key: SMBCommonHdr, + ) -> &mut SMBTransaction { let mut tx = self.new_tx(); if smb_ver == 1 && smb_cmd <= 255 { tx.vercmd.set_smb1_cmd(smb_cmd as u8); @@ -930,16 +955,18 @@ impl SMBState { tx.response_done = self.tc_trunc; // no response expected if tc is truncated tx.hdr = key; - SCLogDebug!("SMB: TX GENERIC created: ID {} tx list {} {:?}", - tx.id, self.transactions.len(), &tx); + SCLogDebug!( + "SMB: TX GENERIC created: ID {} tx list {} {:?}", + tx.id, + self.transactions.len(), + &tx + ); self.transactions.push_back(tx); let tx_ref = self.transactions.back_mut(); return tx_ref.unwrap(); } - pub fn get_last_tx(&mut self, smb_ver: u8, smb_cmd: u16) - -> Option<&mut SMBTransaction> - { + pub fn get_last_tx(&mut self, smb_ver: u8, smb_cmd: u16) -> Option<&mut SMBTransaction> { let tx_ref = self.transactions.back_mut(); if let Some(tx) = tx_ref { let found = if tx.vercmd.get_version() == smb_ver { @@ -964,9 +991,9 @@ impl SMBState { return None; } - pub fn get_generic_tx(&mut self, smb_ver: u8, smb_cmd: u16, key: &SMBCommonHdr) - -> Option<&mut SMBTransaction> - { + pub fn get_generic_tx( + &mut self, smb_ver: u8, smb_cmd: u16, key: &SMBCommonHdr, + ) -> Option<&mut SMBTransaction> { for tx in &mut self.transactions { let found = if tx.vercmd.get_version() == smb_ver { if smb_ver == 1 { @@ -990,9 +1017,7 @@ impl SMBState { return None; } - pub fn new_negotiate_tx(&mut self, smb_ver: u8) - -> &mut SMBTransaction - { + pub fn new_negotiate_tx(&mut self, smb_ver: u8) -> &mut SMBTransaction { let mut tx = self.new_tx(); if smb_ver == 1 { tx.vercmd.set_smb1_cmd(SMB1_COMMAND_NEGOTIATE_PROTOCOL); @@ -1001,25 +1026,26 @@ impl SMBState { } tx.type_data = Some(SMBTransactionTypeData::NEGOTIATE( - SMBTransactionNegotiate::new(smb_ver))); + SMBTransactionNegotiate::new(smb_ver), + )); tx.request_done = true; tx.response_done = self.tc_trunc; // no response expected if tc is truncated - SCLogDebug!("SMB: TX NEGOTIATE created: ID {} SMB ver {}", tx.id, smb_ver); + SCLogDebug!( + "SMB: TX NEGOTIATE created: ID {} SMB ver {}", + tx.id, + smb_ver + ); self.transactions.push_back(tx); let tx_ref = self.transactions.back_mut(); return tx_ref.unwrap(); } - pub fn get_negotiate_tx(&mut self, smb_ver: u8) - -> Option<&mut SMBTransaction> - { + pub fn get_negotiate_tx(&mut self, smb_ver: u8) -> Option<&mut SMBTransaction> { for tx in &mut self.transactions { let found = match tx.type_data { - Some(SMBTransactionTypeData::NEGOTIATE(ref x)) => { - x.smb_ver == smb_ver - }, - _ => { false }, + Some(SMBTransactionTypeData::NEGOTIATE(ref x)) => x.smb_ver == smb_ver, + _ => false, }; if found { tx.tx_data.0.updated_tc = true; @@ -1030,32 +1056,33 @@ impl SMBState { return None; } - pub fn new_treeconnect_tx(&mut self, hdr: SMBCommonHdr, name: Vec) - -> &mut SMBTransaction - { + pub fn new_treeconnect_tx(&mut self, hdr: SMBCommonHdr, name: Vec) -> &mut SMBTransaction { let mut tx = self.new_tx(); tx.hdr = hdr; tx.type_data = Some(SMBTransactionTypeData::TREECONNECT( - SMBTransactionTreeConnect::new(name.to_vec()))); + SMBTransactionTreeConnect::new(name.to_vec()), + )); tx.request_done = true; tx.response_done = self.tc_trunc; // no response expected if tc is truncated - SCLogDebug!("SMB: TX TREECONNECT created: ID {} NAME {}", - tx.id, String::from_utf8_lossy(&name)); + SCLogDebug!( + "SMB: TX TREECONNECT created: ID {} NAME {}", + tx.id, + String::from_utf8_lossy(&name) + ); self.transactions.push_back(tx); let tx_ref = self.transactions.back_mut(); return tx_ref.unwrap(); } - pub fn get_treeconnect_tx(&mut self, hdr: SMBCommonHdr) - -> Option<&mut SMBTransaction> - { + pub fn get_treeconnect_tx(&mut self, hdr: SMBCommonHdr) -> Option<&mut SMBTransaction> { for tx in &mut self.transactions { - let hit = tx.hdr.compare(&hdr) && match tx.type_data { - Some(SMBTransactionTypeData::TREECONNECT(_)) => { true }, - _ => { false }, - }; + let hit = tx.hdr.compare(&hdr) + && match tx.type_data { + Some(SMBTransactionTypeData::TREECONNECT(_)) => true, + _ => false, + }; if hit { tx.tx_data.0.updated_tc = true; tx.tx_data.0.updated_ts = true; @@ -1065,17 +1092,17 @@ impl SMBState { return None; } - pub fn new_create_tx(&mut self, file_name: &[u8], - disposition: u32, del: bool, dir: bool, - hdr: SMBCommonHdr) - -> &mut SMBTransaction - { + pub fn new_create_tx( + &mut self, file_name: &[u8], disposition: u32, del: bool, dir: bool, hdr: SMBCommonHdr, + ) -> &mut SMBTransaction { let mut tx = self.new_tx(); tx.hdr = hdr; - tx.type_data = Some(SMBTransactionTypeData::CREATE( - SMBTransactionCreate::new( - file_name.to_vec(), disposition, - del, dir))); + tx.type_data = Some(SMBTransactionTypeData::CREATE(SMBTransactionCreate::new( + file_name.to_vec(), + disposition, + del, + dir, + ))); tx.request_done = true; tx.response_done = self.tc_trunc; // no response expected if tc is truncated @@ -1084,8 +1111,7 @@ impl SMBState { return tx_ref.unwrap(); } - pub fn get_service_for_guid(&mut self, guid: &[u8]) -> (&'static str, bool) - { + pub fn get_service_for_guid(&mut self, guid: &[u8]) -> (&'static str, bool) { let (name, is_dcerpc) = match self.guid2name_cache.get(guid) { Some(n) => { let mut s = n.as_slice(); @@ -1107,17 +1133,16 @@ impl SMBState { Ok(&_) => { SCLogDebug!("don't know {}", String::from_utf8_lossy(n)); ("UNKNOWN", false) - }, + } } - }, - _ => { ("UNKNOWN", false) }, + } + _ => ("UNKNOWN", false), }; SCLogDebug!("service {} is_dcerpc {}", name, is_dcerpc); (name, is_dcerpc) } - fn post_gap_housekeeping_for_files(&mut self) - { + fn post_gap_housekeeping_for_files(&mut self) { let mut post_gap_txs = false; for tx in &mut self.transactions { if let Some(SMBTransactionTypeData::FILE(ref mut f)) = tx.type_data { @@ -1140,8 +1165,7 @@ impl SMBState { * can handle gaps. For the file transactions we set the current * (flow) time and prune them in 60 seconds if no update for them * was received. */ - fn post_gap_housekeeping(&mut self, dir: Direction) - { + fn post_gap_housekeeping(&mut self, dir: Direction) { if self.ts_ssn_gap && dir == Direction::ToServer { for tx in &mut self.transactions { if tx.id >= self.tx_id { @@ -1179,12 +1203,12 @@ impl SMBState { tx.response_done = true; } } - } } - pub fn set_file_left(&mut self, direction: Direction, rec_size: u32, data_size: u32, fuid: Vec) - { + pub fn set_file_left( + &mut self, direction: Direction, rec_size: u32, data_size: u32, fuid: Vec, + ) { let left = rec_size.saturating_sub(data_size); if direction == Direction::ToServer { self.file_ts_left = left; @@ -1195,8 +1219,7 @@ impl SMBState { } } - pub fn set_skip(&mut self, direction: Direction, nbss_remaining: u32) - { + pub fn set_skip(&mut self, direction: Direction, nbss_remaining: u32) { if direction == Direction::ToServer { self.skip_ts = nbss_remaining; } else { @@ -1212,7 +1235,7 @@ impl SMBState { self.skip_tc }; if skip_left == 0 { - return 0 + return 0; } SCLogDebug!("skip_left {} input_size {}", skip_left, input_size); @@ -1236,61 +1259,161 @@ impl SMBState { return consumed; } - fn add_nbss_ts_frames(&mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) -> (Option, Option, Option) { - let nbss_pdu = Frame::new(flow, stream_slice, input, nbss_len + 4, SMBFrameType::NBSSPdu as u8, None); + fn add_nbss_ts_frames( + &mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, + ) -> (Option, Option, Option) { + let nbss_pdu = Frame::new( + flow, + stream_slice, + input, + nbss_len + 4, + SMBFrameType::NBSSPdu as u8, + None, + ); SCLogDebug!("NBSS PDU frame {:?}", nbss_pdu); - let nbss_hdr_frame = Frame::new(flow, stream_slice, input, 4_i64, SMBFrameType::NBSSHdr as u8, None); + let nbss_hdr_frame = Frame::new( + flow, + stream_slice, + input, + 4_i64, + SMBFrameType::NBSSHdr as u8, + None, + ); SCLogDebug!("NBSS HDR frame {:?}", nbss_hdr_frame); - let nbss_data_frame = Frame::new(flow, stream_slice, &input[4..], nbss_len, SMBFrameType::NBSSData as u8, None); + let nbss_data_frame = Frame::new( + flow, + stream_slice, + &input[4..], + nbss_len, + SMBFrameType::NBSSData as u8, + None, + ); SCLogDebug!("NBSS DATA frame {:?}", nbss_data_frame); (nbss_pdu, nbss_hdr_frame, nbss_data_frame) } - fn add_smb1_ts_pdu_frame(&mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) -> Option { - let smb_pdu = Frame::new(flow, stream_slice, input, nbss_len, SMBFrameType::SMB1Pdu as u8, None); + fn add_smb1_ts_pdu_frame( + &mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, + ) -> Option { + let smb_pdu = Frame::new( + flow, + stream_slice, + input, + nbss_len, + SMBFrameType::SMB1Pdu as u8, + None, + ); SCLogDebug!("SMB PDU frame {:?}", smb_pdu); smb_pdu } - fn add_smb1_ts_hdr_data_frames(&mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) { - let _smb1_hdr = Frame::new(flow, stream_slice, input, 32_i64, SMBFrameType::SMB1Hdr as u8, None); + fn add_smb1_ts_hdr_data_frames( + &mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, + ) { + let _smb1_hdr = Frame::new( + flow, + stream_slice, + input, + 32_i64, + SMBFrameType::SMB1Hdr as u8, + None, + ); SCLogDebug!("SMBv1 HDR frame {:?}", _smb1_hdr); if input.len() > 32 { - let _smb1_data = Frame::new(flow, stream_slice, &input[32..], nbss_len - 32, SMBFrameType::SMB1Data as u8, None); + let _smb1_data = Frame::new( + flow, + stream_slice, + &input[32..], + nbss_len - 32, + SMBFrameType::SMB1Data as u8, + None, + ); SCLogDebug!("SMBv1 DATA frame {:?}", _smb1_data); } } - fn add_smb2_ts_pdu_frame(&mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) -> Option { - let smb_pdu = Frame::new(flow, stream_slice, input, nbss_len, SMBFrameType::SMB2Pdu as u8, None); + fn add_smb2_ts_pdu_frame( + &mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, + ) -> Option { + let smb_pdu = Frame::new( + flow, + stream_slice, + input, + nbss_len, + SMBFrameType::SMB2Pdu as u8, + None, + ); SCLogDebug!("SMBv2 PDU frame {:?}", smb_pdu); smb_pdu } - fn add_smb2_ts_hdr_data_frames(&mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, hdr_len: i64) { - let _smb2_hdr = Frame::new(flow, stream_slice, input, hdr_len, SMBFrameType::SMB2Hdr as u8, None); + fn add_smb2_ts_hdr_data_frames( + &mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, + hdr_len: i64, + ) { + let _smb2_hdr = Frame::new( + flow, + stream_slice, + input, + hdr_len, + SMBFrameType::SMB2Hdr as u8, + None, + ); SCLogDebug!("SMBv2 HDR frame {:?}", _smb2_hdr); if input.len() > hdr_len as usize { - let _smb2_data = Frame::new(flow, stream_slice, &input[hdr_len as usize..], nbss_len - hdr_len, SMBFrameType::SMB2Data as u8, None); + let _smb2_data = Frame::new( + flow, + stream_slice, + &input[hdr_len as usize..], + nbss_len - hdr_len, + SMBFrameType::SMB2Data as u8, + None, + ); SCLogDebug!("SMBv2 DATA frame {:?}", _smb2_data); } } - fn add_smb3_ts_pdu_frame(&mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) -> Option { - let smb_pdu = Frame::new(flow, stream_slice, input, nbss_len, SMBFrameType::SMB3Pdu as u8, None); + fn add_smb3_ts_pdu_frame( + &mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, + ) -> Option { + let smb_pdu = Frame::new( + flow, + stream_slice, + input, + nbss_len, + SMBFrameType::SMB3Pdu as u8, + None, + ); SCLogDebug!("SMBv3 PDU frame {:?}", smb_pdu); smb_pdu } - fn add_smb3_ts_hdr_data_frames(&mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) { - let _smb3_hdr = Frame::new(flow, stream_slice, input, 52_i64, SMBFrameType::SMB3Hdr as u8, None); + fn add_smb3_ts_hdr_data_frames( + &mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, + ) { + let _smb3_hdr = Frame::new( + flow, + stream_slice, + input, + 52_i64, + SMBFrameType::SMB3Hdr as u8, + None, + ); SCLogDebug!("SMBv3 HDR frame {:?}", _smb3_hdr); if input.len() > 52 { - let _smb3_data = Frame::new(flow, stream_slice, &input[52..], nbss_len - 52, SMBFrameType::SMB3Data as u8, None); + let _smb3_data = Frame::new( + flow, + stream_slice, + &input[52..], + nbss_len - 52, + SMBFrameType::SMB3Data as u8, + None, + ); SCLogDebug!("SMBv3 DATA frame {:?}", _smb3_data); } } /// return bytes consumed - pub fn parse_tcp_data_ts_partial(&mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8]) -> usize - { + pub fn parse_tcp_data_ts_partial( + &mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], + ) -> usize { SCLogDebug!("incomplete of size {}", input.len()); if input.len() < 512 { // check for malformed data. Wireshark reports as @@ -1299,7 +1422,10 @@ impl SMBState { if input.len() > 8 { if let Ok((_, ref hdr)) = parse_nbss_record_partial(input) { if !hdr.is_smb() { - SCLogDebug!("partial NBSS, not SMB and no known msg type {}", hdr.message_type); + SCLogDebug!( + "partial NBSS, not SMB and no known msg type {}", + hdr.message_type + ); self.trunc_ts(); return 0; } @@ -1313,14 +1439,19 @@ impl SMBState { if nbss_part_hdr.message_type == NBSS_MSGTYPE_SESSION_MESSAGE { if let Ok((_, ref smb)) = parse_smb_version(nbss_part_hdr.data) { SCLogDebug!("SMB {:?}", smb); - if smb.version == 0xff_u8 { // SMB1 + if smb.version == 0xff_u8 { + // SMB1 SCLogDebug!("SMBv1 record"); if let Ok((_, ref r)) = parse_smb_record(nbss_part_hdr.data) { if r.command == SMB1_COMMAND_WRITE_ANDX { // see if it's a write to a pipe. We only handle those // if complete. - let tree_key = SMBCommonHdr::new(SMBHDR_TYPE_SHARE, - r.ssn_id as u64, r.tree_id as u32, 0); + let tree_key = SMBCommonHdr::new( + SMBHDR_TYPE_SHARE, + r.ssn_id as u64, + r.tree_id as u32, + 0, + ); let is_pipe = match self.ssn2tree_cache.get(&tree_key) { Some(n) => n.is_pipe, None => false, @@ -1331,33 +1462,77 @@ impl SMBState { // how many more bytes are expected within this NBSS record // So that we can check that further parsed offsets and lengths // stay within the NBSS record. - let nbss_remaining = nbss_part_hdr.length - nbss_part_hdr.data.len() as u32; - smb1_write_request_record(self, r, SMB1_HEADER_SIZE, SMB1_COMMAND_WRITE_ANDX, nbss_remaining); + let nbss_remaining = + nbss_part_hdr.length - nbss_part_hdr.data.len() as u32; + smb1_write_request_record( + self, + r, + SMB1_HEADER_SIZE, + SMB1_COMMAND_WRITE_ANDX, + nbss_remaining, + ); + + self.add_nbss_ts_frames( + flow, + stream_slice, + input, + nbss_part_hdr.length as i64, + ); + self.add_smb1_ts_pdu_frame( + flow, + stream_slice, + nbss_part_hdr.data, + nbss_part_hdr.length as i64, + ); + self.add_smb1_ts_hdr_data_frames( + flow, + stream_slice, + nbss_part_hdr.data, + nbss_part_hdr.length as i64, + ); - self.add_nbss_ts_frames(flow, stream_slice, input, nbss_part_hdr.length as i64); - self.add_smb1_ts_pdu_frame(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64); - self.add_smb1_ts_hdr_data_frames(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64); - let consumed = input.len() - output.len(); return consumed; } } - } else if smb.version == 0xfe_u8 { // SMB2 + } else if smb.version == 0xfe_u8 { + // SMB2 SCLogDebug!("SMBv2 record"); - if let Ok((_, ref smb_record)) = parse_smb2_request_record(nbss_part_hdr.data) { - SCLogDebug!("SMB2: partial record {}", - &smb2_command_string(smb_record.command)); + if let Ok((_, ref smb_record)) = + parse_smb2_request_record(nbss_part_hdr.data) + { + SCLogDebug!( + "SMB2: partial record {}", + &smb2_command_string(smb_record.command) + ); if smb_record.command == SMB2_COMMAND_WRITE { // how many more bytes are expected within this NBSS record // So that we can check that further parsed offsets and lengths // stay within the NBSS record. - let nbss_remaining = nbss_part_hdr.length - nbss_part_hdr.data.len() as u32; + let nbss_remaining = + nbss_part_hdr.length - nbss_part_hdr.data.len() as u32; smb2_write_request_record(self, smb_record, nbss_remaining); - self.add_nbss_ts_frames(flow, stream_slice, input, nbss_part_hdr.length as i64); - self.add_smb2_ts_pdu_frame(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64); - self.add_smb2_ts_hdr_data_frames(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64, smb_record.header_len as i64); - + self.add_nbss_ts_frames( + flow, + stream_slice, + input, + nbss_part_hdr.length as i64, + ); + self.add_smb2_ts_pdu_frame( + flow, + stream_slice, + nbss_part_hdr.data, + nbss_part_hdr.length as i64, + ); + self.add_smb2_ts_hdr_data_frames( + flow, + stream_slice, + nbss_part_hdr.data, + nbss_part_hdr.length as i64, + smb_record.header_len as i64, + ); + let consumed = input.len() - output.len(); SCLogDebug!("consumed {}", consumed); return consumed; @@ -1373,8 +1548,9 @@ impl SMBState { } /// Parsing function, handling TCP chunks fragmentation - pub fn parse_tcp_data_ts(&mut self, flow: *mut Flow, stream_slice: &StreamSlice) -> AppLayerResult - { + pub fn parse_tcp_data_ts( + &mut self, flow: *mut Flow, stream_slice: &StreamSlice, + ) -> AppLayerResult { let mut cur_i = stream_slice.as_slice(); let consumed = self.handle_skip(Direction::ToServer, cur_i.len() as u32); if consumed > 0 { @@ -1400,13 +1576,14 @@ impl SMBState { // gap if self.ts_gap { SCLogDebug!("TS trying to catch up after GAP (input {})", cur_i.len()); - while !cur_i.is_empty() { // min record size + while !cur_i.is_empty() { + // min record size match search_smb_record(cur_i) { Ok((_, pg)) => { SCLogDebug!("smb record found"); let smb2_offset = cur_i.len() - pg.len(); if smb2_offset < 4 { - cur_i = &cur_i[smb2_offset+4..]; + cur_i = &cur_i[smb2_offset + 4..]; continue; // see if we have another record in our data } let nbss_offset = smb2_offset - 4; @@ -1414,7 +1591,7 @@ impl SMBState { self.ts_gap = false; break; - }, + } _ => { let mut consumed = stream_slice.len(); if consumed < 4 { @@ -1424,113 +1601,174 @@ impl SMBState { } SCLogDebug!("smb record NOT found"); return AppLayerResult::incomplete(consumed, 8); - }, + } } } } - while !cur_i.is_empty() { // min record size + while !cur_i.is_empty() { + // min record size match parse_nbss_record(cur_i) { Ok((rem, ref nbss_hdr)) => { - SCLogDebug!("nbss frame offset {} len {}", stream_slice.offset_from(cur_i), cur_i.len() - rem.len()); - let (_, _, nbss_data_frame) = self.add_nbss_ts_frames(flow, stream_slice, cur_i, nbss_hdr.length as i64); + SCLogDebug!( + "nbss frame offset {} len {}", + stream_slice.offset_from(cur_i), + cur_i.len() - rem.len() + ); + let (_, _, nbss_data_frame) = + self.add_nbss_ts_frames(flow, stream_slice, cur_i, nbss_hdr.length as i64); if nbss_hdr.message_type == NBSS_MSGTYPE_SESSION_MESSAGE { // we have the full records size worth of data, // let's parse it match parse_smb_version(nbss_hdr.data) { Ok((_, ref smb)) => { - SCLogDebug!("SMB {:?}", smb); - if smb.version == 0xff_u8 { // SMB1 + if smb.version == 0xff_u8 { + // SMB1 SCLogDebug!("SMBv1 record"); match parse_smb_record(nbss_hdr.data) { Ok((_, ref smb_record)) => { - let pdu_frame = self.add_smb1_ts_pdu_frame(flow, stream_slice, nbss_hdr.data, nbss_hdr.length as i64); - self.add_smb1_ts_hdr_data_frames(flow, stream_slice, nbss_hdr.data, nbss_hdr.length as i64); + let pdu_frame = self.add_smb1_ts_pdu_frame( + flow, + stream_slice, + nbss_hdr.data, + nbss_hdr.length as i64, + ); + self.add_smb1_ts_hdr_data_frames( + flow, + stream_slice, + nbss_hdr.data, + nbss_hdr.length as i64, + ); if smb_record.is_request() { smb1_request_record(self, smb_record); } else { // If we received a response when expecting a request, set an event // on the PDU frame instead of handling the response. - SCLogDebug!("SMB1 reply seen from client to server"); + SCLogDebug!( + "SMB1 reply seen from client to server" + ); if let Some(frame) = pdu_frame { - frame.add_event(flow, SMBEvent::ResponseToServer as u8); + frame.add_event( + flow, + SMBEvent::ResponseToServer as u8, + ); } } - }, + } _ => { if let Some(frame) = nbss_data_frame { - frame.add_event(flow, SMBEvent::MalformedData as u8); + frame + .add_event(flow, SMBEvent::MalformedData as u8); } self.set_event(SMBEvent::MalformedData); return AppLayerResult::err(); - }, + } } - } else if smb.version == 0xfe_u8 { // SMB2 + } else if smb.version == 0xfe_u8 { + // SMB2 let mut nbss_data = nbss_hdr.data; while !nbss_data.is_empty() { SCLogDebug!("SMBv2 record"); match parse_smb2_request_record(nbss_data) { Ok((nbss_data_rem, ref smb_record)) => { - let record_len = (nbss_data.len() - nbss_data_rem.len()) as i64; - let pdu_frame = self.add_smb2_ts_pdu_frame(flow, stream_slice, nbss_data, record_len); - self.add_smb2_ts_hdr_data_frames(flow, stream_slice, nbss_data, record_len, smb_record.header_len as i64); - SCLogDebug!("nbss_data_rem {}", nbss_data_rem.len()); + let record_len = + (nbss_data.len() - nbss_data_rem.len()) as i64; + let pdu_frame = self.add_smb2_ts_pdu_frame( + flow, + stream_slice, + nbss_data, + record_len, + ); + self.add_smb2_ts_hdr_data_frames( + flow, + stream_slice, + nbss_data, + record_len, + smb_record.header_len as i64, + ); + SCLogDebug!( + "nbss_data_rem {}", + nbss_data_rem.len() + ); if smb_record.is_request() { smb2_request_record(self, smb_record); } else { // If we received a response when expecting a request, set an event // on the PDU frame instead of handling the response. - SCLogDebug!("SMB2 reply seen from client to server"); + SCLogDebug!( + "SMB2 reply seen from client to server" + ); if let Some(frame) = pdu_frame { - frame.add_event(flow, SMBEvent::ResponseToServer as u8); + frame.add_event( + flow, + SMBEvent::ResponseToServer as u8, + ); } } nbss_data = nbss_data_rem; - }, + } _ => { if let Some(frame) = nbss_data_frame { - frame.add_event(flow, SMBEvent::MalformedData as u8); + frame.add_event( + flow, + SMBEvent::MalformedData as u8, + ); } self.set_event(SMBEvent::MalformedData); return AppLayerResult::err(); - }, + } } } - } else if smb.version == 0xfd_u8 { // SMB3 transform + } else if smb.version == 0xfd_u8 { + // SMB3 transform let mut nbss_data = nbss_hdr.data; while !nbss_data.is_empty() { SCLogDebug!("SMBv3 transform record"); match parse_smb3_transform_record(nbss_data) { Ok((nbss_data_rem, ref _smb3_record)) => { - let record_len = (nbss_data.len() - nbss_data_rem.len()) as i64; - self.add_smb3_ts_pdu_frame(flow, stream_slice, nbss_data, record_len); - self.add_smb3_ts_hdr_data_frames(flow, stream_slice, nbss_data, record_len); + let record_len = + (nbss_data.len() - nbss_data_rem.len()) as i64; + self.add_smb3_ts_pdu_frame( + flow, + stream_slice, + nbss_data, + record_len, + ); + self.add_smb3_ts_hdr_data_frames( + flow, + stream_slice, + nbss_data, + record_len, + ); nbss_data = nbss_data_rem; - }, + } _ => { if let Some(frame) = nbss_data_frame { - frame.add_event(flow, SMBEvent::MalformedData as u8); + frame.add_event( + flow, + SMBEvent::MalformedData as u8, + ); } self.set_event(SMBEvent::MalformedData); return AppLayerResult::err(); - }, + } } } } - }, + } _ => { self.set_event(SMBEvent::MalformedData); return AppLayerResult::err(); - }, + } } } else { SCLogDebug!("NBSS message {:X}", nbss_hdr.message_type); } cur_i = rem; - }, + } Err(Err::Incomplete(needed)) => { if let Needed::Size(n) = needed { let n = usize::from(n) + cur_i.len(); @@ -1543,8 +1781,13 @@ impl SMBState { if consumed == 0 { // if we consumed none we will buffer the entire record let total_consumed = stream_slice.offset_from(cur_i); - SCLogDebug!("setting consumed {} need {} needed {:?} total input {}", - total_consumed, n, needed, stream_slice.len()); + SCLogDebug!( + "setting consumed {} need {} needed {:?} total input {}", + total_consumed, + n, + needed, + stream_slice.len() + ); let need = n; return AppLayerResult::incomplete(total_consumed, need as u32); } @@ -1556,13 +1799,13 @@ impl SMBState { self.set_event(SMBEvent::InternalError); return AppLayerResult::err(); } - }, + } Err(_) => { self.set_event(SMBEvent::MalformedData); return AppLayerResult::err(); - }, + } } - }; + } self.post_gap_housekeeping(Direction::ToServer); if self.check_post_gap_file_txs && !self.post_gap_files_checked { @@ -1572,61 +1815,160 @@ impl SMBState { AppLayerResult::ok() } - fn add_nbss_tc_frames(&mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) -> (Option, Option, Option) { - let nbss_pdu = Frame::new(flow, stream_slice, input, nbss_len + 4, SMBFrameType::NBSSPdu as u8, None); + fn add_nbss_tc_frames( + &mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, + ) -> (Option, Option, Option) { + let nbss_pdu = Frame::new( + flow, + stream_slice, + input, + nbss_len + 4, + SMBFrameType::NBSSPdu as u8, + None, + ); SCLogDebug!("NBSS PDU frame {:?}", nbss_pdu); - let nbss_hdr_frame = Frame::new(flow, stream_slice, input, 4_i64, SMBFrameType::NBSSHdr as u8, None); + let nbss_hdr_frame = Frame::new( + flow, + stream_slice, + input, + 4_i64, + SMBFrameType::NBSSHdr as u8, + None, + ); SCLogDebug!("NBSS HDR frame {:?}", nbss_hdr_frame); - let nbss_data_frame = Frame::new(flow, stream_slice, &input[4..], nbss_len, SMBFrameType::NBSSData as u8, None); + let nbss_data_frame = Frame::new( + flow, + stream_slice, + &input[4..], + nbss_len, + SMBFrameType::NBSSData as u8, + None, + ); SCLogDebug!("NBSS DATA frame {:?}", nbss_data_frame); (nbss_pdu, nbss_hdr_frame, nbss_data_frame) } - fn add_smb1_tc_pdu_frame(&mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) -> Option { - let smb_pdu = Frame::new(flow, stream_slice, input, nbss_len, SMBFrameType::SMB1Pdu as u8, None); + fn add_smb1_tc_pdu_frame( + &mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, + ) -> Option { + let smb_pdu = Frame::new( + flow, + stream_slice, + input, + nbss_len, + SMBFrameType::SMB1Pdu as u8, + None, + ); SCLogDebug!("SMB PDU frame {:?}", smb_pdu); smb_pdu } - fn add_smb1_tc_hdr_data_frames(&mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) { - let _smb1_hdr = Frame::new(flow, stream_slice, input, SMB1_HEADER_SIZE as i64, SMBFrameType::SMB1Hdr as u8, None); + fn add_smb1_tc_hdr_data_frames( + &mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, + ) { + let _smb1_hdr = Frame::new( + flow, + stream_slice, + input, + SMB1_HEADER_SIZE as i64, + SMBFrameType::SMB1Hdr as u8, + None, + ); SCLogDebug!("SMBv1 HDR frame {:?}", _smb1_hdr); if input.len() > SMB1_HEADER_SIZE { - let _smb1_data = Frame::new(flow, stream_slice, &input[SMB1_HEADER_SIZE..], nbss_len - SMB1_HEADER_SIZE as i64, - SMBFrameType::SMB1Data as u8, None); + let _smb1_data = Frame::new( + flow, + stream_slice, + &input[SMB1_HEADER_SIZE..], + nbss_len - SMB1_HEADER_SIZE as i64, + SMBFrameType::SMB1Data as u8, + None, + ); SCLogDebug!("SMBv1 DATA frame {:?}", _smb1_data); } } - fn add_smb2_tc_pdu_frame(&mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) -> Option { - let smb_pdu = Frame::new(flow, stream_slice, input, nbss_len, SMBFrameType::SMB2Pdu as u8, None); + fn add_smb2_tc_pdu_frame( + &mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, + ) -> Option { + let smb_pdu = Frame::new( + flow, + stream_slice, + input, + nbss_len, + SMBFrameType::SMB2Pdu as u8, + None, + ); SCLogDebug!("SMBv2 PDU frame {:?}", smb_pdu); smb_pdu } - fn add_smb2_tc_hdr_data_frames(&mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, hdr_len: i64) { - let _smb2_hdr = Frame::new(flow, stream_slice, input, hdr_len, SMBFrameType::SMB2Hdr as u8, None); + fn add_smb2_tc_hdr_data_frames( + &mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, + hdr_len: i64, + ) { + let _smb2_hdr = Frame::new( + flow, + stream_slice, + input, + hdr_len, + SMBFrameType::SMB2Hdr as u8, + None, + ); SCLogDebug!("SMBv2 HDR frame {:?}", _smb2_hdr); if input.len() > hdr_len as usize { - let _smb2_data = Frame::new(flow, stream_slice, &input[hdr_len as usize ..], nbss_len - hdr_len, SMBFrameType::SMB2Data as u8, None); + let _smb2_data = Frame::new( + flow, + stream_slice, + &input[hdr_len as usize..], + nbss_len - hdr_len, + SMBFrameType::SMB2Data as u8, + None, + ); SCLogDebug!("SMBv2 DATA frame {:?}", _smb2_data); } } - fn add_smb3_tc_pdu_frame(&mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) { - let _smb_pdu = Frame::new(flow, stream_slice, input, nbss_len, SMBFrameType::SMB3Pdu as u8, None); + fn add_smb3_tc_pdu_frame( + &mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, + ) { + let _smb_pdu = Frame::new( + flow, + stream_slice, + input, + nbss_len, + SMBFrameType::SMB3Pdu as u8, + None, + ); SCLogDebug!("SMBv3 PDU frame {:?}", _smb_pdu); } - fn add_smb3_tc_hdr_data_frames(&mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) { - let _smb3_hdr = Frame::new(flow, stream_slice, input, 52_i64, SMBFrameType::SMB3Hdr as u8, None); + fn add_smb3_tc_hdr_data_frames( + &mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, + ) { + let _smb3_hdr = Frame::new( + flow, + stream_slice, + input, + 52_i64, + SMBFrameType::SMB3Hdr as u8, + None, + ); SCLogDebug!("SMBv3 HDR frame {:?}", _smb3_hdr); if input.len() > 52 { - let _smb3_data = Frame::new(flow, stream_slice, &input[52..], nbss_len - 52, SMBFrameType::SMB3Data as u8, None); + let _smb3_data = Frame::new( + flow, + stream_slice, + &input[52..], + nbss_len - 52, + SMBFrameType::SMB3Data as u8, + None, + ); SCLogDebug!("SMBv3 DATA frame {:?}", _smb3_data); } } /// return bytes consumed - pub fn parse_tcp_data_tc_partial(&mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8]) -> usize - { + pub fn parse_tcp_data_tc_partial( + &mut self, flow: *mut Flow, stream_slice: &StreamSlice, input: &[u8], + ) -> usize { SCLogDebug!("incomplete of size {}", input.len()); if input.len() < 512 { // check for malformed data. Wireshark reports as @@ -1635,7 +1977,10 @@ impl SMBState { if input.len() > 8 { if let Ok((_, ref hdr)) = parse_nbss_record_partial(input) { if !hdr.is_smb() { - SCLogDebug!("partial NBSS, not SMB and no known msg type {}", hdr.message_type); + SCLogDebug!( + "partial NBSS, not SMB and no known msg type {}", + hdr.message_type + ); self.trunc_tc(); return 0; } @@ -1649,17 +1994,21 @@ impl SMBState { if nbss_part_hdr.message_type == NBSS_MSGTYPE_SESSION_MESSAGE { if let Ok((_, ref smb)) = parse_smb_version(nbss_part_hdr.data) { SCLogDebug!("SMB {:?}", smb); - if smb.version == 255u8 { // SMB1 + if smb.version == 255u8 { + // SMB1 SCLogDebug!("SMBv1 record"); if let Ok((_, ref r)) = parse_smb_record(nbss_part_hdr.data) { - SCLogDebug!("SMB1: partial record {}", - r.command); + SCLogDebug!("SMB1: partial record {}", r.command); if r.command == SMB1_COMMAND_READ_ANDX { - let tree_key = SMBCommonHdr::new(SMBHDR_TYPE_SHARE, - r.ssn_id as u64, r.tree_id as u32, 0); + let tree_key = SMBCommonHdr::new( + SMBHDR_TYPE_SHARE, + r.ssn_id as u64, + r.tree_id as u32, + 0, + ); let is_pipe = match self.ssn2tree_cache.get(&tree_key) { Some(n) => n.is_pipe, - None => false, + None => false, }; if is_pipe { return 0; @@ -1667,35 +2016,78 @@ impl SMBState { // create NBSS frames here so we don't get double frames // when we don't consume the data now. - self.add_nbss_tc_frames(flow, stream_slice, input, nbss_part_hdr.length as i64); - self.add_smb1_tc_pdu_frame(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64); - self.add_smb1_tc_hdr_data_frames(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64); + self.add_nbss_tc_frames( + flow, + stream_slice, + input, + nbss_part_hdr.length as i64, + ); + self.add_smb1_tc_pdu_frame( + flow, + stream_slice, + nbss_part_hdr.data, + nbss_part_hdr.length as i64, + ); + self.add_smb1_tc_hdr_data_frames( + flow, + stream_slice, + nbss_part_hdr.data, + nbss_part_hdr.length as i64, + ); // how many more bytes are expected within this NBSS record // So that we can check that further parsed offsets and lengths // stay within the NBSS record. - let nbss_remaining = nbss_part_hdr.length - nbss_part_hdr.data.len() as u32; - smb1_read_response_record(self, r, SMB1_HEADER_SIZE, nbss_remaining); + let nbss_remaining = + nbss_part_hdr.length - nbss_part_hdr.data.len() as u32; + smb1_read_response_record( + self, + r, + SMB1_HEADER_SIZE, + nbss_remaining, + ); let consumed = input.len() - output.len(); return consumed; } } - } else if smb.version == 254u8 { // SMB2 + } else if smb.version == 254u8 { + // SMB2 SCLogDebug!("SMBv2 record"); - if let Ok((_, ref smb_record)) = parse_smb2_response_record(nbss_part_hdr.data) { - SCLogDebug!("SMB2: partial record {}", - &smb2_command_string(smb_record.command)); + if let Ok((_, ref smb_record)) = + parse_smb2_response_record(nbss_part_hdr.data) + { + SCLogDebug!( + "SMB2: partial record {}", + &smb2_command_string(smb_record.command) + ); if smb_record.command == SMB2_COMMAND_READ { // create NBSS frames here so we don't get double frames // when we don't consume the data now. - self.add_nbss_tc_frames(flow, stream_slice, input, nbss_part_hdr.length as i64); - self.add_smb2_tc_pdu_frame(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64); - self.add_smb2_tc_hdr_data_frames(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64, smb_record.header_len as i64); + self.add_nbss_tc_frames( + flow, + stream_slice, + input, + nbss_part_hdr.length as i64, + ); + self.add_smb2_tc_pdu_frame( + flow, + stream_slice, + nbss_part_hdr.data, + nbss_part_hdr.length as i64, + ); + self.add_smb2_tc_hdr_data_frames( + flow, + stream_slice, + nbss_part_hdr.data, + nbss_part_hdr.length as i64, + smb_record.header_len as i64, + ); // how many more bytes are expected within this NBSS record // So that we can check that further parsed offsets and lengths // stay within the NBSS record. - let nbss_remaining = nbss_part_hdr.length - nbss_part_hdr.data.len() as u32; + let nbss_remaining = + nbss_part_hdr.length - nbss_part_hdr.data.len() as u32; smb2_read_response_record(self, smb_record, nbss_remaining); let consumed = input.len() - output.len(); return consumed; @@ -1710,8 +2102,9 @@ impl SMBState { } /// Parsing function, handling TCP chunks fragmentation - pub fn parse_tcp_data_tc(&mut self, flow: *mut Flow, stream_slice: &StreamSlice) -> AppLayerResult - { + pub fn parse_tcp_data_tc( + &mut self, flow: *mut Flow, stream_slice: &StreamSlice, + ) -> AppLayerResult { let mut cur_i = stream_slice.as_slice(); let consumed = self.handle_skip(Direction::ToClient, cur_i.len() as u32); if consumed > 0 { @@ -1737,13 +2130,14 @@ impl SMBState { // gap if self.tc_gap { SCLogDebug!("TC trying to catch up after GAP (input {})", cur_i.len()); - while !cur_i.is_empty() { // min record size + while !cur_i.is_empty() { + // min record size match search_smb_record(cur_i) { Ok((_, pg)) => { SCLogDebug!("smb record found"); let smb2_offset = cur_i.len() - pg.len(); if smb2_offset < 4 { - cur_i = &cur_i[smb2_offset+4..]; + cur_i = &cur_i[smb2_offset + 4..]; continue; // see if we have another record in our data } let nbss_offset = smb2_offset - 4; @@ -1751,7 +2145,7 @@ impl SMBState { self.tc_gap = false; break; - }, + } _ => { let mut consumed = stream_slice.len(); if consumed < 4 { @@ -1761,14 +2155,19 @@ impl SMBState { } SCLogDebug!("smb record NOT found"); return AppLayerResult::incomplete(consumed, 8); - }, + } } } } - while !cur_i.is_empty() { // min record size + while !cur_i.is_empty() { + // min record size match parse_nbss_record(cur_i) { Ok((rem, ref nbss_hdr)) => { - SCLogDebug!("nbss record offset {} len {}", stream_slice.offset_from(cur_i), cur_i.len() - rem.len()); + SCLogDebug!( + "nbss record offset {} len {}", + stream_slice.offset_from(cur_i), + cur_i.len() - rem.len() + ); self.add_nbss_tc_frames(flow, stream_slice, cur_i, nbss_hdr.length as i64); SCLogDebug!("nbss frames added"); @@ -1778,88 +2177,134 @@ impl SMBState { match parse_smb_version(nbss_hdr.data) { Ok((_, ref smb)) => { SCLogDebug!("SMB {:?}", smb); - if smb.version == 0xff_u8 { // SMB1 + if smb.version == 0xff_u8 { + // SMB1 SCLogDebug!("SMBv1 record"); match parse_smb_record(nbss_hdr.data) { Ok((_, ref smb_record)) => { - let pdu_frame = self.add_smb1_tc_pdu_frame(flow, stream_slice, nbss_hdr.data, nbss_hdr.length as i64); - self.add_smb1_tc_hdr_data_frames(flow, stream_slice, nbss_hdr.data, nbss_hdr.length as i64); + let pdu_frame = self.add_smb1_tc_pdu_frame( + flow, + stream_slice, + nbss_hdr.data, + nbss_hdr.length as i64, + ); + self.add_smb1_tc_hdr_data_frames( + flow, + stream_slice, + nbss_hdr.data, + nbss_hdr.length as i64, + ); // see https://github.com/rust-lang/rust-clippy/issues/15158 #[allow(clippy::collapsible_else_if)] if smb_record.is_response() { smb1_response_record(self, smb_record); } else { - SCLogDebug!("SMB1 request seen from server to client"); + SCLogDebug!( + "SMB1 request seen from server to client" + ); if let Some(frame) = pdu_frame { - frame.add_event(flow, SMBEvent::RequestToClient as u8); + frame.add_event( + flow, + SMBEvent::RequestToClient as u8, + ); } } - }, + } _ => { self.set_event(SMBEvent::MalformedData); return AppLayerResult::err(); - }, + } } - } else if smb.version == 0xfe_u8 { // SMB2 + } else if smb.version == 0xfe_u8 { + // SMB2 let mut nbss_data = nbss_hdr.data; while !nbss_data.is_empty() { SCLogDebug!("SMBv2 record"); match parse_smb2_response_record(nbss_data) { Ok((nbss_data_rem, ref smb_record)) => { - let record_len = (nbss_data.len() - nbss_data_rem.len()) as i64; - let pdu_frame = self.add_smb2_tc_pdu_frame(flow, stream_slice, nbss_data, record_len); - self.add_smb2_tc_hdr_data_frames(flow, stream_slice, nbss_data, record_len, smb_record.header_len as i64); + let record_len = + (nbss_data.len() - nbss_data_rem.len()) as i64; + let pdu_frame = self.add_smb2_tc_pdu_frame( + flow, + stream_slice, + nbss_data, + record_len, + ); + self.add_smb2_tc_hdr_data_frames( + flow, + stream_slice, + nbss_data, + record_len, + smb_record.header_len as i64, + ); // see https://github.com/rust-lang/rust-clippy/issues/15158 #[allow(clippy::collapsible_else_if)] if smb_record.is_response() { smb2_response_record(self, smb_record); } else { - SCLogDebug!("SMB2 request seen from server to client"); + SCLogDebug!( + "SMB2 request seen from server to client" + ); if let Some(frame) = pdu_frame { - frame.add_event(flow, SMBEvent::RequestToClient as u8); + frame.add_event( + flow, + SMBEvent::RequestToClient as u8, + ); } } nbss_data = nbss_data_rem; - }, + } _ => { self.set_event(SMBEvent::MalformedData); return AppLayerResult::err(); - }, + } } } - } else if smb.version == 0xfd_u8 { // SMB3 transform + } else if smb.version == 0xfd_u8 { + // SMB3 transform let mut nbss_data = nbss_hdr.data; while !nbss_data.is_empty() { SCLogDebug!("SMBv3 transform record"); match parse_smb3_transform_record(nbss_data) { Ok((nbss_data_rem, ref _smb3_record)) => { - let record_len = (nbss_data.len() - nbss_data_rem.len()) as i64; - self.add_smb3_tc_pdu_frame(flow, stream_slice, nbss_data, record_len); - self.add_smb3_tc_hdr_data_frames(flow, stream_slice, nbss_data, record_len); + let record_len = + (nbss_data.len() - nbss_data_rem.len()) as i64; + self.add_smb3_tc_pdu_frame( + flow, + stream_slice, + nbss_data, + record_len, + ); + self.add_smb3_tc_hdr_data_frames( + flow, + stream_slice, + nbss_data, + record_len, + ); nbss_data = nbss_data_rem; - }, + } _ => { self.set_event(SMBEvent::MalformedData); return AppLayerResult::err(); - }, + } } } } - }, + } Err(Err::Incomplete(_)) => { // not enough data to contain basic SMB hdr // TODO event: empty NBSS_MSGTYPE_SESSION_MESSAGE - }, + } Err(_) => { self.set_event(SMBEvent::MalformedData); return AppLayerResult::err(); - }, + } } } else { SCLogDebug!("NBSS message {:X}", nbss_hdr.message_type); } cur_i = rem; - }, + } Err(Err::Incomplete(needed)) => { SCLogDebug!("INCOMPLETE have {} needed {:?}", cur_i.len(), needed); if let Needed::Size(n) = needed { @@ -1873,8 +2318,13 @@ impl SMBState { if consumed == 0 { // if we consumed none we will buffer the entire record let total_consumed = stream_slice.offset_from(cur_i); - SCLogDebug!("setting consumed {} need {} needed {:?} total input {}", - total_consumed, n, needed, stream_slice.len()); + SCLogDebug!( + "setting consumed {} need {} needed {:?} total input {}", + total_consumed, + n, + needed, + stream_slice.len() + ); let need = n; return AppLayerResult::incomplete(total_consumed, need as u32); } @@ -1886,13 +2336,13 @@ impl SMBState { self.set_event(SMBEvent::InternalError); return AppLayerResult::err(); } - }, + } Err(_) => { self.set_event(SMBEvent::MalformedData); return AppLayerResult::err(); - }, + } } - }; + } self.post_gap_housekeeping(Direction::ToClient); if self.check_post_gap_file_txs && !self.post_gap_files_checked { self.post_gap_housekeeping_for_files(); @@ -1923,7 +2373,11 @@ impl SMBState { } if consumed2 > new_gap_size { - SCLogDebug!("consumed more than GAP size: {} > {}", consumed2, new_gap_size); + SCLogDebug!( + "consumed more than GAP size: {} > {}", + consumed2, + new_gap_size + ); self.set_event(SMBEvent::InternalError); return AppLayerResult::err(); } @@ -1955,7 +2409,11 @@ impl SMBState { } if consumed2 > new_gap_size { - SCLogDebug!("consumed more than GAP size: {} > {}", consumed2, new_gap_size); + SCLogDebug!( + "consumed more than GAP size: {} > {}", + consumed2, + new_gap_size + ); self.set_event(SMBEvent::InternalError); return AppLayerResult::err(); } @@ -1975,7 +2433,7 @@ impl SMBState { SCLogDebug!("TRUNCATING TX {} in TOSERVER direction", tx.id); tx.request_done = true; } - } + } } pub fn trunc_tc(&mut self) { SCLogDebug!("TRUNC TC"); @@ -1991,7 +2449,9 @@ impl SMBState { } /// Returns *mut SMBState -extern "C" fn smb_state_new(_orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto) -> *mut std::os::raw::c_void { +extern "C" fn smb_state_new( + _orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto, +) -> *mut std::os::raw::c_void { let state = SMBState::new(); let boxed = Box::new(state); SCLogDebug!("allocating state"); @@ -2007,14 +2467,10 @@ extern "C" fn smb_state_free(state: *mut std::os::raw::c_void) { } /// C binding parse a SMB request. Returns 1 on success, -1 on failure. -unsafe extern "C" fn smb_parse_request_tcp(flow: *mut Flow, - state: *mut ffi::c_void, - _pstate: *mut AppLayerParserState, - stream_slice: StreamSlice, - _data: *mut std::os::raw::c_void, - ) - -> AppLayerResult -{ +unsafe extern "C" fn smb_parse_request_tcp( + flow: *mut Flow, state: *mut ffi::c_void, _pstate: *mut AppLayerParserState, + stream_slice: StreamSlice, _data: *mut std::os::raw::c_void, +) -> AppLayerResult { let state = cast_pointer!(state, SMBState); let flow = cast_pointer!(flow, Flow); @@ -2025,7 +2481,8 @@ unsafe extern "C" fn smb_parse_request_tcp(flow: *mut Flow, SCLogDebug!("parsing {} bytes of request data", stream_slice.len()); /* START with MISTREAM set: record might be starting the middle. */ - if stream_slice.flags() & (STREAM_START|STREAM_MIDSTREAM) == (STREAM_START|STREAM_MIDSTREAM) { + if stream_slice.flags() & (STREAM_START | STREAM_MIDSTREAM) == (STREAM_START | STREAM_MIDSTREAM) + { state.ts_gap = true; } @@ -2033,23 +2490,14 @@ unsafe extern "C" fn smb_parse_request_tcp(flow: *mut Flow, state.parse_tcp_data_ts(flow, &stream_slice) } -extern "C" fn smb_parse_request_tcp_gap( - state: &mut SMBState, - input_len: u32) - -> AppLayerResult -{ +extern "C" fn smb_parse_request_tcp_gap(state: &mut SMBState, input_len: u32) -> AppLayerResult { state.parse_tcp_data_ts_gap(input_len) } - -unsafe extern "C" fn smb_parse_response_tcp(flow: *mut Flow, - state: *mut ffi::c_void, - _pstate: *mut AppLayerParserState, - stream_slice: StreamSlice, - _data: *mut ffi::c_void, - ) - -> AppLayerResult -{ +unsafe extern "C" fn smb_parse_response_tcp( + flow: *mut Flow, state: *mut ffi::c_void, _pstate: *mut AppLayerParserState, + stream_slice: StreamSlice, _data: *mut ffi::c_void, +) -> AppLayerResult { let state = cast_pointer!(state, SMBState); let flow = cast_pointer!(flow, Flow); @@ -2058,7 +2506,8 @@ unsafe extern "C" fn smb_parse_response_tcp(flow: *mut Flow, } /* START with MISTREAM set: record might be starting the middle. */ - if stream_slice.flags() & (STREAM_START|STREAM_MIDSTREAM) == (STREAM_START|STREAM_MIDSTREAM) { + if stream_slice.flags() & (STREAM_START | STREAM_MIDSTREAM) == (STREAM_START | STREAM_MIDSTREAM) + { state.tc_gap = true; } @@ -2066,16 +2515,11 @@ unsafe extern "C" fn smb_parse_response_tcp(flow: *mut Flow, state.parse_tcp_data_tc(flow, &stream_slice) } -extern "C" fn smb_parse_response_tcp_gap( - state: &mut SMBState, - input_len: u32) - -> AppLayerResult -{ +extern "C" fn smb_parse_response_tcp_gap(state: &mut SMBState, input_len: u32) -> AppLayerResult { state.parse_tcp_data_tc_gap(input_len) } -fn smb_probe_tcp_midstream(direction: Direction, slice: &[u8], rdir: *mut u8, begins: bool) -> i8 -{ +fn smb_probe_tcp_midstream(direction: Direction, slice: &[u8], rdir: *mut u8, begins: bool) -> i8 { let r = if begins { // if pattern was found in the beginning, just check first byte if slice[0] == NBSS_MSGTYPE_SESSION_MESSAGE { @@ -2090,7 +2534,8 @@ fn smb_probe_tcp_midstream(direction: Direction, slice: &[u8], rdir: *mut u8, be SCLogDebug!("smb found"); if let Ok((_, ref smb)) = parse_smb_version(data) { SCLogDebug!("SMB {:?}", smb); - if smb.version == 0xff_u8 { // SMB1 + if smb.version == 0xff_u8 { + // SMB1 SCLogDebug!("SMBv1 record"); if let Ok((_, ref smb_record)) = parse_smb_record(data) { // see https://github.com/rust-lang/rust-clippy/issues/15158 @@ -2098,17 +2543,22 @@ fn smb_probe_tcp_midstream(direction: Direction, slice: &[u8], rdir: *mut u8, be if smb_record.flags & 0x80 != 0 { SCLogDebug!("RESPONSE {:02x}", smb_record.flags); if direction == Direction::ToServer { - unsafe { *rdir = Direction::ToClient as u8; } + unsafe { + *rdir = Direction::ToClient as u8; + } } } else { SCLogDebug!("REQUEST {:02x}", smb_record.flags); if direction == Direction::ToClient { - unsafe { *rdir = Direction::ToServer as u8; } + unsafe { + *rdir = Direction::ToServer as u8; + } } } return 1; } - } else if smb.version == 0xfe_u8 { // SMB2 + } else if smb.version == 0xfe_u8 { + // SMB2 SCLogDebug!("SMB2 record"); if let Ok((_, ref smb_record)) = parse_smb2_record_direction(data) { // see https://github.com/rust-lang/rust-clippy/issues/15158 @@ -2116,17 +2566,21 @@ fn smb_probe_tcp_midstream(direction: Direction, slice: &[u8], rdir: *mut u8, be if direction == Direction::ToServer { SCLogDebug!("direction Direction::ToServer smb_record {:?}", smb_record); if !smb_record.request { - unsafe { *rdir = Direction::ToClient as u8; } + unsafe { + *rdir = Direction::ToClient as u8; + } } } else { SCLogDebug!("direction Direction::ToClient smb_record {:?}", smb_record); if smb_record.request { - unsafe { *rdir = Direction::ToServer as u8; } + unsafe { + *rdir = Direction::ToServer as u8; + } } } } - } - else if smb.version == 0xfd_u8 { // SMB3 transform + } else if smb.version == 0xfd_u8 { + // SMB3 transform SCLogDebug!("SMB3 record"); } return 1; @@ -2139,35 +2593,41 @@ fn smb_probe_tcp_midstream(direction: Direction, slice: &[u8], rdir: *mut u8, be return 0; } -fn smb_probe_tcp(flags: u8, slice: &[u8], rdir: *mut u8, begins: bool) -> AppProto -{ - if flags & STREAM_MIDSTREAM == STREAM_MIDSTREAM && smb_probe_tcp_midstream(flags.into(), slice, rdir, begins) == 1 { - unsafe { return ALPROTO_SMB; } +fn smb_probe_tcp(flags: u8, slice: &[u8], rdir: *mut u8, begins: bool) -> AppProto { + if flags & STREAM_MIDSTREAM == STREAM_MIDSTREAM + && smb_probe_tcp_midstream(flags.into(), slice, rdir, begins) == 1 + { + unsafe { + return ALPROTO_SMB; + } } if let Ok((_, ref hdr)) = parse_nbss_record_partial(slice) { if hdr.is_smb() { SCLogDebug!("smb found"); - unsafe { return ALPROTO_SMB; } - } else if hdr.needs_more(){ + unsafe { + return ALPROTO_SMB; + } + } else if hdr.needs_more() { return 0; - } else if hdr.is_valid() && - hdr.message_type != NBSS_MSGTYPE_SESSION_MESSAGE { - //we accept a first small netbios message before real SMB - let hl = hdr.length as usize; - if hdr.data.len() >= hl + 8 { - // 8 is 4 bytes NBSS + 4 bytes SMB0xFX magic - if let Ok((_, ref hdr2)) = parse_nbss_record_partial(&hdr.data[hl..]) { - if hdr2.is_smb() { - SCLogDebug!("smb found"); - unsafe { return ALPROTO_SMB; } + } else if hdr.is_valid() && hdr.message_type != NBSS_MSGTYPE_SESSION_MESSAGE { + //we accept a first small netbios message before real SMB + let hl = hdr.length as usize; + if hdr.data.len() >= hl + 8 { + // 8 is 4 bytes NBSS + 4 bytes SMB0xFX magic + if let Ok((_, ref hdr2)) = parse_nbss_record_partial(&hdr.data[hl..]) { + if hdr2.is_smb() { + SCLogDebug!("smb found"); + unsafe { + return ALPROTO_SMB; } } - } else if hdr.length < 256 { - // we want more data, 256 is some random value - return 0; } - // default is failure + } else if hdr.length < 256 { + // we want more data, 256 is some random value + return 0; } + // default is failure + } } SCLogDebug!("no smb"); return ALPROTO_FAILED; @@ -2175,10 +2635,9 @@ fn smb_probe_tcp(flags: u8, slice: &[u8], rdir: *mut u8, begins: bool) -> AppPro // probing confirmation parser // return 1 if found, 0 is not found -unsafe extern "C" fn smb_probe_begins_tcp(_f: *const Flow, - flags: u8, input: *const u8, len: u32, rdir: *mut u8) - -> AppProto -{ +unsafe extern "C" fn smb_probe_begins_tcp( + _f: *const Flow, flags: u8, input: *const u8, len: u32, rdir: *mut u8, +) -> AppProto { if len < MIN_REC_SIZE as u32 || input.is_null() { return ALPROTO_UNKNOWN; } @@ -2188,10 +2647,9 @@ unsafe extern "C" fn smb_probe_begins_tcp(_f: *const Flow, // probing parser // return 1 if found, 0 is not found -unsafe extern "C" fn c_smb_probe_tcp(_f: *const Flow, - flags: u8, input: *const u8, len: u32, rdir: *mut u8) - -> AppProto -{ +unsafe extern "C" fn c_smb_probe_tcp( + _f: *const Flow, flags: u8, input: *const u8, len: u32, rdir: *mut u8, +) -> AppProto { if len < MIN_REC_SIZE as u32 || input.is_null() { return ALPROTO_UNKNOWN; } @@ -2199,18 +2657,13 @@ unsafe extern "C" fn c_smb_probe_tcp(_f: *const Flow, return smb_probe_tcp(flags, slice, rdir, false); } -unsafe extern "C" fn smb_state_get_tx_count(state: *mut ffi::c_void) - -> u64 -{ +unsafe extern "C" fn smb_state_get_tx_count(state: *mut ffi::c_void) -> u64 { let state = cast_pointer!(state, SMBState); SCLogDebug!("smb_state_get_tx_count: returning {}", state.tx_id); return state.tx_id; } -unsafe extern "C" fn smb_state_get_tx(state: *mut ffi::c_void, - tx_id: u64) - -> *mut ffi::c_void -{ +unsafe extern "C" fn smb_state_get_tx(state: *mut ffi::c_void, tx_id: u64) -> *mut ffi::c_void { let state = cast_pointer!(state, SMBState); match state.get_tx_by_id(tx_id) { Some(tx) => { @@ -2222,18 +2675,13 @@ unsafe extern "C" fn smb_state_get_tx(state: *mut ffi::c_void, } } -unsafe extern "C" fn smb_state_tx_free(state: *mut ffi::c_void, - tx_id: u64) -{ +unsafe extern "C" fn smb_state_tx_free(state: *mut ffi::c_void, tx_id: u64) { let state = cast_pointer!(state, SMBState); SCLogDebug!("freeing tx {}", tx_id); state.free_tx(tx_id); } -unsafe extern "C" fn smb_tx_get_alstate_progress(tx: *mut ffi::c_void, - direction: u8) - -> i32 -{ +unsafe extern "C" fn smb_tx_get_alstate_progress(tx: *mut ffi::c_void, direction: u8) -> i32 { let tx = cast_pointer!(tx, SMBTransaction); if direction == Direction::ToServer as u8 && tx.request_done { @@ -2243,39 +2691,40 @@ unsafe extern "C" fn smb_tx_get_alstate_progress(tx: *mut ffi::c_void, SCLogDebug!("tx {} TOCLIENT progress 1 => {:?}", tx.id, tx); return 1; } else { - SCLogDebug!("tx {} direction {} progress 0 => {:?}", tx.id, direction, tx); + SCLogDebug!( + "tx {} direction {} progress 0 => {:?}", + tx.id, + direction, + tx + ); return 0; } } - export_state_data_get!(smb_get_state_data, SMBState); unsafe extern "C" fn smb_get_tx_data( - tx: *mut std::os::raw::c_void) - -> *mut suricata_sys::sys::AppLayerTxData -{ + tx: *mut std::os::raw::c_void, +) -> *mut suricata_sys::sys::AppLayerTxData { let tx = cast_pointer!(tx, SMBTransaction); return &mut tx.tx_data.0; } unsafe extern "C" fn smb_state_get_event_info_by_id( - event_id: u8, - event_name: *mut *const std::os::raw::c_char, - event_type: *mut AppLayerEventType, + event_id: u8, event_name: *mut *const std::os::raw::c_char, event_type: *mut AppLayerEventType, ) -> std::os::raw::c_int { SMBEvent::get_event_info_by_id(event_id, event_name, event_type) } unsafe extern "C" fn smb_state_get_event_info( - event_name: *const std::os::raw::c_char, - event_id: *mut u8, - event_type: *mut AppLayerEventType, + event_name: *const std::os::raw::c_char, event_id: *mut u8, event_type: *mut AppLayerEventType, ) -> std::os::raw::c_int { SMBEvent::get_event_info(event_name, event_id, event_type) } -unsafe extern "C" fn smb3_probe_tcp(f: *const Flow, dir: u8, input: *const u8, len: u32, rdir: *mut u8) -> u16 { +unsafe extern "C" fn smb3_probe_tcp( + f: *const Flow, dir: u8, input: *const u8, len: u32, rdir: *mut u8, +) -> u16 { let retval = c_smb_probe_tcp(f, dir, input, len, rdir); let f = cast_pointer!(f, Flow); if retval != ALPROTO_SMB { @@ -2283,8 +2732,16 @@ unsafe extern "C" fn smb3_probe_tcp(f: *const Flow, dir: u8, input: *const u8, l } let (sp, dp) = flow_get_ports(f); let flags = flow_get_flags(f); - let fsp = if (flags & FLOW_DIR_REVERSED) != 0 { dp } else { sp }; - let fdp = if (flags & FLOW_DIR_REVERSED) != 0 { sp } else { dp }; + let fsp = if (flags & FLOW_DIR_REVERSED) != 0 { + dp + } else { + sp + }; + let fdp = if (flags & FLOW_DIR_REVERSED) != 0 { + sp + } else { + dp + }; if fsp == 445 && fdp != 445 { match dir.into() { Direction::ToServer => { @@ -2302,26 +2759,74 @@ fn register_pattern_probe() -> i8 { let mut r = 0; unsafe { // SMB1 - r |= SCAppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB, - b"|ff|SMB\0".as_ptr() as *const std::os::raw::c_char, 8, 4, - Direction::ToServer as u8, Some(smb_probe_begins_tcp), MIN_REC_SIZE, MIN_REC_SIZE); - r |= SCAppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB, - b"|ff|SMB\0".as_ptr() as *const std::os::raw::c_char, 8, 4, - Direction::ToClient as u8, Some(smb_probe_begins_tcp), MIN_REC_SIZE, MIN_REC_SIZE); + r |= SCAppLayerProtoDetectPMRegisterPatternCSwPP( + IPPROTO_TCP, + ALPROTO_SMB, + b"|ff|SMB\0".as_ptr() as *const std::os::raw::c_char, + 8, + 4, + Direction::ToServer as u8, + Some(smb_probe_begins_tcp), + MIN_REC_SIZE, + MIN_REC_SIZE, + ); + r |= SCAppLayerProtoDetectPMRegisterPatternCSwPP( + IPPROTO_TCP, + ALPROTO_SMB, + b"|ff|SMB\0".as_ptr() as *const std::os::raw::c_char, + 8, + 4, + Direction::ToClient as u8, + Some(smb_probe_begins_tcp), + MIN_REC_SIZE, + MIN_REC_SIZE, + ); // SMB2/3 - r |= SCAppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB, - b"|fe|SMB\0".as_ptr() as *const std::os::raw::c_char, 8, 4, - Direction::ToServer as u8, Some(smb_probe_begins_tcp), MIN_REC_SIZE, MIN_REC_SIZE); - r |= SCAppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB, - b"|fe|SMB\0".as_ptr() as *const std::os::raw::c_char, 8, 4, - Direction::ToClient as u8, Some(smb_probe_begins_tcp), MIN_REC_SIZE, MIN_REC_SIZE); + r |= SCAppLayerProtoDetectPMRegisterPatternCSwPP( + IPPROTO_TCP, + ALPROTO_SMB, + b"|fe|SMB\0".as_ptr() as *const std::os::raw::c_char, + 8, + 4, + Direction::ToServer as u8, + Some(smb_probe_begins_tcp), + MIN_REC_SIZE, + MIN_REC_SIZE, + ); + r |= SCAppLayerProtoDetectPMRegisterPatternCSwPP( + IPPROTO_TCP, + ALPROTO_SMB, + b"|fe|SMB\0".as_ptr() as *const std::os::raw::c_char, + 8, + 4, + Direction::ToClient as u8, + Some(smb_probe_begins_tcp), + MIN_REC_SIZE, + MIN_REC_SIZE, + ); // SMB3 encrypted records - r |= SCAppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB, - b"|fd|SMB\0".as_ptr() as *const std::os::raw::c_char, 8, 4, - Direction::ToServer as u8, Some(smb3_probe_tcp), MIN_REC_SIZE, MIN_REC_SIZE); - r |= SCAppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB, - b"|fd|SMB\0".as_ptr() as *const std::os::raw::c_char, 8, 4, - Direction::ToClient as u8, Some(smb3_probe_tcp), MIN_REC_SIZE, MIN_REC_SIZE); + r |= SCAppLayerProtoDetectPMRegisterPatternCSwPP( + IPPROTO_TCP, + ALPROTO_SMB, + b"|fd|SMB\0".as_ptr() as *const std::os::raw::c_char, + 8, + 4, + Direction::ToServer as u8, + Some(smb3_probe_tcp), + MIN_REC_SIZE, + MIN_REC_SIZE, + ); + r |= SCAppLayerProtoDetectPMRegisterPatternCSwPP( + IPPROTO_TCP, + ALPROTO_SMB, + b"|fd|SMB\0".as_ptr() as *const std::os::raw::c_char, + 8, + 4, + Direction::ToClient as u8, + Some(smb3_probe_tcp), + MIN_REC_SIZE, + MIN_REC_SIZE, + ); } if r == 0 { @@ -2357,7 +2862,7 @@ pub unsafe extern "C" fn SCRegisterSmbParser() { tx_comp_st_tc: 1, tx_get_progress: smb_tx_get_alstate_progress, get_eventinfo: Some(smb_state_get_event_info), - get_eventinfo_byid : Some(smb_state_get_event_info_by_id), + get_eventinfo_byid: Some(smb_state_get_event_info_by_id), localstorage_new: None, localstorage_free: None, get_tx_files: Some(smb_gettxfiles), @@ -2374,82 +2879,117 @@ pub unsafe extern "C" fn SCRegisterSmbParser() { let ip_proto_str = CString::new("tcp").unwrap(); - if SCAppLayerProtoDetectConfProtoDetectionEnabled( - ip_proto_str.as_ptr(), - parser.name, - ) != 0 - { + if SCAppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { let alproto = applayer_register_protocol_detection(&parser, 1); ALPROTO_SMB = alproto; if register_pattern_probe() < 0 { return; } - let have_cfg = SCAppLayerProtoDetectPPParseConfPorts(ip_proto_str.as_ptr(), - IPPROTO_TCP, parser.name, ALPROTO_SMB, 0, - MIN_REC_SIZE, Some(c_smb_probe_tcp), Some(c_smb_probe_tcp)); - - if have_cfg == 0 { - SCAppLayerProtoDetectPPRegister(IPPROTO_TCP, default_port.as_ptr(), ALPROTO_SMB, - 0, MIN_REC_SIZE, Direction::ToServer as u8, Some(c_smb_probe_tcp), Some(c_smb_probe_tcp)); - } - - if SCAppLayerParserConfParserEnabled( + let have_cfg = SCAppLayerProtoDetectPPParseConfPorts( ip_proto_str.as_ptr(), + IPPROTO_TCP, parser.name, - ) != 0 - { + ALPROTO_SMB, + 0, + MIN_REC_SIZE, + Some(c_smb_probe_tcp), + Some(c_smb_probe_tcp), + ); + + if have_cfg == 0 { + SCAppLayerProtoDetectPPRegister( + IPPROTO_TCP, + default_port.as_ptr(), + ALPROTO_SMB, + 0, + MIN_REC_SIZE, + Direction::ToServer as u8, + Some(c_smb_probe_tcp), + Some(c_smb_probe_tcp), + ); + } + + if SCAppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { let _ = AppLayerRegisterParser(&parser, alproto); } SCLogDebug!("Rust SMB parser registered."); let retval = conf_get("app-layer.protocols.smb.stream-depth"); if let Some(val) = retval { match get_memval(val) { - Ok(retval) => { stream_depth = retval as u32; } - Err(_) => { SCLogError!("Invalid depth value"); } + Ok(retval) => { + stream_depth = retval as u32; + } + Err(_) => { + SCLogError!("Invalid depth value"); + } } } SCAppLayerParserSetStreamDepth(IPPROTO_TCP, ALPROTO_SMB, stream_depth); let retval = conf_get("app-layer.protocols.smb.max-read-size"); if let Some(val) = retval { match get_memval(val) { - Ok(retval) => { SMB_CFG_MAX_READ_SIZE = retval as u32; } - Err(_) => { SCLogError!("Invalid max-read-size value"); } + Ok(retval) => { + SMB_CFG_MAX_READ_SIZE = retval as u32; + } + Err(_) => { + SCLogError!("Invalid max-read-size value"); + } } } let retval = conf_get("app-layer.protocols.smb.max-write-size"); if let Some(val) = retval { match get_memval(val) { - Ok(retval) => { SMB_CFG_MAX_WRITE_SIZE = retval as u32; } - Err(_) => { SCLogError!("Invalid max-write-size value"); } + Ok(retval) => { + SMB_CFG_MAX_WRITE_SIZE = retval as u32; + } + Err(_) => { + SCLogError!("Invalid max-write-size value"); + } } } let retval = conf_get("app-layer.protocols.smb.max-write-queue-size"); if let Some(val) = retval { match get_memval(val) { - Ok(retval) => { SMB_CFG_MAX_WRITE_QUEUE_SIZE = retval as u32; } - Err(_) => { SCLogError!("Invalid max-write-queue-size value"); } + Ok(retval) => { + SMB_CFG_MAX_WRITE_QUEUE_SIZE = retval as u32; + } + Err(_) => { + SCLogError!("Invalid max-write-queue-size value"); + } } } let retval = conf_get("app-layer.protocols.smb.max-write-queue-cnt"); if let Some(val) = retval { match get_memval(val) { - Ok(retval) => { SMB_CFG_MAX_WRITE_QUEUE_CNT = retval as u32; } - Err(_) => { SCLogError!("Invalid max-write-queue-cnt value"); } + Ok(retval) => { + SMB_CFG_MAX_WRITE_QUEUE_CNT = retval as u32; + } + Err(_) => { + SCLogError!("Invalid max-write-queue-cnt value"); + } } } let retval = conf_get("app-layer.protocols.smb.max-read-queue-size"); if let Some(val) = retval { match get_memval(val) { - Ok(retval) => { SMB_CFG_MAX_READ_QUEUE_SIZE = retval as u32; } - Err(_) => { SCLogError!("Invalid max-read-queue-size value"); } + Ok(retval) => { + SMB_CFG_MAX_READ_QUEUE_SIZE = retval as u32; + } + Err(_) => { + SCLogError!("Invalid max-read-queue-size value"); + } } } let retval = conf_get("app-layer.protocols.smb.max-read-queue-cnt"); if let Some(val) = retval { match get_memval(val) { - Ok(retval) => { SMB_CFG_MAX_READ_QUEUE_CNT = retval as u32; } - Err(_) => { SCLogError!("Invalid max-read-queue-cnt value"); } + Ok(retval) => { + SMB_CFG_MAX_READ_QUEUE_CNT = retval as u32; + } + Err(_) => { + SCLogError!("Invalid max-read-queue-cnt value"); + } } } if let Some(val) = conf_get("app-layer.protocols.smb.max-tx") { @@ -2507,21 +3047,21 @@ pub unsafe extern "C" fn SCRegisterSmbParser() { SCLogError!("Invalid max-dcerpc-frag-cache-size value"); } } - let retval = conf_get("app-layer.protocols.smb.dcerpc.max-stub-size"); - if let Some(val) = retval { - match get_memval(val) { - Ok(retval) => { + let retval = conf_get("app-layer.protocols.smb.dcerpc.max-stub-size"); + if let Some(val) = retval { + match get_memval(val) { + Ok(retval) => { if retval > 0 { SMB_DCERPC_MAX_STUB_SIZE = retval as u32; } else { SCLogError!("Invalid max-stub-size value"); } - } - Err(_) => { + } + Err(_) => { SCLogError!("Invalid max-stub-size value"); - } - } - } + } + } + } let retval = conf_get("app-layer.protocols.smb.max-session-cache-size"); if let Some(val) = retval { if let Ok(v) = val.parse::() { @@ -2534,10 +3074,18 @@ pub unsafe extern "C" fn SCRegisterSmbParser() { SCLogError!("Invalid max-session-cache-size value"); } } - SCLogConfig!("read: max record size: {}, max queued chunks {}, max queued size {}", - cfg_max_read_size(), cfg_max_read_queue_cnt(), cfg_max_read_queue_size()); - SCLogConfig!("write: max record size: {}, max queued chunks {}, max queued size {}", - cfg_max_write_size(), cfg_max_write_queue_cnt(), cfg_max_write_queue_size()); + SCLogConfig!( + "read: max record size: {}, max queued chunks {}, max queued size {}", + cfg_max_read_size(), + cfg_max_read_queue_cnt(), + cfg_max_read_queue_size() + ); + SCLogConfig!( + "write: max record size: {}, max queued chunks {}, max queued size {}", + cfg_max_write_size(), + cfg_max_write_queue_cnt(), + cfg_max_write_queue_size() + ); SCLogConfig!("guid: max cache size: {}", cfg_max_guid_cache_size()); } else { SCLogDebug!("Protocol detector and parser disabled for SMB."); @@ -2597,4 +3145,3 @@ fn cfg_max_guid_cache_size() -> usize { pub fn cfg_max_stub_size() -> u32 { unsafe { SMB_DCERPC_MAX_STUB_SIZE } } - diff --git a/rust/src/smb/smb1.rs b/rust/src/smb/smb1.rs index fbb4fc3562..1daa55f17a 100644 --- a/rust/src/smb/smb1.rs +++ b/rust/src/smb/smb1.rs @@ -20,10 +20,10 @@ */ use crate::direction::Direction; -use crate::smb::smb::*; use crate::smb::dcerpc::*; use crate::smb::events::*; use crate::smb::files::*; +use crate::smb::smb::*; use crate::smb::smb1_records::*; use crate::smb::smb1_session::*; @@ -33,105 +33,108 @@ use crate::smb::smb_status::*; use nom8::Err; // https://msdn.microsoft.com/en-us/library/ee441741.aspx -pub const SMB1_COMMAND_CREATE_DIRECTORY: u8 = 0x00; -pub const SMB1_COMMAND_DELETE_DIRECTORY: u8 = 0x01; -pub const SMB1_COMMAND_OPEN: u8 = 0x02; -pub const SMB1_COMMAND_CREATE: u8 = 0x03; -pub const SMB1_COMMAND_CLOSE: u8 = 0x04; -pub const SMB1_COMMAND_FLUSH: u8 = 0x05; -pub const SMB1_COMMAND_DELETE: u8 = 0x06; -pub const SMB1_COMMAND_RENAME: u8 = 0x07; -pub const SMB1_COMMAND_QUERY_INFORMATION: u8 = 0x08; -pub const SMB1_COMMAND_SET_INFORMATION: u8 = 0x09; -pub const SMB1_COMMAND_READ: u8 = 0x0a; -pub const SMB1_COMMAND_WRITE: u8 = 0x0b; -pub const SMB1_COMMAND_LOCK_BYTE_RANGE: u8 = 0x0c; -pub const SMB1_COMMAND_UNLOCK_BYTE_RANGE: u8 = 0x0d; -pub const SMB1_COMMAND_CREATE_TEMPORARY: u8 = 0x0e; -pub const SMB1_COMMAND_CREATE_NEW: u8 = 0x0f; -pub const SMB1_COMMAND_CHECK_DIRECTORY: u8 = 0x10; -pub const SMB1_COMMAND_PROCESS_EXIT: u8 = 0x11; -pub const SMB1_COMMAND_SEEK: u8 = 0x12; -pub const SMB1_COMMAND_LOCK_AND_READ: u8 = 0x13; -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_OPEN_ANDX: u8 = 0x2d; -pub const SMB1_COMMAND_READ_ANDX: u8 = 0x2e; -pub const SMB1_COMMAND_WRITE_ANDX: u8 = 0x2f; -pub const SMB1_COMMAND_TRANS2: u8 = 0x32; -pub const SMB1_COMMAND_TRANS2_SECONDARY: u8 = 0x33; -pub const SMB1_COMMAND_FIND_CLOSE2: u8 = 0x34; -pub const SMB1_COMMAND_TREE_DISCONNECT: u8 = 0x71; -pub const SMB1_COMMAND_NEGOTIATE_PROTOCOL: u8 = 0x72; -pub const SMB1_COMMAND_SESSION_SETUP_ANDX: u8 = 0x73; -pub const SMB1_COMMAND_LOGOFF_ANDX: u8 = 0x74; -pub const SMB1_COMMAND_TREE_CONNECT_ANDX: u8 = 0x75; -pub const SMB1_COMMAND_QUERY_INFO_DISK: u8 = 0x80; -pub const SMB1_COMMAND_NT_TRANS: u8 = 0xa0; -pub const SMB1_COMMAND_NT_TRANS_SECONDARY: u8 = 0xa1; -pub const SMB1_COMMAND_NT_CREATE_ANDX: u8 = 0xa2; -pub const SMB1_COMMAND_NT_CANCEL: u8 = 0xa4; -pub const SMB1_COMMAND_NONE: u8 = 0xff; +pub const SMB1_COMMAND_CREATE_DIRECTORY: u8 = 0x00; +pub const SMB1_COMMAND_DELETE_DIRECTORY: u8 = 0x01; +pub const SMB1_COMMAND_OPEN: u8 = 0x02; +pub const SMB1_COMMAND_CREATE: u8 = 0x03; +pub const SMB1_COMMAND_CLOSE: u8 = 0x04; +pub const SMB1_COMMAND_FLUSH: u8 = 0x05; +pub const SMB1_COMMAND_DELETE: u8 = 0x06; +pub const SMB1_COMMAND_RENAME: u8 = 0x07; +pub const SMB1_COMMAND_QUERY_INFORMATION: u8 = 0x08; +pub const SMB1_COMMAND_SET_INFORMATION: u8 = 0x09; +pub const SMB1_COMMAND_READ: u8 = 0x0a; +pub const SMB1_COMMAND_WRITE: u8 = 0x0b; +pub const SMB1_COMMAND_LOCK_BYTE_RANGE: u8 = 0x0c; +pub const SMB1_COMMAND_UNLOCK_BYTE_RANGE: u8 = 0x0d; +pub const SMB1_COMMAND_CREATE_TEMPORARY: u8 = 0x0e; +pub const SMB1_COMMAND_CREATE_NEW: u8 = 0x0f; +pub const SMB1_COMMAND_CHECK_DIRECTORY: u8 = 0x10; +pub const SMB1_COMMAND_PROCESS_EXIT: u8 = 0x11; +pub const SMB1_COMMAND_SEEK: u8 = 0x12; +pub const SMB1_COMMAND_LOCK_AND_READ: u8 = 0x13; +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_OPEN_ANDX: u8 = 0x2d; +pub const SMB1_COMMAND_READ_ANDX: u8 = 0x2e; +pub const SMB1_COMMAND_WRITE_ANDX: u8 = 0x2f; +pub const SMB1_COMMAND_TRANS2: u8 = 0x32; +pub const SMB1_COMMAND_TRANS2_SECONDARY: u8 = 0x33; +pub const SMB1_COMMAND_FIND_CLOSE2: u8 = 0x34; +pub const SMB1_COMMAND_TREE_DISCONNECT: u8 = 0x71; +pub const SMB1_COMMAND_NEGOTIATE_PROTOCOL: u8 = 0x72; +pub const SMB1_COMMAND_SESSION_SETUP_ANDX: u8 = 0x73; +pub const SMB1_COMMAND_LOGOFF_ANDX: u8 = 0x74; +pub const SMB1_COMMAND_TREE_CONNECT_ANDX: u8 = 0x75; +pub const SMB1_COMMAND_QUERY_INFO_DISK: u8 = 0x80; +pub const SMB1_COMMAND_NT_TRANS: u8 = 0xa0; +pub const SMB1_COMMAND_NT_TRANS_SECONDARY: u8 = 0xa1; +pub const SMB1_COMMAND_NT_CREATE_ANDX: u8 = 0xa2; +pub const SMB1_COMMAND_NT_CANCEL: u8 = 0xa4; +pub const SMB1_COMMAND_NONE: u8 = 0xff; pub fn smb1_command_string(c: u8) -> String { match c { - SMB1_COMMAND_CREATE_DIRECTORY => "SMB1_COMMAND_CREATE_DIRECTORY", - SMB1_COMMAND_DELETE_DIRECTORY => "SMB1_COMMAND_DELETE_DIRECTORY", - SMB1_COMMAND_OPEN => "SMB1_COMMAND_OPEN", - SMB1_COMMAND_CREATE => "SMB1_COMMAND_CREATE", - SMB1_COMMAND_CLOSE => "SMB1_COMMAND_CLOSE", - SMB1_COMMAND_FLUSH => "SMB1_COMMAND_FLUSH", - SMB1_COMMAND_DELETE => "SMB1_COMMAND_DELETE", - SMB1_COMMAND_RENAME => "SMB1_COMMAND_RENAME", - SMB1_COMMAND_QUERY_INFORMATION => "SMB1_COMMAND_QUERY_INFORMATION", - SMB1_COMMAND_SET_INFORMATION => "SMB1_COMMAND_SET_INFORMATION", - SMB1_COMMAND_READ => "SMB1_COMMAND_READ", - SMB1_COMMAND_WRITE => "SMB1_COMMAND_WRITE", - SMB1_COMMAND_LOCK_BYTE_RANGE => "SMB1_COMMAND_LOCK_BYTE_RANGE", - SMB1_COMMAND_UNLOCK_BYTE_RANGE => "SMB1_COMMAND_UNLOCK_BYTE_RANGE", - SMB1_COMMAND_CREATE_TEMPORARY => "SMB1_COMMAND_CREATE_TEMPORARY", - SMB1_COMMAND_CREATE_NEW => "SMB1_COMMAND_CREATE_NEW", - SMB1_COMMAND_CHECK_DIRECTORY => "SMB1_COMMAND_CHECK_DIRECTORY", - SMB1_COMMAND_PROCESS_EXIT => "SMB1_COMMAND_PROCESS_EXIT", - SMB1_COMMAND_SEEK => "SMB1_COMMAND_SEEK", - SMB1_COMMAND_LOCK_AND_READ => "SMB1_COMMAND_LOCK_AND_READ", - 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_OPEN_ANDX => "SMB1_COMMAND_OPEN_ANDX", - SMB1_COMMAND_READ_ANDX => "SMB1_COMMAND_READ_ANDX", - SMB1_COMMAND_WRITE_ANDX => "SMB1_COMMAND_WRITE_ANDX", - SMB1_COMMAND_TRANS => "SMB1_COMMAND_TRANS", - SMB1_COMMAND_TRANS2 => "SMB1_COMMAND_TRANS2", - SMB1_COMMAND_TRANS2_SECONDARY => "SMB1_COMMAND_TRANS2_SECONDARY", - SMB1_COMMAND_FIND_CLOSE2 => "SMB1_COMMAND_FIND_CLOSE2", - SMB1_COMMAND_TREE_DISCONNECT => "SMB1_COMMAND_TREE_DISCONNECT", + SMB1_COMMAND_CREATE_DIRECTORY => "SMB1_COMMAND_CREATE_DIRECTORY", + SMB1_COMMAND_DELETE_DIRECTORY => "SMB1_COMMAND_DELETE_DIRECTORY", + SMB1_COMMAND_OPEN => "SMB1_COMMAND_OPEN", + SMB1_COMMAND_CREATE => "SMB1_COMMAND_CREATE", + SMB1_COMMAND_CLOSE => "SMB1_COMMAND_CLOSE", + SMB1_COMMAND_FLUSH => "SMB1_COMMAND_FLUSH", + SMB1_COMMAND_DELETE => "SMB1_COMMAND_DELETE", + SMB1_COMMAND_RENAME => "SMB1_COMMAND_RENAME", + SMB1_COMMAND_QUERY_INFORMATION => "SMB1_COMMAND_QUERY_INFORMATION", + SMB1_COMMAND_SET_INFORMATION => "SMB1_COMMAND_SET_INFORMATION", + SMB1_COMMAND_READ => "SMB1_COMMAND_READ", + SMB1_COMMAND_WRITE => "SMB1_COMMAND_WRITE", + SMB1_COMMAND_LOCK_BYTE_RANGE => "SMB1_COMMAND_LOCK_BYTE_RANGE", + SMB1_COMMAND_UNLOCK_BYTE_RANGE => "SMB1_COMMAND_UNLOCK_BYTE_RANGE", + SMB1_COMMAND_CREATE_TEMPORARY => "SMB1_COMMAND_CREATE_TEMPORARY", + SMB1_COMMAND_CREATE_NEW => "SMB1_COMMAND_CREATE_NEW", + SMB1_COMMAND_CHECK_DIRECTORY => "SMB1_COMMAND_CHECK_DIRECTORY", + SMB1_COMMAND_PROCESS_EXIT => "SMB1_COMMAND_PROCESS_EXIT", + SMB1_COMMAND_SEEK => "SMB1_COMMAND_SEEK", + SMB1_COMMAND_LOCK_AND_READ => "SMB1_COMMAND_LOCK_AND_READ", + 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_OPEN_ANDX => "SMB1_COMMAND_OPEN_ANDX", + SMB1_COMMAND_READ_ANDX => "SMB1_COMMAND_READ_ANDX", + SMB1_COMMAND_WRITE_ANDX => "SMB1_COMMAND_WRITE_ANDX", + SMB1_COMMAND_TRANS => "SMB1_COMMAND_TRANS", + SMB1_COMMAND_TRANS2 => "SMB1_COMMAND_TRANS2", + SMB1_COMMAND_TRANS2_SECONDARY => "SMB1_COMMAND_TRANS2_SECONDARY", + SMB1_COMMAND_FIND_CLOSE2 => "SMB1_COMMAND_FIND_CLOSE2", + SMB1_COMMAND_TREE_DISCONNECT => "SMB1_COMMAND_TREE_DISCONNECT", SMB1_COMMAND_NEGOTIATE_PROTOCOL => "SMB1_COMMAND_NEGOTIATE_PROTOCOL", SMB1_COMMAND_SESSION_SETUP_ANDX => "SMB1_COMMAND_SESSION_SETUP_ANDX", - SMB1_COMMAND_LOGOFF_ANDX => "SMB1_COMMAND_LOGOFF_ANDX", - SMB1_COMMAND_TREE_CONNECT_ANDX => "SMB1_COMMAND_TREE_CONNECT_ANDX", - SMB1_COMMAND_QUERY_INFO_DISK => "SMB1_COMMAND_QUERY_INFO_DISK", - SMB1_COMMAND_NT_TRANS => "SMB1_COMMAND_NT_TRANS", + SMB1_COMMAND_LOGOFF_ANDX => "SMB1_COMMAND_LOGOFF_ANDX", + SMB1_COMMAND_TREE_CONNECT_ANDX => "SMB1_COMMAND_TREE_CONNECT_ANDX", + SMB1_COMMAND_QUERY_INFO_DISK => "SMB1_COMMAND_QUERY_INFO_DISK", + SMB1_COMMAND_NT_TRANS => "SMB1_COMMAND_NT_TRANS", SMB1_COMMAND_NT_TRANS_SECONDARY => "SMB1_COMMAND_NT_TRANS_SECONDARY", - SMB1_COMMAND_NT_CREATE_ANDX => "SMB1_COMMAND_NT_CREATE_ANDX", - SMB1_COMMAND_NT_CANCEL => "SMB1_COMMAND_NT_CANCEL", - _ => { return (c).to_string(); }, - }.to_string() + SMB1_COMMAND_NT_CREATE_ANDX => "SMB1_COMMAND_NT_CREATE_ANDX", + SMB1_COMMAND_NT_CANCEL => "SMB1_COMMAND_NT_CANCEL", + _ => { + return (c).to_string(); + } + } + .to_string() } // later we'll use this to determine if we need to // track a ssn per type pub fn smb1_create_new_tx(cmd: u8) -> bool { match cmd { - SMB1_COMMAND_READ_ANDX | - SMB1_COMMAND_WRITE_ANDX | - SMB1_COMMAND_TRANS | - SMB1_COMMAND_TRANS2 => { false }, - _ => { true }, + SMB1_COMMAND_READ_ANDX + | SMB1_COMMAND_WRITE_ANDX + | SMB1_COMMAND_TRANS + | SMB1_COMMAND_TRANS2 => false, + _ => true, } } @@ -140,15 +143,12 @@ pub fn smb1_create_new_tx(cmd: u8) -> bool { // excludes the 'maybe' commands like TRANS2 pub fn smb1_check_tx(cmd: u8) -> bool { match cmd { - SMB1_COMMAND_READ_ANDX | - SMB1_COMMAND_WRITE_ANDX | - SMB1_COMMAND_TRANS => { false }, - _ => { true }, + SMB1_COMMAND_READ_ANDX | SMB1_COMMAND_WRITE_ANDX | SMB1_COMMAND_TRANS => false, + _ => true, } } -fn smb1_close_file(state: &mut SMBState, fid: &[u8], direction: Direction) -{ +fn smb1_close_file(state: &mut SMBState, fid: &[u8], direction: Direction) { if let Some(tx) = state.get_file_tx_by_fuid(fid, direction) { SCLogDebug!("found tx {}", tx.id); if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { @@ -165,14 +165,14 @@ fn smb1_close_file(state: &mut SMBState, fid: &[u8], direction: Direction) fn smb1_command_is_andx(c: u8) -> bool { match c { - SMB1_COMMAND_LOCKING_ANDX | - SMB1_COMMAND_OPEN_ANDX | - SMB1_COMMAND_READ_ANDX | - SMB1_COMMAND_SESSION_SETUP_ANDX | - SMB1_COMMAND_LOGOFF_ANDX | - SMB1_COMMAND_TREE_CONNECT_ANDX | - SMB1_COMMAND_NT_CREATE_ANDX | - SMB1_COMMAND_WRITE_ANDX => { + SMB1_COMMAND_LOCKING_ANDX + | SMB1_COMMAND_OPEN_ANDX + | SMB1_COMMAND_READ_ANDX + | SMB1_COMMAND_SESSION_SETUP_ANDX + | SMB1_COMMAND_LOGOFF_ANDX + | SMB1_COMMAND_TREE_CONNECT_ANDX + | SMB1_COMMAND_NT_CREATE_ANDX + | SMB1_COMMAND_WRITE_ANDX => { return true; } _ => { @@ -181,32 +181,32 @@ fn smb1_command_is_andx(c: u8) -> bool { } } -fn smb1_request_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, andx_offset: &mut usize) { - let mut events : Vec = Vec::new(); +fn smb1_request_record_one( + state: &mut SMBState, r: &SmbRecord, command: u8, andx_offset: &mut usize, +) { + let mut events: Vec = Vec::new(); let mut no_response_expected = false; let have_tx = match command { - SMB1_COMMAND_RENAME => { - match parse_smb_rename_request_record(r.data) { - Ok((_, rd)) => { - SCLogDebug!("RENAME {:?}", rd); + SMB1_COMMAND_RENAME => match parse_smb_rename_request_record(r.data) { + Ok((_, rd)) => { + SCLogDebug!("RENAME {:?}", rd); - let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); - let mut newname = rd.newname; - newname.retain(|&i|i != 0x00); - let mut oldname = rd.oldname; - oldname.retain(|&i|i != 0x00); + let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); + let mut newname = rd.newname; + newname.retain(|&i| i != 0x00); + let mut oldname = rd.oldname; + oldname.retain(|&i| i != 0x00); - let tx = state.new_rename_tx(Vec::new(), oldname, newname); - tx.hdr = tx_hdr; - tx.request_done = true; - tx.vercmd.set_smb1_cmd(SMB1_COMMAND_RENAME); - true - }, - _ => { - events.push(SMBEvent::MalformedData); - false - }, + let tx = state.new_rename_tx(Vec::new(), oldname, newname); + tx.hdr = tx_hdr; + tx.request_done = true; + tx.vercmd.set_smb1_cmd(SMB1_COMMAND_RENAME); + true + } + _ => { + events.push(SMBEvent::MalformedData); + false } }, SMB1_COMMAND_TRANS2 => { @@ -220,75 +220,97 @@ fn smb1_request_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, and Ok((_, pd)) => { SCLogDebug!("TRANS2 SET_PATH_INFO PARAMS DONE {:?}", pd); - if pd.loi == 1013 { // set disposition info - match parse_trans2_request_data_set_file_info_disposition(rd.data_blob) { + if pd.loi == 1013 { + // set disposition info + match parse_trans2_request_data_set_file_info_disposition( + rd.data_blob, + ) { Ok((_, disp)) => { - SCLogDebug!("TRANS2 SET_FILE_INFO DATA DISPOSITION DONE {:?}", disp); - let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); - - let tx = state.new_setpathinfo_tx(pd.oldname, - rd.subcmd, pd.loi, disp.delete); + SCLogDebug!( + "TRANS2 SET_FILE_INFO DATA DISPOSITION DONE {:?}", + disp + ); + let tx_hdr = + SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); + + let tx = state.new_setpathinfo_tx( + pd.oldname, + rd.subcmd, + pd.loi, + disp.delete, + ); tx.hdr = tx_hdr; tx.request_done = true; tx.vercmd.set_smb1_cmd(SMB1_COMMAND_TRANS2); true - - }, + } Err(Err::Incomplete(_n)) => { SCLogDebug!("TRANS2 SET_FILE_INFO DATA DISPOSITION INCOMPLETE {:?}", _n); events.push(SMBEvent::MalformedData); false - }, - Err(Err::Error(_e)) | - Err(Err::Failure(_e)) => { - SCLogDebug!("TRANS2 SET_FILE_INFO DATA DISPOSITION ERROR {:?}", _e); + } + Err(Err::Error(_e)) | Err(Err::Failure(_e)) => { + SCLogDebug!( + "TRANS2 SET_FILE_INFO DATA DISPOSITION ERROR {:?}", + _e + ); events.push(SMBEvent::MalformedData); false - }, + } } } else if pd.loi == 1010 { - match parse_trans2_request_data_set_path_info_rename(rd.data_blob) { + match parse_trans2_request_data_set_path_info_rename( + rd.data_blob, + ) { Ok((_, ren)) => { - SCLogDebug!("TRANS2 SET_PATH_INFO DATA RENAME DONE {:?}", ren); - let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); + SCLogDebug!( + "TRANS2 SET_PATH_INFO DATA RENAME DONE {:?}", + ren + ); + let tx_hdr = + SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); let mut newname = ren.newname.to_vec(); - newname.retain(|&i|i != 0x00); + newname.retain(|&i| i != 0x00); - let fid : Vec = Vec::new(); + let fid: Vec = Vec::new(); let tx = state.new_rename_tx(fid, pd.oldname, newname); tx.hdr = tx_hdr; tx.request_done = true; tx.vercmd.set_smb1_cmd(SMB1_COMMAND_TRANS2); true - }, + } Err(Err::Incomplete(_n)) => { - SCLogDebug!("TRANS2 SET_PATH_INFO DATA RENAME INCOMPLETE {:?}", _n); + SCLogDebug!( + "TRANS2 SET_PATH_INFO DATA RENAME INCOMPLETE {:?}", + _n + ); events.push(SMBEvent::MalformedData); false - }, - Err(Err::Error(_e)) | - Err(Err::Failure(_e)) => { - SCLogDebug!("TRANS2 SET_PATH_INFO DATA RENAME ERROR {:?}", _e); + } + Err(Err::Error(_e)) | Err(Err::Failure(_e)) => { + SCLogDebug!( + "TRANS2 SET_PATH_INFO DATA RENAME ERROR {:?}", + _e + ); events.push(SMBEvent::MalformedData); false - }, + } } } else { false } - }, + } Err(Err::Incomplete(_n)) => { SCLogDebug!("TRANS2 SET_PATH_INFO PARAMS INCOMPLETE {:?}", _n); events.push(SMBEvent::MalformedData); false - }, - Err(Err::Error(_e)) | - Err(Err::Failure(_e)) => { + } + Err(Err::Error(_e)) | Err(Err::Failure(_e)) => { SCLogDebug!("TRANS2 SET_PATH_INFO PARAMS ERROR {:?}", _e); events.push(SMBEvent::MalformedData); false - }, + } } } else if rd.subcmd == 8 { SCLogDebug!("SET_FILE_INFO"); @@ -296,107 +318,135 @@ fn smb1_request_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, and Ok((_, pd)) => { SCLogDebug!("TRANS2 SET_FILE_INFO PARAMS DONE {:?}", pd); - if pd.loi == 1013 { // set disposition info - match parse_trans2_request_data_set_file_info_disposition(rd.data_blob) { + if pd.loi == 1013 { + // set disposition info + match parse_trans2_request_data_set_file_info_disposition( + rd.data_blob, + ) { Ok((_, disp)) => { - SCLogDebug!("TRANS2 SET_FILE_INFO DATA DISPOSITION DONE {:?}", disp); - let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); + SCLogDebug!( + "TRANS2 SET_FILE_INFO DATA DISPOSITION DONE {:?}", + disp + ); + let tx_hdr = + SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); let mut frankenfid = pd.fid.to_vec(); frankenfid.extend_from_slice(&r.ssn_id.to_be_bytes()); - let filename = match state.guid2name_cache.get(&frankenfid) { - Some(n) => n.to_vec(), - None => b"".to_vec(), - }; - let tx = state.new_setfileinfo_tx(filename, pd.fid.to_vec(), - rd.subcmd, pd.loi, disp.delete); + let filename = + match state.guid2name_cache.get(&frankenfid) { + Some(n) => n.to_vec(), + None => b"".to_vec(), + }; + let tx = state.new_setfileinfo_tx( + filename, + pd.fid.to_vec(), + rd.subcmd, + pd.loi, + disp.delete, + ); tx.hdr = tx_hdr; tx.request_done = true; tx.vercmd.set_smb1_cmd(SMB1_COMMAND_TRANS2); true - - }, + } Err(Err::Incomplete(_n)) => { SCLogDebug!("TRANS2 SET_FILE_INFO DATA DISPOSITION INCOMPLETE {:?}", _n); events.push(SMBEvent::MalformedData); false - }, - Err(Err::Error(_e)) | - Err(Err::Failure(_e)) => { - SCLogDebug!("TRANS2 SET_FILE_INFO DATA DISPOSITION ERROR {:?}", _e); + } + Err(Err::Error(_e)) | Err(Err::Failure(_e)) => { + SCLogDebug!( + "TRANS2 SET_FILE_INFO DATA DISPOSITION ERROR {:?}", + _e + ); events.push(SMBEvent::MalformedData); false - }, + } } } else if pd.loi == 1010 { - match parse_trans2_request_data_set_file_info_rename(rd.data_blob) { + match parse_trans2_request_data_set_file_info_rename( + rd.data_blob, + ) { Ok((_, ren)) => { - SCLogDebug!("TRANS2 SET_FILE_INFO DATA RENAME DONE {:?}", ren); - let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); + SCLogDebug!( + "TRANS2 SET_FILE_INFO DATA RENAME DONE {:?}", + ren + ); + let tx_hdr = + SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); let mut newname = ren.newname.to_vec(); - newname.retain(|&i|i != 0x00); + newname.retain(|&i| i != 0x00); let mut frankenfid = pd.fid.to_vec(); frankenfid.extend_from_slice(&r.ssn_id.to_be_bytes()); - let oldname = match state.guid2name_cache.get(&frankenfid) { - Some(n) => n.to_vec(), - None => b"".to_vec(), - }; - let tx = state.new_rename_tx(pd.fid.to_vec(), oldname, newname); + let oldname = + match state.guid2name_cache.get(&frankenfid) { + Some(n) => n.to_vec(), + None => b"".to_vec(), + }; + let tx = state.new_rename_tx( + pd.fid.to_vec(), + oldname, + newname, + ); tx.hdr = tx_hdr; tx.request_done = true; tx.vercmd.set_smb1_cmd(SMB1_COMMAND_TRANS2); true - }, + } Err(Err::Incomplete(_n)) => { - SCLogDebug!("TRANS2 SET_FILE_INFO DATA RENAME INCOMPLETE {:?}", _n); + SCLogDebug!( + "TRANS2 SET_FILE_INFO DATA RENAME INCOMPLETE {:?}", + _n + ); events.push(SMBEvent::MalformedData); false - }, - Err(Err::Error(_e)) | - Err(Err::Failure(_e)) => { - SCLogDebug!("TRANS2 SET_FILE_INFO DATA RENAME ERROR {:?}", _e); + } + Err(Err::Error(_e)) | Err(Err::Failure(_e)) => { + SCLogDebug!( + "TRANS2 SET_FILE_INFO DATA RENAME ERROR {:?}", + _e + ); events.push(SMBEvent::MalformedData); false - }, + } } } else { false } - }, + } Err(Err::Incomplete(_n)) => { SCLogDebug!("TRANS2 SET_FILE_INFO PARAMS INCOMPLETE {:?}", _n); events.push(SMBEvent::MalformedData); false - }, - Err(Err::Error(_e)) | - Err(Err::Failure(_e)) => { + } + Err(Err::Error(_e)) | Err(Err::Failure(_e)) => { SCLogDebug!("TRANS2 SET_FILE_INFO PARAMS ERROR {:?}", _e); events.push(SMBEvent::MalformedData); false - }, + } } } else { false } - }, + } Err(Err::Incomplete(_n)) => { SCLogDebug!("TRANS2 INCOMPLETE {:?}", _n); events.push(SMBEvent::MalformedData); false - }, - Err(Err::Error(_e)) | - Err(Err::Failure(_e)) => { + } + Err(Err::Error(_e)) | Err(Err::Failure(_e)) => { SCLogDebug!("TRANS2 ERROR {:?}", _e); events.push(SMBEvent::MalformedData); false - }, + } } - }, + } SMB1_COMMAND_READ_ANDX => { - match parse_smb_read_andx_request_record(&r.data[*andx_offset-SMB1_HEADER_SIZE..]) { + match parse_smb_read_andx_request_record(&r.data[*andx_offset - SMB1_HEADER_SIZE..]) { Ok((_, rr)) => { SCLogDebug!("rr {:?}", rr); @@ -406,70 +456,69 @@ fn smb1_request_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, and fid.extend_from_slice(&r.ssn_id.to_be_bytes()); let fidoff = SMBFileGUIDOffset::new(fid, rr.offset); state.read_offset_cache.put(fid_key, fidoff); - }, + } _ => { events.push(SMBEvent::MalformedData); - }, + } } false - }, - SMB1_COMMAND_WRITE_ANDX | - SMB1_COMMAND_WRITE | - SMB1_COMMAND_WRITE_AND_CLOSE => { + } + SMB1_COMMAND_WRITE_ANDX | SMB1_COMMAND_WRITE | SMB1_COMMAND_WRITE_AND_CLOSE => { smb1_write_request_record(state, r, *andx_offset, command, 0); true // tx handling in func - }, + } SMB1_COMMAND_TRANS => { smb1_trans_request_record(state, r); true - }, - SMB1_COMMAND_NEGOTIATE_PROTOCOL => { - match parse_smb1_negotiate_protocol_record(r.data) { - Ok((_, pr)) => { - SCLogDebug!("SMB_COMMAND_NEGOTIATE_PROTOCOL {:?}", pr); - - let mut bad_dialects = false; - let mut dialects : Vec> = Vec::new(); - for d in &pr.dialects { - if d.is_empty() { - bad_dialects = true; - continue; - } else if d.len() == 1 { - bad_dialects = true; - } - let x = &d[1..d.len()]; - let dvec = x.to_vec(); - dialects.push(dvec); + } + SMB1_COMMAND_NEGOTIATE_PROTOCOL => match parse_smb1_negotiate_protocol_record(r.data) { + Ok((_, pr)) => { + SCLogDebug!("SMB_COMMAND_NEGOTIATE_PROTOCOL {:?}", pr); + + let mut bad_dialects = false; + let mut dialects: Vec> = Vec::new(); + for d in &pr.dialects { + if d.is_empty() { + bad_dialects = true; + continue; + } else if d.len() == 1 { + bad_dialects = true; } + let x = &d[1..d.len()]; + let dvec = x.to_vec(); + dialects.push(dvec); + } - let found = match state.get_negotiate_tx(1) { - Some(tx) => { - SCLogDebug!("WEIRD, should not have NEGOTIATE tx!"); - tx.set_event(SMBEvent::DuplicateNegotiate); - true - }, - None => { false }, - }; - if !found { - let tx = state.new_negotiate_tx(1); - if let Some(SMBTransactionTypeData::NEGOTIATE(ref mut tdn)) = tx.type_data { - tdn.dialects = dialects; - } - tx.request_done = true; - if bad_dialects { - tx.set_event(SMBEvent::NegotiateMalformedDialects); - } + let found = match state.get_negotiate_tx(1) { + Some(tx) => { + SCLogDebug!("WEIRD, should not have NEGOTIATE tx!"); + tx.set_event(SMBEvent::DuplicateNegotiate); + true } - true - }, - _ => { - events.push(SMBEvent::MalformedData); - false - }, + None => false, + }; + if !found { + let tx = state.new_negotiate_tx(1); + if let Some(SMBTransactionTypeData::NEGOTIATE(ref mut tdn)) = tx.type_data { + tdn.dialects = dialects; + } + tx.request_done = true; + if bad_dialects { + tx.set_event(SMBEvent::NegotiateMalformedDialects); + } + } + true + } + _ => { + events.push(SMBEvent::MalformedData); + false } }, SMB1_COMMAND_NT_CREATE_ANDX => { - match parse_smb_create_andx_request_record(&r.data[*andx_offset-SMB1_HEADER_SIZE..], r) { + match parse_smb_create_andx_request_record( + &r.data[*andx_offset - SMB1_HEADER_SIZE..], + r, + ) { Ok((_, cr)) => { SCLogDebug!("Create AndX {:?}", cr); let del = cr.create_options & 0x0000_1000 != 0; @@ -481,26 +530,26 @@ fn smb1_request_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, and state.ssn2vec_cache.put(name_key, name_val); let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); - let tx = state.new_create_tx(&cr.file_name, - cr.disposition, del, dir, tx_hdr); + let tx = state.new_create_tx(&cr.file_name, cr.disposition, del, dir, tx_hdr); tx.vercmd.set_smb1_cmd(command); SCLogDebug!("TS CREATE TX {} created", tx.id); true - }, + } _ => { events.push(SMBEvent::MalformedData); false - }, + } } - }, + } SMB1_COMMAND_SESSION_SETUP_ANDX => { SCLogDebug!("SMB1_COMMAND_SESSION_SETUP_ANDX user_id {}", r.user_id); smb1_session_setup_request(state, r, *andx_offset); true - }, + } SMB1_COMMAND_TREE_CONNECT_ANDX => { SCLogDebug!("SMB1_COMMAND_TREE_CONNECT_ANDX"); - match parse_smb_connect_tree_andx_record(&r.data[*andx_offset-SMB1_HEADER_SIZE..], r) { + match parse_smb_connect_tree_andx_record(&r.data[*andx_offset - SMB1_HEADER_SIZE..], r) + { Ok((_, tr)) => { let name_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_TREE); let mut name_val = tr.path; @@ -517,18 +566,18 @@ fn smb1_request_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, and tx.request_done = true; tx.vercmd.set_smb1_cmd(SMB1_COMMAND_TREE_CONNECT_ANDX); true - }, + } _ => { events.push(SMBEvent::MalformedData); false - }, + } } - }, + } SMB1_COMMAND_TREE_DISCONNECT => { let tree_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_SHARE); state.ssn2tree_cache.pop(&tree_key); false - }, + } SMB1_COMMAND_CLOSE => { match parse_smb1_close_request_record(r.data) { Ok((_, cd)) => { @@ -536,44 +585,53 @@ fn smb1_request_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, and fid.extend_from_slice(&r.ssn_id.to_be_bytes()); let _name = state.guid2name_cache.pop(&fid); - state.ssn2vec_cache.put(SMBCommonHdr::from1(r, SMBHDR_TYPE_GUID), fid.to_vec()); + state + .ssn2vec_cache + .put(SMBCommonHdr::from1(r, SMBHDR_TYPE_GUID), fid.to_vec()); SCLogDebug!("closing FID {:?}/{:?}", cd.fid, fid); smb1_close_file(state, &fid, Direction::ToServer); - }, + } _ => { events.push(SMBEvent::MalformedData); - }, + } } false - }, - SMB1_COMMAND_NT_CANCEL | - SMB1_COMMAND_TRANS2_SECONDARY | - SMB1_COMMAND_LOCKING_ANDX => { + } + SMB1_COMMAND_NT_CANCEL | SMB1_COMMAND_TRANS2_SECONDARY | SMB1_COMMAND_LOCKING_ANDX => { no_response_expected = true; false - }, + } _ => { - if command == SMB1_COMMAND_LOGOFF_ANDX || - command == SMB1_COMMAND_TREE_DISCONNECT || - command == SMB1_COMMAND_NT_TRANS || - command == SMB1_COMMAND_NT_TRANS_SECONDARY || - command == SMB1_COMMAND_NT_CANCEL || - command == SMB1_COMMAND_RENAME || - command == SMB1_COMMAND_CHECK_DIRECTORY || - command == SMB1_COMMAND_ECHO || - command == SMB1_COMMAND_TRANS - { } else { - SCLogDebug!("unsupported command {}/{}", - command, &smb1_command_string(command)); + if command == SMB1_COMMAND_LOGOFF_ANDX + || command == SMB1_COMMAND_TREE_DISCONNECT + || command == SMB1_COMMAND_NT_TRANS + || command == SMB1_COMMAND_NT_TRANS_SECONDARY + || command == SMB1_COMMAND_NT_CANCEL + || command == SMB1_COMMAND_RENAME + || command == SMB1_COMMAND_CHECK_DIRECTORY + || command == SMB1_COMMAND_ECHO + || command == SMB1_COMMAND_TRANS + { + } else { + SCLogDebug!( + "unsupported command {}/{}", + command, + &smb1_command_string(command) + ); } false - }, + } }; if !have_tx && smb1_create_new_tx(command) { let tx_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); let tx = state.new_generic_tx(1, command as u16, tx_key); - SCLogDebug!("tx {} created for {}/{}", tx.id, command, &smb1_command_string(command)); + SCLogDebug!( + "tx {} created for {}/{}", + tx.id, + command, + &smb1_command_string(command) + ); tx.set_events(events); if no_response_expected { tx.response_done = true; @@ -591,10 +649,13 @@ pub fn smb1_request_record(state: &mut SMBState, r: &SmbRecord) -> u32 { // continue for next andx command if any if smb1_command_is_andx(command) { - if let Ok((_, andx_hdr)) = smb1_parse_andx_header(&r.data[andx_offset-SMB1_HEADER_SIZE..]) { - if (andx_hdr.andx_offset as usize) > andx_offset && - andx_hdr.andx_command != SMB1_COMMAND_NONE && - (andx_hdr.andx_offset as usize) - SMB1_HEADER_SIZE < r.data.len() { + if let Ok((_, andx_hdr)) = + smb1_parse_andx_header(&r.data[andx_offset - SMB1_HEADER_SIZE..]) + { + if (andx_hdr.andx_offset as usize) > andx_offset + && andx_hdr.andx_command != SMB1_COMMAND_NONE + && (andx_hdr.andx_offset as usize) - SMB1_HEADER_SIZE < r.data.len() + { andx_offset = andx_hdr.andx_offset as usize; command = andx_hdr.andx_command; continue; @@ -607,20 +668,27 @@ pub fn smb1_request_record(state: &mut SMBState, r: &SmbRecord) -> u32 { 0 } -fn smb1_response_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, andx_offset: &mut usize) { - SCLogDebug!("record: command {} status {} -> {:?}", r.command, r.nt_status, r); +fn smb1_response_record_one( + state: &mut SMBState, r: &SmbRecord, command: u8, andx_offset: &mut usize, +) { + SCLogDebug!( + "record: command {} status {} -> {:?}", + r.command, + r.nt_status, + r + ); let key_ssn_id = r.ssn_id; let key_tree_id = r.tree_id; let key_multiplex_id = r.multiplex_id; let mut tx_sync = false; - let mut events : Vec = Vec::new(); + let mut events: Vec = Vec::new(); let have_tx = match command { SMB1_COMMAND_READ_ANDX => { smb1_read_response_record(state, r, *andx_offset, 0); true // tx handling in func - }, + } SMB1_COMMAND_NEGOTIATE_PROTOCOL => { SCLogDebug!("SMB1_COMMAND_NEGOTIATE_PROTOCOL response"); match parse_smb1_negotiate_protocol_response_record(r.data) { @@ -641,28 +709,28 @@ fn smb1_response_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, an let d = x.dialects[dialect_idx].to_vec(); Some(d) } - }, - _ => { None }, + } + _ => None, }; if d.is_none() { tx.set_event(SMBEvent::NegotiateMalformedDialects); } (true, d) - }, - None => { (false, None) }, + } + None => (false, None), }; if let Some(d) = dialect { SCLogDebug!("dialect {:?}", d); state.dialect_vec = Some(d); } have_ntx - }, + } _ => { events.push(SMBEvent::MalformedData); false - }, + } } - }, + } SMB1_COMMAND_TREE_CONNECT_ANDX => { if r.nt_status != SMB_NTSTATUS_SUCCESS { let name_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_TREE); @@ -677,14 +745,18 @@ fn smb1_response_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, an return; } - match parse_smb_connect_tree_andx_response_record(&r.data[*andx_offset-SMB1_HEADER_SIZE..]) { + match parse_smb_connect_tree_andx_response_record( + &r.data[*andx_offset - SMB1_HEADER_SIZE..], + ) { Ok((_, tr)) => { let name_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_TREE); let is_pipe = tr.service == "IPC".as_bytes(); let mut share_name = Vec::new(); let found = match state.get_treeconnect_tx(name_key) { Some(tx) => { - if let Some(SMBTransactionTypeData::TREECONNECT(ref mut tdn)) = tx.type_data { + if let Some(SMBTransactionTypeData::TREECONNECT(ref mut tdn)) = + tx.type_data + { tdn.is_pipe = is_pipe; tdn.tree_id = r.tree_id as u32; share_name = tdn.share_name.to_vec(); @@ -695,8 +767,8 @@ fn smb1_response_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, an tx.response_done = true; SCLogDebug!("tx {} is done", tx.id); true - }, - None => { false }, + } + None => false, }; if found { let tree = SMBTree::new(share_name.to_vec(), is_pipe); @@ -704,28 +776,29 @@ fn smb1_response_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, an state.ssn2tree_cache.put(tree_key, tree); } found - }, + } _ => { events.push(SMBEvent::MalformedData); false - }, + } } - }, + } SMB1_COMMAND_TREE_DISCONNECT => { // normally removed when processing request, // but in case we missed that try again here let tree_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_SHARE); state.ssn2tree_cache.pop(&tree_key); false - }, + } SMB1_COMMAND_NT_CREATE_ANDX if r.nt_status == SMB_NTSTATUS_SUCCESS => { - match parse_smb_create_andx_response_record(&r.data[*andx_offset-SMB1_HEADER_SIZE..]) { + match parse_smb_create_andx_response_record(&r.data[*andx_offset - SMB1_HEADER_SIZE..]) + { Ok((_, cr)) => { SCLogDebug!("Create AndX {:?}", cr); let guid_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_FILENAME); if let Some(mut p) = state.ssn2vec_cache.pop(&guid_key) { - p.retain(|&i|i != 0x00); + p.retain(|&i| i != 0x00); let mut fid = cr.fid.to_vec(); fid.extend_from_slice(&r.ssn_id.to_be_bytes()); @@ -738,8 +811,12 @@ fn smb1_response_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, an let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); if let Some(tx) = state.get_generic_tx(1, command as u16, &tx_hdr) { - SCLogDebug!("tx {} with {}/{} marked as done", - tx.id, command, &smb1_command_string(command)); + SCLogDebug!( + "tx {} with {}/{} marked as done", + tx.id, + command, + &smb1_command_string(command) + ); tx.set_status(r.nt_status, false); tx.response_done = true; @@ -753,36 +830,36 @@ fn smb1_response_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, an } } true - }, + } _ => { events.push(SMBEvent::MalformedData); false - }, + } } - }, + } SMB1_COMMAND_CLOSE => { - let fid = state.ssn2vec_cache.pop(&SMBCommonHdr::from1(r, SMBHDR_TYPE_GUID)); + let fid = state + .ssn2vec_cache + .pop(&SMBCommonHdr::from1(r, SMBHDR_TYPE_GUID)); if let Some(fid) = fid { SCLogDebug!("closing FID {:?}", fid); smb1_close_file(state, &fid, Direction::ToClient); } false - }, + } SMB1_COMMAND_TRANS => { smb1_trans_response_record(state, r); true - }, + } SMB1_COMMAND_SESSION_SETUP_ANDX => { smb1_session_setup_response(state, r, *andx_offset); true - }, + } SMB1_COMMAND_LOGOFF_ANDX => { tx_sync = true; false - }, - _ => { - false - }, + } + _ => false, }; if !have_tx && tx_sync { @@ -794,8 +871,12 @@ fn smb1_response_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, an tx.set_events(events); } } else if !have_tx && smb1_check_tx(command) { - let tx_key = SMBCommonHdr::new(SMBHDR_TYPE_GENERICTX, - key_ssn_id as u64, key_tree_id as u32, key_multiplex_id as u64); + let tx_key = SMBCommonHdr::new( + SMBHDR_TYPE_GENERICTX, + key_ssn_id as u64, + key_tree_id as u32, + key_multiplex_id as u64, + ); let _have_tx2 = match state.get_generic_tx(1, command as u16, &tx_key) { Some(tx) => { tx.request_done = true; @@ -804,11 +885,11 @@ fn smb1_response_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, an tx.set_status(r.nt_status, r.is_dos_error); tx.set_events(events); true - }, + } None => { SCLogDebug!("no TX found for key {:?}", tx_key); false - }, + } }; } else { SCLogDebug!("have tx for cmd {}", command); @@ -823,10 +904,13 @@ pub fn smb1_response_record(state: &mut SMBState, r: &SmbRecord) -> u32 { // continue for next andx command if any if smb1_command_is_andx(command) { - if let Ok((_, andx_hdr)) = smb1_parse_andx_header(&r.data[andx_offset-SMB1_HEADER_SIZE..]) { - if (andx_hdr.andx_offset as usize) > andx_offset && - andx_hdr.andx_command != SMB1_COMMAND_NONE && - (andx_hdr.andx_offset as usize) - SMB1_HEADER_SIZE < r.data.len() { + if let Ok((_, andx_hdr)) = + smb1_parse_andx_header(&r.data[andx_offset - SMB1_HEADER_SIZE..]) + { + if (andx_hdr.andx_offset as usize) > andx_offset + && andx_hdr.andx_command != SMB1_COMMAND_NONE + && (andx_hdr.andx_offset as usize) - SMB1_HEADER_SIZE < r.data.len() + { andx_offset = andx_hdr.andx_offset as usize; command = andx_hdr.andx_command; continue; @@ -839,9 +923,8 @@ pub fn smb1_response_record(state: &mut SMBState, r: &SmbRecord) -> u32 { 0 } -pub fn smb1_trans_request_record(state: &mut SMBState, r: &SmbRecord) -{ - let mut events : Vec = Vec::new(); +pub fn smb1_trans_request_record(state: &mut SMBState, r: &SmbRecord) { + let mut events: Vec = Vec::new(); match parse_smb_trans_request_record(r.data, r) { Ok((_, rd)) => { @@ -850,16 +933,20 @@ pub fn smb1_trans_request_record(state: &mut SMBState, r: &SmbRecord) /* if we have a fid, store it so the response can pick it up */ let mut pipe_dcerpc = false; if let Some(pipe) = rd.pipe { - state.ssn2vec_cache.put(SMBCommonHdr::from1(r, SMBHDR_TYPE_GUID), - pipe.fid.to_vec()); + state + .ssn2vec_cache + .put(SMBCommonHdr::from1(r, SMBHDR_TYPE_GUID), pipe.fid.to_vec()); let mut frankenfid = pipe.fid.to_vec(); frankenfid.extend_from_slice(&r.ssn_id.to_be_bytes()); let (_filename, is_dcerpc) = state.get_service_for_guid(&frankenfid); - SCLogDebug!("smb1_trans_request_record: name {} is_dcerpc {}", - _filename, is_dcerpc); + SCLogDebug!( + "smb1_trans_request_record: name {} is_dcerpc {}", + _filename, + is_dcerpc + ); pipe_dcerpc = is_dcerpc; } @@ -869,25 +956,26 @@ pub fn smb1_trans_request_record(state: &mut SMBState, r: &SmbRecord) let vercmd = SMBVerCmdStat::new1(r.command); smb_write_dcerpc_record(state, vercmd, hdr, rd.data.data); } - }, + } _ => { events.push(SMBEvent::MalformedData); - }, + } } smb1_request_record_generic(state, r, events); } -pub fn smb1_trans_response_record(state: &mut SMBState, r: &SmbRecord) -{ - let mut events : Vec = Vec::new(); +pub fn smb1_trans_response_record(state: &mut SMBState, r: &SmbRecord) { + let mut events: Vec = Vec::new(); match parse_smb_trans_response_record(r.data) { Ok((_, rd)) => { SCLogDebug!("TRANS response {:?}", rd); // see if we have a stored fid - let fid = state.ssn2vec_cache.pop( - &SMBCommonHdr::from1(r, SMBHDR_TYPE_GUID)).unwrap_or_default(); + let fid = state + .ssn2vec_cache + .pop(&SMBCommonHdr::from1(r, SMBHDR_TYPE_GUID)) + .unwrap_or_default(); SCLogDebug!("FID {:?}", fid); let mut frankenfid = fid.to_vec(); @@ -895,14 +983,22 @@ pub fn smb1_trans_response_record(state: &mut SMBState, r: &SmbRecord) let (_filename, is_dcerpc) = state.get_service_for_guid(&frankenfid); - SCLogDebug!("smb1_trans_response_record: name {} is_dcerpc {}", - _filename, is_dcerpc); + SCLogDebug!( + "smb1_trans_response_record: name {} is_dcerpc {}", + _filename, + is_dcerpc + ); // if we get status 'BUFFER_OVERFLOW' this is only a part of // the data. Store it in the ssn/tree for later use. if r.nt_status == SMB_NTSTATUS_BUFFER_OVERFLOW { - let key = SMBHashKeyHdrGuid::new(SMBCommonHdr::from1(r, SMBHDR_TYPE_TRANS_FRAG), fid); - SCLogDebug!("SMBv1/TRANS: queueing data for len {} key {:?}", rd.data.len(), key); + let key = + SMBHashKeyHdrGuid::new(SMBCommonHdr::from1(r, SMBHDR_TYPE_TRANS_FRAG), fid); + SCLogDebug!( + "SMBv1/TRANS: queueing data for len {} key {:?}", + rd.data.len(), + key + ); state.dcerpc_rec_frag_cache.put(key, rd.data.to_vec()); } else if is_dcerpc { SCLogDebug!("SMBv1 TRANS TO PIPE"); @@ -910,10 +1006,10 @@ pub fn smb1_trans_response_record(state: &mut SMBState, r: &SmbRecord) let vercmd = SMBVerCmdStat::new1_with_ntstatus(r.command, r.nt_status); smb_read_dcerpc_record(state, vercmd, hdr, &fid, rd.data); } - }, + } _ => { events.push(SMBEvent::MalformedData); - }, + } } // generic tx as well. Set events if needed. @@ -921,12 +1017,13 @@ pub fn smb1_trans_response_record(state: &mut SMBState, r: &SmbRecord) } /// Handle WRITE, WRITE_ANDX, WRITE_AND_CLOSE request records -pub fn smb1_write_request_record(state: &mut SMBState, r: &SmbRecord, andx_offset: usize, command: u8, nbss_remaining: u32) -{ - let mut events : Vec = Vec::new(); +pub fn smb1_write_request_record( + state: &mut SMBState, r: &SmbRecord, andx_offset: usize, command: u8, nbss_remaining: u32, +) { + let mut events: Vec = Vec::new(); let result = if command == SMB1_COMMAND_WRITE_ANDX { - parse_smb1_write_andx_request_record(&r.data[andx_offset-SMB1_HEADER_SIZE..], andx_offset) + parse_smb1_write_andx_request_record(&r.data[andx_offset - SMB1_HEADER_SIZE..], andx_offset) } else if command == SMB1_COMMAND_WRITE { parse_smb1_write_request_record(r.data) } else { @@ -944,30 +1041,36 @@ pub fn smb1_write_request_record(state: &mut SMBState, r: &SmbRecord, andx_offse } let mut file_fid = rd.fid.to_vec(); file_fid.extend_from_slice(&r.ssn_id.to_be_bytes()); - SCLogDebug!("SMBv1 WRITE: FID {:?} offset {}", - file_fid, rd.offset); + SCLogDebug!("SMBv1 WRITE: FID {:?} offset {}", file_fid, rd.offset); let file_name = match state.guid2name_cache.get(&file_fid) { Some(n) => n.to_vec(), None => b"".to_vec(), }; let mut set_event_fileoverlap = false; - let found = match state.get_file_tx_by_fuid_with_open_file(&file_fid, Direction::ToServer) { - Some(tx) => { - let file_id : u32 = tx.id as u32; - if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { - if rd.offset < tdf.file_tracker.tracked { - set_event_fileoverlap = true; + let found = + match state.get_file_tx_by_fuid_with_open_file(&file_fid, Direction::ToServer) { + Some(tx) => { + let file_id: u32 = tx.id as u32; + if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { + if rd.offset < tdf.file_tracker.tracked { + set_event_fileoverlap = true; + } + filetracker_newchunk( + &mut tdf.file_tracker, + &file_name, + rd.data, + rd.offset, + rd.len, + false, + &file_id, + ); + SCLogDebug!("FID {:?} found at tx {} => {:?}", file_fid, tx.id, tx); } - filetracker_newchunk(&mut tdf.file_tracker, - &file_name, rd.data, rd.offset, - rd.len, false, &file_id); - SCLogDebug!("FID {:?} found at tx {} => {:?}", file_fid, tx.id, tx); + true } - true - }, - None => { false }, - }; + None => false, + }; if !found { let tree_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_SHARE); let (share_name, is_pipe) = match state.ssn2tree_cache.get(&tree_key) { @@ -982,13 +1085,19 @@ pub fn smb1_write_request_record(state: &mut SMBState, r: &SmbRecord, andx_offse } else { let tx = state.new_file_tx(&file_fid, &file_name, Direction::ToServer); if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { - let file_id : u32 = tx.id as u32; + let file_id: u32 = tx.id as u32; if rd.offset < tdf.file_tracker.tracked { set_event_fileoverlap = true; } - filetracker_newchunk(&mut tdf.file_tracker, - &file_name, rd.data, rd.offset, - rd.len, false, &file_id); + filetracker_newchunk( + &mut tdf.file_tracker, + &file_name, + rd.data, + rd.offset, + rd.len, + false, + &file_id, + ); tdf.share_name = share_name; SCLogDebug!("tdf {:?}", tdf); } @@ -1000,27 +1109,33 @@ pub fn smb1_write_request_record(state: &mut SMBState, r: &SmbRecord, andx_offse state.set_event(SMBEvent::FileOverlap); } - state.set_file_left(Direction::ToServer, rd.len, rd.data.len() as u32, file_fid.to_vec()); + state.set_file_left( + Direction::ToServer, + rd.len, + rd.data.len() as u32, + file_fid.to_vec(), + ); if command == SMB1_COMMAND_WRITE_AND_CLOSE { let _name = state.guid2name_cache.pop(&file_fid); SCLogDebug!("closing FID {:?}", file_fid); smb1_close_file(state, &file_fid, Direction::ToServer); } - }, + } _ => { events.push(SMBEvent::MalformedData); - }, + } } smb1_request_record_generic(state, r, events); } -pub fn smb1_read_response_record(state: &mut SMBState, r: &SmbRecord, andx_offset: usize, nbss_remaining: u32) -{ - let mut events : Vec = Vec::new(); +pub fn smb1_read_response_record( + state: &mut SMBState, r: &SmbRecord, andx_offset: usize, nbss_remaining: u32, +) { + let mut events: Vec = Vec::new(); if r.nt_status == SMB_NTSTATUS_SUCCESS { - match parse_smb_read_andx_response_record(&r.data[andx_offset-SMB1_HEADER_SIZE..]) { + match parse_smb_read_andx_response_record(&r.data[andx_offset - SMB1_HEADER_SIZE..]) { Ok((_, rd)) => { SCLogDebug!("SMBv1: read response => {:?}", rd); if rd.len > nbss_remaining + rd.data.len() as u32 { @@ -1034,18 +1149,21 @@ pub fn smb1_read_response_record(state: &mut SMBState, r: &SmbRecord, andx_offse let (offset, file_fid) = match state.read_offset_cache.pop(&fid_key) { Some(o) => (o.offset, o.guid), None => { - SCLogDebug!("SMBv1 READ response: reply to unknown request: left {} {:?}", - rd.len - rd.data.len() as u32, rd); + SCLogDebug!( + "SMBv1 READ response: reply to unknown request: left {} {:?}", + rd.len - rd.data.len() as u32, + rd + ); state.set_skip(Direction::ToClient, nbss_remaining); return; - }, + } }; SCLogDebug!("SMBv1 READ: FID {:?} offset {}", file_fid, offset); let tree_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_SHARE); let (is_pipe, share_name) = match state.ssn2tree_cache.get(&tree_key) { Some(n) => (n.is_pipe, n.name.to_vec()), - _ => { (false, Vec::new()) }, + _ => (false, Vec::new()), }; if !is_pipe { let file_name = match state.guid2name_cache.get(&file_fid) { @@ -1053,33 +1171,47 @@ pub fn smb1_read_response_record(state: &mut SMBState, r: &SmbRecord, andx_offse None => Vec::new(), }; let mut set_event_fileoverlap = false; - let found = match state.get_file_tx_by_fuid_with_open_file(&file_fid, Direction::ToClient) { + let found = match state + .get_file_tx_by_fuid_with_open_file(&file_fid, Direction::ToClient) + { Some(tx) => { if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { - let file_id : u32 = tx.id as u32; + let file_id: u32 = tx.id as u32; SCLogDebug!("FID {:?} found at tx {}", file_fid, tx.id); if offset < tdf.file_tracker.tracked { set_event_fileoverlap = true; } - filetracker_newchunk(&mut tdf.file_tracker, - &file_name, rd.data, offset, - rd.len, false, &file_id); + filetracker_newchunk( + &mut tdf.file_tracker, + &file_name, + rd.data, + offset, + rd.len, + false, + &file_id, + ); } true - }, - None => { false }, + } + None => false, }; if !found { let tx = state.new_file_tx(&file_fid, &file_name, Direction::ToClient); if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { - let file_id : u32 = tx.id as u32; + let file_id: u32 = tx.id as u32; SCLogDebug!("FID {:?} found at tx {}", file_fid, tx.id); if offset < tdf.file_tracker.tracked { set_event_fileoverlap = true; } - filetracker_newchunk(&mut tdf.file_tracker, - &file_name, rd.data, offset, - rd.len, false, &file_id); + filetracker_newchunk( + &mut tdf.file_tracker, + &file_name, + rd.data, + offset, + rd.len, + false, + &file_id, + ); tdf.share_name = share_name; } tx.vercmd.set_smb1_cmd(SMB1_COMMAND_READ_ANDX); @@ -1094,15 +1226,24 @@ pub fn smb1_read_response_record(state: &mut SMBState, r: &SmbRecord, andx_offse // hack: we store fid with ssn id mixed in, but here we want the // real thing instead. - let pure_fid = if file_fid.len() > 2 { &file_fid[0..2] } else { &[] }; + let pure_fid = if file_fid.len() > 2 { + &file_fid[0..2] + } else { + &[] + }; smb_read_dcerpc_record(state, vercmd, hdr, pure_fid, rd.data); } - state.set_file_left(Direction::ToClient, rd.len, rd.data.len() as u32, file_fid.to_vec()); + state.set_file_left( + Direction::ToClient, + rd.len, + rd.data.len() as u32, + file_fid.to_vec(), + ); } _ => { events.push(SMBEvent::MalformedData); - }, + } } } diff --git a/rust/src/smb/smb1_records.rs b/rust/src/smb/smb1_records.rs index d727311cce..3e2ce8b988 100644 --- a/rust/src/smb/smb1_records.rs +++ b/rust/src/smb/smb1_records.rs @@ -22,9 +22,9 @@ use crate::smb::smb_records::*; use nom8::bytes::streaming::{tag, take}; use nom8::combinator::{complete, cond, peek, rest, verify}; use nom8::error::{make_error, ErrorKind}; -use nom8::Err; use nom8::multi::many1; -use nom8::number::streaming::{le_u8, le_u16, le_u32, le_u64}; +use nom8::number::streaming::{le_u16, le_u32, le_u64, le_u8}; +use nom8::Err; use nom8::IResult; use nom8::Parser; @@ -33,14 +33,17 @@ pub const SMB1_HEADER_SIZE: usize = 32; // SMB_FLAGS_REPLY in Microsoft docs. const SMB1_FLAGS_RESPONSE: u8 = 0x80; -fn smb_get_unicode_string_with_offset(i: &[u8], offset: usize) -> IResult<&[u8], Vec, SmbError> -{ +fn smb_get_unicode_string_with_offset( + i: &[u8], offset: usize, +) -> IResult<&[u8], Vec, SmbError> { let (i, _) = cond(offset % 2 == 1, take(1_usize)).parse(i)?; smb_get_unicode_string(i) } /// take a string, unicode or ascii based on record -pub fn smb1_get_string<'a>(i: &'a[u8], r: &SmbRecord, offset: usize) -> IResult<&'a[u8], Vec, SmbError> { +pub fn smb1_get_string<'a>( + i: &'a [u8], r: &SmbRecord, offset: usize, +) -> IResult<&'a [u8], Vec, SmbError> { if r.has_unicode_support() { smb_get_unicode_string_with_offset(i, offset) } else { @@ -48,8 +51,7 @@ pub fn smb1_get_string<'a>(i: &'a[u8], r: &SmbRecord, offset: usize) -> IResult< } } - -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbParamBlockAndXHeader { pub wct: u8, pub andx_command: u8, @@ -69,12 +71,12 @@ pub fn smb1_parse_andx_header(i: &[u8]) -> IResult<&[u8], SmbParamBlockAndXHeade Ok((i, hdr)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Smb1WriteRequestRecord<'a> { pub offset: u64, pub len: u32, - pub fid: &'a[u8], - pub data: &'a[u8], + pub fid: &'a [u8], + pub data: &'a [u8], } pub fn parse_smb1_write_request_record(i: &[u8]) -> IResult<&[u8], Smb1WriteRequestRecord<'_>> { @@ -91,12 +93,14 @@ pub fn parse_smb1_write_request_record(i: &[u8]) -> IResult<&[u8], Smb1WriteRequ offset: offset as u64, len: data_len as u32, fid, - data:file_data, + data: file_data, }; Ok((i, record)) } -pub fn parse_smb1_write_andx_request_record(i : &[u8], andx_offset: usize) -> IResult<&[u8], Smb1WriteRequestRecord<'_>> { +pub fn parse_smb1_write_andx_request_record( + i: &[u8], andx_offset: usize, +) -> IResult<&[u8], Smb1WriteRequestRecord<'_>> { let origin_i = i; let ax = andx_offset as u16; let (i, wct) = le_u8.parse(i)?; @@ -110,14 +114,14 @@ pub fn parse_smb1_write_andx_request_record(i : &[u8], andx_offset: usize) -> IR let (i, _remaining) = le_u16.parse(i)?; let (i, data_len_high) = le_u16.parse(i)?; let (i, data_len_low) = le_u16.parse(i)?; - let data_len = ((data_len_high as u32) << 16)|(data_len_low as u32); + let data_len = ((data_len_high as u32) << 16) | (data_len_low as u32); let (i, data_offset) = le_u16.parse(i)?; - if data_offset < 0x3c || data_offset < ax{ + if data_offset < 0x3c || data_offset < ax { return Err(Err::Error(make_error(i, ErrorKind::LengthValue))); } let (i, high_offset) = cond(wct == 14, le_u32).parse(i)?; let (_i, _bcc) = le_u16.parse(i)?; - let (i, _padding_data) = take(data_offset-ax).parse(origin_i)?; + let (i, _padding_data) = take(data_offset - ax).parse(origin_i)?; let (i, file_data) = take(std::cmp::min(data_len, i.len() as u32))(i)?; let record = Smb1WriteRequestRecord { @@ -129,7 +133,9 @@ pub fn parse_smb1_write_andx_request_record(i : &[u8], andx_offset: usize) -> IR Ok((i, record)) } -pub fn parse_smb1_write_and_close_request_record(i: &[u8]) -> IResult<&[u8], Smb1WriteRequestRecord<'_>> { +pub fn parse_smb1_write_and_close_request_record( + i: &[u8], +) -> IResult<&[u8], Smb1WriteRequestRecord<'_>> { let (i, _wct) = le_u8.parse(i)?; let (i, fid) = take(2_usize).parse(i)?; let (i, count) = le_u16.parse(i)?; @@ -147,25 +153,27 @@ pub fn parse_smb1_write_and_close_request_record(i: &[u8]) -> IResult<&[u8], Smb Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Smb1NegotiateProtocolResponseRecord<'a> { pub dialect_idx: u16, - pub server_guid: &'a[u8], + pub server_guid: &'a [u8], } -pub fn parse_smb1_negotiate_protocol_response_record_error(i: &[u8]) - -> IResult<&[u8], Smb1NegotiateProtocolResponseRecord<'_>> { - let (i, _wct) = le_u8.parse(i)?; - let (i, _bcc) = le_u16.parse(i)?; - let record = Smb1NegotiateProtocolResponseRecord { - dialect_idx: 0, - server_guid: &[], - }; - Ok((i, record)) +pub fn parse_smb1_negotiate_protocol_response_record_error( + i: &[u8], +) -> IResult<&[u8], Smb1NegotiateProtocolResponseRecord<'_>> { + let (i, _wct) = le_u8.parse(i)?; + let (i, _bcc) = le_u16.parse(i)?; + let record = Smb1NegotiateProtocolResponseRecord { + dialect_idx: 0, + server_guid: &[], + }; + Ok((i, record)) } -pub fn parse_smb1_negotiate_protocol_response_record_ok(i: &[u8]) - -> IResult<&[u8], Smb1NegotiateProtocolResponseRecord<'_>> { +pub fn parse_smb1_negotiate_protocol_response_record_ok( + i: &[u8], +) -> IResult<&[u8], Smb1NegotiateProtocolResponseRecord<'_>> { let (i, _wct) = le_u8.parse(i)?; let (i, dialect_idx) = le_u16.parse(i)?; let (i, _sec_mode) = le_u8.parse(i)?; @@ -183,8 +191,9 @@ pub fn parse_smb1_negotiate_protocol_response_record_ok(i: &[u8]) Ok((i, record)) } -pub fn parse_smb1_negotiate_protocol_response_record(i: &[u8]) - -> IResult<&[u8], Smb1NegotiateProtocolResponseRecord<'_>> { +pub fn parse_smb1_negotiate_protocol_response_record( + i: &[u8], +) -> IResult<&[u8], Smb1NegotiateProtocolResponseRecord<'_>> { let (i, wct) = peek(le_u8).parse(i)?; match wct { 0 => parse_smb1_negotiate_protocol_response_record_error(i), @@ -192,13 +201,14 @@ pub fn parse_smb1_negotiate_protocol_response_record(i: &[u8]) } } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Smb1NegotiateProtocolRecord<'a> { pub dialects: Vec<&'a [u8]>, } -pub fn parse_smb1_negotiate_protocol_record(i: &[u8]) - -> IResult<&[u8], Smb1NegotiateProtocolRecord<'_>> { +pub fn parse_smb1_negotiate_protocol_record( + i: &[u8], +) -> IResult<&[u8], Smb1NegotiateProtocolRecord<'_>> { let (i, _wtc) = le_u8.parse(i)?; let (i, _bcc) = le_u16.parse(i)?; // dialects is a list of [1 byte buffer format][string][0 terminator] @@ -207,15 +217,15 @@ pub fn parse_smb1_negotiate_protocol_record(i: &[u8]) Ok((i, record)) } - -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Smb1ResponseRecordTreeConnectAndX<'a> { - pub service: &'a[u8], - pub nativefs: &'a[u8], + pub service: &'a [u8], + pub nativefs: &'a [u8], } -pub fn parse_smb_connect_tree_andx_response_record(i: &[u8]) - -> IResult<&[u8], Smb1ResponseRecordTreeConnectAndX<'_>> { +pub fn parse_smb_connect_tree_andx_response_record( + i: &[u8], +) -> IResult<&[u8], Smb1ResponseRecordTreeConnectAndX<'_>> { let (i, wct) = le_u8.parse(i)?; let (i, _andx_command) = le_u8.parse(i)?; let (i, _) = take(1_usize).parse(i)?; // reserved @@ -225,35 +235,30 @@ pub fn parse_smb_connect_tree_andx_response_record(i: &[u8]) let (i, _bcc) = le_u16.parse(i)?; let (i, service) = take_until_and_consume(b"\x00").parse(i)?; let (i, nativefs) = take_until_and_consume(b"\x00").parse(i)?; - let record = Smb1ResponseRecordTreeConnectAndX { - service, - nativefs - }; + let record = Smb1ResponseRecordTreeConnectAndX { service, nativefs }; Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbRecordTreeConnectAndX<'a> { pub path: Vec, - pub service: &'a[u8], + pub service: &'a [u8], } -pub fn parse_smb_connect_tree_andx_record<'a>(i: &'a[u8], r: &SmbRecord) - -> IResult<&'a[u8], SmbRecordTreeConnectAndX<'a>, SmbError> { - let (i, _skip1) = take(7_usize).parse(i)?; - let (i, pwlen) = le_u16.parse(i)?; - let (i, _bcc) = le_u16.parse(i)?; - let (i, _pw) = take(pwlen).parse(i)?; - let (i, path) = smb1_get_string(i, r, 11 + pwlen as usize)?; - let (i, service) = take_until_and_consume(b"\x00").parse(i)?; - let record = SmbRecordTreeConnectAndX { - path, - service - }; - Ok((i, record)) +pub fn parse_smb_connect_tree_andx_record<'a>( + i: &'a [u8], r: &SmbRecord, +) -> IResult<&'a [u8], SmbRecordTreeConnectAndX<'a>, SmbError> { + let (i, _skip1) = take(7_usize).parse(i)?; + let (i, pwlen) = le_u16.parse(i)?; + let (i, _bcc) = le_u16.parse(i)?; + let (i, _pw) = take(pwlen).parse(i)?; + let (i, path) = smb1_get_string(i, r, 11 + pwlen as usize)?; + let (i, service) = take_until_and_consume(b"\x00").parse(i)?; + let record = SmbRecordTreeConnectAndX { path, service }; + Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbRecordTransRequest<'a> { pub params: SmbRecordTransRequestParams, pub pipe: Option>, @@ -261,26 +266,23 @@ pub struct SmbRecordTransRequest<'a> { pub data: SmbRecordTransRequestData<'a>, } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbPipeProtocolRecord<'a> { pub function: u16, - pub fid: &'a[u8], + pub fid: &'a [u8], } -pub fn parse_smb_trans_request_record_pipe(i: &[u8]) - -> IResult<&[u8], SmbPipeProtocolRecord<'_>, SmbError> { +pub fn parse_smb_trans_request_record_pipe( + i: &[u8], +) -> IResult<&[u8], SmbPipeProtocolRecord<'_>, SmbError> { let (i, fun) = le_u16.parse(i)?; let (i, fid) = take(2_usize).parse(i)?; - let record = SmbPipeProtocolRecord { - function: fun, - fid - }; + let record = SmbPipeProtocolRecord { function: fun, fid }; Ok((i, record)) } - -#[derive(Debug,PartialEq, Eq)] -pub struct SmbRecordTransRequestParams<> { +#[derive(Debug, PartialEq, Eq)] +pub struct SmbRecordTransRequestParams { pub max_data_cnt: u16, param_cnt: u16, param_offset: u16, @@ -289,47 +291,57 @@ pub struct SmbRecordTransRequestParams<> { bcc: u16, } -pub fn parse_smb_trans_request_record_params(i: &[u8]) - -> IResult<&[u8], (SmbRecordTransRequestParams, Option>), SmbError> -{ - let (i, wct) = le_u8.parse(i)?; - let (i, _total_param_cnt) = le_u16.parse(i)?; - let (i, _total_data_count) = le_u16.parse(i)?; - let (i, _max_param_cnt) = le_u16.parse(i)?; - let (i, max_data_cnt) = le_u16.parse(i)?; - let (i, _max_setup_cnt) = le_u8.parse(i)?; - let (i, _) = take(1_usize).parse(i)?; // reserved - let (i, _) = take(2_usize).parse(i)?; // flags - let (i, _timeout) = le_u32.parse(i)?; - let (i, _) = take(2_usize).parse(i)?; // reserved - let (i, param_cnt) = le_u16.parse(i)?; - let (i, param_offset) = le_u16.parse(i)?; - let (i, data_cnt) = le_u16.parse(i)?; - let (i, data_offset) = le_u16.parse(i)?; - let (i, setup_cnt) = le_u8.parse(i)?; - let (i, _) = take(1_usize).parse(i)?; // reserved - let (i, pipe) = cond(wct == 16 && setup_cnt == 2 && data_cnt > 0, parse_smb_trans_request_record_pipe).parse(i)?; - let (i, bcc) = le_u16.parse(i)?; - let params = SmbRecordTransRequestParams { - max_data_cnt, - param_cnt, - param_offset, - data_cnt, - data_offset, - bcc - }; - Ok((i, (params, pipe))) +pub fn parse_smb_trans_request_record_params( + i: &[u8], +) -> IResult< + &[u8], + ( + SmbRecordTransRequestParams, + Option>, + ), + SmbError, +> { + let (i, wct) = le_u8.parse(i)?; + let (i, _total_param_cnt) = le_u16.parse(i)?; + let (i, _total_data_count) = le_u16.parse(i)?; + let (i, _max_param_cnt) = le_u16.parse(i)?; + let (i, max_data_cnt) = le_u16.parse(i)?; + let (i, _max_setup_cnt) = le_u8.parse(i)?; + let (i, _) = take(1_usize).parse(i)?; // reserved + let (i, _) = take(2_usize).parse(i)?; // flags + let (i, _timeout) = le_u32.parse(i)?; + let (i, _) = take(2_usize).parse(i)?; // reserved + let (i, param_cnt) = le_u16.parse(i)?; + let (i, param_offset) = le_u16.parse(i)?; + let (i, data_cnt) = le_u16.parse(i)?; + let (i, data_offset) = le_u16.parse(i)?; + let (i, setup_cnt) = le_u8.parse(i)?; + let (i, _) = take(1_usize).parse(i)?; // reserved + let (i, pipe) = cond( + wct == 16 && setup_cnt == 2 && data_cnt > 0, + parse_smb_trans_request_record_pipe, + ) + .parse(i)?; + let (i, bcc) = le_u16.parse(i)?; + let params = SmbRecordTransRequestParams { + max_data_cnt, + param_cnt, + param_offset, + data_cnt, + data_offset, + bcc, + }; + Ok((i, (params, pipe))) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbRecordTransRequestData<'a> { - pub data: &'a[u8], + pub data: &'a [u8], } -pub fn parse_smb_trans_request_record_data(i: &[u8], - pad1: usize, param_cnt: u16, pad2: usize, data_len: u16) - -> IResult<&[u8], SmbRecordTransRequestData<'_>, SmbError> -{ +pub fn parse_smb_trans_request_record_data( + i: &[u8], pad1: usize, param_cnt: u16, pad2: usize, data_len: u16, +) -> IResult<&[u8], SmbRecordTransRequestData<'_>, SmbError> { let (i, _) = take(pad1).parse(i)?; let (i, _) = take(param_cnt).parse(i)?; let (i, _) = take(pad2).parse(i)?; @@ -338,9 +350,9 @@ pub fn parse_smb_trans_request_record_data(i: &[u8], Ok((i, req)) } -pub fn parse_smb_trans_request_record<'a>(i: &'a[u8], r: &SmbRecord) - -> IResult<&'a[u8], SmbRecordTransRequest<'a>, SmbError> -{ +pub fn parse_smb_trans_request_record<'a>( + i: &'a [u8], r: &SmbRecord, +) -> IResult<&'a [u8], SmbRecordTransRequest<'a>, SmbError> { let (rem, (params, pipe)) = parse_smb_trans_request_record_params(i)?; let mut offset = 32 + (i.len() - rem.len()); // init with SMB header SCLogDebug!("params {:?}: offset {}", params, offset); @@ -351,8 +363,7 @@ pub fn parse_smb_trans_request_record<'a>(i: &'a[u8], r: &SmbRecord) // spec says pad to 4 bytes, but traffic shows this doesn't // always happen. - let pad1 = if offset == params.param_offset as usize || - offset == params.data_offset as usize { + let pad1 = if offset == params.param_offset as usize || offset == params.data_offset as usize { 0 } else { offset % 4 @@ -371,68 +382,81 @@ pub fn parse_smb_trans_request_record<'a>(i: &'a[u8], r: &SmbRecord) }; SCLogDebug!("pad2 {}", pad2); - let d = match parse_smb_trans_request_record_data(rem2, - pad1, params.param_cnt, pad2, params.data_cnt) { + let d = match parse_smb_trans_request_record_data( + rem2, + pad1, + params.param_cnt, + pad2, + params.data_cnt, + ) { Ok((_, rd)) => rd, - Err(e) => { return Err(e); } + Err(e) => { + return Err(e); + } }; SCLogDebug!("d {:?}", d); d } else { - SmbRecordTransRequestData { data: &[], } // no data + SmbRecordTransRequestData { data: &[] } // no data }; let res = SmbRecordTransRequest { - params, pipe, txname: n, data: recdata, + params, + pipe, + txname: n, + data: recdata, }; Ok((rem, res)) } - -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbRecordTransResponse<'a> { pub data_cnt: u16, pub bcc: u16, - pub data: &'a[u8], -} - -pub fn parse_smb_trans_response_error_record(i: &[u8]) -> IResult<&[u8], SmbRecordTransResponse<'_>> { - let (i, _wct) = le_u8.parse(i)?; - let (i, bcc) = le_u16.parse(i)?; - let resp = SmbRecordTransResponse { - data_cnt: 0, - bcc, - data: &[], - }; - Ok((i, resp)) -} - -pub fn parse_smb_trans_response_regular_record(i: &[u8]) -> IResult<&[u8], SmbRecordTransResponse<'_>> { - let (i, wct) = le_u8.parse(i)?; - let (i, _total_param_cnt) = le_u16.parse(i)?; - let (i, _total_data_count) = le_u16.parse(i)?; - let (i, _) = take(2_usize).parse(i)?; // reserved - let (i, _param_cnt) = le_u16.parse(i)?; - let (i, _param_offset) = le_u16.parse(i)?; - let (i, _param_displacement) = le_u16.parse(i)?; - let (i, data_cnt) = le_u16.parse(i)?; - let (i, data_offset) = le_u16.parse(i)?; - let (i, _data_displacement) = le_u16.parse(i)?; - let (i, _setup_cnt) = le_u8.parse(i)?; - let (i, _) = take(1_usize).parse(i)?; // reserved - let (i, bcc) = le_u16.parse(i)?; - let (i, _) = take(1_usize).parse(i)?; // padding - let (i, _padding_evasion) = cond( - data_offset > 36+2*(wct as u16), - |b| take(data_offset - (36+2*(wct as u16)))(b) - ).parse(i)?; - let (i, data) = take(data_cnt).parse(i)?; - let resp = SmbRecordTransResponse { - data_cnt, - bcc, - data - }; - Ok((i, resp)) + pub data: &'a [u8], +} + +pub fn parse_smb_trans_response_error_record( + i: &[u8], +) -> IResult<&[u8], SmbRecordTransResponse<'_>> { + let (i, _wct) = le_u8.parse(i)?; + let (i, bcc) = le_u16.parse(i)?; + let resp = SmbRecordTransResponse { + data_cnt: 0, + bcc, + data: &[], + }; + Ok((i, resp)) +} + +pub fn parse_smb_trans_response_regular_record( + i: &[u8], +) -> IResult<&[u8], SmbRecordTransResponse<'_>> { + let (i, wct) = le_u8.parse(i)?; + let (i, _total_param_cnt) = le_u16.parse(i)?; + let (i, _total_data_count) = le_u16.parse(i)?; + let (i, _) = take(2_usize).parse(i)?; // reserved + let (i, _param_cnt) = le_u16.parse(i)?; + let (i, _param_offset) = le_u16.parse(i)?; + let (i, _param_displacement) = le_u16.parse(i)?; + let (i, data_cnt) = le_u16.parse(i)?; + let (i, data_offset) = le_u16.parse(i)?; + let (i, _data_displacement) = le_u16.parse(i)?; + let (i, _setup_cnt) = le_u8.parse(i)?; + let (i, _) = take(1_usize).parse(i)?; // reserved + let (i, bcc) = le_u16.parse(i)?; + let (i, _) = take(1_usize).parse(i)?; // padding + let (i, _padding_evasion) = cond(data_offset > 36 + 2 * (wct as u16), |b| { + take(data_offset - (36 + 2 * (wct as u16)))(b) + }) + .parse(i)?; + let (i, data) = take(data_cnt).parse(i)?; + let resp = SmbRecordTransResponse { + data_cnt, + bcc, + data, + }; + Ok((i, resp)) } pub fn parse_smb_trans_response_record(i: &[u8]) -> IResult<&[u8], SmbRecordTransResponse<'_>> { @@ -443,40 +467,40 @@ pub fn parse_smb_trans_response_record(i: &[u8]) -> IResult<&[u8], SmbRecordTran } } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbRecordSetupAndX<'a> { - pub sec_blob: &'a[u8], + pub sec_blob: &'a [u8], pub request_host: SessionSetupRequest, } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SessionSetupRequest { pub native_os: Vec, pub native_lm: Vec, pub primary_domain: Vec, } -pub fn smb1_session_setup_request_host_info(r: &SmbRecord, blob: &[u8]) -> SessionSetupRequest -{ +pub fn smb1_session_setup_request_host_info(r: &SmbRecord, blob: &[u8]) -> SessionSetupRequest { if blob.len() > 1 && r.has_unicode_support() { let offset = r.data.len() - blob.len(); let blob = if offset % 2 == 1 { &blob[1..] } else { blob }; let (native_os, native_lm, primary_domain) = match smb_get_unicode_string(blob) { - Ok((rem, n1)) => { - match smb_get_unicode_string(rem) { - Ok((rem, n2)) => { - match smb_get_unicode_string(rem) { - Ok((_, n3)) => { (n1, n2, n3) }, - _ => { (n1, n2, Vec::new()) }, - } - }, - _ => { (n1, Vec::new(), Vec::new()) }, - } + Ok((rem, n1)) => match smb_get_unicode_string(rem) { + Ok((rem, n2)) => match smb_get_unicode_string(rem) { + Ok((_, n3)) => (n1, n2, n3), + _ => (n1, n2, Vec::new()), + }, + _ => (n1, Vec::new(), Vec::new()), }, - _ => { (Vec::new(), Vec::new(), Vec::new()) }, + _ => (Vec::new(), Vec::new(), Vec::new()), }; - SCLogDebug!("name1 {:?} name2 {:?} name3 {:?}", native_os,native_lm,primary_domain); + SCLogDebug!( + "name1 {:?} name2 {:?} name3 {:?}", + native_os, + native_lm, + primary_domain + ); SessionSetupRequest { native_os, native_lm, @@ -484,18 +508,14 @@ pub fn smb1_session_setup_request_host_info(r: &SmbRecord, blob: &[u8]) -> Sessi } } else { let (native_os, native_lm, primary_domain) = match smb_get_ascii_string(blob) { - Ok((rem, n1)) => { - match smb_get_ascii_string(rem) { - Ok((rem, n2)) => { - match smb_get_ascii_string(rem) { - Ok((_, n3)) => { (n1, n2, n3) }, - _ => { (n1, n2, Vec::new()) }, - } - }, - _ => { (n1, Vec::new(), Vec::new()) }, - } + Ok((rem, n1)) => match smb_get_ascii_string(rem) { + Ok((rem, n2)) => match smb_get_ascii_string(rem) { + Ok((_, n3)) => (n1, n2, n3), + _ => (n1, n2, Vec::new()), + }, + _ => (n1, Vec::new(), Vec::new()), }, - _ => { (Vec::new(), Vec::new(), Vec::new()) }, + _ => (Vec::new(), Vec::new(), Vec::new()), }; SCLogDebug!("session_setup_request_host_info: not unicode"); @@ -507,26 +527,36 @@ pub fn smb1_session_setup_request_host_info(r: &SmbRecord, blob: &[u8]) -> Sessi } } -pub fn smb1_session_setup_parse_wct13<'a>(r: &'a SmbRecord, blob: &'a [u8]) -> (&'a [u8], SessionSetupRequest) { +pub fn smb1_session_setup_parse_wct13<'a>( + r: &'a SmbRecord, blob: &'a [u8], +) -> (&'a [u8], SessionSetupRequest) { if let Ok((rem, primary_domain)) = smb1_get_string(blob, r, 0) { if let Ok((rem, native_os)) = smb1_get_string(rem, r, 0) { if let Ok((rem, native_lm)) = smb1_get_string(rem, r, 0) { - return (rem, SessionSetupRequest { - native_os, - native_lm, - primary_domain, - }); + return ( + rem, + SessionSetupRequest { + native_os, + native_lm, + primary_domain, + }, + ); } } } - return (blob, SessionSetupRequest { - native_os: Vec::new(), - native_lm: Vec::new(), - primary_domain: Vec::new(), - }); + return ( + blob, + SessionSetupRequest { + native_os: Vec::new(), + native_lm: Vec::new(), + primary_domain: Vec::new(), + }, + ); } -pub fn parse_smb_setup_andx_record<'a>(i: &'a [u8], r: &'a SmbRecord) -> IResult<&'a [u8], SmbRecordSetupAndX<'a>> { +pub fn parse_smb_setup_andx_record<'a>( + i: &'a [u8], r: &'a SmbRecord, +) -> IResult<&'a [u8], SmbRecordSetupAndX<'a>> { let (i, wct) = le_u8.parse(i)?; if wct == 12 { let (i, _skip1) = take(14_usize).parse(i)?; @@ -534,7 +564,10 @@ pub fn parse_smb_setup_andx_record<'a>(i: &'a [u8], r: &'a SmbRecord) -> IResult let (i, _skip2) = take(8_usize).parse(i)?; let (i, _bcc) = le_u16.parse(i)?; let (i, sec_blob) = take(sec_blob_len).parse(i)?; - let record = SmbRecordSetupAndX { sec_blob, request_host: smb1_session_setup_request_host_info(r, i) }; + let record = SmbRecordSetupAndX { + sec_blob, + request_host: smb1_session_setup_request_host_info(r, i), + }; Ok((i, record)) } else if wct == 13 { let (i, _skip1) = take(14_usize).parse(i)?; @@ -547,7 +580,10 @@ pub fn parse_smb_setup_andx_record<'a>(i: &'a [u8], r: &'a SmbRecord) -> IResult let (i, _pad) = cond(oem_pass_len.wrapping_add(uni_pass_len) % 2 == 1, le_u8).parse(i)?; if let Ok((i, _account_name)) = smb1_get_string(i, r, 0) { let (i, request_host) = smb1_session_setup_parse_wct13(r, i); - let record = SmbRecordSetupAndX { sec_blob: &[], request_host }; + let record = SmbRecordSetupAndX { + sec_blob: &[], + request_host, + }; Ok((i, record)) } else { Err(Err::Error(make_error(i, ErrorKind::LengthValue))) @@ -557,39 +593,37 @@ pub fn parse_smb_setup_andx_record<'a>(i: &'a [u8], r: &'a SmbRecord) -> IResult } } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbResponseRecordSetupAndX<'a> { - pub sec_blob: &'a[u8], + pub sec_blob: &'a [u8], } fn response_setup_andx_record(i: &[u8]) -> IResult<&[u8], SmbResponseRecordSetupAndX<'_>> { - let (i, _skip1) = take(7_usize).parse(i)?; - let (i, sec_blob_len) = le_u16.parse(i)?; - let (i, _bcc) = le_u16.parse(i)?; - let (i, sec_blob) = take(sec_blob_len).parse(i)?; - let record = SmbResponseRecordSetupAndX { sec_blob }; - Ok((i, record)) + let (i, _skip1) = take(7_usize).parse(i)?; + let (i, sec_blob_len) = le_u16.parse(i)?; + let (i, _bcc) = le_u16.parse(i)?; + let (i, sec_blob) = take(sec_blob_len).parse(i)?; + let record = SmbResponseRecordSetupAndX { sec_blob }; + Ok((i, record)) } fn response_setup_andx_wct3_record(i: &[u8]) -> IResult<&[u8], SmbResponseRecordSetupAndX<'_>> { - let (i, _skip1) = take(7_usize).parse(i)?; - let (i, _bcc) = le_u16.parse(i)?; - let record = SmbResponseRecordSetupAndX { - sec_blob: &[], - }; - Ok((i, record)) + let (i, _skip1) = take(7_usize).parse(i)?; + let (i, _bcc) = le_u16.parse(i)?; + let record = SmbResponseRecordSetupAndX { sec_blob: &[] }; + Ok((i, record)) } fn response_setup_andx_error_record(i: &[u8]) -> IResult<&[u8], SmbResponseRecordSetupAndX<'_>> { - let (i, _wct) = le_u8.parse(i)?; - let (i, _bcc) = le_u16.parse(i)?; - let record = SmbResponseRecordSetupAndX { - sec_blob: &[], - }; - Ok((i, record)) + let (i, _wct) = le_u8.parse(i)?; + let (i, _bcc) = le_u16.parse(i)?; + let record = SmbResponseRecordSetupAndX { sec_blob: &[] }; + Ok((i, record)) } -pub fn parse_smb_response_setup_andx_record(i: &[u8]) -> IResult<&[u8], SmbResponseRecordSetupAndX<'_>> { +pub fn parse_smb_response_setup_andx_record( + i: &[u8], +) -> IResult<&[u8], SmbResponseRecordSetupAndX<'_>> { let (i, wct) = peek(le_u8).parse(i)?; match wct { 0 => response_setup_andx_error_record(i), @@ -598,14 +632,16 @@ pub fn parse_smb_response_setup_andx_record(i: &[u8]) -> IResult<&[u8], SmbRespo } } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbRequestReadAndXRecord<'a> { - pub fid: &'a[u8], + pub fid: &'a [u8], pub size: u64, pub offset: u64, } -pub fn parse_smb_read_andx_request_record(i: &[u8]) -> IResult<&[u8], SmbRequestReadAndXRecord<'_>> { +pub fn parse_smb_read_andx_request_record( + i: &[u8], +) -> IResult<&[u8], SmbRequestReadAndXRecord<'_>> { let (i, wct) = le_u8.parse(i)?; let (i, _andx_command) = le_u8.parse(i)?; let (i, _) = take(1_usize).parse(i)?; // reserved @@ -619,19 +655,23 @@ pub fn parse_smb_read_andx_request_record(i: &[u8]) -> IResult<&[u8], SmbRequest let (i, high_offset) = cond(wct == 12, le_u32).parse(i)?; // only from wct ==12? let record = SmbRequestReadAndXRecord { fid, - size: (((max_count_high as u64) << 16)|max_count_low as u64), - offset: high_offset.map(|ho| ((ho as u64) << 32) | offset as u64).unwrap_or(0), + size: (((max_count_high as u64) << 16) | max_count_low as u64), + offset: high_offset + .map(|ho| ((ho as u64) << 32) | offset as u64) + .unwrap_or(0), }; Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbResponseReadAndXRecord<'a> { pub len: u32, - pub data: &'a[u8], + pub data: &'a [u8], } -pub fn parse_smb_read_andx_response_record(i: &[u8]) -> IResult<&[u8], SmbResponseReadAndXRecord<'_>> { +pub fn parse_smb_read_andx_response_record( + i: &[u8], +) -> IResult<&[u8], SmbResponseReadAndXRecord<'_>> { let (i, wct) = le_u8.parse(i)?; let (i, _andx_command) = le_u8.parse(i)?; let (i, _) = take(1_usize).parse(i)?; // reserved @@ -642,30 +682,29 @@ pub fn parse_smb_read_andx_response_record(i: &[u8]) -> IResult<&[u8], SmbRespon let (i, data_len_high) = le_u32.parse(i)?; let (i, _) = take(6_usize).parse(i)?; // reserved let (i, bcc) = le_u16.parse(i)?; - let (i, _padding) = cond( - bcc > data_len_low, - |b| take(bcc - data_len_low)(b) - ).parse(i)?; // TODO figure out how this works with data_len_high - let (i, _padding_evasion) = cond( - data_offset > 36+2*(wct as u16), - |b| take(data_offset - (36+2*(wct as u16)))(b) - ).parse(i)?; + let (i, _padding) = cond(bcc > data_len_low, |b| take(bcc - data_len_low)(b)).parse(i)?; // TODO figure out how this works with data_len_high + let (i, _padding_evasion) = cond(data_offset > 36 + 2 * (wct as u16), |b| { + take(data_offset - (36 + 2 * (wct as u16)))(b) + }) + .parse(i)?; let (i, file_data) = rest.parse(i)?; let record = SmbResponseReadAndXRecord { - len: ((data_len_high << 16)|data_len_low as u32), + len: ((data_len_high << 16) | data_len_low as u32), data: file_data, - }; + }; Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbRequestRenameRecord { pub oldname: Vec, pub newname: Vec, } -pub fn parse_smb_rename_request_record(i: &[u8]) -> IResult<&[u8], SmbRequestRenameRecord, SmbError> { +pub fn parse_smb_rename_request_record( + i: &[u8], +) -> IResult<&[u8], SmbRequestRenameRecord, SmbError> { let (i, _wct) = le_u8.parse(i)?; let (i, _search_attr) = le_u16.parse(i)?; let (i, _bcc) = le_u16.parse(i)?; @@ -673,23 +712,20 @@ pub fn parse_smb_rename_request_record(i: &[u8]) -> IResult<&[u8], SmbRequestRen let (i, oldname) = smb_get_unicode_string(i)?; let (i, _newtype) = le_u8.parse(i)?; let (i, newname) = smb_get_unicode_string_with_offset(i, 1)?; // HACK if we assume oldname is a series of utf16 chars offset would be 1 - let record = SmbRequestRenameRecord { - oldname, - newname - }; + let record = SmbRequestRenameRecord { oldname, newname }; Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] -pub struct SmbRequestCreateAndXRecord<> { +#[derive(Debug, PartialEq, Eq)] +pub struct SmbRequestCreateAndXRecord { pub disposition: u32, pub create_options: u32, pub file_name: Vec, } -pub fn parse_smb_create_andx_request_record<'a>(i: &'a[u8], r: &SmbRecord) - -> IResult<&'a[u8], SmbRequestCreateAndXRecord<>, SmbError> -{ +pub fn parse_smb_create_andx_request_record<'a>( + i: &'a [u8], r: &SmbRecord, +) -> IResult<&'a [u8], SmbRequestCreateAndXRecord, SmbError> { let (i, _skip1) = take(6_usize).parse(i)?; let (i, file_name_len) = le_u16.parse(i)?; let (i, _skip3) = take(28_usize).parse(i)?; @@ -697,10 +733,10 @@ pub fn parse_smb_create_andx_request_record<'a>(i: &'a[u8], r: &SmbRecord) let (i, create_options) = le_u32.parse(i)?; let (i, _skip2) = take(5_usize).parse(i)?; let (i, bcc) = le_u16.parse(i)?; - let (i, file_name) = cond( - bcc >= file_name_len, - |b| smb1_get_string(b, r, (bcc - file_name_len) as usize) - ).parse(i)?; + let (i, file_name) = cond(bcc >= file_name_len, |b| { + smb1_get_string(b, r, (bcc - file_name_len) as usize) + }) + .parse(i)?; let (i, _skip3) = rest.parse(i)?; let record = SmbRequestCreateAndXRecord { disposition, @@ -710,13 +746,14 @@ pub fn parse_smb_create_andx_request_record<'a>(i: &'a[u8], r: &SmbRecord) Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] -pub struct Trans2RecordParamSetFileInfoDisposition<> { +#[derive(Debug, PartialEq, Eq)] +pub struct Trans2RecordParamSetFileInfoDisposition { pub delete: bool, } -pub fn parse_trans2_request_data_set_file_info_disposition(i: &[u8]) - -> IResult<&[u8], Trans2RecordParamSetFileInfoDisposition> { +pub fn parse_trans2_request_data_set_file_info_disposition( + i: &[u8], +) -> IResult<&[u8], Trans2RecordParamSetFileInfoDisposition> { let (i, delete) = le_u8.parse(i)?; let record = Trans2RecordParamSetFileInfoDisposition { delete: delete & 1 == 1, @@ -724,45 +761,51 @@ pub fn parse_trans2_request_data_set_file_info_disposition(i: &[u8]) Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Trans2RecordParamSetFileInfo<'a> { - pub fid: &'a[u8], + pub fid: &'a [u8], pub loi: u16, } -pub fn parse_trans2_request_params_set_file_info(i: &[u8]) -> IResult<&[u8], Trans2RecordParamSetFileInfo<'_>> { +pub fn parse_trans2_request_params_set_file_info( + i: &[u8], +) -> IResult<&[u8], Trans2RecordParamSetFileInfo<'_>> { let (i, fid) = take(2_usize).parse(i)?; let (i, loi) = le_u16.parse(i)?; let record = Trans2RecordParamSetFileInfo { fid, loi }; Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Trans2RecordParamSetFileInfoRename<'a> { pub replace: bool, - pub newname: &'a[u8], + pub newname: &'a [u8], } -pub fn parse_trans2_request_data_set_file_info_rename(i: &[u8]) -> IResult<&[u8], Trans2RecordParamSetFileInfoRename<'_>> { +pub fn parse_trans2_request_data_set_file_info_rename( + i: &[u8], +) -> IResult<&[u8], Trans2RecordParamSetFileInfoRename<'_>> { let (i, replace) = le_u8.parse(i)?; let (i, _reserved) = take(3_usize).parse(i)?; let (i, _root_dir) = take(4_usize).parse(i)?; let (i, newname_len) = le_u32.parse(i)?; let (i, newname) = take(newname_len).parse(i)?; let record = Trans2RecordParamSetFileInfoRename { - replace: replace==1, + replace: replace == 1, newname, }; Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] -pub struct Trans2RecordParamSetPathInfo<> { +#[derive(Debug, PartialEq, Eq)] +pub struct Trans2RecordParamSetPathInfo { pub loi: u16, pub oldname: Vec, } -pub fn parse_trans2_request_params_set_path_info(i: &[u8]) -> IResult<&[u8], Trans2RecordParamSetPathInfo, SmbError> { +pub fn parse_trans2_request_params_set_path_info( + i: &[u8], +) -> IResult<&[u8], Trans2RecordParamSetPathInfo, SmbError> { let (i, loi) = le_u16.parse(i)?; let (i, _reserved) = take(4_usize).parse(i)?; let (i, oldname) = smb_get_unicode_string(i)?; @@ -770,30 +813,32 @@ pub fn parse_trans2_request_params_set_path_info(i: &[u8]) -> IResult<&[u8], Tra Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Trans2RecordParamSetPathInfoRename<'a> { pub replace: bool, - pub newname: &'a[u8], + pub newname: &'a [u8], } -pub fn parse_trans2_request_data_set_path_info_rename(i: &[u8]) -> IResult<&[u8], Trans2RecordParamSetPathInfoRename<'_>> { +pub fn parse_trans2_request_data_set_path_info_rename( + i: &[u8], +) -> IResult<&[u8], Trans2RecordParamSetPathInfoRename<'_>> { let (i, replace) = le_u8.parse(i)?; let (i, _reserved) = take(3_usize).parse(i)?; let (i, _root_dir) = take(4_usize).parse(i)?; let (i, newname_len) = le_u32.parse(i)?; let (i, newname) = take(newname_len).parse(i)?; let record = Trans2RecordParamSetPathInfoRename { - replace: replace==1, - newname + replace: replace == 1, + newname, }; Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbRequestTrans2Record<'a> { pub subcmd: u16, - pub setup_blob: &'a[u8], - pub data_blob: &'a[u8], + pub setup_blob: &'a [u8], + pub data_blob: &'a [u8], } pub fn parse_smb_trans2_request_record(i: &[u8]) -> IResult<&[u8], SmbRequestTrans2Record<'_>> { @@ -818,23 +863,23 @@ pub fn parse_smb_trans2_request_record(i: &[u8]) -> IResult<&[u8], SmbRequestTra //TODO test and use param_offset let (i, _padding) = take(3_usize).parse(i)?; let (i, setup_blob) = take(param_cnt).parse(i)?; - let (i, _padding2) = cond( - data_offset > param_offset + param_cnt, - |b| take(data_offset - param_offset - param_cnt)(b) - ).parse(i)?; + let (i, _padding2) = cond(data_offset > param_offset + param_cnt, |b| { + take(data_offset - param_offset - param_cnt)(b) + }) + .parse(i)?; let (i, data_blob) = take(data_cnt).parse(i)?; let record = SmbRequestTrans2Record { subcmd, setup_blob, - data_blob + data_blob, }; Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbResponseCreateAndXRecord<'a> { - pub fid: &'a[u8], + pub fid: &'a [u8], pub create_ts: SMBFiletime, pub last_access_ts: SMBFiletime, pub last_write_ts: SMBFiletime, @@ -842,7 +887,9 @@ pub struct SmbResponseCreateAndXRecord<'a> { pub file_size: u64, } -pub fn parse_smb_create_andx_response_record(i: &[u8]) -> IResult<&[u8], SmbResponseCreateAndXRecord<'_>> { +pub fn parse_smb_create_andx_response_record( + i: &[u8], +) -> IResult<&[u8], SmbResponseCreateAndXRecord<'_>> { let (i, wct) = le_u8.parse(i)?; let (i, _andx_command) = le_u8.parse(i)?; let (i, _) = take(1_usize).parse(i)?; // reserved @@ -873,22 +920,20 @@ pub fn parse_smb_create_andx_response_record(i: &[u8]) -> IResult<&[u8], SmbResp Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbRequestCloseRecord<'a> { - pub fid: &'a[u8], + pub fid: &'a [u8], } pub fn parse_smb1_close_request_record(i: &[u8]) -> IResult<&[u8], SmbRequestCloseRecord<'_>> { let (i, _) = take(1_usize).parse(i)?; let (i, fid) = take(2_usize).parse(i)?; - let record = SmbRequestCloseRecord { - fid, - }; + let record = SmbRequestCloseRecord { fid }; Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] -pub struct SmbVersion<> { +#[derive(Debug, PartialEq, Eq)] +pub struct SmbVersion { pub version: u8, } @@ -899,7 +944,7 @@ pub fn parse_smb_version(i: &[u8]) -> IResult<&[u8], SmbVersion> { Ok((i, version)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbRecord<'a> { pub command: u8, pub is_dos_error: bool, @@ -914,7 +959,7 @@ pub struct SmbRecord<'a> { pub process_id: u32, pub ssn_id: u32, - pub data: &'a[u8], + pub data: &'a [u8], } impl SmbRecord<'_> { @@ -953,7 +998,7 @@ pub fn parse_smb_record(i: &[u8]) -> IResult<&[u8], SmbRecord<'_>> { nt_status, flags, flags2, - is_dos_error: (flags2 & 0x4000_u16 == 0),// && nt_status != 0), + is_dos_error: (flags2 & 0x4000_u16 == 0), // && nt_status != 0), tree_id, user_id, multiplex_id, @@ -970,7 +1015,7 @@ pub fn parse_smb_record(i: &[u8]) -> IResult<&[u8], SmbRecord<'_>> { fn test_parse_smb1_write_andx_request_record_origin() { let data = hex::decode("0eff000000014000000000ff00000008001400000014003f000000000014004142434445464748494a4b4c4d4e4f5051520a0a").unwrap(); let result = parse_smb1_write_andx_request_record(&data, SMB1_HEADER_SIZE); - assert!(result.is_ok()); + assert!(result.is_ok()); let record = result.unwrap().1; assert_eq!(record.offset, 0); assert_eq!(record.len, 20); diff --git a/rust/src/smb/smb1_session.rs b/rust/src/smb/smb1_session.rs index 0522239dee..849b259028 100644 --- a/rust/src/smb/smb1_session.rs +++ b/rust/src/smb/smb1_session.rs @@ -15,11 +15,11 @@ * 02110-1301, USA. */ -use crate::smb::smb_records::*; -use crate::smb::smb1_records::*; -use crate::smb::smb::*; -use crate::smb::events::*; use crate::smb::auth::*; +use crate::smb::events::*; +use crate::smb::smb::*; +use crate::smb::smb1_records::*; +use crate::smb::smb_records::*; #[derive(Debug)] pub struct SessionSetupResponse { @@ -27,22 +27,19 @@ pub struct SessionSetupResponse { pub native_lm: Vec, } -pub fn smb1_session_setup_response_host_info(r: &SmbRecord, blob: &[u8]) -> SessionSetupResponse -{ +pub fn smb1_session_setup_response_host_info(r: &SmbRecord, blob: &[u8]) -> SessionSetupResponse { if blob.len() > 1 && r.has_unicode_support() { let offset = r.data.len() - blob.len(); let blob = if offset % 2 == 1 { &blob[1..] } else { blob }; let (native_os, native_lm) = match smb_get_unicode_string(blob) { - Ok((rem, n1)) => { - match smb_get_unicode_string(rem) { - Ok((_, n2)) => (n1, n2), - _ => { (n1, Vec::new()) }, - } + Ok((rem, n1)) => match smb_get_unicode_string(rem) { + Ok((_, n2)) => (n1, n2), + _ => (n1, Vec::new()), }, - _ => { (Vec::new(), Vec::new()) }, + _ => (Vec::new(), Vec::new()), }; - SCLogDebug!("name1 {:?} name2 {:?}", native_os,native_lm); + SCLogDebug!("name1 {:?} name2 {:?}", native_os, native_lm); SessionSetupResponse { native_os, native_lm, @@ -50,13 +47,11 @@ pub fn smb1_session_setup_response_host_info(r: &SmbRecord, blob: &[u8]) -> Sess } else { SCLogDebug!("session_setup_response_host_info: not unicode"); let (native_os, native_lm) = match smb_get_ascii_string(blob) { - Ok((rem, n1)) => { - match smb_get_ascii_string(rem) { - Ok((_, n2)) => (n1, n2), - _ => { (n1, Vec::new()) }, - } + Ok((rem, n1)) => match smb_get_ascii_string(rem) { + Ok((_, n2)) => (n1, n2), + _ => (n1, Vec::new()), }, - _ => { (Vec::new(), Vec::new()) }, + _ => (Vec::new(), Vec::new()), }; SessionSetupResponse { native_os, @@ -65,14 +60,17 @@ pub fn smb1_session_setup_response_host_info(r: &SmbRecord, blob: &[u8]) -> Sess } } -pub fn smb1_session_setup_request(state: &mut SMBState, r: &SmbRecord, andx_offset: usize) -{ +pub fn smb1_session_setup_request(state: &mut SMBState, r: &SmbRecord, andx_offset: usize) { SCLogDebug!("SMB1_COMMAND_SESSION_SETUP_ANDX user_id {}", r.user_id); #[allow(clippy::single_match)] - match parse_smb_setup_andx_record(&r.data[andx_offset-SMB1_HEADER_SIZE..], r) { + match parse_smb_setup_andx_record(&r.data[andx_offset - SMB1_HEADER_SIZE..], r) { Ok((_rem, setup)) => { - let hdr = SMBCommonHdr::new(SMBHDR_TYPE_HEADER, - r.ssn_id as u64, 0, r.multiplex_id as u64); + let hdr = SMBCommonHdr::new( + SMBHDR_TYPE_HEADER, + r.ssn_id as u64, + 0, + r.multiplex_id as u64, + ); let tx = state.new_sessionsetup_tx(hdr); tx.vercmd.set_smb1_cmd(r.command); @@ -88,24 +86,23 @@ pub fn smb1_session_setup_request(state: &mut SMBState, r: &SmbRecord, andx_offs } } } - }, + } _ => { // events.push(SMBEvent::MalformedData); - }, + } } } -fn smb1_session_setup_update_tx(tx: &mut SMBTransaction, r: &SmbRecord, andx_offset: usize) -{ - match parse_smb_response_setup_andx_record(&r.data[andx_offset-SMB1_HEADER_SIZE..]) { +fn smb1_session_setup_update_tx(tx: &mut SMBTransaction, r: &SmbRecord, andx_offset: usize) { + match parse_smb_response_setup_andx_record(&r.data[andx_offset - SMB1_HEADER_SIZE..]) { Ok((rem, _setup)) => { if let Some(SMBTransactionTypeData::SESSIONSETUP(ref mut td)) = tx.type_data { td.response_host = Some(smb1_session_setup_response_host_info(r, rem)); } - }, + } _ => { tx.set_event(SMBEvent::MalformedData); - }, + } } // update tx even if we can't parse the response tx.hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_HEADER); // to overwrite ssn_id 0 @@ -113,25 +110,30 @@ fn smb1_session_setup_update_tx(tx: &mut SMBTransaction, r: &SmbRecord, andx_off tx.response_done = true; } -pub fn smb1_session_setup_response(state: &mut SMBState, r: &SmbRecord, andx_offset: usize) -{ +pub fn smb1_session_setup_response(state: &mut SMBState, r: &SmbRecord, andx_offset: usize) { // try exact match with session id already set (e.g. NTLMSSP AUTH phase) - let found = r.ssn_id != 0 && match state.get_sessionsetup_tx( - SMBCommonHdr::new(SMBHDR_TYPE_HEADER, - r.ssn_id as u64, 0, r.multiplex_id as u64)) - { - Some(tx) => { - smb1_session_setup_update_tx(tx, r, andx_offset); - SCLogDebug!("smb1_session_setup_response: tx {:?}", tx); - true - }, - None => { false }, - }; + let found = r.ssn_id != 0 + && match state.get_sessionsetup_tx(SMBCommonHdr::new( + SMBHDR_TYPE_HEADER, + r.ssn_id as u64, + 0, + r.multiplex_id as u64, + )) { + Some(tx) => { + smb1_session_setup_update_tx(tx, r, andx_offset); + SCLogDebug!("smb1_session_setup_response: tx {:?}", tx); + true + } + None => false, + }; // otherwise try match with ssn id 0 (e.g. NTLMSSP_NEGOTIATE) if !found { - if let Some(tx) = state.get_sessionsetup_tx( - SMBCommonHdr::new(SMBHDR_TYPE_HEADER, 0, 0, r.multiplex_id as u64)) - { + if let Some(tx) = state.get_sessionsetup_tx(SMBCommonHdr::new( + SMBHDR_TYPE_HEADER, + 0, + 0, + r.multiplex_id as u64, + )) { smb1_session_setup_update_tx(tx, r, andx_offset); SCLogDebug!("smb1_session_setup_response: tx {:?}", tx); } else { diff --git a/rust/src/smb/smb2.rs b/rust/src/smb/smb2.rs index 76c625fd3d..b8bd6b5720 100644 --- a/rust/src/smb/smb2.rs +++ b/rust/src/smb/smb2.rs @@ -18,59 +18,61 @@ use nom8::Err; use crate::direction::Direction; -use crate::smb::smb::*; -use crate::smb::smb2_records::*; -use crate::smb::smb2_session::*; -use crate::smb::smb2_ioctl::*; use crate::smb::dcerpc::*; use crate::smb::events::*; use crate::smb::files::*; +use crate::smb::smb::*; +use crate::smb::smb2_ioctl::*; +use crate::smb::smb2_records::*; +use crate::smb::smb2_session::*; use crate::smb::smb_status::*; -pub const SMB2_COMMAND_NEGOTIATE_PROTOCOL: u16 = 0; -pub const SMB2_COMMAND_SESSION_SETUP: u16 = 1; -pub const SMB2_COMMAND_SESSION_LOGOFF: u16 = 2; -pub const SMB2_COMMAND_TREE_CONNECT: u16 = 3; -pub const SMB2_COMMAND_TREE_DISCONNECT: u16 = 4; -pub const SMB2_COMMAND_CREATE: u16 = 5; -pub const SMB2_COMMAND_CLOSE: u16 = 6; -pub const SMB2_COMMAND_FLUSH: u16 = 7; -pub const SMB2_COMMAND_READ: u16 = 8; -pub const SMB2_COMMAND_WRITE: u16 = 9; -pub const SMB2_COMMAND_LOCK: u16 = 10; -pub const SMB2_COMMAND_IOCTL: u16 = 11; -pub const SMB2_COMMAND_CANCEL: u16 = 12; -pub const SMB2_COMMAND_KEEPALIVE: u16 = 13; -pub const SMB2_COMMAND_FIND: u16 = 14; -pub const SMB2_COMMAND_CHANGE_NOTIFY: u16 = 15; -pub const SMB2_COMMAND_GET_INFO: u16 = 16; -pub const SMB2_COMMAND_SET_INFO: u16 = 17; -pub const SMB2_COMMAND_OPLOCK_BREAK: u16 = 18; +pub const SMB2_COMMAND_NEGOTIATE_PROTOCOL: u16 = 0; +pub const SMB2_COMMAND_SESSION_SETUP: u16 = 1; +pub const SMB2_COMMAND_SESSION_LOGOFF: u16 = 2; +pub const SMB2_COMMAND_TREE_CONNECT: u16 = 3; +pub const SMB2_COMMAND_TREE_DISCONNECT: u16 = 4; +pub const SMB2_COMMAND_CREATE: u16 = 5; +pub const SMB2_COMMAND_CLOSE: u16 = 6; +pub const SMB2_COMMAND_FLUSH: u16 = 7; +pub const SMB2_COMMAND_READ: u16 = 8; +pub const SMB2_COMMAND_WRITE: u16 = 9; +pub const SMB2_COMMAND_LOCK: u16 = 10; +pub const SMB2_COMMAND_IOCTL: u16 = 11; +pub const SMB2_COMMAND_CANCEL: u16 = 12; +pub const SMB2_COMMAND_KEEPALIVE: u16 = 13; +pub const SMB2_COMMAND_FIND: u16 = 14; +pub const SMB2_COMMAND_CHANGE_NOTIFY: u16 = 15; +pub const SMB2_COMMAND_GET_INFO: u16 = 16; +pub const SMB2_COMMAND_SET_INFO: u16 = 17; +pub const SMB2_COMMAND_OPLOCK_BREAK: u16 = 18; pub fn smb2_command_string(c: u16) -> String { match c { - SMB2_COMMAND_NEGOTIATE_PROTOCOL => "SMB2_COMMAND_NEGOTIATE_PROTOCOL", - SMB2_COMMAND_SESSION_SETUP => "SMB2_COMMAND_SESSION_SETUP", - SMB2_COMMAND_SESSION_LOGOFF => "SMB2_COMMAND_SESSION_LOGOFF", - SMB2_COMMAND_TREE_CONNECT => "SMB2_COMMAND_TREE_CONNECT", - SMB2_COMMAND_TREE_DISCONNECT => "SMB2_COMMAND_TREE_DISCONNECT", - SMB2_COMMAND_CREATE => "SMB2_COMMAND_CREATE", - SMB2_COMMAND_CLOSE => "SMB2_COMMAND_CLOSE", - SMB2_COMMAND_READ => "SMB2_COMMAND_READ", - SMB2_COMMAND_FLUSH => "SMB2_COMMAND_FLUSH", - SMB2_COMMAND_WRITE => "SMB2_COMMAND_WRITE", - SMB2_COMMAND_LOCK => "SMB2_COMMAND_LOCK", - SMB2_COMMAND_IOCTL => "SMB2_COMMAND_IOCTL", - SMB2_COMMAND_CANCEL => "SMB2_COMMAND_CANCEL", - SMB2_COMMAND_KEEPALIVE => "SMB2_COMMAND_KEEPALIVE", - SMB2_COMMAND_FIND => "SMB2_COMMAND_FIND", - SMB2_COMMAND_CHANGE_NOTIFY => "SMB2_COMMAND_CHANGE_NOTIFY", - SMB2_COMMAND_GET_INFO => "SMB2_COMMAND_GET_INFO", - SMB2_COMMAND_SET_INFO => "SMB2_COMMAND_SET_INFO", - SMB2_COMMAND_OPLOCK_BREAK => "SMB2_COMMAND_OPLOCK_BREAK", - _ => { return (c).to_string(); }, - }.to_string() - + SMB2_COMMAND_NEGOTIATE_PROTOCOL => "SMB2_COMMAND_NEGOTIATE_PROTOCOL", + SMB2_COMMAND_SESSION_SETUP => "SMB2_COMMAND_SESSION_SETUP", + SMB2_COMMAND_SESSION_LOGOFF => "SMB2_COMMAND_SESSION_LOGOFF", + SMB2_COMMAND_TREE_CONNECT => "SMB2_COMMAND_TREE_CONNECT", + SMB2_COMMAND_TREE_DISCONNECT => "SMB2_COMMAND_TREE_DISCONNECT", + SMB2_COMMAND_CREATE => "SMB2_COMMAND_CREATE", + SMB2_COMMAND_CLOSE => "SMB2_COMMAND_CLOSE", + SMB2_COMMAND_READ => "SMB2_COMMAND_READ", + SMB2_COMMAND_FLUSH => "SMB2_COMMAND_FLUSH", + SMB2_COMMAND_WRITE => "SMB2_COMMAND_WRITE", + SMB2_COMMAND_LOCK => "SMB2_COMMAND_LOCK", + SMB2_COMMAND_IOCTL => "SMB2_COMMAND_IOCTL", + SMB2_COMMAND_CANCEL => "SMB2_COMMAND_CANCEL", + SMB2_COMMAND_KEEPALIVE => "SMB2_COMMAND_KEEPALIVE", + SMB2_COMMAND_FIND => "SMB2_COMMAND_FIND", + SMB2_COMMAND_CHANGE_NOTIFY => "SMB2_COMMAND_CHANGE_NOTIFY", + SMB2_COMMAND_GET_INFO => "SMB2_COMMAND_GET_INFO", + SMB2_COMMAND_SET_INFO => "SMB2_COMMAND_SET_INFO", + SMB2_COMMAND_OPLOCK_BREAK => "SMB2_COMMAND_OPLOCK_BREAK", + _ => { + return (c).to_string(); + } + } + .to_string() } pub fn smb2_dialect_string(d: u16) -> String { @@ -84,24 +86,25 @@ pub fn smb2_dialect_string(d: u16) -> String { 0x0302 => "3.02", 0x0310 => "3.10", 0x0311 => "3.11", - _ => { return (d).to_string(); }, - }.to_string() + _ => { + return (d).to_string(); + } + } + .to_string() } // later we'll use this to determine if we need to // track a ssn per type fn smb2_create_new_tx(cmd: u16) -> bool { match cmd { - SMB2_COMMAND_READ | - SMB2_COMMAND_WRITE | - SMB2_COMMAND_GET_INFO | - SMB2_COMMAND_SET_INFO => { false }, - _ => { true }, + SMB2_COMMAND_READ | SMB2_COMMAND_WRITE | SMB2_COMMAND_GET_INFO | SMB2_COMMAND_SET_INFO => { + false + } + _ => true, } } -fn smb2_read_response_record_generic(state: &mut SMBState, r: &Smb2Record) -{ +fn smb2_read_response_record_generic(state: &mut SMBState, r: &Smb2Record) { if smb2_create_new_tx(r.command) { let tx_hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_GENERICTX); let tx = state.get_generic_tx(2, r.command, &tx_hdr); @@ -112,8 +115,7 @@ fn smb2_read_response_record_generic(state: &mut SMBState, r: &Smb2Record) } } -pub fn smb2_read_response_record(state: &mut SMBState, r: &Smb2Record, nbss_remaining: u32) -{ +pub fn smb2_read_response_record(state: &mut SMBState, r: &Smb2Record, nbss_remaining: u32) { let max_queue_size = unsafe { SMB_CFG_MAX_READ_QUEUE_SIZE }; let max_queue_cnt = unsafe { SMB_CFG_MAX_READ_QUEUE_CNT }; @@ -131,15 +133,14 @@ pub fn smb2_read_response_record(state: &mut SMBState, r: &Smb2Record, nbss_rema if r.nt_status == SMB_NTSTATUS_BUFFER_OVERFLOW { SCLogDebug!("SMBv2/READ: incomplete record, expecting a follow up"); // fall through - } else if r.nt_status != SMB_NTSTATUS_SUCCESS { SCLogDebug!("SMBv2: read response error code received: skip record"); state.set_skip(Direction::ToClient, nbss_remaining); return; } - if (state.max_read_size != 0 && rd.len > state.max_read_size) || - (unsafe { SMB_CFG_MAX_READ_SIZE != 0 && SMB_CFG_MAX_READ_SIZE < rd.len }) + if (state.max_read_size != 0 && rd.len > state.max_read_size) + || (unsafe { SMB_CFG_MAX_READ_SIZE != 0 && SMB_CFG_MAX_READ_SIZE < rd.len }) { state.set_event(SMBEvent::ReadResponseTooLarge); state.set_skip(Direction::ToClient, nbss_remaining); @@ -154,31 +155,44 @@ pub fn smb2_read_response_record(state: &mut SMBState, r: &Smb2Record, nbss_rema let (offset, file_guid) = match state.read_offset_cache.pop(&guid_key) { Some(o) => (o.offset, o.guid), None => { - SCLogDebug!("SMBv2 READ response: reply to unknown request {:?}",rd); + SCLogDebug!("SMBv2 READ response: reply to unknown request {:?}", rd); state.set_skip(Direction::ToClient, nbss_remaining); return; - }, + } }; SCLogDebug!("SMBv2 READ: GUID {:?} offset {}", file_guid, offset); let mut set_event_fileoverlap = false; // look up existing tracker and if we have it update it - let found = if let Some(tx) = state.get_file_tx_by_fuid_with_open_file(&file_guid, Direction::ToClient) { + let found = if let Some(tx) = + state.get_file_tx_by_fuid_with_open_file(&file_guid, Direction::ToClient) + { if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { - let file_id : u32 = tx.id as u32; + let file_id: u32 = tx.id as u32; if offset < tdf.file_tracker.tracked { set_event_fileoverlap = true; } - if max_queue_size != 0 && tdf.file_tracker.get_inflight_size() + rd.len as u64 > u64::from(max_queue_size) { + if max_queue_size != 0 + && tdf.file_tracker.get_inflight_size() + rd.len as u64 + > u64::from(max_queue_size) + { state.set_event(SMBEvent::ReadQueueSizeExceeded); state.set_skip(Direction::ToClient, nbss_remaining); - } else if max_queue_cnt != 0 && tdf.file_tracker.get_inflight_cnt() >= max_queue_cnt as usize { + } else if max_queue_cnt != 0 + && tdf.file_tracker.get_inflight_cnt() >= max_queue_cnt as usize + { state.set_event(SMBEvent::ReadQueueCntExceeded); state.set_skip(Direction::ToClient, nbss_remaining); } else { - filetracker_newchunk(&mut tdf.file_tracker, - &tdf.file_name, rd.data, offset, - rd.len, false, &file_id); + filetracker_newchunk( + &mut tdf.file_tracker, + &tdf.file_name, + rd.data, + offset, + rd.len, + false, + &file_id, + ); } } true @@ -190,15 +204,19 @@ pub fn smb2_read_response_record(state: &mut SMBState, r: &Smb2Record, nbss_rema let tree_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_SHARE); let (share_name, mut is_pipe) = match state.ssn2tree_cache.get(&tree_key) { Some(n) => (n.name.to_vec(), n.is_pipe), - _ => { (Vec::new(), false) }, + _ => (Vec::new(), false), }; let mut is_dcerpc = if is_pipe || share_name.is_empty() { state.get_service_for_guid(&file_guid).1 } else { false }; - SCLogDebug!("SMBv2/READ: share_name {:?} is_pipe {} is_dcerpc {}", - share_name, is_pipe, is_dcerpc); + SCLogDebug!( + "SMBv2/READ: share_name {:?} is_pipe {} is_dcerpc {}", + share_name, + is_pipe, + is_dcerpc + ); if share_name.is_empty() && !is_pipe { SCLogDebug!("SMBv2/READ: no tree connect seen, we don't know if we are a pipe"); @@ -209,7 +227,9 @@ pub fn smb2_read_response_record(state: &mut SMBState, r: &Smb2Record, nbss_rema let tree = SMBTree::new(b"suricata::dcerpc".to_vec(), true); state.ssn2tree_cache.put(tree_key, tree); if !is_dcerpc { - _ = state.guid2name_cache.put(file_guid.to_vec(), b"suricata::dcerpc".to_vec()); + _ = state + .guid2name_cache + .put(file_guid.to_vec(), b"suricata::dcerpc".to_vec()); } is_pipe = true; is_dcerpc = true; @@ -228,30 +248,40 @@ pub fn smb2_read_response_record(state: &mut SMBState, r: &Smb2Record, nbss_rema state.set_skip(Direction::ToClient, nbss_remaining); } else { let file_name = match state.guid2name_cache.get(&file_guid) { - Some(n) => { n.to_vec() } - None => { b"".to_vec() } + Some(n) => n.to_vec(), + None => b"".to_vec(), }; let tx = state.new_file_tx(&file_guid, &file_name, Direction::ToClient); tx.vercmd.set_smb2_cmd(SMB2_COMMAND_READ); - tx.hdr = SMBCommonHdr::new(SMBHDR_TYPE_HEADER, - r.session_id, r.tree_id, 0); // TODO move into new_file_tx + tx.hdr = SMBCommonHdr::new(SMBHDR_TYPE_HEADER, r.session_id, r.tree_id, 0); // TODO move into new_file_tx if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { tdf.share_name = share_name; - let file_id : u32 = tx.id as u32; + let file_id: u32 = tx.id as u32; if offset < tdf.file_tracker.tracked { set_event_fileoverlap = true; } - if max_queue_size != 0 && tdf.file_tracker.get_inflight_size() + rd.len as u64 > u64::from(max_queue_size) { + if max_queue_size != 0 + && tdf.file_tracker.get_inflight_size() + rd.len as u64 + > u64::from(max_queue_size) + { state.set_event(SMBEvent::ReadQueueSizeExceeded); state.set_skip(Direction::ToClient, nbss_remaining); - } else if max_queue_cnt != 0 && tdf.file_tracker.get_inflight_cnt() >= max_queue_cnt as usize { + } else if max_queue_cnt != 0 + && tdf.file_tracker.get_inflight_cnt() >= max_queue_cnt as usize + { state.set_event(SMBEvent::ReadQueueCntExceeded); state.set_skip(Direction::ToClient, nbss_remaining); } else { - filetracker_newchunk(&mut tdf.file_tracker, - &file_name, rd.data, offset, - rd.len, false, &file_id); + filetracker_newchunk( + &mut tdf.file_tracker, + &file_name, + rd.data, + offset, + rd.len, + false, + &file_id, + ); } } } @@ -260,7 +290,12 @@ pub fn smb2_read_response_record(state: &mut SMBState, r: &Smb2Record, nbss_rema if set_event_fileoverlap { state.set_event(SMBEvent::FileOverlap); } - state.set_file_left(Direction::ToClient, rd.len, rd.data.len() as u32, file_guid.to_vec()); + state.set_file_left( + Direction::ToClient, + rd.len, + rd.data.len() as u32, + file_guid.to_vec(), + ); } _ => { SCLogDebug!("SMBv2: failed to parse read response"); @@ -269,8 +304,7 @@ pub fn smb2_read_response_record(state: &mut SMBState, r: &Smb2Record, nbss_rema } } -pub fn smb2_write_request_record(state: &mut SMBState, r: &Smb2Record, nbss_remaining: u32) -{ +pub fn smb2_write_request_record(state: &mut SMBState, r: &Smb2Record, nbss_remaining: u32) { let max_queue_size = unsafe { SMB_CFG_MAX_WRITE_QUEUE_SIZE }; let max_queue_cnt = unsafe { SMB_CFG_MAX_WRITE_QUEUE_CNT }; @@ -289,8 +323,9 @@ pub fn smb2_write_request_record(state: &mut SMBState, r: &Smb2Record, nbss_rema state.set_skip(Direction::ToServer, nbss_remaining); return; } - if (state.max_write_size != 0 && wr.wr_len > state.max_write_size) || - (unsafe { SMB_CFG_MAX_WRITE_SIZE != 0 && SMB_CFG_MAX_WRITE_SIZE < wr.wr_len }) { + if (state.max_write_size != 0 && wr.wr_len > state.max_write_size) + || (unsafe { SMB_CFG_MAX_WRITE_SIZE != 0 && SMB_CFG_MAX_WRITE_SIZE < wr.wr_len }) + { state.set_event(SMBEvent::WriteRequestTooLarge); state.set_skip(Direction::ToServer, nbss_remaining); return; @@ -307,22 +342,35 @@ pub fn smb2_write_request_record(state: &mut SMBState, r: &Smb2Record, nbss_rema }; let mut set_event_fileoverlap = false; - let found = if let Some(tx) = state.get_file_tx_by_fuid_with_open_file(&file_guid, Direction::ToServer) { + let found = if let Some(tx) = + state.get_file_tx_by_fuid_with_open_file(&file_guid, Direction::ToServer) + { if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { - let file_id : u32 = tx.id as u32; + let file_id: u32 = tx.id as u32; if wr.wr_offset < tdf.file_tracker.tracked { set_event_fileoverlap = true; } - if max_queue_size != 0 && tdf.file_tracker.get_inflight_size() + wr.wr_len as u64 > u64::from(max_queue_size) { + if max_queue_size != 0 + && tdf.file_tracker.get_inflight_size() + wr.wr_len as u64 + > u64::from(max_queue_size) + { state.set_event(SMBEvent::WriteQueueSizeExceeded); state.set_skip(Direction::ToServer, nbss_remaining); - } else if max_queue_cnt != 0 && tdf.file_tracker.get_inflight_cnt() >= max_queue_cnt as usize { + } else if max_queue_cnt != 0 + && tdf.file_tracker.get_inflight_cnt() >= max_queue_cnt as usize + { state.set_event(SMBEvent::WriteQueueCntExceeded); state.set_skip(Direction::ToServer, nbss_remaining); } else { - filetracker_newchunk(&mut tdf.file_tracker, - &file_name, wr.data, wr.wr_offset, - wr.wr_len, false, &file_id); + filetracker_newchunk( + &mut tdf.file_tracker, + &file_name, + wr.data, + wr.wr_offset, + wr.wr_len, + false, + &file_id, + ); } } true @@ -332,20 +380,26 @@ pub fn smb2_write_request_record(state: &mut SMBState, r: &Smb2Record, nbss_rema if !found { let tree_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_SHARE); let (share_name, mut is_pipe) = match state.ssn2tree_cache.get(&tree_key) { - Some(n) => { (n.name.to_vec(), n.is_pipe) }, - _ => { (Vec::new(), false) }, + Some(n) => (n.name.to_vec(), n.is_pipe), + _ => (Vec::new(), false), }; let mut is_dcerpc = if is_pipe || share_name.is_empty() { state.get_service_for_guid(wr.guid).1 } else { false }; - SCLogDebug!("SMBv2/WRITE: share_name {:?} is_pipe {} is_dcerpc {}", - share_name, is_pipe, is_dcerpc); + SCLogDebug!( + "SMBv2/WRITE: share_name {:?} is_pipe {} is_dcerpc {}", + share_name, + is_pipe, + is_dcerpc + ); // if we missed the TREE connect we can't be sure if 'is_dcerpc' is correct if share_name.is_empty() && !is_pipe { - SCLogDebug!("SMBv2/WRITE: no tree connect seen, we don't know if we are a pipe"); + SCLogDebug!( + "SMBv2/WRITE: no tree connect seen, we don't know if we are a pipe" + ); if smb_dcerpc_probe(wr.data) { SCLogDebug!("SMBv2/WRITE: looks like we have dcerpc"); @@ -353,8 +407,9 @@ pub fn smb2_write_request_record(state: &mut SMBState, r: &Smb2Record, nbss_rema let tree = SMBTree::new(b"suricata::dcerpc".to_vec(), true); state.ssn2tree_cache.put(tree_key, tree); if !is_dcerpc { - _ = state.guid2name_cache.put(file_guid.to_vec(), - b"suricata::dcerpc".to_vec()); + _ = state + .guid2name_cache + .put(file_guid.to_vec(), b"suricata::dcerpc".to_vec()); } is_pipe = true; is_dcerpc = true; @@ -373,24 +428,34 @@ pub fn smb2_write_request_record(state: &mut SMBState, r: &Smb2Record, nbss_rema } else { let tx = state.new_file_tx(&file_guid, &file_name, Direction::ToServer); tx.vercmd.set_smb2_cmd(SMB2_COMMAND_WRITE); - tx.hdr = SMBCommonHdr::new(SMBHDR_TYPE_HEADER, - r.session_id, r.tree_id, 0); // TODO move into new_file_tx + tx.hdr = SMBCommonHdr::new(SMBHDR_TYPE_HEADER, r.session_id, r.tree_id, 0); // TODO move into new_file_tx if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { - let file_id : u32 = tx.id as u32; + let file_id: u32 = tx.id as u32; if wr.wr_offset < tdf.file_tracker.tracked { set_event_fileoverlap = true; } - if max_queue_size != 0 && tdf.file_tracker.get_inflight_size() + wr.wr_len as u64 > u64::from(max_queue_size) { + if max_queue_size != 0 + && tdf.file_tracker.get_inflight_size() + wr.wr_len as u64 + > u64::from(max_queue_size) + { state.set_event(SMBEvent::WriteQueueSizeExceeded); state.set_skip(Direction::ToServer, nbss_remaining); - } else if max_queue_cnt != 0 && tdf.file_tracker.get_inflight_cnt() >= max_queue_cnt as usize { + } else if max_queue_cnt != 0 + && tdf.file_tracker.get_inflight_cnt() >= max_queue_cnt as usize + { state.set_event(SMBEvent::WriteQueueCntExceeded); state.set_skip(Direction::ToServer, nbss_remaining); } else { - filetracker_newchunk(&mut tdf.file_tracker, - &file_name, wr.data, wr.wr_offset, - wr.wr_len, false, &file_id); + filetracker_newchunk( + &mut tdf.file_tracker, + &file_name, + wr.data, + wr.wr_offset, + wr.wr_len, + false, + &file_id, + ); } } } @@ -399,20 +464,28 @@ pub fn smb2_write_request_record(state: &mut SMBState, r: &Smb2Record, nbss_rema if set_event_fileoverlap { state.set_event(SMBEvent::FileOverlap); } - state.set_file_left(Direction::ToServer, wr.wr_len, wr.data.len() as u32, file_guid.to_vec()); - }, + state.set_file_left( + Direction::ToServer, + wr.wr_len, + wr.data.len() as u32, + file_guid.to_vec(), + ); + } _ => { state.set_event(SMBEvent::MalformedData); - }, + } } } -pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record) -{ - SCLogDebug!("SMBv2 request record, command {} tree {} session {}", - &smb2_command_string(r.command), r.tree_id, r.session_id); +pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record) { + SCLogDebug!( + "SMBv2 request record, command {} tree {} session {}", + &smb2_command_string(r.command), + r.tree_id, + r.session_id + ); - let mut events : Vec = Vec::new(); + let mut events: Vec = Vec::new(); let have_tx = match r.command { SMB2_COMMAND_SET_INFO => { @@ -425,10 +498,10 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record) Smb2SetInfoRequestData::RENAME(ref ren) => { let tx_hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_GENERICTX); let mut newname = ren.name.to_vec(); - newname.retain(|&i|i != 0x00); + newname.retain(|&i| i != 0x00); let oldname = match state.guid2name_cache.get(rd.guid) { - Some(n) => { n.to_vec() }, - None => { b"".to_vec() }, + Some(n) => n.to_vec(), + None => b"".to_vec(), }; let tx = state.new_rename_tx(rd.guid.to_vec(), oldname, newname); tx.hdr = tx_hdr; @@ -439,22 +512,29 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record) Smb2SetInfoRequestData::DISPOSITION(ref dis) => { let tx_hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_GENERICTX); let fname = match state.guid2name_cache.get(rd.guid) { - Some(n) => { n.to_vec() }, + Some(n) => n.to_vec(), None => { // try to find latest created file in case of chained commands - let mut guid_key = SMBCommonHdr::from2_notree(r, SMBHDR_TYPE_FILENAME); + let mut guid_key = + SMBCommonHdr::from2_notree(r, SMBHDR_TYPE_FILENAME); if guid_key.msg_id == 0 { b"".to_vec() } else { guid_key.msg_id -= 1; match state.ssn2vec_cache.get(&guid_key) { - Some(n) => { n.to_vec() }, - None => { b"".to_vec()}, + Some(n) => n.to_vec(), + None => b"".to_vec(), } } - }, + } }; - let tx = state.new_setfileinfo_tx(fname, rd.guid.to_vec(), rd.class as u16, rd.infolvl as u16, dis.delete); + let tx = state.new_setfileinfo_tx( + fname, + rd.guid.to_vec(), + rd.class as u16, + rd.infolvl as u16, + dis.delete, + ); tx.hdr = tx_hdr; tx.request_done = true; tx.vercmd.set_smb2_cmd(SMB2_COMMAND_SET_INFO); @@ -462,25 +542,24 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record) } _ => false, } - }, + } Err(Err::Incomplete(_n)) => { SCLogDebug!("SMB2_COMMAND_SET_INFO: {:?}", _n); events.push(SMBEvent::MalformedData); false - }, - Err(Err::Error(_e)) | - Err(Err::Failure(_e)) => { + } + Err(Err::Error(_e)) | Err(Err::Failure(_e)) => { SCLogDebug!("SMB2_COMMAND_SET_INFO: {:?}", _e); events.push(SMBEvent::MalformedData); false - }, + } }; have_si_tx - }, + } SMB2_COMMAND_IOCTL => { smb2_ioctl_request_record(state, r); true - }, + } SMB2_COMMAND_TREE_DISCONNECT => { let tree_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_SHARE); state.ssn2tree_cache.pop(&tree_key); @@ -488,7 +567,7 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record) } SMB2_COMMAND_NEGOTIATE_PROTOCOL => { if let Ok((_, rd)) = parse_smb2_request_negotiate_protocol(r.data) { - let mut dialects : Vec> = Vec::new(); + let mut dialects: Vec> = Vec::new(); for d in rd.dialects_vec { SCLogDebug!("dialect {:x} => {}", d, &smb2_dialect_string(d)); let dvec = smb2_dialect_string(d).as_bytes().to_vec(); @@ -508,16 +587,16 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record) events.push(SMBEvent::MalformedData); false } - }, + } SMB2_COMMAND_SESSION_SETUP => { smb2_session_setup_request(state, r); true - }, + } SMB2_COMMAND_TREE_CONNECT => { if let Ok((_, tr)) = parse_smb2_request_tree_connect(r.data) { let name_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_TREE); let mut name_val = tr.share_name.to_vec(); - name_val.retain(|&i|i != 0x00); + name_val.retain(|&i| i != 0x00); if name_val.len() > 1 { name_val = name_val[1..].to_vec(); } @@ -530,26 +609,31 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record) events.push(SMBEvent::MalformedData); false } - }, + } SMB2_COMMAND_READ => { if let Ok((_, rd)) = parse_smb2_request_read(r.data) { - if (state.max_read_size != 0 && rd.rd_len > state.max_read_size) || - (unsafe { SMB_CFG_MAX_READ_SIZE != 0 && SMB_CFG_MAX_READ_SIZE < rd.rd_len }) { - events.push(SMBEvent::ReadRequestTooLarge); - } else { - SCLogDebug!("SMBv2 READ: GUID {:?} requesting {} bytes at offset {}", - rd.guid, rd.rd_len, rd.rd_offset); - - // store read guid,offset in map - let guid_key = SMBCommonHdr::from2_notree(r, SMBHDR_TYPE_OFFSET); - let guidoff = SMBFileGUIDOffset::new(rd.guid.to_vec(), rd.rd_offset); - state.read_offset_cache.put(guid_key, guidoff); + if (state.max_read_size != 0 && rd.rd_len > state.max_read_size) + || (unsafe { SMB_CFG_MAX_READ_SIZE != 0 && SMB_CFG_MAX_READ_SIZE < rd.rd_len }) + { + events.push(SMBEvent::ReadRequestTooLarge); + } else { + SCLogDebug!( + "SMBv2 READ: GUID {:?} requesting {} bytes at offset {}", + rd.guid, + rd.rd_len, + rd.rd_offset + ); + + // store read guid,offset in map + let guid_key = SMBCommonHdr::from2_notree(r, SMBHDR_TYPE_OFFSET); + let guidoff = SMBFileGUIDOffset::new(rd.guid.to_vec(), rd.rd_offset); + state.read_offset_cache.put(guid_key, guidoff); } } else { events.push(SMBEvent::MalformedData); } false - }, + } SMB2_COMMAND_CREATE => { if let Ok((_, cr)) = parse_smb2_request_create(r.data) { let del = cr.create_options & 0x0000_1000 != 0; @@ -568,41 +652,43 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record) events.push(SMBEvent::MalformedData); false } - }, + } SMB2_COMMAND_WRITE => { smb2_write_request_record(state, r, 0); true // write handling creates both file tx and generic tx - }, + } SMB2_COMMAND_CLOSE => { if let Ok((_, cd)) = parse_smb2_request_close(r.data) { let _name = state.guid2name_cache.pop(cd.guid); - let found_ts = if let Some(tx) = state.get_file_tx_by_fuid(cd.guid, Direction::ToServer) { - if !tx.request_done { - if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { - filetracker_close(&mut tdf.file_tracker); + let found_ts = + if let Some(tx) = state.get_file_tx_by_fuid(cd.guid, Direction::ToServer) { + if !tx.request_done { + if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { + filetracker_close(&mut tdf.file_tracker); + } } - } - tx.request_done = true; - tx.response_done = true; - tx.set_status(SMB_NTSTATUS_SUCCESS, false); - true - } else { - false - }; - let found_tc = if let Some(tx) = state.get_file_tx_by_fuid(cd.guid, Direction::ToClient) { - if !tx.request_done { - if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { - filetracker_close(&mut tdf.file_tracker); + tx.request_done = true; + tx.response_done = true; + tx.set_status(SMB_NTSTATUS_SUCCESS, false); + true + } else { + false + }; + let found_tc = + if let Some(tx) = state.get_file_tx_by_fuid(cd.guid, Direction::ToClient) { + if !tx.request_done { + if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { + filetracker_close(&mut tdf.file_tracker); + } } - } - tx.request_done = true; - tx.response_done = true; - tx.set_status(SMB_NTSTATUS_SUCCESS, false); - true - } else { - false - }; + tx.request_done = true; + tx.response_done = true; + tx.set_status(SMB_NTSTATUS_SUCCESS, false); + true + } else { + false + }; if !found_ts && !found_tc { SCLogDebug!("SMBv2: CLOSE(TS): no TX at GUID {:?}", cd.guid); } @@ -610,46 +696,54 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record) events.push(SMBEvent::MalformedData); } false - }, - _ => { - false - }, + } + _ => false, }; /* if we don't have a tx, create it here (maybe) */ if !have_tx && smb2_create_new_tx(r.command) { let tx_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_GENERICTX); let tx = state.new_generic_tx(2, r.command, tx_key); - SCLogDebug!("TS TX {} command {} created with session_id {} tree_id {} message_id {}", - tx.id, r.command, r.session_id, r.tree_id, r.message_id); + SCLogDebug!( + "TS TX {} command {} created with session_id {} tree_id {} message_id {}", + tx.id, + r.command, + r.session_id, + r.tree_id, + r.message_id + ); tx.set_events(events); } } -pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record) -{ - SCLogDebug!("SMBv2 response record, command {} status {} tree {} session {} message {}", - &smb2_command_string(r.command), r.nt_status, - r.tree_id, r.session_id, r.message_id); +pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record) { + SCLogDebug!( + "SMBv2 response record, command {} status {} tree {} session {} message {}", + &smb2_command_string(r.command), + r.nt_status, + r.tree_id, + r.session_id, + r.message_id + ); - let mut events : Vec = Vec::new(); + let mut events: Vec = Vec::new(); let have_tx = match r.command { SMB2_COMMAND_IOCTL => { smb2_ioctl_response_record(state, r); true - }, + } SMB2_COMMAND_SESSION_SETUP => { smb2_session_setup_response(state, r); true - }, + } SMB2_COMMAND_WRITE => { if r.nt_status == SMB_NTSTATUS_SUCCESS { if let Ok((_, _wr)) = parse_smb2_response_write(r.data) { SCLogDebug!("SMBv2: Write response => {:?}", _wr); /* search key-guid map */ - let guid_key = SMBCommonHdr::new(SMBHDR_TYPE_GUID, - r.session_id, r.tree_id, r.message_id); + let guid_key = + SMBCommonHdr::new(SMBHDR_TYPE_GUID, r.session_id, r.tree_id, r.message_id); let _guid_vec = state.ssn2vec_cache.pop(&guid_key).unwrap_or_default(); SCLogDebug!("SMBv2 write response for GUID {:?}", _guid_vec); } else { @@ -657,10 +751,9 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record) } } false // the request may have created a generic tx, so handle that here - }, + } SMB2_COMMAND_READ => { - if r.nt_status == SMB_NTSTATUS_SUCCESS || - r.nt_status == SMB_NTSTATUS_BUFFER_OVERFLOW { + if r.nt_status == SMB_NTSTATUS_SUCCESS || r.nt_status == SMB_NTSTATUS_BUFFER_OVERFLOW { smb2_read_response_record(state, r, 0); } else if r.nt_status == SMB_NTSTATUS_END_OF_FILE { SCLogDebug!("SMBv2: read response => EOF"); @@ -685,7 +778,7 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record) SCLogDebug!("SMBv2 READ: status {}", r.nt_status); } false - }, + } SMB2_COMMAND_CREATE => { if r.nt_status == SMB_NTSTATUS_SUCCESS { if let Ok((_, cr)) = parse_smb2_response_create(r.data) { @@ -693,7 +786,7 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record) let guid_key = SMBCommonHdr::from2_notree(r, SMBHDR_TYPE_FILENAME); if let Some(mut p) = state.ssn2vec_cache.pop(&guid_key) { - p.retain(|&i|i != 0x00); + p.retain(|&i| i != 0x00); _ = state.guid2name_cache.put(cr.guid.to_vec(), p); } else { SCLogDebug!("SMBv2 response: GUID NOT FOUND"); @@ -701,8 +794,12 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record) let tx_hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_GENERICTX); if let Some(tx) = state.get_generic_tx(2, r.command, &tx_hdr) { - SCLogDebug!("tx {} with {}/{} marked as done", - tx.id, r.command, &smb2_command_string(r.command)); + SCLogDebug!( + "tx {} with {}/{} marked as done", + tx.id, + r.command, + &smb2_command_string(r.command) + ); tx.set_status(r.nt_status, false); tx.response_done = true; @@ -722,7 +819,7 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record) } else { false } - }, + } SMB2_COMMAND_TREE_DISCONNECT => { // normally removed when processing request, // but in case we missed that try again here @@ -738,7 +835,9 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record) let is_pipe = tr.share_type == 2; let found = match state.get_treeconnect_tx(name_key) { Some(tx) => { - if let Some(SMBTransactionTypeData::TREECONNECT(ref mut tdn)) = tx.type_data { + if let Some(SMBTransactionTypeData::TREECONNECT(ref mut tdn)) = + tx.type_data + { tdn.share_type = tr.share_type; tdn.is_pipe = is_pipe; tdn.tree_id = r.tree_id; @@ -749,8 +848,8 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record) tx.response_done = true; tx.set_status(r.nt_status, false); true - }, - None => { false }, + } + None => false, }; if found { let tree = SMBTree::new(share_name.to_vec(), is_pipe); @@ -772,7 +871,7 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record) false } } - }, + } SMB2_COMMAND_NEGOTIATE_PROTOCOL => { let res = if r.nt_status == SMB_NTSTATUS_SUCCESS { parse_smb2_response_negotiate_protocol(r.data) @@ -803,52 +902,63 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record) tx.set_status(r.nt_status, false); tx.response_done = true; true - }, - None => { false }, + } + None => false, }; // SMB2 response to SMB1 request? - let found1 = !found2 && match state.get_negotiate_tx(1) { - Some(tx) => { - if let Some(SMBTransactionTypeData::NEGOTIATE(ref mut tdn)) = tx.type_data { - tdn.server_guid = rd.server_guid.to_vec(); + let found1 = !found2 + && match state.get_negotiate_tx(1) { + Some(tx) => { + if let Some(SMBTransactionTypeData::NEGOTIATE(ref mut tdn)) = + tx.type_data + { + tdn.server_guid = rd.server_guid.to_vec(); + } + tx.set_status(r.nt_status, false); + tx.response_done = true; + true } - tx.set_status(r.nt_status, false); - tx.response_done = true; - true - }, - None => { false }, - }; + None => false, + }; found1 || found2 } else { events.push(SMBEvent::MalformedData); false } - }, + } _ => { SCLogDebug!("default case: no TX"); false - }, + } }; if !have_tx { let tx_hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_GENERICTX); - SCLogDebug!("looking for TX {} with session_id {} tree_id {} message_id {}", - &smb2_command_string(r.command), - r.session_id, r.tree_id, r.message_id); + SCLogDebug!( + "looking for TX {} with session_id {} tree_id {} message_id {}", + &smb2_command_string(r.command), + r.session_id, + r.tree_id, + r.message_id + ); let _found = match state.get_generic_tx(2, r.command, &tx_hdr) { Some(tx) => { - SCLogDebug!("tx {} with {}/{} marked as done", - tx.id, r.command, &smb2_command_string(r.command)); + SCLogDebug!( + "tx {} with {}/{} marked as done", + tx.id, + r.command, + &smb2_command_string(r.command) + ); if r.nt_status != SMB_NTSTATUS_PENDING { tx.response_done = true; } tx.set_status(r.nt_status, false); tx.set_events(events); true - }, + } _ => { SCLogDebug!("no tx found for {:?}", r); false - }, + } }; } } diff --git a/rust/src/smb/smb2_ioctl.rs b/rust/src/smb/smb2_ioctl.rs index ff85a5fefb..fe11a386ba 100644 --- a/rust/src/smb/smb2_ioctl.rs +++ b/rust/src/smb/smb2_ioctl.rs @@ -15,13 +15,13 @@ * 02110-1301, USA. */ -use crate::smb::smb::*; -use crate::smb::smb2::*; -use crate::smb::smb2_records::*; use crate::smb::dcerpc::*; use crate::smb::events::*; #[cfg(feature = "debug")] use crate::smb::funcs::*; +use crate::smb::smb::*; +use crate::smb::smb2::*; +use crate::smb::smb2_records::*; use crate::smb::smb_status::*; #[derive(Debug)] @@ -31,25 +31,26 @@ pub struct SMBTransactionIoctl { impl SMBTransactionIoctl { pub fn new(func: u32) -> Self { - return Self { - func, - }; + return Self { func }; } } impl SMBState { - pub fn new_ioctl_tx(&mut self, hdr: SMBCommonHdr, func: u32) - -> &mut SMBTransaction - { + pub fn new_ioctl_tx(&mut self, hdr: SMBCommonHdr, func: u32) -> &mut SMBTransaction { let mut tx = self.new_tx(); tx.hdr = hdr; - tx.type_data = Some(SMBTransactionTypeData::IOCTL( - SMBTransactionIoctl::new(func))); + tx.type_data = Some(SMBTransactionTypeData::IOCTL(SMBTransactionIoctl::new( + func, + ))); tx.request_done = true; tx.response_done = self.tc_trunc; // no response expected if tc is truncated - SCLogDebug!("SMB: TX IOCTL created: ID {} FUNC {:08x}: {}", - tx.id, func, &fsctl_func_to_string(func)); + SCLogDebug!( + "SMB: TX IOCTL created: ID {} FUNC {:08x}: {}", + tx.id, + func, + &fsctl_func_to_string(func) + ); self.transactions.push_back(tx); let tx_ref = self.transactions.back_mut(); return tx_ref.unwrap(); @@ -57,8 +58,7 @@ impl SMBState { } // IOCTL responses ASYNC don't set the tree id -pub fn smb2_ioctl_request_record(state: &mut SMBState, r: &Smb2Record) -{ +pub fn smb2_ioctl_request_record(state: &mut SMBState, r: &Smb2Record) { let hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_HEADER); match parse_smb2_request_ioctl(r.data) { Ok((_, rd)) => { @@ -73,21 +73,24 @@ pub fn smb2_ioctl_request_record(state: &mut SMBState, r: &Smb2Record) let vercmd = SMBVerCmdStat::new2(SMB2_COMMAND_IOCTL); smb_write_dcerpc_record(state, vercmd, hdr, rd.data); } else { - SCLogDebug!("IOCTL {:08x} {}", rd.function, &fsctl_func_to_string(rd.function)); + SCLogDebug!( + "IOCTL {:08x} {}", + rd.function, + &fsctl_func_to_string(rd.function) + ); let tx = state.new_ioctl_tx(hdr, rd.function); tx.vercmd.set_smb2_cmd(SMB2_COMMAND_IOCTL); } - }, + } _ => { let tx = state.new_generic_tx(2, r.command, hdr); tx.set_event(SMBEvent::MalformedData); - }, + } }; } // IOCTL responses ASYNC don't set the tree id -pub fn smb2_ioctl_response_record(state: &mut SMBState, r: &Smb2Record) -{ +pub fn smb2_ioctl_response_record(state: &mut SMBState, r: &Smb2Record) { let hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_HEADER); match parse_smb2_response_ioctl(r.data) { Ok((_, rd)) => { @@ -104,9 +107,12 @@ pub fn smb2_ioctl_response_record(state: &mut SMBState, r: &Smb2Record) SCLogDebug!("IOCTL response data is_pipe. Calling smb_read_dcerpc_record"); let vercmd = SMBVerCmdStat::new2_with_ntstatus(SMB2_COMMAND_IOCTL, r.nt_status); SCLogDebug!("TODO passing empty GUID"); - smb_read_dcerpc_record(state, vercmd, hdr, &[],rd.data); + smb_read_dcerpc_record(state, vercmd, hdr, &[], rd.data); } else { - SCLogDebug!("SMB2_COMMAND_IOCTL/SMB_NTSTATUS_PENDING looking for {:?}", hdr); + SCLogDebug!( + "SMB2_COMMAND_IOCTL/SMB_NTSTATUS_PENDING looking for {:?}", + hdr + ); if let Some(tx) = state.get_generic_tx(2, SMB2_COMMAND_IOCTL, &hdr) { tx.set_status(r.nt_status, false); if r.nt_status != SMB_NTSTATUS_PENDING { @@ -114,22 +120,25 @@ pub fn smb2_ioctl_response_record(state: &mut SMBState, r: &Smb2Record) } } } - }, + } _ => { - SCLogDebug!("SMB2_COMMAND_IOCTL/SMB_NTSTATUS_PENDING looking for {:?}", hdr); + SCLogDebug!( + "SMB2_COMMAND_IOCTL/SMB_NTSTATUS_PENDING looking for {:?}", + hdr + ); if let Some(tx) = state.get_generic_tx(2, SMB2_COMMAND_IOCTL, &hdr) { SCLogDebug!("updated status of tx {}", tx.id); tx.set_status(r.nt_status, false); if r.nt_status != SMB_NTSTATUS_PENDING { tx.response_done = true; } - + // parsing failed for 'SUCCESS' record, set event if r.nt_status == SMB_NTSTATUS_SUCCESS { SCLogDebug!("parse fail {:?}", r); tx.set_event(SMBEvent::MalformedData); } } - }, + } }; } diff --git a/rust/src/smb/smb2_records.rs b/rust/src/smb/smb2_records.rs index 5a1ef74177..d8057c1ecf 100644 --- a/rust/src/smb/smb2_records.rs +++ b/rust/src/smb/smb2_records.rs @@ -201,7 +201,9 @@ pub struct Smb2SessionSetupRequestRecord<'a> { pub data: &'a [u8], } -pub fn parse_smb2_request_session_setup(i: &[u8]) -> IResult<&[u8], Smb2SessionSetupRequestRecord<'_>> { +pub fn parse_smb2_request_session_setup( + i: &[u8], +) -> IResult<&[u8], Smb2SessionSetupRequestRecord<'_>> { let (i, _struct_size) = take(2_usize).parse(i)?; let (i, _flags) = le_u8.parse(i)?; let (i, _security_mode) = le_u8.parse(i)?; @@ -220,7 +222,9 @@ pub struct Smb2TreeConnectRequestRecord<'a> { pub share_name: &'a [u8], } -pub fn parse_smb2_request_tree_connect(i: &[u8]) -> IResult<&[u8], Smb2TreeConnectRequestRecord<'_>> { +pub fn parse_smb2_request_tree_connect( + i: &[u8], +) -> IResult<&[u8], Smb2TreeConnectRequestRecord<'_>> { let (i, _struct_size) = take(2_usize).parse(i)?; let (i, _offset_length) = take(4_usize).parse(i)?; let (i, data) = rest.parse(i)?; @@ -363,7 +367,9 @@ pub struct Smb2SetInfoRequestDispoRecord { pub delete: bool, } -pub fn parse_smb2_request_setinfo_disposition(i: &[u8]) -> IResult<&[u8], Smb2SetInfoRequestData<'_>> { +pub fn parse_smb2_request_setinfo_disposition( + i: &[u8], +) -> IResult<&[u8], Smb2SetInfoRequestData<'_>> { let (i, info) = le_u8.parse(i)?; let record = Smb2SetInfoRequestData::DISPOSITION(Smb2SetInfoRequestDispoRecord { delete: info & 1 != 0, @@ -415,7 +421,8 @@ pub fn parse_smb2_request_setinfo(i: &[u8]) -> IResult<&[u8], Smb2SetInfoRequest let (i, guid) = take(16_usize).parse(i)?; let (i, data) = map_parser(take(setinfo_size), |b| { parse_smb2_request_setinfo_data(b, class, infolvl) - }).parse(i)?; + }) + .parse(i)?; let record = Smb2SetInfoRequestRecord { guid, class, diff --git a/rust/src/smb/smb2_session.rs b/rust/src/smb/smb2_session.rs index 31a34165e4..89db7d7265 100644 --- a/rust/src/smb/smb2_session.rs +++ b/rust/src/smb/smb2_session.rs @@ -15,13 +15,12 @@ * 02110-1301, USA. */ -use crate::smb::smb2_records::*; -use crate::smb::smb::*; -use crate::smb::events::*; use crate::smb::auth::*; +use crate::smb::events::*; +use crate::smb::smb::*; +use crate::smb::smb2_records::*; -pub fn smb2_session_setup_request(state: &mut SMBState, r: &Smb2Record) -{ +pub fn smb2_session_setup_request(state: &mut SMBState, r: &Smb2Record) { SCLogDebug!("SMB2_COMMAND_SESSION_SETUP: r.data.len() {}", r.data.len()); #[allow(clippy::single_match)] match parse_smb2_request_session_setup(r.data) { @@ -41,37 +40,34 @@ pub fn smb2_session_setup_request(state: &mut SMBState, r: &Smb2Record) } } } - }, - _ => { -// events.push(SMBEvent::MalformedData); - }, + } + _ => { + // events.push(SMBEvent::MalformedData); + } } } -fn smb2_session_setup_update_tx(tx: &mut SMBTransaction, r: &Smb2Record) -{ +fn smb2_session_setup_update_tx(tx: &mut SMBTransaction, r: &Smb2Record) { tx.hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_HEADER); // to overwrite ssn_id 0 tx.set_status(r.nt_status, false); tx.response_done = true; } -pub fn smb2_session_setup_response(state: &mut SMBState, r: &Smb2Record) -{ +pub fn smb2_session_setup_response(state: &mut SMBState, r: &Smb2Record) { // try exact match with session id already set (e.g. NTLMSSP AUTH phase) - let found = r.session_id != 0 && match state.get_sessionsetup_tx( - SMBCommonHdr::from2(r, SMBHDR_TYPE_HEADER)) - { - Some(tx) => { - smb2_session_setup_update_tx(tx, r); - SCLogDebug!("smb2_session_setup_response: tx {:?}", tx); - true - }, - None => { false }, - }; + let found = r.session_id != 0 + && match state.get_sessionsetup_tx(SMBCommonHdr::from2(r, SMBHDR_TYPE_HEADER)) { + Some(tx) => { + smb2_session_setup_update_tx(tx, r); + SCLogDebug!("smb2_session_setup_response: tx {:?}", tx); + true + } + None => false, + }; // otherwise try match with ssn id 0 (e.g. NTLMSSP_NEGOTIATE) if !found { - if let Some(tx) = state.get_sessionsetup_tx( - SMBCommonHdr::new(SMBHDR_TYPE_HEADER, 0, 0, r.message_id)) + if let Some(tx) = + state.get_sessionsetup_tx(SMBCommonHdr::new(SMBHDR_TYPE_HEADER, 0, 0, r.message_id)) { smb2_session_setup_update_tx(tx, r); SCLogDebug!("smb2_session_setup_response: tx {:?}", tx); diff --git a/rust/src/smb/smb3.rs b/rust/src/smb/smb3.rs index f77b0d8608..b33c9533c8 100644 --- a/rust/src/smb/smb3.rs +++ b/rust/src/smb/smb3.rs @@ -17,14 +17,14 @@ use nom8::bytes::streaming::{tag, take}; use nom8::number::streaming::{le_u16, le_u32, le_u64}; -use nom8::Parser; use nom8::IResult; +use nom8::Parser; -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Smb3TransformRecord<'a> { pub session_id: u64, pub enc_algo: u16, - pub enc_data: &'a[u8], + pub enc_data: &'a [u8], } pub fn parse_smb3_transform_record(i: &[u8]) -> IResult<&[u8], Smb3TransformRecord<'_>> { @@ -47,8 +47,8 @@ pub fn parse_smb3_transform_record(i: &[u8]) -> IResult<&[u8], Smb3TransformReco #[cfg(test)] mod tests { use super::*; - #[test] - fn test_parse_smb3_transform_record() { + #[test] + fn test_parse_smb3_transform_record() { // https://raw.githubusercontent.com/bro/bro/master/testing/btest/Traces/smb/smb3.pcap let data = hex::decode("fd534d42188d39cea4b1e3f640aff5d0b1569852c0bd665516dbb4b499507f000000000069000000000001003d00009400480000d9f8a66572b40c621bea6f5922a412a8eb2e3cc2af9ce26a277e75898cb523b9eb49ef660a6a1a09368fadd6a58e893e08eb3b7c068bdb74b6cd38e9ed1a2559cefb2ebc2172fd86c08a1a636eb851f20bf53a242f4cfaf7ab44e77291073ad492d6297c3d3a67757c").unwrap(); let result = parse_smb3_transform_record(&data).unwrap(); diff --git a/rust/src/smb/smb_records.rs b/rust/src/smb/smb_records.rs index 720b59961a..02cc9dec83 100644 --- a/rust/src/smb/smb_records.rs +++ b/rust/src/smb/smb_records.rs @@ -23,22 +23,21 @@ use nom8::{Err, IResult}; /// parse a UTF16 string that is null terminated. Normally by 2 null /// bytes, but at the end of the data it can also be a single null. /// Skip every second byte. -pub fn smb_get_unicode_string(blob: &[u8]) -> IResult<&[u8], Vec, SmbError> -{ +pub fn smb_get_unicode_string(blob: &[u8]) -> IResult<&[u8], Vec, SmbError> { SCLogDebug!("get_unicode_string: blob {} {:?}", blob.len(), blob); - let mut name : Vec = Vec::new(); + let mut name: Vec = Vec::new(); let mut c = blob; while !c.is_empty() { if c.len() == 1 && c[0] == 0 { let rem = &c[1..]; SCLogDebug!("get_unicode_string: name {:?}", name); - return Ok((rem, name)) + return Ok((rem, name)); } else if c.len() == 1 { break; } else if c[0] == 0 && c[1] == 0 { let rem = &c[2..]; SCLogDebug!("get_unicode_string: name {:?}", name); - return Ok((rem, name)) + return Ok((rem, name)); } name.push(c[0]); c = &c[2..]; @@ -51,4 +50,3 @@ pub fn smb_get_ascii_string(i: &[u8]) -> IResult<&[u8], Vec, SmbError> { let (i, s) = take_until_and_consume(b"\x00").parse(i)?; Ok((i, s.to_vec())) } - diff --git a/scripts/rustfmt.sh b/scripts/rustfmt.sh index 75a81a740b..bb3373ba28 100755 --- a/scripts/rustfmt.sh +++ b/scripts/rustfmt.sh @@ -42,3 +42,6 @@ rustfmt --check rust/src/dns/*.rs rust/src/applayertemplate/*.rs rust/src/asn1/* rust/src/nfs/*.rs rust/src/pgsql/*.rs rust/src/rdp/*.rs rust/src/sdp/*.rs \ rust/src/sip/*.rs rust/src/telnet/*.rs rust/src/tftp/*.rs rust/src/x509/*.rs \ rust/src/snmp/*.rs rust/src/llmnr/*.rs rust/src/detect/*.rs rust/src/dcerpc/*.rs + +# do not do *.rs so as not to rustfmt smb_status.rs which skips formatting in mod.rs +rustfmt --check rust/src/smb/mod.rs