]>
Commit | Line | Data |
---|---|---|
74305c04 | 1 | /* Copyright (C) 2017-2020 Open Information Security Foundation |
9b42073e VJ |
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 | // written by Victor Julien | |
19 | ||
42e5065a | 20 | use crate::core::*; |
9b42073e | 21 | |
42e5065a JI |
22 | use crate::nfs::nfs::*; |
23 | use crate::nfs::types::*; | |
24 | use crate::nfs::rpc_records::*; | |
25 | use crate::nfs::nfs3_records::*; | |
9b42073e | 26 | |
acb3ec6d PC |
27 | use nom7::IResult; |
28 | use nom7::number::streaming::be_u32; | |
5b809f77 | 29 | |
9b42073e VJ |
30 | impl NFSState { |
31 | /// complete NFS3 request record | |
66598f9c | 32 | pub fn process_request_record_v3<'b>(&mut self, r: &RpcPacket<'b>) { |
9b42073e VJ |
33 | SCLogDebug!("REQUEST {} procedure {} ({}) blob size {}", |
34 | r.hdr.xid, r.procedure, self.requestmap.len(), r.prog_data.len()); | |
35 | ||
36 | let mut xidmap = NFSRequestXidMap::new(r.progver, r.procedure, 0); | |
37 | let mut aux_file_name = Vec::new(); | |
38 | ||
39 | if self.nfs_version == 0 { | |
40 | self.nfs_version = r.progver as u16; | |
41 | } | |
42 | ||
43 | if r.procedure == NFSPROC3_LOOKUP { | |
44 | self.process_request_record_lookup(r, &mut xidmap); | |
45 | ||
46 | } else if r.procedure == NFSPROC3_ACCESS { | |
6ae66cb2 VJ |
47 | if let Ok((_, rd)) = parse_nfs3_request_access(r.prog_data) { |
48 | xidmap.file_handle = rd.handle.value.to_vec(); | |
49 | self.xidmap_handle2name(&mut xidmap); | |
50 | } else { | |
51 | self.set_event(NFSEvent::MalformedData); | |
9b42073e VJ |
52 | }; |
53 | } else if r.procedure == NFSPROC3_GETATTR { | |
6ae66cb2 VJ |
54 | if let Ok((_, rd)) = parse_nfs3_request_getattr(r.prog_data) { |
55 | xidmap.file_handle = rd.handle.value.to_vec(); | |
56 | self.xidmap_handle2name(&mut xidmap); | |
57 | } else { | |
58 | self.set_event(NFSEvent::MalformedData); | |
9b42073e VJ |
59 | }; |
60 | } else if r.procedure == NFSPROC3_READDIRPLUS { | |
6ae66cb2 VJ |
61 | if let Ok((_, rd)) = parse_nfs3_request_readdirplus(r.prog_data) { |
62 | xidmap.file_handle = rd.handle.value.to_vec(); | |
63 | self.xidmap_handle2name(&mut xidmap); | |
64 | } else { | |
65 | self.set_event(NFSEvent::MalformedData); | |
9b42073e VJ |
66 | }; |
67 | } else if r.procedure == NFSPROC3_READ { | |
6ae66cb2 VJ |
68 | if let Ok((_, rd)) = parse_nfs3_request_read(r.prog_data) { |
69 | xidmap.chunk_offset = rd.offset; | |
70 | xidmap.file_handle = rd.handle.value.to_vec(); | |
71 | self.xidmap_handle2name(&mut xidmap); | |
72 | } else { | |
73 | self.set_event(NFSEvent::MalformedData); | |
9b42073e VJ |
74 | }; |
75 | } else if r.procedure == NFSPROC3_WRITE { | |
6ae66cb2 VJ |
76 | if let Ok((_, rd)) = parse_nfs3_request_write(r.prog_data) { |
77 | self.process_write_record(r, &rd); | |
78 | } else { | |
79 | self.set_event(NFSEvent::MalformedData); | |
9b42073e VJ |
80 | } |
81 | } else if r.procedure == NFSPROC3_CREATE { | |
6ae66cb2 VJ |
82 | if let Ok((_, rd)) = parse_nfs3_request_create(r.prog_data) { |
83 | xidmap.file_handle = rd.handle.value.to_vec(); | |
84 | xidmap.file_name = rd.name_vec; | |
85 | } else { | |
86 | self.set_event(NFSEvent::MalformedData); | |
9b42073e | 87 | }; |
9b42073e | 88 | } else if r.procedure == NFSPROC3_REMOVE { |
6ae66cb2 VJ |
89 | if let Ok((_, rd)) = parse_nfs3_request_remove(r.prog_data) { |
90 | xidmap.file_handle = rd.handle.value.to_vec(); | |
91 | xidmap.file_name = rd.name_vec; | |
92 | } else { | |
93 | self.set_event(NFSEvent::MalformedData); | |
9b42073e | 94 | }; |
9b42073e | 95 | } else if r.procedure == NFSPROC3_RENAME { |
6ae66cb2 VJ |
96 | if let Ok((_, rd)) = parse_nfs3_request_rename(r.prog_data) { |
97 | xidmap.file_handle = rd.from_handle.value.to_vec(); | |
98 | xidmap.file_name = rd.from_name_vec; | |
99 | aux_file_name = rd.to_name_vec; | |
100 | } else { | |
101 | self.set_event(NFSEvent::MalformedData); | |
9b42073e VJ |
102 | }; |
103 | } else if r.procedure == NFSPROC3_MKDIR { | |
6ae66cb2 VJ |
104 | if let Ok((_, rd)) = parse_nfs3_request_mkdir(r.prog_data) { |
105 | xidmap.file_handle = rd.handle.value.to_vec(); | |
106 | xidmap.file_name = rd.name_vec; | |
107 | } else { | |
108 | self.set_event(NFSEvent::MalformedData); | |
9b42073e VJ |
109 | }; |
110 | } else if r.procedure == NFSPROC3_RMDIR { | |
6ae66cb2 VJ |
111 | if let Ok((_, rd)) = parse_nfs3_request_rmdir(r.prog_data) { |
112 | xidmap.file_handle = rd.handle.value.to_vec(); | |
113 | xidmap.file_name = rd.name_vec; | |
114 | } else { | |
115 | self.set_event(NFSEvent::MalformedData); | |
9b42073e VJ |
116 | }; |
117 | } else if r.procedure == NFSPROC3_COMMIT { | |
118 | SCLogDebug!("COMMIT, closing shop"); | |
6ae66cb2 VJ |
119 | if let Ok((_, rd)) = parse_nfs3_request_commit(r.prog_data) { |
120 | let file_handle = rd.handle.value.to_vec(); | |
11c438a0 | 121 | if let Some((tx, files, flags)) = self.get_file_tx_by_handle(&file_handle, Direction::ToServer) { |
6ae66cb2 VJ |
122 | if let Some(NFSTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { |
123 | tdf.chunk_count += 1; | |
124 | tdf.file_additional_procs.push(NFSPROC3_COMMIT); | |
125 | tdf.file_tracker.close(files, flags); | |
126 | tdf.file_last_xid = r.hdr.xid; | |
127 | tx.is_last = true; | |
128 | tx.request_done = true; | |
67759795 | 129 | tx.is_file_closed = true; |
9b42073e | 130 | } |
6ae66cb2 VJ |
131 | } |
132 | } else { | |
133 | self.set_event(NFSEvent::MalformedData); | |
9b42073e VJ |
134 | }; |
135 | } | |
136 | ||
137 | if !(r.procedure == NFSPROC3_COMMIT || // commit handled separately | |
138 | r.procedure == NFSPROC3_WRITE || // write handled in file tx | |
139 | r.procedure == NFSPROC3_READ) // read handled in file tx at reply | |
140 | { | |
141 | let mut tx = self.new_tx(); | |
142 | tx.xid = r.hdr.xid; | |
143 | tx.procedure = r.procedure; | |
144 | tx.request_done = true; | |
145 | tx.file_name = xidmap.file_name.to_vec(); | |
146 | tx.nfs_version = r.progver as u16; | |
147 | tx.file_handle = xidmap.file_handle.to_vec(); | |
148 | ||
149 | if r.procedure == NFSPROC3_RENAME { | |
150 | tx.type_data = Some(NFSTransactionTypeData::RENAME(aux_file_name)); | |
151 | } | |
152 | ||
153 | tx.auth_type = r.creds_flavor; | |
154 | match r.creds { | |
155 | RpcRequestCreds::Unix(ref u) => { | |
156 | tx.request_machine_name = u.machine_name_buf.to_vec(); | |
157 | tx.request_uid = u.uid; | |
158 | tx.request_gid = u.gid; | |
159 | }, | |
160 | _ => { }, | |
161 | } | |
162 | SCLogDebug!("TX created: ID {} XID {} PROCEDURE {}", | |
163 | tx.id, tx.xid, tx.procedure); | |
164 | self.transactions.push(tx); | |
165 | ||
166 | } else if r.procedure == NFSPROC3_READ { | |
167 | ||
11c438a0 | 168 | let found = match self.get_file_tx_by_handle(&xidmap.file_handle, Direction::ToClient) { |
9b42073e VJ |
169 | Some((_, _, _)) => true, |
170 | None => false, | |
171 | }; | |
172 | if !found { | |
11c438a0 | 173 | let (tx, _, _) = self.new_file_tx(&xidmap.file_handle, &xidmap.file_name, Direction::ToClient); |
9b42073e VJ |
174 | tx.procedure = NFSPROC3_READ; |
175 | tx.xid = r.hdr.xid; | |
176 | tx.is_first = true; | |
177 | tx.nfs_version = r.progver as u16; | |
178 | ||
179 | tx.auth_type = r.creds_flavor; | |
6ae66cb2 VJ |
180 | if let RpcRequestCreds::Unix(ref u) = r.creds { |
181 | tx.request_machine_name = u.machine_name_buf.to_vec(); | |
182 | tx.request_uid = u.uid; | |
183 | tx.request_gid = u.gid; | |
9b42073e VJ |
184 | } |
185 | } | |
186 | } | |
187 | ||
188 | self.requestmap.insert(r.hdr.xid, xidmap); | |
9b42073e VJ |
189 | } |
190 | ||
66598f9c | 191 | pub fn process_reply_record_v3<'b>(&mut self, r: &RpcReplyPacket<'b>, xidmap: &mut NFSRequestXidMap) { |
9b42073e VJ |
192 | let mut nfs_status = 0; |
193 | let mut resp_handle = Vec::new(); | |
194 | ||
195 | if xidmap.procedure == NFSPROC3_LOOKUP { | |
6ae66cb2 VJ |
196 | if let Ok((_, rd)) = parse_nfs3_response_lookup(r.prog_data) { |
197 | SCLogDebug!("LOOKUP: {:?}", rd); | |
198 | SCLogDebug!("RESPONSE LOOKUP file_name {:?}", xidmap.file_name); | |
9b42073e | 199 | |
6ae66cb2 | 200 | nfs_status = rd.status; |
9b42073e | 201 | |
6ae66cb2 VJ |
202 | SCLogDebug!("LOOKUP handle {:?}", rd.handle); |
203 | self.namemap.insert(rd.handle.value.to_vec(), xidmap.file_name.to_vec()); | |
204 | resp_handle = rd.handle.value.to_vec(); | |
205 | } else { | |
206 | self.set_event(NFSEvent::MalformedData); | |
9b42073e VJ |
207 | }; |
208 | } else if xidmap.procedure == NFSPROC3_CREATE { | |
6ae66cb2 VJ |
209 | if let Ok((_, rd)) = parse_nfs3_response_create(r.prog_data) { |
210 | SCLogDebug!("nfs3_create_record: {:?}", rd); | |
211 | SCLogDebug!("RESPONSE CREATE file_name {:?}", xidmap.file_name); | |
212 | nfs_status = rd.status; | |
9b42073e | 213 | |
6ae66cb2 VJ |
214 | if let Some(h) = rd.handle { |
215 | SCLogDebug!("handle {:?}", h); | |
216 | self.namemap.insert(h.value.to_vec(), xidmap.file_name.to_vec()); | |
217 | resp_handle = h.value.to_vec(); | |
218 | } | |
219 | } else { | |
220 | self.set_event(NFSEvent::MalformedData); | |
9b42073e VJ |
221 | }; |
222 | } else if xidmap.procedure == NFSPROC3_READ { | |
6ae66cb2 | 223 | if let Ok((_, rd)) = parse_nfs3_reply_read(r.prog_data) { |
69cf5c9e | 224 | self.process_read_record(r, &rd, Some(xidmap)); |
6ae66cb2 VJ |
225 | nfs_status = rd.status; |
226 | } else { | |
227 | self.set_event(NFSEvent::MalformedData); | |
9b42073e VJ |
228 | } |
229 | } else if xidmap.procedure == NFSPROC3_READDIRPLUS { | |
6ae66cb2 VJ |
230 | if let Ok((_, rd)) = parse_nfs3_response_readdirplus(r.prog_data) { |
231 | nfs_status = rd.status; | |
9b42073e | 232 | |
6ae66cb2 VJ |
233 | // cut off final eof field |
234 | let d = if rd.data.len() >= 4 { | |
235 | &rd.data[..rd.data.len()-4 as usize] | |
236 | } else { | |
237 | rd.data | |
238 | }; | |
9b42073e | 239 | |
6ae66cb2 VJ |
240 | // store all handle/filename mappings |
241 | if let Ok((_, ref entries)) = many0_nfs3_response_readdirplus_entries(d) { | |
242 | SCLogDebug!("READDIRPLUS ENTRIES reply {:?}", entries); | |
243 | for ce in entries { | |
244 | SCLogDebug!("ce {:?}", ce); | |
245 | if let Some(ref e) = ce.entry { | |
246 | SCLogDebug!("e {:?}", e); | |
247 | if let Some(ref h) = e.handle { | |
248 | SCLogDebug!("h {:?}", h); | |
249 | self.namemap.insert(h.value.to_vec(), | |
250 | e.name_vec.to_vec()); | |
9b42073e | 251 | } |
6ae66cb2 | 252 | } |
9b42073e | 253 | } |
6ae66cb2 | 254 | } else { |
9b42073e | 255 | self.set_event(NFSEvent::MalformedData); |
6ae66cb2 VJ |
256 | } |
257 | } else { | |
258 | self.set_event(NFSEvent::MalformedData); | |
9b42073e VJ |
259 | } |
260 | } | |
261 | // for all other record types only parse the status | |
262 | else { | |
69cf5c9e | 263 | let stat : u32 = match be_u32(r.prog_data) as IResult<&[u8],_> { |
6ae66cb2 VJ |
264 | Ok((_, stat)) => stat, |
265 | _ => 0 | |
9b42073e VJ |
266 | }; |
267 | nfs_status = stat; | |
268 | } | |
269 | SCLogDebug!("REPLY {} to procedure {} blob size {}", | |
270 | r.hdr.xid, xidmap.procedure, r.prog_data.len()); | |
271 | ||
272 | if xidmap.procedure != NFSPROC3_READ { | |
273 | self.mark_response_tx_done(r.hdr.xid, r.reply_state, nfs_status, &resp_handle); | |
274 | } | |
9b42073e | 275 | } |
9b42073e | 276 | } |