#!/usr/bin/bash
#
# ng-server config post-install script
# !IMPORTANT! this script *MUST* be idempotent
#

#########################################
# Audit rules installation
#########################################
augenrules --load >/dev/null || :

# passwd/group back file permissions for CIS benchmark
chmod -f 0600 /etc/passwd- /etc/group-


#########################################
# Authseed Generation
#########################################
# SSH key generation will run during the kickstart package installation (%packages)
# However, this happens BEFORE the authseed has been generated in the kickstart %post
# Therefore we will either retrieve or create an authseed here

AUTHSEEDFILE=/etc/sysconfig/authseed
if [ ! -s "$AUTHSEEDFILE" ]; then
	# If the authseed is empty (doesn't exist), attempt to pull the authseed from the cmdline arguments
	AUTHSEED=$(sed -nre 's/^.* (--)?(noggin.)?authseed=([^ ]+).*$/\3/ p' < /proc/cmdline)
	if [ -z "$AUTHSEED" ]; then
		# Nothing on the cmdline, but We really really need one, so we generate the authseed here
		AUTHSEED=$(dd if=/dev/urandom bs=1 count=24 2>/dev/null | base64)
	fi
	# We have the authseed now
	printf "$AUTHSEED" >$AUTHSEEDFILE
	# Its a key file, set those permissions!
	chmod 0600 "$AUTHSEEDFILE"
fi

# Install custom config overrides from %{_sysconfdir}/%{name}/overrides
SRCDIR=/etc/ng-server-config/overrides
for i in `find $SRCDIR -type f -printf '%P\n'`; do
  SRC="$SRCDIR/$i"
  DST="/$i"

  # Make a backup of the existing file if we haven't already
  [ -e "$DST" ] && [ ! -e "$DST.ngbak" ] && cp "$DST" "$DST.ngbak"

  # Replace the contents of the existing file with the contents of
  # the override file, this should ensure that security contexts etc
  # of the original target file are maintained
  cat $SRC >$DST
done


#########################################
# RPM Config
#########################################
# import our trusted keys (NB: Some files might be missing on RHEL)
find /etc/pki/rpm-gpg/RPM-GPG-KEY-{CentOS-7,EPEL-7,mysql,noggin} -print0 2>/dev/null \
  | xargs --null --max-lines=1 --no-run-if-empty rpmkeys --import

# Accumulate everything for augeas into a single file for performance reasons
AUGSCRIPT=$(mktemp)

# (re)configure atd to be safer (90% load max, 1 job per second spawn max
if [ -f /etc/sysconfig/atd ]; then
	echo set /files/etc/sysconfig/atd/OPTS "'\"-l $(getconf _NPROCESSORS_ONLN | awk '{print ($1+1)*0.9}') -b 1\"'" >>$AUGSCRIPT
fi

# enable automated freshclam updates for clamav (random offset per hostid)
if [ -f /etc/sysconfig/freshclam ]; then
	echo set /files/etc/sysconfig/freshclam/FRESHCLAM_DELAY random  >>$AUGSCRIPT
fi

# Configure named to be IPv4 only
echo "set /files/etc/sysconfig/named/OPTIONS -4" >>$AUGSCRIPT

# SSHD Configuration
# Check for ng keygen script and (re)generate keys if needed
if [ -f /usr/libexec/ng-server-config/sshd-keygen ]; then
	/usr/libexec/ng-server-config/sshd-keygen
fi

# Disable (client) ssh roaming (CVE-0216-0777, CVE-0216-0778)
cat <<-EOD >>$AUGSCRIPT
	set /files/etc/ssh/ssh_config/Host *
	set "/files/etc/ssh/ssh_config/Host[.='*']/UseRoaming" no
EOD


#########################################
# Setup named?
#########################################
# NOTE: This will fail in kickstart
if [ ! -f /etc/named/cluster-zones.conf ]; then
	if [ -f /etc/sysconfig/ng-kickstart ] && grep -Pq '^clustersoa=' /etc/sysconfig/ng-kickstart; then
		/usr/libexec/ng-server-config/init-named-soa --from-ksconfig
	fi
