#!/bin/bash
# changes SANS values, recreates cert.conf

SPATH="$(dirname "$(readlink -f ${BASH_SOURCE[0]})")"    # dir of the script
SNAME="$(basename ${BASH_SOURCE[0]})"                    # name of the script

ASCEDSCONF='local site certbot hostconf'
ASCEDSLIBS='utils hosts postfix openssl'

if [ ! -r "${SPATH}/asceds-head" ] ; then
   echo "No header ${SPATH}/asceds-head. Exiting"
   exit 9
fi

. ${SPATH}/asceds-head

asceds-sans-update-usage()
{
  cat << ENDUSAGE

Usage: asceds-sans-update [-h] [-l] [-r] [-a <hostname>,...]  [-d <hostname>,...]
-h --> display usage and exit
-r --> set noreturn policy if client is read-only
-l --> local mode (appropriate for asceds-init)
-a <hostname>[,<hostname>,...] adds comma separated SAN values
-d <hostname>[,<hostname>,...] deletes comma separated SAN values

Refresh cert.conf according to the current version of asceds;
If no -a/-d, displays current configuration and goes into interactive mode;
Deletes SAN values from /etc/hosts, /etc/postfix/main.cf, openssl.cnf
Checks DNS records of SANs to be added; configures with the host IP address
Adds SAN values to /etc/hosts, /etc/postfix/main.cf, openssl.cnf
Refreshes ~asceds/cert.conf
Provides instructions to manually complete the action.

ENDUSAGE
exit 0
}

# initialize  SANS delete and add lists
SANS_DEL=''
SANS_ADD=''

# default noreturn is false for automatic update of the certs
SETNORETURN=''

# force config rebuild
LOCALMODE=''

# general validation and parse of the command line
for ARG in ${ARGS} ; do
   #echo "ARG=${ARG}"
   if [ "${ARG}" != "${ARG//[^-_a-zA-Z0-9.,]/}" ] ; then
      asceds-error "Malformed argument ${ARG}"
   elif [ "${ARG}" == "-h" ] ; then
      asceds-sans-update-usage
   elif [ "${ARG}" == "-r" ] ; then
      shift
      SETNORETURN='yes'
   elif [ "${ARG}" == "-l" ] ; then
      shift
      LOCALMODE='yes'
   elif [ "${ARG}" == "-a" ] ; then
      shift
      if [[ "$1" != -* ]] ; then
         NEWVAL=$( cat <<< $1 | tr '[:upper:]' '[:lower:]' )
         if [ -z "${SANS_ADD}" ] ; then
            SANS_ADD="${NEWVAL}"
         else 
            SANS_ADD="${SANS_ADD},${NEWVAL}"
         fi
      fi
   elif [ "${ARG}" == "-d" ] ; then
      shift
      if [[ "$1" != -* ]] ; then
         NEWVAL=$( cat <<< $1 | tr '[:upper:]' '[:lower:]' )
         if [ -z "${SANS_DEL}" ] ; then
            SANS_DEL="${NEWVAL}"
         else 
            SANS_DEL="${SANS_DEL},${NEWVAL}"
         fi
      fi
   else
      shift
   fi
done

# run as root only
asceds-run-asroot

# refresh cert.conf
asceds-build-certconf "${SETNORETURN}"

if [ -z "${SANS_ADD}" ] && [ -z "${SANS_DEL}" ] ; then
   asceds-client-showconf
   YE=''
   echo -n "Make interactive changes? [y/N] "
   read YE   
   if [ "${YE}" == 'y' ] || [ "${YE}" == 'Y' ] ; then
      # interactive mode
      YE=''
      while [ "${YE}" != 'y' ] && [ "${YE}" != 'Y' ] ; do
   
         # show current status
         read -e -p "Please type SANS to be ADDED: " SANS_ADD0
         echo
         read -e -p "Please type SANS to be REMOVED: " SANS_DEL0      
         echo
         
         asceds-client-showconf
         # check and sanitize input
         SANS_ADD=$( cat <<< ${SANS_ADD0} | tr '[:upper:]' '[:lower:]' )
         if [ "${SANS_ADD}" != "${SANS_ADD//[^-a-zA-Z0-9.,]/}" ] ; then
            asceds-warning "Malformed SANS list ${SANS_ADD}, skipping"
            SANS_ADD=''
         fi

         SANS_DEL=$( cat <<< ${SANS_DEL0} | tr '[:upper:]' '[:lower:]' )
         if [ "${SANS_DEL}" != "${SANS_DEL//[^-a-zA-Z0-9.,]/}" ] ; then
            asceds-warning "Malformed SANS list ${SANS_DEL}, skipping"
            SANS_DEL=''
         fi
      
         echo
         echo "SANS to be added: ${SANS_ADD}"
         echo "SANS to be deleted: ${SANS_DEL}"
      
         echo -n "Is this the desired change? [y/N] "
         read YE
      done
   fi
