#!/usr/bin/env bash

VULS_USER=${VULS_USER:=vuls-saas}
VULS_GROUP=${VULS_GROUP:=vuls-saas}
VULS_ROOT_DIR=${VULS_ROOT_DIR:=/opt/vuls-saas}

VULS_SAAS_GROUPID=${VULS_SAAS_GROUPID:=null}
VULS_SAAS_TOKEN=${VULS_SAAS_TOKEN:=null}

VULS_INSTALLER_REPO=${VULS_INSTALLER_REPO:=https://installer.vuls.biz}
VULS_AUTH_URL=${VULS_AUTH_URL:=https://auth.vuls.biz/one-time-auth}
VULS_SCAN_MODE=${VULS_SCAN_MODE:="fast-root"}
VULS_SCAN_OFFLINE=${VULS_SCAN_OFFLINE:="dummy"}
VULS_PROXY=${VULS_PROXY:=null}
AUTO_REFRESH_BINARY=${AUTO_REFRESH_BINARY:=true}


function mylogger(){
    local now=`date '+%Y/%m/%d %H:%M:%S'`
    local str="${now} [$1\t]:\t$2"
    echo -e "${str}\r"
    echo -e "${str}\r" >> ./vuls-installer.log
}

function chkRootUser() {
  if [ ${EUID:-${UID}} != 0 ]; then
    mylogger "ERROR" "Please run as root user."
    exit 1
  fi
  mylogger "SUCCESS" "Check root user."
}

function chkDistribution (){
  dist=""  #global
  if [ `cat /etc/*-release | grep "Red Hat" | wc -l` -ne 0 ]; then
      dist='redhat'
  fi
  if [ `cat /etc/*-release | grep CentOS | wc -l` -ne 0 ]; then
      dist='centos'
  fi
  if [ `cat /etc/*-release | grep Amazon | wc -l` -ne 0 ]; then
      dist='amazon'
  fi
  if [ `cat /etc/*-release | grep Oracle | wc -l` -ne 0 ]; then
      dist='oracle'
  fi
  if [ `cat /etc/*-release | grep Debian | wc -l` -ne 0 ]; then
      dist='debian'
  fi
  if [ `cat /etc/*-release | grep Ubuntu | wc -l` -ne 0 ]; then
      dist='ubuntu'
  fi
  if [ `cat /etc/*-release | grep SUSE | wc -l` -ne 0 ]; then
      dist='suse'
  fi
  if [ `cat /etc/*-release | grep Fedora | wc -l` -ne 0 ]; then
      dist='fedora'
  fi
  if [ `cat /etc/*-release | grep Rocky | wc -l` -ne 0 ]; then
      dist='rocky'
  fi
  if [ `cat /etc/*-release | grep AlmaLinux | wc -l` -ne 0 ]; then
      dist='alma'
  fi
  if [ `uname -a | grep FreeBSD | wc -l` -ne 0 ]; then
      dist='freebsd'
  fi

  if [ -z "${dist}" ];then
    local dist=`uname -a`
    mylogger "ERROR" "It's an unsupported distribution. [OS: ${dist}]"
    exit 1
  fi
  mylogger "SUCCESS" "Check distribution. [OS: ${dist}]"
}


function chkArchitecture (){
  arch=`uname -m`   #global

  if [ "${arch}" = "" ]; then
    mylogger "ERROR" "Architecture unknown."
    exit 1
  fi

  if [ "${arch}" != "x86_64" -a "${arch}" != "i686" -a "${arch}" != "aarch64" ]; then
    mylogger "ERROR" "Architecture unknown. [arch: ${arch}]"
    exit 1
  fi
  mylogger "SUCCESS" "Check Architecture [arch: ${arch}]"
}

chkOsPkgStatus() {
  case "${dist}" in
    redhat|centos|oracle|rocky|alma|fedora)
      out="$(dnf -q check --assumeno 2>&1)"
      if [ -n "$(echo "$out" | grep -v '^[[:space:]]*$')" ]; then
        mylogger "ERROR" "Package dependency issues detected. Run 'dnf -q check' to identify problems, then fix with 'dnf install <package>'."
        exit 1
      fi
      ;;
    amazon)
      amzn_ver=""
      if [ -r /etc/os-release ]; then
        amzn_ver=$(grep '^VERSION_ID=' /etc/os-release | cut -d= -f2 | tr -d '"')
      fi
      if [ -z "$amzn_ver" ] && [ -r /etc/system-release ]; then
        amzn_ver=$(sed 's/^.*release \([0-9.]*\).*$/\1/' /etc/system-release)
      fi

      pkg_mgr="dnf"
      if [ "$amzn_ver" = "1" ] || [ "$amzn_ver" = "2" ]; then
        pkg_mgr="yum"
      fi

      check_opts="-q check --assumeno"

      out=$(timeout 4 $pkg_mgr $check_opts 2>&1)

      if [ -n "$(echo "$out" | grep -v '^[[:space:]]*$')" ]; then
        mylogger "ERROR" "Package dependency issues detected. Run '$pkg_mgr check' to identify problems, then fix with '$pkg_mgr install <package>'."
        exit 1
      fi
      ;;
    debian|ubuntu)
      out="$(dpkg --audit 2>&1)"
      if [ -n "$(echo "$out" | grep -v '^[[:space:]]*$')" ]; then
        mylogger "ERROR" "Package configuration or dependency issues detected. Run 'dpkg --configure -a' to fix."
        exit 1
      fi
      ;;
    suse)
      out="$(zypper --non-interactive --no-refresh verify --dry-run 2>&1)"
      if ! echo "$out" | grep -q "Dependencies of all installed packages are satisfied"; then
        mylogger "ERROR" "Package dependency issues detected. Run 'zypper verify -y && zypper update -y' to fix."
        exit 1
      fi
      ;;
    *)
    ;;
  esac
  mylogger "SUCCESS" "Check OS Package Status."
}

