Coverage Report

Created: 2026-03-31 07:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/rust/src/smb/smb.rs
Line
Count
Source
1
/* Copyright (C) 2017-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
/*  GAP processing:
23
 *  - if post-gap we've seen a succesful tx req/res: we consider "re-sync'd"
24
 */
25
26
// written by Victor Julien
27
28
use std;
29
use std::str;
30
use std::ffi::{self, CString};
31
32
use std::collections::HashMap;
33
use std::collections::VecDeque;
34
 
35
use nom7::{Err, Needed};
36
use nom7::error::{make_error, ErrorKind};
37
38
use crate::core::*;
39
use crate::applayer;
40
use crate::applayer::*;
41
use crate::frames::*;
42
use crate::conf::*;
43
use crate::applayer::{AppLayerResult, AppLayerTxData, AppLayerEvent};
44
45
use crate::smb::nbss_records::*;
46
use crate::smb::smb1_records::*;
47
use crate::smb::smb2_records::*;
48
49
use crate::smb::smb1::*;
50
use crate::smb::smb2::*;
51
use crate::smb::smb3::*;
52
use crate::smb::dcerpc::*;
53
use crate::smb::session::*;
54
use crate::smb::events::*;
55
use crate::smb::files::*;
56
use crate::smb::smb2_ioctl::*;
57
58
#[derive(AppLayerFrameType)]
59
pub enum SMBFrameType {
60
    NBSSPdu,
61
    NBSSHdr,
62
    NBSSData,
63
    SMB1Pdu,
64
    SMB1Hdr,
65
    SMB1Data,
66
    SMB2Pdu,
67
    SMB2Hdr,
68
    SMB2Data,
69
    SMB3Pdu,
70
    SMB3Hdr,
71
    SMB3Data,
72
}
73
74
pub const MIN_REC_SIZE: u16 = 32 + 4; // SMB hdr + nbss hdr
75
pub const SMB_CONFIG_DEFAULT_STREAM_DEPTH: u32 = 0;
76
77
pub static mut SMB_CFG_MAX_READ_SIZE: u32 = 16777216;
78
pub static mut SMB_CFG_MAX_READ_QUEUE_SIZE: u32 = 67108864;
79
pub static mut SMB_CFG_MAX_READ_QUEUE_CNT: u32 = 64;
80
pub static mut SMB_CFG_MAX_WRITE_SIZE: u32 = 16777216;
81
pub static mut SMB_CFG_MAX_WRITE_QUEUE_SIZE: u32 = 67108864;
82
pub static mut SMB_CFG_MAX_WRITE_QUEUE_CNT: u32 = 64;
83
84
pub static mut SMB_DCERPC_MAX_STUB_SIZE: u32 = 1048576;
85
86
static mut ALPROTO_SMB: AppProto = ALPROTO_UNKNOWN;
87
88
static mut SMB_MAX_TX: usize = 1024;
89
90
pub static mut SURICATA_SMB_FILE_CONFIG: Option<&'static SuricataFileContext> = None;
91
92
#[no_mangle]
93
34
pub extern "C" fn rs_smb_init(context: &'static mut SuricataFileContext)
94
{
95
34
    unsafe {
96
34
        SURICATA_SMB_FILE_CONFIG = Some(context);
97
34
    }
98
34
}
99
100
pub const SMB_SRV_ERROR:                u16 = 1;
101
pub const SMB_SRV_BADPW:                u16 = 2;
102
pub const SMB_SRV_BADTYPE:              u16 = 3;
103
pub const SMB_SRV_ACCESS:               u16 = 4;
104
pub const SMB_SRV_BADUID:               u16 = 91;
105
106
91
pub fn smb_srv_error_string(c: u16) -> String {
107
91
    match c {
108
5
        SMB_SRV_ERROR           => "SRV_ERROR",
109
0
        SMB_SRV_BADPW           => "SRV_BADPW",
110
0
        SMB_SRV_BADTYPE         => "SRV_BADTYPE",
111
0
        SMB_SRV_ACCESS          => "SRV_ACCESS",
112
15
        SMB_SRV_BADUID          => "SRV_BADUID",
113
71
        _ => { return (c).to_string(); },
114
20
    }.to_string()
115
91
}
116
117
pub const SMB_DOS_SUCCESS:                u16 = 0;
118
pub const SMB_DOS_BAD_FUNC:               u16 = 1;
119
pub const SMB_DOS_BAD_FILE:               u16 = 2;
120
pub const SMB_DOS_BAD_PATH:               u16 = 3;
121
pub const SMB_DOS_TOO_MANY_OPEN_FILES:    u16 = 4;
122
pub const SMB_DOS_ACCESS_DENIED:          u16 = 5;
123
124
1
pub fn smb_dos_error_string(c: u16) -> String {
125
1
    match c {
126
1
        SMB_DOS_SUCCESS           => "DOS_SUCCESS",
127
0
        SMB_DOS_BAD_FUNC          => "DOS_BAD_FUNC",
128
0
        SMB_DOS_BAD_FILE          => "DOS_BAD_FILE",
129
0
        SMB_DOS_BAD_PATH          => "DOS_BAD_PATH",
130
0
        SMB_DOS_TOO_MANY_OPEN_FILES => "DOS_TOO_MANY_OPEN_FILES",
131
0
        SMB_DOS_ACCESS_DENIED     => "DOS_ACCESS_DENIED",
132
0
        _ => { return (c).to_string(); },
133
1
    }.to_string()
134
1
}
135
136
pub const NTLMSSP_NEGOTIATE:               u32 = 1;
137
#[cfg(feature = "debug")]
138
pub const NTLMSSP_CHALLENGE:               u32 = 2;
139
pub const NTLMSSP_AUTH:                    u32 = 3;
140
141
#[cfg(feature = "debug")]
142
pub fn ntlmssp_type_string(c: u32) -> String {
143
    match c {
144
        NTLMSSP_NEGOTIATE   => "NTLMSSP_NEGOTIATE",
145
        NTLMSSP_CHALLENGE   => "NTLMSSP_CHALLENGE",
146
        NTLMSSP_AUTH        => "NTLMSSP_AUTH",
147
        _ => { return (c).to_string(); },
148
    }.to_string()
149
}
150
151
#[derive(Default, Eq, PartialEq, Debug, Clone)]
152
pub struct SMBVerCmdStat {
153
    smb_ver: u8,
154
    smb1_cmd: u8,
155
    smb2_cmd: u16,
156
157
    status_set: bool,
158
    status_is_dos_error: bool,
159
    status_error_class: u8,
160
    status: u32,
161
}
162
163
impl SMBVerCmdStat {
164
1.79M
    pub fn new() -> Self {
165
1.79M
        Default::default()
166
1.79M
    }
167
11.3k
    pub fn new1(cmd: u8) -> Self {
168
11.3k
        return Self {
169
11.3k
            smb_ver: 1,
170
11.3k
            smb1_cmd: cmd,
171
11.3k
            ..Default::default()
172
11.3k
        }
173
11.3k
    }
174
18.0k
    pub fn new1_with_ntstatus(cmd: u8, status: u32) -> Self {
175
18.0k
        return Self {
176
18.0k
            smb_ver: 1,
177
18.0k
            smb1_cmd: cmd,
178
18.0k
            status_set: true,
179
18.0k
            status,
180
18.0k
            ..Default::default()
181
18.0k
        }
182
18.0k
    }
183
68.8k
    pub fn new2(cmd: u16) -> Self {
184
68.8k
        return Self {
185
68.8k
            smb_ver: 2,
186
68.8k
            smb2_cmd: cmd,
187
68.8k
            ..Default::default()
188
68.8k
        }
189
68.8k
    }
190
191
25.2k
    pub fn new2_with_ntstatus(cmd: u16, status: u32) -> Self {
192
25.2k
        return Self {
193
25.2k
            smb_ver: 2,
194
25.2k
            smb2_cmd: cmd,
195
25.2k
            status_set: true,
196
25.2k
            status,
197
25.2k
            ..Default::default()
198
25.2k
        }
199
25.2k
    }
200
201
1.48M
    pub fn set_smb1_cmd(&mut self, cmd: u8) -> bool {
202
1.48M
        if self.smb_ver != 0 {
203
0
            return false;
204
1.48M
        }
205
1.48M
        self.smb_ver = 1;
206
1.48M
        self.smb1_cmd = cmd;
207
1.48M
        return true;
208
1.48M
    }
209
210
244k
    pub fn set_smb2_cmd(&mut self, cmd: u16) -> bool {
211
244k
        if self.smb_ver != 0 {
212
0
            return false;
213
244k
        }
214
244k
        self.smb_ver = 2;
215
244k
        self.smb2_cmd = cmd;
216
244k
        return true;
217
244k
    }
218
219
6.74M
    pub fn get_version(&self) -> u8 {
220
6.74M
        self.smb_ver
221
6.74M
    }
222
223
3.62M
    pub fn get_smb1_cmd(&self) -> (bool, u8) {
224
3.62M
        if self.smb_ver != 1 {
225
0
            return (false, 0);
226
3.62M
        }
227
3.62M
        return (true, self.smb1_cmd);
228
3.62M
    }
229
230
1.78M
    pub fn get_smb2_cmd(&self) -> (bool, u16) {
231
1.78M
        if self.smb_ver != 2 {
232
0
            return (false, 0);
233
1.78M
        }
234
1.78M
        return (true, self.smb2_cmd);
235
1.78M
    }
236
237
157k
    pub fn get_ntstatus(&self) -> (bool, u32) {
238
157k
        (self.status_set && !self.status_is_dos_error, self.status)
239
157k
    }
240
241
35.9k
    pub fn get_dos_error(&self) -> (bool, u8, u16) {
242
35.9k
        (self.status_set && self.status_is_dos_error, self.status_error_class, self.status as u16)
243
35.9k
    }
244
245
198k
    fn set_status(&mut self, status: u32, is_dos_error: bool)
246
    {
247
198k
        if is_dos_error {
248
27.3k
            self.status_is_dos_error = true;
249
27.3k
            self.status_error_class = (status & 0x0000_00ff) as u8;
250
27.3k
            self.status = (status & 0xffff_0000) >> 16;
251
170k
        } else {
252
170k
            self.status = status;
253
170k
        }
254
198k
        self.status_set = true;
255
198k
    }
256
257
170k
    pub fn set_ntstatus(&mut self, status: u32)
258
    {
259
170k
        self.set_status(status, false)
260
170k
    }
261
262
27.3k
    pub fn set_status_dos_error(&mut self, status: u32)
263
    {
264
27.3k
        self.set_status(status, true)
265
27.3k
    }
266
}
267
268
/// "The FILETIME structure is a 64-bit value that represents the number of
269
/// 100-nanosecond intervals that have elapsed since January 1, 1601,
270
/// Coordinated Universal Time (UTC)."
271
#[derive(Eq, PartialEq, Debug, Clone)]
272
pub struct SMBFiletime {
273
    ts: u64, 
274
}
275
276
impl SMBFiletime {
277
304k
    pub fn new(raw: u64) -> Self {
278
304k
        Self {
279
304k
            ts: raw,
280
304k
        }
281
304k
    }
282
283
    /// inspired by Bro, convert FILETIME to secs since unix epoch
284
100k
    pub fn as_unix(&self) -> u32 {
285
100k
        if self.ts > 116_444_736_000_000_000_u64 {
286
74.3k
            let ts = self.ts / 10000000 - 11644473600;
287
74.3k
            ts as u32
288
        } else {
289
26.2k
            0
290
        }
291
100k
    }
292
}
293
294
#[derive(Debug)]
295
pub enum SMBTransactionTypeData {
296
    FILE(SMBTransactionFile),
297
    TREECONNECT(SMBTransactionTreeConnect),
298
    NEGOTIATE(SMBTransactionNegotiate),
299
    DCERPC(SMBTransactionDCERPC),
300
    CREATE(SMBTransactionCreate),
301
    SESSIONSETUP(SMBTransactionSessionSetup),
302
    IOCTL(SMBTransactionIoctl),
303
    RENAME(SMBTransactionRename),
304
    SETFILEPATHINFO(SMBTransactionSetFilePathInfo),
305
}
306
307
// Used for Trans2 SET_PATH_INFO and SET_FILE_INFO
308
#[derive(Debug)]
309
pub struct SMBTransactionSetFilePathInfo {
310
    pub subcmd: u16,
311
    pub loi: u16,
312
    pub delete_on_close: bool,
313
    pub filename: Vec<u8>,
314
    pub fid: Vec<u8>,
315
}
316
317
impl SMBTransactionSetFilePathInfo {
318
13.4k
    pub fn new(filename: Vec<u8>, fid: Vec<u8>, subcmd: u16, loi: u16, delete_on_close: bool)
319
13.4k
        -> Self
320
    {
321
13.4k
        return Self {
322
13.4k
            filename, fid,
323
13.4k
            subcmd,
324
13.4k
            loi,
325
13.4k
            delete_on_close,
326
13.4k
        };
327
13.4k
    }
328
}
329
330
impl SMBState {
331
12.5k
    pub fn new_setfileinfo_tx(&mut self, filename: Vec<u8>, fid: Vec<u8>,
332
12.5k
            subcmd: u16, loi: u16, delete_on_close: bool)
333
12.5k
        -> &mut SMBTransaction
334
    {
335
12.5k
        let mut tx = self.new_tx();
336
337
12.5k
        tx.type_data = Some(SMBTransactionTypeData::SETFILEPATHINFO(
338
12.5k
                    SMBTransactionSetFilePathInfo::new(
339
12.5k
                        filename, fid, subcmd, loi, delete_on_close)));
340
12.5k
        tx.request_done = true;
341
12.5k
        tx.response_done = self.tc_trunc; // no response expected if tc is truncated
342
343
        SCLogDebug!("SMB: TX SETFILEPATHINFO created: ID {}", tx.id);
344
12.5k
        self.transactions.push_back(tx);
345
12.5k
        let tx_ref = self.transactions.back_mut();
346
12.5k
        return tx_ref.unwrap();
347
12.5k
    }
348
349
852
    pub fn new_setpathinfo_tx(&mut self, filename: Vec<u8>,
350
852
            subcmd: u16, loi: u16, delete_on_close: bool)
351
852
        -> &mut SMBTransaction
352
    {
353
852
        let mut tx = self.new_tx();
354
355
852
        let fid : Vec<u8> = Vec::new();
356
852
        tx.type_data = Some(SMBTransactionTypeData::SETFILEPATHINFO(
357
852
                    SMBTransactionSetFilePathInfo::new(filename, fid,
358
852
                        subcmd, loi, delete_on_close)));
359
852
        tx.request_done = true;
360
852
        tx.response_done = self.tc_trunc; // no response expected if tc is truncated
361
362
        SCLogDebug!("SMB: TX SETFILEPATHINFO created: ID {}", tx.id);
363
852
        self.transactions.push_back(tx);
364
852
        let tx_ref = self.transactions.back_mut();
365
852
        return tx_ref.unwrap();
366
852
    }
367
}
368
369
#[derive(Debug)]
370
pub struct SMBTransactionRename {
371
    pub oldname: Vec<u8>,
372
    pub newname: Vec<u8>,
373
    pub fuid: Vec<u8>,
374
}
375
376
impl SMBTransactionRename {
377
48.9k
    pub fn new(fuid: Vec<u8>, oldname: Vec<u8>, newname: Vec<u8>) -> Self {
378
48.9k
        return Self {
379
48.9k
            fuid, oldname, newname,
380
48.9k
        };
381
48.9k
    }
382
}
383
384
impl SMBState {
385
48.9k
    pub fn new_rename_tx(&mut self, fuid: Vec<u8>, oldname: Vec<u8>, newname: Vec<u8>)
386
48.9k
        -> &mut SMBTransaction
387
    {
388
48.9k
        let mut tx = self.new_tx();
389
390
48.9k
        tx.type_data = Some(SMBTransactionTypeData::RENAME(
391
48.9k
                    SMBTransactionRename::new(fuid, oldname, newname)));
392
48.9k
        tx.request_done = true;
393
48.9k
        tx.response_done = self.tc_trunc; // no response expected if tc is truncated
394
395
        SCLogDebug!("SMB: TX RENAME created: ID {}", tx.id);
396
48.9k
        self.transactions.push_back(tx);
397
48.9k
        let tx_ref = self.transactions.back_mut();
398
48.9k
        return tx_ref.unwrap();
399
48.9k
    }
400
}
401
402
#[derive(Default, Debug)]
403
pub struct SMBTransactionCreate {
404
    pub disposition: u32,
405
    pub delete_on_close: bool,
406
    pub directory: bool,
407
    pub filename: Vec<u8>,
408
    pub guid: Vec<u8>,
409
410
    pub create_ts: u32,
411
    pub last_access_ts: u32,
412
    pub last_write_ts: u32,
413
    pub last_change_ts: u32,
414
415
    pub size: u64,
416
}
417
418
impl SMBTransactionCreate {
419
109k
    pub fn new(filename: Vec<u8>, disp: u32, del: bool, dir: bool) -> Self {
420
109k
        return Self {
421
109k
            disposition: disp,
422
109k
            delete_on_close: del,
423
109k
            directory: dir,
424
109k
            filename,
425
109k
            ..Default::default()
426
109k
        }
427
109k
    }
428
}
429
430
#[derive(Default, Debug)]
431
pub struct SMBTransactionNegotiate {
432
    pub smb_ver: u8,
433
    pub dialects: Vec<Vec<u8>>,
434
    pub dialects2: Vec<Vec<u8>>,
435
436
    // SMB1 doesn't have the client GUID
437
    pub client_guid: Option<Vec<u8>>,
438
    pub server_guid: Vec<u8>,
439
}
440
441
impl SMBTransactionNegotiate {
442
19.6k
    pub fn new(smb_ver: u8) -> Self {
443
19.6k
        return Self {
444
19.6k
            smb_ver,
445
19.6k
            server_guid: Vec::with_capacity(16),
446
19.6k
            ..Default::default()
447
19.6k
        };
448
19.6k
    }
449
}
450
451
#[derive(Default, Debug)]
452
pub struct SMBTransactionTreeConnect {
453
    pub is_pipe: bool,
454
    pub share_type: u8,
455
    pub tree_id: u32,
456
    pub share_name: Vec<u8>,
457
458
    /// SMB1 service strings
459
    pub req_service: Option<Vec<u8>>,
460
    pub res_service: Option<Vec<u8>>,
461
}
462
463
impl SMBTransactionTreeConnect {
464
65.1k
    pub fn new(share_name: Vec<u8>) -> Self {
465
65.1k
        return Self {
466
65.1k
            share_name,
467
65.1k
            ..Default::default()
468
65.1k
        };
469
65.1k
    }
470
}
471
472
#[derive(Debug)]
473
pub struct SMBTransaction {
474
    /// internal id
475
    pub id: u64,
476
477
    /// version, command and status
478
    pub vercmd: SMBVerCmdStat,
479
    /// session id, tree id, etc.
480
    pub hdr: SMBCommonHdr,
481
482
    /// for state tracking. false means this side is in progress, true
483
    /// that it's complete.
484
    pub request_done: bool,
485
    pub response_done: bool,
486
487
    /// Command specific data
488
    pub type_data: Option<SMBTransactionTypeData>,
489
490
    pub tx_data: AppLayerTxData,
491
}
492
493
impl Transaction for SMBTransaction {
494
791M
    fn id(&self) -> u64 {
495
791M
        self.id
496
791M
    }
497
}
498
499
impl Default for SMBTransaction {
500
0
    fn default() -> Self {
501
0
        Self::new()
502
0
    }
503
}
504
505
impl SMBTransaction {
506
1.79M
    pub fn new() -> Self {
507
1.79M
        return Self {
508
1.79M
              id: 0,
509
1.79M
              vercmd: SMBVerCmdStat::new(),
510
1.79M
              hdr: SMBCommonHdr::default(),
511
1.79M
              request_done: false,
512
1.79M
              response_done: false,
513
1.79M
              type_data: None,
514
1.79M
              tx_data: AppLayerTxData::new(),
515
1.79M
        }
516
1.79M
    }
517
518
187k
    pub fn set_status(&mut self, status: u32, is_dos_error: bool)
519
    {
520
187k
        if is_dos_error {
521
27.3k
            self.vercmd.set_status_dos_error(status);
522
160k
        } else {
523
160k
            self.vercmd.set_ntstatus(status);
524
160k
        }
525
187k
    }
526
527
1.79M
    pub fn free(&mut self) {
528
        SCLogDebug!("SMB TX {:p} free ID {}", &self, self.id);
529
1.79M
        debug_validate_bug_on!(self.tx_data.files_opened > 1);
530
1.79M
        debug_validate_bug_on!(self.tx_data.files_logged > 1);
531
1.79M
    }
532
}
533
534
impl Drop for SMBTransaction {
535
1.79M
    fn drop(&mut self) {
536
598k
        if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = self.type_data {
537
74.4k
            if let Some(sfcm) = unsafe { SURICATA_SMB_FILE_CONFIG } {
538
74.4k
                tdf.file_tracker.file.free(sfcm);
539
74.4k
            }
540
1.72M
        }
541
1.79M
        self.free();
542
1.79M
    }
543
}
544
545
#[derive(Hash, Eq, PartialEq, Debug, Clone)]
546
pub struct SMBFileGUIDOffset {
547
    pub guid: Vec<u8>,
548
    pub offset: u64,
549
}
550
551
impl SMBFileGUIDOffset {
552
112k
    pub fn new(guid: Vec<u8>, offset: u64) -> Self {
553
112k
        Self {
554
112k
            guid,
555
112k
            offset,
556
112k
        }
557
112k
    }
558
}
559
560
/// type values to make sure we're not mixing things
561
/// up in hashmap lookups
562
pub const SMBHDR_TYPE_GUID:        u32 = 1;
563
pub const SMBHDR_TYPE_SHARE:       u32 = 2;
564
pub const SMBHDR_TYPE_FILENAME:    u32 = 3;
565
pub const SMBHDR_TYPE_OFFSET:      u32 = 4;
566
pub const SMBHDR_TYPE_GENERICTX:   u32 = 5;
567
pub const SMBHDR_TYPE_HEADER:      u32 = 6;
568
//unused pub const SMBHDR_TYPE_MAX_SIZE:    u32 = 7; // max resp size for SMB1_COMMAND_TRANS
569
pub const SMBHDR_TYPE_TRANS_FRAG:  u32 = 8;
570
pub const SMBHDR_TYPE_TREE:        u32 = 9;
571
pub const SMBHDR_TYPE_DCERPCTX:    u32 = 10;
572
573
#[derive(Default, Hash, Eq, PartialEq, Debug)]
574
pub struct SMBCommonHdr {
575
    pub ssn_id: u64,
576
    pub tree_id: u32,
577
    pub rec_type: u32,
578
    pub msg_id: u64,
579
}
580
581
impl SMBCommonHdr {
582
389k
    pub fn new(rec_type: u32, ssn_id: u64, tree_id: u32, msg_id: u64) -> Self {
583
389k
        Self {
584
389k
            rec_type,
585
389k
            ssn_id,
586
389k
            tree_id,
587
389k
            msg_id,
588
389k
        }
589
389k
    }
590
747k
    pub fn from2(r: &Smb2Record, rec_type: u32) -> SMBCommonHdr {
591
747k
        let tree_id = match rec_type {
592
31.5k
            SMBHDR_TYPE_TREE => { 0 },
593
716k
            _ => r.tree_id,
594
        };
595
747k
        let msg_id = match rec_type {
596
139k
            SMBHDR_TYPE_TRANS_FRAG | SMBHDR_TYPE_SHARE => { 0 },
597
608k
            _ => { r.message_id },
598
        };
599
600
747k
        SMBCommonHdr {
601
747k
            rec_type,
602
747k
            ssn_id : r.session_id,
603
747k
            tree_id,
604
747k
            msg_id,
605
747k
        }
606
607
747k
    }
608
134k
    pub fn from2_notree(r: &Smb2Record, rec_type: u32) -> SMBCommonHdr {
609
        // async responses do not have a tree id (even if the request has it)
610
        // making thus the match between the two impossible.
611
        // Per spec, MessageId should be enough to identify a message request and response uniquely
612
        // across all messages that are sent on the same SMB2 Protocol transport connection.
613
        // cf https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/ea4560b7-90da-4803-82b5-344754b92a79
614
134k
        let msg_id = match rec_type {
615
0
            SMBHDR_TYPE_TRANS_FRAG | SMBHDR_TYPE_SHARE => { 0 },
616
134k
            _ => { r.message_id },
617
        };
618
619
134k
        SMBCommonHdr {
620
134k
            rec_type,
621
134k
            ssn_id : r.session_id,
622
134k
            tree_id : 0,
623
134k
            msg_id,
624
134k
        }
625
134k
    }
626
2.02M
    pub fn from1(r: &SmbRecord, rec_type: u32) -> SMBCommonHdr {
627
2.02M
        let tree_id = match rec_type {
628
75.0k
            SMBHDR_TYPE_TREE => { 0 },
629
1.94M
            _ => r.tree_id as u32,
630
        };
631
2.02M
        let msg_id = match rec_type {
632
141k
            SMBHDR_TYPE_TRANS_FRAG | SMBHDR_TYPE_SHARE => { 0 },
633
1.88M
            _ => { r.multiplex_id as u64 },
634
        };
635
636
2.02M
        SMBCommonHdr {
637
2.02M
            rec_type,
638
2.02M
            ssn_id : r.ssn_id as u64,
639
2.02M
            tree_id,
640
2.02M
            msg_id,
641
2.02M
        }
642
2.02M
    }
643
644
    // don't include tree id
645
5.95M
    pub fn compare(&self, hdr: &SMBCommonHdr) -> bool {
646
5.95M
        self.rec_type == hdr.rec_type && self.ssn_id == hdr.ssn_id &&
647
1.15M
            self.msg_id == hdr.msg_id
648
5.95M
    }
649
}
650
651
#[derive(Hash, Eq, PartialEq, Debug)]
652
pub struct SMBHashKeyHdrGuid {
653
    hdr: SMBCommonHdr,
654
    guid: Vec<u8>,
655
}
656
657
impl SMBHashKeyHdrGuid {
658
78.7k
    pub fn new(hdr: SMBCommonHdr, guid: Vec<u8>) -> Self {
659
78.7k
        Self {
660
78.7k
            hdr, guid,
661
78.7k
        }
662
78.7k
    }
663
}
664
665
#[derive(Hash, Eq, PartialEq, Debug)]
666
pub struct SMBTree {
667
    pub name: Vec<u8>,
668
    pub is_pipe: bool,
669
}
670
671
impl SMBTree {
672
34.7k
    pub fn new(name: Vec<u8>, is_pipe: bool) -> Self {
673
34.7k
        Self {
674
34.7k
            name,
675
34.7k
            is_pipe,
676
34.7k
        }
677
34.7k
    }
678
}
679
680
342k
pub fn u32_as_bytes(i: u32) -> [u8;4] {
681
342k
    let o1: u8 = ((i >> 24) & 0xff) as u8;
682
342k
    let o2: u8 = ((i >> 16) & 0xff) as u8;
683
342k
    let o3: u8 = ((i >> 8)  & 0xff) as u8;
684
342k
    let o4: u8 =  (i        & 0xff) as u8;
685
342k
    return [o1, o2, o3, o4]
686
342k
}
687
688
#[derive(Default, Debug)]
689
pub struct SMBState<> {
690
    pub state_data: AppLayerStateData,
691
692
    /// map ssn/tree/msgid to vec (guid/name/share)
693
    pub ssn2vec_map: HashMap<SMBCommonHdr, Vec<u8>>,
694
    /// map guid to filename
695
    pub guid2name_map: HashMap<Vec<u8>, Vec<u8>>,
696
    /// map ssn key to read offset
697
    pub ssn2vecoffset_map: HashMap<SMBCommonHdr, SMBFileGUIDOffset>,
698
699
    pub ssn2tree_map: HashMap<SMBCommonHdr, SMBTree>,
700
701
    // store partial data records that are transferred in multiple
702
    // requests for DCERPC.
703
    pub ssnguid2vec_map: HashMap<SMBHashKeyHdrGuid, Vec<u8>>,
704
705
    skip_ts: u32,
706
    skip_tc: u32,
707
708
    pub file_ts_left : u32,
709
    pub file_tc_left : u32,
710
    pub file_ts_guid : Vec<u8>,
711
    pub file_tc_guid : Vec<u8>,
712
713
    pub ts_ssn_gap: bool,
714
    pub tc_ssn_gap: bool,
715
716
    pub ts_gap: bool, // last TS update was gap
717
    pub tc_gap: bool, // last TC update was gap
718
719
    pub ts_trunc: bool, // no more data for TOSERVER
720
    pub tc_trunc: bool, // no more data for TOCLIENT
721
722
    /// true as long as we have file txs that are in a post-gap
723
    /// state. It means we'll do extra house keeping for those.
724
    check_post_gap_file_txs: bool,
725
    post_gap_files_checked: bool,
726
727
    /// transactions list
728
    pub transactions: VecDeque<SMBTransaction>,
729
    tx_index_completed: usize,
730
731
    /// tx counter for assigning incrementing id's to tx's
732
    tx_id: u64,
733
734
    /// SMB2 dialect or 0 if not set or SMB1
735
    pub dialect: u16,
736
    /// contains name of SMB1 dialect
737
    pub dialect_vec: Option<Vec<u8>>, // used if dialect == 0
738
739
    /// dcerpc interfaces, stored here to be able to match
740
    /// them while inspecting DCERPC REQUEST txs
741
    pub dcerpc_ifaces: Option<Vec<DCERPCIface>>,
742
743
    pub max_read_size: u32,
744
    pub max_write_size: u32,
745
746
    /// Timestamp in seconds of last update. This is packet time,
747
    /// potentially coming from pcaps.
748
    ts: u64,
749
}
750
751
impl State<SMBTransaction> for SMBState {
752
267M
    fn get_transaction_count(&self) -> usize {
753
267M
        self.transactions.len()
754
267M
    }
755
756
526M
    fn get_transaction_by_index(&self, index: usize) -> Option<&SMBTransaction> {
757
526M
        self.transactions.get(index)
758
526M
    }
759
}
760
761
impl SMBState {
762
    /// Allocation function for a new TLS parser instance
763
61.1k
    pub fn new() -> Self {
764
61.1k
        Self {
765
61.1k
            state_data:AppLayerStateData::new(),
766
61.1k
            ssn2vec_map:HashMap::new(),
767
61.1k
            guid2name_map:HashMap::new(),
768
61.1k
            ssn2vecoffset_map:HashMap::new(),
769
61.1k
            ssn2tree_map:HashMap::new(),
770
61.1k
            ssnguid2vec_map:HashMap::new(),
771
61.1k
            skip_ts:0,
772
61.1k
            skip_tc:0,
773
61.1k
            file_ts_left:0,
774
61.1k
            file_tc_left:0,
775
61.1k
            file_ts_guid:Vec::new(),
776
61.1k
            file_tc_guid:Vec::new(),
777
61.1k
            ts_ssn_gap: false,
778
61.1k
            tc_ssn_gap: false,
779
61.1k
            ts_gap: false,
780
61.1k
            tc_gap: false,
781
61.1k
            ts_trunc: false,
782
61.1k
            tc_trunc: false,
783
61.1k
            check_post_gap_file_txs: false,
784
61.1k
            post_gap_files_checked: false,
785
61.1k
            transactions: VecDeque::new(),
786
61.1k
            tx_index_completed: 0,
787
61.1k
            tx_id:0,
788
61.1k
            dialect:0,
789
61.1k
            dialect_vec: None,
790
61.1k
            dcerpc_ifaces: None,
791
61.1k
            ts: 0,
792
61.1k
            ..Default::default()
793
61.1k
        }
794
61.1k
    }
795
796
61.1k
    pub fn free(&mut self) {
797
        //self._debug_state_stats();
798
61.1k
        self._debug_tx_stats();
799
61.1k
    }
800
801
1.79M
    pub fn new_tx(&mut self) -> SMBTransaction {
802
1.79M
        let mut tx = SMBTransaction::new();
803
1.79M
        self.tx_id += 1;
804
1.79M
        tx.id = self.tx_id;
805
        SCLogDebug!("TX {} created", tx.id);
806
1.79M
        if self.transactions.len() > unsafe { SMB_MAX_TX } {
807
549k
            let mut index = self.tx_index_completed;
808
633k
            for tx_old in &mut self.transactions.range_mut(self.tx_index_completed..) {
809
633k
                index += 1;
810
633k
                if !tx_old.request_done || !tx_old.response_done {
811
350k
                    tx_old.tx_data.updated_tc = true;
812
350k
                    tx_old.tx_data.updated_ts = true;
813
350k
                    tx_old.request_done = true;
814
350k
                    tx_old.response_done = true;
815
350k
                    tx_old.set_event(SMBEvent::TooManyTransactions);
816
350k
                    break;
817
282k
                }
818
            }
819
549k
            self.tx_index_completed = index;
820
821
1.24M
        }
822
1.79M
        return tx;
823
1.79M
    }
824
825
1.27M
    pub fn free_tx(&mut self, tx_id: u64) {
826
        SCLogDebug!("Freeing TX with ID {} TX.ID {}", tx_id, tx_id+1);
827
1.27M
        let len = self.transactions.len();
828
1.27M
        let mut found = false;
829
1.27M
        let mut index = 0;
830
7.11M
        for i in 0..len {
831
7.11M
            let tx = &self.transactions[i];
832
7.11M
            if tx.id == tx_id + 1 {
833
1.27M
                found = true;
834
1.27M
                index = i;
835
                SCLogDebug!("tx {} progress {}/{}", tx.id, tx.request_done, tx.response_done);
836
1.27M
                break;
837
5.84M
            }
838
        }
839
1.27M
        if found {
840
1.27M
            SCLogDebug!("freeing TX with ID {} TX.ID {} at index {} left: {} max id: {}",
841
1.27M
                    tx_id, tx_id+1, index, self.transactions.len(), self.tx_id);
842
1.27M
            self.tx_index_completed = 0;
843
1.27M
            self.transactions.remove(index);
844
1.27M
        }
845
1.27M
    }
846
847
16.7k
    pub fn get_tx_by_id(&mut self, tx_id: u64) -> Option<&SMBTransaction> {
848
/*
849
        if self.transactions.len() > 100 {
850
            SCLogNotice!("get_tx_by_id: tx_id={} in list={}", tx_id, self.transactions.len());
851
            self._dump_txs();
852
            panic!("txs exploded");
853
        }
854
*/
855
39.8k
        for tx in &mut self.transactions {
856
32.7k
            if tx.id == tx_id + 1 {
857
9.63k
                let ver = tx.vercmd.get_version();
858
                let mut _smbcmd;
859
9.63k
                if ver == 2 {
860
6.15k
                    let (_, cmd) = tx.vercmd.get_smb2_cmd();
861
6.15k
                    _smbcmd = cmd;
862
6.15k
                } else {
863
3.48k
                    let (_, cmd) = tx.vercmd.get_smb1_cmd();
864
3.48k
                    _smbcmd = cmd as u16;
865
3.48k
                }
866
                SCLogDebug!("Found SMB TX: id {} ver:{} cmd:{} progress {}/{} type_data {:?}",
867
                        tx.id, ver, _smbcmd, tx.request_done, tx.response_done, tx.type_data);
868
                /* hack: apply flow file flags to file tx here to make sure its propagated */
869
8.61k
                if let Some(SMBTransactionTypeData::FILE(ref mut d)) = tx.type_data {
870
5.31k
                    tx.tx_data.update_file_flags(self.state_data.file_flags);
871
5.31k
                    d.update_file_flags(tx.tx_data.file_flags);
872
5.31k
                }
873
9.63k
                return Some(tx);
874
23.0k
            }
875
        }
876
        SCLogDebug!("Failed to find SMB TX with ID {}", tx_id);
877
7.15k
        return None;
878
16.7k
    }
879
880
4.82M
    fn update_ts(&mut self, ts: u64) {
881
4.82M
        if ts != self.ts {
882
38.1k
            self.ts = ts;
883
38.1k
            self.post_gap_files_checked = false;
884
4.78M
        }
885
4.82M
    }
886
887
    /* generic TX has no type_data and is only used to
888
     * track a single cmd request/reply pair. */
889
890
1.19M
    pub fn new_generic_tx(&mut self, smb_ver: u8, smb_cmd: u16, key: SMBCommonHdr)
891
1.19M
        -> &mut SMBTransaction
892
    {
893
1.19M
        let mut tx = self.new_tx();
894
1.19M
        if smb_ver == 1 && smb_cmd <= 255 {
895
1.11M
            tx.vercmd.set_smb1_cmd(smb_cmd as u8);
896
1.11M
        } else if smb_ver == 2 {
897
85.6k
            tx.vercmd.set_smb2_cmd(smb_cmd);
898
85.6k
        }
899
900
1.19M
        tx.type_data = None;
901
1.19M
        tx.request_done = true;
902
1.19M
        tx.response_done = self.tc_trunc; // no response expected if tc is truncated
903
1.19M
        tx.hdr = key;
904
905
        SCLogDebug!("SMB: TX GENERIC created: ID {} tx list {} {:?}",
906
                tx.id, self.transactions.len(), &tx);
907
1.19M
        self.transactions.push_back(tx);
908
1.19M
        let tx_ref = self.transactions.back_mut();
909
1.19M
        return tx_ref.unwrap();
910
1.19M
    }
911
912
3.57k
    pub fn get_last_tx(&mut self, smb_ver: u8, smb_cmd: u16)
913
3.57k
        -> Option<&mut SMBTransaction>
914
    {
915
3.57k
        let tx_ref = self.transactions.back_mut();
916
3.57k
        if let Some(tx) = tx_ref {
917
2.63k
            let found = if tx.vercmd.get_version() == smb_ver {
918
1.88k
                if smb_ver == 1 {
919
1.88k
                    let (_, cmd) = tx.vercmd.get_smb1_cmd();
920
1.88k
                    cmd as u16 == smb_cmd
921
0
                } else if smb_ver == 2 {
922
0
                    let (_, cmd) = tx.vercmd.get_smb2_cmd();
923
0
                    cmd == smb_cmd
924
                } else {
925
0
                    false
926
                }
927
            } else {
928
744
                false
929
            };
930
2.63k
            if found {
931
1.19k
                tx.tx_data.updated_tc = true;
932
1.19k
                tx.tx_data.updated_ts = true;
933
1.19k
                return Some(tx);
934
1.44k
            }
935
942
        }
936
2.38k
        return None;
937
3.57k
    }
938
939
482k
    pub fn get_generic_tx(&mut self, smb_ver: u8, smb_cmd: u16, key: &SMBCommonHdr)
940
482k
        -> Option<&mut SMBTransaction>
941
    {
942
6.36M
        for tx in &mut self.transactions {
943
5.98M
            let found = if tx.vercmd.get_version() == smb_ver {
944
5.09M
                if smb_ver == 1 {
945
3.56M
                    let (_, cmd) = tx.vercmd.get_smb1_cmd();
946
3.56M
                    cmd as u16 == smb_cmd && tx.hdr.compare(key)
947
1.53M
                } else if smb_ver == 2 {
948
1.53M
                    let (_, cmd) = tx.vercmd.get_smb2_cmd();
949
1.53M
                    cmd == smb_cmd && tx.hdr.compare(key)
950
                } else {
951
0
                    false
952
                }
953
            } else {
954
883k
                false
955
            };
956
5.98M
            if found {
957
104k
                tx.tx_data.updated_tc = true;
958
104k
                tx.tx_data.updated_ts = true;
959
104k
                return Some(tx);
960
5.87M
            }
961
        }
962
378k
        return None;
963
482k
    }
964
965
19.6k
    pub fn new_negotiate_tx(&mut self, smb_ver: u8)
966
19.6k
        -> &mut SMBTransaction
967
    {
968
19.6k
        let mut tx = self.new_tx();
969
19.6k
        if smb_ver == 1 {
970
10.6k
            tx.vercmd.set_smb1_cmd(SMB1_COMMAND_NEGOTIATE_PROTOCOL);
971
10.6k
        } else if smb_ver == 2 {
972
9.01k
            tx.vercmd.set_smb2_cmd(SMB2_COMMAND_NEGOTIATE_PROTOCOL);
973
9.01k
        }
974
975
19.6k
        tx.type_data = Some(SMBTransactionTypeData::NEGOTIATE(
976
19.6k
                    SMBTransactionNegotiate::new(smb_ver)));
977
19.6k
        tx.request_done = true;
978
19.6k
        tx.response_done = self.tc_trunc; // no response expected if tc is truncated
979
980
        SCLogDebug!("SMB: TX NEGOTIATE created: ID {} SMB ver {}", tx.id, smb_ver);
981
19.6k
        self.transactions.push_back(tx);
982
19.6k
        let tx_ref = self.transactions.back_mut();
983
19.6k
        return tx_ref.unwrap();
984
19.6k
    }
985
986
54.9k
    pub fn get_negotiate_tx(&mut self, smb_ver: u8)
987
54.9k
        -> Option<&mut SMBTransaction>
988
    {
989
1.19M
        for tx in &mut self.transactions {
990
1.14M
            let found = match tx.type_data {
991
19.3k
                Some(SMBTransactionTypeData::NEGOTIATE(ref x)) => {
992
19.3k
                    x.smb_ver == smb_ver
993
                },
994
1.13M
                _ => { false },
995
            };
996
1.14M
            if found {
997
14.6k
                tx.tx_data.updated_tc = true;
998
14.6k
                tx.tx_data.updated_ts = true;
999
14.6k
                return Some(tx);
1000
1.13M
            }
1001
        }
1002
40.2k
        return None;
1003
54.9k
    }
1004
1005
65.1k
    pub fn new_treeconnect_tx(&mut self, hdr: SMBCommonHdr, name: Vec<u8>)
1006
65.1k
        -> &mut SMBTransaction
1007
    {
1008
65.1k
        let mut tx = self.new_tx();
1009
1010
65.1k
        tx.hdr = hdr;
1011
65.1k
        tx.type_data = Some(SMBTransactionTypeData::TREECONNECT(
1012
65.1k
                    SMBTransactionTreeConnect::new(name.to_vec())));
1013
65.1k
        tx.request_done = true;
1014
65.1k
        tx.response_done = self.tc_trunc; // no response expected if tc is truncated
1015
1016
        SCLogDebug!("SMB: TX TREECONNECT created: ID {} NAME {}",
1017
                tx.id, String::from_utf8_lossy(&name));
1018
65.1k
        self.transactions.push_back(tx);
1019
65.1k
        let tx_ref = self.transactions.back_mut();
1020
65.1k
        return tx_ref.unwrap();
1021
65.1k
    }
1022
1023
41.4k
    pub fn get_treeconnect_tx(&mut self, hdr: SMBCommonHdr)
1024
41.4k
        -> Option<&mut SMBTransaction>
1025
    {
1026
1.41M
        for tx in &mut self.transactions {
1027
1.38M
            let hit = tx.hdr.compare(&hdr) && match tx.type_data {
1028
8.51k
                Some(SMBTransactionTypeData::TREECONNECT(_)) => { true },
1029
0
                _ => { false },
1030
            };
1031
1.38M
            if hit {
1032
8.51k
                tx.tx_data.updated_tc = true;
1033
8.51k
                tx.tx_data.updated_ts = true;
1034
8.51k
                return Some(tx);
1035
1.37M
            }
1036
        }
1037
32.8k
        return None;
1038
41.4k
    }
1039
1040
109k
    pub fn new_create_tx(&mut self, file_name: &[u8],
1041
109k
            disposition: u32, del: bool, dir: bool,
1042
109k
            hdr: SMBCommonHdr)
1043
109k
        -> &mut SMBTransaction
1044
    {
1045
109k
        let mut tx = self.new_tx();
1046
109k
        tx.hdr = hdr;
1047
109k
        tx.type_data = Some(SMBTransactionTypeData::CREATE(
1048
109k
                            SMBTransactionCreate::new(
1049
109k
                                file_name.to_vec(), disposition,
1050
109k
                                del, dir)));
1051
109k
        tx.request_done = true;
1052
109k
        tx.response_done = self.tc_trunc; // no response expected if tc is truncated
1053
1054
109k
        self.transactions.push_back(tx);
1055
109k
        let tx_ref = self.transactions.back_mut();
1056
109k
        return tx_ref.unwrap();
1057
109k
    }
1058
1059
192k
    pub fn get_service_for_guid(&self, guid: &[u8]) -> (&'static str, bool)
1060
    {
1061
192k
        let (name, is_dcerpc) = match self.guid2name_map.get(guid) {
1062
94.5k
            Some(n) => {
1063
94.5k
                let mut s = n.as_slice();
1064
                // skip leading \ if we have it
1065
94.5k
                if s.len() > 1 && s[0] == 0x5c_u8 {
1066
6.77k
                    s = &s[1..];
1067
87.7k
                }
1068
94.5k
                match str::from_utf8(s) {
1069
93.5k
                    Ok("PSEXESVC") => ("PSEXESVC", false),
1070
93.2k
                    Ok("svcctl") => ("svcctl", true),
1071
88.6k
                    Ok("srvsvc") => ("srvsvc", true),
1072
87.7k
                    Ok("atsvc") => ("atsvc", true),
1073
87.3k
                    Ok("lsarpc") => ("lsarpc", true),
1074
86.8k
                    Ok("samr") => ("samr", true),
1075
81.0k
                    Ok("spoolss") => ("spoolss", true),
1076
79.9k
                    Ok("winreg") => ("winreg", true),
1077
78.0k
                    Ok("suricata::dcerpc") => ("unknown", true),
1078
962
                    Err(_) => ("MALFORMED", false),
1079
                    Ok(&_) => {
1080
                        SCLogDebug!("don't know {}", String::from_utf8_lossy(n));
1081
4.04k
                        ("UNKNOWN", false)
1082
                    },
1083
                }
1084
            },
1085
97.8k
            _ => { ("UNKNOWN", false) },
1086
        };
1087
        SCLogDebug!("service {} is_dcerpc {}", name, is_dcerpc);
1088
192k
        (name, is_dcerpc)
1089
192k
    }
1090
1091
1.06k
    fn post_gap_housekeeping_for_files(&mut self)
1092
    {
1093
1.06k
        let mut post_gap_txs = false;
1094
13.9k
        for tx in &mut self.transactions {
1095
10.3k
            if let Some(SMBTransactionTypeData::FILE(ref mut f)) = tx.type_data {
1096
1.25k
                if f.post_gap_ts > 0 {
1097
1.15k
                    if self.ts > f.post_gap_ts {
1098
5
                        tx.request_done = true;
1099
5
                        tx.response_done = true;
1100
5
                        filetracker_trunc(&mut f.file_tracker);
1101
1.15k
                    } else {
1102
1.15k
                        post_gap_txs = true;
1103
1.15k
                    }
1104
96
                }
1105
11.6k
            }
1106
        }
1107
1.06k
        self.check_post_gap_file_txs = post_gap_txs;
1108
1.06k
    }
1109
1110
    /* after a gap we will consider all transactions complete for our
1111
     * direction. File transfer transactions are an exception. Those
1112
     * can handle gaps. For the file transactions we set the current
1113
     * (flow) time and prune them in 60 seconds if no update for them
1114
     * was received. */
1115
381k
    fn post_gap_housekeeping(&mut self, dir: Direction)
1116
    {
1117
381k
        if self.ts_ssn_gap && dir == Direction::ToServer {
1118
594k
            for tx in &mut self.transactions {
1119
586k
                if tx.id >= self.tx_id {
1120
                    SCLogDebug!("post_gap_housekeeping: done");
1121
31.5k
                    break;
1122
555k
                }
1123
492k
                if let Some(SMBTransactionTypeData::FILE(ref mut f)) = tx.type_data {
1124
                    // leaving FILE txs open as they can deal with gaps. We
1125
                    // remove them after 60 seconds of no activity though.
1126
28.8k
                    if f.post_gap_ts == 0 {
1127
1.47k
                        f.post_gap_ts = self.ts + 60;
1128
1.47k
                        self.check_post_gap_file_txs = true;
1129
27.3k
                    }
1130
526k
                } else {
1131
526k
                    SCLogDebug!("post_gap_housekeeping: tx {} marked as done TS", tx.id);
1132
526k
                    tx.request_done = true;
1133
526k
                }
1134
            }
1135
342k
        } else if self.tc_ssn_gap && dir == Direction::ToClient {
1136
188k
            for tx in &mut self.transactions {
1137
172k
                if tx.id >= self.tx_id {
1138
                    SCLogDebug!("post_gap_housekeeping: done");
1139
28.4k
                    break;
1140
143k
                }
1141
125k
                if let Some(SMBTransactionTypeData::FILE(ref mut f)) = tx.type_data {
1142
                    // leaving FILE txs open as they can deal with gaps. We
1143
                    // remove them after 60 seconds of no activity though.
1144
29.0k
                    if f.post_gap_ts == 0 {
1145
681
                        f.post_gap_ts = self.ts + 60;
1146
681
                        self.check_post_gap_file_txs = true;
1147
28.3k
                    }
1148
114k
                } else {
1149
114k
                    SCLogDebug!("post_gap_housekeeping: tx {} marked as done TC", tx.id);
1150
114k
                    tx.request_done = true;
1151
114k
                    tx.response_done = true;
1152
114k
                }
1153
            }
1154
1155
298k
        }
1156
381k
    }
1157
1158
267k
    pub fn set_file_left(&mut self, direction: Direction, rec_size: u32, data_size: u32, fuid: Vec<u8>)
1159
    {
1160
267k
        let left = rec_size.saturating_sub(data_size);
1161
267k
        if direction == Direction::ToServer {
1162
212k
            self.file_ts_left = left;
1163
212k
            self.file_ts_guid = fuid;
1164
212k
        } else {
1165
54.8k
            self.file_tc_left = left;
1166
54.8k
            self.file_tc_guid = fuid;
1167
54.8k
        }
1168
267k
    }
1169
1170
45.9k
    pub fn set_skip(&mut self, direction: Direction, nbss_remaining: u32)
1171
    {
1172
45.9k
        if direction == Direction::ToServer {
1173
24.7k
            self.skip_ts = nbss_remaining;
1174
24.7k
        } else {
1175
21.1k
            self.skip_tc = nbss_remaining;
1176
21.1k
        }
1177
45.9k
    }
1178
1179
    // return how much data we consumed
1180
4.85M
    fn handle_skip(&mut self, direction: Direction, input_size: u32) -> u32 {
1181
4.85M
        let mut skip_left = if direction == Direction::ToServer {
1182
2.46M
            self.skip_ts
1183
        } else {
1184
2.39M
            self.skip_tc
1185
        };
1186
4.85M
        if skip_left == 0 {
1187
4.79M
            return 0
1188
58.4k
        }
1189
        SCLogDebug!("skip_left {} input_size {}", skip_left, input_size);
1190
1191
58.4k
        let consumed = if skip_left >= input_size {
1192
58.1k
            input_size
1193
        } else {
1194
296
            skip_left
1195
        };
1196
1197
58.4k
        if skip_left <= input_size {
1198
388
            skip_left = 0;
1199
58.0k
        } else {
1200
58.0k
            skip_left -= input_size;
1201
58.0k
        }
1202
1203
58.4k
        if direction == Direction::ToServer {
1204
27.6k
            self.skip_ts = skip_left;
1205
30.8k
        } else {
1206
30.8k
            self.skip_tc = skip_left;
1207
30.8k
        }
1208
58.4k
        return consumed;
1209
4.85M
    }
1210
1211
1.95M
    fn add_nbss_ts_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) -> (Option<Frame>, Option<Frame>, Option<Frame>) {
1212
1.95M
        let nbss_pdu = Frame::new(flow, stream_slice, input, nbss_len + 4, SMBFrameType::NBSSPdu as u8);
1213
        SCLogDebug!("NBSS PDU frame {:?}", nbss_pdu);
1214
1.95M
        let nbss_hdr_frame = Frame::new(flow, stream_slice, input, 4_i64, SMBFrameType::NBSSHdr as u8);
1215
        SCLogDebug!("NBSS HDR frame {:?}", nbss_hdr_frame);
1216
1.95M
        let nbss_data_frame = Frame::new(flow, stream_slice, &input[4..], nbss_len, SMBFrameType::NBSSData as u8);
1217
        SCLogDebug!("NBSS DATA frame {:?}", nbss_data_frame);
1218
1.95M
        (nbss_pdu, nbss_hdr_frame, nbss_data_frame)
1219
1.95M
    }
1220
1221
1.38M
    fn add_smb1_ts_pdu_frame(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) -> Option<Frame> {
1222
1.38M
        let smb_pdu = Frame::new(flow, stream_slice, input, nbss_len, SMBFrameType::SMB1Pdu as u8);
1223
        SCLogDebug!("SMB PDU frame {:?}", smb_pdu);
1224
1.38M
        smb_pdu
1225
1.38M
    }
1226
1.38M
    fn add_smb1_ts_hdr_data_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) {
1227
1.38M
        let _smb1_hdr = Frame::new(flow, stream_slice, input, 32_i64, SMBFrameType::SMB1Hdr as u8);
1228
        SCLogDebug!("SMBv1 HDR frame {:?}", _smb1_hdr);
1229
1.38M
        if input.len() > 32 {
1230
1.11M
            let _smb1_data = Frame::new(flow, stream_slice, &input[32..], nbss_len - 32, SMBFrameType::SMB1Data as u8);
1231
1.11M
            SCLogDebug!("SMBv1 DATA frame {:?}", _smb1_data);
1232
1.11M
        }
1233
1.38M
    }
1234
1235
473k
    fn add_smb2_ts_pdu_frame(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) -> Option<Frame> {
1236
473k
        let smb_pdu = Frame::new(flow, stream_slice, input, nbss_len, SMBFrameType::SMB2Pdu as u8);
1237
        SCLogDebug!("SMBv2 PDU frame {:?}", smb_pdu);
1238
473k
        smb_pdu
1239
473k
    }
1240
473k
    fn add_smb2_ts_hdr_data_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, hdr_len: i64) {
1241
473k
        let _smb2_hdr = Frame::new(flow, stream_slice, input, hdr_len, SMBFrameType::SMB2Hdr as u8);
1242
        SCLogDebug!("SMBv2 HDR frame {:?}", _smb2_hdr);
1243
473k
        if input.len() > hdr_len as usize {
1244
137k
            let _smb2_data = Frame::new(flow, stream_slice, &input[hdr_len as usize..], nbss_len - hdr_len, SMBFrameType::SMB2Data as u8);
1245
137k
            SCLogDebug!("SMBv2 DATA frame {:?}", _smb2_data);
1246
335k
        }
1247
473k
    }