fi

#########################################
# Apache config
#########################################

# Apache needs access to homedirs
if ! getsebool httpd_enable_homedirs | grep -Pq ' on$'; then
	setsebool -P httpd_enable_homedirs 1
fi

# Disable welcome.conf
if grep -Pq '^[^#]' /etc/httpd/conf.d/welcome.conf; then
	sed -i -r \
	    -e 's/^/#/g' \
	    -e '1 s/^/##\n## This file disabled by ng-server-config\n##\n/g' \
	    /etc/httpd/conf.d/welcome.conf
fi

# Disable /icons/ alias
if grep -Pqi '^[ \t]*Alias[ \t]+/icons/[ \t]+' /etc/httpd/conf.d/autoindex.conf; then
	sed -i -r \
	    -e 's|^[ \t]*Alias[ \t]+/icons/[ \t]+|#\0|ig' \
	    /etc/httpd/conf.d/autoindex.conf
fi

# Disable ssl.conf Listen & VirtualHost
if grep -Pq '^[ \t]*Listen' /etc/httpd/conf.d/ssl.conf; then
	sed -i -r \
	    -e '/^[ \t]*<VirtualHost/,/^[ \t]*<\/VirtualHost/ s/^/#/g' \
 	    -e '1 s/^/##\n## This file disabled by ng-server-config\n##\n/g' \
	    /etc/httpd/conf.d/ssl.conf
fi

# Make php.conf conditional on mod_php5.c
if ! grep -Pq 'IfModule' /etc/httpd/conf.d/php.conf; then
	sed  -i -r \
	     -e '1 s/^/<IfModule mod_php5.c>\n/g' \
	     -e '$ s/^.*$/\0\n<\/IfModule>/g' \
	    /etc/httpd/conf.d/php.conf
fi

# Disable extraneous modules we don't need (ignore any symlinked config though!)
sed -i -r \
        -e 's/^[ \t]*LoadModule[ \t]+(dav(_.*?)?|lua|auth[nz]_(anon|dbd|dbm|socache|owner)|cache(_.*?)?)_module[ \t]/#\0/ig' \
        -e 's/^[ \t]*LoadModule[ \t]+(data|dbd|dumpio|echo|ext_filter|include|socache_(dbm|memcache)|substitute)_module[ \t]/#\0/ig' \
        -e 's/^[ \t]*LoadModule[ \t]+(suexec|userdir|apreq2?)_module[ \t]/#\0/ig' \
        -e 's/^[ \t]*LoadModule[ \t]+(lbmethod_.*?|proxy_(ajp|balancer|connect|express|fdpass|ftp|scgi))_module[ \t]/#\0/ig' \
        $(find /etc/httpd/conf.modules.d/ -type f -iname '*.conf' )

# Switch from prefork to event
if grep -Pq '^\s*LoadModule\s+mpm_prefork' /etc/httpd/conf.modules.d/00-mpm.conf; then
	sed -i -r \
		-e 's/^[ \t]*LoadModule[ \t]+mpm_prefork/#\0/' \
		-e 's/^[ \t]*#+[ \t]*(LoadModule[ \t]+mpm_event)/\1/' \
		/etc/httpd/conf.modules.d/00-mpm.conf
fi