installPkg() {
  local i_dist=$1

  if [ "${i_dist}" = "redhat" -o "${i_dist}" = "centos" -o "${i_dist}" = "oracle" -o "${i_dist}" = "rocky" -o "${i_dist}" = "alma" ]; then
    yum install -y yum-utils lsof >> ./vuls-installer.log 2>&1
    if [ $? -ne 0 ]; then
      mylogger "ERROR" "yum install aborted. please see vuls-installer.log"
      exit 1
    fi
    mylogger "SUCCESS" "Install package. [yum-utils lsof]"
  fi

  if [ "${i_dist}" = "amazon" ]; then
    yum install -y yum-utils lsof cronie >> ./vuls-installer.log 2>&1
    if [ $? -ne 0 ]; then
      mylogger "ERROR" "yum install aborted. please see vuls-installer.log"
      exit 1
    fi
    mylogger "SUCCESS" "Install package. [yum-utils lsof cronie]"

    systemctl start crond.service
    systemctl enable crond.service
  fi

  if [ "${i_dist}" = "fedora" ]; then
    dnf install -y yum-utils lsof >> ./vuls-installer.log 2>&1
    if [ $? -ne 0 ]; then
      mylogger "ERROR" "dnf install aborted. please see vuls-installer.log"
      exit 1
    fi
    mylogger "SUCCESS" "Install package. [yum-utils lsof]"
  fi

  if [ "${i_dist}" = "debian" ]; then
    apt-get update  >> ./vuls-installer.log 2>&1
    apt-get install -y --no-install-recommends aptitude reboot-notifier debian-goodies lsof >> ./vuls-installer.log 2>&1
    if [ $? -ne 0 ]; then
      mylogger "ERROR" "apt-get install aborted. please see vuls-installer.log"
      exit 1
    fi
    mylogger "SUCCESS" "Install package. [aptitude, reboot-notifier, debian-goodies]"
  fi

  if [ "${i_dist}" = "ubuntu" ]; then
    apt-get update  >> ./vuls-installer.log 2>&1
    apt-get install -y --no-install-recommends debian-goodies  >> ./vuls-installer.log 2>&1
    if [ $? -ne 0 ]; then
      mylogger "ERROR" "apt-get install aborted. please see vuls-installer.log"
      exit 1
    fi
    mylogger "SUCCESS" "Install package. [debian-goodies]"
  fi
}