1248
1249
1.17k
    fn add_smb3_ts_pdu_frame(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) -> Option<Frame> {
1250
1.17k
        let smb_pdu = Frame::new(flow, stream_slice, input, nbss_len, SMBFrameType::SMB3Pdu as u8);
1251
        SCLogDebug!("SMBv3 PDU frame {:?}", smb_pdu);
1252
1.17k
        smb_pdu
1253
1.17k
    }
1254
1.17k
    fn add_smb3_ts_hdr_data_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) {
1255
1.17k
        let _smb3_hdr = Frame::new(flow, stream_slice, input, 52_i64, SMBFrameType::SMB3Hdr as u8);
1256
        SCLogDebug!("SMBv3 HDR frame {:?}", _smb3_hdr);
1257
1.17k
        if input.len() > 52 {
1258
677
            let _smb3_data = Frame::new(flow, stream_slice, &input[52..], nbss_len - 52, SMBFrameType::SMB3Data as u8);
1259
677
            SCLogDebug!("SMBv3 DATA frame {:?}", _smb3_data);
1260
677
        }
1261
1.17k
    }
1262
1263
    /// return bytes consumed
1264
821k
    pub fn parse_tcp_data_ts_partial(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8]) -> usize
1265
    {
1266
        SCLogDebug!("incomplete of size {}", input.len());
1267
821k
        if input.len() < 512 {
1268
            // check for malformed data. Wireshark reports as
1269
            // 'NBSS continuation data'. If it's invalid we're
1270
            // lost so we give up.
1271
765k
            if input.len() > 8 {
1272
393k
                if let Ok((_, ref hdr)) = parse_nbss_record_partial(input) {
1273
393k
                    if !hdr.is_smb() {
1274
                        SCLogDebug!("partial NBSS, not SMB and no known msg type {}", hdr.message_type);
1275
133k
                        self.trunc_ts();
1276
133k
                        return 0;
1277
260k
                    }
1278
0
                }
1279
371k
            }
1280
632k
            return 0;
1281
56.1k
        }
1282
1283
56.1k
        if let Ok((output, ref nbss_part_hdr)) = parse_nbss_record_partial(input) {
1284
            SCLogDebug!("parse_nbss_record_partial ok, output len {}", output.len());
1285
56.1k
            if nbss_part_hdr.message_type == NBSS_MSGTYPE_SESSION_MESSAGE {
1286
28.0k
                if let Ok((_, ref smb)) = parse_smb_version(nbss_part_hdr.data) {
1287
                    SCLogDebug!("SMB {:?}", smb);
1288
19.8k
                    if smb.version == 0xff_u8 { // SMB1
1289
                        SCLogDebug!("SMBv1 record");
1290
3.14k
                        if let Ok((_, ref r)) = parse_smb_record(nbss_part_hdr.data) {
1291
3.14k
                            if r.command == SMB1_COMMAND_WRITE_ANDX {
1292
                                // see if it's a write to a pipe. We only handle those
1293
                                // if complete.
1294
1.29k
                                let tree_key = SMBCommonHdr::new(SMBHDR_TYPE_SHARE,
1295
1.29k
                                                                 r.ssn_id as u64, r.tree_id as u32, 0);
1296
1.29k
                                let is_pipe = match self.ssn2tree_map.get(&tree_key) {
1297
709
                                    Some(n) => n.is_pipe,
1298
588
                                    None => false,
1299
                                };
1300
1.29k
                                if is_pipe {
1301
425
                                    return 0;
1302
872
                                }
1303
                                // how many more bytes are expected within this NBSS record
1304
                                // So that we can check that further parsed offsets and lengths
1305
                                // stay within the NBSS record.
1306
872
                                let nbss_remaining = nbss_part_hdr.length - nbss_part_hdr.data.len() as u32;
1307
872
                                smb1_write_request_record(self, r, SMB1_HEADER_SIZE, SMB1_COMMAND_WRITE_ANDX, nbss_remaining);
1308
1309
872
                                self.add_nbss_ts_frames(flow, stream_slice, input, nbss_part_hdr.length as i64);
1310
872
                                self.add_smb1_ts_pdu_frame(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64);
1311
872
                                self.add_smb1_ts_hdr_data_frames(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64);
1312
                                
1313
872
                                let consumed = input.len() - output.len();
1314
872
                                return consumed;
1315
1.84k
                            }
1316
0
                        }
1317
16.7k
                    } else if smb.version == 0xfe_u8 { // SMB2
1318
                        SCLogDebug!("SMBv2 record");
1319
15.6k
                        if let Ok((_, ref smb_record)) = parse_smb2_request_record(nbss_part_hdr.data) {
1320
                            SCLogDebug!("SMB2: partial record {}",
1321
                                        &smb2_command_string(smb_record.command));
1322
14.9k
                            if smb_record.command == SMB2_COMMAND_WRITE {
1323
                                // how many more bytes are expected within this NBSS record
1324
                                // So that we can check that further parsed offsets and lengths
1325
                                // stay within the NBSS record.
1326
12.5k
                                let nbss_remaining = nbss_part_hdr.length - nbss_part_hdr.data.len() as u32;
1327
12.5k
                                smb2_write_request_record(self, smb_record, nbss_remaining);
1328
1329
12.5k
                                self.add_nbss_ts_frames(flow, stream_slice, input, nbss_part_hdr.length as i64);
1330
12.5k
                                self.add_smb2_ts_pdu_frame(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64);
1331
12.5k
                                self.add_smb2_ts_hdr_data_frames(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64, smb_record.header_len as i64);
1332
                                
1333
12.5k
                                let consumed = input.len() - output.len();
1334
                                SCLogDebug!("consumed {}", consumed);
1335
12.5k
                                return consumed;
1336
2.44k
                            }
1337
652
                        }
1338
1.08k
                    }
1339
                    // no SMB3 here yet, will buffer full records
1340
8.14k
                }
1341
28.1k
            }
1342
0
        }
1343
1344
42.3k
        return 0;
1345
821k
    }
