// See the file "COPYING" in the main distribution directory for copyright. #include #include "Extract.h" #include "util.h" #include "Event.h" #include "file_analysis/Manager.h" using namespace file_analysis; Extract::Extract(RecordVal* args, File* file, const string& arg_filename, uint64 arg_limit) : file_analysis::Analyzer(file_mgr->GetComponentTag("EXTRACT"), args, file), filename(arg_filename), limit(arg_limit), depth(0) { fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, 0666); if ( fd < 0 ) { fd = 0; char buf[128]; strerror_r(errno, buf, sizeof(buf)); reporter->Error("cannot open %s: %s", filename.c_str(), buf); } } Extract::~Extract() { if ( fd ) safe_close(fd); } static Val* get_extract_field_val(RecordVal* args, const char* name) { Val* rval = args->Lookup(name); if ( ! rval ) reporter->Error("File extraction analyzer missing arg field: %s", name); return rval; } file_analysis::Analyzer* Extract::Instantiate(RecordVal* args, File* file) { Val* fname = get_extract_field_val(args, "extract_filename"); Val* limit = get_extract_field_val(args, "extract_limit"); if ( ! fname || ! limit ) return 0; return new Extract(args, file, fname->AsString()->CheckString(), limit->AsCount()); } static bool check_limit_exceeded(uint64 lim, uint64 depth, uint64 len, uint64* n) { if ( lim == 0 ) { *n = len; return false; } if ( depth >= lim ) { *n = 0; return true; } else if ( depth + len > lim ) { printf("exceeded the maximum extraction lenght depth: %llu len: %llu lim: %llu\n", depth, len, lim); *n = lim - depth; return true; } else { *n = len; } return false; } bool Extract::DeliverStream(const u_char* data, uint64 len) { if ( ! fd ) return false; uint64 towrite = 0; bool limit_exceeded = check_limit_exceeded(limit, depth, len, &towrite); if ( limit_exceeded && file_extraction_limit ) { File* f = GetFile(); val_list* vl = new val_list(); vl->append(f->GetVal()->Ref()); vl->append(Args()->Ref()); vl->append(new Val(limit, TYPE_COUNT)); vl->append(new Val(len, TYPE_COUNT)); f->FileEvent(file_extraction_limit, vl); // Limit may have been modified by a BIF, re-check it. limit_exceeded = check_limit_exceeded(limit, depth, len, &towrite); } if ( towrite > 0 ) { safe_pwrite(fd, (const u_char *) data, towrite, depth); depth += towrite; } return ( ! limit_exceeded ); } bool Extract::Undelivered(uint64 offset, uint64 len) { depth += len; return true; }