createUserAndGroup() {
  local i_dist=$1
  if [ "${i_dist}" = "redhat" -o "${i_dist}" = "centos" -o "${i_dist}" = "amazon" -o "${i_dist}" = "oracle" -o "${i_dist}" = "suse" -o "${i_dist}" = "fedora" -o "${i_dist}" = "rocky" -o "${i_dist}" = "alma" ]; then
    sbincmds=("groupadd" "useradd" "passwd")
    for cmd in "${sbincmds[@]}"; do
      if ! command -v $cmd &> /dev/null; then
        mylogger "ERROR" "command $cmd is not found."
        exit 1
      fi
    done
    if [ `cat /etc/group | grep ${VULS_GROUP} | wc -l` -eq 0 ]; then
      groupadd "${VULS_GROUP}" >> ./vuls-installer.log 2>&1
      mylogger "SUCCESS" "Create group. [group: ${VULS_GROUP}]"
    else
      mylogger "SKIP" "Create group. Already exist. [group: ${VULS_GROUP}]"
    fi
    if [ `cat /etc/passwd | grep ${VULS_USER} | wc -l` -eq 0 ]; then
      useradd -m -g "${VULS_GROUP}" "${VULS_USER}" >> ./vuls-installer.log 2>&1
      passwd -l ${VULS_USER} >> ./vuls-installer.log 2>&1
      mylogger "SUCCESS" "Create user. [user: ${VULS_USER}]"
    else
      mylogger "SKIP" "Create user. Already exist. [user: ${VULS_USER}]"
    fi
  fi

  if [ "${i_dist}" = "debian" -o "${i_dist}" = "ubuntu" -o "${i_dist}" = "freebsd" ]; then
    sbincmds=("adduser")
    for cmd in "${sbincmds[@]}"; do
      if ! command -v $cmd &> /dev/null; then
        mylogger "ERROR" "command $cmd is not found."
        exit 1
      fi
    done
    if [ `cat /etc/passwd | grep ${VULS_USER} | wc -l` -eq 0 ]; then
      adduser "${VULS_USER}" --gecos "${VULS_USER},${VULS_GROUP},Room Number,WorkPhone,HomePhone" --disabled-password >> ./vuls-installer.log 2>&1
      mylogger "SUCCESS" "Create user and group. [user: ${VULS_USER} / group: ${VULS_GROUP}]"
    else
      mylogger "SKIP" "Create user and group. Already exist. [user: ${VULS_USER} / group: ${VULS_GROUP}]"
    fi
  fi
}

createDir() {
  if [ ! -d "${VULS_ROOT_DIR}" ]; then
    mkdir -p "${VULS_ROOT_DIR}"
    chown "${VULS_USER}":"${VULS_USER}" "${VULS_ROOT_DIR}"
    chmod 770 "${VULS_ROOT_DIR}"
    mylogger "SUCCESS" "Create directory. [${VULS_ROOT_DIR}]"
  else
    mylogger "SKIP" "Create directory. Already exist. [${VULS_ROOT_DIR}]"
  fi

  if [ ! -d "/var/log/vuls" ]; then
    mkdir -p /var/log/vuls
    chown "${VULS_USER}":"${VULS_USER}" /var/log/vuls
    chmod 770 /var/log/vuls
    mylogger "SUCCESS" "Create directory. [/var/log/vuls]"
  else
    mylogger "SKIP" "Create directory. Already exist. [/var/log/vuls]"
  fi
}

downloadBinary() {
  local i_dist=$1
  local i_arch=$2

  local binType=""
  if [ "${i_dist}" = "redhat" -o "${i_dist}" = "centos" -o "${i_dist}" = "amazon" -o "${i_dist}" = "oracle" -o "${i_dist}" = "debian" -o "${i_dist}" = "ubuntu" -o "${i_dist}" = "suse" -o "${i_dist}" = "fedora" -o "${i_dist}" = "rocky" -o "${i_dist}" = "alma" ]; then
    binType="linux"
  fi
  
  if [ "${i_dist}" = "freebsd" ]; then
    binType="freebsd"  
  fi

  curl -L -s -o ${VULS_ROOT_DIR}/vuls ${VULS_INSTALLER_REPO}/vuls_${binType}_${arch}
  if [ $? -ne 0 ]; then
    mylogger "ERROR" "Download binary failer. [type: ${binType}_${arch}]"
    exit 1
  fi
  chown "${VULS_USER}":"${VULS_GROUP}" "${VULS_ROOT_DIR}/vuls"
  chmod 770 ${VULS_ROOT_DIR}/vuls
  mylogger "SUCCESS" "Download binary. [${VULS_ROOT_DIR}/vuls   type: ${binType}_${arch}]"
}