1346
1347
    /// Parsing function, handling TCP chunks fragmentation
1348
2.44M
    pub fn parse_tcp_data_ts(&mut self, flow: *const Flow, stream_slice: &StreamSlice) -> AppLayerResult
1349
    {
1350
2.44M
        let mut cur_i = stream_slice.as_slice();
1351
2.44M
        let consumed = self.handle_skip(Direction::ToServer, cur_i.len() as u32);
1352
2.44M
        if consumed > 0 {
1353
27.6k
            if consumed > cur_i.len() as u32 {
1354
0
                self.set_event(SMBEvent::InternalError);
1355
0
                return AppLayerResult::err();
1356
27.6k
            }
1357
27.6k
            cur_i = &cur_i[consumed as usize..];
1358
2.41M
        }
1359
        // take care of in progress file chunk transfers
1360
        // and skip buffer beyond it
1361
2.44M
        let consumed = self.filetracker_update(Direction::ToServer, cur_i, 0);
1362
2.44M
        if consumed > 0 {
1363
40.5k
            if consumed > cur_i.len() as u32 {
1364
0
                self.set_event(SMBEvent::InternalError);
1365
0
                return AppLayerResult::err();
1366
40.5k
            }
1367
40.5k
            cur_i = &cur_i[consumed as usize..];
1368
2.40M
        }
1369
2.44M
        if cur_i.is_empty() {
1370
75.1k
            return AppLayerResult::ok();
1371
2.37M
        }
1372
        // gap
1373
2.37M
        if self.ts_gap {
1374
            SCLogDebug!("TS trying to catch up after GAP (input {})", cur_i.len());
1375
35.3k
            while !cur_i.is_empty() { // min record size
1376
35.3k
                match search_smb_record(cur_i) {
1377
30.1k
                    Ok((_, pg)) => {
1378
                        SCLogDebug!("smb record found");
1379
30.1k
                        let smb2_offset = cur_i.len() - pg.len();
1380
30.1k
                        if smb2_offset < 4 {
1381
276
                            cur_i = &cur_i[smb2_offset+4..];
1382
276
                            continue; // see if we have another record in our data
1383
29.8k
                        }
1384
29.8k
                        let nbss_offset = smb2_offset - 4;
1385
29.8k
                        cur_i = &cur_i[nbss_offset..];
1386
1387
29.8k
                        self.ts_gap = false;
1388
29.8k
                        break;
1389
                    },
1390
                    _ => {
1391
5.23k
                        let mut consumed = stream_slice.len();
1392
5.23k
                        if consumed < 4 {
1393
1.13k
                            consumed = 0;
1394
4.09k
                        } else {
1395
4.09k
                            consumed -= 3;
1396
4.09k
                        }
1397
                        SCLogDebug!("smb record NOT found");
1398
5.23k
                        return AppLayerResult::incomplete(consumed, 8);
1399
                    },
1400
                }
1401
            }
1402
2.33M
        }
1403
4.30M
        while !cur_i.is_empty() { // min record size
1404
4.09M
            match parse_nbss_record(cur_i) {
1405
1.94M
                Ok((rem, ref nbss_hdr)) => {
1406
                    SCLogDebug!("nbss frame offset {} len {}", stream_slice.offset_from(cur_i), cur_i.len() - rem.len());
1407
1.94M
                    let (_, _, nbss_data_frame) = self.add_nbss_ts_frames(flow, stream_slice, cur_i, nbss_hdr.length as i64);
1408
1409
1.94M
                    if nbss_hdr.message_type == NBSS_MSGTYPE_SESSION_MESSAGE {
1410
                        // we have the full records size worth of data,
1411
                        // let's parse it
1412
1.83M
                        match parse_smb_version(nbss_hdr.data) {
1413
1.83M
                            Ok((_, ref smb)) => {
1414
1415
                                SCLogDebug!("SMB {:?}", smb);
1416
1.83M
                                if smb.version == 0xff_u8 { // SMB1
1417
1418
                                    SCLogDebug!("SMBv1 record");
1419
1.38M
                                    match parse_smb_record(nbss_hdr.data) {
1420
1.38M
                                        Ok((_, ref smb_record)) => {
1421
1.38M
                                            let pdu_frame = self.add_smb1_ts_pdu_frame(flow, stream_slice, nbss_hdr.data, nbss_hdr.length as i64);
1422
1.38M
                                            self.add_smb1_ts_hdr_data_frames(flow, stream_slice, nbss_hdr.data, nbss_hdr.length as i64);
1423
1.38M
                                            if smb_record.is_request() {
1424
1.26M
                                                smb1_request_record(self, smb_record);
1425
1.26M
                                            } else {
1426
                                                // If we received a response when expecting a request, set an event
1427
                                                // on the PDU frame instead of handling the response.
1428
                                                SCLogDebug!("SMB1 reply seen from client to server");
1429
115k
                                                if let Some(frame) = pdu_frame {
1430
29
                                                    frame.add_event(flow, SMBEvent::ResponseToServer as u8);
1431
115k
                                                }
1432
                                            }
1433
                                        },
1434
                                        _ => {
1435
45
                                            if let Some(frame) = nbss_data_frame {
1436
0
                                                frame.add_event(flow, SMBEvent::MalformedData as u8);
1437
45
                                            }
1438
45
                                            self.set_event(SMBEvent::MalformedData);
1439
45
                                            return AppLayerResult::err();
1440
                                        },
1441
                                    }
1442
452k
                                } else if smb.version == 0xfe_u8 { // SMB2
1443
448k
                                    let mut nbss_data = nbss_hdr.data;
1444
909k
                                    while !nbss_data.is_empty() {
1445
                                        SCLogDebug!("SMBv2 record");
1446
461k
                                        match parse_smb2_request_record(nbss_data) {
1447
460k
                                            Ok((nbss_data_rem, ref smb_record)) => {
1448
460k
                                                let record_len = (nbss_data.len() - nbss_data_rem.len()) as i64;
1449
460k
                                                let pdu_frame = self.add_smb2_ts_pdu_frame(flow, stream_slice, nbss_data, record_len);
1450
460k
                                                self.add_smb2_ts_hdr_data_frames(flow, stream_slice, nbss_data, record_len, smb_record.header_len as i64);
1451
                                                SCLogDebug!("nbss_data_rem {}", nbss_data_rem.len());
1452
460k
                                                if smb_record.is_request() {
1453
384k
                                                    smb2_request_record(self, smb_record);
1454
384k
                                                } else {
1455
                                                    // If we received a response when expecting a request, set an event
1456
                                                    // on the PDU frame instead of handling the response.
1457
                                                    SCLogDebug!("SMB2 reply seen from client to server");
1458
76.7k
                                                    if let Some(frame) = pdu_frame {
1459
670
                                                        frame.add_event(flow, SMBEvent::ResponseToServer as u8);
1460
76.0k
                                                    }
1461
                                                }
1462
460k
                                                nbss_data = nbss_data_rem;
1463
                                            },
1464
                                            _ => {
1465
918
                                                if let Some(frame) = nbss_data_frame {
1466
0
                                                    frame.add_event(flow, SMBEvent::MalformedData as u8);
1467
918
                                                }
1468
918
                                                self.set_event(SMBEvent::MalformedData);
1469
918
                                                return AppLayerResult::err();
1470
                                            },
1471
                                        }
1472
                                    }
1473
3.58k
                                } else if smb.version == 0xfd_u8 { // SMB3 transform
1474
1475
883
                                    let mut nbss_data = nbss_hdr.data;
1476
2.05k
                                    while !nbss_data.is_empty() {
1477
                                        SCLogDebug!("SMBv3 transform record");
1478
1.23k
                                        match parse_smb3_transform_record(nbss_data) {
1479
1.17k
                                            Ok((nbss_data_rem, ref _smb3_record)) => {
1480
1.17k
                                                let record_len = (nbss_data.len() - nbss_data_rem.len()) as i64;
1481
1.17k
                                                self.add_smb3_ts_pdu_frame(flow, stream_slice, nbss_data, record_len);
1482
1.17k
                                                self.add_smb3_ts_hdr_data_frames(flow, stream_slice, nbss_data, record_len);
1483
1.17k
                                                nbss_data = nbss_data_rem;
1484
1.17k
                                            },
1485
                                            _ => {
1486
64
                                                if let Some(frame) = nbss_data_frame {
1487
0
                                                    frame.add_event(flow, SMBEvent::MalformedData as u8);
1488
64
                                                }
1489
64
                                                self.set_event(SMBEvent::MalformedData);
1490
64
                                                return AppLayerResult::err();
1491
                                            },
1492
                                        }
1493
                                    }
1494
2.70k
                                }
1495
                            },
1496
                            _ => {
1497
2.15k
                                self.set_event(SMBEvent::MalformedData);
1498
2.15k
                                return AppLayerResult::err();
1499
                            },
1500
                        }
1501
101k
                    } else {
1502
101k
                        SCLogDebug!("NBSS message {:X}", nbss_hdr.message_type);
1503
101k
                    }
1504
1.93M
                    cur_i = rem;
1505
                },
1506
2.15M
                Err(Err::Incomplete(needed)) => {
1507
2.15M
                    if let Needed::Size(n) = needed {
1508
2.15M
                        let n = usize::from(n) + cur_i.len();
1509
                        // 512 is the minimum for parse_tcp_data_ts_partial
1510
2.15M
                        if n >= 512 && cur_i.len() < 512 {
1511
1.33M
                            let total_consumed = stream_slice.offset_from(cur_i);
1512
1.33M
                            return AppLayerResult::incomplete(total_consumed, 512);
1513
821k
                        }
1514
821k
                        let consumed = self.parse_tcp_data_ts_partial(flow, stream_slice, cur_i);
1515
821k
                        if consumed == 0 {
1516
                            // if we consumed none we will buffer the entire record
1517
807k
                            let total_consumed = stream_slice.offset_from(cur_i);
1518
                            SCLogDebug!("setting consumed {} need {} needed {:?} total input {}",
1519
                                    total_consumed, n, needed, stream_slice.len());
1520
807k
                            let need = n;
1521
807k
                            return AppLayerResult::incomplete(total_consumed, need as u32);
1522
13.4k
                        }
1523
                        // tracking a write record, which we don't need to
1524
                        // queue up at the stream level, but can feed to us
1525
                        // in small chunks
1526
13.4k
                        return AppLayerResult::ok();
1527
                    } else {
1528
0
                        self.set_event(SMBEvent::InternalError);
1529
0
                        return AppLayerResult::err();
1530
                    }
1531
                },
1532
                Err(_) => {
1533
0
                    self.set_event(SMBEvent::MalformedData);
1534
0
                    return AppLayerResult::err();
1535
                },
1536
            }
1537
        };
1538
1539
206k
        self.post_gap_housekeeping(Direction::ToServer);
1540
206k
        if self.check_post_gap_file_txs && !self.post_gap_files_checked {
1541
754
            self.post_gap_housekeeping_for_files();
1542
754
            self.post_gap_files_checked = true;
1543
205k
        }
1544
206k
        AppLayerResult::ok()
1545
2.44M
    }
