1 /* Copyright (C) 2018 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /* TODO
19  * - check all parsers for calls on non-SUCCESS status
20  */
21 
22 use nom;
23 
24 use crate::core::*;
25 
26 use crate::smb::smb::*;
27 use crate::smb::dcerpc::*;
28 use crate::smb::events::*;
29 use crate::smb::files::*;
30 
31 use crate::smb::smb1_records::*;
32 use crate::smb::smb1_session::*;
33 
34 // https://msdn.microsoft.com/en-us/library/ee441741.aspx
35 pub const SMB1_COMMAND_CREATE_DIRECTORY:        u8 = 0x00;
36 pub const SMB1_COMMAND_DELETE_DIRECTORY:        u8 = 0x01;
37 pub const SMB1_COMMAND_OPEN:                    u8 = 0x02;
38 pub const SMB1_COMMAND_CREATE:                  u8 = 0x03;
39 pub const SMB1_COMMAND_CLOSE:                   u8 = 0x04;
40 pub const SMB1_COMMAND_FLUSH:                   u8 = 0x05;
41 pub const SMB1_COMMAND_DELETE:                  u8 = 0x06;
42 pub const SMB1_COMMAND_RENAME:                  u8 = 0x07;
43 pub const SMB1_COMMAND_QUERY_INFORMATION:       u8 = 0x08;
44 pub const SMB1_COMMAND_SET_INFORMATION:         u8 = 0x09;
45 pub const SMB1_COMMAND_READ:                    u8 = 0x0a;
46 pub const SMB1_COMMAND_WRITE:                   u8 = 0x0b;
47 pub const SMB1_COMMAND_LOCK_BYTE_RANGE:         u8 = 0x0c;
48 pub const SMB1_COMMAND_UNLOCK_BYTE_RANGE:       u8 = 0x0d;
49 pub const SMB1_COMMAND_CREATE_TEMPORARY:        u8 = 0x0e;
50 pub const SMB1_COMMAND_CREATE_NEW:              u8 = 0x0f;
51 pub const SMB1_COMMAND_CHECK_DIRECTORY:         u8 = 0x10;
52 pub const SMB1_COMMAND_PROCESS_EXIT:            u8 = 0x11;
53 pub const SMB1_COMMAND_SEEK:                    u8 = 0x12;
54 pub const SMB1_COMMAND_LOCK_AND_READ:           u8 = 0x13;
55 pub const SMB1_COMMAND_WRITE_AND_UNLOCK:        u8 = 0x14;
56 pub const SMB1_COMMAND_LOCKING_ANDX:            u8 = 0x24;
57 pub const SMB1_COMMAND_TRANS:                   u8 = 0x25;
58 pub const SMB1_COMMAND_ECHO:                    u8 = 0x2b;
59 pub const SMB1_COMMAND_WRITE_AND_CLOSE:         u8 = 0x2c;
60 pub const SMB1_COMMAND_OPEN_ANDX:               u8 = 0x2d;
61 pub const SMB1_COMMAND_READ_ANDX:               u8 = 0x2e;
62 pub const SMB1_COMMAND_WRITE_ANDX:              u8 = 0x2f;
63 pub const SMB1_COMMAND_TRANS2:                  u8 = 0x32;
64 pub const SMB1_COMMAND_TRANS2_SECONDARY:        u8 = 0x33;
65 pub const SMB1_COMMAND_FIND_CLOSE2:             u8 = 0x34;
66 pub const SMB1_COMMAND_TREE_DISCONNECT:         u8 = 0x71;
67 pub const SMB1_COMMAND_NEGOTIATE_PROTOCOL:      u8 = 0x72;
68 pub const SMB1_COMMAND_SESSION_SETUP_ANDX:      u8 = 0x73;
69 pub const SMB1_COMMAND_LOGOFF_ANDX:             u8 = 0x74;
70 pub const SMB1_COMMAND_TREE_CONNECT_ANDX:       u8 = 0x75;
71 pub const SMB1_COMMAND_QUERY_INFO_DISK:         u8 = 0x80;
72 pub const SMB1_COMMAND_NT_TRANS:                u8 = 0xa0;
73 pub const SMB1_COMMAND_NT_CREATE_ANDX:          u8 = 0xa2;
74 pub const SMB1_COMMAND_NT_CANCEL:               u8 = 0xa4;
75 
smb1_command_string(c: u8) -> String76 pub fn smb1_command_string(c: u8) -> String {
77     match c {
78         SMB1_COMMAND_CREATE_DIRECTORY   => "SMB1_COMMAND_CREATE_DIRECTORY",
79         SMB1_COMMAND_DELETE_DIRECTORY   => "SMB1_COMMAND_DELETE_DIRECTORY",
80         SMB1_COMMAND_OPEN               => "SMB1_COMMAND_OPEN",
81         SMB1_COMMAND_CREATE             => "SMB1_COMMAND_CREATE",
82         SMB1_COMMAND_CLOSE              => "SMB1_COMMAND_CLOSE",
83         SMB1_COMMAND_FLUSH              => "SMB1_COMMAND_FLUSH",
84         SMB1_COMMAND_DELETE             => "SMB1_COMMAND_DELETE",
85         SMB1_COMMAND_RENAME             => "SMB1_COMMAND_RENAME",
86         SMB1_COMMAND_QUERY_INFORMATION  => "SMB1_COMMAND_QUERY_INFORMATION",
87         SMB1_COMMAND_SET_INFORMATION    => "SMB1_COMMAND_SET_INFORMATION",
88         SMB1_COMMAND_READ               => "SMB1_COMMAND_READ",
89         SMB1_COMMAND_WRITE              => "SMB1_COMMAND_WRITE",
90         SMB1_COMMAND_LOCK_BYTE_RANGE    => "SMB1_COMMAND_LOCK_BYTE_RANGE",
91         SMB1_COMMAND_UNLOCK_BYTE_RANGE  => "SMB1_COMMAND_UNLOCK_BYTE_RANGE",
92         SMB1_COMMAND_CREATE_TEMPORARY   => "SMB1_COMMAND_CREATE_TEMPORARY",
93         SMB1_COMMAND_CREATE_NEW         => "SMB1_COMMAND_CREATE_NEW",
94         SMB1_COMMAND_CHECK_DIRECTORY    => "SMB1_COMMAND_CHECK_DIRECTORY",
95         SMB1_COMMAND_PROCESS_EXIT       => "SMB1_COMMAND_PROCESS_EXIT",
96         SMB1_COMMAND_SEEK               => "SMB1_COMMAND_SEEK",
97         SMB1_COMMAND_LOCK_AND_READ      => "SMB1_COMMAND_LOCK_AND_READ",
98         SMB1_COMMAND_WRITE_AND_UNLOCK   => "SMB1_COMMAND_WRITE_AND_UNLOCK",
99         SMB1_COMMAND_LOCKING_ANDX       => "SMB1_COMMAND_LOCKING_ANDX",
100         SMB1_COMMAND_ECHO               => "SMB1_COMMAND_ECHO",
101         SMB1_COMMAND_WRITE_AND_CLOSE    => "SMB1_COMMAND_WRITE_AND_CLOSE",
102         SMB1_COMMAND_OPEN_ANDX          => "SMB1_COMMAND_OPEN_ANDX",
103         SMB1_COMMAND_READ_ANDX          => "SMB1_COMMAND_READ_ANDX",
104         SMB1_COMMAND_WRITE_ANDX         => "SMB1_COMMAND_WRITE_ANDX",
105         SMB1_COMMAND_TRANS              => "SMB1_COMMAND_TRANS",
106         SMB1_COMMAND_TRANS2             => "SMB1_COMMAND_TRANS2",
107         SMB1_COMMAND_TRANS2_SECONDARY   => "SMB1_COMMAND_TRANS2_SECONDARY",
108         SMB1_COMMAND_FIND_CLOSE2        => "SMB1_COMMAND_FIND_CLOSE2",
109         SMB1_COMMAND_TREE_DISCONNECT    => "SMB1_COMMAND_TREE_DISCONNECT",
110         SMB1_COMMAND_NEGOTIATE_PROTOCOL => "SMB1_COMMAND_NEGOTIATE_PROTOCOL",
111         SMB1_COMMAND_SESSION_SETUP_ANDX => "SMB1_COMMAND_SESSION_SETUP_ANDX",
112         SMB1_COMMAND_LOGOFF_ANDX        => "SMB1_COMMAND_LOGOFF_ANDX",
113         SMB1_COMMAND_TREE_CONNECT_ANDX  => "SMB1_COMMAND_TREE_CONNECT_ANDX",
114         SMB1_COMMAND_QUERY_INFO_DISK    => "SMB1_COMMAND_QUERY_INFO_DISK",
115         SMB1_COMMAND_NT_TRANS           => "SMB1_COMMAND_NT_TRANS",
116         SMB1_COMMAND_NT_CREATE_ANDX     => "SMB1_COMMAND_NT_CREATE_ANDX",
117         SMB1_COMMAND_NT_CANCEL          => "SMB1_COMMAND_NT_CANCEL",
118         _ => { return (c).to_string(); },
119     }.to_string()
120 }
121 
122 // later we'll use this to determine if we need to
123 // track a ssn per type
smb1_create_new_tx(cmd: u8) -> bool124 pub fn smb1_create_new_tx(cmd: u8) -> bool {
125     match cmd {
126         SMB1_COMMAND_READ_ANDX |
127         SMB1_COMMAND_WRITE_ANDX |
128         SMB1_COMMAND_TRANS |
129         SMB1_COMMAND_TRANS2 => { false },
130         _ => { true },
131     }
132 }
133 
134 // see if we're going to do a lookup for a TX.
135 // related to smb1_create_new_tx(), however it
136 // excludes the 'maybe' commands like TRANS2
smb1_check_tx(cmd: u8) -> bool137 pub fn smb1_check_tx(cmd: u8) -> bool {
138     match cmd {
139         SMB1_COMMAND_READ_ANDX |
140         SMB1_COMMAND_WRITE_ANDX |
141         SMB1_COMMAND_TRANS => { false },
142         _ => { true },
143     }
144 }
145 
smb1_close_file(state: &mut SMBState, fid: &Vec<u8>)146 fn smb1_close_file(state: &mut SMBState, fid: &Vec<u8>)
147 {
148     // we can have created 2 txs for a FID: one for reads
149     // and one for writes. So close both.
150     match state.get_file_tx_by_fuid(&fid, STREAM_TOSERVER) {
151         Some((tx, files, flags)) => {
152             SCLogDebug!("found tx {}", tx.id);
153             if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data {
154                 if !tx.request_done {
155                     SCLogDebug!("closing file tx {} FID {:?}", tx.id, fid);
156                     tdf.file_tracker.close(files, flags);
157                     tx.request_done = true;
158                     tx.response_done = true;
159                     SCLogDebug!("tx {} is done", tx.id);
160                 }
161             }
162         },
163         None => { },
164     }
165     match state.get_file_tx_by_fuid(&fid, STREAM_TOCLIENT) {
166         Some((tx, files, flags)) => {
167             SCLogDebug!("found tx {}", tx.id);
168             if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data {
169                 if !tx.request_done {
170                     SCLogDebug!("closing file tx {} FID {:?}", tx.id, fid);
171                     tdf.file_tracker.close(files, flags);
172                     tx.request_done = true;
173                     tx.response_done = true;
174                     SCLogDebug!("tx {} is done", tx.id);
175                 }
176             }
177         },
178         None => { },
179     }
180 }
181 
smb1_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32182 pub fn smb1_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32 {
183     SCLogDebug!("record: command {}: record {:?}", r.command, r);
184 
185     let mut events : Vec<SMBEvent> = Vec::new();
186     let mut no_response_expected = false;
187 
188     let have_tx = match r.command {
189         SMB1_COMMAND_RENAME => {
190             match parse_smb_rename_request_record(r.data) {
191                 Ok((_, rd)) => {
192                     SCLogDebug!("RENAME {:?}", rd);
193 
194                     let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX);
195                     let mut newname = rd.newname;
196                     newname.retain(|&i|i != 0x00);
197                     let mut oldname = rd.oldname;
198                     oldname.retain(|&i|i != 0x00);
199 
200                     let tx = state.new_rename_tx(Vec::new(), oldname, newname);
201                     tx.hdr = tx_hdr;
202                     tx.request_done = true;
203                     tx.vercmd.set_smb1_cmd(SMB1_COMMAND_RENAME);
204                     true
205                 },
206                 _ => {
207                     events.push(SMBEvent::MalformedData);
208                     false
209                 },
210             }
211         },
212         SMB1_COMMAND_TRANS2 => {
213             match parse_smb_trans2_request_record(r.data) {
214                 Ok((_, rd)) => {
215                     SCLogDebug!("TRANS2 DONE {:?}", rd);
216 
217                     if rd.subcmd == 6 {
218                         SCLogDebug!("SET_PATH_INFO");
219                         match parse_trans2_request_params_set_path_info(rd.setup_blob) {
220                             Ok((_, pd)) => {
221                                 SCLogDebug!("TRANS2 SET_PATH_INFO PARAMS DONE {:?}", pd);
222 
223                                 if pd.loi == 1013 { // set disposition info
224                                     match parse_trans2_request_data_set_file_info_disposition(rd.data_blob) {
225                                         Ok((_, disp)) => {
226                                             SCLogDebug!("TRANS2 SET_FILE_INFO DATA DISPOSITION DONE {:?}", disp);
227                                             let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX);
228 
229                                             let tx = state.new_setpathinfo_tx(pd.oldname,
230                                                     rd.subcmd, pd.loi, disp.delete);
231                                             tx.hdr = tx_hdr;
232                                             tx.request_done = true;
233                                             tx.vercmd.set_smb1_cmd(SMB1_COMMAND_TRANS2);
234                                             true
235 
236                                         },
237                                         Err(nom::Err::Incomplete(_n)) => {
238                                             SCLogDebug!("TRANS2 SET_FILE_INFO DATA DISPOSITION INCOMPLETE {:?}", _n);
239                                             events.push(SMBEvent::MalformedData);
240                                             false
241                                         },
242                                         Err(nom::Err::Error(_e)) |
243                                         Err(nom::Err::Failure(_e)) => {
244                                             SCLogDebug!("TRANS2 SET_FILE_INFO DATA DISPOSITION ERROR {:?}", _e);
245                                             events.push(SMBEvent::MalformedData);
246                                             false
247                                         },
248                                     }
249                                 } else if pd.loi == 1010 {
250                                     match parse_trans2_request_data_set_path_info_rename(rd.data_blob) {
251                                         Ok((_, ren)) => {
252                                             SCLogDebug!("TRANS2 SET_PATH_INFO DATA RENAME DONE {:?}", ren);
253                                             let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX);
254                                             let mut newname = ren.newname.to_vec();
255                                             newname.retain(|&i|i != 0x00);
256 
257                                             let fid : Vec<u8> = Vec::new();
258 
259                                             let tx = state.new_rename_tx(fid, pd.oldname, newname);
260                                             tx.hdr = tx_hdr;
261                                             tx.request_done = true;
262                                             tx.vercmd.set_smb1_cmd(SMB1_COMMAND_TRANS2);
263                                             true
264                                         },
265                                         Err(nom::Err::Incomplete(_n)) => {
266                                             SCLogDebug!("TRANS2 SET_PATH_INFO DATA RENAME INCOMPLETE {:?}", _n);
267                                             events.push(SMBEvent::MalformedData);
268                                             false
269                                         },
270                                         Err(nom::Err::Error(_e)) |
271                                         Err(nom::Err::Failure(_e)) => {
272                                             SCLogDebug!("TRANS2 SET_PATH_INFO DATA RENAME ERROR {:?}", _e);
273                                             events.push(SMBEvent::MalformedData);
274                                             false
275                                         },
276                                     }
277                                 } else {
278                                     false
279                                 }
280                             },
281                             Err(nom::Err::Incomplete(_n)) => {
282                                 SCLogDebug!("TRANS2 SET_PATH_INFO PARAMS INCOMPLETE {:?}", _n);
283                                 events.push(SMBEvent::MalformedData);
284                                 false
285                             },
286                             Err(nom::Err::Error(_e)) |
287                             Err(nom::Err::Failure(_e)) => {
288                                 SCLogDebug!("TRANS2 SET_PATH_INFO PARAMS ERROR {:?}", _e);
289                                 events.push(SMBEvent::MalformedData);
290                                 false
291                             },
292                         }
293                     } else if rd.subcmd == 8 {
294                         SCLogDebug!("SET_FILE_INFO");
295                         match parse_trans2_request_params_set_file_info(rd.setup_blob) {
296                             Ok((_, pd)) => {
297                                 SCLogDebug!("TRANS2 SET_FILE_INFO PARAMS DONE {:?}", pd);
298 
299                                 if pd.loi == 1013 { // set disposition info
300                                     match parse_trans2_request_data_set_file_info_disposition(rd.data_blob) {
301                                         Ok((_, disp)) => {
302                                             SCLogDebug!("TRANS2 SET_FILE_INFO DATA DISPOSITION DONE {:?}", disp);
303                                             let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX);
304 
305                                             let mut frankenfid = pd.fid.to_vec();
306                                             frankenfid.extend_from_slice(&u32_as_bytes(r.ssn_id));
307 
308                                             let filename = match state.guid2name_map.get(&frankenfid) {
309                                                 Some(n) => n.to_vec(),
310                                                 None => b"<unknown>".to_vec(),
311                                             };
312                                             let tx = state.new_setfileinfo_tx(filename, pd.fid.to_vec(),
313                                                     rd.subcmd, pd.loi, disp.delete);
314                                             tx.hdr = tx_hdr;
315                                             tx.request_done = true;
316                                             tx.vercmd.set_smb1_cmd(SMB1_COMMAND_TRANS2);
317                                             true
318 
319                                         },
320                                         Err(nom::Err::Incomplete(_n)) => {
321                                             SCLogDebug!("TRANS2 SET_FILE_INFO DATA DISPOSITION INCOMPLETE {:?}", _n);
322                                             events.push(SMBEvent::MalformedData);
323                                             false
324                                         },
325                                         Err(nom::Err::Error(_e)) |
326                                         Err(nom::Err::Failure(_e)) => {
327                                             SCLogDebug!("TRANS2 SET_FILE_INFO DATA DISPOSITION ERROR {:?}", _e);
328                                             events.push(SMBEvent::MalformedData);
329                                             false
330                                         },
331                                     }
332                                 } else if pd.loi == 1010 {
333                                     match parse_trans2_request_data_set_file_info_rename(rd.data_blob) {
334                                         Ok((_, ren)) => {
335                                             SCLogDebug!("TRANS2 SET_FILE_INFO DATA RENAME DONE {:?}", ren);
336                                             let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX);
337                                             let mut newname = ren.newname.to_vec();
338                                             newname.retain(|&i|i != 0x00);
339 
340                                             let mut frankenfid = pd.fid.to_vec();
341                                             frankenfid.extend_from_slice(&u32_as_bytes(r.ssn_id));
342 
343                                             let oldname = match state.guid2name_map.get(&frankenfid) {
344                                                 Some(n) => n.to_vec(),
345                                                 None => b"<unknown>".to_vec(),
346                                             };
347                                             let tx = state.new_rename_tx(pd.fid.to_vec(), oldname, newname);
348                                             tx.hdr = tx_hdr;
349                                             tx.request_done = true;
350                                             tx.vercmd.set_smb1_cmd(SMB1_COMMAND_TRANS2);
351                                             true
352                                         },
353                                         Err(nom::Err::Incomplete(_n)) => {
354                                             SCLogDebug!("TRANS2 SET_FILE_INFO DATA RENAME INCOMPLETE {:?}", _n);
355                                             events.push(SMBEvent::MalformedData);
356                                             false
357                                         },
358                                         Err(nom::Err::Error(_e)) |
359                                         Err(nom::Err::Failure(_e)) => {
360                                             SCLogDebug!("TRANS2 SET_FILE_INFO DATA RENAME ERROR {:?}", _e);
361                                             events.push(SMBEvent::MalformedData);
362                                             false
363                                         },
364                                     }
365                                 } else {
366                                     false
367                                 }
368                             },
369                             Err(nom::Err::Incomplete(_n)) => {
370                                 SCLogDebug!("TRANS2 SET_FILE_INFO PARAMS INCOMPLETE {:?}", _n);
371                                 events.push(SMBEvent::MalformedData);
372                                 false
373                             },
374                             Err(nom::Err::Error(_e)) |
375                             Err(nom::Err::Failure(_e)) => {
376                                 SCLogDebug!("TRANS2 SET_FILE_INFO PARAMS ERROR {:?}", _e);
377                                 events.push(SMBEvent::MalformedData);
378                                 false
379                             },
380                         }
381                     } else {
382                         false
383                     }
384                 },
385                 Err(nom::Err::Incomplete(_n)) => {
386                     SCLogDebug!("TRANS2 INCOMPLETE {:?}", _n);
387                     events.push(SMBEvent::MalformedData);
388                     false
389                 },
390                 Err(nom::Err::Error(_e)) |
391                 Err(nom::Err::Failure(_e)) => {
392                     SCLogDebug!("TRANS2 ERROR {:?}", _e);
393                     events.push(SMBEvent::MalformedData);
394                     false
395                 },
396             }
397         },
398         SMB1_COMMAND_READ_ANDX => {
399             match parse_smb_read_andx_request_record(r.data) {
400                 Ok((_, rr)) => {
401                     SCLogDebug!("rr {:?}", rr);
402 
403                     // store read fid,offset in map
404                     let fid_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_OFFSET);
405                     let mut fid = rr.fid.to_vec();
406                     fid.extend_from_slice(&u32_as_bytes(r.ssn_id));
407                     let fidoff = SMBFileGUIDOffset::new(fid, rr.offset);
408                     state.ssn2vecoffset_map.insert(fid_key, fidoff);
409                 },
410                 _ => {
411                     events.push(SMBEvent::MalformedData);
412                 },
413             }
414             false
415         },
416         SMB1_COMMAND_WRITE_ANDX |
417         SMB1_COMMAND_WRITE |
418         SMB1_COMMAND_WRITE_AND_CLOSE => {
419             smb1_write_request_record(state, r);
420             true // tx handling in func
421         },
422         SMB1_COMMAND_TRANS => {
423             smb1_trans_request_record(state, r);
424             true
425         },
426         SMB1_COMMAND_NEGOTIATE_PROTOCOL => {
427             match parse_smb1_negotiate_protocol_record(r.data) {
428                 Ok((_, pr)) => {
429                     SCLogDebug!("SMB_COMMAND_NEGOTIATE_PROTOCOL {:?}", pr);
430 
431                     let mut bad_dialects = false;
432                     let mut dialects : Vec<Vec<u8>> = Vec::new();
433                     for d in &pr.dialects {
434                         if d.len() == 0 {
435                             bad_dialects = true;
436                             continue;
437                         } else if d.len() == 1 {
438                             bad_dialects = true;
439                         }
440                         let x = &d[1..d.len()];
441                         let dvec = x.to_vec();
442                         dialects.push(dvec);
443                     }
444 
445                     let found = match state.get_negotiate_tx(1) {
446                         Some(tx) => {
447                             SCLogDebug!("WEIRD, should not have NEGOTIATE tx!");
448                             tx.set_event(SMBEvent::DuplicateNegotiate);
449                             true
450                         },
451                         None => { false },
452                     };
453                     if !found {
454                         let tx = state.new_negotiate_tx(1);
455                         if let Some(SMBTransactionTypeData::NEGOTIATE(ref mut tdn)) = tx.type_data {
456                             tdn.dialects = dialects;
457                         }
458                         tx.request_done = true;
459                         if bad_dialects {
460                             tx.set_event(SMBEvent::NegotiateMalformedDialects);
461                         }
462                     }
463                     true
464                 },
465                 _ => {
466                     events.push(SMBEvent::MalformedData);
467                     false
468                 },
469             }
470         },
471         SMB1_COMMAND_NT_CREATE_ANDX => {
472             match parse_smb_create_andx_request_record(r.data, r) {
473                 Ok((_, cr)) => {
474                     SCLogDebug!("Create AndX {:?}", cr);
475                     let del = cr.create_options & 0x0000_1000 != 0;
476                     let dir = cr.create_options & 0x0000_0001 != 0;
477                     SCLogDebug!("del {} dir {} options {:08x}", del, dir, cr.create_options);
478 
479                     let name_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_FILENAME);
480                     let name_val = cr.file_name.to_vec();
481                     state.ssn2vec_map.insert(name_key, name_val);
482 
483                     let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX);
484                     let tx = state.new_create_tx(&cr.file_name.to_vec(),
485                             cr.disposition, del, dir, tx_hdr);
486                     tx.vercmd.set_smb1_cmd(r.command);
487                     SCLogDebug!("TS CREATE TX {} created", tx.id);
488                     true
489                 },
490                 _ => {
491                     events.push(SMBEvent::MalformedData);
492                     false
493                 },
494             }
495         },
496         SMB1_COMMAND_SESSION_SETUP_ANDX => {
497             SCLogDebug!("SMB1_COMMAND_SESSION_SETUP_ANDX user_id {}", r.user_id);
498             smb1_session_setup_request(state, r);
499             true
500         },
501         SMB1_COMMAND_TREE_CONNECT_ANDX => {
502             SCLogDebug!("SMB1_COMMAND_TREE_CONNECT_ANDX");
503             match parse_smb_connect_tree_andx_record(r.data, r) {
504                 Ok((_, tr)) => {
505                     let name_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_TREE);
506                     let mut name_val = tr.path;
507                     if name_val.len() > 1 {
508                         name_val = name_val[1..].to_vec();
509                     }
510 
511                     // store hdr as SMBHDR_TYPE_TREE, so with tree id 0
512                     // when the response finds this we update it
513                     let tx = state.new_treeconnect_tx(name_key, name_val);
514                     if let Some(SMBTransactionTypeData::TREECONNECT(ref mut tdn)) = tx.type_data {
515                         tdn.req_service = Some(tr.service.to_vec());
516                     }
517                     tx.request_done = true;
518                     tx.vercmd.set_smb1_cmd(SMB1_COMMAND_TREE_CONNECT_ANDX);
519                     true
520                 },
521                 _ => {
522                     events.push(SMBEvent::MalformedData);
523                     false
524                 },
525             }
526         },
527         SMB1_COMMAND_TREE_DISCONNECT => {
528             let tree_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_SHARE);
529             state.ssn2tree_map.remove(&tree_key);
530             false
531         },
532         SMB1_COMMAND_CLOSE => {
533             match parse_smb1_close_request_record(r.data) {
534                 Ok((_, cd)) => {
535                     let mut fid = cd.fid.to_vec();
536                     fid.extend_from_slice(&u32_as_bytes(r.ssn_id));
537                     SCLogDebug!("closing FID {:?}/{:?}", cd.fid, fid);
538                     smb1_close_file(state, &fid);
539                 },
540                 _ => {
541                     events.push(SMBEvent::MalformedData);
542                 },
543             }
544             false
545         },
546         SMB1_COMMAND_NT_CANCEL |
547         SMB1_COMMAND_TRANS2_SECONDARY |
548         SMB1_COMMAND_LOCKING_ANDX => {
549             no_response_expected = true;
550             false
551         },
552         _ => {
553             if r.command == SMB1_COMMAND_LOGOFF_ANDX ||
554                r.command == SMB1_COMMAND_TREE_DISCONNECT ||
555                r.command == SMB1_COMMAND_NT_TRANS ||
556                r.command == SMB1_COMMAND_NT_CANCEL ||
557                r.command == SMB1_COMMAND_RENAME ||
558                r.command == SMB1_COMMAND_CHECK_DIRECTORY ||
559                r.command == SMB1_COMMAND_ECHO ||
560                r.command == SMB1_COMMAND_TRANS
561             { } else {
562                  SCLogDebug!("unsupported command {}/{}",
563                          r.command, &smb1_command_string(r.command));
564             }
565             false
566         },
567     };
568     if !have_tx {
569         if smb1_create_new_tx(r.command) {
570             let tx_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX);
571             let tx = state.new_generic_tx(1, r.command as u16, tx_key);
572             SCLogDebug!("tx {} created for {}/{}", tx.id, r.command, &smb1_command_string(r.command));
573             tx.set_events(events);
574             if no_response_expected {
575                 tx.response_done = true;
576             }
577         }
578     }
579     0
580 }
581 
smb1_response_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32582 pub fn smb1_response_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32 {
583     SCLogDebug!("record: command {} status {} -> {:?}", r.command, r.nt_status, r);
584 
585     let key_ssn_id = r.ssn_id;
586     let key_tree_id = r.tree_id;
587     let key_multiplex_id = r.multiplex_id;
588     let mut tx_sync = false;
589     let mut events : Vec<SMBEvent> = Vec::new();
590 
591     let have_tx = match r.command {
592         SMB1_COMMAND_READ_ANDX => {
593             smb1_read_response_record(state, &r);
594             true // tx handling in func
595         },
596         SMB1_COMMAND_NEGOTIATE_PROTOCOL => {
597             SCLogDebug!("SMB1_COMMAND_NEGOTIATE_PROTOCOL response");
598             match parse_smb1_negotiate_protocol_response_record(r.data) {
599                 Ok((_, pr)) => {
600                     let (have_ntx, dialect) = match state.get_negotiate_tx(1) {
601                         Some(tx) => {
602                             tx.set_status(r.nt_status, r.is_dos_error);
603                             tx.response_done = true;
604                             SCLogDebug!("tx {} is done", tx.id);
605                             let d = match tx.type_data {
606                                 Some(SMBTransactionTypeData::NEGOTIATE(ref mut x)) => {
607                                     x.server_guid = pr.server_guid.to_vec();
608 
609                                     let dialect_idx = pr.dialect_idx as usize;
610                                     if x.dialects.len() <= dialect_idx {
611                                         None
612                                     } else {
613                                         let d = x.dialects[dialect_idx].to_vec();
614                                         Some(d)
615                                     }
616                                 },
617                                 _ => { None },
618                             };
619                             if d == None {
620                                 tx.set_event(SMBEvent::NegotiateMalformedDialects);
621                             }
622                             (true, d)
623                         },
624                         None => { (false, None) },
625                     };
626                     if let Some(d) = dialect {
627                         SCLogDebug!("dialect {:?}", d);
628                         state.dialect_vec = Some(d);
629                     }
630                     have_ntx
631                 },
632                 _ => {
633                     events.push(SMBEvent::MalformedData);
634                     false
635                 },
636             }
637         },
638         SMB1_COMMAND_TREE_CONNECT_ANDX => {
639             if r.nt_status != SMB_NTSTATUS_SUCCESS {
640                 let name_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_TREE);
641                 match state.get_treeconnect_tx(name_key) {
642                     Some(tx) => {
643                         if let Some(SMBTransactionTypeData::TREECONNECT(ref mut tdn)) = tx.type_data {
644                             tdn.tree_id = r.tree_id as u32;
645                         }
646                         tx.set_status(r.nt_status, r.is_dos_error);
647                         tx.response_done = true;
648                         SCLogDebug!("tx {} is done", tx.id);
649                     },
650                     None => { },
651                 }
652                 return 0;
653             }
654 
655             match parse_smb_connect_tree_andx_response_record(r.data) {
656                 Ok((_, tr)) => {
657                     let name_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_TREE);
658                     let is_pipe = tr.service == "IPC".as_bytes();
659                     let mut share_name = Vec::new();
660                     let found = match state.get_treeconnect_tx(name_key) {
661                         Some(tx) => {
662                             if let Some(SMBTransactionTypeData::TREECONNECT(ref mut tdn)) = tx.type_data {
663                                 tdn.is_pipe = is_pipe;
664                                 tdn.tree_id = r.tree_id as u32;
665                                 share_name = tdn.share_name.to_vec();
666                                 tdn.res_service = Some(tr.service.to_vec());
667                             }
668                             tx.hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_HEADER);
669                             tx.set_status(r.nt_status, r.is_dos_error);
670                             tx.response_done = true;
671                             SCLogDebug!("tx {} is done", tx.id);
672                             true
673                         },
674                         None => { false },
675                     };
676                     if found {
677                         let tree = SMBTree::new(share_name.to_vec(), is_pipe);
678                         let tree_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_SHARE);
679                         state.ssn2tree_map.insert(tree_key, tree);
680                     }
681                     found
682                 },
683                 _ => {
684                     events.push(SMBEvent::MalformedData);
685                     false
686                 },
687             }
688         },
689         SMB1_COMMAND_TREE_DISCONNECT => {
690             // normally removed when processing request,
691             // but in case we missed that try again here
692             let tree_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_SHARE);
693             state.ssn2tree_map.remove(&tree_key);
694             false
695         },
696         SMB1_COMMAND_NT_CREATE_ANDX => {
697             SCLogDebug!("SMB1_COMMAND_NT_CREATE_ANDX response {:08x}", r.nt_status);
698             if r.nt_status == SMB_NTSTATUS_SUCCESS {
699                 match parse_smb_create_andx_response_record(r.data) {
700                     Ok((_, cr)) => {
701                         SCLogDebug!("Create AndX {:?}", cr);
702 
703                         let guid_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_FILENAME);
704                         match state.ssn2vec_map.remove(&guid_key) {
705                             Some(mut p) => {
706                                 p.retain(|&i|i != 0x00);
707 
708                                 let mut fid = cr.fid.to_vec();
709                                 fid.extend_from_slice(&u32_as_bytes(r.ssn_id));
710                                 SCLogDebug!("SMB1_COMMAND_NT_CREATE_ANDX fid {:?}", fid);
711                                 SCLogDebug!("fid {:?} name {:?}", fid, p);
712                                 state.guid2name_map.insert(fid, p);
713                             },
714                             _ => {
715                                 SCLogDebug!("SMBv1 response: GUID NOT FOUND");
716                             },
717                         }
718 
719                         let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX);
720                         if let Some(tx) = state.get_generic_tx(1, r.command as u16, &tx_hdr) {
721                             SCLogDebug!("tx {} with {}/{} marked as done",
722                                     tx.id, r.command, &smb1_command_string(r.command));
723                             tx.set_status(r.nt_status, false);
724                             tx.response_done = true;
725 
726                             if let Some(SMBTransactionTypeData::CREATE(ref mut tdn)) = tx.type_data {
727                                 tdn.create_ts = cr.create_ts.as_unix();
728                                 tdn.last_access_ts = cr.last_access_ts.as_unix();
729                                 tdn.last_write_ts = cr.last_write_ts.as_unix();
730                                 tdn.last_change_ts = cr.last_change_ts.as_unix();
731                                 tdn.size = cr.file_size;
732                                 tdn.guid = cr.fid.to_vec();
733                             }
734                         }
735                         true
736                     },
737                     _ => {
738                         events.push(SMBEvent::MalformedData);
739                         false
740                     },
741                 }
742             } else {
743                 false
744             }
745         },
746         SMB1_COMMAND_TRANS => {
747             smb1_trans_response_record(state, r);
748             true
749         },
750         SMB1_COMMAND_SESSION_SETUP_ANDX => {
751             smb1_session_setup_response(state, r);
752             true
753         },
754         SMB1_COMMAND_LOGOFF_ANDX => {
755             tx_sync = true;
756             false
757         },
758         _ => {
759             false
760         },
761     };
762 
763     if !have_tx && tx_sync {
764         match state.get_last_tx(1, r.command as u16) {
765             Some(tx) => {
766                 SCLogDebug!("last TX {} is CMD {}", tx.id, &smb1_command_string(r.command));
767                 tx.response_done = true;
768                 SCLogDebug!("tx {} cmd {} is done", tx.id, r.command);
769                 tx.set_status(r.nt_status, r.is_dos_error);
770                 tx.set_events(events);
771             },
772             _ => {},
773         }
774     } else if !have_tx && smb1_check_tx(r.command) {
775         let tx_key = SMBCommonHdr::new(SMBHDR_TYPE_GENERICTX,
776                 key_ssn_id as u64, key_tree_id as u32, key_multiplex_id as u64);
777         let _have_tx2 = match state.get_generic_tx(1, r.command as u16, &tx_key) {
778             Some(tx) => {
779                 tx.request_done = true;
780                 tx.response_done = true;
781                 SCLogDebug!("tx {} cmd {} is done", tx.id, r.command);
782                 tx.set_status(r.nt_status, r.is_dos_error);
783                 tx.set_events(events);
784                 true
785             },
786             _ => {
787                 SCLogDebug!("no TX found for key {:?}", tx_key);
788                 false
789             },
790         };
791     } else {
792         SCLogDebug!("have tx for cmd {}", r.command);
793     }
794     0
795 }
796 
smb1_trans_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>)797 pub fn smb1_trans_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>)
798 {
799     let mut events : Vec<SMBEvent> = Vec::new();
800 
801     match parse_smb_trans_request_record(r.data, r) {
802         Ok((_, rd)) => {
803             SCLogDebug!("TRANS request {:?}", rd);
804 
805             /* if we have a fid, store it so the response can pick it up */
806             let mut pipe_dcerpc = false;
807             if rd.pipe != None {
808                 let pipe = rd.pipe.unwrap();
809                 state.ssn2vec_map.insert(SMBCommonHdr::from1(r, SMBHDR_TYPE_GUID),
810                         pipe.fid.to_vec());
811 
812                 let mut frankenfid = pipe.fid.to_vec();
813                 frankenfid.extend_from_slice(&u32_as_bytes(r.ssn_id));
814 
815                 let (_filename, is_dcerpc) = match state.get_service_for_guid(&frankenfid) {
816                     (n, x) => (n, x),
817                 };
818                 SCLogDebug!("smb1_trans_request_record: name {} is_dcerpc {}",
819                         _filename, is_dcerpc);
820                 pipe_dcerpc = is_dcerpc;
821             }
822 
823             if pipe_dcerpc {
824                 SCLogDebug!("SMBv1 TRANS TO PIPE");
825                 let hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_HEADER);
826                 let vercmd = SMBVerCmdStat::new1(r.command);
827                 smb_write_dcerpc_record(state, vercmd, hdr, &rd.data.data);
828             }
829         },
830         _ => {
831             events.push(SMBEvent::MalformedData);
832         },
833     }
834     smb1_request_record_generic(state, r, events);
835 }
836 
smb1_trans_response_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>)837 pub fn smb1_trans_response_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>)
838 {
839     let mut events : Vec<SMBEvent> = Vec::new();
840 
841     match parse_smb_trans_response_record(r.data) {
842         Ok((_, rd)) => {
843             SCLogDebug!("TRANS response {:?}", rd);
844 
845             // see if we have a stored fid
846             let fid = match state.ssn2vec_map.remove(
847                     &SMBCommonHdr::from1(r, SMBHDR_TYPE_GUID)) {
848                 Some(f) => f,
849                 None => Vec::new(),
850             };
851             SCLogDebug!("FID {:?}", fid);
852 
853             let mut frankenfid = fid.to_vec();
854             frankenfid.extend_from_slice(&u32_as_bytes(r.ssn_id));
855 
856             let (_filename, is_dcerpc) = match state.get_service_for_guid(&frankenfid) {
857                 (n, x) => (n, x),
858             };
859             SCLogDebug!("smb1_trans_response_record: name {} is_dcerpc {}",
860                     _filename, is_dcerpc);
861 
862             // if we get status 'BUFFER_OVERFLOW' this is only a part of
863             // the data. Store it in the ssn/tree for later use.
864             if r.nt_status == SMB_NTSTATUS_BUFFER_OVERFLOW {
865                 let key = SMBHashKeyHdrGuid::new(SMBCommonHdr::from1(r, SMBHDR_TYPE_TRANS_FRAG), fid);
866                 SCLogDebug!("SMBv1/TRANS: queueing data for len {} key {:?}", rd.data.len(), key);
867                 state.ssnguid2vec_map.insert(key, rd.data.to_vec());
868             } else if is_dcerpc {
869                 SCLogDebug!("SMBv1 TRANS TO PIPE");
870                 let hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_HEADER);
871                 let vercmd = SMBVerCmdStat::new1_with_ntstatus(r.command, r.nt_status);
872                 smb_read_dcerpc_record(state, vercmd, hdr, &fid, &rd.data);
873             }
874         },
875         _ => {
876             events.push(SMBEvent::MalformedData);
877         },
878     }
879 
880     // generic tx as well. Set events if needed.
881     smb1_response_record_generic(state, r, events);
882 }
883 
884 /// Handle WRITE, WRITE_ANDX, WRITE_AND_CLOSE request records
smb1_write_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>)885 pub fn smb1_write_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>)
886 {
887     let mut events : Vec<SMBEvent> = Vec::new();
888 
889     let result = if r.command == SMB1_COMMAND_WRITE_ANDX {
890         parse_smb1_write_andx_request_record(r.data)
891     } else if r.command == SMB1_COMMAND_WRITE {
892         parse_smb1_write_request_record(r.data)
893     } else {
894         parse_smb1_write_and_close_request_record(r.data)
895     };
896     match result {
897         Ok((_, rd)) => {
898             SCLogDebug!("SMBv1: write andx => {:?}", rd);
899 
900             let mut file_fid = rd.fid.to_vec();
901             file_fid.extend_from_slice(&u32_as_bytes(r.ssn_id));
902             SCLogDebug!("SMBv1 WRITE: FID {:?} offset {}",
903                     file_fid, rd.offset);
904 
905             let file_name = match state.guid2name_map.get(&file_fid) {
906                 Some(n) => n.to_vec(),
907                 None => b"<unknown>".to_vec(),
908             };
909             let mut set_event_fileoverlap = false;
910             let found = match state.get_file_tx_by_fuid(&file_fid, STREAM_TOSERVER) {
911                 Some((tx, files, flags)) => {
912                     let file_id : u32 = tx.id as u32;
913                     if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data {
914                         if rd.offset < tdf.file_tracker.tracked {
915                             set_event_fileoverlap = true;
916                         }
917                         filetracker_newchunk(&mut tdf.file_tracker, files, flags,
918                                 &file_name, rd.data, rd.offset,
919                                 rd.len, 0, false, &file_id);
920                         SCLogDebug!("FID {:?} found at tx {}", file_fid, tx.id);
921                     }
922                     true
923                 },
924                 None => { false },
925             };
926             if !found {
927                 let tree_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_SHARE);
928                 let (share_name, is_pipe) = match state.ssn2tree_map.get(&tree_key) {
929                     Some(n) => (n.name.to_vec(), n.is_pipe),
930                     None => (Vec::new(), false),
931                 };
932                 if is_pipe {
933                     SCLogDebug!("SMBv1 WRITE TO PIPE");
934                     let hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_HEADER);
935                     let vercmd = SMBVerCmdStat::new1_with_ntstatus(r.command, r.nt_status);
936                     smb_write_dcerpc_record(state, vercmd, hdr, &rd.data);
937                 } else {
938                     let (tx, files, flags) = state.new_file_tx(&file_fid, &file_name, STREAM_TOSERVER);
939                     if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data {
940                         let file_id : u32 = tx.id as u32;
941                         SCLogDebug!("FID {:?} found at tx {}", file_fid, tx.id);
942                         if rd.offset < tdf.file_tracker.tracked {
943                             set_event_fileoverlap = true;
944                         }
945                         filetracker_newchunk(&mut tdf.file_tracker, files, flags,
946                                 &file_name, rd.data, rd.offset,
947                                 rd.len, 0, false, &file_id);
948                         tdf.share_name = share_name;
949                     }
950                     tx.vercmd.set_smb1_cmd(SMB1_COMMAND_WRITE_ANDX);
951                 }
952             }
953             if set_event_fileoverlap {
954                 state.set_event(SMBEvent::FileOverlap);
955             }
956 
957             state.set_file_left(STREAM_TOSERVER, rd.len, rd.data.len() as u32, file_fid.to_vec());
958 
959             if r.command == SMB1_COMMAND_WRITE_AND_CLOSE {
960                 SCLogDebug!("closing FID {:?}", file_fid);
961                 smb1_close_file(state, &file_fid);
962             }
963         },
964         _ => {
965             events.push(SMBEvent::MalformedData);
966         },
967     }
968     smb1_request_record_generic(state, r, events);
969 }
970 
smb1_read_response_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>)971 pub fn smb1_read_response_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>)
972 {
973     let mut events : Vec<SMBEvent> = Vec::new();
974 
975     if r.nt_status == SMB_NTSTATUS_SUCCESS {
976         match parse_smb_read_andx_response_record(r.data) {
977             Ok((_, rd)) => {
978                 SCLogDebug!("SMBv1: read response => {:?}", rd);
979 
980                 let fid_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_OFFSET);
981                 let (offset, file_fid) = match state.ssn2vecoffset_map.remove(&fid_key) {
982                     Some(o) => (o.offset, o.guid),
983                     None => {
984                         SCLogDebug!("SMBv1 READ response: reply to unknown request: left {} {:?}",
985                                 rd.len - rd.data.len() as u32, rd);
986                         state.set_skip(STREAM_TOCLIENT, rd.len, rd.data.len() as u32);
987                         return;
988                     },
989                 };
990                 SCLogDebug!("SMBv1 READ: FID {:?} offset {}", file_fid, offset);
991 
992                 let tree_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_SHARE);
993                 let (is_pipe, share_name) = match state.ssn2tree_map.get(&tree_key) {
994                     Some(n) => (n.is_pipe, n.name.to_vec()),
995                     _ => { (false, Vec::new()) },
996                 };
997                 if !is_pipe {
998                     let file_name = match state.guid2name_map.get(&file_fid) {
999                         Some(n) => n.to_vec(),
1000                         None => Vec::new(),
1001                     };
1002                     let mut set_event_fileoverlap = false;
1003                     let found = match state.get_file_tx_by_fuid(&file_fid, STREAM_TOCLIENT) {
1004                         Some((tx, files, flags)) => {
1005                             if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data {
1006                                 let file_id : u32 = tx.id as u32;
1007                                 SCLogDebug!("FID {:?} found at tx {}", file_fid, tx.id);
1008                                 if offset < tdf.file_tracker.tracked {
1009                                     set_event_fileoverlap = true;
1010                                 }
1011                                 filetracker_newchunk(&mut tdf.file_tracker, files, flags,
1012                                         &file_name, rd.data, offset,
1013                                         rd.len, 0, false, &file_id);
1014                             }
1015                             true
1016                         },
1017                         None => { false },
1018                     };
1019                     if !found {
1020                         let (tx, files, flags) = state.new_file_tx(&file_fid, &file_name, STREAM_TOCLIENT);
1021                         if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data {
1022                             let file_id : u32 = tx.id as u32;
1023                             SCLogDebug!("FID {:?} found at tx {}", file_fid, tx.id);
1024                             if offset < tdf.file_tracker.tracked {
1025                                 set_event_fileoverlap = true;
1026                             }
1027                             filetracker_newchunk(&mut tdf.file_tracker, files, flags,
1028                                     &file_name, rd.data, offset,
1029                                     rd.len, 0, false, &file_id);
1030                             tdf.share_name = share_name;
1031                         }
1032                         tx.vercmd.set_smb1_cmd(SMB1_COMMAND_READ_ANDX);
1033                     }
1034                     if set_event_fileoverlap {
1035                         state.set_event(SMBEvent::FileOverlap);
1036                     }
1037                 } else {
1038                     SCLogDebug!("SMBv1 READ response from PIPE");
1039                     let hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_HEADER);
1040                     let vercmd = SMBVerCmdStat::new1(r.command);
1041 
1042                     // hack: we store fid with ssn id mixed in, but here we want the
1043                     // real thing instead.
1044                     let pure_fid = if file_fid.len() > 2 { &file_fid[0..2] } else { &[] };
1045                     smb_read_dcerpc_record(state, vercmd, hdr, &pure_fid, &rd.data);
1046                 }
1047 
1048                 state.set_file_left(STREAM_TOCLIENT, rd.len, rd.data.len() as u32, file_fid.to_vec());
1049             }
1050             _ => {
1051                 events.push(SMBEvent::MalformedData);
1052             },
1053         }
1054     }
1055 
1056     // generic tx as well. Set events if needed.
1057     smb1_response_record_generic(state, r, events);
1058 }
1059 
1060 /// create a tx for a command / response pair if we're
1061 /// configured to do so, or if this is a tx especially
1062 /// for setting an event.
smb1_request_record_generic<'b>(state: &mut SMBState, r: &SmbRecord<'b>, events: Vec<SMBEvent>)1063 fn smb1_request_record_generic<'b>(state: &mut SMBState, r: &SmbRecord<'b>, events: Vec<SMBEvent>) {
1064     if smb1_create_new_tx(r.command) || events.len() > 0 {
1065         let tx_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX);
1066         let tx = state.new_generic_tx(1, r.command as u16, tx_key);
1067         tx.set_events(events);
1068     }
1069 }
1070 
1071 /// update or create a tx for a command / reponse pair based
1072 /// on the response. We only create a tx for the response side
1073 /// if we didn't already update a tx, and we have to set events
smb1_response_record_generic<'b>(state: &mut SMBState, r: &SmbRecord<'b>, events: Vec<SMBEvent>)1074 fn smb1_response_record_generic<'b>(state: &mut SMBState, r: &SmbRecord<'b>, events: Vec<SMBEvent>) {
1075     let tx_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX);
1076     match state.get_generic_tx(1, r.command as u16, &tx_key) {
1077         Some(tx) => {
1078             tx.request_done = true;
1079             tx.response_done = true;
1080             SCLogDebug!("tx {} cmd {} is done", tx.id, r.command);
1081             tx.set_status(r.nt_status, r.is_dos_error);
1082             tx.set_events(events);
1083             return;
1084         },
1085         None => {},
1086     }
1087     if events.len() > 0 {
1088         let tx = state.new_generic_tx(1, r.command as u16, tx_key);
1089         tx.request_done = true;
1090         tx.response_done = true;
1091         SCLogDebug!("tx {} cmd {} is done", tx.id, r.command);
1092         tx.set_status(r.nt_status, r.is_dos_error);
1093         tx.set_events(events);
1094     }
1095 }
1096