downloadScript() {
  curl -L -s -o ${VULS_ROOT_DIR}/vuls-saas.sh ${VULS_INSTALLER_REPO}/vuls-saas.sh
  if [ $? -ne 0 ]; then
    mylogger "ERROR" "Download script."
    exit 1
  fi
  chown "${VULS_USER}":"${VULS_GROUP}" "${VULS_ROOT_DIR}/vuls-saas.sh"
  chmod 770 ${VULS_ROOT_DIR}/vuls-saas.sh
  if [ ${VULS_PROXY} != null ]; then
    sed -i "s|^# PROXY=.*|PROXY='${VULS_PROXY}'|" ${VULS_ROOT_DIR}/vuls-saas.sh
  fi
  if [ ${AUTO_REFRESH_BINARY} == false ]; then
    sed -i "s/^AUTO_REFRESH_BINARY=.*/AUTO_REFRESH_BINARY=false/" ${VULS_ROOT_DIR}/vuls-saas.sh
  fi
  mylogger "SUCCESS" "Download script. [${VULS_ROOT_DIR}/vuls-saas.sh]"
}

createConfig() {
  if [ ! -e "${VULS_ROOT_DIR}/config.toml" ]; then
    host=`hostname | sed 's/\./_/g'`
    if [ -z "$host" ]; then
      host="localhost"
    fi
    cat > "${VULS_ROOT_DIR}/config.toml" << EOF
[servers]

[servers.${host}]
host        = "localhost"
port        = "local"
user        = "${VULS_USER}"
scanMode    = ["${VULS_SCAN_MODE}" , "${VULS_SCAN_OFFLINE}"]

[saas]
GroupID = ${VULS_SAAS_GROUPID}
Token = "${VULS_SAAS_TOKEN}"
URL = "${VULS_AUTH_URL}"

EOF

    if [ "${VULS_SCAN_OFFLINE}" = "dummy" ]; then
      sed -i 's/\"dummy\"//g' "${VULS_ROOT_DIR}/config.toml"
    fi

    chown "${VULS_USER}":"${VULS_GROUP}" "${VULS_ROOT_DIR}/config.toml"
    chmod 660 "${VULS_ROOT_DIR}/config.toml"
    mylogger "SUCCESS" "Create config. [${VULS_ROOT_DIR}/config.toml]"
  else 
    mylogger "SKIP" "Create config. Already exist. [${VULS_ROOT_DIR}/config.toml]"
  fi
}

createSudoers() {
  if [ ! -d "/etc/sudoers.d" ]; then
    mkdir /etc/sudoers.d
    mylogger "INFO" "Create directory. [/etc/sudoers.d]"
  fi

  local i_dist=$1

  if [ "${VULS_SCAN_MODE}" = "fast-root" ]; then
    if [ "${i_dist}" = "redhat" -o "${i_dist}" = "oracle" -o "${i_dist}" = "fedora" ]; then
      echo "${VULS_USER} ALL=(ALL) NOPASSWD:SETENV: /usr/bin/stat, /usr/bin/needs-restarting, /usr/bin/which, /usr/bin/repoquery, /usr/bin/yum makecache --assumeyes, /bin/ls -l /proc/*/exe, /bin/cat, /usr/bin/lsof -i -P -n, /usr/sbin/lsof -i -P -n, /opt/ds_agent/dsa_query, /usr/bin/test, /usr/bin/find, /usr/bin/cat"  > /etc/sudoers.d/vuls-saas
    fi

    if [ "${i_dist}" = "centos" -o "${i_dist}" = "amazon" -o "${i_dist}" = "rocky" -o "${i_dist}" = "alma" ]; then
      echo "${VULS_USER} ALL=(ALL) NOPASSWD:SETENV: /usr/bin/stat, /usr/bin/needs-restarting, /usr/bin/which, /bin/ls -l /proc/*/exe, /bin/cat, /usr/bin/lsof -i -P -n, /usr/sbin/lsof -i -P -n, /opt/ds_agent/dsa_query, /usr/bin/test, /usr/bin/find, /usr/bin/cat" > /etc/sudoers.d/vuls-saas
    fi

    if [ "${i_dist}" = "debian" -o "${i_dist}" = "ubuntu" ]; then
      echo "${VULS_USER} ALL=(ALL) NOPASSWD:SETENV: /usr/bin/apt-get update, /usr/bin/stat *, /usr/sbin/checkrestart, /bin/ls -l /proc/*/exe, /bin/cat, /usr/bin/lsof -i -P -n, /opt/ds_agent/dsa_query, /usr/bin/test, /opt/ds_agent/dsa_query, /usr/bin/test, /usr/bin/find, /usr/bin/cat" > /etc/sudoers.d/vuls-saas
    fi

    echo "Defaults:${VULS_USER} !requiretty" >> /etc/sudoers.d/vuls-saas

    # sudo-rs (Ubuntu 25.10+/Debian trixie+ default sudo) rejects argument
    # wildcards and requiretty. Strip them so the file parses. NOTE: these sed
    # patterns are coupled to the wildcards in the echo lines above; update the
    # sed if you add a new argument wildcard.
    if sudo --version 2>/dev/null | grep -qi 'sudo-rs'; then
      sed -i -e 's/ \*//g' -e 's| -l /proc/\*/exe||g' -e '/^Defaults:.*!requiretty/d' /etc/sudoers.d/vuls-saas
    fi

    # A malformed sudoers file breaks sudo for everyone, so validate it and, if
    # invalid, remove it and abort rather than leave the system broken.
    if command -v visudo >/dev/null 2>&1; then
      if ! visudo -c -f /etc/sudoers.d/vuls-saas >> ./vuls-installer.log 2>&1; then
        rm -f /etc/sudoers.d/vuls-saas
        mylogger "ERROR" "Invalid sudoers file generated. [/etc/sudoers.d/vuls-saas]"
        exit 1
      fi
    fi

    chmod 0440 /etc/sudoers.d/vuls-saas

    mylogger "SUCCESS" "Create sudoers. [/etc/sudoers.d/vuls-saas]"
  fi
}

