#!/bin/bash
#
# ***** BEGIN LICENSE BLOCK *****
# Zimbra Collaboration Suite Server
# Copyright (C) 2011, 2013, 2014, 2015, 2016 Synacor, Inc.
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software Foundation,
# version 2 of the License.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along with this program.
# If not, see <https://www.gnu.org/licenses/>.
# ***** END LICENSE BLOCK *****
#

if [ "$(whoami)" != "zimbra" ]; then
  echo "$0 must be run as user zimbra"
  exit 1
fi
umask 027

source /opt/zimbra/bin/zmshutil || exit 1
zmsetvars -f

exp_thres_days=${zimbra_zmcertmgr_expiration_threshold:=30}
exp_thres_secs=$(($exp_thres_days*24*60*60))

zimbra_domain_cert_directory=/opt/zimbra/conf/domaincerts

ERROR_PREFIX="ERROR:"

saveConfigKey() {
  local key=$1
  local file=$2
  local location=$3
  local content=$(cat "$file")
  if [ "$location" = "global" ]; then
    local zmprov_opts="mcf"
  elif [ "$location" = "server" ]; then
    local zmprov_opts="ms ${zimbra_server_hostname}"
  elif [ "$location" = "domain" ]; then
    local domain=$4
    local zmprov_opts="md $domain"
  else
    echo "Unknown config section $location"
    return
  fi

  echo -n "** Saving $location config key $key..."
  /opt/zimbra/bin/zmprov -m -l ${zmprov_opts} "$key" "$content" 2> /dev/null
  if [ $? = 0 ]; then
    echo "done."
  else
    echo "failed."
  fi
}

cleanConfigKey() {
  local key=$1
  local location=$2
  if [ "$location" = "global" ]; then
    local zmprov_opts="mcf"
  elif [ "$location" = "server" ]; then
    local zmprov_opts="ms ${zimbra_server_hostname}"
  elif [ "$location" = "domain" ]; then
    local domain=$3
    local zmprov_opts="md $domain"
  else
    echo "Unknown config section $location"
    return
  fi

  echo -n "** Clean $location config key $key..."
  /opt/zimbra/bin/zmprov -m -l ${zmprov_opts} "$key" "" 2> /dev/null
  if [ $? = 0 ]; then
    echo "done."
  else
    echo "failed."
  fi
}

loadConfigKey() {
  local key=$1
  local file=$2
  local location=$3
  if [ "$location" = "global" ]; then
    local zmprov_opts="gacf"
  elif [ "$location" = "server" ]; then
    local server=$4
    if [ "$server" = "" ]; then
      server="${zimbra_server_hostname}"
    fi
    local zmprov_opts="gs $server"
  elif [ "$location" = "domain" ]; then
    local domain=$4
    local zmprov_opts="gd $domain"
  else
    echo "Unknown config section $location"
    return
  fi
  TMPDIR="${zimbra_tmp_directory}"
  local tmpfile=`mktemp -t zmcertmgr.XXXXXX 2> /dev/null` || { echo "Failed to create tmpfile"; exit 1; }
  if [ ! -s "$file" ]; then
    echo -n "** Retrieving $location config key $key..."
    /opt/zimbra/bin/zmprov -m -l ${zmprov_opts} "${key}" | sed  -e 's/^${key}: //' > "$tmpfile" 2> /dev/null && mv -f "$tmpfile" "$file" 2> /dev/null
    if [ $? = 0 -a -s "$file" ]; then
      chmod 400 "$file" 2> /dev/null
      echo "done."
    else
      echo "failed."
    fi
  fi
  rm -f "$tmpfile" 2> /dev/null
}

deployCerts() {
  if [ "$1" = "-force" ]; then
    if [ -d "$zimbra_domain_cert_directory" ]; then
      rm -rf "$zimbra_domain_cert_directory" > /dev/null 2>&1
    fi
  fi

  DOMAINS=$(/opt/zimbra/bin/zmprov -m -l garpd | awk '{print $1}')
  if [ $? != 0 ]; then
    echo "Unable to retrieve list of domains with SSL certificates";
    exit 1
  fi

  for i in ${DOMAINS}; do
    echo -n "** Deploying cert for $i..."
    getClientCertFromLdap "$i" > /dev/null 2>&1
    if [ $? = 0 ]; then
      echo "done."
    else
      echo "failed."
    fi

  done
}

saveClientCertToLdap() {
  target=$1
  current_crt=$2
  if [ ! -e "$current_crt" ]; then
    echo "$ERROR_PREFIX Certificate file $current_crt does not exist."
    return
  fi

  if [ "$target" = "global" ]; then
    saveConfigKey "zimbraReverseProxyClientCertCA" "$current_crt" "global"
    return
  fi

  if [ "$target" = "server" ]; then
    saveConfigKey "zimbraReverseProxyClientCertCA" "$current_crt" "server"
    return
  fi

  domain=$target
  if [ "$domain" = "" ]; then
    echo "$ERROR_PREFIX Domain must be specified."
    return
  fi

  saveConfigKey "zimbraReverseProxyClientCertCA" "$current_crt" "domain" "$domain"
}

cleanClientCertFromLdap() {
  target=$1
  if [ "$target" = "global" ]; then
    cleanConfigKey "zimbraReverseProxyClientCertCA" "global"
    return
  fi

  if [ "$target" = "server" ]; then
    cleanConfigKey "zimbraReverseProxyClientCertCA" "server"
    return
  fi

  domain=$target
  if [ "$domain" = "" ]; then
    echo "$ERROR_PREFIX Domain must be specified."
    return
  fi

  cleanConfigKey "zimbraReverseProxyClientCertCA" "domain" "$domain"
}


getClientCertFromLdap() {
  domain=$1
  if [ "$domain" = "" ]; then
    echo "$ERROR_PREFIX Domain must be specified"
  fi
  if [ ! -d "$zimbra_domain_cert_directory" ]; then
    mkdir -p "$zimbra_domain_cert_directory"
  fi
  chmod 755 "$zimbra_domain_cert_directory" 2> /dev/null
  current_crt="${zimbra_domain_cert_directory}/${domain}.client.crt"

  loadConfigKey "zimbraReverseProxyClientCertCA" "$current_crt" "domain" "$domain"
}

usage () {
  rc=${1:-1}
  echo "Usage:
  $0 -h | --help
  $0 savecrt <domain> <cert file>
  $0 savecrt server <cert file>
  $0 savecrt global <cert file>
  $0 cleancrt <domain>
  $0 cleancrt server
  $0 cleancrt global
"
  exit $rc;
}

###Main Execution###

if [[ $# = 0 ]]; then
  usage
fi

ACTION="$1"
shift

# check for valid usage
if [[ "$ACTION" = "savecrt" ]]; then
  saveClientCertToLdap "$@"
elif [[ "$ACTION" = "cleancrt" ]]; then
  cleanClientCertFromLdap "$@"
else
  for arg in "$ACTION" "$@"; do
    [[ "$arg" =~ ^-?-h ]] && usage 0
  done
  echo "$ERROR_PREFIX unknown argument(s): $ACTION $@"
  usage
fi

exit 0
