#!/usr/bin/perl

eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
    if 0; # not running under some shell
#
# Copyright (c) 2014--2015 Red Hat, Inc.
#
# This software is licensed to you under the GNU General Public License,
# version 2 (GPLv2). There is NO WARRANTY for this software, express or
# implied, including the implied warranties of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
# along with this software; if not, see
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
#
# Red Hat trademarks are not licensed under GPLv2. No permission is
# granted to use or replicate Red Hat trademarks that are incorporated
# in this software or its documentation.
#

use strict 'refs';
use warnings;

use Getopt::Long;
use Spacewalk::Setup;

sub id_like_match {
  $what = shift;
  my $filename = '/etc/os-release';
  if(! -e $filename) {
    return 0;
  }
  open my $fh, "<", $filename or die "Could not open '$filename': $!\n";
  while( my $line = <$fh> ) {
    if ($line =~ m/ID_LIKE="$what"/) {
      close $fh;
      return 1;
    }
  }
  close $fh;
  return 0;
}

sub is_suse_like {
   return id_like_match(".*suse.*");
}

sub is_opensuse {
   return id_like_match(".*opensuse.*");
}

sub os_fips_mode_on {
        # For kernels without CONFIG_CRYPTO_FIPS enabled
        return 0 if (!-e '/proc/sys/crypto/fips_enabled');

        my $sysctl = (-x '/usr/sbin/sysctl') ? '/usr/sbin/sysctl' : '/sbin/sysctl';
        my $ret = `$sysctl -n crypto.fips_enabled`;
        chomp($ret);

        return $ret;
}

sub mod_ssl_fipsmode_option {
        # Remove this IF as soon as we have FIPS support enabled at openSUSE Leap 15.2.
        if (is_opensuse()) {
                return 0;
        }
        if(is_suse_like()) {
                # Remove this return as soon as we have FIPS support enabled at SLE15SP2.
                return 0;

                $mod_ssl_version = `rpm -q --qf='%{VERSION}' apache2-prefork`;
        }
        else {
                $mod_ssl_version = `rpm -q --qf='%{VERSION}' mod_ssl`;
        }
        # mod_ssl > 2.4 supports SSLFIPS directive (Fedora 19, 20, ...)
        # apache2-prefork > 2.4 supports SSLFIPS directive (SLE15, openSUSE Leap 15.0, ...)
        if ($mod_ssl_version gt '2.4.0') {
                return 1;
        }
        return 0;
}

sub modify_conf_content {
        my $conf_content = ${(shift)};
        my $conf_files = shift;
        local *FILE;

        for my $file (glob Spacewalk::Setup::SHARED_DIR . "/$conf_files.*") {
                open FILE, $file or die "Error reading [$file]: $!\n";
                my $regexp = <FILE>;
                chomp $regexp;

                my $content;
                {
                        local $/ = undef;
                        $content = <FILE>;
                }
                close FILE;

                $conf_content =~ s!$regexp!$content!gm or $conf_content .= $content;
        }
        return $conf_content;
}

sub setup_mod_ssl {
        my $fips_mode_on = shift;

        my ($sslconf_content, $original_sslconf_content, $pre, $vhost, $post);
        my $sslconf_dir = '/etc/httpd/conf.d';
        $sslconf_dir = '/etc/apache2/vhosts.d' if(is_suse_like());
        my $sslconf     = 'ssl.conf';
        $sslconf = 'vhost-ssl.conf' if(is_suse_like());

	my $sslconf_path = "$sslconf_dir/$sslconf";
	local *FILE;
        if(is_suse_like() && ! -f $sslconf_path)
	{
		`cp "$sslconf_dir/vhost-ssl.template" "$sslconf_path"`;
	}
        die "$sslconf_path does not exist.\n" unless (-f $sslconf_path);

        {
                open FILE, $sslconf_path or die "Error opening [$sslconf_path]: $!\n";
                local $/ = undef;
                $sslconf_content = <FILE>;
                $original_sslconf_content = $sslconf_content;
                close FILE;
        }

        if ($sslconf_content =~ /(.*<VirtualHost _default_:443>)(.*)(<\/VirtualHost>.*)/s) {
                $pre = $1;
                $vhost = $2;
                $post = $3;
        } else {
                print Spacewalk::Setup::loc("Setup was unable to locate VirtualHost section " .
                        "in existing mod_ssl configuration.\n");
                exit;
        }

        $vhost = modify_conf_content(\$vhost, 'mod_ssl.conf.vhost');

        # (If requested explicitly or the OS is already switched into FIPS mode) and
        # the particular mod_ssl being used supports SSLFIPS option
        if (($fips_mode_on or os_fips_mode_on()) and mod_ssl_fipsmode_option()) {
                $post = modify_conf_content(\$post, 'mod_ssl.conf.sslfips');
        }

        $sslconf_content = $pre . $vhost . $post;

        if ($sslconf_content ne $original_sslconf_content) {
                Spacewalk::Setup::backup_file($sslconf_dir, $sslconf);

                open FILE, ">$sslconf_path" or die "Error opening [$sslconf_path]: $!\n";
                chmod 0644, $sslconf_path;
                print FILE $pre . $vhost . $post;
                close FILE;
        }

        return;
}

# main

my $help;
my $fips_mode_on;

my $usage = <<EOHELP;
Usage: $0 --help | --fips-mode-on
Options:
        --help                  Print this help message
        --fips-mode-on  Turn SSL FIPS mode on (when applicable)
EOHELP

GetOptions(
        "help" => \$help,
        "fips-mode-on" => \$fips_mode_on
        ) or die $usage;

if ($help) {
        print $usage;
        exit 0;
}

setup_mod_ssl($fips_mode_on);

=head1 NAME

spacewalk-setup-httpd - utility for configuring httpd service to work with
Uyuni / SUSE Manager

=head1 SYNOPSIS

B<spacewalk-setup-httpd>
[B<--help>]
[B<--fips-mode-on>]

=head1 OPTIONS

=over 5

=item B<--fips-mode-on>

Configure httpd to work correctly in FIPS mode. For mod_ssl, this means turning
the SSLFIPS directive on in ssl.conf where applicable.

=item B<--help>

Print help message.

=back

=head1 DESCRIPTION

B<spacewalk-setup-httpd> is a utility for configuring httpd service to work
with Uyuni / SUSE Manager. The script uses configuration templates
to modify existing httpd configuration files.

Ordinarily, spacewalk-setup-httpd is called by spacewalk-setup(1) during
initial Uyuni / SUSE Manager configuration or upgrade.

=head1 FILES

mod_ssl configuration

F</etc/httpd/conf.d/ssl.conf>

Configuration templates

F</usr/share/spacewalk/setup/mod_ssl*>

=head1 SEE ALSO

B<spacewalk-setup>(1) - Spacewalk setup program

=head1 AUTHORS

Milan Zazrivec <mzazrivec@redhat.com>

=cut
