# -*- perl -*-
use 5.008;
use utf8;
use Fcntl qw':flock :seek :mode';
use IO::Handle;
use IPC::Open3;
use Encode;
use Digest::MD5 qw'md5_hex';
use File::Basename;
use Sys::Hostname;
use Symbol qw'gensym';
# set and untaint ENV if not in CLI (fexsrv provides clean ENV)
unless (-t) {
foreach my $v (keys %ENV) {
($ENV{$v}) = ($ENV{$v} =~ /(.*)/s) if defined $ENV{$v};
}
$ENV{PATH} = '/usr/local/bin:/bin:/usr/bin';
$ENV{IFS} = " \t\n";
$ENV{BASH_ENV} = '';
}
unless ($FEXLIB = $ENV{FEXLIB} and -d $FEXLIB) {
die "$0: found no FEXLIB - fexsrv needs full path\n"
}
$FEXLIB =~ s:/+:/:g;
$FEXLIB =~ s:/$::;
# $FEXHOME is top-level directory of F*EX installation or vhost
# $ENV{HOME} is login-directory of user fex
# in default-installation both are equal, but they may differ
$FEXHOME = $ENV{FEXHOME} or $ENV{FEXHOME} = $FEXHOME = dirname($FEXLIB);
umask 077;
# defaults
$hostname = gethostname();
$tmpdir = $ENV{TMPDIR} || '/var/tmp';
$spooldir = $FEXHOME.'/spool';
$docdir = $FEXHOME.'/htdocs';
$logdir = $spooldir;
$autodelete = 'YES';
$overwrite = 'YES';
$limited_download = 'YES'; # multiple downloads only from same client
$fex_yourself = 'YES'; # allow SENDER = RECIPIENT
$keep = 5; # days
$recipient_quota = 0; # MB
$sender_quota = 0; # MB
$timeout = 30; # seconds
$bs = 2**16; # I/O blocksize
$DS = 60*60*24; # seconds in a day
$MB = 1024*1024; # binary Mega
$use_cookies = 1;
$sendmail = '/usr/lib/sendmail';
$sendmail = '/usr/sbin/sendmail' unless -x $sendmail;
$mailmode = 'auto';
$bcc = 'fex';
$default_locale = '';
$fop_auth = 0;
$mail_authid = 'yes';
$force_https = 0;
$debug = 0;
@forbidden_user_agents = ('FDM');
# https://securityheaders.io/
# https://scotthelme.co.uk/hardening-your-http-response-headers/
# http://content-security-policy.com/
@extra_header = (
# "Content-Security-Policy: sandbox allow-forms allow-scripts",
"Content-Security-Policy: script-src 'self' 'unsafe-inline'",
"X-Frame-Options: SAMEORIGIN",
"X-XSS-Protection: 1; mode=block",
"X-Content-Type-Options: nosniff",
);
$FHS = -f '/etc/fex/fex.ph' and -d '/usr/share/fex/lib';
# Debian FHS
if ($FHS) {
$ENV{FEXHOME} = $FEXHOME = '/usr/share/fex';
$spooldir = '/var/spool/fex';
$logdir = '/var/log/fex';
$docdir = '/var/lib/fex/htdocs';
$notify_newrelease = '';
}
# allowed download managers (HTTP User-Agent)
$adlm = '^(Axel|fex)';
# local config
require "$FEXLIB/fex.ph" or die "$0: cannot load $FEXLIB/fex.ph - $!";
$fop_auth = 0 if $fop_auth =~ /no/i;
$mail_authid = 0 if $mail_authid =~ /no/i;
$force_https = 0 if $force_https =~ /no/i;
$debug = 0 if $debug =~ /no/i;
@logdir = ($logdir) unless @logdir;
$logdir = $logdir[0];
# allowed multi download recipients: from any ip, any times
if (@mailing_lists) {
$amdl = '^('.join('|',map { quotewild($_) } @mailing_lists).')$';
} else {
$amdl = '^-$';
}
# check for name based virtual host
$vhost = vhost($ENV{'HTTP_HOST'});
$RB = 0; # read POST bytes
push @doc_dirs,$docdir;
foreach my $ld (glob "$FEXHOME/locale/*/htdocs") {
push @doc_dirs,$ld;
}
$nomail = ($mailmode =~ /^MANUAL|nomail$/i);
if (not $nomail and not -x $sendmail) {
http_die("found no sendmail");
}
http_die("cannot determine the server hostname") unless $hostname;
$ENV{PROTO} = 'http' unless $ENV{PROTO};
$keep = $keep_default ||= $keep || 5;
$purge ||= 3*$keep;
$fra = $ENV{REMOTE_ADDR} || '';
$sid = $ENV{SID} || '';
$dkeydir = "$spooldir/.dkeys"; # download keys
$ukeydir = "$spooldir/.ukeys"; # upload keys
$akeydir = "$spooldir/.akeys"; # authentification keys
$skeydir = "$spooldir/.skeys"; # subuser authentification keys
$gkeydir = "$spooldir/.gkeys"; # group authentification keys
$xkeydir = "$spooldir/.xkeys"; # extra download keys
$lockdir = "$spooldir/.locks"; # download lock files
if (my $ra = $ENV{REMOTE_ADDR} and $max_fail) {
mkdirp("$spooldir/.fail");
$faillog = "$spooldir/.fail/$ra";
}
unless ($admin) {
$admin = $ENV{SERVER_ADMIN} ? $ENV{SERVER_ADMIN} : 'fex@'.$hostname;
}
# $ENV{SERVER_ADMIN} may be set empty in fex.ph!
$ENV{SERVER_ADMIN} = $admin unless defined $ENV{SERVER_ADMIN};
$mdomain ||= '';
if ($use_cookies) {
if (my $cookie = $ENV{HTTP_COOKIE}) {
if ($cookie =~ /\bakey=(\w+)/) { $akey = $1 }
# elsif ($cookie =~ /\bskey=(\w+)/) { $skey = $1 }
}
}
if (@locales) {
if ($default_locale and not grep /^$default_locale$/,@locales) {
push @locales,$default_locale;
}
if (@locales == 1) {
$default_locale = $locales[0];
}
}
$default_locale ||= 'english';
# $durl is first default fop download URL
# @durl is optional mandatory fop download URL list (from fex.ph)
unless ($durl) {
my $host = '';
my $port = 80;
my $xinetd = '/etc/xinetd.d/fex';
if (@durl) {
$durl = $durl[0];
} elsif ($ENV{HTTP_HOST} and $ENV{PROTO}) {
($host,$port) = split(':',$ENV{HTTP_HOST}||'');
$host = $hostname;
unless ($port) {
$port = 80;
if (open $xinetd,$xinetd) {
while (<$xinetd>) {
if (/^\s*port\s*=\s*(\d+)/) {
$port = $1;
last;
}
}
close $xinetd;
}
}
# use same protocal as uploader for download
if ($ENV{PROTO} eq 'https' and $port == 443 or $port == 80) {
$durl = "$ENV{PROTO}://$host/fop";
} else {
$durl = "$ENV{PROTO}://$host:$port/fop";
}
} else {
if (open $xinetd,$xinetd) {
while (<$xinetd>) {
if (/^\s*port\s*=\s*(\d+)/) {
$port = $1;
last;
}
}
close $xinetd;
}
if ($port == 80) {
$durl = "http://$hostname/fop";
} else {
$durl = "http://$hostname:$port/fop";
}
}
}
@durl = ($durl) unless @durl;
sub reexec {
exec($FEXHOME.'/bin/fexsrv') if $ENV{KEEP_ALIVE};
exit;
}
sub jsredirect {
$url = shift;
$cont = shift || 'request accepted: continue';
http_header('200 ok');
print html_header($head||$ENV{SERVER_NAME});
pq(qq(
''
''
'