# Create a self-signed last-resort fallback SSL certificate for the system default vhost
if [ ! -f /etc/pki/tls/certs/ng-fallback.crt ]; then
	# Find unique id for this host
	HOSTID=
	[[ -z "$HOSTID" && -f /sys/class/dmi/id/product_uuid ]] && HOSTID=$(</sys/class/dmi/id/product_uuid)
	[[ -z "$HOSTID" ]] && command -v hostid >/dev/null      && HOSTID=$(hostid)
	[[ -z "$HOSTID"                                      ]] && HOSTID="unknown-host-id"

	# Cryptographically mask it
	HOSTUNIQ=$(ng-mk-auth-token X509::HTTPS/machineid/${HOSTID}@self-signed 16)

	# Now generate the private key
	ng-mk-rsa-key httpd::ng-fallback@${HOSTNAME} 2048 >/etc/pki/tls/private/ng-fallback.key
	chmod 0600 /etc/pki/tls/private/ng-fallback.key

	# And the TLS certificate
	BASEDATE=$(date '+%Y-%m-01 00:00:00')
	env TZ=UTC faketime -f "${BASEDATE}" openssl req -new -x509 -utf8 -batch \
		-key /etc/pki/tls/private/ng-fallback.key \
		-subj "/C=AU/ST=New South Wales/O=Noggin Pty Ltd/OU=Noggin Server Autoconfig (${HOSTUNIQ})/CN=${HOSTNAME}" \
		-days $[3*365] \
		-set_serial 0x$(echo -n "httpd::ng-fallback@${HOSTNAME}/machine/${HOSTUNIQ}" | sha512sum | cut -c 1-16) \
		-outform PEM -out /etc/pki/tls/certs/ng-fallback.crt

	# Make sure we trust ourself....
	SUBJHASH=$(openssl x509 -in /etc/pki/tls/certs/ng-fallback.crt -noout -subject_hash)
	if [ ! -e /etc/pki/tls/certs/$SUBJHASH.0 ]; then
		ln -s ng-fallback.crt /etc/pki/tls/certs/$SUBJHASH.0
	fi
fi


#########################################
# PHP config
#########################################

# Copy the system TZ to PHP
if [ -L /etc/localtime ]; then
	ZONE=$(readlink /etc/localtime | sed -re 's|^.*/zoneinfo(/posix)?/(.*)$|\2|g')
elif [ -f /etc/sysconfig/clock ]; then
	source /etc/sysconfig/clock
fi
if [ -n "$ZONE" ]; then
	cat <<-EOD >>$AUGSCRIPT
		set /files/etc/php.d/zz-15-timezone.ini/.anon/date.timezone $ZONE
	EOD
fi


# Disable the default php-fpm pool
if grep -Pq '^[^;]' /etc/php-fpm.d/www.conf; then
	sed -i -r \
	    -e 's/^/;/g' \
	    -e '1 s/^/;;\n;; This file disabled by ng-server-config\n;;\n/g' \
	    /etc/php-fpm.d/www.conf
fi

############################################
# Postfix
############################################
cat <<-EOD >>$AUGSCRIPT
	set /files/etc/postfix/main.cf/inet_protocols ipv4
	set /files/etc/postfix/main.cf/mynetworks_style host
	set /files/etc/postfix/main.cf/smtpd_helo_restrictions 'permit_mynetworks, reject_invalid_helo_hostname'
	set /files/etc/postfix/main.cf/smtpd_sender_restrictions reject_unknown_sender_domain
	set /files/etc/postfix/main.cf/smtpd_data_restrictions 'reject_unauth_pipelining, permit'
	set /files/etc/postfix/main.cf/disable_vrfy_command yes
EOD

augtool --autosave <$AUGSCRIPT

rm -f ${AUGSCRIPT}

# Configure the audit subsystem and auditd
augtool --autosave --backup --noautoload >/dev/null <<'EOD'
	transform simplevars.lns incl /etc/audit/auditd.conf
	transform simplevars.lns incl /etc/audisp/plugins.d/syslog.conf
	transform shellvars_list.lns incl /etc/default/grub
	load

	# Configure auditd native log preservation
	set /files/etc/audit/auditd.conf/max_log_file 10
	set /files/etc/audit/auditd.conf/num_logs 25

	# Enable the auditd syslog plugin
	set /files/etc/audisd/plugins.d/syslog.conf/active yes
	set /files/etc/audisd/plugins.d/syslog.conf/args   LOG_AUTHPRIV

	# Enable early boot audit (before auditd starts)
	set /files/etc/default/grub/GRUB_CMDLINE_LINUX/value[. =~ regexp('.*audit=.*','i')] 'audit=1'

	# Disable Transparent Hugetables, this is known to cause XFS corruption and system crashes on some AWS instance types
	set /files/etc/default/grub/GRUB_CMDLINE_LINUX/value[. =~ regexp('.*transparent_hugepage=.*','i')] 'transparent_hugepage=never'

