#! /usr/bin/perl
use strict;
use warnings;
use File::Spec qw(rel2abs);
use File::Basename;

my @args = ();
my $enabled = 0;
my $debug = 0;
my $debug_fd = *STDERR;

# Set up defaults
my %default;
$default{'DEB_BUILD_HARDENING'}=0;
$default{'DEB_BUILD_HARDENING_DEBUG'}=0;

# Architecture settings
# #OS# #ARCH#
$default{'DEB_BUILD_HARDENING_RELRO'}=1;
$default{'DEB_BUILD_HARDENING_BINDNOW'}=1;

# System settings
my $system_conf = '/etc/hardening-wrapper.conf';
if (-r $system_conf) {
    open(CONF,$system_conf) || warn "Cannot read $system_conf\n";
    while (my $line = <CONF>) {
        if ($line =~ /^\s*(DEB_BUILD_HARDENING[_A-Z]*)\s*=\s*(\d)$/) {
            $default{$1}=$2+0;
        }
    }
    close(CONF);
}

# Environment settings
$enabled =        defined($ENV{'DEB_BUILD_HARDENING'}) ?
                          $ENV{'DEB_BUILD_HARDENING'} :
                          $default{'DEB_BUILD_HARDENING'};
$debug =          defined($ENV{'DEB_BUILD_HARDENING_DEBUG'}) ?
                          $ENV{'DEB_BUILD_HARDENING_DEBUG'} :
                          $default{'DEB_BUILD_HARDENING_DEBUG'};
my $force_relro = defined($ENV{'DEB_BUILD_HARDENING_RELRO'}) ?
                          $ENV{'DEB_BUILD_HARDENING_RELRO'} :
                          $default{'DEB_BUILD_HARDENING_RELRO'};
my $force_bindnow = defined($ENV{'DEB_BUILD_HARDENING_BINDNOW'}) ?
                          $ENV{'DEB_BUILD_HARDENING_BINDNOW'} :
                          $default{'DEB_BUILD_HARDENING_BINDNOW'};

if ($enabled) {
    # Scan arguments
    my $index = 0;
    foreach my $arg (@ARGV) {
        if ($arg eq "relro" && $index>0 && $ARGV[$index-1] eq "-z") {
            $force_relro = 0;
        }
        if ($arg eq "now" && $index>0 && $ARGV[$index-1] eq "-z") {
            $force_bindnow = 0;
        }
        $index++;
    }

    if ($force_relro) {
        push(@args,'-z','relro');
    }
    if ($force_bindnow) {
        push(@args,'-z','now');
    }
}

my $self = "hardened-ld";
my $link = "";
my $arg0 = File::Spec->rel2abs(basename($0),dirname($0));
my $tool = $arg0;
if ($tool =~ /$self$/ || defined($ENV{'HARDENING_USE_USR_BIN'})) {
    $tool = "/usr/bin/ld";
}

if (defined($ENV{'DEB_BUILD_HARDENING_DEBUG_OUTPUT'})) {
    $debug_fd = undef;
    if (!open($debug_fd, ">>$ENV{'DEB_BUILD_HARDENING_DEBUG_OUTPUT'}")) {
        die "Cannot open $ENV{'DEB_BUILD_HARDENING_DEBUG_OUTPUT'}: $!\n";
    }
}

sub resolve_link($)
{
    my $origin = $_[0];
    my $link = readlink($origin);
    return File::Spec->rel2abs($link,dirname($origin));
}

while (-l $tool && ($link = resolve_link($tool)) !~ /$self$/) {
    $tool = $link;
}
if (-x "$tool.real") {
    $tool = "$tool.real";
}
# Abort if we ended up on a circular symlink resolution
if ($tool eq $arg0) {
    my $short = $tool;
    $short =~ s/.*\///g;
	print STDERR "$tool: not found (maybe $short is not installed?)\n";
	exit(127);
}
my @target = ($tool, @args, @ARGV);

print $debug_fd join(" ",@target),"\n" if ($debug);

exec @target or die "Unable to exec $target[0]: $!\n";
