/src/suricata7/src/util-file.c
Line | Count | Source |
1 | | /* Copyright (C) 2007-2020 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 | | /** |
19 | | * \file |
20 | | * |
21 | | * \author Victor Julien <victor@inliniac.net> |
22 | | * \author Pablo Rincon <pablo.rincon.crespo@gmail.com> |
23 | | * |
24 | | */ |
25 | | |
26 | | #include "suricata-common.h" |
27 | | #include "suricata.h" |
28 | | #include "flow.h" |
29 | | #include "stream.h" |
30 | | #include "stream-tcp.h" |
31 | | #include "runmodes.h" |
32 | | #include "util-hash.h" |
33 | | #include "util-debug.h" |
34 | | #include "util-memcmp.h" |
35 | | #include "util-print.h" |
36 | | #include "app-layer-parser.h" |
37 | | #include "util-validate.h" |
38 | | #include "rust.h" |
39 | | |
40 | | extern int g_detect_disabled; |
41 | | |
42 | | /** \brief mask of file flags we'll not set |
43 | | * This mask is set based on global file settings and |
44 | | * cannot be overridden by detection. |
45 | | */ |
46 | | static uint16_t g_file_flow_mask = 0; |
47 | | |
48 | | /** \brief switch to force filestore on all files |
49 | | * regardless of the rules. |
50 | | */ |
51 | | static int g_file_force_filestore = 0; |
52 | | |
53 | | /** \brief switch to force magic checks on all files |
54 | | * regardless of the rules. |
55 | | */ |
56 | | static int g_file_force_magic = 0; |
57 | | |
58 | | /** \brief switch to force md5 calculation on all files |
59 | | * regardless of the rules. |
60 | | */ |
61 | | static int g_file_force_md5 = 0; |
62 | | |
63 | | /** \brief switch to force sha1 calculation on all files |
64 | | * regardless of the rules. |
65 | | */ |
66 | | static int g_file_force_sha1 = 0; |
67 | | |
68 | | /** \brief switch to force sha256 calculation on all files |
69 | | * regardless of the rules. |
70 | | */ |
71 | | static int g_file_force_sha256 = 0; |
72 | | |
73 | | /** \brief switch to force tracking off all files |
74 | | * regardless of the rules. |
75 | | */ |
76 | | static int g_file_force_tracking = 0; |
77 | | |
78 | | /** \brief switch to use g_file_store_reassembly_depth |
79 | | * to reassembly files |
80 | | */ |
81 | | static int g_file_store_enable = 0; |
82 | | |
83 | | /** \brief stream_config.reassembly_depth equivalent |
84 | | * for files |
85 | | */ |
86 | | static uint32_t g_file_store_reassembly_depth = 0; |
87 | | |
88 | | /* prototypes */ |
89 | | static void FileFree(File *, const StreamingBufferConfig *cfg); |
90 | | static void FileEndSha256(File *ff); |
91 | | |
92 | | void FileForceFilestoreEnable(void) |
93 | 4 | { |
94 | 4 | g_file_force_filestore = 1; |
95 | 4 | g_file_flow_mask |= (FLOWFILE_NO_STORE_TS|FLOWFILE_NO_STORE_TC); |
96 | 4 | } |
97 | | |
98 | | void FileForceMagicEnable(void) |
99 | 0 | { |
100 | 0 | g_file_force_magic = 1; |
101 | 0 | g_file_flow_mask |= (FLOWFILE_NO_MAGIC_TS|FLOWFILE_NO_MAGIC_TC); |
102 | 0 | } |
103 | | |
104 | | void FileForceMd5Enable(void) |
105 | 0 | { |
106 | 0 | g_file_force_md5 = 1; |
107 | 0 | g_file_flow_mask |= (FLOWFILE_NO_MD5_TS|FLOWFILE_NO_MD5_TC); |
108 | 0 | } |
109 | | |
110 | | void FileForceSha1Enable(void) |
111 | 0 | { |
112 | 0 | g_file_force_sha1 = 1; |
113 | 0 | g_file_flow_mask |= (FLOWFILE_NO_SHA1_TS|FLOWFILE_NO_SHA1_TC); |
114 | 0 | } |
115 | | |
116 | | void FileForceSha256Enable(void) |
117 | 4 | { |
118 | 4 | g_file_force_sha256 = 1; |
119 | 4 | g_file_flow_mask |= (FLOWFILE_NO_SHA256_TS|FLOWFILE_NO_SHA256_TC); |
120 | 4 | } |
121 | | |
122 | | int FileForceFilestore(void) |
123 | 0 | { |
124 | 0 | return g_file_force_filestore; |
125 | 0 | } |
126 | | |
127 | | void FileReassemblyDepthEnable(uint32_t size) |
128 | 0 | { |
129 | 0 | g_file_store_enable = 1; |
130 | 0 | g_file_store_reassembly_depth = size; |
131 | 0 | } |
132 | | |
133 | | uint32_t FileReassemblyDepth(void) |
134 | 5.21M | { |
135 | 5.21M | if (g_file_store_enable == 1) |
136 | 0 | return g_file_store_reassembly_depth; |
137 | 5.21M | else |
138 | 5.21M | return stream_config.reassembly_depth; |
139 | 5.21M | } |
140 | | |
141 | | int FileForceMagic(void) |
142 | 0 | { |
143 | 0 | return g_file_force_magic; |
144 | 0 | } |
145 | | |
146 | | int FileForceMd5(void) |
147 | 0 | { |
148 | 0 | return g_file_force_md5; |
149 | 0 | } |
150 | | |
151 | | int FileForceSha1(void) |
152 | 0 | { |
153 | 0 | return g_file_force_sha1; |
154 | 0 | } |
155 | | |
156 | | int FileForceSha256(void) |
157 | 0 | { |
158 | 0 | return g_file_force_sha256; |
159 | 0 | } |
160 | | |
161 | | void FileForceTrackingEnable(void) |
162 | 4 | { |
163 | 4 | g_file_force_tracking = 1; |
164 | 4 | g_file_flow_mask |= (FLOWFILE_NO_SIZE_TS|FLOWFILE_NO_SIZE_TC); |
165 | 4 | } |
166 | | |
167 | | /** |
168 | | * \brief Function to parse forced file hashing configuration. |
169 | | */ |
170 | | void FileForceHashParseCfg(ConfNode *conf) |
171 | 2 | { |
172 | 2 | BUG_ON(conf == NULL); |
173 | | |
174 | 2 | ConfNode *forcehash_node = NULL; |
175 | | |
176 | | /* legacy option */ |
177 | 2 | const char *force_md5 = ConfNodeLookupChildValue(conf, "force-md5"); |
178 | 2 | if (force_md5 != NULL) { |
179 | 0 | SCLogWarning("deprecated 'force-md5' option " |
180 | 0 | "found. Please use 'force-hash: [md5]' instead"); |
181 | |
|
182 | 0 | if (ConfValIsTrue(force_md5)) { |
183 | 0 | if (g_disable_hashing) { |
184 | 0 | SCLogInfo( |
185 | 0 | "not forcing md5 calculation for logged files: hashing globally disabled"); |
186 | 0 | } else { |
187 | 0 | FileForceMd5Enable(); |
188 | 0 | SCLogInfo("forcing md5 calculation for logged files"); |
189 | 0 | } |
190 | 0 | } |
191 | 0 | } |
192 | | |
193 | 2 | if (conf != NULL) |
194 | 2 | forcehash_node = ConfNodeLookupChild(conf, "force-hash"); |
195 | | |
196 | 2 | if (forcehash_node != NULL) { |
197 | 0 | ConfNode *field = NULL; |
198 | |
|
199 | 0 | TAILQ_FOREACH(field, &forcehash_node->head, next) { |
200 | 0 | if (strcasecmp("md5", field->val) == 0) { |
201 | 0 | if (g_disable_hashing) { |
202 | 0 | SCLogInfo("not forcing md5 calculation for logged files: hashing globally " |
203 | 0 | "disabled"); |
204 | 0 | } else { |
205 | 0 | FileForceMd5Enable(); |
206 | 0 | SCLogConfig("forcing md5 calculation for logged or stored files"); |
207 | 0 | } |
208 | 0 | } |
209 | |
|
210 | 0 | if (strcasecmp("sha1", field->val) == 0) { |
211 | 0 | if (g_disable_hashing) { |
212 | 0 | SCLogInfo("not forcing sha1 calculation for logged files: hashing globally " |
213 | 0 | "disabled"); |
214 | 0 | } else { |
215 | 0 | FileForceSha1Enable(); |
216 | 0 | SCLogConfig("forcing sha1 calculation for logged or stored files"); |
217 | 0 | } |
218 | 0 | } |
219 | |
|
220 | 0 | if (strcasecmp("sha256", field->val) == 0) { |
221 | 0 | if (g_disable_hashing) { |
222 | 0 | SCLogInfo("not forcing sha256 calculation for logged files: hashing globally " |
223 | 0 | "disabled"); |
224 | 0 | } else { |
225 | 0 | FileForceSha256Enable(); |
226 | 0 | SCLogConfig("forcing sha256 calculation for logged or stored files"); |
227 | 0 | } |
228 | 0 | } |
229 | 0 | } |
230 | 0 | } |
231 | 2 | } |
232 | | |
233 | | uint16_t FileFlowFlagsToFlags(const uint16_t flow_file_flags, uint8_t direction) |
234 | 8.96M | { |
235 | 8.96M | uint16_t flags = 0; |
236 | | |
237 | 8.96M | if (direction == STREAM_TOSERVER) { |
238 | 6.42M | if ((flow_file_flags & (FLOWFILE_NO_STORE_TS | FLOWFILE_STORE_TS)) == |
239 | 6.42M | FLOWFILE_NO_STORE_TS) { |
240 | 0 | flags |= FILE_NOSTORE; |
241 | 6.42M | } else if (flow_file_flags & FLOWFILE_STORE_TS) { |
242 | 0 | flags |= FILE_STORE; |
243 | 0 | } |
244 | | |
245 | 6.42M | if (flow_file_flags & FLOWFILE_NO_MAGIC_TS) { |
246 | 159k | flags |= FILE_NOMAGIC; |
247 | 159k | } |
248 | | |
249 | 6.42M | if (flow_file_flags & FLOWFILE_NO_MD5_TS) { |
250 | 368k | flags |= FILE_NOMD5; |
251 | 368k | } |
252 | | |
253 | 6.42M | if (flow_file_flags & FLOWFILE_NO_SHA1_TS) { |
254 | 368k | flags |= FILE_NOSHA1; |
255 | 368k | } |
256 | | |
257 | 6.42M | if (flow_file_flags & FLOWFILE_NO_SHA256_TS) { |
258 | 0 | flags |= FILE_NOSHA256; |
259 | 0 | } |
260 | 6.42M | } else { |
261 | 2.53M | if ((flow_file_flags & (FLOWFILE_NO_STORE_TC | FLOWFILE_STORE_TC)) == |
262 | 2.53M | FLOWFILE_NO_STORE_TC) { |
263 | 0 | flags |= FILE_NOSTORE; |
264 | 2.53M | } else if (flow_file_flags & FLOWFILE_STORE_TC) { |
265 | 0 | flags |= FILE_STORE; |
266 | 0 | } |
267 | | |
268 | 2.53M | if (flow_file_flags & FLOWFILE_NO_MAGIC_TC) { |
269 | 370k | flags |= FILE_NOMAGIC; |
270 | 370k | } |
271 | | |
272 | 2.53M | if (flow_file_flags & FLOWFILE_NO_MD5_TC) { |
273 | 787k | flags |= FILE_NOMD5; |
274 | 787k | } |
275 | | |
276 | 2.53M | if (flow_file_flags & FLOWFILE_NO_SHA1_TC) { |
277 | 787k | flags |= FILE_NOSHA1; |
278 | 787k | } |
279 | | |
280 | 2.53M | if (flow_file_flags & FLOWFILE_NO_SHA256_TC) { |
281 | 0 | flags |= FILE_NOSHA256; |
282 | 0 | } |
283 | 2.53M | } |
284 | 8.96M | DEBUG_VALIDATE_BUG_ON((flags & (FILE_STORE | FILE_NOSTORE)) == (FILE_STORE | FILE_NOSTORE)); |
285 | | |
286 | 8.96M | SCLogDebug("direction %02x flags %02x", direction, flags); |
287 | 8.96M | return flags; |
288 | 8.96M | } |
289 | | |
290 | | uint16_t FileFlowToFlags(const Flow *flow, uint8_t direction) |
291 | 26.4M | { |
292 | 26.4M | return FileFlowFlagsToFlags(flow->file_flags, direction); |
293 | 26.4M | } |
294 | | |
295 | | void FileApplyTxFlags(const AppLayerTxData *txd, const uint8_t direction, File *file) |
296 | 4.44M | { |
297 | 4.44M | SCLogDebug("file flags %04x STORE %s NOSTORE %s", file->flags, |
298 | 4.44M | (file->flags & FILE_STORE) ? "true" : "false", |
299 | 4.44M | (file->flags & FILE_NOSTORE) ? "true" : "false"); |
300 | 4.44M | uint16_t update_flags = FileFlowFlagsToFlags(txd->file_flags, direction); |
301 | 4.44M | DEBUG_VALIDATE_BUG_ON( |
302 | 4.44M | (file->flags & (FILE_STORE | FILE_NOSTORE)) == (FILE_STORE | FILE_NOSTORE)); |
303 | 4.44M | if (file->flags & FILE_STORE) |
304 | 4.44M | update_flags &= ~FILE_NOSTORE; |
305 | | |
306 | 4.44M | file->flags |= update_flags; |
307 | 4.44M | SCLogDebug("file flags %04x STORE %s NOSTORE %s", file->flags, |
308 | 4.44M | (file->flags & FILE_STORE) ? "true" : "false", |
309 | 4.44M | (file->flags & FILE_NOSTORE) ? "true" : "false"); |
310 | 4.44M | DEBUG_VALIDATE_BUG_ON( |
311 | 4.44M | (file->flags & (FILE_STORE | FILE_NOSTORE)) == (FILE_STORE | FILE_NOSTORE)); |
312 | 4.44M | } |
313 | | |
314 | | static int FileMagicSize(void) |
315 | 0 | { |
316 | | /** \todo make this size configurable */ |
317 | 0 | return 512; |
318 | 0 | } |
319 | | |
320 | | /** |
321 | | * \brief get the size of the file data |
322 | | * |
323 | | * This doesn't reflect how much of the file we have in memory, just the |
324 | | * total size of filedata so far. |
325 | | */ |
326 | | uint64_t FileDataSize(const File *file) |
327 | 80.8M | { |
328 | 80.8M | if (file != NULL && file->sb != NULL) { |
329 | 80.8M | const uint64_t size = StreamingBufferGetConsecutiveDataRightEdge(file->sb); |
330 | 80.8M | SCLogDebug("returning %" PRIu64, size); |
331 | 80.8M | return size; |
332 | 80.8M | } |
333 | 0 | SCLogDebug("returning 0 (default)"); |
334 | 0 | return 0; |
335 | 80.8M | } |
336 | | |
337 | | /** |
338 | | * \brief get the size of the file |
339 | | * |
340 | | * This doesn't reflect how much of the file we have in memory, just the |
341 | | * total size of file so far. |
342 | | */ |
343 | | uint64_t FileTrackedSize(const File *file) |
344 | 222k | { |
345 | 222k | if (file != NULL) { |
346 | 222k | return file->size; |
347 | 222k | } |
348 | 0 | return 0; |
349 | 222k | } |
350 | | |
351 | | /** \brief test if file is ready to be pruned |
352 | | * |
353 | | * If a file is in the 'CLOSED' state, it means it has been processed |
354 | | * completely by the pipeline in the correct direction. So we can |
355 | | * prune it then. |
356 | | * |
357 | | * For other states, as well as for files we may not need to track |
358 | | * until the close state, more specific checks are done. |
359 | | * |
360 | | * Also does house keeping within the file: move streaming buffer |
361 | | * forward if possible. |
362 | | * |
363 | | * \retval 1 prune (free) this file |
364 | | * \retval 0 file not ready to be freed |
365 | | */ |
366 | | static int FilePruneFile(File *file, const StreamingBufferConfig *cfg) |
367 | 40.3M | { |
368 | 40.3M | SCEnter(); |
369 | | |
370 | | /* file is done when state is closed+, logging/storing is done (if any) */ |
371 | 40.3M | SCLogDebug("file->state %d. Is >= FILE_STATE_CLOSED: %s", |
372 | 40.3M | file->state, (file->state >= FILE_STATE_CLOSED) ? "yes" : "no"); |
373 | 40.3M | if (file->state >= FILE_STATE_CLOSED) { |
374 | 1.10M | SCReturnInt(1); |
375 | 1.10M | } |
376 | | |
377 | | #ifdef HAVE_MAGIC |
378 | | if (!(file->flags & FILE_NOMAGIC)) { |
379 | | /* need magic but haven't set it yet, bail out */ |
380 | | if (file->magic == NULL) |
381 | | SCReturnInt(0); |
382 | | else |
383 | | SCLogDebug("file->magic %s", file->magic); |
384 | | } else { |
385 | | SCLogDebug("file->flags & FILE_NOMAGIC == true"); |
386 | | } |
387 | | #endif |
388 | 39.2M | uint64_t left_edge = FileDataSize(file); |
389 | 39.2M | if (file->flags & FILE_STORE) { |
390 | 1.86M | left_edge = MIN(left_edge,file->content_stored); |
391 | 1.86M | } |
392 | | |
393 | 39.2M | if (!g_detect_disabled) { |
394 | 39.2M | left_edge = MIN(left_edge, file->content_inspected); |
395 | | /* if file has inspect window and min size set, we |
396 | | * do some house keeping here */ |
397 | 39.2M | if (file->inspect_window != 0 && file->inspect_min_size != 0) { |
398 | 39.2M | const uint64_t file_offset = StreamingBufferGetOffset(file->sb); |
399 | 39.2M | uint32_t window = file->inspect_window; |
400 | 39.2M | if (file_offset == 0) |
401 | 39.0M | window = MAX(window, file->inspect_min_size); |
402 | | |
403 | 39.2M | uint64_t file_size = FileDataSize(file); |
404 | 39.2M | uint64_t data_size = file_size - file_offset; |
405 | | |
406 | 39.2M | SCLogDebug("window %"PRIu32", file_size %"PRIu64", data_size %"PRIu64, |
407 | 39.2M | window, file_size, data_size); |
408 | | |
409 | 39.2M | if (data_size > (window * 3)) { |
410 | 30.1k | file->content_inspected = MAX(file->content_inspected, file->size - window); |
411 | 30.1k | SCLogDebug("file->content_inspected now %" PRIu64, file->content_inspected); |
412 | 30.1k | } |
413 | | |
414 | 39.2M | if (left_edge > window) |
415 | 209k | left_edge -= window; |
416 | 39.0M | else |
417 | 39.0M | left_edge = 0; |
418 | 39.2M | } |
419 | 39.2M | } |
420 | | |
421 | 39.2M | if (left_edge) { |
422 | 209k | SCLogDebug("sliding to %" PRIu64, left_edge); |
423 | 209k | StreamingBufferSlideToOffset(file->sb, cfg, left_edge); |
424 | 209k | } |
425 | | |
426 | 39.2M | SCReturnInt(0); |
427 | 40.3M | } |
428 | | |
429 | | #ifdef DEBUG |
430 | | #define P(file, flag) ((file)->flags & (flag)) ? "true" : "false" |
431 | | void FilePrintFlags(const File *file) |
432 | | { |
433 | | SCLogDebug("file %p flags %04x " |
434 | | "FILE_TRUNCATED %s " |
435 | | "FILE_NOMAGIC %s " |
436 | | "FILE_NOMD5 %s " |
437 | | "FILE_MD5 %s " |
438 | | "FILE_NOSHA1 %s " |
439 | | "FILE_SHA1 %s " |
440 | | "FILE_NOSHA256 %s " |
441 | | "FILE_SHA256 %s " |
442 | | "FILE_LOGGED %s " |
443 | | "FILE_NOSTORE %s " |
444 | | "FILE_STORE %s " |
445 | | "FILE_STORED %s " |
446 | | "FILE_NOTRACK %s " |
447 | | "FILE_HAS_GAPS %s", |
448 | | file, file->flags, P(file, FILE_TRUNCATED), P(file, FILE_NOMAGIC), P(file, FILE_NOMD5), |
449 | | P(file, FILE_MD5), P(file, FILE_NOSHA1), P(file, FILE_SHA1), P(file, FILE_NOSHA256), |
450 | | P(file, FILE_SHA256), P(file, FILE_LOGGED), P(file, FILE_NOSTORE), P(file, FILE_STORE), |
451 | | P(file, FILE_STORED), P(file, FILE_NOTRACK), P(file, FILE_HAS_GAPS)); |
452 | | } |
453 | | #undef P |
454 | | #endif |
455 | | |
456 | | static void FilePrune(FileContainer *ffc, const StreamingBufferConfig *cfg) |
457 | 111M | { |
458 | 111M | SCEnter(); |
459 | 111M | SCLogDebug("ffc %p head %p", ffc, ffc->head); |
460 | 111M | File *file = ffc->head; |
461 | 111M | File *prev = NULL; |
462 | | |
463 | 152M | while (file) { |
464 | | #ifdef DEBUG |
465 | | FilePrintFlags(file); |
466 | | #endif |
467 | 40.3M | if (FilePruneFile(file, cfg) == 0) { |
468 | 39.2M | prev = file; |
469 | 39.2M | file = file->next; |
470 | 39.2M | continue; |
471 | 39.2M | } |
472 | | |
473 | 1.10M | SCLogDebug("removing file %p", file); |
474 | | |
475 | 1.10M | File *file_next = file->next; |
476 | | |
477 | 1.10M | if (prev) |
478 | 1.60k | prev->next = file_next; |
479 | | /* update head and tail */ |
480 | 1.10M | if (file == ffc->head) |
481 | 1.10M | ffc->head = file_next; |
482 | 1.10M | if (file == ffc->tail) |
483 | 824k | ffc->tail = prev; |
484 | | |
485 | 1.10M | FileFree(file, cfg); |
486 | 1.10M | file = file_next; |
487 | 1.10M | } |
488 | 111M | SCReturn; |
489 | 111M | } |
490 | | |
491 | | /** |
492 | | * \brief allocate a FileContainer |
493 | | * |
494 | | * \retval new newly allocated FileContainer |
495 | | * \retval NULL error |
496 | | */ |
497 | | FileContainer *FileContainerAlloc(void) |
498 | 8.10k | { |
499 | 8.10k | FileContainer *new = SCMalloc(sizeof(FileContainer)); |
500 | 8.10k | if (unlikely(new == NULL)) { |
501 | 0 | SCLogError("Error allocating mem"); |
502 | 0 | return NULL; |
503 | 0 | } |
504 | 8.10k | memset(new, 0, sizeof(FileContainer)); |
505 | 8.10k | new->head = new->tail = NULL; |
506 | 8.10k | return new; |
507 | 8.10k | } |
508 | | |
509 | | /** |
510 | | * \brief Recycle a FileContainer |
511 | | * |
512 | | * \param ffc FileContainer |
513 | | */ |
514 | | void FileContainerRecycle(FileContainer *ffc, const StreamingBufferConfig *cfg) |
515 | 8.46M | { |
516 | 8.46M | SCLogDebug("ffc %p", ffc); |
517 | 8.46M | if (ffc == NULL) |
518 | 0 | return; |
519 | | |
520 | 8.46M | File *cur = ffc->head; |
521 | 8.46M | File *next = NULL; |
522 | 8.73M | for (;cur != NULL; cur = next) { |
523 | 274k | next = cur->next; |
524 | 274k | FileFree(cur, cfg); |
525 | 274k | } |
526 | 8.46M | ffc->head = ffc->tail = NULL; |
527 | 8.46M | } |
528 | | |
529 | | /** |
530 | | * \brief Free a FileContainer |
531 | | * |
532 | | * \param ffc FileContainer |
533 | | */ |
534 | | void FileContainerFree(FileContainer *ffc, const StreamingBufferConfig *cfg) |
535 | 5.80k | { |
536 | 5.80k | SCLogDebug("ffc %p", ffc); |
537 | 5.80k | if (ffc == NULL) |
538 | 67 | return; |
539 | | |
540 | 5.74k | File *ptr = ffc->head; |
541 | 5.74k | File *next = NULL; |
542 | 5.84k | for (;ptr != NULL; ptr = next) { |
543 | 105 | next = ptr->next; |
544 | 105 | FileFree(ptr, cfg); |
545 | 105 | } |
546 | 5.74k | ffc->head = ffc->tail = NULL; |
547 | 5.74k | SCFree(ffc); |
548 | 5.74k | } |
549 | | |
550 | | /** |
551 | | * \brief Alloc a new File |
552 | | * |
553 | | * \param name character array containing the name (not a string) |
554 | | * \param name_len length in bytes of the name |
555 | | * |
556 | | * \retval new File object or NULL on error |
557 | | */ |
558 | | static File *FileAlloc(const uint8_t *name, uint16_t name_len) |
559 | 1.38M | { |
560 | 1.38M | File *new = SCMalloc(sizeof(File)); |
561 | 1.38M | if (unlikely(new == NULL)) { |
562 | 0 | SCLogError("Error allocating mem"); |
563 | 0 | return NULL; |
564 | 0 | } |
565 | 1.38M | memset(new, 0, sizeof(File)); |
566 | | |
567 | 1.38M | new->name = SCMalloc(name_len); |
568 | 1.38M | if (new->name == NULL) { |
569 | 0 | SCFree(new); |
570 | 0 | return NULL; |
571 | 0 | } |
572 | | |
573 | 1.38M | new->name_len = name_len; |
574 | 1.38M | memcpy(new->name, name, name_len); |
575 | | |
576 | 1.38M | new->sid_cnt = 0; |
577 | 1.38M | new->sid_max = 8; |
578 | | /* SCMalloc() is allowed to fail here because sid well be checked later on */ |
579 | 1.38M | new->sid = SCMalloc(sizeof(uint32_t) * new->sid_max); |
580 | 1.38M | if (new->sid == NULL) |
581 | 0 | new->sid_max = 0; |
582 | | |
583 | 1.38M | return new; |
584 | 1.38M | } |
585 | | |
586 | | static void FileFree(File *ff, const StreamingBufferConfig *sbcfg) |
587 | 1.37M | { |
588 | 1.37M | SCLogDebug("ff %p", ff); |
589 | 1.37M | if (ff == NULL) |
590 | 0 | return; |
591 | | |
592 | 1.37M | if (ff->name != NULL) |
593 | 1.37M | SCFree(ff->name); |
594 | 1.37M | if (ff->sid != NULL) |
595 | 1.37M | SCFree(ff->sid); |
596 | | #ifdef HAVE_MAGIC |
597 | | /* magic returned by libmagic is strdup'd by MagicLookup. */ |
598 | | if (ff->magic != NULL) |
599 | | SCFree(ff->magic); |
600 | | #endif |
601 | 1.37M | if (ff->sb != NULL) { |
602 | 1.37M | StreamingBufferFree(ff->sb, sbcfg); |
603 | 1.37M | } |
604 | | |
605 | 1.37M | if (ff->md5_ctx) |
606 | 195k | SCMd5Free(ff->md5_ctx); |
607 | 1.37M | if (ff->sha1_ctx) |
608 | 195k | SCSha1Free(ff->sha1_ctx); |
609 | 1.37M | if (ff->sha256_ctx) |
610 | 209k | SCSha256Free(ff->sha256_ctx); |
611 | 1.37M | SCFree(ff); |
612 | 1.37M | } |
613 | | |
614 | | void FileContainerAdd(FileContainer *ffc, File *ff) |
615 | 1.38M | { |
616 | 1.38M | SCLogDebug("ffc %p ff %p", ffc, ff); |
617 | 1.38M | if (ffc->head == NULL || ffc->tail == NULL) { |
618 | 1.09M | ffc->head = ffc->tail = ff; |
619 | 1.09M | } else { |
620 | 290k | ffc->tail->next = ff; |
621 | 290k | ffc->tail = ff; |
622 | 290k | } |
623 | 1.38M | } |
624 | | |
625 | | /** |
626 | | * \brief Tag a file for storing |
627 | | * |
628 | | * \param ff The file to store |
629 | | */ |
630 | | int FileStore(File *ff) |
631 | 220k | { |
632 | 220k | SCLogDebug("ff %p", ff); |
633 | 220k | ff->flags |= FILE_STORE; |
634 | 220k | SCReturnInt(0); |
635 | 220k | } |
636 | | |
637 | | /** |
638 | | * \brief check if we have stored enough |
639 | | * |
640 | | * \param ff file |
641 | | * |
642 | | * \retval 0 limit not reached yet |
643 | | * \retval 1 limit reached |
644 | | */ |
645 | | static int FileStoreNoStoreCheck(File *ff) |
646 | 0 | { |
647 | 0 | SCEnter(); |
648 | |
|
649 | 0 | if (ff == NULL) { |
650 | 0 | SCReturnInt(0); |
651 | 0 | } |
652 | | |
653 | 0 | if (ff->flags & FILE_NOSTORE) { |
654 | 0 | if (ff->state == FILE_STATE_OPENED && |
655 | 0 | FileDataSize(ff) >= (uint64_t)FileMagicSize()) |
656 | 0 | { |
657 | 0 | SCReturnInt(1); |
658 | 0 | } |
659 | 0 | } |
660 | | |
661 | 0 | SCReturnInt(0); |
662 | 0 | } |
663 | | |
664 | | static int AppendData( |
665 | | const StreamingBufferConfig *sbcfg, File *file, const uint8_t *data, uint32_t data_len) |
666 | 3.67M | { |
667 | 3.67M | SCLogDebug("file %p data_len %u", file, data_len); |
668 | 3.67M | if (StreamingBufferAppendNoTrack(file->sb, sbcfg, data, data_len) != 0) { |
669 | 0 | SCLogDebug("file %p StreamingBufferAppendNoTrack failed", file); |
670 | 0 | SCReturnInt(-1); |
671 | 0 | } |
672 | | |
673 | 3.67M | if (file->md5_ctx) { |
674 | 3.23M | SCMd5Update(file->md5_ctx, data, data_len); |
675 | 3.23M | } |
676 | 3.67M | if (file->sha1_ctx) { |
677 | 3.23M | SCSha1Update(file->sha1_ctx, data, data_len); |
678 | 3.23M | } |
679 | 3.67M | if (file->sha256_ctx) { |
680 | 3.67M | SCLogDebug("SHA256 file %p data %p data_len %u", file, data, data_len); |
681 | 3.67M | SCSha256Update(file->sha256_ctx, data, data_len); |
682 | 3.67M | } else { |
683 | 0 | SCLogDebug("NO SHA256 file %p data %p data_len %u", file, data, data_len); |
684 | 0 | } |
685 | 3.67M | SCReturnInt(0); |
686 | 3.67M | } |
687 | | |
688 | | /** \internal |
689 | | * \brief Flags a file as having gaps |
690 | | * |
691 | | * \param ff the file |
692 | | */ |
693 | 1.52k | static void FileFlagGap(File *ff) { |
694 | 1.52k | ff->flags |= FILE_HAS_GAPS; |
695 | 1.52k | ff->flags |= (FILE_NOMD5|FILE_NOSHA1|FILE_NOSHA256); |
696 | 1.52k | ff->flags &= ~(FILE_MD5|FILE_SHA1|FILE_SHA256); |
697 | 1.52k | } |
698 | | |
699 | | /** \internal |
700 | | * \brief Store/handle a chunk of file data in the File structure |
701 | | * |
702 | | * \param ff the file |
703 | | * \param data data chunk |
704 | | * \param data_len data chunk len |
705 | | * |
706 | | * \retval 0 ok |
707 | | * \retval -1 error |
708 | | * \retval -2 no store for this file |
709 | | */ |
710 | | static int FileAppendDataDo( |
711 | | const StreamingBufferConfig *sbcfg, File *ff, const uint8_t *data, uint32_t data_len) |
712 | 22.2M | { |
713 | 22.2M | SCEnter(); |
714 | 22.2M | #ifdef DEBUG_VALIDATION |
715 | 22.2M | BUG_ON(ff == NULL); |
716 | 22.2M | #endif |
717 | | |
718 | 22.2M | ff->size += data_len; |
719 | 22.2M | if (data == NULL) { |
720 | 818 | FileFlagGap(ff); |
721 | 818 | SCReturnInt(0); |
722 | 818 | } |
723 | | |
724 | 22.2M | if (ff->state != FILE_STATE_OPENED) { |
725 | 1.09k | if (ff->flags & FILE_NOSTORE) { |
726 | 0 | SCReturnInt(-2); |
727 | 0 | } |
728 | 1.09k | SCReturnInt(-1); |
729 | 1.09k | } |
730 | | |
731 | 22.2M | if (g_detect_disabled && FileStoreNoStoreCheck(ff) == 1) { |
732 | 0 | int hash_done = 0; |
733 | | /* no storage but forced hashing */ |
734 | 0 | if (ff->md5_ctx) { |
735 | 0 | SCMd5Update(ff->md5_ctx, data, data_len); |
736 | 0 | hash_done = 1; |
737 | 0 | } |
738 | 0 | if (ff->sha1_ctx) { |
739 | 0 | SCSha1Update(ff->sha1_ctx, data, data_len); |
740 | 0 | hash_done = 1; |
741 | 0 | } |
742 | 0 | if (ff->sha256_ctx) { |
743 | 0 | SCLogDebug("file %p data %p data_len %u", ff, data, data_len); |
744 | 0 | SCSha256Update(ff->sha256_ctx, data, data_len); |
745 | 0 | hash_done = 1; |
746 | 0 | } |
747 | |
|
748 | 0 | if (hash_done) |
749 | 0 | SCReturnInt(0); |
750 | | |
751 | 0 | if (g_file_force_tracking || (!(ff->flags & FILE_NOTRACK))) |
752 | 0 | SCReturnInt(0); |
753 | | |
754 | 0 | ff->state = FILE_STATE_TRUNCATED; |
755 | 0 | SCLogDebug("flowfile state transitioned to FILE_STATE_TRUNCATED"); |
756 | 0 | SCReturnInt(-2); |
757 | 0 | } |
758 | | |
759 | 22.2M | SCLogDebug("appending %"PRIu32" bytes", data_len); |
760 | | |
761 | 22.2M | int r = AppendData(sbcfg, ff, data, data_len); |
762 | 22.2M | if (r != 0) { |
763 | 0 | ff->state = FILE_STATE_ERROR; |
764 | 0 | SCReturnInt(r); |
765 | 0 | } |
766 | | |
767 | 22.2M | SCReturnInt(0); |
768 | 22.2M | } |
769 | | |
770 | | /** |
771 | | * \brief Store/handle a chunk of file data in the File structure |
772 | | * The last file in the FileContainer will be used. |
773 | | * |
774 | | * \param ffc FileContainer used to append to |
775 | | * \param data data chunk |
776 | | * \param data_len data chunk len |
777 | | * |
778 | | * \retval 0 ok |
779 | | * \retval -1 error |
780 | | * \retval -2 no store for this file |
781 | | */ |
782 | | int FileAppendData(FileContainer *ffc, const StreamingBufferConfig *sbcfg, const uint8_t *data, |
783 | | uint32_t data_len) |
784 | 36.7M | { |
785 | 36.7M | SCEnter(); |
786 | | |
787 | 36.7M | if (ffc == NULL || ffc->tail == NULL || data_len == 0 || sbcfg == NULL) { |
788 | 15.2M | SCReturnInt(-1); |
789 | 15.2M | } |
790 | 21.4M | int r = FileAppendDataDo(sbcfg, ffc->tail, data, data_len); |
791 | 21.4M | SCReturnInt(r); |
792 | 36.7M | } |
793 | | |
794 | | /** |
795 | | * \brief Store/handle a chunk of file data in the File structure |
796 | | * The file with 'track_id' in the FileContainer will be used. |
797 | | * |
798 | | * \param ffc FileContainer used to append to |
799 | | * \param track_id id to lookup the file |
800 | | * \param data data chunk |
801 | | * \param data_len data chunk len |
802 | | * |
803 | | * \retval 0 ok |
804 | | * \retval -1 error |
805 | | * \retval -2 no store for this file |
806 | | */ |
807 | | int FileAppendDataById(FileContainer *ffc, const StreamingBufferConfig *sbcfg, uint32_t track_id, |
808 | | const uint8_t *data, uint32_t data_len) |
809 | 845k | { |
810 | 845k | SCEnter(); |
811 | | |
812 | 845k | if (ffc == NULL || ffc->tail == NULL || data == NULL || data_len == 0) { |
813 | 1.50k | SCReturnInt(-1); |
814 | 1.50k | } |
815 | 843k | File *ff = ffc->head; |
816 | 843k | for ( ; ff != NULL; ff = ff->next) { |
817 | 843k | if (track_id == ff->file_track_id) { |
818 | 843k | int r = FileAppendDataDo(sbcfg, ff, data, data_len); |
819 | 843k | SCReturnInt(r); |
820 | 843k | } |
821 | 843k | } |
822 | 843k | SCReturnInt(-1); |
823 | 843k | } |
824 | | |
825 | | /** |
826 | | * \brief Store/handle a chunk of file data in the File structure |
827 | | * The file with 'track_id' in the FileContainer will be used. |
828 | | * |
829 | | * \param ffc FileContainer used to append to |
830 | | * \param track_id id to lookup the file |
831 | | * \param data data chunk |
832 | | * \param data_len data chunk len |
833 | | * |
834 | | * \retval 0 ok |
835 | | * \retval -1 error |
836 | | * \retval -2 no store for this file |
837 | | */ |
838 | | int FileAppendGAPById(FileContainer *ffc, const StreamingBufferConfig *sbcfg, uint32_t track_id, |
839 | | const uint8_t *data, uint32_t data_len) |
840 | 588 | { |
841 | 588 | SCEnter(); |
842 | | |
843 | 588 | if (ffc == NULL || ffc->tail == NULL || data == NULL || data_len == 0) { |
844 | 25 | SCReturnInt(-1); |
845 | 25 | } |
846 | 563 | File *ff = ffc->head; |
847 | 563 | for ( ; ff != NULL; ff = ff->next) { |
848 | 563 | if (track_id == ff->file_track_id) { |
849 | 563 | FileFlagGap(ff); |
850 | 563 | SCLogDebug("FILE_HAS_GAPS set"); |
851 | | |
852 | 563 | int r = FileAppendDataDo(sbcfg, ff, data, data_len); |
853 | 563 | SCReturnInt(r); |
854 | 563 | } |
855 | 563 | } |
856 | 563 | SCReturnInt(-1); |
857 | 563 | } |
858 | | |
859 | | void FileSetInspectSizes(File *file, const uint32_t win, const uint32_t min) |
860 | 2.03M | { |
861 | 2.03M | file->inspect_window = win; |
862 | 2.03M | file->inspect_min_size = min; |
863 | 2.03M | } |
864 | | |
865 | | /** |
866 | | * \brief Sets the offset range for a file. |
867 | | * |
868 | | * \param ffc the container |
869 | | * \param start start offset |
870 | | * \param end end offset |
871 | | * |
872 | | * \retval 0 ok |
873 | | * \retval -1 error |
874 | | */ |
875 | | int FileSetRange(FileContainer *ffc, uint64_t start, uint64_t end) |
876 | 19.3k | { |
877 | 19.3k | SCEnter(); |
878 | | |
879 | 19.3k | if (ffc == NULL || ffc->tail == NULL) { |
880 | 0 | SCReturnInt(-1); |
881 | 0 | } |
882 | 19.3k | ffc->tail->start = start; |
883 | 19.3k | ffc->tail->end = end; |
884 | 19.3k | SCReturnInt(0); |
885 | 19.3k | } |
886 | | |
887 | | /** |
888 | | * \brief Open a new File |
889 | | * |
890 | | * \param ffc flow container |
891 | | * \param sbcfg buffer config |
892 | | * \param name filename character array |
893 | | * \param name_len filename len |
894 | | * \param data initial data |
895 | | * \param data_len initial data len |
896 | | * \param flags open flags |
897 | | * |
898 | | * \retval ff flowfile object |
899 | | * |
900 | | * \note filename is not a string, so it's not nul terminated. |
901 | | */ |
902 | | static File *FileOpenFile(FileContainer *ffc, const StreamingBufferConfig *sbcfg, |
903 | | const uint8_t *name, uint16_t name_len, |
904 | | const uint8_t *data, uint32_t data_len, uint16_t flags) |
905 | 1.38M | { |
906 | 1.38M | SCEnter(); |
907 | | |
908 | | //PrintRawDataFp(stdout, name, name_len); |
909 | | |
910 | 1.38M | File *ff = FileAlloc(name, name_len); |
911 | 1.38M | if (ff == NULL) { |
912 | 0 | SCReturnPtr(NULL, "File"); |
913 | 0 | } |
914 | | |
915 | 1.38M | ff->sb = StreamingBufferInit(sbcfg); |
916 | 1.38M | if (ff->sb == NULL) { |
917 | 0 | FileFree(ff, sbcfg); |
918 | 0 | SCReturnPtr(NULL, "File"); |
919 | 0 | } |
920 | 1.38M | SCLogDebug("ff->sb %p", ff->sb); |
921 | | |
922 | 1.38M | if (flags & FILE_STORE || g_file_force_filestore) { |
923 | 180k | FileStore(ff); |
924 | 1.20M | } else if (flags & FILE_NOSTORE) { |
925 | 0 | SCLogDebug("not storing this file"); |
926 | 0 | ff->flags |= FILE_NOSTORE; |
927 | 0 | } |
928 | 1.38M | if (flags & FILE_NOMAGIC) { |
929 | 84.2k | SCLogDebug("not doing magic for this file"); |
930 | 84.2k | ff->flags |= FILE_NOMAGIC; |
931 | 84.2k | } |
932 | 1.38M | if (flags & FILE_NOMD5) { |
933 | 177k | SCLogDebug("not doing md5 for this file"); |
934 | 177k | ff->flags |= FILE_NOMD5; |
935 | 177k | } |
936 | 1.38M | if (flags & FILE_NOSHA1) { |
937 | 177k | SCLogDebug("not doing sha1 for this file"); |
938 | 177k | ff->flags |= FILE_NOSHA1; |
939 | 177k | } |
940 | 1.38M | if (flags & FILE_NOSHA256) { |
941 | 0 | SCLogDebug("not doing sha256 for this file"); |
942 | 0 | ff->flags |= FILE_NOSHA256; |
943 | 0 | } |
944 | | |
945 | 1.38M | if (!(ff->flags & FILE_NOMD5) || g_file_force_md5) { |
946 | 1.20M | ff->md5_ctx = SCMd5New(); |
947 | 1.20M | } |
948 | 1.38M | if (!(ff->flags & FILE_NOSHA1) || g_file_force_sha1) { |
949 | 1.20M | ff->sha1_ctx = SCSha1New(); |
950 | 1.20M | } |
951 | 1.38M | if (!(ff->flags & FILE_NOSHA256) || g_file_force_sha256) { |
952 | 1.38M | ff->sha256_ctx = SCSha256New(); |
953 | 1.38M | SCLogDebug("ff %p ff->sha256_ctx %p", ff, ff->sha256_ctx); |
954 | 1.38M | } |
955 | | |
956 | 1.38M | ff->state = FILE_STATE_OPENED; |
957 | 1.38M | SCLogDebug("flowfile state transitioned to FILE_STATE_OPENED"); |
958 | | |
959 | 1.38M | ff->fd = -1; |
960 | | |
961 | 1.38M | FileContainerAdd(ffc, ff); |
962 | | |
963 | | /* set default window and min inspection size */ |
964 | 1.38M | FileSetInspectSizes(ff, FILEDATA_CONTENT_INSPECT_WINDOW, FILEDATA_CONTENT_INSPECT_MIN_SIZE); |
965 | | |
966 | 1.38M | ff->size += data_len; |
967 | 1.38M | if (data != NULL) { |
968 | 471k | if (AppendData(sbcfg, ff, data, data_len) != 0) { |
969 | 0 | ff->state = FILE_STATE_ERROR; |
970 | 0 | SCReturnPtr(NULL, "File"); |
971 | 0 | } |
972 | 471k | SCLogDebug("file size is now %"PRIu64, FileTrackedSize(ff)); |
973 | 909k | } else if (data_len > 0) { |
974 | 146 | FileFlagGap(ff); |
975 | 146 | } |
976 | | |
977 | 1.38M | SCReturnPtr(ff, "File"); |
978 | 1.38M | } |
979 | | |
980 | | /** |
981 | | * \retval 0 ok |
982 | | * \retval -1 failed */ |
983 | | int FileOpenFileWithId(FileContainer *ffc, const StreamingBufferConfig *sbcfg, |
984 | | uint32_t track_id, const uint8_t *name, uint16_t name_len, |
985 | | const uint8_t *data, uint32_t data_len, uint16_t flags) |
986 | 1.38M | { |
987 | 1.38M | SCLogDebug("ffc %p track_id %u", ffc, track_id); |
988 | 1.38M | File *ff = FileOpenFile(ffc, sbcfg, name, name_len, data, data_len, flags); |
989 | 1.38M | if (ff == NULL) |
990 | 0 | return -1; |
991 | | |
992 | 1.38M | ff->file_track_id = track_id; |
993 | 1.38M | return 0; |
994 | 1.38M | } |
995 | | |
996 | | int FileCloseFilePtr(File *ff, const StreamingBufferConfig *sbcfg, const uint8_t *data, |
997 | | uint32_t data_len, uint16_t flags) |
998 | 1.18M | { |
999 | 1.18M | SCEnter(); |
1000 | | |
1001 | 1.18M | if (ff == NULL) { |
1002 | 0 | SCReturnInt(-1); |
1003 | 0 | } |
1004 | | |
1005 | 1.18M | if (ff->state != FILE_STATE_OPENED) { |
1006 | 450 | SCReturnInt(-1); |
1007 | 450 | } |
1008 | | |
1009 | 1.18M | ff->size += data_len; |
1010 | 1.18M | if (data != NULL) { |
1011 | 125k | if (AppendData(sbcfg, ff, data, data_len) != 0) { |
1012 | 0 | ff->state = FILE_STATE_ERROR; |
1013 | 0 | SCReturnInt(-1); |
1014 | 0 | } |
1015 | 125k | } |
1016 | | |
1017 | 1.18M | if ((flags & FILE_TRUNCATED) || (ff->flags & FILE_HAS_GAPS)) { |
1018 | 21.3k | SCLogDebug("flags FILE_TRUNCATED %s", (flags & FILE_TRUNCATED) ? "true" : "false"); |
1019 | 21.3k | SCLogDebug("ff->flags FILE_HAS_GAPS %s", (ff->flags & FILE_HAS_GAPS) ? "true" : "false"); |
1020 | | |
1021 | 21.3k | ff->state = FILE_STATE_TRUNCATED; |
1022 | 21.3k | SCLogDebug("flowfile state transitioned to FILE_STATE_TRUNCATED"); |
1023 | | |
1024 | 21.3k | if (flags & FILE_NOSTORE) { |
1025 | 0 | SCLogDebug("not storing this file"); |
1026 | 0 | ff->flags |= FILE_NOSTORE; |
1027 | 21.3k | } else { |
1028 | 21.3k | if (g_file_force_sha256 && ff->sha256_ctx) { |
1029 | 4.80k | SCLogDebug("file %p data %p data_len %u", ff, data, data_len); |
1030 | 4.80k | FileEndSha256(ff); |
1031 | 4.80k | } |
1032 | 21.3k | } |
1033 | 1.16M | } else { |
1034 | 1.16M | ff->state = FILE_STATE_CLOSED; |
1035 | 1.16M | SCLogDebug("flowfile state transitioned to FILE_STATE_CLOSED"); |
1036 | | |
1037 | 1.16M | if (ff->md5_ctx) { |
1038 | 1.00M | SCMd5Finalize(ff->md5_ctx, ff->md5, sizeof(ff->md5)); |
1039 | 1.00M | ff->md5_ctx = NULL; |
1040 | 1.00M | ff->flags |= FILE_MD5; |
1041 | 1.00M | } |
1042 | 1.16M | if (ff->sha1_ctx) { |
1043 | 1.00M | SCSha1Finalize(ff->sha1_ctx, ff->sha1, sizeof(ff->sha1)); |
1044 | 1.00M | ff->sha1_ctx = NULL; |
1045 | 1.00M | ff->flags |= FILE_SHA1; |
1046 | 1.00M | } |
1047 | 1.16M | if (ff->sha256_ctx) { |
1048 | 1.16M | SCLogDebug("file %p data %p data_len %u", ff, data, data_len); |
1049 | 1.16M | FileEndSha256(ff); |
1050 | 1.16M | } |
1051 | 1.16M | } |
1052 | | |
1053 | 1.18M | SCReturnInt(0); |
1054 | 1.18M | } |
1055 | | |
1056 | | /** |
1057 | | * \brief Close a File |
1058 | | * |
1059 | | * \param ffc the container |
1060 | | * \param data final data if any |
1061 | | * \param data_len data len if any |
1062 | | * \param flags flags |
1063 | | * |
1064 | | * \retval 0 ok |
1065 | | * \retval -1 error |
1066 | | */ |
1067 | | int FileCloseFile(FileContainer *ffc, const StreamingBufferConfig *sbcfg, const uint8_t *data, |
1068 | | uint32_t data_len, uint16_t flags) |
1069 | 640k | { |
1070 | 640k | SCEnter(); |
1071 | | |
1072 | 640k | if (ffc == NULL || ffc->tail == NULL) { |
1073 | 126 | SCReturnInt(-1); |
1074 | 126 | } |
1075 | | |
1076 | 640k | if (FileCloseFilePtr(ffc->tail, sbcfg, data, data_len, flags) == -1) { |
1077 | 5 | SCReturnInt(-1); |
1078 | 5 | } |
1079 | | |
1080 | 640k | SCReturnInt(0); |
1081 | 640k | } |
1082 | | |
1083 | | int FileCloseFileById(FileContainer *ffc, const StreamingBufferConfig *sbcfg, uint32_t track_id, |
1084 | | const uint8_t *data, uint32_t data_len, uint16_t flags) |
1085 | 544k | { |
1086 | 544k | SCEnter(); |
1087 | | |
1088 | 544k | if (ffc == NULL || ffc->tail == NULL) { |
1089 | 664 | SCReturnInt(-1); |
1090 | 664 | } |
1091 | | |
1092 | 543k | File *ff = ffc->head; |
1093 | 543k | for ( ; ff != NULL; ff = ff->next) { |
1094 | 543k | if (track_id == ff->file_track_id) { |
1095 | 543k | int r = FileCloseFilePtr(ff, sbcfg, data, data_len, flags); |
1096 | 543k | SCReturnInt(r); |
1097 | 543k | } |
1098 | 543k | } |
1099 | 543k | SCReturnInt(-1); |
1100 | 543k | } |
1101 | | |
1102 | | /** \brief set a flow's file flags |
1103 | | * \param set_file_flags flags in both directions that are requested to set |
1104 | | * |
1105 | | * This function will ignore the flags for the irrelevant direction and |
1106 | | * also mask the flags with the global settings. |
1107 | | */ |
1108 | | void FileUpdateFlowFileFlags(Flow *f, uint16_t set_file_flags, uint8_t direction) |
1109 | 823k | { |
1110 | 823k | SCEnter(); |
1111 | 823k | DEBUG_ASSERT_FLOW_LOCKED(f); |
1112 | | |
1113 | | /* remove flags not in our direction and |
1114 | | don't disable what is globally enabled */ |
1115 | 823k | if (direction == STREAM_TOSERVER) { |
1116 | 487k | set_file_flags &= ~(FLOWFILE_NONE_TC|g_file_flow_mask); |
1117 | 487k | } else { |
1118 | 335k | set_file_flags &= ~(FLOWFILE_NONE_TS|g_file_flow_mask); |
1119 | 335k | } |
1120 | 823k | f->file_flags |= set_file_flags; |
1121 | | |
1122 | 823k | SCLogDebug("f->file_flags %04x set_file_flags %04x g_file_flow_mask %04x", |
1123 | 823k | f->file_flags, set_file_flags, g_file_flow_mask); |
1124 | | |
1125 | 823k | if (set_file_flags != 0 && f->alproto != ALPROTO_UNKNOWN && f->alstate != NULL) { |
1126 | 141k | AppLayerStateData *sd = AppLayerParserGetStateData(f->proto, f->alproto, f->alstate); |
1127 | 141k | if (sd != NULL) { |
1128 | 141k | if ((sd->file_flags & f->file_flags) != f->file_flags) { |
1129 | 112k | SCLogDebug("state data: updating file_flags %04x with flow file_flags %04x", |
1130 | 112k | sd->file_flags, f->file_flags); |
1131 | 112k | sd->file_flags |= f->file_flags; |
1132 | 112k | } |
1133 | 141k | } |
1134 | 141k | } |
1135 | 823k | } |
1136 | | |
1137 | | /** |
1138 | | * \brief disable file storing for files in a transaction |
1139 | | * |
1140 | | * \param f *LOCKED* flow |
1141 | | * \param direction flow direction |
1142 | | * \param tx_id transaction id |
1143 | | */ |
1144 | | void FileDisableStoringForTransaction(Flow *f, const uint8_t direction, void *tx, uint64_t tx_id) |
1145 | 20.5k | { |
1146 | 20.5k | if (g_file_force_filestore == 0) { |
1147 | 0 | AppLayerTxData *txd = AppLayerParserGetTxData(f->proto, f->alproto, tx); |
1148 | 0 | if (txd != NULL) { |
1149 | 0 | if (direction & STREAM_TOSERVER) { |
1150 | 0 | txd->file_flags |= FLOWFILE_NO_STORE_TS; |
1151 | 0 | } else { |
1152 | 0 | txd->file_flags |= FLOWFILE_NO_STORE_TC; |
1153 | 0 | } |
1154 | 0 | } |
1155 | 0 | } |
1156 | 20.5k | } |
1157 | | |
1158 | | /** |
1159 | | * \brief flag a file with id "file_id" to be stored. |
1160 | | * |
1161 | | * \param fc file store |
1162 | | * \param file_id the file's id |
1163 | | */ |
1164 | | void FileStoreFileById(FileContainer *fc, uint32_t file_id) |
1165 | 40.3k | { |
1166 | 40.3k | File *ptr = NULL; |
1167 | | |
1168 | 40.3k | SCEnter(); |
1169 | | |
1170 | 40.3k | if (fc != NULL) { |
1171 | 80.6k | for (ptr = fc->head; ptr != NULL; ptr = ptr->next) { |
1172 | 40.3k | if (ptr->file_track_id == file_id) { |
1173 | 40.3k | FileStore(ptr); |
1174 | 40.3k | } |
1175 | 40.3k | } |
1176 | 40.3k | } |
1177 | 40.3k | } |
1178 | | |
1179 | | static void FileTruncateAllOpenFiles(FileContainer *fc, const StreamingBufferConfig *sbcfg) |
1180 | 394 | { |
1181 | 394 | File *ptr = NULL; |
1182 | | |
1183 | 394 | SCEnter(); |
1184 | | |
1185 | 394 | if (fc != NULL) { |
1186 | 535 | for (ptr = fc->head; ptr != NULL; ptr = ptr->next) { |
1187 | 141 | if (ptr->state == FILE_STATE_OPENED) { |
1188 | 0 | FileCloseFilePtr(ptr, sbcfg, NULL, 0, FILE_TRUNCATED); |
1189 | 0 | } |
1190 | 141 | } |
1191 | 394 | } |
1192 | 394 | } |
1193 | | |
1194 | | void FilesPrune(FileContainer *fc, const StreamingBufferConfig *sbcfg, const bool trunc) |
1195 | 111M | { |
1196 | 111M | if (trunc) { |
1197 | 394 | FileTruncateAllOpenFiles(fc, sbcfg); |
1198 | 394 | } |
1199 | 111M | FilePrune(fc, sbcfg); |
1200 | 111M | } |
1201 | | |
1202 | | /** |
1203 | | * \brief Finish the SHA256 calculation. |
1204 | | */ |
1205 | | static void FileEndSha256(File *ff) |
1206 | 1.16M | { |
1207 | 1.16M | SCLogDebug("ff %p ff->size %" PRIu64, ff, ff->size); |
1208 | 1.16M | if (!(ff->flags & FILE_SHA256) && ff->sha256_ctx) { |
1209 | 1.16M | SCSha256Finalize(ff->sha256_ctx, ff->sha256, sizeof(ff->sha256)); |
1210 | 1.16M | ff->sha256_ctx = NULL; |
1211 | 1.16M | ff->flags |= FILE_SHA256; |
1212 | 1.16M | } |
1213 | 1.16M | } |