/src/suricata/rust/src/smb/smb2_ioctl.rs
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2018 Open Information Security Foundation |
2 | | * |
3 | | * You can copy, redistribute or modify this Program under the terms of |
4 | | * the GNU General Public License version 2 as published by the Free |
5 | | * Software Foundation. |
6 | | * |
7 | | * This program is distributed in the hope that it will be useful, |
8 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | | * GNU General Public License for more details. |
11 | | * |
12 | | * You should have received a copy of the GNU General Public License |
13 | | * version 2 along with this program; if not, write to the Free Software |
14 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
15 | | * 02110-1301, USA. |
16 | | */ |
17 | | |
18 | | use crate::smb::smb::*; |
19 | | use crate::smb::smb2::*; |
20 | | use crate::smb::smb2_records::*; |
21 | | use crate::smb::dcerpc::*; |
22 | | use crate::smb::events::*; |
23 | | #[cfg(feature = "debug")] |
24 | | use crate::smb::funcs::*; |
25 | | |
26 | 0 | #[derive(Debug)] |
27 | | pub struct SMBTransactionIoctl { |
28 | | pub func: u32, |
29 | | } |
30 | | |
31 | | impl SMBTransactionIoctl { |
32 | 21.0k | pub fn new(func: u32) -> Self { |
33 | 21.0k | return Self { |
34 | 21.0k | func: func, |
35 | 21.0k | } |
36 | 21.0k | } |
37 | | } |
38 | | |
39 | | impl SMBState { |
40 | 21.0k | pub fn new_ioctl_tx(&mut self, hdr: SMBCommonHdr, func: u32) |
41 | 21.0k | -> &mut SMBTransaction |
42 | 21.0k | { |
43 | 21.0k | let mut tx = self.new_tx(); |
44 | 21.0k | tx.hdr = hdr; |
45 | 21.0k | tx.type_data = Some(SMBTransactionTypeData::IOCTL( |
46 | 21.0k | SMBTransactionIoctl::new(func))); |
47 | 21.0k | tx.request_done = true; |
48 | 21.0k | tx.response_done = self.tc_trunc; // no response expected if tc is truncated |
49 | 21.0k | |
50 | 21.0k | SCLogDebug!("SMB: TX IOCTL created: ID {} FUNC {:08x}: {}", |
51 | 21.0k | tx.id, func, &fsctl_func_to_string(func)); |
52 | 21.0k | self.transactions.push(tx); |
53 | 21.0k | let tx_ref = self.transactions.last_mut(); |
54 | 21.0k | return tx_ref.unwrap(); |
55 | 21.0k | } |
56 | | } |
57 | | |
58 | | // IOCTL responses ASYNC don't set the tree id |
59 | 47.3k | pub fn smb2_ioctl_request_record<'b>(state: &mut SMBState, r: &Smb2Record<'b>) |
60 | 47.3k | { |
61 | 47.3k | let hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_HEADER); |
62 | 47.3k | match parse_smb2_request_ioctl(r.data) { |
63 | 27.7k | Ok((_, rd)) => { |
64 | | SCLogDebug!("IOCTL request data: {:?}", rd); |
65 | 27.7k | let is_dcerpc = if rd.is_pipe { |
66 | 23.2k | state.get_service_for_guid(rd.guid).1 |
67 | | } else { |
68 | 4.55k | false |
69 | | }; |
70 | 27.7k | if is_dcerpc { |
71 | 6.76k | SCLogDebug!("IOCTL request data is_pipe. Calling smb_write_dcerpc_record"); |
72 | 6.76k | let vercmd = SMBVerCmdStat::new2(SMB2_COMMAND_IOCTL); |
73 | 6.76k | smb_write_dcerpc_record(state, vercmd, hdr, rd.data); |
74 | 21.0k | } else { |
75 | 21.0k | SCLogDebug!("IOCTL {:08x} {}", rd.function, &fsctl_func_to_string(rd.function)); |
76 | 21.0k | let tx = state.new_ioctl_tx(hdr, rd.function); |
77 | 21.0k | tx.vercmd.set_smb2_cmd(SMB2_COMMAND_IOCTL); |
78 | 21.0k | } |
79 | | }, |
80 | 19.5k | _ => { |
81 | 19.5k | let tx = state.new_generic_tx(2, r.command, hdr); |
82 | 19.5k | tx.set_event(SMBEvent::MalformedData); |
83 | 19.5k | }, |
84 | | }; |
85 | 47.3k | } |
86 | | |
87 | | // IOCTL responses ASYNC don't set the tree id |
88 | 51.6k | pub fn smb2_ioctl_response_record<'b>(state: &mut SMBState, r: &Smb2Record<'b>) |
89 | 51.6k | { |
90 | 51.6k | let hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_HEADER); |
91 | 51.6k | match parse_smb2_response_ioctl(r.data) { |
92 | 29.6k | Ok((_, rd)) => { |
93 | | SCLogDebug!("IOCTL response data: {:?}", rd); |
94 | | |
95 | 29.6k | let is_dcerpc = if rd.is_pipe { |
96 | 25.7k | state.get_service_for_guid(rd.guid).1 |
97 | | } else { |
98 | 3.90k | false |
99 | | }; |
100 | 29.6k | if is_dcerpc { |
101 | 7.99k | SCLogDebug!("IOCTL response data is_pipe. Calling smb_read_dcerpc_record"); |
102 | 7.99k | let vercmd = SMBVerCmdStat::new2_with_ntstatus(SMB2_COMMAND_IOCTL, r.nt_status); |
103 | 7.99k | SCLogDebug!("TODO passing empty GUID"); |
104 | 7.99k | smb_read_dcerpc_record(state, vercmd, hdr, &[],rd.data); |
105 | 7.99k | } else { |
106 | | SCLogDebug!("SMB2_COMMAND_IOCTL/SMB_NTSTATUS_PENDING looking for {:?}", hdr); |
107 | 21.6k | match state.get_generic_tx(2, SMB2_COMMAND_IOCTL, &hdr) { |
108 | 17.0k | Some(tx) => { |
109 | 17.0k | tx.set_status(r.nt_status, false); |
110 | 17.0k | if r.nt_status != SMB_NTSTATUS_PENDING { |
111 | 16.9k | tx.response_done = true; |
112 | 16.9k | } |
113 | | }, |
114 | 4.57k | None => { }, |
115 | | } |
116 | | } |
117 | | }, |
118 | | _ => { |
119 | | SCLogDebug!("SMB2_COMMAND_IOCTL/SMB_NTSTATUS_PENDING looking for {:?}", hdr); |
120 | 22.0k | match state.get_generic_tx(2, SMB2_COMMAND_IOCTL, &hdr) { |
121 | 14.0k | Some(tx) => { |
122 | 14.0k | SCLogDebug!("updated status of tx {}", tx.id); |
123 | 14.0k | tx.set_status(r.nt_status, false); |
124 | 14.0k | if r.nt_status != SMB_NTSTATUS_PENDING { |
125 | 12.9k | tx.response_done = true; |
126 | 12.9k | } |
127 | | |
128 | | // parsing failed for 'SUCCESS' record, set event |
129 | 14.0k | if r.nt_status == SMB_NTSTATUS_SUCCESS { |
130 | 2.06k | SCLogDebug!("parse fail {:?}", r); |
131 | 2.06k | tx.set_event(SMBEvent::MalformedData); |
132 | 11.9k | } |
133 | | }, |
134 | 7.98k | _ => { }, |
135 | | } |
136 | | }, |
137 | | }; |
138 | 51.6k | } |