EOD

# Do we need to regenerate grub.cfg?
[ /etc/default/grub -nt /boot/grub2/grub.cfg ] && grub2-mkconfig -o /boot/grub2/grub.cfg

# INFRA-276: Modify the crond PAM stack to read environment variables (PATH) from our environment file
# What is augtool doing?:
# Remove our configuration (line) if it already exists
# AFTER the last entry in the file which has a type of "session"
# Insert the configuration (node) this line - use a node value of 999 - this doesnt actually effect ordering in the file
# Insert our remaining configuration after this node
augtool --autosave --backup --noautoload >/dev/null <<'EOD'
        set /augeas/load/pam/lens "pam.lns"
        set /augeas/load/pam/incl "/etc/pam.d/crond"
        load
        rm /files/etc/pam.d/crond/*[type = 'session'][control='optional'][module='pam_env.so']

        ins 999 after /files/etc/pam.d/crond/*[type="session"][last()]
        defvar entry /files/etc/pam.d/crond/999
        set $entry/type 'session'
        set $entry/control 'optional'
        set $entry/module 'pam_env.so'
        set $entry/argument[1] 'envfile=/run/crond.env'
EOD

# For any new drop-ins we may have added
systemctl daemon-reload

# Kill/Start the audit subsystem (can only be requested by dependency so we must kill/start it)
systemctl kill auditd
systemctl start auditd

# enable and (re)start services
systemctl -q --no-block reload-or-try-restart atd sshd
systemctl -q enable httpd psacct sysstat

# named-chroot should be used not named, make accidents harder
systemctl -q mask named
systemctl -q mask php-fpm

# Migrate php-fpm pools from sockets.target to php-fpm-pool.service
systemctl -q enable php-fpm-pool.service
if [ -n "$(find /etc/systemd/system/sockets.target.wants -type l -lname /usr/lib/systemd/system/php-fpm-pool@.socket -print -quit)" ]; then
	find /etc/systemd/system/sockets.target.wants -type l -lname /usr/lib/systemd/system/php-fpm-pool@.socket -printf '%f\0' \
	  | xargs --null --no-run-if-empty systemctl -q reenable
	systemctl -q --no-block start php-fpm-pool.service
fi

# Enable mysqld log filter
systemctl -q enable mysqld-log-filter.service

# (Re)run service autotune
find $(dirname $(readlink -f $0)) -name 'autotune-*' -type f -executable -exec '{}' ';'

# Reload any php-fpm worker pools in case the config has been updated
systemctl -q --no-block reload php-fpm-pool.service

# reload apache if the config passes
apachectl configtest && systemctl -q --no-block reload httpd

# Kick mysqld config (via reconf-mysql) for any updates we may have made
# Currently disabled through systemctl reload due to permission issues
#mysqladmin ping && systemctl -q --no-block reload mysqld
/usr/libexec/ng-server-config/reconf-mysql --verbose --log-only --apply

# Duplicates from rpm spec triggerin (refer to spec for why these exist)
sed -re 's/RSYSLOG_TraditionalFileFormat/RSYSLOG_FileFormat/' -i /etc/rsyslog.conf
systemctl reload rsyslog

augtool --autosave --backup --noautoload >/dev/null <<'EOD'
    set /augeas/load/logrotate/lens Logrotate.lns
    set /augeas/load/logrotate/incl "/etc/logrotate.d/percona-telemetry-agent"
    load

    defvar prc /files/etc/logrotate.d/percona-telemetry-agent
   # Remove existing config
   rm $prc/rule/su
   rm $prc/rule/#comment[. = "su directive set by ng-server-config post-install script"]

   set $prc/rule/#comment[last()+1] "su directive set by ng-server-config post-install script"
   set $prc/rule/su
   set $prc/rule/su/owner root
   set $prc/rule/su/group root
EOD