1546
1547
1.41M
    fn add_nbss_tc_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) -> (Option<Frame>, Option<Frame>, Option<Frame>) {
1548
1.41M
        let nbss_pdu = Frame::new(flow, stream_slice, input, nbss_len + 4, SMBFrameType::NBSSPdu as u8);
1549
        SCLogDebug!("NBSS PDU frame {:?}", nbss_pdu);
1550
1.41M
        let nbss_hdr_frame = Frame::new(flow, stream_slice, input, 4_i64, SMBFrameType::NBSSHdr as u8);
1551
        SCLogDebug!("NBSS HDR frame {:?}", nbss_hdr_frame);
1552
1.41M
        let nbss_data_frame = Frame::new(flow, stream_slice, &input[4..], nbss_len, SMBFrameType::NBSSData as u8);
1553
        SCLogDebug!("NBSS DATA frame {:?}", nbss_data_frame);
1554
1.41M
        (nbss_pdu, nbss_hdr_frame, nbss_data_frame)
1555
1.41M
    }
1556
1557
546k
    fn add_smb1_tc_pdu_frame(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) -> Option<Frame> {
1558
546k
        let smb_pdu = Frame::new(flow, stream_slice, input, nbss_len, SMBFrameType::SMB1Pdu as u8);
1559
        SCLogDebug!("SMB PDU frame {:?}", smb_pdu);
1560
546k
        smb_pdu
1561
546k
    }
