#include "detection/detection_engine.h"
#include "file_api/file_flows.h"
+#include "hash/hashfcn.h"
#include "log/messages.h"
#include "search_engines/search_tool.h"
#include "utils/util_cstring.h"
}
/*Process file type/file signature*/
- FileFlows* file_flows = FileFlows::get_file_flows(flow);
- if (file_flows && file_flows->file_process(p, buffer, buf_size, position, upload)
- && (isFileStart(position)) && log_state)
- {
- file_flows->set_file_name((const uint8_t*)filename.c_str(), filename.length());
- filename.clear();
- }
+ mime_file_process(p, buffer, buf_size, position, upload);
+
if (mime_stats)
{
switch (decode_state->get_decode_type())
return end;
}
+void MimeSession::reset_file_data()
+{
+ // Clear MIME's file data to prepare for next file
+ file_counter++;
+ file_process_offset = 0;
+ current_mime_file_id = 0;
+ continue_inspecting_file = true;
+}
+
// Main function for mime processing
// This should be called when mime data is available
const uint8_t* MimeSession::process_mime_data(Packet* p, const uint8_t* start,
int data_size, bool upload, FilePosition position)
{
- Flow* flow = p->flow;
const uint8_t* attach_start = start;
const uint8_t* attach_end;
if (position != SNORT_FILE_POSITION_UNKNOWN)
{
+ if (position == SNORT_FILE_START or position == SNORT_FILE_FULL)
+ reset_file_data();
process_mime_data_paf(p, attach_start, data_end_marker,
upload, position);
return data_end_marker;
}
- initFilePosition(&position, get_file_processed_size(flow));
+ initFilePosition(&position, file_process_offset);
/* look for boundary */
while (start < data_end_marker)
{
finalFilePosition(&position);
process_mime_data_paf(p, attach_start, attach_end,
upload, position);
+ reset_file_data();
data_state = STATE_MIME_HEADER;
position = SNORT_FILE_START;
attach_start = start + 1;
if ((start == data_end_marker) && (attach_start < data_end_marker))
{
- updateFilePosition(&position, get_file_processed_size(flow));
+ updateFilePosition(&position, file_process_offset);
process_mime_data_paf(p, attach_start, data_end_marker,
upload, position);
}
delete mime_hdr_search_mpse;
}
-MimeSession::MimeSession(DecodeConfig* dconf, MailLogConfig* lconf)
+MimeSession::MimeSession(DecodeConfig* dconf, MailLogConfig* lconf, uint64_t base_file_id)
{
decode_conf = dconf;
log_config = lconf;
log_state = new MailLogState(log_config);
+ session_base_file_id = base_file_id;
reset_mime_paf_state(&mime_boundary);
}
delete(log_state);
}
+uint64_t MimeSession::get_mime_file_id()
+{
+ if (!current_mime_file_id)
+ {
+ const int data_len = sizeof(session_base_file_id) + sizeof(file_counter);
+ uint8_t data[data_len];
+ memcpy(data, (void*)&session_base_file_id, sizeof(session_base_file_id));
+ memcpy(data + sizeof(session_base_file_id), (void*)&file_counter, sizeof(file_counter));
+ current_mime_file_id = str_to_hash(data, data_len);
+ }
+ return current_mime_file_id;
+}
+
+void MimeSession::mime_file_process(Packet* p, const uint8_t* data, int data_size,
+ FilePosition position, bool upload)
+{
+ Flow* flow = p->flow;
+ FileFlows* file_flows = FileFlows::get_file_flows(flow);
+ if(!file_flows)
+ return;
+
+ if (continue_inspecting_file or position == SNORT_FILE_END)
+ {
+ if (session_base_file_id)
+ {
+ const FileDirection dir = upload? FILE_UPLOAD : FILE_DOWNLOAD;
+ uint64_t offset = file_process_offset;
+ // MIME has found the end of a file that file processing didn't want - tell file
+ // processing it can clear this file's data
+ if (!continue_inspecting_file)
+ offset = 0;
+ uint64_t file_id = get_mime_file_id();
+ continue_inspecting_file = file_flows->file_process(p, file_id, data, data_size, offset,
+ dir, file_id, position);
+ }
+ else
+ {
+ continue_inspecting_file = file_flows->file_process(p, data, data_size, position,
+ upload);
+ }
+ file_process_offset += data_size;
+ if (continue_inspecting_file and (isFileStart(position)) && log_state)
+ {
+ file_flows->set_file_name((const uint8_t*)filename.c_str(), filename.length());
+ filename.clear();
+ }
+ }
+ if (position == SNORT_FILE_FULL or position == SNORT_FILE_END)
+ reset_file_data();
+}
class SO_PUBLIC MimeSession
{
public:
- MimeSession(DecodeConfig*, MailLogConfig*);
+ MimeSession(DecodeConfig*, MailLogConfig*, uint64_t base_file_id=0);
virtual ~MimeSession();
MimeSession(const MimeSession&) = delete;
MailLogState* log_state = nullptr;
MimeStats* mime_stats = nullptr;
std::string filename;
+ bool continue_inspecting_file = true;
+ // This counter is not an accurate count of files; used only for creating a unique mime_file_id
+ uint32_t file_counter = 0;
+ uint32_t file_process_offset = 0;
+ uint64_t session_base_file_id = 0;
+ uint64_t current_mime_file_id = 0;
+ uint64_t get_mime_file_id();
+ void mime_file_process(Packet* p, const uint8_t* data, int data_size,
+ FilePosition position, bool upload);
+ void reset_file_data();
// SMTP, IMAP, POP might have different implementation for this
virtual int handle_header_line(const uint8_t*, const uint8_t*, int, Packet*) { return 0; }
return true;
}
+ // FIXIT-M No longer necessary to send an empty body section because the header section is
+ // always forwarded to detection.
// If the message has been truncated immediately following the start line or immediately
// following the headers (a body was expected) then we need to process an empty section to
// provide an inspection section. Otherwise the start line and headers won't go through
if (!session_data->mime_state[source_id])
{
FileFlows* file_flows = FileFlows::get_file_flows(flow);
- const bool download = (source_id == SRC_SERVER);
+ const FileDirection dir = source_id == SRC_SERVER ? FILE_DOWNLOAD : FILE_UPLOAD;
size_t file_index = 0;
+ uint64_t file_processing_id = 0;
+ // FIXIT-L How can there be a file in progress and no transaction in this direction?
if (session_data->transaction[source_id] != nullptr)
{
HttpMsgRequest* request = session_data->transaction[source_id]->get_request();
{
file_index = request->get_http_uri()->get_file_proc_hash();
}
+ file_processing_id =
+ session_data->transaction[source_id]->get_file_processing_id(source_id);
}
-
- file_flows->file_process(packet, nullptr, 0, SNORT_FILE_END, !download, file_index);
+ file_flows->file_process(packet, file_index, nullptr, 0, 0, dir, file_processing_id,
+ SNORT_FILE_END);
}
else
{