193 lines
6.8 KiB
Bash
193 lines
6.8 KiB
Bash
# Executes a command inside the postfix container.
|
|
function postfixExec() {
|
|
k3sRun exec -it deploy/"$postfixKube" -c "$postfixKube" -- "$@"
|
|
}
|
|
|
|
# Executes a command inside a specific Postfix pod.
|
|
# $1 (pod): pod name.
|
|
# $@ (...): command and arguments to execute.
|
|
function postfixPodExec() {
|
|
local pod="$1"
|
|
[[ -n "$pod" ]] || { appError "Pod not specified"; return 1; }
|
|
shift || true
|
|
|
|
k3sRun exec pod/"$pod" -c "$postfixKube" -- "$@"
|
|
}
|
|
|
|
# Converts a domain name to a random 64-char postfix ID.
|
|
function postfixDomain2id() {
|
|
domainToRandom "$1" 64
|
|
}
|
|
|
|
# Reloads the Postfix daemon.
|
|
function postfixReload() {
|
|
postfixExec postfix reload
|
|
}
|
|
|
|
# Creates or updates a Postfix SASL user.
|
|
# $1 (login): SASL username.
|
|
# $2 (password): password.
|
|
function postfixUserSet() {
|
|
local login="$1" password="$2"
|
|
[[ -n "$login" ]] || { appError "Login not specified"; return 1; }
|
|
[[ -n "$password" ]] || { appError "Password not specified"; return 1; }
|
|
|
|
local error
|
|
runError error postfixExec \
|
|
env SASL_LOGIN="$login" SASL_PWD="$password" SASL_DB="/config/sasldb2" SASL_REALM="$postfixDefaultRealm" \
|
|
sh -lc 'printf "%s\n" "$SASL_PWD" | saslpasswd2 -p -c -f "$SASL_DB" -u "$SASL_REALM" "$SASL_LOGIN"' || {
|
|
appError "Failed to create/update SASL user $login: $error"
|
|
return 1
|
|
}
|
|
}
|
|
|
|
# Deletes a Postfix SASL user.
|
|
# $1 (login): SASL username.
|
|
function postfixUserRemove() {
|
|
local login="$1"
|
|
[[ -n "$login" ]] || { appError "Login not specified"; return 1; }
|
|
|
|
local error
|
|
runError error postfixExec saslpasswd2 -d -f "/config/sasldb2" -u "$postfixDefaultRealm" "$login" || {
|
|
appError "Failed to delete SASL user $login"
|
|
return 1
|
|
}
|
|
}
|
|
|
|
# Lists all SASL users from the sasldb2 database.
|
|
function postfixUserList() {
|
|
local output error
|
|
run output error postfixExec sasldblistusers2 -f /config/sasldb2 || { appError "$error"; return 1; }
|
|
|
|
awk -F':' '
|
|
/^[[:space:]]*$/ { next }
|
|
{ gsub(/[[:space:]]+$/, "", $1); print $1 }
|
|
' <<<"$output"
|
|
}
|
|
|
|
# Rebuilds the senders map from the current SASL user list.
|
|
function postfixSendersRebuild() {
|
|
local outFile="$postfixConfigPath/$postfixSendersFile"
|
|
|
|
local saslList error
|
|
run saslList error postfixUserList || { appError "Failed to get SASL list: $error"; return 1; }
|
|
|
|
local logins
|
|
logins=$(awk 'NF' <<<"$saslList" | paste -sd ',' -)
|
|
|
|
local tmpOut
|
|
tmpOut=$(mktemp)
|
|
[[ -n "$logins" ]] && printf '%s %s\n' "$postfixPostmaster" "$logins" > "$tmpOut"
|
|
mv -f "$tmpOut" "$outFile"
|
|
}
|
|
|
|
function postfixConfigRebuild() {
|
|
local domain="$1"
|
|
if [[ -n "$domain" ]]; then
|
|
postfixDomainSet "$domain"
|
|
fi
|
|
|
|
local error
|
|
# runError error postfixExec postmap "lmdb:/config/$postfixDomainsFile" || { appError "Failed rebuild $postfixDomainsFile: $error"; return 1; }
|
|
# runError error postfixExec postmap "lmdb:/config/$postfixAliasesFile" || { appError "Failed rebuild $postfixAliasesFile: $error"; return 1; }
|
|
runError error postfixExec postmap "lmdb:/config/$postfixSendersFile" || { appError "Failed rebuild $postfixSendersFile: $error"; return 1; }
|
|
}
|
|
|
|
function postfixDomainSet() {
|
|
local domain="$1"
|
|
[[ -n "$domain" ]] || { appError "Domain not specified"; return 1; }
|
|
domainCheck "$domain" || return 1
|
|
|
|
local pfxId
|
|
pfxId=$(postfixDomain2id "$domain")
|
|
local postfixUser postfixPass
|
|
postfixUser=$(siteConfigGetOrSet "$domain" "postfixUser" "$pfxId")
|
|
postfixPass=$(siteConfigGetOrCreate "$domain" "postfixPass")
|
|
|
|
postfixUserSet "$postfixUser" "$postfixPass" || return 1
|
|
postfixSendersRebuild
|
|
postfixConfigRebuild
|
|
}
|
|
|
|
function postfixDomainRemove() {
|
|
local domain="$1"
|
|
[[ -n "$domain" ]] || { appError "Domain not specified"; return 1; }
|
|
|
|
local postfixUser
|
|
postfixUser=$(siteConfigGet "$domain" "postfixUser")
|
|
[[ -n "$postfixUser" ]] || { appError "postfixUser not found"; return 1; }
|
|
|
|
postfixUserRemove "$postfixUser"
|
|
postfixSendersRebuild
|
|
postfixConfigRebuild
|
|
}
|
|
|
|
# Reloads the opendkim daemon.
|
|
function postfixDkimReload() {
|
|
postfixExec sh -lc "pkill -HUP -f '/usr/sbin/opendkim' 2>/dev/null" || true
|
|
}
|
|
|
|
# Lists domains that have DKIM key material present.
|
|
function postfixDkimList() {
|
|
local f
|
|
for f in "$postfixDkimPath/keys/"*.txt; do
|
|
[[ -f "$f" ]] || continue
|
|
basename -- "$f" .txt
|
|
done
|
|
}
|
|
|
|
# Generates a DKIM keypair for a domain and updates SigningTable/KeyTable.
|
|
# $1 (domain): domain name.
|
|
function postfixDkimAdd() {
|
|
local domain="$1"
|
|
[[ -n "$domain" ]] || { appError "Domain not specified"; return 1; }
|
|
|
|
if [[ ! -s "$postfixDkimPath/keys/$domain.private" || ! -s "$postfixDkimPath/keys/$domain.txt" ]]; then
|
|
postfixExec sh -lc "
|
|
set -e
|
|
mkdir -p /etc/opendkim/keys
|
|
opendkim-genkey -b 2048 -r -D '/etc/opendkim/keys' -d '$domain' -s '$postfixDkimSelector'
|
|
mv -f \"/etc/opendkim/keys/$postfixDkimSelector.private\" \"/etc/opendkim/keys/$domain.private\"
|
|
mv -f \"/etc/opendkim/keys/$postfixDkimSelector.txt\" \"/etc/opendkim/keys/$domain.txt\"
|
|
chown opendkim:opendkim \"/etc/opendkim/keys/$domain.private\" \"/etc/opendkim/keys/$domain.txt\" || true
|
|
chmod 0600 \"/etc/opendkim/keys/$domain.private\"
|
|
chmod 0644 \"/etc/opendkim/keys/$domain.txt\"
|
|
" || { appError "Failed to generate DKIM keys for $domain"; return 1; }
|
|
fi
|
|
|
|
local domainEsc="${domain//./\\.}"
|
|
local selectorEsc="${postfixDkimSelector//./\\.}"
|
|
sed -i "/^\*@${domainEsc}[[:space:]]/d" "$postfixDkimPath/SigningTable"
|
|
sed -i "/^${selectorEsc}\._domainkey\.${domainEsc}[[:space:]]/d" "$postfixDkimPath/KeyTable"
|
|
|
|
printf '*@%s %s._domainkey.%s\n' "$domain" "$postfixDkimSelector" "$domain" >> "$postfixDkimPath/SigningTable"
|
|
printf '%s._domainkey.%s %s:%s:/etc/opendkim/keys/%s.private\n' \
|
|
"$postfixDkimSelector" "$domain" "$domain" "$postfixDkimSelector" "$domain" >> "$postfixDkimPath/KeyTable"
|
|
|
|
postfixDkimReload
|
|
}
|
|
|
|
# Ensures DKIM keys exist for a domain and returns the TXT record.
|
|
# $1 (domain): domain name.
|
|
function postfixDkimGet() {
|
|
local domain="$1"
|
|
[[ -n "$domain" ]] || { appError "Domain not specified"; return 1; }
|
|
domainCheck "$domain" || return 1
|
|
postfixDkimAdd "$domain" || return 1
|
|
cat "$postfixDkimPath/keys/$domain.txt" 2>/dev/null || true
|
|
}
|
|
|
|
# Removes DKIM table entries for a domain and reloads opendkim.
|
|
# $1 (domain): domain name.
|
|
function postfixDkimRemove() {
|
|
local domain="$1"
|
|
[[ -n "$domain" ]] || { appError "Domain not specified"; return 1; }
|
|
|
|
local domainEsc="${domain//./\\.}"
|
|
local selectorEsc="${postfixDkimSelector//./\\.}"
|
|
sed -i "/^\*@${domainEsc}[[:space:]]/d" "$postfixDkimPath/SigningTable"
|
|
sed -i "/^${selectorEsc}\._domainkey\.${domainEsc}[[:space:]]/d" "$postfixDkimPath/KeyTable"
|
|
|
|
postfixDkimReload
|
|
}
|