Coverage Report

Created: 2026-06-30 07:20

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