1562
546k
    fn add_smb1_tc_hdr_data_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) {
1563
546k
        let _smb1_hdr = Frame::new(flow, stream_slice, input, SMB1_HEADER_SIZE as i64, SMBFrameType::SMB1Hdr as u8);
1564
        SCLogDebug!("SMBv1 HDR frame {:?}", _smb1_hdr);
1565
546k
        if input.len() > SMB1_HEADER_SIZE {
1566
519k
            let _smb1_data = Frame::new(flow, stream_slice, &input[SMB1_HEADER_SIZE..], nbss_len - SMB1_HEADER_SIZE as i64,
1567
519k
                    SMBFrameType::SMB1Data as u8);
1568
519k
            SCLogDebug!("SMBv1 DATA frame {:?}", _smb1_data);
1569
519k
        }
1570
546k
    }
1571
1572
328k
    fn add_smb2_tc_pdu_frame(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) -> Option<Frame> {
1573
328k
        let smb_pdu = Frame::new(flow, stream_slice, input, nbss_len, SMBFrameType::SMB2Pdu as u8);
1574
        SCLogDebug!("SMBv2 PDU frame {:?}", smb_pdu);
1575
328k
        smb_pdu
1576
328k
    }
1577
328k
    fn add_smb2_tc_hdr_data_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, hdr_len: i64) {
1578
328k
        let _smb2_hdr = Frame::new(flow, stream_slice, input, hdr_len, SMBFrameType::SMB2Hdr as u8);
1579
        SCLogDebug!("SMBv2 HDR frame {:?}", _smb2_hdr);
1580
328k
        if input.len() > hdr_len as usize {
1581
147k
            let _smb2_data = Frame::new(flow, stream_slice, &input[hdr_len as usize ..], nbss_len - hdr_len, SMBFrameType::SMB2Data as u8);
1582
147k
            SCLogDebug!("SMBv2 DATA frame {:?}", _smb2_data);
1583
181k
        }
1584
328k
    }
1585
1586
1.27k
    fn add_smb3_tc_pdu_frame(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) {
1587
1.27k
        let _smb_pdu = Frame::new(flow, stream_slice, input, nbss_len, SMBFrameType::SMB3Pdu as u8);
1588
        SCLogDebug!("SMBv3 PDU frame {:?}", _smb_pdu);
1589
1.27k
    }
1590
1.27k
    fn add_smb3_tc_hdr_data_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) {
1591
1.27k
        let _smb3_hdr = Frame::new(flow, stream_slice, input, 52_i64, SMBFrameType::SMB3Hdr as u8);
1592
        SCLogDebug!("SMBv3 HDR frame {:?}", _smb3_hdr);
1593
1.27k
        if input.len() > 52 {
1594
674
            let _smb3_data = Frame::new(flow, stream_slice, &input[52..], nbss_len - 52, SMBFrameType::SMB3Data as u8);
1595
674
            SCLogDebug!("SMBv3 DATA frame {:?}", _smb3_data);
1596
674
        }
1597
1.27k
    }
1598
1599
    /// return bytes consumed
1600
849k
    pub fn parse_tcp_data_tc_partial(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8]) -> usize
