#!/usr/bin/perl -w
# Copyright (C) 2000-2022 Kern Sibbald
# License: BSD 2-Clause; see file LICENSE-FOSS

use strict;
use File::Basename;
use Fcntl ':flock'; # Import LOCK_* constants

################################################################
# Script to update the Bacula malware database from abuse.ch
#
# Output: dest file
# Return code:
#  -1: Error
#   0: Should truncate the database and load the data
#   1: No changes
#   2: Should load the data (incremental changes)


my $type = shift or die "Usage: $0 [MD5|SHA256] destfile";
my $dest = shift or die "Usage: $0 [MD5|SHA256] destfile";

my $level = "full";             # full or recent
my $url;

################################################################
# We use a lock file to avoid to update the same database in parallel
my $lock = "$dest.lk";
my $fh;
open($fh, ">", $lock)  or die "Unable to create lock file $lock $@";
flock($fh, LOCK_EX)    or die "Unable to lock $lock $@";
################################################################

# We check if the destination database file already exists
# If yes, we check the date to see if we can update it or not
if (-r $dest && -s $dest > 0 ) {
    my $last_mod_time = (stat($dest))[9]; # mtime
    my $now = scalar(time);
    if (($last_mod_time + 60*60) > $now) {
        print "$dest\n";
        exit 1;                 # Nothing to do

    } elsif (($last_mod_time + 24*60*60) > $now) {
        $level = "recent";
    }
    # We can adapt the level of the full
}

# Place where to find additional commands
my $dir = dirname($0);

if ($type eq "MD5") {
    $url = "https://bazaar.abuse.ch/export/txt/md5/$level/";

} elsif ($type eq "SHA256") {
    $url = "https://bazaar.abuse.ch/export/txt/sha256/$level/";

} else {
    die "Unknown algorithm $type. Expecting MD5 or SHA256";
}

if (! -x "$dir/md5tobase64.py") {
    die "Unable to find $dir/md5tobase64.py";
}

my $uncompress = "";
if ($level eq "full") {
    $uncompress = "|gunzip";
}

if ($ENV{REGRESS_MALWARE_URL}) {
    $url = $ENV{REGRESS_MALWARE_URL};
    $uncompress = "";
}

open(FP2, ">$dest") or die "Unable to open $dest $!";
open(FP, "curl --silent $url $uncompress | $dir/md5tobase64.py|") or die "Unable to download $url database";
while (my $l = <FP>) {
    print FP2 $l;
}
close(FP) or die "Unable to download $url database";
close(FP2);

print "$dest\n";
if ($level eq "full") {
    exit 0;                     # Truncate + load

} else {
    exit 2;                     # Load
}
