From: Pierre Chifflier Date: Sun, 14 Nov 2021 17:24:00 +0000 (+0100) Subject: rust/smb: convert parser to nom7 functions (SMB1) X-Git-Tag: suricata-7.0.0-beta1~1113 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F6705%2Fhead;p=thirdparty%2Fsuricata.git rust/smb: convert parser to nom7 functions (SMB1) --- diff --git a/rust/src/smb/dcerpc_records.rs b/rust/src/smb/dcerpc_records.rs index 57bbdf830a..4cfd40c567 100644 --- a/rust/src/smb/dcerpc_records.rs +++ b/rust/src/smb/dcerpc_records.rs @@ -24,7 +24,7 @@ use nom7::multi::count; use nom7::number::Endianness; use nom7::number::streaming::{be_u16, le_u8, le_u16, le_u32, u16, u32}; use nom7::sequence::tuple; -use nom7::IResult; +use nom7::{Err, IResult}; #[derive(Debug,PartialEq)] pub struct DceRpcResponseRecord<'a> { @@ -34,18 +34,15 @@ pub struct DceRpcResponseRecord<'a> { /// 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 ) - -> nom::IResult<&[u8], DceRpcResponseRecord, SmbError> + -> IResult<&[u8], DceRpcResponseRecord, SmbError> { if frag_len < 24 { - return Err(nom::Err::Error(SmbError::RecordTooSmall)); + return Err(Err::Error(SmbError::RecordTooSmall)); } - do_parse!(i, - take!(8) - >> data:take!(frag_len - 24) - >> (DceRpcResponseRecord { - data:data, - }) - ) + let (i, _) = take(8_usize)(i)?; + let (i, data) = take(frag_len - 24)(i)?; + let record = DceRpcResponseRecord { data }; + Ok((i, record)) } #[derive(Debug,PartialEq)] @@ -57,22 +54,17 @@ pub struct DceRpcRequestRecord<'a> { /// 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) - -> nom::IResult<&[u8], DceRpcRequestRecord, SmbError> + -> IResult<&[u8], DceRpcRequestRecord, SmbError> { - use nom::number::Endianness; if frag_len < 24 { - return Err(nom::Err::Error(SmbError::RecordTooSmall)); + return Err(Err::Error(SmbError::RecordTooSmall)); } - do_parse!(i, - take!(6) - >> endian: value!(if little { Endianness::Little } else { Endianness::Big }) - >> opnum: u16!(endian) - >> data:take!(frag_len - 24) - >> (DceRpcRequestRecord { - opnum:opnum, - data:data, - }) - ) + let (i, _) = take(6_usize)(i)?; + let endian = if little { Endianness::Little } else { Endianness::Big }; + let (i, opnum) = u16(endian)(i)?; + let (i, data) = take(frag_len - 24)(i)?; + let record = DceRpcRequestRecord { opnum, data }; + Ok((i, record)) } #[derive(Debug,PartialEq)] diff --git a/rust/src/smb/error.rs b/rust/src/smb/error.rs index ab9c863674..352c275ad7 100644 --- a/rust/src/smb/error.rs +++ b/rust/src/smb/error.rs @@ -16,7 +16,7 @@ */ // Author: Pierre Chifflier -use nom::error::{ErrorKind, ParseError}; +use nom7::error::{ErrorKind, ParseError}; #[derive(Debug)] pub enum SmbError { diff --git a/rust/src/smb/smb.rs b/rust/src/smb/smb.rs index 393c7868ed..e9fa49b252 100644 --- a/rust/src/smb/smb.rs +++ b/rust/src/smb/smb.rs @@ -31,7 +31,6 @@ use std::ffi::{self, CString}; use std::collections::HashMap; -use nom; use nom7::{Err, Needed}; use crate::core::*; @@ -1649,7 +1648,7 @@ impl SMBState { } } }, - Err(nom::Err::Incomplete(_)) => { + Err(Err::Incomplete(_)) => { // not enough data to contain basic SMB hdr // TODO event: empty NBSS_MSGTYPE_SESSION_MESSAGE }, diff --git a/rust/src/smb/smb1.rs b/rust/src/smb/smb1.rs index b81ebee944..ec4149d3b2 100644 --- a/rust/src/smb/smb1.rs +++ b/rust/src/smb/smb1.rs @@ -19,8 +19,6 @@ * - check all parsers for calls on non-SUCCESS status */ -use nom; - use crate::core::*; use crate::smb::smb::*; @@ -31,6 +29,8 @@ use crate::smb::files::*; use crate::smb::smb1_records::*; use crate::smb::smb1_session::*; +use nom7::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; @@ -251,13 +251,13 @@ fn smb1_request_record_one<'b>(state: &mut SMBState, r: &SmbRecord<'b>, command: true }, - Err(nom::Err::Incomplete(_n)) => { + Err(Err::Incomplete(_n)) => { SCLogDebug!("TRANS2 SET_FILE_INFO DATA DISPOSITION INCOMPLETE {:?}", _n); events.push(SMBEvent::MalformedData); false }, - Err(nom::Err::Error(_e)) | - Err(nom::Err::Failure(_e)) => { + Err(Err::Error(_e)) | + Err(Err::Failure(_e)) => { SCLogDebug!("TRANS2 SET_FILE_INFO DATA DISPOSITION ERROR {:?}", _e); events.push(SMBEvent::MalformedData); false @@ -279,13 +279,13 @@ fn smb1_request_record_one<'b>(state: &mut SMBState, r: &SmbRecord<'b>, command: tx.vercmd.set_smb1_cmd(SMB1_COMMAND_TRANS2); true }, - Err(nom::Err::Incomplete(_n)) => { + Err(Err::Incomplete(_n)) => { SCLogDebug!("TRANS2 SET_PATH_INFO DATA RENAME INCOMPLETE {:?}", _n); events.push(SMBEvent::MalformedData); false }, - Err(nom::Err::Error(_e)) | - Err(nom::Err::Failure(_e)) => { + Err(Err::Error(_e)) | + Err(Err::Failure(_e)) => { SCLogDebug!("TRANS2 SET_PATH_INFO DATA RENAME ERROR {:?}", _e); events.push(SMBEvent::MalformedData); false @@ -295,13 +295,13 @@ fn smb1_request_record_one<'b>(state: &mut SMBState, r: &SmbRecord<'b>, command: false } }, - Err(nom::Err::Incomplete(_n)) => { + Err(Err::Incomplete(_n)) => { SCLogDebug!("TRANS2 SET_PATH_INFO PARAMS INCOMPLETE {:?}", _n); events.push(SMBEvent::MalformedData); false }, - Err(nom::Err::Error(_e)) | - Err(nom::Err::Failure(_e)) => { + Err(Err::Error(_e)) | + Err(Err::Failure(_e)) => { SCLogDebug!("TRANS2 SET_PATH_INFO PARAMS ERROR {:?}", _e); events.push(SMBEvent::MalformedData); false @@ -334,13 +334,13 @@ fn smb1_request_record_one<'b>(state: &mut SMBState, r: &SmbRecord<'b>, command: true }, - Err(nom::Err::Incomplete(_n)) => { + Err(Err::Incomplete(_n)) => { SCLogDebug!("TRANS2 SET_FILE_INFO DATA DISPOSITION INCOMPLETE {:?}", _n); events.push(SMBEvent::MalformedData); false }, - Err(nom::Err::Error(_e)) | - Err(nom::Err::Failure(_e)) => { + Err(Err::Error(_e)) | + Err(Err::Failure(_e)) => { SCLogDebug!("TRANS2 SET_FILE_INFO DATA DISPOSITION ERROR {:?}", _e); events.push(SMBEvent::MalformedData); false @@ -367,13 +367,13 @@ fn smb1_request_record_one<'b>(state: &mut SMBState, r: &SmbRecord<'b>, command: tx.vercmd.set_smb1_cmd(SMB1_COMMAND_TRANS2); true }, - Err(nom::Err::Incomplete(_n)) => { + Err(Err::Incomplete(_n)) => { SCLogDebug!("TRANS2 SET_FILE_INFO DATA RENAME INCOMPLETE {:?}", _n); events.push(SMBEvent::MalformedData); false }, - Err(nom::Err::Error(_e)) | - Err(nom::Err::Failure(_e)) => { + Err(Err::Error(_e)) | + Err(Err::Failure(_e)) => { SCLogDebug!("TRANS2 SET_FILE_INFO DATA RENAME ERROR {:?}", _e); events.push(SMBEvent::MalformedData); false @@ -383,13 +383,13 @@ fn smb1_request_record_one<'b>(state: &mut SMBState, r: &SmbRecord<'b>, command: false } }, - Err(nom::Err::Incomplete(_n)) => { + Err(Err::Incomplete(_n)) => { SCLogDebug!("TRANS2 SET_FILE_INFO PARAMS INCOMPLETE {:?}", _n); events.push(SMBEvent::MalformedData); false }, - Err(nom::Err::Error(_e)) | - Err(nom::Err::Failure(_e)) => { + Err(Err::Error(_e)) | + Err(Err::Failure(_e)) => { SCLogDebug!("TRANS2 SET_FILE_INFO PARAMS ERROR {:?}", _e); events.push(SMBEvent::MalformedData); false @@ -399,13 +399,13 @@ fn smb1_request_record_one<'b>(state: &mut SMBState, r: &SmbRecord<'b>, command: false } }, - Err(nom::Err::Incomplete(_n)) => { + Err(Err::Incomplete(_n)) => { SCLogDebug!("TRANS2 INCOMPLETE {:?}", _n); events.push(SMBEvent::MalformedData); false }, - Err(nom::Err::Error(_e)) | - Err(nom::Err::Failure(_e)) => { + Err(Err::Error(_e)) | + Err(Err::Failure(_e)) => { SCLogDebug!("TRANS2 ERROR {:?}", _e); events.push(SMBEvent::MalformedData); false diff --git a/rust/src/smb/smb1_records.rs b/rust/src/smb/smb1_records.rs index 671ac0f12f..97e26337c2 100644 --- a/rust/src/smb/smb1_records.rs +++ b/rust/src/smb/smb1_records.rs @@ -15,22 +15,22 @@ * 02110-1301, USA. */ +use crate::common::nom7::take_until_and_consume; use crate::smb::error::SmbError; -use nom::IResult; -use nom::combinator::rest; -use nom::number::streaming::{le_u8, le_u16, le_u32, le_u64}; use crate::smb::smb::*; use crate::smb::smb_records::*; +use nom7::bytes::streaming::{tag, take}; +use nom7::combinator::{complete, cond, peek, rest}; +use nom7::multi::many1; +use nom7::number::streaming::{le_u8, le_u16, le_u32, le_u64}; +use nom7::IResult; pub const SMB1_HEADER_SIZE: usize = 32; fn smb_get_unicode_string_with_offset(i: &[u8], offset: usize) -> IResult<&[u8], Vec, SmbError> { - do_parse!(i, - cond!(offset % 2 == 1, take!(1)) - >> s: call!(smb_get_unicode_string) - >> ( s ) - ) + let (i, _) = cond(offset % 2 == 1, take(1_usize))(i)?; + smb_get_unicode_string(i) } /// take a string, unicode or ascii based on record @@ -50,19 +50,18 @@ pub struct SmbParamBlockAndXHeader { pub andx_offset: u16, } -named!(pub smb1_parse_andx_header, - do_parse!( - wct: le_u8 - >> andx_command: le_u8 - >> take!(1) // reserved - >> andx_offset: le_u16 - >> (SmbParamBlockAndXHeader { - wct: wct, - andx_command: andx_command, - andx_offset: andx_offset, - })) - -); +pub fn smb1_parse_andx_header(i: &[u8]) -> IResult<&[u8], SmbParamBlockAndXHeader> { + let (i, wct) = le_u8(i)?; + let (i, andx_command) = le_u8(i)?; + let (i, _) = take(1_usize)(i)?; // reserved + let (i, andx_offset) = le_u16(i)?; + let hdr = SmbParamBlockAndXHeader { + wct, + andx_command, + andx_offset, + }; + Ok((i, hdr)) +} #[derive(Debug,PartialEq)] pub struct Smb1WriteRequestRecord<'a> { @@ -72,71 +71,71 @@ pub struct Smb1WriteRequestRecord<'a> { pub data: &'a[u8], } -named!(pub parse_smb1_write_request_record, - do_parse!( - _wct: le_u8 - >> fid: take!(2) - >> _count: le_u16 - >> offset: le_u32 - >> _remaining: le_u16 - >> _bcc: le_u16 - >> _buffer_format: le_u8 - >> data_len: le_u16 - >> file_data: take!(data_len) - >> (Smb1WriteRequestRecord { - offset: offset as u64, - len: data_len as u32, - fid, - data:file_data, - })) -); +pub fn parse_smb1_write_request_record(i: &[u8]) -> IResult<&[u8], Smb1WriteRequestRecord> { + let (i, _wct) = le_u8(i)?; + let (i, fid) = take(2_usize)(i)?; + let (i, _count) = le_u16(i)?; + let (i, offset) = le_u32(i)?; + let (i, _remaining) = le_u16(i)?; + let (i, _bcc) = le_u16(i)?; + let (i, _buffer_format) = le_u8(i)?; + let (i, data_len) = le_u16(i)?; + let (i, file_data) = take(data_len)(i)?; + let record = Smb1WriteRequestRecord { + offset: offset as u64, + len: data_len as u32, + fid, + data:file_data, + }; + Ok((i, record)) +} pub fn parse_smb1_write_andx_request_record(i : &[u8], andx_offset: usize) -> IResult<&[u8], Smb1WriteRequestRecord> { let ax = andx_offset as u16; - do_parse!(i, - wct: le_u8 - >> _andx_command: le_u8 - >> take!(1) // reserved - >> _andx_offset: le_u16 - >> fid: take!(2) - >> offset: le_u32 - >> take!(4) // reserved - >> _write_mode: le_u16 - >> _remaining: le_u16 - >> data_len_high: le_u16 - >> data_len_low: le_u16 - >> data_offset: le_u16 - >> high_offset: cond!(wct==14,le_u32) - >> bcc: le_u16 - //spec [MS-CIFS].pdf says always take one byte padding - >> _padding: cond!(bcc > data_len_low, take!(bcc - data_len_low)) // TODO figure out how this works with data_len_high - >> _padding_evasion: cond!(data_offset > ax+4+2*(wct as u16), take!(data_offset - (ax+4+2*(wct as u16)))) - >> file_data: rest - >> (Smb1WriteRequestRecord { - offset: if high_offset != None { ((high_offset.unwrap() as u64) << 32)|(offset as u64) } else { 0 }, - len: (((data_len_high as u32) << 16) as u32)|(data_len_low as u32), - fid, - data:file_data, - })) -} - -named!(pub parse_smb1_write_and_close_request_record, - do_parse!( - _wct: le_u8 - >> fid: take!(2) - >> count: le_u16 - >> offset: le_u32 - >> _last_write: take!(4) - >> bcc: le_u16 - >> _padding: cond!(bcc > count, take!(bcc - count)) - >> file_data: take!(count) - >> (Smb1WriteRequestRecord { - offset: offset as u64, - len: count as u32, - fid, - data:file_data, - })) -); + let (i, wct) = le_u8(i)?; + let (i, _andx_command) = le_u8(i)?; + let (i, _) = take(1_usize)(i)?; // reserved + let (i, _andx_offset) = le_u16(i)?; + let (i, fid) = take(2_usize)(i)?; + let (i, offset) = le_u32(i)?; + let (i, _) = take(4_usize)(i)?; // reserved + let (i, _write_mode) = le_u16(i)?; + let (i, _remaining) = le_u16(i)?; + let (i, data_len_high) = le_u16(i)?; + let (i, data_len_low) = le_u16(i)?; + let (i, data_offset) = le_u16(i)?; + let (i, high_offset) = cond(wct == 14, le_u32)(i)?; + let (i, bcc) = le_u16(i)?; + //spec [MS-CIFS].pdf says always take one byte padding + let (i, _padding) = cond(bcc > data_len_low, |b| take(bcc - data_len_low)(b))(i)?; // TODO figure out how this works with data_len_high + let (i, _padding_evasion) = cond(data_offset > ax+4+2*(wct as u16), |b| take(data_offset - (ax+4+2*(wct as u16)))(b))(i)?; + let (i, file_data) = rest(i)?; + let record = Smb1WriteRequestRecord { + offset: if high_offset != None { ((high_offset.unwrap() as u64) << 32)|(offset as u64) } else { 0 }, + len: (((data_len_high as u32) << 16) as u32)|(data_len_low as u32), + fid, + data: file_data, + }; + Ok((i, record)) +} + +pub fn parse_smb1_write_and_close_request_record(i: &[u8]) -> IResult<&[u8], Smb1WriteRequestRecord> { + let (i, _wct) = le_u8(i)?; + let (i, fid) = take(2_usize)(i)?; + let (i, count) = le_u16(i)?; + let (i, offset) = le_u32(i)?; + let (i, _last_write) = take(4_usize)(i)?; + let (i, bcc) = le_u16(i)?; + let (i, _padding) = cond(bcc > count, |b| take(bcc - count)(b))(i)?; + let (i, file_data) = take(count)(i)?; + let record = Smb1WriteRequestRecord { + offset: offset as u64, + len: count as u32, + fid, + data: file_data, + }; + Ok((i, record)) +} #[derive(Debug,PartialEq)] pub struct Smb1NegotiateProtocolResponseRecord<'a> { @@ -144,55 +143,59 @@ pub struct Smb1NegotiateProtocolResponseRecord<'a> { pub server_guid: &'a[u8], } -named!(pub parse_smb1_negotiate_protocol_response_record_error, - do_parse!( - _wct: le_u8 - >> _bcc: le_u16 - >> ( Smb1NegotiateProtocolResponseRecord { - dialect_idx: 0, - server_guid: &[], - }) -)); - -named!(pub parse_smb1_negotiate_protocol_response_record_ok, - do_parse!( - _wct: le_u8 - >> dialect_idx: le_u16 - >> _sec_mode: le_u8 - >> take!(16) - >> _caps: le_u32 - >> _sys_time: le_u64 - >> _server_tz: le_u16 - >> _challenge_len: le_u8 - >> bcc: le_u16 - >> server_guid: cond!(bcc >= 16, take!(16)) - >> (Smb1NegotiateProtocolResponseRecord { - dialect_idx, - server_guid: server_guid.unwrap_or(&[]), - })) -); +pub fn parse_smb1_negotiate_protocol_response_record_error(i: &[u8]) + -> IResult<&[u8], Smb1NegotiateProtocolResponseRecord> { + let (i, _wct) = le_u8(i)?; + let (i, _bcc) = le_u16(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> { + let (i, _wct) = le_u8(i)?; + let (i, dialect_idx) = le_u16(i)?; + let (i, _sec_mode) = le_u8(i)?; + let (i, _) = take(16_usize)(i)?; + let (i, _caps) = le_u32(i)?; + let (i, _sys_time) = le_u64(i)?; + let (i, _server_tz) = le_u16(i)?; + let (i, _challenge_len) = le_u8(i)?; + let (i, bcc) = le_u16(i)?; + let (i, server_guid) = cond(bcc >= 16, take(16_usize))(i)?; + let record = Smb1NegotiateProtocolResponseRecord { + dialect_idx, + server_guid: server_guid.unwrap_or(&[]), + }; + Ok((i, record)) +} -named!(pub parse_smb1_negotiate_protocol_response_record, - switch!(peek!(le_u8), - 0 => call!(parse_smb1_negotiate_protocol_response_record_error) | - _ => call!(parse_smb1_negotiate_protocol_response_record_ok) - )); +pub fn parse_smb1_negotiate_protocol_response_record(i: &[u8]) + -> IResult<&[u8], Smb1NegotiateProtocolResponseRecord> { + let (i, wct) = peek(le_u8)(i)?; + match wct { + 0 => parse_smb1_negotiate_protocol_response_record_error(i), + _ => parse_smb1_negotiate_protocol_response_record_ok(i), + } +} #[derive(Debug,PartialEq)] pub struct Smb1NegotiateProtocolRecord<'a> { pub dialects: Vec<&'a [u8]>, } -named!(pub parse_smb1_negotiate_protocol_record, - do_parse!( - _wtc: le_u8 - >> _bcc: le_u16 - // dialects is a list of [1 byte buffer format][string][0 terminator] - >> dialects: many1!(complete!(take_until_and_consume!("\0"))) - >> (Smb1NegotiateProtocolRecord { - dialects - })) -); +pub fn parse_smb1_negotiate_protocol_record(i: &[u8]) + -> IResult<&[u8], Smb1NegotiateProtocolRecord> { + let (i, _wtc) = le_u8(i)?; + let (i, _bcc) = le_u16(i)?; + // dialects is a list of [1 byte buffer format][string][0 terminator] + let (i, dialects) = many1(complete(take_until_and_consume(b"\0")))(i)?; + let record = Smb1NegotiateProtocolRecord { dialects }; + Ok((i, record)) +} #[derive(Debug,PartialEq)] @@ -201,22 +204,23 @@ pub struct Smb1ResponseRecordTreeConnectAndX<'a> { pub nativefs: &'a[u8], } -named!(pub parse_smb_connect_tree_andx_response_record, - do_parse!( - wct: le_u8 - >> _andx_command: le_u8 - >> take!(1) // reserved - >> _andx_offset: le_u16 - >> cond!(wct >= 3, take!(2)) // optional support - >> cond!(wct == 7, take!(8)) // access masks - >> _bcc: le_u16 - >> service: take_until_and_consume!("\x00") - >> nativefs: take_until_and_consume!("\x00") - >> (Smb1ResponseRecordTreeConnectAndX { - service, - nativefs - })) -); +pub fn parse_smb_connect_tree_andx_response_record(i: &[u8]) + -> IResult<&[u8], Smb1ResponseRecordTreeConnectAndX> { + let (i, wct) = le_u8(i)?; + let (i, _andx_command) = le_u8(i)?; + let (i, _) = take(1_usize)(i)?; // reserved + let (i, _andx_offset) = le_u16(i)?; + let (i, _) = cond(wct >= 3, take(2_usize))(i)?; // optional support + let (i, _) = cond(wct == 7, take(8_usize))(i)?; // access masks + let (i, _bcc) = le_u16(i)?; + let (i, service) = take_until_and_consume(b"\x00")(i)?; + let (i, nativefs) = take_until_and_consume(b"\x00")(i)?; + let record = Smb1ResponseRecordTreeConnectAndX { + service, + nativefs + }; + Ok((i, record)) +} #[derive(Debug,PartialEq)] pub struct SmbRecordTreeConnectAndX<'a> { @@ -224,18 +228,19 @@ pub struct SmbRecordTreeConnectAndX<'a> { pub service: &'a[u8], } -pub fn parse_smb_connect_tree_andx_record<'a>(i: &'a[u8], r: &SmbRecord) -> IResult<&'a[u8], SmbRecordTreeConnectAndX<'a>, SmbError> { - do_parse!(i, - _skip1: take!(7) - >> pwlen: le_u16 - >> _bcc: le_u16 - >> _pw: take!(pwlen) - >> path: call!(smb1_get_string, r, 11 + pwlen as usize) - >> service: take_until_and_consume!("\x00") - >> (SmbRecordTreeConnectAndX { - path, - service - })) +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)(i)?; + let (i, pwlen) = le_u16(i)?; + let (i, _bcc) = le_u16(i)?; + let (i, _pw) = take(pwlen)(i)?; + let (i, path) = smb1_get_string(i, r, 11 + pwlen as usize)?; + let (i, service) = take_until_and_consume(b"\x00")(i)?; + let record = SmbRecordTreeConnectAndX { + path, + service + }; + Ok((i, record)) } #[derive(Debug,PartialEq)] @@ -252,16 +257,16 @@ pub struct SmbPipeProtocolRecord<'a> { pub fid: &'a[u8], } -named!(pub parse_smb_trans_request_record_pipe<&[u8], SmbPipeProtocolRecord, SmbError>, - do_parse!( - fun: le_u16 - >> fid: take!(2) - >> (SmbPipeProtocolRecord { - function: fun, - fid - }) - ) -); +pub fn parse_smb_trans_request_record_pipe(i: &[u8]) + -> IResult<&[u8], SmbPipeProtocolRecord, SmbError> { + let (i, fun) = le_u16(i)?; + let (i, fid) = take(2_usize)(i)?; + let record = SmbPipeProtocolRecord { + function: fun, + fid + }; + Ok((i, record)) +} #[derive(Debug,PartialEq)] @@ -274,36 +279,37 @@ pub struct SmbRecordTransRequestParams<> { bcc: u16, } -named!(pub parse_smb_trans_request_record_params<&[u8], (SmbRecordTransRequestParams, Option), SmbError>, - do_parse!( - wct: le_u8 - >> _total_param_cnt: le_u16 - >> _total_data_count: le_u16 - >> _max_param_cnt: le_u16 - >> max_data_cnt: le_u16 - >> _max_setup_cnt: le_u8 - >> take!(1) // reserved - >> take!(2) // flags - >> _timeout: le_u32 - >> take!(2) // reserved - >> param_cnt: le_u16 - >> param_offset: le_u16 - >> data_cnt: le_u16 - >> data_offset: le_u16 - >> setup_cnt: le_u8 - >> take!(1) // reserved - >> pipe: cond!(wct == 16 && setup_cnt == 2 && data_cnt > 0, parse_smb_trans_request_record_pipe) - >> bcc: le_u16 - >> (( SmbRecordTransRequestParams { - max_data_cnt, - param_cnt, - param_offset, - data_cnt, - data_offset, - bcc - }, - pipe))) -); +pub fn parse_smb_trans_request_record_params(i: &[u8]) + -> IResult<&[u8], (SmbRecordTransRequestParams, Option), SmbError> +{ + let (i, wct) = le_u8(i)?; + let (i, _total_param_cnt) = le_u16(i)?; + let (i, _total_data_count) = le_u16(i)?; + let (i, _max_param_cnt) = le_u16(i)?; + let (i, max_data_cnt) = le_u16(i)?; + let (i, _max_setup_cnt) = le_u8(i)?; + let (i, _) = take(1_usize)(i)?; // reserved + let (i, _) = take(2_usize)(i)?; // flags + let (i, _timeout) = le_u32(i)?; + let (i, _) = take(2_usize)(i)?; // reserved + let (i, param_cnt) = le_u16(i)?; + let (i, param_offset) = le_u16(i)?; + let (i, data_cnt) = le_u16(i)?; + let (i, data_offset) = le_u16(i)?; + let (i, setup_cnt) = le_u8(i)?; + let (i, _) = take(1_usize)(i)?; // reserved + let (i, pipe) = cond(wct == 16 && setup_cnt == 2 && data_cnt > 0, parse_smb_trans_request_record_pipe)(i)?; + let (i, bcc) = le_u16(i)?; + let params = SmbRecordTransRequestParams { + max_data_cnt, + param_cnt, + param_offset, + data_cnt, + data_offset, + bcc + }; + Ok((i, (params, pipe))) +} #[derive(Debug,PartialEq)] pub struct SmbRecordTransRequestData<'a> { @@ -314,15 +320,12 @@ pub fn parse_smb_trans_request_record_data(i: &[u8], pad1: usize, param_cnt: u16, pad2: usize, data_len: u16) -> IResult<&[u8], SmbRecordTransRequestData, SmbError> { - do_parse!(i, - take!(pad1) - >> take!(param_cnt) - >> take!(pad2) - >> data: take!(data_len) - >> (SmbRecordTransRequestData { - data:data, - }) - ) + let (i, _) = take(pad1)(i)?; + let (i, _) = take(param_cnt)(i)?; + let (i, _) = take(pad2)(i)?; + let (i, data) = take(data_len)(i)?; + let req = SmbRecordTransRequestData { data }; + Ok((i, req)) } pub fn parse_smb_trans_request_record<'a, 'b>(i: &'a[u8], r: &SmbRecord<'b>) @@ -370,7 +373,7 @@ pub fn parse_smb_trans_request_record<'a, 'b>(i: &'a[u8], r: &SmbRecord<'b>) }; let res = SmbRecordTransRequest { - params: params, pipe: pipe, txname: n, data: recdata, + params, pipe, txname: n, data: recdata, }; Ok((rem, res)) } @@ -383,105 +386,108 @@ pub struct SmbRecordTransResponse<'a> { pub data: &'a[u8], } -named!(pub parse_smb_trans_response_error_record, - do_parse!( - _wct: le_u8 - >> bcc: le_u16 - >> (SmbRecordTransResponse { - data_cnt:0, - bcc:bcc, - data:&[], - })) -); - -named!(pub parse_smb_trans_response_regular_record, - do_parse!( - wct: le_u8 - >> _total_param_cnt: le_u16 - >> _total_data_count: le_u16 - >> take!(2) // reserved - >> _param_cnt: le_u16 - >> _param_offset: le_u16 - >> _param_displacement: le_u16 - >> data_cnt: le_u16 - >> data_offset: le_u16 - >> _data_displacement: le_u16 - >> _setup_cnt: le_u8 - >> take!(1) // reserved - >> bcc: le_u16 - >> take!(1) // padding - >> _padding_evasion: cond!(data_offset > 36+2*(wct as u16), take!(data_offset - (36+2*(wct as u16)))) - >> data: take!(data_cnt) - >> (SmbRecordTransResponse { - data_cnt, - bcc, - data - })) -); - -named!(pub parse_smb_trans_response_record, - switch!(peek!(le_u8), // wct - 0 => call!(parse_smb_trans_response_error_record) | - _ => call!(parse_smb_trans_response_regular_record)) -); +pub fn parse_smb_trans_response_error_record(i: &[u8]) -> IResult<&[u8], SmbRecordTransResponse> { + let (i, _wct) = le_u8(i)?; + let (i, bcc) = le_u16(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(i)?; + let (i, _total_param_cnt) = le_u16(i)?; + let (i, _total_data_count) = le_u16(i)?; + let (i, _) = take(2_usize)(i)?; // reserved + let (i, _param_cnt) = le_u16(i)?; + let (i, _param_offset) = le_u16(i)?; + let (i, _param_displacement) = le_u16(i)?; + let (i, data_cnt) = le_u16(i)?; + let (i, data_offset) = le_u16(i)?; + let (i, _data_displacement) = le_u16(i)?; + let (i, _setup_cnt) = le_u8(i)?; + let (i, _) = take(1_usize)(i)?; // reserved + let (i, bcc) = le_u16(i)?; + let (i, _) = take(1_usize)(i)?; // padding + let (i, _padding_evasion) = cond( + data_offset > 36+2*(wct as u16), + |b| take(data_offset - (36+2*(wct as u16)))(b) + )(i)?; + let (i, data) = take(data_cnt)(i)?; + let resp = SmbRecordTransResponse { + data_cnt, + bcc, + data + }; + Ok((i, resp)) +} + +pub fn parse_smb_trans_response_record(i: &[u8]) -> IResult<&[u8], SmbRecordTransResponse> { + let (i, wct) = peek(le_u8)(i)?; + match wct { + 0 => parse_smb_trans_response_error_record(i), + _ => parse_smb_trans_response_regular_record(i), + } +} #[derive(Debug,PartialEq)] pub struct SmbRecordSetupAndX<'a> { pub sec_blob: &'a[u8], } -named!(pub parse_smb_setup_andx_record, - do_parse!( - _skip1: take!(15) - >> sec_blob_len: le_u16 - >> _skip2: take!(8) - >> _bcc: le_u16 - >> sec_blob: take!(sec_blob_len) - >> (SmbRecordSetupAndX { - sec_blob - })) -); +pub fn parse_smb_setup_andx_record(i: &[u8]) -> IResult<&[u8], SmbRecordSetupAndX> { + let (i, _skip1) = take(15_usize)(i)?; + let (i, sec_blob_len) = le_u16(i)?; + let (i, _skip2) = take(8_usize)(i)?; + let (i, _bcc) = le_u16(i)?; + let (i, sec_blob) = take(sec_blob_len)(i)?; + let record = SmbRecordSetupAndX { sec_blob }; + Ok((i, record)) +} #[derive(Debug,PartialEq)] pub struct SmbResponseRecordSetupAndX<'a> { pub sec_blob: &'a[u8], } -named!(response_setup_andx_record, - do_parse!( - _skip1: take!(7) - >> sec_blob_len: le_u16 - >> _bcc: le_u16 - >> sec_blob: take!(sec_blob_len) - >> (SmbResponseRecordSetupAndX { - sec_blob - })) -); +fn response_setup_andx_record(i: &[u8]) -> IResult<&[u8], SmbResponseRecordSetupAndX> { + let (i, _skip1) = take(7_usize)(i)?; + let (i, sec_blob_len) = le_u16(i)?; + let (i, _bcc) = le_u16(i)?; + let (i, sec_blob) = take(sec_blob_len)(i)?; + let record = SmbResponseRecordSetupAndX { sec_blob }; + Ok((i, record)) +} -named!(response_setup_andx_wct3_record, - do_parse!( - _skip1: take!(7) - >> _bcc: le_u16 - >> (SmbResponseRecordSetupAndX { - sec_blob:&[], - })) -); +fn response_setup_andx_wct3_record(i: &[u8]) -> IResult<&[u8], SmbResponseRecordSetupAndX> { + let (i, _skip1) = take(7_usize)(i)?; + let (i, _bcc) = le_u16(i)?; + let record = SmbResponseRecordSetupAndX { + sec_blob: &[], + }; + Ok((i, record)) +} -named!(response_setup_andx_error_record, - do_parse!( - _wct: le_u8 - >> _bcc: le_u16 - >> (SmbResponseRecordSetupAndX { - sec_blob: &[], - })) -); +fn response_setup_andx_error_record(i: &[u8]) -> IResult<&[u8], SmbResponseRecordSetupAndX> { + let (i, _wct) = le_u8(i)?; + let (i, _bcc) = le_u16(i)?; + let record = SmbResponseRecordSetupAndX { + sec_blob: &[], + }; + Ok((i, record)) +} -named!(pub parse_smb_response_setup_andx_record, - switch!(peek!(le_u8), // wct - 0 => call!(response_setup_andx_error_record) | - 3 => call!(response_setup_andx_wct3_record) | - _ => call!(response_setup_andx_record)) -); +pub fn parse_smb_response_setup_andx_record(i: &[u8]) -> IResult<&[u8], SmbResponseRecordSetupAndX> { + let (i, wct) = peek(le_u8)(i)?; + match wct { + 0 => response_setup_andx_error_record(i), + 3 => response_setup_andx_wct3_record(i), + _ => response_setup_andx_record(i), + } +} #[derive(Debug,PartialEq)] pub struct SmbRequestReadAndXRecord<'a> { @@ -490,25 +496,25 @@ pub struct SmbRequestReadAndXRecord<'a> { pub offset: u64, } -named!(pub parse_smb_read_andx_request_record, - do_parse!( - wct: le_u8 - >> _andx_command: le_u8 - >> take!(1) // reserved - >> _andx_offset: le_u16 - >> fid: take!(2) - >> offset: le_u32 - >> max_count_low: le_u16 - >> take!(2) - >> max_count_high: le_u32 - >> take!(2) - >> high_offset: cond!(wct==12,le_u32) // only from wct ==12? - >> (SmbRequestReadAndXRecord { - fid, - size: (((max_count_high as u64) << 16)|max_count_low as u64), - offset: if high_offset != None { ((high_offset.unwrap() as u64) << 32)|(offset as u64) } else { 0 }, - })) -); +pub fn parse_smb_read_andx_request_record(i: &[u8]) -> IResult<&[u8], SmbRequestReadAndXRecord> { + let (i, wct) = le_u8(i)?; + let (i, _andx_command) = le_u8(i)?; + let (i, _) = take(1_usize)(i)?; // reserved + let (i, _andx_offset) = le_u16(i)?; + let (i, fid) = take(2_usize)(i)?; + let (i, offset) = le_u32(i)?; + let (i, max_count_low) = le_u16(i)?; + let (i, _) = take(2_usize)(i)?; + let (i, max_count_high) = le_u32(i)?; + let (i, _) = take(2_usize)(i)?; + let (i, high_offset) = cond(wct == 12,le_u32)(i)?; // only from wct ==12? + let record = SmbRequestReadAndXRecord { + fid, + size: (((max_count_high as u64) << 16)|max_count_low as u64), + offset: if high_offset != None { ((high_offset.unwrap() as u64) << 32)|(offset as u64) } else { 0 }, + }; + Ok((i, record)) +} #[derive(Debug,PartialEq)] pub struct SmbResponseReadAndXRecord<'a> { @@ -516,27 +522,33 @@ pub struct SmbResponseReadAndXRecord<'a> { pub data: &'a[u8], } -named!(pub parse_smb_read_andx_response_record, - do_parse!( - wct: le_u8 - >> _andx_command: le_u8 - >> take!(1) // reserved - >> _andx_offset: le_u16 - >> take!(6) - >> data_len_low: le_u16 - >> data_offset: le_u16 - >> data_len_high: le_u32 - >> take!(6) // reserved - >> bcc: le_u16 - >> _padding: cond!(bcc > data_len_low, take!(bcc - data_len_low)) // TODO figure out how this works with data_len_high - >> _padding_evasion: cond!(data_offset > 36+2*(wct as u16), take!(data_offset - (36+2*(wct as u16)))) - >> file_data: rest - - >> (SmbResponseReadAndXRecord { - len: (((data_len_high as u32) << 16)|data_len_low as u32), - data:file_data, - })) -); +pub fn parse_smb_read_andx_response_record(i: &[u8]) -> IResult<&[u8], SmbResponseReadAndXRecord> { + let (i, wct) = le_u8(i)?; + let (i, _andx_command) = le_u8(i)?; + let (i, _) = take(1_usize)(i)?; // reserved + let (i, _andx_offset) = le_u16(i)?; + let (i, _) = take(6_usize)(i)?; + let (i, data_len_low) = le_u16(i)?; + let (i, data_offset) = le_u16(i)?; + let (i, data_len_high) = le_u32(i)?; + let (i, _) = take(6_usize)(i)?; // reserved + let (i, bcc) = le_u16(i)?; + let (i, _padding) = cond( + bcc > data_len_low, + |b| take(bcc - data_len_low)(b) + )(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) + )(i)?; + let (i, file_data) = rest(i)?; + + let record = SmbResponseReadAndXRecord { + len: (((data_len_high as u32) << 16)|data_len_low as u32), + data: file_data, + }; + Ok((i, record)) +} #[derive(Debug,PartialEq)] pub struct SmbRequestRenameRecord { @@ -544,20 +556,20 @@ pub struct SmbRequestRenameRecord { pub newname: Vec, } -named!(pub parse_smb_rename_request_record<&[u8], SmbRequestRenameRecord, SmbError>, - do_parse!( - _wct: le_u8 - >> _search_attr: le_u16 - >> _bcc: le_u16 - >> _oldtype: le_u8 - >> oldname: smb_get_unicode_string - >> _newtype: le_u8 - >> newname: call!(smb_get_unicode_string_with_offset, 1) // HACK if we assume oldname is a series of utf16 chars offset would be 1 - >> (SmbRequestRenameRecord { - oldname, - newname - })) -); +pub fn parse_smb_rename_request_record(i: &[u8]) -> IResult<&[u8], SmbRequestRenameRecord, SmbError> { + let (i, _wct) = le_u8(i)?; + let (i, _search_attr) = le_u16(i)?; + let (i, _bcc) = le_u16(i)?; + let (i, _oldtype) = le_u8(i)?; + let (i, oldname) = smb_get_unicode_string(i)?; + let (i, _newtype) = le_u8(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 + }; + Ok((i, record)) +} #[derive(Debug,PartialEq)] pub struct SmbRequestCreateAndXRecord<> { @@ -569,21 +581,24 @@ pub struct SmbRequestCreateAndXRecord<> { pub fn parse_smb_create_andx_request_record<'a>(i: &'a[u8], r: &SmbRecord) -> IResult<&'a[u8], SmbRequestCreateAndXRecord<>, SmbError> { - do_parse!(i, - _skip1: take!(6) - >> file_name_len: le_u16 - >> _skip3: take!(28) - >> disposition: le_u32 - >> create_options: le_u32 - >> _skip2: take!(5) - >> bcc: le_u16 - >> file_name: cond!(bcc >= file_name_len, call!(smb1_get_string, r, (bcc - file_name_len) as usize)) - >> _skip3: rest - >> (SmbRequestCreateAndXRecord { - disposition: disposition, - create_options: create_options, - file_name: file_name.unwrap_or_default(), - })) + let (i, _skip1) = take(6_usize)(i)?; + let (i, file_name_len) = le_u16(i)?; + let (i, _skip3) = take(28_usize)(i)?; + let (i, disposition) = le_u32(i)?; + let (i, create_options) = le_u32(i)?; + let (i, _skip2) = take(5_usize)(i)?; + let (i, bcc) = le_u16(i)?; + let (i, file_name) = cond( + bcc >= file_name_len, + |b| smb1_get_string(b, r, (bcc - file_name_len) as usize) + )(i)?; + let (i, _skip3) = rest(i)?; + let record = SmbRequestCreateAndXRecord { + disposition, + create_options, + file_name: file_name.unwrap_or_default(), + }; + Ok((i, record)) } #[derive(Debug,PartialEq)] @@ -591,13 +606,14 @@ pub struct Trans2RecordParamSetFileInfoDisposition<> { pub delete: bool, } -named!(pub parse_trans2_request_data_set_file_info_disposition, - do_parse!( - delete: le_u8 - >> (Trans2RecordParamSetFileInfoDisposition { - delete: delete & 1 == 1, - }) -)); +pub fn parse_trans2_request_data_set_file_info_disposition(i: &[u8]) + -> IResult<&[u8], Trans2RecordParamSetFileInfoDisposition> { + let (i, delete) = le_u8(i)?; + let record = Trans2RecordParamSetFileInfoDisposition { + delete: delete & 1 == 1, + }; + Ok((i, record)) +} #[derive(Debug,PartialEq)] pub struct Trans2RecordParamSetFileInfo<'a> { @@ -605,15 +621,12 @@ pub struct Trans2RecordParamSetFileInfo<'a> { pub loi: u16, } -named!(pub parse_trans2_request_params_set_file_info, - do_parse!( - fid: take!(2) - >> loi: le_u16 - >> (Trans2RecordParamSetFileInfo { - fid:fid, - loi:loi, - }) -)); +pub fn parse_trans2_request_params_set_file_info(i: &[u8]) -> IResult<&[u8], Trans2RecordParamSetFileInfo> { + let (i, fid) = take(2_usize)(i)?; + let (i, loi) = le_u16(i)?; + let record = Trans2RecordParamSetFileInfo { fid, loi }; + Ok((i, record)) +} #[derive(Debug,PartialEq)] pub struct Trans2RecordParamSetFileInfoRename<'a> { @@ -621,18 +634,18 @@ pub struct Trans2RecordParamSetFileInfoRename<'a> { pub newname: &'a[u8], } -named!(pub parse_trans2_request_data_set_file_info_rename, - do_parse!( - replace: le_u8 - >> _reserved: take!(3) - >> _root_dir: take!(4) - >> newname_len: le_u32 - >> newname: take!(newname_len) - >> (Trans2RecordParamSetFileInfoRename { - replace: replace==1, - newname: newname, - }) -)); +pub fn parse_trans2_request_data_set_file_info_rename(i: &[u8]) -> IResult<&[u8], Trans2RecordParamSetFileInfoRename> { + let (i, replace) = le_u8(i)?; + let (i, _reserved) = take(3_usize)(i)?; + let (i, _root_dir) = take(4_usize)(i)?; + let (i, newname_len) = le_u32(i)?; + let (i, newname) = take(newname_len)(i)?; + let record = Trans2RecordParamSetFileInfoRename { + replace: replace==1, + newname, + }; + Ok((i, record)) +} #[derive(Debug,PartialEq)] pub struct Trans2RecordParamSetPathInfo<> { @@ -640,16 +653,13 @@ pub struct Trans2RecordParamSetPathInfo<> { pub oldname: Vec, } -named!(pub parse_trans2_request_params_set_path_info<&[u8], Trans2RecordParamSetPathInfo, SmbError>, - do_parse!( - loi: le_u16 - >> _reserved: take!(4) - >> oldname: call!(smb_get_unicode_string) - >> (Trans2RecordParamSetPathInfo { - loi, - oldname - }) -)); +pub fn parse_trans2_request_params_set_path_info(i: &[u8]) -> IResult<&[u8], Trans2RecordParamSetPathInfo, SmbError> { + let (i, loi) = le_u16(i)?; + let (i, _reserved) = take(4_usize)(i)?; + let (i, oldname) = smb_get_unicode_string(i)?; + let record = Trans2RecordParamSetPathInfo { loi, oldname }; + Ok((i, record)) +} #[derive(Debug,PartialEq)] pub struct Trans2RecordParamSetPathInfoRename<'a> { @@ -657,18 +667,18 @@ pub struct Trans2RecordParamSetPathInfoRename<'a> { pub newname: &'a[u8], } -named!(pub parse_trans2_request_data_set_path_info_rename, - do_parse!( - replace: le_u8 - >> _reserved: take!(3) - >> _root_dir: take!(4) - >> newname_len: le_u32 - >> newname: take!(newname_len) - >> (Trans2RecordParamSetPathInfoRename { - replace: replace==1, - newname - }) -)); +pub fn parse_trans2_request_data_set_path_info_rename(i: &[u8]) -> IResult<&[u8], Trans2RecordParamSetPathInfoRename> { + let (i, replace) = le_u8(i)?; + let (i, _reserved) = take(3_usize)(i)?; + let (i, _root_dir) = take(4_usize)(i)?; + let (i, newname_len) = le_u32(i)?; + let (i, newname) = take(newname_len)(i)?; + let record = Trans2RecordParamSetPathInfoRename { + replace: replace==1, + newname + }; + Ok((i, record)) +} #[derive(Debug,PartialEq)] pub struct SmbRequestTrans2Record<'a> { @@ -677,38 +687,41 @@ pub struct SmbRequestTrans2Record<'a> { pub data_blob: &'a[u8], } -named!(pub parse_smb_trans2_request_record, - do_parse!( - _wct: le_u8 - >> _total_param_cnt: le_u16 - >> _total_data_cnt: le_u16 - >> _max_param_cnt: le_u16 - >> _max_data_cnt: le_u16 - >> _max_setup_cnt: le_u8 - >> _reserved1: take!(1) - >> _flags: le_u16 - >> _timeout: le_u32 - >> _reserved2: take!(2) - >> param_cnt: le_u16 - >> param_offset: le_u16 - >> data_cnt: le_u16 - >> data_offset: le_u16 - >> _setup_cnt: le_u8 - >> _reserved3: take!(1) - >> subcmd: le_u16 - >> _bcc: le_u16 - //TODO test and use param_offset - >> _padding: take!(3) - >> setup_blob: take!(param_cnt) - >> _padding2: cond!(data_offset > param_offset + param_cnt, take!(data_offset - param_offset - param_cnt)) - >> data_blob: take!(data_cnt) - - >> (SmbRequestTrans2Record { - subcmd, - setup_blob, - data_blob - })) -); +pub fn parse_smb_trans2_request_record(i: &[u8]) -> IResult<&[u8], SmbRequestTrans2Record> { + let (i, _wct) = le_u8(i)?; + let (i, _total_param_cnt) = le_u16(i)?; + let (i, _total_data_cnt) = le_u16(i)?; + let (i, _max_param_cnt) = le_u16(i)?; + let (i, _max_data_cnt) = le_u16(i)?; + let (i, _max_setup_cnt) = le_u8(i)?; + let (i, _reserved1) = take(1_usize)(i)?; + let (i, _flags) = le_u16(i)?; + let (i, _timeout) = le_u32(i)?; + let (i, _reserved2) = take(2_usize)(i)?; + let (i, param_cnt) = le_u16(i)?; + let (i, param_offset) = le_u16(i)?; + let (i, data_cnt) = le_u16(i)?; + let (i, data_offset) = le_u16(i)?; + let (i, _setup_cnt) = le_u8(i)?; + let (i, _reserved3) = take(1_usize)(i)?; + let (i, subcmd) = le_u16(i)?; + let (i, _bcc) = le_u16(i)?; + //TODO test and use param_offset + let (i, _padding) = take(3_usize)(i)?; + let (i, setup_blob) = take(param_cnt)(i)?; + let (i, _padding2) = cond( + data_offset > param_offset + param_cnt, + |b| take(data_offset - param_offset - param_cnt)(b) + )(i)?; + let (i, data_blob) = take(data_cnt)(i)?; + + let record = SmbRequestTrans2Record { + subcmd, + setup_blob, + data_blob + }; + Ok((i, record)) +} #[derive(Debug,PartialEq)] pub struct SmbResponseCreateAndXRecord<'a> { @@ -720,36 +733,36 @@ pub struct SmbResponseCreateAndXRecord<'a> { pub file_size: u64, } -named!(pub parse_smb_create_andx_response_record, - do_parse!( - wct: le_u8 - >> _andx_command: le_u8 - >> take!(1) // reserved - >> _andx_offset: le_u16 - >> _oplock_level: le_u8 - >> fid: take!(2) - >> _create_action: le_u32 - >> create_ts: le_u64 - >> last_access_ts: le_u64 - >> last_write_ts: le_u64 - >> last_change_ts: le_u64 - >> take!(4) - >> file_size: le_u64 - >> _eof: le_u64 - >> _file_type: le_u16 - >> _ipc_state: le_u16 - >> _is_dir: le_u8 - >> cond!(wct == 42, take!(32)) - >> _bcc: le_u16 - >> (SmbResponseCreateAndXRecord { - fid:fid, - create_ts: SMBFiletime::new(create_ts), - last_access_ts: SMBFiletime::new(last_access_ts), - last_write_ts: SMBFiletime::new(last_write_ts), - last_change_ts: SMBFiletime::new(last_change_ts), - file_size:file_size, - })) -); +pub fn parse_smb_create_andx_response_record(i: &[u8]) -> IResult<&[u8], SmbResponseCreateAndXRecord> { + let (i, wct) = le_u8(i)?; + let (i, _andx_command) = le_u8(i)?; + let (i, _) = take(1_usize)(i)?; // reserved + let (i, _andx_offset) = le_u16(i)?; + let (i, _oplock_level) = le_u8(i)?; + let (i, fid) = take(2_usize)(i)?; + let (i, _create_action) = le_u32(i)?; + let (i, create_ts) = le_u64(i)?; + let (i, last_access_ts) = le_u64(i)?; + let (i, last_write_ts) = le_u64(i)?; + let (i, last_change_ts) = le_u64(i)?; + let (i, _) = take(4_usize)(i)?; + let (i, file_size) = le_u64(i)?; + let (i, _eof) = le_u64(i)?; + let (i, _file_type) = le_u16(i)?; + let (i, _ipc_state) = le_u16(i)?; + let (i, _is_dir) = le_u8(i)?; + let (i, _) = cond(wct == 42, take(32_usize))(i)?; + let (i, _bcc) = le_u16(i)?; + let record = SmbResponseCreateAndXRecord { + fid, + create_ts: SMBFiletime::new(create_ts), + last_access_ts: SMBFiletime::new(last_access_ts), + last_write_ts: SMBFiletime::new(last_write_ts), + last_change_ts: SMBFiletime::new(last_change_ts), + file_size, + }; + Ok((i, record)) +} #[derive(Debug,PartialEq)] pub struct SmbRequestCloseRecord<'a> { @@ -770,14 +783,12 @@ pub struct SmbVersion<> { pub version: u8, } -named!(pub parse_smb_version, - do_parse!( - version: le_u8 - >> tag!("SMB") - >> (SmbVersion { - version:version, - })) -); +pub fn parse_smb_version(i: &[u8]) -> IResult<&[u8], SmbVersion> { + let (i, version) = le_u8(i)?; + let (i, _) = tag(b"SMB")(i)?; + let version = SmbVersion { version }; + Ok((i, version)) +} #[derive(Debug,PartialEq)] pub struct SmbRecord<'a> { @@ -806,35 +817,35 @@ impl<'a> SmbRecord<'a> { } } -named!(pub parse_smb_record, - do_parse!( - tag!(b"\xffSMB") - >> command:le_u8 - >> nt_status:le_u32 - >> flags:le_u8 - >> flags2:le_u16 - >> process_id_high:le_u16 - >> _signature:take!(8) - >> _reserved:take!(2) - >> tree_id:le_u16 - >> process_id:le_u16 - >> user_id:le_u16 - >> multiplex_id:le_u16 - >> data: rest - - >> (SmbRecord { - command:command, - nt_status:nt_status, - flags:flags, - flags2:flags2, - is_dos_error: (flags2 & 0x4000_u16 == 0),// && nt_status != 0), - tree_id:tree_id, - user_id:user_id, - multiplex_id:multiplex_id, - - process_id: (process_id_high as u32) << 16 | process_id as u32, - //ssn_id: (((process_id as u32)<< 16)|(user_id as u32)), - ssn_id: user_id as u32, - data:data, - }) -)); +pub fn parse_smb_record(i: &[u8]) -> IResult<&[u8], SmbRecord> { + let (i, _) = tag(b"\xffSMB")(i)?; + let (i, command) = le_u8(i)?; + let (i, nt_status) = le_u32(i)?; + let (i, flags) = le_u8(i)?; + let (i, flags2) = le_u16(i)?; + let (i, process_id_high) = le_u16(i)?; + let (i, _signature) = take(8_usize)(i)?; + let (i, _reserved) = take(2_usize)(i)?; + let (i, tree_id) = le_u16(i)?; + let (i, process_id) = le_u16(i)?; + let (i, user_id) = le_u16(i)?; + let (i, multiplex_id) = le_u16(i)?; + let (i, data) = rest(i)?; + + let record = SmbRecord { + command, + nt_status, + flags, + flags2, + is_dos_error: (flags2 & 0x4000_u16 == 0),// && nt_status != 0), + tree_id, + user_id, + multiplex_id, + + process_id: (process_id_high as u32) << 16 | process_id as u32, + //ssn_id: (((process_id as u32)<< 16)|(user_id as u32)), + ssn_id: user_id as u32, + data, + }; + Ok((i, record)) +} diff --git a/rust/src/smb/smb_records.rs b/rust/src/smb/smb_records.rs index 6080075d36..1ee2248448 100644 --- a/rust/src/smb/smb_records.rs +++ b/rust/src/smb/smb_records.rs @@ -15,9 +15,9 @@ * 02110-1301, USA. */ +use crate::common::nom7::take_until_and_consume; use crate::smb::error::SmbError; -use nom; -use nom::IResult; +use nom7::{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. @@ -42,13 +42,12 @@ pub fn smb_get_unicode_string(blob: &[u8]) -> IResult<&[u8], Vec, SmbError> name.push(c[0]); c = &c[2..]; } - Err(nom::Err::Error(SmbError::BadEncoding)) + Err(Err::Error(SmbError::BadEncoding)) } // parse an ASCII string that is null terminated -named!(pub smb_get_ascii_string<&[u8], Vec, SmbError>, - do_parse!( - s: take_until_and_consume!("\x00") - >> ( s.to_vec() ) -)); +pub fn smb_get_ascii_string(i: &[u8]) -> IResult<&[u8], Vec, SmbError> { + let (i, s) = take_until_and_consume(b"\x00")(i)?; + Ok((i, s.to_vec())) +}