1601
    {
1602
        SCLogDebug!("incomplete of size {}", input.len());
1603
849k
        if input.len() < 512 {
1604
            // check for malformed data. Wireshark reports as
1605
            // 'NBSS continuation data'. If it's invalid we're
1606
            // lost so we give up.
1607
810k
            if input.len() > 8 {
1608
294k
                if let Ok((_, ref hdr)) = parse_nbss_record_partial(input) {
1609
294k
                    if !hdr.is_smb() {
1610
                        SCLogDebug!("partial NBSS, not SMB and no known msg type {}", hdr.message_type);
1611
105k
                        self.trunc_tc();
1612
105k
                        return 0;
1613
188k
                    }
1614
0
                }
1615
516k
            }
1616
704k
            return 0;
1617
38.5k
        }
1618
1619
38.5k
        if let Ok((output, ref nbss_part_hdr)) = parse_nbss_record_partial(input) {
1620
            SCLogDebug!("parse_nbss_record_partial ok, output len {}", output.len());
1621
38.5k
            if nbss_part_hdr.message_type == NBSS_MSGTYPE_SESSION_MESSAGE {
1622
20.9k
                if let Ok((_, ref smb)) = parse_smb_version(nbss_part_hdr.data) {
1623
                    SCLogDebug!("SMB {:?}", smb);
1624
14.5k
                    if smb.version == 255u8 { // SMB1
1625
                        SCLogDebug!("SMBv1 record");
1626
3.23k
                        if let Ok((_, ref r)) = parse_smb_record(nbss_part_hdr.data) {
1627
                            SCLogDebug!("SMB1: partial record {}",
1628
                                    r.command);
1629
3.23k
                            if r.command == SMB1_COMMAND_READ_ANDX {
1630
1.62k
                                let tree_key = SMBCommonHdr::new(SMBHDR_TYPE_SHARE,
1631
1.62k
                                        r.ssn_id as u64, r.tree_id as u32, 0);
1632
1.62k
                                let is_pipe = match self.ssn2tree_map.get(&tree_key) {
1633
989
                                    Some(n) => n.is_pipe,
1634
634
                                        None => false,
1635
                                };
1636
1.62k
                                if is_pipe {
1637
340
                                    return 0;
1638
1.28k
                                }
1639
1640
                                // create NBSS frames here so we don't get double frames
1641
                                // when we don't consume the data now.
1642
1.28k
                                self.add_nbss_tc_frames(flow, stream_slice, input, nbss_part_hdr.length as i64);
1643
1.28k
                                self.add_smb1_tc_pdu_frame(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64);
1644
1.28k
                                self.add_smb1_tc_hdr_data_frames(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64);
1645
1646
                                // how many more bytes are expected within this NBSS record
1647
                                // So that we can check that further parsed offsets and lengths
1648
                                // stay within the NBSS record.
1649
1.28k
                                let nbss_remaining = nbss_part_hdr.length - nbss_part_hdr.data.len() as u32;
1650
1.28k
                                smb1_read_response_record(self, r, SMB1_HEADER_SIZE, nbss_remaining);
1651
1.28k
                                let consumed = input.len() - output.len();
1652
1.28k
                                return consumed;
1653
1.60k
                            }
1654
0
                        }
1655
11.3k
                    } else if smb.version == 254u8 { // SMB2
1656
                        SCLogDebug!("SMBv2 record");
1657
10.8k
                        if let Ok((_, ref smb_record)) = parse_smb2_response_record(nbss_part_hdr.data) {
1658
                            SCLogDebug!("SMB2: partial record {}",
1659
                                    &smb2_command_string(smb_record.command));
1660
10.1k
                            if smb_record.command == SMB2_COMMAND_READ {
1661
                                // create NBSS frames here so we don't get double frames
1662
                                // when we don't consume the data now.
1663
7.80k
                                self.add_nbss_tc_frames(flow, stream_slice, input, nbss_part_hdr.length as i64);
1664
7.80k
                                self.add_smb2_tc_pdu_frame(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64);
1665
7.80k
                                self.add_smb2_tc_hdr_data_frames(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64, smb_record.header_len as i64);
1666
1667
                                // how many more bytes are expected within this NBSS record
1668
                                // So that we can check that further parsed offsets and lengths
1669
                                // stay within the NBSS record.
1670
7.80k
                                let nbss_remaining = nbss_part_hdr.length - nbss_part_hdr.data.len() as u32;
1671
7.80k
                                smb2_read_response_record(self, smb_record, nbss_remaining);
1672
7.80k
                                let consumed = input.len() - output.len();
1673
7.80k
                                return consumed;
1674
2.39k
                            }
1675
613
                        }
1676
554
                    }
1677
                    // no SMB3 here yet, will buffer full records
1678
6.31k
                }
1679
17.6k
            }
1680
0
        }
1681
29.1k
        return 0;
1682
849k
    }
1683
1684
    /// Parsing function, handling TCP chunks fragmentation
1685
2.37M
    pub fn parse_tcp_data_tc(&mut self, flow: *const Flow, stream_slice: &StreamSlice) -> AppLayerResult
1686
    {
1687
2.37M
        let mut cur_i = stream_slice.as_slice();
1688
2.37M
        let consumed = self.handle_skip(Direction::ToClient, cur_i.len() as u32);
1689
2.37M
        if consumed > 0 {
1690
30.8k
            if consumed > cur_i.len() as u32 {
1691
0
                self.set_event(SMBEvent::InternalError);
1692
0
                return AppLayerResult::err();
1693
30.8k
            }
1694
30.8k
            cur_i = &cur_i[consumed as usize..];
1695
2.34M
        }
1696
        // take care of in progress file chunk transfers
1697
        // and skip buffer beyond it
1698
2.37M
        let consumed = self.filetracker_update(Direction::ToClient, cur_i, 0);
1699
2.37M
        if consumed > 0 {
1700
19.3k
            if consumed > cur_i.len() as u32 {
1701
0
                self.set_event(SMBEvent::InternalError);
1702
0
                return AppLayerResult::err();
1703
19.3k
            }
1704
19.3k
            cur_i = &cur_i[consumed as usize..];
1705
2.35M
        }
1706
2.37M
        if cur_i.is_empty() {
1707
58.0k
            return AppLayerResult::ok();
1708
2.31M
        }
1709
        // gap
1710
2.31M
        if self.tc_gap {
1711
            SCLogDebug!("TC trying to catch up after GAP (input {})", cur_i.len());
1712
37.4k
            while !cur_i.is_empty() { // min record size
1713
37.4k
                match search_smb_record(cur_i) {
1714
29.7k
                    Ok((_, pg)) => {
1715
                        SCLogDebug!("smb record found");
1716
29.7k
                        let smb2_offset = cur_i.len() - pg.len();
1717
29.7k
                        if smb2_offset < 4 {
1718
1.00k
                            cur_i = &cur_i[smb2_offset+4..];
1719
1.00k
                            continue; // see if we have another record in our data
1720
28.7k
                        }
1721
28.7k
                        let nbss_offset = smb2_offset - 4;
1722
28.7k
                        cur_i = &cur_i[nbss_offset..];
1723
1724
28.7k
                        self.tc_gap = false;
1725
28.7k
                        break;
1726
                    },
1727
                    _ => {
1728
7.75k
                        let mut consumed = stream_slice.len();
1729
7.75k
                        if consumed < 4 {
1730
752
                            consumed = 0;
1731
7.00k
                        } else {
1732
7.00k
                            consumed -= 3;
1733
7.00k
                        }
1734
                        SCLogDebug!("smb record NOT found");
1735
7.75k
                        return AppLayerResult::incomplete(consumed, 8);
1736
                    },
1737
                }
1738
            }
1739
2.28M
        }
1740
3.71M
        while !cur_i.is_empty() { // min record size
1741
3.54M
            match parse_nbss_record(cur_i) {
1742
1.40M
                Ok((rem, ref nbss_hdr)) => {
1743
                    SCLogDebug!("nbss record offset {} len {}", stream_slice.offset_from(cur_i), cur_i.len() - rem.len());
1744
1.40M
                    self.add_nbss_tc_frames(flow, stream_slice, cur_i, nbss_hdr.length as i64);
1745
                    SCLogDebug!("nbss frames added");
1746
1747
1.40M
                    if nbss_hdr.message_type == NBSS_MSGTYPE_SESSION_MESSAGE {
1748
                        // we have the full records size worth of data,
1749
                        // let's parse it
1750
1.33M
                        match parse_smb_version(nbss_hdr.data) {
1751
857k
                            Ok((_, ref smb)) => {
1752
                                SCLogDebug!("SMB {:?}", smb);
1753
857k
                                if smb.version == 0xff_u8 { // SMB1
1754
                                    SCLogDebug!("SMBv1 record");
1755
545k
                                    match parse_smb_record(nbss_hdr.data) {
1756
545k
                                        Ok((_, ref smb_record)) => {
1757
545k
                                            let pdu_frame = self.add_smb1_tc_pdu_frame(flow, stream_slice, nbss_hdr.data, nbss_hdr.length as i64);
1758
545k
                                            self.add_smb1_tc_hdr_data_frames(flow, stream_slice, nbss_hdr.data, nbss_hdr.length as i64);
1759
                                            // see https://github.com/rust-lang/rust-clippy/issues/15158
1760
                                            #[allow(clippy::collapsible_else_if)]
1761
545k
                                            if smb_record.is_response() {
1762
308k
                                                smb1_response_record(self, smb_record);
1763
308k
                                            } else {
1764
                                                SCLogDebug!("SMB1 request seen from server to client");
1765
237k
                                                if let Some(frame) = pdu_frame {
1766
45
                                                    frame.add_event(flow, SMBEvent::RequestToClient as u8);
1767
237k
                                                }
1768
                                            }
1769
                                        },
1770
                                        _ => {
1771
12
                                            self.set_event(SMBEvent::MalformedData);
1772
12
                                            return AppLayerResult::err();
1773
                                        },
1774
                                    }
1775
312k
                                } else if smb.version == 0xfe_u8 { // SMB2
1776
309k
                                    let mut nbss_data = nbss_hdr.data;
1777
630k
                                    while !nbss_data.is_empty() {
1778
                                        SCLogDebug!("SMBv2 record");
1779
322k
                                        match parse_smb2_response_record(nbss_data) {
1780
320k
                                            Ok((nbss_data_rem, ref smb_record)) => {
1781
320k
                                                let record_len = (nbss_data.len() - nbss_data_rem.len()) as i64;
1782
320k
                                                let pdu_frame = self.add_smb2_tc_pdu_frame(flow, stream_slice, nbss_data, record_len);
1783
320k
                                                self.add_smb2_tc_hdr_data_frames(flow, stream_slice, nbss_data, record_len, smb_record.header_len as i64);
1784
                                                // see https://github.com/rust-lang/rust-clippy/issues/15158
1785
                                                #[allow(clippy::collapsible_else_if)]
1786
320k
                                                if smb_record.is_response() {
1787
205k
                                                    smb2_response_record(self, smb_record);
1788
205k
                                                } else {
1789
                                                    SCLogDebug!("SMB2 request seen from server to client");
1790
115k
                                                    if let Some(frame) = pdu_frame {
1791
1.63k
                                                        frame.add_event(flow, SMBEvent::RequestToClient as u8);
1792
113k
                                                    }
1793
                                                }
1794
320k
                                                nbss_data = nbss_data_rem;
1795
                                            },
1796
                                            _ => {
1797
1.58k
                                                self.set_event(SMBEvent::MalformedData);
1798
1.58k
                                                return AppLayerResult::err();
1799
                                            },
1800
                                        }
1801
                                    }
1802
2.81k
                                } else if smb.version == 0xfd_u8 { // SMB3 transform
1803
962
                                    let mut nbss_data = nbss_hdr.data;
1804
2.23k
                                    while !nbss_data.is_empty() {
1805
                                        SCLogDebug!("SMBv3 transform record");
1806
1.31k
                                        match parse_smb3_transform_record(nbss_data) {
1807
1.27k
                                            Ok((nbss_data_rem, ref _smb3_record)) => {
1808
1.27k
                                                let record_len = (nbss_data.len() - nbss_data_rem.len()) as i64;
1809
1.27k
                                                self.add_smb3_tc_pdu_frame(flow, stream_slice, nbss_data, record_len);
1810
1.27k
                                                self.add_smb3_tc_hdr_data_frames(flow, stream_slice, nbss_data, record_len);
1811
1.27k
                                                nbss_data = nbss_data_rem;
1812
1.27k
                                            },
1813
                                            _ => {
1814
36
                                                self.set_event(SMBEvent::MalformedData);
1815
36
                                                return AppLayerResult::err();
1816
                                            },
1817
                                        }
1818
                                    }
1819
1.84k
                                }
1820
                            },
1821
472k
                            Err(Err::Incomplete(_)) => {
1822
472k
                                // not enough data to contain basic SMB hdr
1823
472k
                                // TODO event: empty NBSS_MSGTYPE_SESSION_MESSAGE
1824
472k
                            },
1825
                            Err(_) => {
1826
799
                                self.set_event(SMBEvent::MalformedData);
1827
799
                                return AppLayerResult::err();
1828
                            },
1829
                        }
1830
77.2k
                    } else {
1831
77.2k
                        SCLogDebug!("NBSS message {:X}", nbss_hdr.message_type);
1832
77.2k
                    }
1833
1.40M
                    cur_i = rem;
1834
                },
1835
2.13M
                Err(Err::Incomplete(needed)) => {
1836
                    SCLogDebug!("INCOMPLETE have {} needed {:?}", cur_i.len(), needed);
1837
2.13M
                    if let Needed::Size(n) = needed {
1838
2.13M
                        let n = usize::from(n) + cur_i.len();
1839
                        // 512 is the minimum for parse_tcp_data_tc_partial
1840
2.13M
                        if n >= 512 && cur_i.len() < 512 {
1841
1.28M
                            let total_consumed = stream_slice.offset_from(cur_i);
1842
1.28M
                            return AppLayerResult::incomplete(total_consumed, 512);
1843
849k
                        }
1844
849k
                        let consumed = self.parse_tcp_data_tc_partial(flow, stream_slice, cur_i);
1845
849k
                        if consumed == 0 {
1846
                            // if we consumed none we will buffer the entire record
1847
840k
                            let total_consumed = stream_slice.offset_from(cur_i);
1848
                            SCLogDebug!("setting consumed {} need {} needed {:?} total input {}",
1849
                                    total_consumed, n, needed, stream_slice.len());
1850
840k
                            let need = n;
1851
840k
                            return AppLayerResult::incomplete(total_consumed, need as u32);
1852
9.08k
                        }
1853
                        // tracking a read record, which we don't need to
1854
                        // queue up at the stream level, but can feed to us
1855
                        // in small chunks
1856
9.08k
                        return AppLayerResult::ok();
1857
                    } else {
1858
0
                        self.set_event(SMBEvent::InternalError);
1859
0
                        return AppLayerResult::err();
1860
                    }
1861
                },
1862
                Err(_) => {
1863
0
                    self.set_event(SMBEvent::MalformedData);
1864
0
                    return AppLayerResult::err();
1865
                },
1866
            }
1867
        };
1868
175k
        self.post_gap_housekeeping(Direction::ToClient);
1869
175k
        if self.check_post_gap_file_txs && !self.post_gap_files_checked {
1870
312
            self.post_gap_housekeeping_for_files();
1871
312
            self.post_gap_files_checked = true;
1872
174k
        }
1873
175k
        self._debug_tx_stats();
1874
175k
        AppLayerResult::ok()
1875
2.37M
    }
1876
1877
    /// handle a gap in the TOSERVER direction
1878
    /// returns: 0 ok, 1 unrecoverable error
