File: /volume1/@appstore/MailPlus-Server/backend_hook/hookUtils.conf
#!/bin/bash
[ ! -z ${MAILPLUS_SERVER_LOG_UTIL+MAILPLUS_SERVER_LOG_DEFINED} ] || . /var/packages/MailPlus-Server/target/scripts/MailPlusServerLogUtil.sh
PACKAGE_NAME="MailPlus-Server"
PRIVATE_LOCATION="/var/packages/${PACKAGE_NAME}/target"
VOLUME=$(/usr/bin/readlink ${PRIVATE_LOCATION} | /usr/bin/cut -d '/' -f2)
CONF_TEMPLATE_DIR="${PRIVATE_LOCATION}/etc/template"
MAILPLUS_SERVER_BACKEND_BINARY="${PRIVATE_LOCATION}/bin/syno_mailserver_backend"
HAPROXY_BINARY="${PRIVATE_LOCATION}/sbin/haproxy"
CONFDEST_OUTPUT_DIR="/var/packages/MailPlus-Server/etc/mailconf.d/"
CONFDEST_OUTPUT_DIR_BAK="/var/packages/MailPlus-Server/etc/mailconf.d_bak/"
BACKEND_BINARY="${PRIVATE_LOCATION}/usr/bin/syno-mailplus-server-go-utils"
CALLBACK_BINARY="${PRIVATE_LOCATION}/bin/syno_action"
SET_CONF_BINARY="${PRIVATE_LOCATION}/bin/syno_set_config"
## Mail storage
MAIL_STORAGE_DIR_PATH="/var/spool/mail"
MAIL_STORAGE_DIR_PATH_BAK="/var/packages/${PACKAGE_NAME}/etc/MailDirBak"
DOVEADM_BINARY="${PRIVATE_LOCATION}/bin/doveadm"
DOVECOT_SCRIPT="${PRIVATE_LOCATION}/scripts/daemon/dovecot.sh"
POSTFIX_SCRIPT="/var/packages/${PACKAGE_NAME}/target/scripts/daemon/postfix.sh"
FIREWALL_REFRESH_FLAG="/tmp/.mailplus_server_firewall_refresh"
CURL_BACKEND_OPT="-s ${CURL_TIMEOUT} --cacert /var/packages/MailPlus-Server/etc/internal-ca-ssl/ca.crt --cert /var/packages/MailPlus-Server/etc/internal-ssl/client.crt --key /var/packages/MailPlus-Server/etc/internal-ssl/client.key"
BACKEND_IP="127.0.0.1"
BACKEND_PORT="8500"
BACKEND_PEER_PORT="8501"
SPOOL_MAILPLUS=/var/spool/@MailPlus-Server
SPOOL_MAILSCANNER=${SPOOL_MAILPLUS}/MailScanner
MAIL_SHARE_NAME="MailPlus"
SPAM_ACCOUNT="e14dd245-5d25-41b1-95da-2d1ee815cb89"
MAILPLUS_TMP_PRE_BUILD_DIR_LIST="/run/lock/mailplus_server /run/mailplus_server /run/mailplus_server/mimedefang /tmp/mailplus_server /tmp/mailplus_server/service_status /tmp/mailplus_server/service_status_db"
TMP_MAILPLUS_SERVER_DIR="/tmp/mailplus_server"
SCRIPT_LOCK_WAIT_DIR="/tmp/mailplus_server/script_lock_wait"
IPV4_REGEXP="^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"
containString()
{
local substr=$1
local str=$2
if [ "${str}" == "" ]; then
return 1
fi
[ -z "${str##*"$substr"*}" ]
}
getHostID()
{
${MAILPLUS_SERVER_BACKEND_BINARY} --getHostID
}
getHostIP()
{
${MAILPLUS_SERVER_BACKEND_BINARY} --getHostIP
}
getHostIF()
{
${MAILPLUS_SERVER_BACKEND_BINARY} --getHostIF
}
getLockFullName()
{
if [ -n "$1" ]; then
echo "script_lock/$1"
else
echo "script_lock/common_lock"
fi
}
getLockWaitingkDir()
{
if [ -n "$1" ]; then
echo "${SCRIPT_LOCK_WAIT_DIR}/$1"
else
echo "${SCRIPT_LOCK_WAIT_DIR}/common_lock"
fi
}
getLockWaitingKey()
{
echo "$$"
}
shouldWaitingLock() {
local lockWaitingDir=$1
local lockWaitingName=$2
local lockWaitingKeys=
local oldestPid=
# if the directory does not exist, we do not waiting at all
if [ ! -d "${TMP_MAILPLUS_SERVER_DIR}" ]; then
debug_log "tmp dir does not exist, skip waiting check"
return 1
fi
mkdir -p "${lockWaitingDir}"
chown "MailPlus-Server:system" "${SCRIPT_LOCK_WAIT_DIR}"
if ! ( ls "${lockWaitingDir}/${lockWaitingName}" || \
cat "/proc/$$/cmdline" > "${lockWaitingDir}/${lockWaitingName}"); then
err_log "failed to create lock waiting key [${lockWaitingName}]"
return 0
fi
if ! lockWaitingKeys=$(ls -tr "${lockWaitingDir}"); then
err_log "failed to list lock waiting keys"
return 0
fi
for key in ${lockWaitingKeys}
do
if [ ! -d "/proc/${key}" ] || [ "$(cat /proc/$$/cmdline)" != "$(cat ${lockWaitingDir}/${key})" ]; then
rm -f "${lockWaitingDir}/${key}"
continue
fi
oldestPid=${key}
break
done
if [ -z "${oldestPid}" -o "$$" = "${oldestPid}" ]; then
return 1
fi
return 0
}
acquireClusterLock()
{
# acuireClusterLock <lock_name> [ttl]
local lockName="$(getLockFullName $1)"
local lockWaitingDir=$(getLockWaitingkDir "$1")
local lockWaitingName=$(getLockWaitingKey)
local ttl=0
if [ -n "$2" ]; then
ttl="$2"
fi
if shouldWaitingLock "${lockWaitingDir}" "${lockWaitingName}"; then
return 1
fi
if ${BACKEND_BINARY} backend-command --command create --key "${lockName}" --value "locked" --ttl "${ttl}"; then
rm -f "${lockWaitingDir}/${lockWaitingName}" || \
err_log "failed to remove waiting lock key ${lockWaitingDir}/${lockWaitingName}"
return 0
fi
return 1
}
releaseClusterLock()
{
# releaseClusterLock <lock_name>
local lockName="$(getLockFullName $1)"
local lockWaitingDir=$(getLockWaitingkDir "$1")
local lockWaitingName=$(getLockWaitingKey)
${BACKEND_BINARY} backend-command --command del --key "${lockName}" || \
err_log "failed to remove lock key ${lockName}"
rm -f "${lockWaitingDir}/${lockWaitingName}"
}
isLoadBalancer()
{
${MAILPLUS_SERVER_BACKEND_BINARY} --isBalancerMaster
}
getWeight()
{
local weight_list=$1
local server=$2
local serv=""
for serv in ${weight_list}; do
id=`echo "${serv}" | cut -d ":" -f1`
weight=`echo "${serv}" | cut -d ":" -f2`
ip="$(${MAILPLUS_SERVER_BACKEND_BINARY} --idToIP "${id}")"
if [ "${server}" = "${ip}" ]; then
echo "${weight}"
return
fi
done
}
isPrefixKeyChanged()
{
local changedKey
local changedKeysArray=(${_MAIL_mailserver_trigger_events})
for changedKey in "${changedKeysArray[@]}"
do
if [[ "${changedKey}" == "${1}"* ]]; then
return 0
fi
done
return 1
}
isKeyChanged()
{
local key="$1"
local changedKey="${_MAIL_mailserver_trigger_events}"
if containString "${key} " "${changedKey}"; then
return 0
else
return 1
fi
}
isTreeChanged()
{
local key=$1
local changedTree=${_MAIL_mailserver_trigger_tree}
if containString "${key}" "${changedTree}"; then
return 0
else
return 1
fi
}
reloadSmtp()
{
local trigger_keys="$1"
## Convert syno config
if ! ${SET_CONF_BINARY} "smtp" "${trigger_keys}"; then
err_log "failed to set conf smtp"
return 1
fi
## Actions
if ! ${CALLBACK_BINARY} "smtp" "${trigger_keys}"; then
err_log "failed to callback smtp"
return 1
fi
return 0
}
imapPop3PortGet()
{
local servType="$1"
local imapPort="143"
local imapsPort="993"
local pop3Port="110"
local pop3sPort="995"
if [ "${servType}" == "imap" ]; then
echo "${imapPort}"
elif [ "${servType}" == "imaps" ]; then
local imapsEnable="$(${MAILPLUS_SERVER_BACKEND_BINARY} --getConfKeyVal "imaps_enabled")"
if [ "yes" != "${imapsEnable}" ]; then
imapsPort="0"
fi
echo "${imapsPort}"
elif [ "${servType}" == "pop3" ]; then
local pop3Enable="$(${MAILPLUS_SERVER_BACKEND_BINARY} --getConfKeyVal "pop3_enabled")"
if [ "yes" != "${pop3Enable}" ]; then
pop3Port="0"
fi
echo "${pop3Port}"
elif [ "${servType}" == "pop3s" ]; then
local pop3sEnable="$(${MAILPLUS_SERVER_BACKEND_BINARY} --getConfKeyVal "pop3s_enabled")"
if [ "yes" != "${pop3sEnable}" ]; then
pop3sPort="0"
fi
echo "${pop3sPort}"
fi
}
GenerateInternalCert()
{
local depot="/tmp/mailplus_server/.deopt"
local etcdCa="${PRIVATE_LOCATION}/usr/bin/etcd-ca --depot-path $depot"
## Due to updater may run when package stop and link is not ready so have to use real path
local caDir="/var/packages/MailPlus-Server/etc/internal-ca-ssl"
local sslDir="/var/packages/MailPlus-Server/etc/internal-ssl"
local caCertPath="${caDir}/ca.crt"
local caKeyPath="${caDir}/ca.key"
local caInfoPath="${caDir}/ca.crt.info"
local certPath="${sslDir}/server.crt"
local keyPath="${sslDir}/server.key"
local clientCertPath="${sslDir}/client.crt"
local clientKeyPath="${sslDir}/client.key"
local passphrase="--passphrase asdf"
local keyBits=1024
local certHostname="syno.interanl.ca"
local certIP="127.0.0.1"
# location for temporary depot
rm -rf $depot 2>/dev/null
oriUmask=$(umask)
umask 022
if [ "$1" != "onlyCert" ]; then
if [ -e ${caCertPath} ]; then
return
fi
mkdir ${caDir} ${sslDir}
chown MailPlus-Server:MailPlus-Server ${caDir} ${sslDir}
# create ca
$etcdCa init --key-bits ${keyBits} $passphrase
$etcdCa export | tar xvf -
mv "ca.crt" ${caCertPath}
mv "ca.key" ${caKeyPath}
cp "${depot}/ca.crt.info" ${caInfoPath}
chown MailPlus-Server:MailPlus-Server ${caCertPath} ${caKeyPath} ${caInfoPath}
chmod 640 ${caCertPath} ${caKeyPath} ${caInfoPath}
# create certificate for client
$etcdCa new-cert --key-bits ${keyBits} $passphrase client
$etcdCa sign $passphrase client
$etcdCa export --insecure $passphrase client | tar xvf -
mv "client.crt" "${clientCertPath}"
mv "client.key.insecure" "${clientKeyPath}"
chown MailPlus-Server:MailPlus-Server ${clientCertPath} ${clientKeyPath}
chmod 640 ${clientCertPath} ${clientKeyPath}
fi
# create certificate for server
if [ ! -e $depot ]; then
mkdir -p $depot
cp -a ${caCertPath} ${depot}
cp -a ${caKeyPath} ${depot}
cp -a ${caInfoPath} ${depot}
chmod 666 -R ${depot}
fi
# Get node ip list
local ipList="$(${MAILPLUS_SERVER_BACKEND_BINARY} --getHostIPList)"
local ip=""
for ip in ${ipList}; do
certIP="${certIP},${ip}"
done
$etcdCa new-cert --key-bits ${keyBits} $passphrase --ip $certIP --domain $certHostname server
$etcdCa sign $passphrase server
$etcdCa export --insecure $passphrase server | tar xvf -
mv "server.crt" "${certPath}"
mv "server.key.insecure" "${keyPath}"
chown MailPlus-Server:MailPlus-Server ${certPath} ${keyPath}
chmod 640 ${certPath} ${keyPath}
rm -rf $depot 2>/dev/null
umask ${oriUmask}
return 0
}
GenerateInternalCaChain()
{
local caDir="/var/packages/MailPlus-Server/etc/internal-ca-ssl"
local caChainPath="${caDir}/chain-ca.pem"
local crt=""
rm -f ${caChainPath}
# Only iterator *.crt file
for crt in ${caDir}/*.crt; do
cat ${crt} >> ${caChainPath}
echo "" >> ${caChainPath}
done
chown MailPlus-Server:MailPlus-Server ${caChainPath}
chmod 640 ${caChainPath}
}
getNonBalancerNodeIP()
{
local IPList="$(${MAILPLUS_SERVER_BACKEND_BINARY} --listPeersIP)"
local BALANCER_MASTER_IP="$(${MAILPLUS_SERVER_BACKEND_BINARY} --getMasterBalancer)"
local RESULT_IP=""
local IP=""
for IP in $IPList
do
if [ "${IP}" != "${BALANCER_MASTER_IP}" ]; then
RESULT_IP=${IP}
fi
done
echo ${RESULT_IP}
}
GetMailPlusSharePath()
{
local share=$(/usr/syno/sbin/synoshare --get "${MAIL_SHARE_NAME}" | grep "Path " | sed -e 's?.*\[\(\S*\)\].*?\1?')
echo ${share}
}
AddAclEntryIfnotExist()
{
local path=$1
local aclEntry=$2
if [ ! -e "${path}" -o -z "${aclEntry}" ]; then
return 1
fi
local grepedAcl=$(/usr/syno/bin/synoacltool -get "${path}" | grep "${aclEntry}")
if [ -n "${grepedAcl}" ]; then
return 0
fi
/usr/syno/bin/synoacltool -add "${path}" "${aclEntry}"
}
PrepareMailPlusShareEnv()
{
local volume=`echo $1 | sed -e 's/\///g'`
local installVolume=`/usr/bin/readlink ${PRIVATE_LOCATION} | /usr/bin/cut -d'/' -f2`
local mailScannerVolume=${installVolume}/@MailPlus-Server/MailScanner
local sharePath="$(GetMailPlusSharePath)"
local quarantineDir="/${sharePath}/@quarantine"
local virusQuarantineDir="/${quarantineDir}/virus"
local mcpQuarantineDir="/${quarantineDir}/mcp"
local spamDataDir="/${sharePath}/@spamdata"
local spamReportDir="${spamDataDir}/spamreport"
local hamReportDir="${spamDataDir}/hamreport"
local autoLearnDir="${spamDataDir}/autolearn"
local autoLearnDirOld="${sharePath}/${SPAM_ACCOUNT}"
if [ -z "${sharePath}" ]; then
/usr/syno/bin/synowebapi --exec api=SYNO.Core.Share method=create version=1 name=$MAIL_SHARE_NAME shareinfo="{\"name\":\"$MAIL_SHARE_NAME\",\"desc\":\"Synology MailPlus\",\"vol_path\":\"/$volume\",\"enable_share_cow\":false}" || err_log "failed to create ${MAIL_SHARE_NAME} on ${volume}"
sharePath="$(GetMailPlusSharePath)"
fi
if [ -s "${sharePath}" -a -d "${sharePath}" ]; then
AddAclEntryIfnotExist "${sharePath}" "owner:*:allow:rwxpdDaARWcCo:fd--"
AddAclEntryIfnotExist "${sharePath}" "everyone:*:allow:--x----------:fd--"
if [ ! -d "${sharePath}/spamassassin" ]; then
mkdir "${sharePath}/spamassassin"
chown -R postfix "${sharePath}/spamassassin"
fi
rm -fr "${MAIL_STORAGE_DIR_PATH}"
ln -sfn "${sharePath}" "${MAIL_STORAGE_DIR_PATH}"
rm -fr ${mailScannerVolume}/spamassassin
ln -sfn ${MAIL_STORAGE_DIR_PATH}/spamassassin ${mailScannerVolume}/spamassassin
else
err_log "MailPlus share folder does not exist"
fi
# prepare folders for quarantine
if [ ! -d "${quarantineDir}" ]; then
mkdir "${quarantineDir}"
chmod 700 "${quarantineDir}"
chown admin:users "${quarantineDir}"
fi
if [ ! -d "${virusQuarantineDir}" ]; then
mkdir "${virusQuarantineDir}"
chmod 700 "${virusQuarantineDir}"
chown admin:users "${virusQuarantineDir}"
fi
if [ ! -d "${mcpQuarantineDir}" ]; then
mkdir "${mcpQuarantineDir}"
chmod 700 "${mcpQuarantineDir}"
chown admin:users "${mcpQuarantineDir}"
fi
# prepare folders for spam learning
if [ ! -d "${spamDataDir}" ]; then
mkdir "${spamDataDir}"
chmod 700 "${spamDataDir}"
chown admin:users "${spamDataDir}"
fi
if [ ! -d "${spamReportDir}" ]; then
mkdir "${spamReportDir}"
chmod 700 "${spamReportDir}"
chown admin:users "${spamReportDir}"
fi
if [ ! -d "${hamReportDir}" ]; then
mkdir "${hamReportDir}"
chmod 700 "${hamReportDir}"
chown admin:users "${hamReportDir}"
fi
if [ ! -d "${autoLearnDir}" ] && [ -d "${autoLearnDirOld}" ]; then
mv "${autoLearnDirOld}" "${autoLearnDir}"
elif [ ! -d "${autoLearnDir}" ]; then
mkdir "${autoLearnDir}"
chmod 700 "${autoLearnDir}"
chown admin:users "${autoLearnDir}"
cp "${PRIVATE_LOCATION}/scripts/sieve_after/spam_account.sieve.template" "${autoLearnDir}/.dovecot.sieve"
chmod 755 "${autoLearnDir}/.dovecot.sieve"
chown admin:users "${autoLearnDir}/.dovecot.sieve"
fi
return 0
}
loadEnv()
{
local envFile="/tmp/mailplus_server/env_output"
if [ -f "${envFile}" ]; then
. ${envFile}
fi
}
CreatePreBuildDir()
{
local dir=""
for dir in ${MAILPLUS_TMP_PRE_BUILD_DIR_LIST}; do
mkdir -p ${dir}
chmod 755 "${dir}"
chown MailPlus-Server:MailPlus-Server -R ${dir}
done
}
RemovePreBuildDir()
{
local dir=""
for dir in ${MAILPLUS_TMP_PRE_BUILD_DIR_LIST}; do
rm -fr ${dir}
done
}
setMasterInterface()
{
local NODE_INET=$(${MAILPLUS_SERVER_BACKEND_BINARY} --getHostIF)
local balancerIface=$(${MAILPLUS_SERVER_BACKEND_BINARY} --getBalancerIF)
local enable_balancer_address="$(${MAILPLUS_SERVER_BACKEND_BINARY} --getConfKeyVal "enable_balancer_address")"
local balancerAddress="$(${MAILPLUS_SERVER_BACKEND_BINARY} --getConfKeyVal "balancer_address")"
local balancerNetmask="$(${MAILPLUS_SERVER_BACKEND_BINARY} --getConfKeyVal "balancer_netmask")"
if [ "${enable_balancer_address}" == "no" ]; then
/usr/sbin/ifconfig "${balancerIface}" down
return 0
fi
if [ "" == "${balancerIface}" -o "" == "${balancerAddress}" -o "" == "${balancerNetmask}" ];then
log_err "Failed to set new balancer info addr[${balancerAddress}] netmask[${balancerNetmask}] interface[${balancerIface}]"
return 1
fi
if isLoadBalancer; then
/usr/sbin/ifconfig "${balancerIface}" "${balancerAddress}" netmask "${balancerNetmask}" up
/usr/sbin/arping -A -U -I "${NODE_INET}" "${balancerAddress}" -w 10 &
else
/usr/sbin/ifconfig "${balancerIface}" down
fi
return 0
}
getInterfaceIP()
{
local IF_NAME=$1
local RETRY_TIMES=0
local IP=
IP=$(${MAILPLUS_SERVER_BACKEND_BINARY} --getIFIP "$IF_NAME")
if [ -n "${IP}" ]; then
echo "${IP}"
return 0
fi
while [ ${RETRY_TIMES} -lt 2 ];
do
IP=$(/sbin/ifconfig "${IF_NAME}" | grep "inet addr" | awk -F: '{print $2}' | awk '{print $1}')
if [[ "${IP}" =~ ${IPV4_REGEXP} ]]; then
echo "${IP}"
return
fi
RETRY_TIMES=$((RETRY_TIMES + 1))
sleep 1
done
}
bringDownMPSinterface()
{
local master_if=$1
ip addr list | grep -o -P '\b\S+(?=:MPS$)' |
while read -r if_name
do
if [ -n "${if_name}" -a "${if_name}" != "${master_if}" ]; then
info_log "remove alias interface "${if_name}":MPS"
ifconfig "${if_name}:MPS" down
fi
done
}
GetMailAccountBaseDir() {
## Get current domain
local domainName="@local"
local nodeId=$(getHostID)
if [ $? -ne 0 -o -z "${nodeId}" ]; then
return 1
fi
local volumeConfigKey="general_storage_volume-${nodeId}"
local storageVolume="$(${MAILPLUS_SERVER_BACKEND_BINARY} --getConfKeyVal "${volumeConfigKey}")"
local accountType="$(${MAILPLUS_SERVER_BACKEND_BINARY} --getConfKeyVal "account_type")"
if [ $? -ne 0 ]; then
return 1
fi
if [ "${accountType}" == "win" ]; then
domainName="$(${MAILPLUS_SERVER_BACKEND_BINARY} --getConfKeyVal "win_domain_short_name")"
elif [ "${accountType}" == "ldap" ]; then
domainName="$(${MAILPLUS_SERVER_BACKEND_BINARY} --getConfKeyVal "acc_domain_name")"
fi
if [ -z "${storageVolume}" -o -z "${domainName}" ]; then
return 1
fi
echo "/${storageVolume}/${MAIL_SHARE_NAME}/${domainName}"
return 0
}