createCron() {
  if [ ! -e  "/etc/cron.d/vuls-saas-scan" ]; then
    if [ ! -d "/etc/cron.d" ]; then
      mkdir /etc/cron.d
      mylogger "INFO" "Create directory. [/etc/cron.d]"
    fi

    time_h=`date -d '5 minutes' '+%H'`
    time_m=`date -d '5 minutes' '+%M'`
    echo "${time_m} ${time_h} * * * ${VULS_USER} ${VULS_ROOT_DIR}/vuls-saas.sh >/dev/null 2>&1" > /etc/cron.d/vuls-saas-scan
    chown root:root "/etc/cron.d/vuls-saas-scan"
    chmod 644 "/etc/cron.d/vuls-saas-scan"
    mylogger "SUCCESS" "Create cron. [/etc/cron.d/vuls-saas-scan]"
  else 
    mylogger "SKIP" "Create cron. Already exist. [/etc/cron.d/vuls-saas-scan]"
  fi
}

delete() {
  if [ `grep ${VULS_USER} /etc/passwd | wc -l` -ne 0 ]; then
    userdel ${VULS_USER}
    mylogger "SUCCESS" "Delete user. [${VULS_USER}]"
  fi

  if [ `grep ${VULS_GROUP} /etc/group | wc -l` -ne 0 ]; then
    groupdel ${VULS_GROUP}
    mylogger "SUCCESS" "Delete group. [${VULS_GROUP}]"
  fi

  if [ -d ${VULS_ROOT_DIR} ]; then
    rm -r ${VULS_ROOT_DIR}
    mylogger "SUCCESS" "Delete directory. [${VULS_ROOT_DIR}]"
  fi

  if [ -d /var/log/vuls ]; then
    rm -r /var/log/vuls
    mylogger "SUCCESS" "Delete directory. [/var/log/vuls]"
  fi

  if [ -e /etc/sudoers.d/vuls-saas ]; then
    rm /etc/sudoers.d/vuls-saas
    mylogger "SUCCESS" "Delete sudoers settting. [/etc/sudoers.d/vuls-saas]"
  fi

  if [ -e /etc/cron.d/vuls-saas-scan ]; then
    rm /etc/cron.d/vuls-saas-scan
    mylogger "SUCCESS" "Delete cron setting. [/etc/cron.d/vuls-saas-scan]"
  fi
}

main() {
  args="$1"
  case "${args}" in
  "inst")
    mylogger "START" "Install scanner."
    chkRootUser
    chkDistribution
    chkArchitecture
    chkOsPkgStatus ${dist}
    installPkg ${dist}
    createUserAndGroup ${dist}
    createDir
    downloadBinary ${dist} ${arch}
    downloadScript
    createConfig
    createSudoers ${dist}
    createCron
    mylogger "END" "Install scanner finish."
    ;;
  "del")
    mylogger "START" "Uninstall scanner."
    chkRootUser
    delete
    mylogger "END" "Uninstall scanner finish."
    ;;
  * )
    mylogger "ERROR" "Args not found."
    ;;
  esac
}

main $1
exit 0