1879
14.0k
    pub fn parse_tcp_data_ts_gap(&mut self, gap_size: u32) -> AppLayerResult {
1880
14.0k
        let consumed = self.handle_skip(Direction::ToServer, gap_size);
1881
14.0k
        if consumed < gap_size {
1882
14.0k
            let new_gap_size = gap_size - consumed;
1883
14.0k
            let gap = vec![0; new_gap_size as usize];
1884
1885
14.0k
            let consumed2 = self.filetracker_update(Direction::ToServer, &gap, new_gap_size);
1886
14.0k
            if consumed2 > new_gap_size {
1887
                SCLogDebug!("consumed more than GAP size: {} > {}", consumed2, new_gap_size);
1888
0
                self.set_event(SMBEvent::InternalError);
1889
0
                return AppLayerResult::err();
1890
14.0k
            }
1891
17
        }
1892
        SCLogDebug!("GAP of size {} in toserver direction", gap_size);
1893
14.0k
        self.ts_ssn_gap = true;
1894
14.0k
        self.ts_gap = true;
1895
14.0k
        return AppLayerResult::ok();
1896
14.0k
    }
1897
1898
    /// handle a gap in the TOCLIENT direction
1899
    /// returns: 0 ok, 1 unrecoverable error
1900
17.0k
    pub fn parse_tcp_data_tc_gap(&mut self, gap_size: u32) -> AppLayerResult {
1901
17.0k
        let consumed = self.handle_skip(Direction::ToClient, gap_size);
1902
17.0k
        if consumed < gap_size {
1903
17.0k
            let new_gap_size = gap_size - consumed;
1904
17.0k
            let gap = vec![0; new_gap_size as usize];
1905
1906
17.0k
            let consumed2 = self.filetracker_update(Direction::ToClient, &gap, new_gap_size);
1907
17.0k
            if consumed2 > new_gap_size {
1908
                SCLogDebug!("consumed more than GAP size: {} > {}", consumed2, new_gap_size);
1909
0
                self.set_event(SMBEvent::InternalError);
1910
0
                return AppLayerResult::err();
1911
17.0k
            }
1912
24
        }
1913
        SCLogDebug!("GAP of size {} in toclient direction", gap_size);
1914
17.0k
        self.tc_ssn_gap = true;
1915
17.0k
        self.tc_gap = true;
1916
17.0k
        return AppLayerResult::ok();
1917
17.0k
    }
1918
1919
133k
    pub fn trunc_ts(&mut self) {
1920
        SCLogDebug!("TRUNC TS");
1921
133k
        self.ts_trunc = true;
1922
1923
3.49M
        for tx in &mut self.transactions {
1924
3.36M
            if !tx.request_done {
1925
33.6k
                SCLogDebug!("TRUNCATING TX {} in TOSERVER direction", tx.id);
1926
33.6k
                tx.request_done = true;
1927
3.32M
            }
1928
       }
1929
133k
    }
1930
105k
    pub fn trunc_tc(&mut self) {
1931
        SCLogDebug!("TRUNC TC");
1932
105k
        self.tc_trunc = true;
1933
1934
294k
        for tx in &mut self.transactions {
1935
188k
            if !tx.response_done {
1936
163k
                SCLogDebug!("TRUNCATING TX {} in TOCLIENT direction", tx.id);
1937
163k
                tx.response_done = true;
1938
163k
            }
1939
        }
1940
105k
    }
1941
}
1942
1943
/// Returns *mut SMBState
1944
#[no_mangle]
1945
61.1k
pub extern "C" fn rs_smb_state_new(_orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto) -> *mut std::os::raw::c_void {
1946
61.1k
    let state = SMBState::new();
1947
61.1k
    let boxed = Box::new(state);
1948
    SCLogDebug!("allocating state");
1949
61.1k
    return Box::into_raw(boxed) as *mut _;
1950
61.1k
}
1951
1952
/// Params:
1953
/// - state: *mut SMBState as void pointer
1954
#[no_mangle]
1955
61.1k
pub extern "C" fn rs_smb_state_free(state: *mut std::os::raw::c_void) {
1956
    SCLogDebug!("freeing state");
1957
61.1k
    let mut smb_state = unsafe { Box::from_raw(state as *mut SMBState) };
1958
61.1k
    smb_state.free();
1959
61.1k
}
1960
1961
/// C binding parse a SMB request. Returns 1 on success, -1 on failure.
1962
#[no_mangle]
1963
2.46M
pub unsafe extern "C" fn rs_smb_parse_request_tcp(flow: *const Flow,
1964
2.46M
                                       state: *mut ffi::c_void,
1965
2.46M
                                       _pstate: *mut std::os::raw::c_void,
1966
2.46M
                                       stream_slice: StreamSlice,
1967
2.46M
                                       _data: *const std::os::raw::c_void,
1968
2.46M
                                       )
1969
2.46M
                                       -> AppLayerResult
1970
{
1971
2.46M
    let state = cast_pointer!(state, SMBState);
1972
2.46M
    let flow = cast_pointer!(flow, Flow);
1973
1974
2.46M
    if stream_slice.is_gap() {
1975
14.0k
        return rs_smb_parse_request_tcp_gap(state, stream_slice.gap_size());
1976
2.44M
    }
1977
1978
    SCLogDebug!("parsing {} bytes of request data", stream_slice.len());
1979
1980
    /* START with MISTREAM set: record might be starting the middle. */
1981
2.44M
    if stream_slice.flags() & (STREAM_START|STREAM_MIDSTREAM) == (STREAM_START|STREAM_MIDSTREAM) {
1982
20.4k
        state.ts_gap = true;
1983
2.42M
    }
1984
1985
2.44M
    state.update_ts(flow.get_last_time().as_secs());
1986
2.44M
    state.parse_tcp_data_ts(flow, &stream_slice)
1987
2.46M
}
1988
1989
#[no_mangle]
1990
14.0k
pub extern "C" fn rs_smb_parse_request_tcp_gap(
1991
14.0k
                                        state: &mut SMBState,
1992
14.0k
                                        input_len: u32)
1993
14.0k
                                        -> AppLayerResult
1994
{
1995
14.0k
    state.parse_tcp_data_ts_gap(input_len)
1996
14.0k
}
1997
1998
1999
#[no_mangle]
2000
2.39M
pub unsafe extern "C" fn rs_smb_parse_response_tcp(flow: *const Flow,
2001
2.39M
                                        state: *mut ffi::c_void,
2002
2.39M
                                        _pstate: *mut std::os::raw::c_void,
2003
2.39M
                                        stream_slice: StreamSlice,
2004
2.39M
                                        _data: *const ffi::c_void,
2005
2.39M
                                        )
2006
2.39M
                                        -> AppLayerResult
2007
{
2008
2.39M
    let state = cast_pointer!(state, SMBState);
2009
2.39M
    let flow = cast_pointer!(flow, Flow);
2010
2011
2.39M
    if stream_slice.is_gap() {
2012
17.0k
        return rs_smb_parse_response_tcp_gap(state, stream_slice.gap_size());
2013
2.37M
    }
2014
2015
    /* START with MISTREAM set: record might be starting the middle. */
2016
2.37M
    if stream_slice.flags() & (STREAM_START|STREAM_MIDSTREAM) == (STREAM_START|STREAM_MIDSTREAM) {
2017
17.0k
        state.tc_gap = true;
2018
2.35M
    }
2019
2020
2.37M
    state.update_ts(flow.get_last_time().as_secs());
2021
2.37M
    state.parse_tcp_data_tc(flow, &stream_slice)
2022
2.39M
}
2023
2024
#[no_mangle]
2025
17.0k
pub extern "C" fn rs_smb_parse_response_tcp_gap(
2026
17.0k
                                        state: &mut SMBState,
2027
17.0k
                                        input_len: u32)
2028
17.0k
                                        -> AppLayerResult
2029
{
2030
17.0k
    state.parse_tcp_data_tc_gap(input_len)
2031
17.0k
}
2032
2033
54.2k
fn smb_probe_tcp_midstream(direction: Direction, slice: &[u8], rdir: *mut u8, begins: bool) -> i8
2034
{
2035
54.2k
    let r = if begins {
2036
        // if pattern was found in the beginning, just check first byte
2037
29.3k
        if slice[0] == NBSS_MSGTYPE_SESSION_MESSAGE {
2038
23.5k
            Ok((&slice[..4], &slice[4..]))
2039
        } else {
2040
5.81k
            Err(Err::Error(make_error(slice, ErrorKind::Eof)))
2041
        }
2042
    } else {
2043
24.8k
        search_smb_record(slice)
2044
    };
2045
54.2k
    if let Ok((_, data)) = r {
2046
        SCLogDebug!("smb found");
2047
36.7k
        if let Ok((_, ref smb)) = parse_smb_version(data) {
2048
            SCLogDebug!("SMB {:?}", smb);
2049
36.7k
            if smb.version == 0xff_u8 { // SMB1
2050
                SCLogDebug!("SMBv1 record");
2051
8.94k
                if let Ok((_, ref smb_record)) = parse_smb_record(data) {
2052
                    // see https://github.com/rust-lang/rust-clippy/issues/15158
2053
                    #[allow(clippy::collapsible_else_if)]
2054
8.92k
                    if smb_record.flags & 0x80 != 0 {
2055
                        SCLogDebug!("RESPONSE {:02x}", smb_record.flags);
2056
1.99k
                        if direction == Direction::ToServer {
2057
1.23k
                            unsafe { *rdir = Direction::ToClient as u8; }
2058
759
                        }
2059
                    } else {
2060
                        SCLogDebug!("REQUEST {:02x}", smb_record.flags);
2061
6.92k
                        if direction == Direction::ToClient {
2062
56
                            unsafe { *rdir = Direction::ToServer as u8; }
2063
6.87k
                        }
2064
                    }
2065
8.92k
                    return 1;
2066
22
                }
2067
27.7k
            } else if smb.version == 0xfe_u8 { // SMB2
2068
                SCLogDebug!("SMB2 record");
2069
27.7k
                if let Ok((_, ref smb_record)) = parse_smb2_record_direction(data) {
2070
                    // see https://github.com/rust-lang/rust-clippy/issues/15158
2071
                    #[allow(clippy::collapsible_else_if)]
2072
27.6k
                    if direction == Direction::ToServer {
2073
                        SCLogDebug!("direction Direction::ToServer smb_record {:?}", smb_record);
2074
22.3k
                        if !smb_record.request {
2075
9.64k
                            unsafe { *rdir = Direction::ToClient as u8; }
2076
12.6k
                        }
2077
                    } else {
2078
                        SCLogDebug!("direction Direction::ToClient smb_record {:?}", smb_record);
2079
5.33k
                        if smb_record.request {
2080
1.14k
                            unsafe { *rdir = Direction::ToServer as u8; }
2081
4.18k
                        }
2082
                    }
2083
107
                }
2084
            }
2085
4
            else if smb.version == 0xfd_u8 { // SMB3 transform
2086
4
                SCLogDebug!("SMB3 record");
2087
4
            }
2088
27.8k
            return 1;
2089
0
        } else {
2090
0
            SCLogDebug!("smb not found in {:?}", slice);
2091
0
        }
2092
17.5k
    } else {
2093
17.5k
        SCLogDebug!("no dice");
2094
17.5k
    }
2095
17.5k
    return 0;
2096
54.2k
}
2097
2098
66.6k
fn smb_probe_tcp(flags: u8, slice: &[u8], rdir: *mut u8, begins: bool) -> AppProto
2099
{
2100
66.6k
    if flags & STREAM_MIDSTREAM == STREAM_MIDSTREAM && smb_probe_tcp_midstream(flags.into(), slice, rdir, begins) == 1 {
2101
36.7k
        unsafe { return ALPROTO_SMB; }
2102
29.8k
    }
2103
29.8k
    if let Ok((_, ref hdr)) = parse_nbss_record_partial(slice) {
2104
29.8k
        if hdr.is_smb() {
2105
            SCLogDebug!("smb found");
2106
5.15k
            unsafe { return ALPROTO_SMB; }
2107
24.7k
        } else if hdr.needs_more(){
2108
0
            return 0;
2109
24.7k
        } else if hdr.is_valid() &&
2110
9.08k
            hdr.message_type != NBSS_MSGTYPE_SESSION_MESSAGE {
2111
                //we accept a first small netbios message before real SMB
2112
6.03k
                let hl = hdr.length as usize;
2113
6.03k
                if hdr.data.len() >= hl + 8 {
2114
                    // 8 is 4 bytes NBSS + 4 bytes SMB0xFX magic
2115
4.31k
                    if let Ok((_, ref hdr2)) = parse_nbss_record_partial(&hdr.data[hl..]) {
2116
4.31k
                        if hdr2.is_smb() {
2117
                            SCLogDebug!("smb found");
2118
4.26k
                            unsafe { return ALPROTO_SMB; }
2119
50
                        }
2120
0
                    }
2121
1.71k
                } else if hdr.length < 256 {
2122
                    // we want more data, 256 is some random value
2123
227
                    return 0;
2124
1.48k
                }
2125
                // default is failure
2126
18.6k
            }
2127
0
    }
2128
    SCLogDebug!("no smb");
2129
20.2k
    unsafe { return ALPROTO_FAILED; }
2130
66.6k
}
2131
2132
// probing confirmation parser
2133
// return 1 if found, 0 is not found
2134
#[no_mangle]
2135
33.9k
pub unsafe extern "C" fn rs_smb_probe_begins_tcp(_f: *const Flow,
2136
33.9k
                                   flags: u8, input: *const u8, len: u32, rdir: *mut u8)
2137
33.9k
    -> AppProto
2138
{
2139
33.9k
    if len < MIN_REC_SIZE as u32 || input.is_null() {
2140
0
        return ALPROTO_UNKNOWN;
2141
33.9k
    }
2142
33.9k
    let slice = build_slice!(input, len as usize);
2143
33.9k
    return smb_probe_tcp(flags, slice, rdir, true);
2144
33.9k
}
2145
2146
// probing parser
2147
// return 1 if found, 0 is not found
2148
#[no_mangle]
2149
159k
pub unsafe extern "C" fn rs_smb_probe_tcp(_f: *const Flow,
2150
159k
                                   flags: u8, input: *const u8, len: u32, rdir: *mut u8)
2151
159k
    -> AppProto
2152
{
2153
159k
    if len < MIN_REC_SIZE as u32 || input.is_null() {
2154
126k
        return ALPROTO_UNKNOWN;
2155
32.6k
    }
2156
32.6k
    let slice = build_slice!(input, len as usize);
2157
32.6k
    return smb_probe_tcp(flags, slice, rdir, false);
2158
159k
}
2159
2160
#[no_mangle]
2161
15.0M
pub unsafe extern "C" fn rs_smb_state_get_tx_count(state: *mut ffi::c_void)
2162
15.0M
                                            -> u64
2163
{
2164
15.0M
    let state = cast_pointer!(state, SMBState);
2165
    SCLogDebug!("rs_smb_state_get_tx_count: returning {}", state.tx_id);
2166
15.0M
    return state.tx_id;
2167
15.0M
}
2168
2169
#[no_mangle]
2170
16.7k
pub unsafe extern "C" fn rs_smb_state_get_tx(state: *mut ffi::c_void,
2171
16.7k
                                      tx_id: u64)
2172
16.7k
                                      -> *mut ffi::c_void
2173
{
2174
16.7k
    let state = cast_pointer!(state, SMBState);
2175
16.7k
    match state.get_tx_by_id(tx_id) {
2176
9.63k
        Some(tx) => {
2177
9.63k
            return tx as *const _ as *mut _;
2178
        }
2179
        None => {
2180
7.15k
            return std::ptr::null_mut();
2181
        }
2182
    }
2183
16.7k
}
2184
2185
#[no_mangle]
2186
1.27M
pub unsafe extern "C" fn rs_smb_state_tx_free(state: *mut ffi::c_void,
2187
1.27M
                                       tx_id: u64)