fi

if [ -n "${SANS_DEL}" ] ; then
   asceds-echo "SANS to be deleted: ${SANS_DEL}"
   
   # transform comma-separated lists into space separated-lists
   SANS_DEL=$( cat <<< "${SANS_DEL}" | sed -e "s/,/ /g" )
   for SANS_VAL in ${SANS_DEL} ; do
      asceds-echo "Deleting SANS value ${SANS_VAL}"
      asceds-validate-fqdn "${SANS_VAL}" || \
         asceds-error "Invalid FQDN ${SANS_VAL}"
      
      asceds-hosts-check "${SANS_VAL}" && asceds-hosts-del "${SANS_VAL}"
      asceds-postfix-check "${SANS_VAL}" && asceds-postfix-del "${SANS_VAL}"
      asceds-openssl-check "${SANS_VAL}" && asceds-openssl-del "${SANS_VAL}"
      
   done
fi

if [ -n "${SANS_ADD}" ] ; then
   asceds-echo "SANS to be added: ${SANS_ADD}"

   # transform comma-separated lists into space separated-lists
   SANS_ADD=$( cat <<< "${SANS_ADD}" | sed -e "s/,/ /g" )

   DOMAIN_NAME=$( hostname -f | tr '[:upper:]' '[:lower:]' )
   # find the host IP address
   asceds-ip-resolve "${DOMAIN_NAME}"
   HSTIPADDR="${ASCEDS_IP}"

   for SANS_VAL in ${SANS_ADD} ; do
      asceds-echo "Adding SANS value ${SANS_VAL}"
      asceds-validate-fqdn "${SANS_VAL}" || \
         asceds-error "Invalid FQDN ${SANS_VAL}"

      # find the SANS-associated IP address
      asceds-ip-resolve "${SANS_VAL}"
      IPADDR="${ASCEDS_IP}"
      
      if [ -z "${HSTIPADDR}" ] ; then
         asceds-error "Host doesn't have a DNS IP, check the network setup and try again."
      elif [ -z "${IPADDR}" ] ; then
         IPADDR="${HSTIPADDR}"
         asceds-warning "SANS value ${SANS_VAL} does not have a DNS record.
         Generating certificate, but this must be fixed to make the services functional"
      elif [ "${IPADDR}" != "${HSTIPADDR}" ] ; then
         # if the two are not identical, ask for confirmation to continue
         # add in /etc/hosts SANS value with the host IP address (warn about that)
         IPADDR="${HSTIPADDR}"
         asceds-warning "SANS value ${SANS_VAL} and the local host have different IPs.
         Using the local host IP address and generating certificate.
         Please fix the DNS records to make the services functional"
      fi

      asceds-hosts-check "${SANS_VAL}" || asceds-hosts-add "${SANS_VAL}" "${IPADDR}"
      asceds-postfix-check "${SANS_VAL}" || asceds-postfix-add "${SANS_VAL}"
      asceds-openssl-check "${SANS_VAL}" || asceds-openssl-add "${SANS_VAL}"
      
   done
fi 

if [ -n "${SANS_ADD}" ] || [ -n "${SANS_DEL}" ] ; then
   # create cert.conf
   asceds-build-certconf "${SETNORETURN}"
   # refresh cert parameters
   asceds-parse-certconf "${ASCEDSHOMEDIR}/cert.conf" 
   if [ "${CLIENT_DOMAIN_NAME}" != "${DOMAIN_NAME}" ] ; then
      asceds-error "Detected domain name differs from the contents of cert.conf"
   fi

   # display the configuration
   asceds-client-showconf

   # if in local mode, just exit
   if [ -n "${LOCALMODE}" ] ; then
      exit 0
   fi

   # final instructions
   echo
   if [ -n "${ASCEDSCRTMGR}" ] ; then
      echo "Please continue the setup on the ASCEDS website of the local certificate manager"
      echo "https://${ASCEDSCRTMGR}/cert/host_check.php?client_type=asceds&hostname=${DOMAIN_NAME%%.*}&domain=${DOMAIN_NAME#*.}"
   else
      echo "Please execute as root/sudo on the certificate manager:"
      echo "asceds-client-setup -q -c ${CLIENT_DOMAIN_NAME}"
   fi   
   echo "Then execute as root/sudo on this computer (or wait for cron to do it):"
   echo "asceds-service-reconfig -q -t"
fi

