1use std::io::SeekFrom;
4
5use smb_dtyp::binrw_util::prelude::*;
6use smb_msg_derive::smb_message_binrw;
7
8use super::negotiate::CompressionAlgorithm;
9use binrw::io::TakeSeekExt;
10use binrw::prelude::*;
11
12#[smb_message_binrw]
19#[brw(little)]
20pub enum CompressedMessage {
21 Unchained(CompressedUnchainedMessage),
22 Chained(CompressedChainedMessage),
23}
24
25impl CompressedMessage {
26 pub fn total_size(&self) -> usize {
28 match self {
29 CompressedMessage::Unchained(m) => {
30 m.data.len() + CompressedUnchainedMessage::STRUCT_SIZE
31 }
32 CompressedMessage::Chained(m) => {
33 m.items.iter().map(|i| i.payload_data.len()).sum::<usize>()
34 + m.items.len() * 4
35 + CompressedChainedMessage::STRUCT_SIZE
36 }
37 }
38 }
39}
40
41#[smb_message_binrw]
48#[brw(magic(b"\xfcSMB"), little)]
49pub struct CompressedUnchainedMessage {
50 pub original_size: u32,
52 #[brw(assert(!matches!(compression_algorithm, CompressionAlgorithm::None)))]
54 pub compression_algorithm: CompressionAlgorithm,
55 #[br(assert(flags == 0))]
57 #[bw(calc = 0)]
58 flags: u16,
59 #[bw(calc = 0)]
61 offset: u32,
62 #[br(seek_before = SeekFrom::Current(offset as i64))]
64 #[br(parse_with = binrw::helpers::until_eof)]
65 pub data: Vec<u8>,
66}
67
68impl CompressedUnchainedMessage {
69 const MAGIC_SIZE: usize = 4;
71 pub const STRUCT_SIZE: usize = Self::MAGIC_SIZE
73 + std::mem::size_of::<u32>() * 2
74 + std::mem::size_of::<CompressionAlgorithm>()
75 + std::mem::size_of::<u16>();
76}
77
78#[smb_message_binrw]
85#[brw(magic(b"\xfcSMB"), little)]
86pub struct CompressedChainedMessage {
87 pub original_size: u32,
89 #[br(parse_with = binrw::helpers::until_eof)]
91 pub items: Vec<CompressedChainedItem>,
92}
93
94impl CompressedChainedMessage {
95 pub const STRUCT_SIZE: usize = std::mem::size_of::<u32>() + 4;
97}
98
99fn add_original_size_to_total_length(algo: &CompressionAlgorithm) -> u64 {
101 if algo.original_size_required() {
102 std::mem::size_of::<u32>() as u64
103 } else {
104 0
105 }
106}
107
108#[smb_message_binrw]
115pub struct CompressedChainedItem {
116 pub compression_algorithm: CompressionAlgorithm,
118 pub flags: u16,
120 #[bw(calc = PosMarker::default())]
122 #[br(temp)]
123 length: PosMarker<u32>,
124 #[brw(if(compression_algorithm.original_size_required()))]
126 #[bw(assert(original_size.is_none() ^ compression_algorithm.original_size_required()))]
127 pub original_size: Option<u32>,
128 #[br(map_stream = |s| s.take_seek(length.value as u64 - (add_original_size_to_total_length(&compression_algorithm))), parse_with = binrw::helpers::until_eof)]
130 #[bw(write_with = PosMarker::write_size_plus, args(&length, add_original_size_to_total_length(compression_algorithm)))]
131 pub payload_data: Vec<u8>,
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137 use smb_tests::*;
138
139 test_binrw! {
142 CompressedMessage => chained0: CompressedMessage::Chained(CompressedChainedMessage {
143 original_size: 368,
144 items: vec![
145 CompressedChainedItem {
146 compression_algorithm: CompressionAlgorithm::None,
147 flags: 1,
148 original_size: None,
149 payload_data: vec![
150 0xfe, 0x53, 0x4d, 0x42, 0x40, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10,
151 0x0, 0x1, 0x0, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x91, 0x0, 0x0,
152 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
153 0x7d, 0x0, 0x0, 0x28, 0x0, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
154 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x29, 0x0, 0x1,
155 0xf, 0x2a, 0x2, 0x0, 0x0, 0x68, 0x0, 0x0, 0x0, 0x8, 0x1, 0x0, 0x0, 0x0,
156 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0xee, 0x5, 0x0, 0x0, 0xc, 0x0, 0x0,
157 0x0, 0x8d, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0
158 ],
159 },
160 CompressedChainedItem {
161 compression_algorithm: CompressionAlgorithm::None,
162 flags: 0xb975,
163 original_size: None,
164 payload_data: vec![
165 0x0, 0x0, 0x0, 0x0, 0x15, 0x24, 0x4d, 0x70, 0x45, 0x61, 0x5f, 0x44,
166 0x32, 0x36, 0x32, 0x41, 0x43, 0x36, 0x32, 0x34, 0x34, 0x35, 0x31, 0x32,
167 0x39, 0x35
168 ],
169 },
170 CompressedChainedItem {
171 compression_algorithm: CompressionAlgorithm::PatternV1,
172 flags: 0,
173 original_size: None,
174 payload_data: vec![0x0, 0x0, 0x0, 0x0, 0xee, 0x0, 0x0, 0x0]
175 }
176 ]
177 }) => "fc534d42700100000000010068000000fe534d4240000100000000001000010030000000000000009100000000000000fffe0000010000007d00002800300000000000000000000000000000000000002900010f2a02000068000000080100000000000003000000ee0500000c0000008d0000000c000000000075b91a0000000000000015244d7045615f443236324143363234343531323935040000000800000000000000ee000000"
178 }
179
180 const CHAINED1_ITEM2_DATA: &'static str = "f2034d5a90000300000004000000ffff0000b8000\
182 100124007000f02000af32e200100000e1fba0e00b409cd21b8014ccd21546869732070726f677\
183 2616d2063616e6e6f742062652072756e20696e20444f53206d6f64652e0d0d0a245a0084a98ee\
184 eb9edef80ea0400d1996e86ebddef80ea9f6e83ebe81000b181ebe1ef80eabe9084ebec0800318\
185 3ebe320003181ebef3800b181eaadef80eae49713eaf010003180ea7f38004088eb5ee94000318\
186 5ebf310003184eb9008003183eba908001180500040996e7fea580031996e82100040526963684\
187 400039f00d4005045000064862400bbf4ba231400f10bf00022000b020e260090a60000e01d000\
188 0f061009002b100001022002040010700000c00561000000a00040001020030f044012800b126d\
189 1c2000100604100000817002200200700013500000200004000030200010b00c17014008fb3010\
190 028471400b86100f3144001288e030000700d00b4cf06000070c200b825000000904301dc5f000\
191 0101004007040000f02000120a05b4200071a0057401400f80610000b0200b22e7264617461000\
192 0305c0d91001360080007020062400000482e702800029400400d0000d09c00170d26000328001\
193 26928002224267c0023003008000702000150001265280000fc00630070140000c00800070200c\
194 14000004050524f54444154411b01223016a400000800070200005000a047464944530000002ca\
195 9700043160000b0080007020081400000425061643113006110090000f0160b000c0200f200800\
196 000422e746578740000000ba14cc5012db04c30008020000068504147454000f0008042440000b\
197 06c000050440000a063130005020040200000602800f5044c4b00001c6402000000b1000070020\
198 000f0a72400000200012800804f4f4c434f4445bef4012270b340012060aa1f00050200047800e\
199 04b440000ea5d000000a0b300006024020d2800017800605652465919150e048fb400002003000\
200 0f02800035048444c53760e032220b778002510ae740000020001a000904147454247465868694\
201 50321b7008d021e402800f1005452414345535550a319000000c0b73d002d00b02800014001b24\
202 34d5243f30e000000e0b7e0011dd0280050604b5641531801107e610413f0a0001de0280050684\
203 b534350ac0010607f032220b850002010af1300050200004001904452565052580000b71600133\
204 028001e20280050666f74686b240000ad03134028001e302800e0494e49544b444247a6f101000\
205 0506e054e020000402800904d494e4945580000bc20032250ba68012040b162000502004020000\
206 0625000001100ee1be009000080ba0000f0090000702800405061643228007100901b000070c40\
207 b000c020052800000622e6f03400080291c690100ed0449000060bb2b00f104400000c8414c4d4\
208 f5354524f409c00000030fc8d003d0050bc2800f2004341434845414c49008e000000d0fc20011\
209 e70280000f80200c0037250b401000060fd50001d80280010c02800e056524644503c01000020f\
210 f0000a0d8020e280000180100500030b41402f402017405390040bda00081200000c2506164331\
211 50061801d000080023f040c020090800000c2434647524fe30001a80521200170031a505000001\
212 8014150616434400050d01f00003022070e020080800000ca2e727372fe0301c4059d004001009\
213 0030000805000c1422e72656c6f630000dc5501dc0578006001000010c15500500040000042";
214
215 const CHAINED1_TEST_DATA: &'static str = const_format::concatcp!(
216 "fc534d42501000000000010050000000fe534d424000010000000000080001001900000000000000070000000000000000000000010000001d00000000600000251698bc898e3e86aeb713557cfaf1bb1100500000100000000000000000000005000000f7040000c8070000",
217 CHAINED1_ITEM2_DATA,
218 "04000000080000000000000038080000"
219 );
220
221 test_binrw! {
222 CompressedMessage => chained1: CompressedMessage::Chained(CompressedChainedMessage {
223 original_size: 4176,
224 items: vec![
225 CompressedChainedItem {
226 compression_algorithm: CompressionAlgorithm::None,
227 flags: 1,
228 original_size: None,
229 payload_data: vec![
230 0xfe, 0x53, 0x4d, 0x42, 0x40, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8,
231 0x0, 0x1, 0x0, 0x19, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0,
232 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1d,
233 0x0, 0x0, 0x0, 0x0, 0x60, 0x0, 0x0, 0x25, 0x16, 0x98, 0xbc, 0x89, 0x8e,
234 0x3e, 0x86, 0xae, 0xb7, 0x13, 0x55, 0x7c, 0xfa, 0xf1, 0xbb, 0x11, 0x0,
235 0x50, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
236 ],
237 },
238 CompressedChainedItem {
239 compression_algorithm: CompressionAlgorithm::LZ4,
240 flags: 0,
241 original_size: Some(0x7c8),
242 payload_data: smb_tests::hex_to_u8_array! {CHAINED1_ITEM2_DATA}
243 },
244 CompressedChainedItem {
245 compression_algorithm: CompressionAlgorithm::PatternV1,
246 flags: 0,
247 original_size: None,
248 payload_data: vec![0x0, 0x0, 0x0, 0x0, 0x38, 0x8, 0x0, 0x0]
249 },
250 ]
251 }) => CHAINED1_TEST_DATA
252 }
253
254 test_binrw! {
255 CompressedMessage => multiple2: CompressedMessage::Chained(CompressedChainedMessage {
256 original_size: 368,
257 items: vec![
258 CompressedChainedItem {
259 compression_algorithm: CompressionAlgorithm::None,
260 flags: 1,
261 original_size: None,
262 payload_data: vec![
263 0xfe, 0x53, 0x4d, 0x42, 0x40, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0,
264 0x1, 0x0, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1e, 0x3, 0x0, 0x0,
265 0x0, 0x0, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x9, 0x0,
266 0x0, 0x2c, 0x0, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
267 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x29, 0x0, 0x1, 0xf, 0x2a, 0x2,
268 0x0, 0x0, 0x68, 0x0, 0x0, 0x0, 0x8, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3,
269 0x0, 0x0, 0x0, 0x11, 0x7, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x69, 0x0, 0x20,
270 0x0, 0xc, 0x0, 0x0, 0x0,
271 ],
272 },
273 CompressedChainedItem {
274 compression_algorithm: CompressionAlgorithm::None,
275 flags: 0,
276 original_size: None,
277 payload_data: vec![
278 0x0, 0x0, 0x0, 0x0, 0x15, 0x24, 0x4d, 0x70, 0x45, 0x61, 0x5f, 0x44, 0x32,
279 0x36, 0x32, 0x41, 0x43, 0x36, 0x32, 0x34, 0x34, 0x35, 0x31, 0x32, 0x39,
280 0x35,
281 ],
282 },
283 CompressedChainedItem {
284 compression_algorithm: CompressionAlgorithm::PatternV1,
285 flags: 0,
286 original_size: None,
287 payload_data: vec![0x0, 0x0, 0x0, 0x0, 0xee, 0x0, 0x0, 0x0],
288 },
289 ],
290 }) => "fc534d42700100000000010068000000fe534d4240000100000000001000010030000000000000001e03000000000000fffe0000050000000900002c00300000000000000000000000000000000000002900010f2a02000068000000080100000000000003000000110700000c000000690020000c000000000000001a0000000000000015244d7045615f443236324143363234343531323935040000000800000000000000ee000000"
291 }
292}