2188
{
2189
1.27M
    let state = cast_pointer!(state, SMBState);
2190
    SCLogDebug!("freeing tx {}", tx_id);
2191
1.27M
    state.free_tx(tx_id);
2192
1.27M
}
2193
2194
#[no_mangle]
2195
270M
pub unsafe extern "C" fn rs_smb_tx_get_alstate_progress(tx: *mut ffi::c_void,
2196
270M
                                                  direction: u8)
2197
270M
                                                  -> i32
2198
{
2199
270M
    let tx = cast_pointer!(tx, SMBTransaction);
2200
2201
270M
    if direction == Direction::ToServer as u8 && tx.request_done {
2202
        SCLogDebug!("tx {} TOSERVER progress 1 => {:?}", tx.id, tx);
2203
3.56M
        return 1;
2204
266M
    } else if direction == Direction::ToClient as u8 && tx.response_done {
2205
        SCLogDebug!("tx {} TOCLIENT progress 1 => {:?}", tx.id, tx);
2206
3.06M
        return 1;
2207
    } else {
2208
        SCLogDebug!("tx {} direction {} progress 0 => {:?}", tx.id, direction, tx);
2209
263M
        return 0;
2210
    }
2211
270M
}
2212
2213
2214
export_state_data_get!(rs_smb_get_state_data, SMBState);
2215
2216
#[no_mangle]
2217
267M
pub unsafe extern "C" fn rs_smb_get_tx_data(
2218
267M
    tx: *mut std::os::raw::c_void)
2219
267M
    -> *mut AppLayerTxData
2220
{
2221
267M
    let tx = cast_pointer!(tx, SMBTransaction);
2222
267M
    return &mut tx.tx_data;
2223
267M
}
2224
2225
2226
#[no_mangle]
2227
0
pub unsafe extern "C" fn rs_smb_state_truncate(
2228
0
        state: *mut std::ffi::c_void,
2229
0
        direction: u8)
2230
{
2231
0
    let state = cast_pointer!(state, SMBState);
2232
0
    match direction.into() {
2233
0
        Direction::ToServer => {
2234
0
            state.trunc_ts();
2235
0
        }
2236
0
        Direction::ToClient => {
2237
0
            state.trunc_tc();
2238
0
        }
2239
    }
2240
0
}
2241
2242
#[no_mangle]
2243
4.35k
pub unsafe extern "C" fn rs_smb_state_get_event_info_by_id(
2244
4.35k
    event_id: std::os::raw::c_int,
2245
4.35k
    event_name: *mut *const std::os::raw::c_char,
2246
4.35k
    event_type: *mut AppLayerEventType,
2247
4.35k
) -> std::os::raw::c_int {
2248
4.35k
    SMBEvent::get_event_info_by_id(event_id, event_name, event_type)
2249
4.35k
}
2250
2251
#[no_mangle]
2252
1.82k
pub unsafe extern "C" fn rs_smb_state_get_event_info(
2253
1.82k
    event_name: *const std::os::raw::c_char,
2254
1.82k
    event_id: *mut std::os::raw::c_int,
2255
1.82k
    event_type: *mut AppLayerEventType,
2256
1.82k
) -> std::os::raw::c_int {
2257
1.82k
    SMBEvent::get_event_info(event_name, event_id, event_type)
2258
1.82k
}
2259
2260
16
pub unsafe extern "C" fn smb3_probe_tcp(f: *const Flow, dir: u8, input: *const u8, len: u32, rdir: *mut u8) -> u16 {
2261
16
    let retval = rs_smb_probe_tcp(f, dir, input, len, rdir);
2262
16
    let f = cast_pointer!(f, Flow);
2263
16
    if retval != ALPROTO_SMB {
2264
4
        return retval;
2265
12
    }
2266
12
    let (sp, dp) = f.get_ports();
2267
12
    let flags = f.get_flags();
2268
12
    let fsp = if (flags & FLOW_DIR_REVERSED) != 0 { dp } else { sp };
2269
12
    let fdp = if (flags & FLOW_DIR_REVERSED) != 0 { sp } else { dp };
2270
12
    if fsp == 445 && fdp != 445 {
2271
4
        match dir.into() {
2272
2
            Direction::ToServer => {
2273
2
                *rdir = Direction::ToClient as u8;
2274
2
            }
2275
2
            Direction::ToClient => {
2276
2
                *rdir = Direction::ToServer as u8;
2277
2
            }
2278
        }
2279
8
    }
2280
12
    return ALPROTO_SMB;
2281
16
}
2282
2283
34
fn register_pattern_probe() -> i8 {
2284
34
    let mut r = 0;
2285
34
    unsafe {
2286
34
        // SMB1
2287
34
        r |= AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB,
2288
34
                                                     b"|ff|SMB\0".as_ptr() as *const std::os::raw::c_char, 8, 4,
2289
34
                                                     Direction::ToServer as u8, rs_smb_probe_begins_tcp, MIN_REC_SIZE, MIN_REC_SIZE);
2290
34
        r |= AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB,
2291
34
                                                     b"|ff|SMB\0".as_ptr() as *const std::os::raw::c_char, 8, 4,
2292
34
                                                     Direction::ToClient as u8, rs_smb_probe_begins_tcp, MIN_REC_SIZE, MIN_REC_SIZE);
2293
34
        // SMB2/3
2294
34
        r |= AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB,
2295
34
                                                     b"|fe|SMB\0".as_ptr() as *const std::os::raw::c_char, 8, 4,
2296
34
                                                     Direction::ToServer as u8, rs_smb_probe_begins_tcp, MIN_REC_SIZE, MIN_REC_SIZE);
2297
34
        r |= AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB,
2298
34
                                                     b"|fe|SMB\0".as_ptr() as *const std::os::raw::c_char, 8, 4,
2299
34
                                                     Direction::ToClient as u8, rs_smb_probe_begins_tcp, MIN_REC_SIZE, MIN_REC_SIZE);
2300
34
        // SMB3 encrypted records
2301
34
        r |= AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB,
2302
34
                                                     b"|fd|SMB\0".as_ptr() as *const std::os::raw::c_char, 8, 4,
2303
34
                                                     Direction::ToServer as u8, smb3_probe_tcp, MIN_REC_SIZE, MIN_REC_SIZE);
2304
34
        r |= AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB,
2305
34
                                                     b"|fd|SMB\0".as_ptr() as *const std::os::raw::c_char, 8, 4,
2306
34
                                                     Direction::ToClient as u8, smb3_probe_tcp, MIN_REC_SIZE, MIN_REC_SIZE);
2307
34
    }
2308
2309
34
    if r == 0 {
2310
34
        return 0;
2311
    } else {
2312
0
        return -1;
2313
    }
2314
34
}
2315
2316
// Parser name as a C style string.
2317
const PARSER_NAME: &[u8] = b"smb\0";
2318
2319
#[no_mangle]
2320
34
pub unsafe extern "C" fn rs_smb_register_parser() {
2321
34
    let default_port = CString::new("445").unwrap();
2322
34
    let mut stream_depth = SMB_CONFIG_DEFAULT_STREAM_DEPTH;
2323
34
    let parser = RustParser {
2324
34
        name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char,
2325
34
        default_port: std::ptr::null(),
2326
34
        ipproto: IPPROTO_TCP,
2327
34
        probe_ts: None,
2328
34
        probe_tc: None,
2329
34
        min_depth: 0,
2330
34
        max_depth: 16,
2331
34
        state_new: rs_smb_state_new,
2332
34
        state_free: rs_smb_state_free,
2333
34
        tx_free: rs_smb_state_tx_free,
2334
34
        parse_ts: rs_smb_parse_request_tcp,
2335
34
        parse_tc: rs_smb_parse_response_tcp,
2336
34
        get_tx_count: rs_smb_state_get_tx_count,
2337
34
        get_tx: rs_smb_state_get_tx,
2338
34
        tx_comp_st_ts: 1,
2339
34
        tx_comp_st_tc: 1,
2340
34
        tx_get_progress: rs_smb_tx_get_alstate_progress,
2341
34
        get_eventinfo: Some(rs_smb_state_get_event_info),
2342
34
        get_eventinfo_byid : Some(rs_smb_state_get_event_info_by_id),
2343
34
        localstorage_new: None,
2344
34
        localstorage_free: None,
2345
34
        get_tx_files: Some(rs_smb_gettxfiles),
2346
34
        get_tx_iterator: Some(applayer::state_get_tx_iterator::<SMBState, SMBTransaction>),
2347
34
        get_tx_data: rs_smb_get_tx_data,
2348
34
        get_state_data: rs_smb_get_state_data,
2349
34
        apply_tx_config: None,
2350
34
        flags: APP_LAYER_PARSER_OPT_ACCEPT_GAPS,
2351
34
        truncate: Some(rs_smb_state_truncate),
2352
34
        get_frame_id_by_name: Some(SMBFrameType::ffi_id_from_name),
2353
34
        get_frame_name_by_id: Some(SMBFrameType::ffi_name_from_id),
2354
34
    };
2355
2356
34
    let ip_proto_str = CString::new("tcp").unwrap();
2357
2358
34
    if AppLayerProtoDetectConfProtoDetectionEnabled(
2359
34
        ip_proto_str.as_ptr(),
2360
34
        parser.name,
2361
34
    ) != 0
2362
    {
2363
34
        let alproto = AppLayerRegisterProtocolDetection(&parser, 1);
2364
34
        ALPROTO_SMB = alproto;
2365
34
        if register_pattern_probe() < 0 {
2366
0
            return;
2367
34
        }
2368
2369
34
        let have_cfg = AppLayerProtoDetectPPParseConfPorts(ip_proto_str.as_ptr(),
2370
34
                    IPPROTO_TCP, parser.name, ALPROTO_SMB, 0,
2371
34
                    MIN_REC_SIZE, rs_smb_probe_tcp, rs_smb_probe_tcp);
2372
2373
34
        if have_cfg == 0 {
2374
34
            AppLayerProtoDetectPPRegister(IPPROTO_TCP, default_port.as_ptr(), ALPROTO_SMB,
2375
34
                                          0, MIN_REC_SIZE, Direction::ToServer as u8, rs_smb_probe_tcp, rs_smb_probe_tcp);
2376
34
        }
2377
2378
34
        if AppLayerParserConfParserEnabled(
2379
34
            ip_proto_str.as_ptr(),
2380
34
            parser.name,
2381
34
        ) != 0
2382
34
        {
2383
34
            let _ = AppLayerRegisterParser(&parser, alproto);
2384
34
        }
2385
        SCLogDebug!("Rust SMB parser registered.");
2386
34
        let retval = conf_get("app-layer.protocols.smb.stream-depth");
2387
34
        if let Some(val) = retval {
2388
0
            match get_memval(val) {
2389
0
                Ok(retval) => { stream_depth = retval as u32; }
2390
0
                Err(_) => { SCLogError!("Invalid depth value"); }
2391
            }
2392
34
        }
2393
34
        AppLayerParserSetStreamDepth(IPPROTO_TCP, ALPROTO_SMB, stream_depth);
2394
34
        let retval = conf_get("app-layer.protocols.smb.max-read-size");
2395
34
        if let Some(val) = retval {
2396
0
            match get_memval(val) {
2397
0
                Ok(retval) => { SMB_CFG_MAX_READ_SIZE = retval as u32; }
2398
0
                Err(_) => { SCLogError!("Invalid max-read-size value"); }
2399
            }
2400
34
        }
2401
34
        let retval = conf_get("app-layer.protocols.smb.max-write-size");
2402
34
        if let Some(val) = retval {
2403
0
            match get_memval(val) {
2404
0
                Ok(retval) => { SMB_CFG_MAX_WRITE_SIZE = retval as u32; }
2405
0
                Err(_) => { SCLogError!("Invalid max-write-size value"); }
2406
            }
2407
34
        }
2408
34
        let retval = conf_get("app-layer.protocols.smb.max-write-queue-size");
2409
34
        if let Some(val) = retval {
2410
0
            match get_memval(val) {
2411
0
                Ok(retval) => { SMB_CFG_MAX_WRITE_QUEUE_SIZE = retval as u32; }
2412
0
                Err(_) => { SCLogError!("Invalid max-write-queue-size value"); }
2413
            }
2414
34
        }
2415
34
        let retval = conf_get("app-layer.protocols.smb.max-write-queue-cnt");
2416
34
        if let Some(val) = retval {
2417
0
            match get_memval(val) {
2418
0
                Ok(retval) => { SMB_CFG_MAX_WRITE_QUEUE_CNT = retval as u32; }
2419
0
                Err(_) => { SCLogError!("Invalid max-write-queue-cnt value"); }
2420
            }
2421
34
        }
2422
34
        let retval = conf_get("app-layer.protocols.smb.max-read-queue-size");
2423
34
        if let Some(val) = retval {
2424
0
            match get_memval(val) {
2425
0
                Ok(retval) => { SMB_CFG_MAX_READ_QUEUE_SIZE = retval as u32; }
2426
0
                Err(_) => { SCLogError!("Invalid max-read-queue-size value"); }
2427
            }
2428
34
        }
2429
34
        let retval = conf_get("app-layer.protocols.smb.max-read-queue-cnt");
2430
34
        if let Some(val) = retval {
2431
0
            match get_memval(val) {
2432
0
                Ok(retval) => { SMB_CFG_MAX_READ_QUEUE_CNT = retval as u32; }
2433
0
                Err(_) => { SCLogError!("Invalid max-read-queue-cnt value"); }
2434
            }
2435
34
        }
2436
34
        if let Some(val) = conf_get("app-layer.protocols.smb.max-tx") {
2437
0
            if let Ok(v) = val.parse::<usize>() {
2438
0
                SMB_MAX_TX = v;
2439
0
            } else {
2440
0
                SCLogError!("Invalid value for smb.max-tx");
2441
            }
2442
34
        }
2443
34
       let retval = conf_get("app-layer.protocols.smb.dcerpc.max-stub-size");
2444
34
       if let Some(val) = retval {
2445
0
           match get_memval(val) {
2446
0
               Ok(retval) => {
2447
0
                    if retval > 0 {
2448
0
                        SMB_DCERPC_MAX_STUB_SIZE = retval as u32;
2449
0
                    } else {
2450
0
                        SCLogError!("Invalid max-stub-size value");
2451
                    }
2452
               }
2453
               Err(_) => {
2454
0
                    SCLogError!("Invalid max-stub-size value");
2455
               }
2456
           }
2457
34
       }
2458
34
        SCLogConfig!("read: max record size: {}, max queued chunks {}, max queued size {}",
2459
0
                SMB_CFG_MAX_READ_SIZE, SMB_CFG_MAX_READ_QUEUE_CNT, SMB_CFG_MAX_READ_QUEUE_SIZE);
2460
34
        SCLogConfig!("write: max record size: {}, max queued chunks {}, max queued size {}",
2461
0
                SMB_CFG_MAX_WRITE_SIZE, SMB_CFG_MAX_WRITE_QUEUE_CNT, SMB_CFG_MAX_WRITE_QUEUE_SIZE);
2462
0
    } else {
2463
0
        SCLogDebug!("Protocol detector and parser disabled for SMB.");
2464
0
    }
2465
34
}
2466
2467
#[inline(always)]
2468
17.1k
pub fn cfg_max_stub_size() -> u32 {
2469
17.1k
    unsafe { SMB_DCERPC_MAX_STUB_SIZE }
2470
17.1k
}
2471