#!/bin/bash
# CloudLinux Links Traversal Protection configure utility


set -o pipefail

function fix_linksafe {
    # fix permissions for alt-php packages installed without linksafe group
    find /opt/alt/php* \( -user root -a ! -group root -a ! -group linksafe \) -exec chown -h root:linksafe {} \; &> /dev/null
    # fix permissions for alt-python packages installed without linksafe group
    find /opt/alt/python* \( -user root -a ! -group root -a ! -group linksafe \) -exec chown -h root:linksafe {} \; &> /dev/null
    # fix permissions for alt-ruby packages installed without linksafe group
    find /opt/alt/ruby* \( -user root -a ! -group root -a ! -group linksafe \) -exec chown -h root:linksafe {} \; &> /dev/null
    # fix permissions for native php
    chown root:linksafe /usr/selector.etc/php.ini &> /dev/null
    chown root:linksafe /usr/selector/lsphp &> /dev/null
    chown root:linksafe /usr/selector/php &> /dev/null
    chown root:linksafe /usr/selector/php-cli &> /dev/null
    if [ -e /usr/sbin/cagefsctl ] && [ -e /usr/share/cagefs-skeleton/bin ]; then
        if /usr/sbin/cagefsctl --setup-cl-selector &> /dev/null; then
            if [ -e /usr/share/cagefs/need.remount ]; then
                if /usr/sbin/cagefsctl --remount-all &> /dev/null; then
                    rm -f /usr/share/cagefs/need.remount &> /dev/null
                fi
            fi
        fi
    fi
}

function initial_setup_linksafe {
    local linksafe="$1"
    local sgid="$2"
    local hgid="$3"
    local sysctl_file="$4"

    if [ -n "$linksafe" ]; then
        if ! grep "fs.protected_symlinks_create" "${sysctl_file}" > /dev/null; then
            echo "fs.protected_symlinks_create = 1" >> "${sysctl_file}"
        fi
        if ! grep "fs.protected_hardlinks_create" "${sysctl_file}" > /dev/null; then
            echo "fs.protected_hardlinks_create = 1" >> "${sysctl_file}"
        fi
        if ! grep "$sgid" "${sysctl_file}" > /dev/null; then
            echo "# SecureLinks Link Traversal Protection Allowd Group Id" >> "${sysctl_file}"
            echo "$sgid = $linksafe" >> "${sysctl_file}"
        fi
        if ! grep "$hgid" "${sysctl_file}" > /dev/null; then
            echo "$hgid = $linksafe" >> "${sysctl_file}"
        fi
        sysctl -p >/dev/null 2>&1
        if id mailman > /dev/null 2>&1; then
            usermod -a -G linksafe mailman > /dev/null 2>&1
        fi
    fi
}

function disable_linksafe {
    local sysctl_file=$1
    sed -i "s/^fs\.protected_symlinks/#\ fs\.protected_symlinks/" "$sysctl_file"
    sed -i "s/^fs\.protected_hardlinks/#\ fs\.protected_hardlinks/" "$sysctl_file"
}

SGID="fs.protected_symlinks_allow_gid"
HGID="fs.protected_hardlinks_allow_gid"
SYSCTL_FILE="/etc/sysctl.conf"

SYSTEM_LINKSAFE_GID="$(getent group linksafe | cut -d: -f3)"

if [[ "$SYSTEM_LINKSAFE_GID" == "" ]]; then
    groupadd -r linksafe
fi

if [ -e /proc/sys/fs/protected_symlinks_allow_gid ]; then
    SYSCTL_LINKSAFE_GID=$(grep -F "$SGID" "$SYSCTL_FILE" | awk '{print $3}')
    if ! grep "$SGID" "$SYSCTL_FILE" > /dev/null || ! grep "$HGID" "$SYSCTL_FILE" > /dev/null; then
        initial_setup_linksafe "$SYSTEM_LINKSAFE_GID" "$SGID" "$HGID" "$SYSCTL_FILE"
    fi
    if [[ "$SYSCTL_LINKSAFE_GID" != "$SYSTEM_LINKSAFE_GID" ]]; then
        fix_linksafe
        sed -i -e "s/${SGID}\s*=.*/${SGID} = ${SYSTEM_LINKSAFE_GID}/" "$SYSCTL_FILE" &> /dev/null
        sed -i -e "s/${HGID}\s*=.*/${HGID} = ${SYSTEM_LINKSAFE_GID}/" "$SYSCTL_FILE" &> /dev/null
    fi
else
    disable_linksafe "$SYSCTL_FILE"
fi
