Merge branch 'dma-type' into 'master'
Add __mail_alias, __dma* types See merge request ungleich-public/cdist-contrib!6
This commit is contained in:
commit
f4375dbbb9
30 changed files with 1357 additions and 9 deletions
|
@ -1,21 +1,29 @@
|
|||
#!/bin/sh
|
||||
#!/bin/sh -eu
|
||||
|
||||
SHELLCHECKCMD="shellcheck -s sh -f gcc -x"
|
||||
SHELLCHECKCMD='shellcheck -s sh -f gcc -x'
|
||||
# Skip SC2154 for variables starting with __ since such variables are cdist
|
||||
# environment variables.
|
||||
SHELLCHECK_SKIP=': __.*is referenced but not assigned.*\[SC2154\]'
|
||||
SHELLCHECKTMP=".shellcheck.tmp"
|
||||
SHELLCHECKTMP='.shellcheck.tmp'
|
||||
|
||||
# Move to top-level cdist-contrib directory.
|
||||
cd $(dirname $0)/..
|
||||
cd "$(dirname $0)"/..
|
||||
|
||||
check() {
|
||||
find type/ -type f $1 $2 -exec ${SHELLCHECKCMD} {} + | grep -v "${SHELLCHECK_SKIP}" > "${SHELLCHECKTMP}"
|
||||
test ! -s "${SHELLCHECKTMP}" || { cat "${SHELLCHECKTMP}"; exit 1; }
|
||||
find type/ -type f "$@" -exec ${SHELLCHECKCMD} {} + \
|
||||
| grep -v "${SHELLCHECK_SKIP}" >>"${SHELLCHECKTMP}" || true
|
||||
}
|
||||
|
||||
check -path "*/explorer/*"
|
||||
check -path "*/files/*.sh"
|
||||
rm -f "${SHELLCHECKTMP}"
|
||||
|
||||
check -path '*/explorer/*'
|
||||
check -path '*/files/*' -name '*.sh'
|
||||
check -name manifest
|
||||
check -name gencode-local
|
||||
check -name gencode-remote
|
||||
|
||||
if test -s "${SHELLCHECKTMP}"
|
||||
then
|
||||
cat "${SHELLCHECKTMP}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
|
49
type/__dma/explorer/auth_conf
Executable file
49
type/__dma/explorer/auth_conf
Executable file
|
@ -0,0 +1,49 @@
|
|||
#!/bin/sh -e
|
||||
#
|
||||
# 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch)
|
||||
#
|
||||
# This file is part of cdist.
|
||||
#
|
||||
# cdist 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, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# cdist 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 cdist. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# This explorer determines the path of dma's auth.conf file
|
||||
|
||||
# No dma.conf -> use default
|
||||
test -f /etc/dma/dma.conf || {
|
||||
echo /etc/dma/auth.conf
|
||||
exit 0
|
||||
}
|
||||
test -r /etc/dma/dma.conf || {
|
||||
echo 'Cannot read /etc/dma/dma.conf' >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Get AUTHPATH from dma.conf
|
||||
awk -F'[ \t]' '
|
||||
{
|
||||
sub(/#.*$/, "", $0) # remove comments
|
||||
if (!$0) next # ignore empty lines
|
||||
}
|
||||
$1 == "AUTHPATH" {
|
||||
# Store authpath. In dma conf parsing last wins.
|
||||
if ($2) authpath = substr($0, index($0, " ") + 1)
|
||||
}
|
||||
END {
|
||||
if (authpath) {
|
||||
print authpath
|
||||
exit 0
|
||||
} else exit 1
|
||||
}
|
||||
' /etc/dma/dma.conf \
|
||||
|| echo /etc/dma/auth.conf # default
|
34
type/__dma/explorer/conf
Executable file
34
type/__dma/explorer/conf
Executable file
|
@ -0,0 +1,34 @@
|
|||
#!/bin/sh -e
|
||||
#
|
||||
# 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch)
|
||||
#
|
||||
# This file is part of cdist.
|
||||
#
|
||||
# cdist 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, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# cdist 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 cdist. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# This explorer returns a sorted list of "active" (= non-commented) lines
|
||||
# in the dma.conf file.
|
||||
# "Trailing" line comments are stripped off.
|
||||
#
|
||||
# NOTE: This explorer assumes that the sort(1) utility supports the non-POXIX
|
||||
# -s (stable sort) option.
|
||||
|
||||
CONF_PATH=/etc/dma # set in Makefile
|
||||
dma_conf="${CONF_PATH:?}/dma.conf"
|
||||
|
||||
test -f "${dma_conf}" || exit 0
|
||||
|
||||
grep -v -e '^[ \t]*#\|^$' "${dma_conf}" \
|
||||
| sed -e 's/[ \t]*#.*$//' \
|
||||
| sort -s -k 1,1
|
178
type/__dma/files/update_dma_conf.awk
Normal file
178
type/__dma/files/update_dma_conf.awk
Normal file
|
@ -0,0 +1,178 @@
|
|||
#!/usr/bin/awk -f
|
||||
#
|
||||
# 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch)
|
||||
#
|
||||
# This file is part of cdist.
|
||||
#
|
||||
# cdist 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, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# cdist 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 cdist. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
function comment_line(line) {
|
||||
# returns the position in line at which the comment's text starts
|
||||
# (0 if the line is not a comment)
|
||||
match(line, /^[ \t]*\#+[ \t]*/)
|
||||
return RSTART ? (RLENGTH + 1) : 0
|
||||
}
|
||||
function empty_line(line) { return line ~ /^[ \t]*$/ }
|
||||
function is_word(s) { return s ~ /^[A-Z_]+$/ } # "looks like a plausible word"
|
||||
|
||||
function first(line, sep_re) {
|
||||
# returns the part of the line until sep is found
|
||||
# (or the whole line if sep is not found)
|
||||
if (!sep_re) sep_re = "[" SUBSEP "]"
|
||||
match(line, sep_re)
|
||||
return RSTART ? substr(line, 1, RSTART - 1) : line
|
||||
}
|
||||
|
||||
function rest(line, sep_re) {
|
||||
# returns the part of the line after the first occurrence of sep is found.
|
||||
# (or nothing if sep is not found)
|
||||
if (!sep_re) sep_re = "[" SUBSEP "]"
|
||||
if (match(line, sep_re))
|
||||
return substr(line, RSTART + RLENGTH)
|
||||
}
|
||||
|
||||
function conf_pop(word, value) {
|
||||
# returns the next value for the config `word` and delete it from the list.
|
||||
# if value is set, this function will only return value if it is the first
|
||||
# option in the list, otherwise it returns 0.
|
||||
|
||||
if (!(word in conf)) return 0
|
||||
if (!value) {
|
||||
if (index(conf[word], SUBSEP)) # more than one element?
|
||||
value = substr(conf[word], 1, index(conf[word], SUBSEP) - 1)
|
||||
else
|
||||
value = conf[word]
|
||||
}
|
||||
|
||||
if (index(conf[word], SUBSEP)) {
|
||||
if (index(conf[word], value SUBSEP) != 1) return 0
|
||||
conf[word] = substr(conf[word], length(value) + 2)
|
||||
} else {
|
||||
if (conf[word] != value) return 0
|
||||
delete conf[word]
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
function print_conf(word, value) {
|
||||
# print a config line with the given parameters
|
||||
printf "%s", word
|
||||
if (value) printf " %s", value
|
||||
printf "\n"
|
||||
}
|
||||
|
||||
function print_confs(word, value) {
|
||||
# print config lines for all values stored in conf[word].
|
||||
if (!(word in conf)) return
|
||||
if (conf[word]) {
|
||||
while (value = conf_pop(word))
|
||||
print_conf(word, value)
|
||||
} else {
|
||||
print_conf(word)
|
||||
delete conf[word]
|
||||
}
|
||||
}
|
||||
|
||||
BEGIN {
|
||||
FS = "\n"
|
||||
EQS = "[ \t]" # copied from dma/conf.c
|
||||
|
||||
if (ARGV[2]) exit (e=1)
|
||||
|
||||
# Loop over file twice!
|
||||
ARGV[2] = ARGV[1]
|
||||
ARGC++
|
||||
|
||||
# read the "should" state into the `conf` array.
|
||||
while (getline < "/dev/stdin") {
|
||||
word = first($0, EQS)
|
||||
if ((word in conf))
|
||||
conf[word] = conf[word] SUBSEP rest($0, EQS)
|
||||
else
|
||||
conf[word] = rest($0, EQS)
|
||||
}
|
||||
}
|
||||
|
||||
# first pass, gather information about where which information is stored in the
|
||||
# current config file. This information will be used in the second pass.
|
||||
NR == FNR {
|
||||
if (comment_line($0)) {
|
||||
# comment line
|
||||
word = first(substr($0, comment_line($0)), " ")
|
||||
if (is_word(word)) last_occ["#" word] = FNR
|
||||
} else {
|
||||
word = first($0, EQS)
|
||||
if (is_word(word)) last_occ[word] = FNR
|
||||
}
|
||||
}
|
||||
|
||||
# before second pass prepare hashes containing location information to be used
|
||||
# in the second pass.
|
||||
NR > FNR && FNR == 1 {
|
||||
# First we drop the locations of commented-out options if a non-commented
|
||||
# option is available. If a non-commented option is available, we will
|
||||
# append new config options there to have them all at one place.
|
||||
for (k in last_occ)
|
||||
if (k ~ /^\#/ && (substr(k, 2) in last_occ))
|
||||
delete last_occ[k]
|
||||
|
||||
# Reverse the option => line mapping. The line_map allows for easier lookups
|
||||
# in the second pass.
|
||||
for (k in last_occ) line_map[last_occ[k]] = k
|
||||
}
|
||||
|
||||
# second pass, generate and output new config
|
||||
NR > FNR {
|
||||
if (comment_line($0) || empty_line($0)) {
|
||||
# comment or empty line
|
||||
print
|
||||
|
||||
if ((FNR in line_map)) {
|
||||
if (line_map[FNR] ~ /^\#/) {
|
||||
# This line contains a commented config option. If the conf hash
|
||||
# contains options to be set, we output them here because this
|
||||
# option is not used in the current config.
|
||||
k = substr(line_map[FNR], 2)
|
||||
if ((k in conf)) print_confs(k)
|
||||
}
|
||||
|
||||
if (("INSECURE" in conf) && line_map[FNR] ~ /^\#?SECURE$/) {
|
||||
# INSECURE goes where SECURE comment is.
|
||||
print_confs("INSECURE")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
word = first($0, EQS)
|
||||
value = rest($0, EQS)
|
||||
sub(/[ \t]*\#.*$/, "", value) # ignore comments in value
|
||||
|
||||
if ((word in conf) && value == first(conf[word])) {
|
||||
# keep config options we want
|
||||
conf_pop(word)
|
||||
print
|
||||
}
|
||||
|
||||
if ((FNR in line_map) && line_map[FNR] == word) {
|
||||
# rest of config options should be here
|
||||
print_confs(word)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
END {
|
||||
if (e) exit
|
||||
|
||||
# print rest of config options (
|
||||
for (word in conf) print_confs(word)
|
||||
}
|
177
type/__dma/gencode-remote
Executable file
177
type/__dma/gencode-remote
Executable file
|
@ -0,0 +1,177 @@
|
|||
#!/bin/sh -e
|
||||
#
|
||||
# 2020 Dennis Camera (dennis.camera@ssrq-sds-fds.ch)
|
||||
#
|
||||
# This file is part of cdist.
|
||||
#
|
||||
# cdist 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, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# cdist 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 cdist. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
quote() { printf "'%s'" "$(printf '%s' "$*" | sed -e "s/'/'\\\\''/g")"; }
|
||||
drop_awk_comments() { quote "$(sed '/^[[:blank:]]*#.*$/d;/^$/d' "$@")"; }
|
||||
|
||||
CONF_PATH=/etc/dma # set in Makefile
|
||||
|
||||
# Determine mailname
|
||||
if test -f "${__object:?}/parameter/mailname"
|
||||
then
|
||||
mailname=$(cat "${__object:?}/parameter/mailname")
|
||||
else
|
||||
case $(cat "${__global:?}/explorer/os")
|
||||
in
|
||||
(debian|devuan|ubuntu)
|
||||
# On Debian-like systems use /etc/mailname unless --mailname is used
|
||||
mailname='/etc/mailname'
|
||||
;;
|
||||
(*)
|
||||
mailname=${__target_fqdn:?}
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
|
||||
# Generate "should" values for config
|
||||
conf_should=$(
|
||||
if test -s "${__object:?}/parameter/smarthost"
|
||||
then
|
||||
printf 'SMARTHOST %s\n' "$(cat "${__object:?}/parameter/smarthost")"
|
||||
fi
|
||||
|
||||
printf 'MAILNAME %s\n' "${mailname}"
|
||||
|
||||
if test -s "${__object:?}/explorer/auth_conf"
|
||||
then
|
||||
printf "AUTHPATH %s\n" "$(cat "${__object:?}/explorer/auth_conf")"
|
||||
fi
|
||||
|
||||
case $(cat "${__object:?}/parameter/security")
|
||||
in
|
||||
(ssl|tls)
|
||||
default_smtp_port=465
|
||||
echo 'SECURETRANSFER'
|
||||
;;
|
||||
(starttls)
|
||||
default_smtp_port=587
|
||||
echo 'SECURETRANSFER'
|
||||
echo 'STARTTLS'
|
||||
;;
|
||||
(opportunistic)
|
||||
default_smtp_port=25
|
||||
echo 'SECURETRANSFER'
|
||||
echo 'STARTTLS'
|
||||
echo 'OPPORTUNISTIC_TLS'
|
||||
;;
|
||||
(insecure)
|
||||
default_smtp_port=25
|
||||
echo 'INSECURE'
|
||||
;;
|
||||
esac
|
||||
|
||||
if test -s "${__object:?}/parameter/port"
|
||||
then
|
||||
printf 'PORT %u\n' "$(cat "${__object:?}/parameter/port")"
|
||||
elif test "${default_smtp_port}" -ne 25 # DMA uses port 25 by default
|
||||
then
|
||||
printf 'PORT %u\n' "${default_smtp_port}"
|
||||
fi
|
||||
|
||||
if test -f "${__object:?}/parameter/masquerade"
|
||||
then
|
||||
while read -r line
|
||||
do
|
||||
printf 'MASQUERADE %s\n' "${line}"
|
||||
done <"${__object:?}/parameter/masquerade"
|
||||
fi
|
||||
|
||||
if test -f "${__object:?}/parameter/defer"
|
||||
then
|
||||
echo 'DEFER'
|
||||
fi
|
||||
|
||||
if test -f "${__object:?}/parameter/fullbounce"
|
||||
then
|
||||
echo 'FULLBOUNCE'
|
||||
fi
|
||||
|
||||
if test -f "${__object:?}/parameter/nullclient"
|
||||
then
|
||||
test -s "${__object:?}/parameter/smarthost" || {
|
||||
echo '--nullclient requires a --smarthost to be defined' >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo 'NULLCLIENT'
|
||||
fi
|
||||
)
|
||||
# Sort conf_should to compare against "conf_is"
|
||||
conf_should=$(echo "${conf_should}" | sort -s -k 1,1)
|
||||
|
||||
config_updated=false
|
||||
if ! echo "${conf_should}" | cmp -s "${__object:?}/explorer/conf" -
|
||||
then
|
||||
# config needs to be updated
|
||||
dma_conf="${CONF_PATH:?}/dma.conf"
|
||||
|
||||
# The following AWK script will output the new config file to be stored on
|
||||
# disk. To do so it reads the current dma.conf file and the config options
|
||||
# that should be set (from stdin).
|
||||
# Note that the path to the current dma.conf is passed to AWK twice, because
|
||||
# the new file cannot be generated in one pass.
|
||||
|
||||
# The logic tries to place options at a sensible location, that is:
|
||||
# a) if the option is already used in the config file:
|
||||
# group all similar options (e.g. MASQUERADE) at one place in the order
|
||||
# they are listed in stdin.
|
||||
# b) if it is a new option and a "default comment" (e.g. "#PORT 25") exists:
|
||||
# place options grouped directly after the comment (the comment is left
|
||||
# alone)
|
||||
# c) otherwise:
|
||||
# options are grouped by word (the first word in the line) and appended
|
||||
# at the end of the file.
|
||||
|
||||
cat <<-CODE
|
||||
awk $(drop_awk_comments "${__type:?}/files/update_dma_conf.awk") $(quote "${dma_conf}") <<'EOF' >$(quote "${dma_conf}.tmp") \
|
||||
&& cat $(quote "${dma_conf}.tmp") >$(quote "${dma_conf}")
|
||||
${conf_should}
|
||||
EOF
|
||||
rm $(quote "${dma_conf}.tmp")
|
||||
CODE
|
||||
|
||||
config_updated=true
|
||||
echo 'config updated' >>"${__messages_out:?}"
|
||||
fi
|
||||
|
||||
|
||||
# Send a test email if enabled and necessary (=configuration changed)
|
||||
if test -f "${__object:?}/parameter/send-test-mail"
|
||||
then
|
||||
if grep -q '^__mail_alias/root:' "${__messages_in:?}" \
|
||||
|| grep -q '^__dma_auth/' "${__messages_in:?}" \
|
||||
|| ${config_updated}
|
||||
then
|
||||
cat <<-CODE
|
||||
sendmail root <<'EOF'
|
||||
Subject: [cdist] Test mail from '${__target_fqdn:?}'
|
||||
|
||||
Hi,
|
||||
|
||||
you can ignore this message.
|
||||
Its sole purpose is to notify you that root mail on ${__target_fqdn:?}
|
||||
will be redirected to you.
|
||||
|
||||
Enjoy!
|
||||
EOF
|
||||
CODE
|
||||
fi
|
||||
fi
|
112
type/__dma/man.rst
Normal file
112
type/__dma/man.rst
Normal file
|
@ -0,0 +1,112 @@
|
|||
cdist-type__dma(7)
|
||||
============================
|
||||
|
||||
NAME
|
||||
----
|
||||
cdist-type__dma - Setup the DragonFly Mail Agent as the MTA.
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
This (singleton) type uses DMA, a small Mail Transport Agent (MTA), to accept
|
||||
mails from locally installed Mail User Agents (MUA) and either deliver the mails
|
||||
to a remote smart host for delivery or communicate with remote SMTP servers
|
||||
directly.
|
||||
|
||||
|
||||
REQUIRED PARAMETERS
|
||||
-------------------
|
||||
None.
|
||||
|
||||
|
||||
BOOLEAN PARAMETERS
|
||||
------------------
|
||||
defer
|
||||
If enabled, mail will not be sent immediately, but stored in a queue.
|
||||
To flush the queue and send the mails, ```dma -q`` has to be run
|
||||
periodically (e.g. using a cron job.)
|
||||
This type does not manage such a cron job, but some operating systems ship
|
||||
such a cron job with the package.
|
||||
fullbounce
|
||||
Enable if bounce messages should include the complete original message,
|
||||
not just the headers.
|
||||
nullclient
|
||||
Enable to bypass aliases and local delivery, and instead forward all mails
|
||||
to the defined ``--smarthost``.
|
||||
send-test-mail
|
||||
If set, this type will send a test email to root after setup, to check if
|
||||
the configured settings work.
|
||||
|
||||
|
||||
OPTIONAL PARAMETERS
|
||||
-------------------
|
||||
mailname
|
||||
If present, this will be the hostname used to identify this host and the
|
||||
remote part of the sender addresses.
|
||||
If not defined, it defaults to ``/etc/mailname`` on Debian derivatives and
|
||||
to ``__target_fqdn`` otherwise.
|
||||
See `dma(8)` for more information.
|
||||
|
||||
Note: on Debian derivatives the ``/etc/mailname`` file should be updated
|
||||
instead of using this parameter.
|
||||
masquerade
|
||||
Masquerade the envelope-from addresses with this address/hostname.
|
||||
Use this setting if mails are not accepted by destination mail servers
|
||||
because your sender domain is invalid.
|
||||
This option can be used multiple times.
|
||||
For more information see the `dma(8)` man page.
|
||||
port
|
||||
The port on which to deliver email.
|
||||
If not provided, a sensible default port will be used based on the
|
||||
``--security`` argument.
|
||||
security
|
||||
Configures whether and how DMA should use secure connections.
|
||||
|
||||
ssl/tls
|
||||
Enable TLS/SSL secured transfer.
|
||||
starttls
|
||||
Use STARTTLS to establish a secure connection.
|
||||
opportunistic (default)
|
||||
Will try to establish a secure connection using STARTTLS, but allow
|
||||
unencrypted transfer if STARTTLS fails.
|
||||
Most useful when dma is used without a smarthost, delivering remote
|
||||
messages directly to the outside mail exchangers.
|
||||
insecure
|
||||
allow plain text SMTP login over an insecure connection.
|
||||
Should really *not* be used anymore!
|
||||
smarthost
|
||||
The mail server used to send email.
|
||||
It must be configured to act as a relay for the host being configured by
|
||||
this type so that mail can be sent to users non-local to the smarthost.
|
||||
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
# Install DMA and use the smarthost mx1.domain.tld to send mail.
|
||||
__dma --smarthost mx1.domain.tld --send-test-mail
|
||||
|
||||
# Install DMA in a default configuration.
|
||||
__dma
|
||||
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
- `DragonFly Mail Agent <https://github.com/corecode/dma>`_
|
||||
- `DragonFly Handbook MTA <https://www.dragonflybsd.org/handbook/mta/>`_
|
||||
|
||||
|
||||
AUTHORS
|
||||
-------
|
||||
Evilham <contact@evilham.com>
|
||||
Dennis Camera <dennis.camera@ssrq-sds-fds.ch>
|
||||
|
||||
|
||||
COPYING
|
||||
-------
|
||||
Copyright \(C) 2020 Evilham and Dennis Camera. You can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
66
type/__dma/manifest
Executable file
66
type/__dma/manifest
Executable file
|
@ -0,0 +1,66 @@
|
|||
#!/bin/sh -e
|
||||
#
|
||||
# 2020 Dennis Camera (dennis.camera@ssrq-sds-fds.ch)
|
||||
#
|
||||
# This file is part of cdist.
|
||||
#
|
||||
# cdist 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, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# cdist 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 cdist. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
os=$(cat "${__global:?}/explorer/os")
|
||||
|
||||
# Install DMA
|
||||
case ${os}
|
||||
in
|
||||
(alpine)
|
||||
__package dma --state present
|
||||
export require='__package/dma'
|
||||
;;
|
||||
(debian|devuan|ubuntu)
|
||||
__package dma --state present
|
||||
export require='__package/dma'
|
||||
;;
|
||||
(freebsd)
|
||||
# Stop sendmail if necessary
|
||||
__process 'sendmail' --name 'sendmail.*' --state absent \
|
||||
--stop '/etc/rc.d/sendmail onestop'
|
||||
|
||||
# ... and disable it
|
||||
__key_value 'rcconf-sendmail-enable' --file '/etc/rc.conf' \
|
||||
--key 'sendmail_enable' --delimiter '=' --value '"NONE"' \
|
||||
--exact_delimiter
|
||||
|
||||
# Setup mailwrapper accordingly
|
||||
__file '/etc/mail/mailer.conf' --mode 0644 --source - <<-'EOF'
|
||||
#
|
||||
# Execute the "real" sendmail program, named /usr/libexec/sendmail/sendmail
|
||||
#
|
||||
sendmail /usr/libexec/dma
|
||||
send-mail /usr/libexec/dma
|
||||
mailq /usr/libexec/dma
|
||||
newaliases /usr/libexec/dma
|
||||
rmail /usr/libexec/dma
|
||||
EOF
|
||||
;;
|
||||
(*)
|
||||
cat <<EOF >&2
|
||||
Your OS (${os}) is not supported yet.
|
||||
|
||||
Maybe adding support is as simple as adapting the packages or allowing it,
|
||||
we highly encourage you to open a PR with the necessary changes.
|
||||
See: https://code.ungleich.ch/ungleich-public/cdist-contrib/
|
||||
EOF
|
||||
exit 1
|
||||
;;
|
||||
esac
|
4
type/__dma/parameter/boolean
Normal file
4
type/__dma/parameter/boolean
Normal file
|
@ -0,0 +1,4 @@
|
|||
defer
|
||||
fullbounce
|
||||
nullclient
|
||||
send-test-mail
|
1
type/__dma/parameter/default/security
Normal file
1
type/__dma/parameter/default/security
Normal file
|
@ -0,0 +1 @@
|
|||
opportunistic
|
4
type/__dma/parameter/optional
Normal file
4
type/__dma/parameter/optional
Normal file
|
@ -0,0 +1,4 @@
|
|||
mailname
|
||||
port
|
||||
security
|
||||
smarthost
|
1
type/__dma/parameter/optional_multiple
Normal file
1
type/__dma/parameter/optional_multiple
Normal file
|
@ -0,0 +1 @@
|
|||
masquerade
|
0
type/__dma/singleton
Normal file
0
type/__dma/singleton
Normal file
1
type/__dma_auth/explorer/auth_conf
Symbolic link
1
type/__dma_auth/explorer/auth_conf
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../__dma/explorer/auth_conf
|
91
type/__dma_auth/explorer/state
Executable file
91
type/__dma_auth/explorer/state
Executable file
|
@ -0,0 +1,91 @@
|
|||
#!/bin/sh -e
|
||||
#
|
||||
# 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch)
|
||||
#
|
||||
# This file is part of cdist.
|
||||
#
|
||||
# cdist 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, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# cdist 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 cdist. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# This explorer looks for a line matching the server parameter
|
||||
# in dma's auth.conf and reports:
|
||||
# present: a line matching login + host + password exists
|
||||
# absent: no line matching login + host exists
|
||||
# different_login: a line exists but with a different login user
|
||||
# different_password: a line exists but with a different password
|
||||
# multiple: multiple lines matching host exist (should not happen)
|
||||
|
||||
auth_conf=$("${__type_explorer:?}/auth_conf")
|
||||
test -r "${auth_conf}" || exit 0
|
||||
|
||||
awk -F'\n' '
|
||||
function getvalue(path) {
|
||||
# Reads the first line of the file located at path and returns it.
|
||||
getline < path
|
||||
close(path)
|
||||
return $0
|
||||
}
|
||||
|
||||
BEGIN {
|
||||
DP = "[: \t]" # copied from dma/conf.c
|
||||
|
||||
parameter_dir = ENVIRON["__object"] "/parameter/"
|
||||
|
||||
# Read the parameters of this object
|
||||
host_param = ENVIRON["__object_id"]
|
||||
login_param = getvalue(parameter_dir "login")
|
||||
passwd_param = getvalue(parameter_dir "password")
|
||||
|
||||
state = "absent"
|
||||
}
|
||||
|
||||
/^#/ || /^$/ {
|
||||
# skip comments and empty lines
|
||||
next
|
||||
}
|
||||
|
||||
{
|
||||
# parse line
|
||||
|
||||
login = substr($0, 1, index($0, "|") - 1)
|
||||
if (!login) { login = $0 } # if no "|" found
|
||||
|
||||
host = substr($0, length(login) + 2)
|
||||
|
||||
if (match(host, DP)) {
|
||||
passwd = substr(host, RSTART + 1)
|
||||
host = substr(host, 1, RSTART - 1)
|
||||
} else {
|
||||
passwd = ""
|
||||
}
|
||||
}
|
||||
|
||||
host == host_param {
|
||||
# a match…
|
||||
if (state == "absent") {
|
||||
if (login != login_param)
|
||||
state = "different_login"
|
||||
else if (passwd != passwd_param)
|
||||
state = "different_password"
|
||||
else
|
||||
state = "present"
|
||||
} else {
|
||||
# report "multiple" to that the type can remove the duplicates.
|
||||
state = "multiple"
|
||||
}
|
||||
}
|
||||
|
||||
END {
|
||||
print state
|
||||
}
|
||||
' "${auth_conf}"
|
93
type/__dma_auth/files/update_dma_auth.awk
Normal file
93
type/__dma_auth/files/update_dma_auth.awk
Normal file
|
@ -0,0 +1,93 @@
|
|||
#!/usr/bin/awk -f
|
||||
#
|
||||
# 2020 Dennis Camera (dennis.camera@ssrq-sds-fds.ch)
|
||||
#
|
||||
# This file is part of cdist.
|
||||
#
|
||||
# cdist 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, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# cdist 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 cdist. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
function getvalue(path) {
|
||||
# Reads the first line of the file located at path and returns it.
|
||||
getline < path
|
||||
close(path)
|
||||
return $0
|
||||
}
|
||||
|
||||
function print_should() {
|
||||
printf "%s|%s:%s\n", login_param, host_param, passwd_param
|
||||
}
|
||||
|
||||
BEGIN {
|
||||
FS = "\n"
|
||||
DP = "[: \t]" # copied from dma/conf.c
|
||||
|
||||
parameter_dir = ENVIRON["__object"] "/parameter/"
|
||||
|
||||
mode = (getvalue(parameter_dir "state") != "absent")
|
||||
|
||||
host_param = ENVIRON["__object_id"]
|
||||
login_param = getvalue(parameter_dir "login")
|
||||
passwd_param = getvalue(parameter_dir "password")
|
||||
}
|
||||
|
||||
# skip comments and empty lines
|
||||
/^#/ || /^$/ {
|
||||
print
|
||||
next
|
||||
}
|
||||
|
||||
{
|
||||
# parse line (like dma/conf.c would)
|
||||
|
||||
login = substr($0, 1, index($0, "|") - 1)
|
||||
if (!login) { login = $0 } # if no "|" found
|
||||
|
||||
host = substr($0, length(login) + 2)
|
||||
|
||||
if (match(host, DP)) {
|
||||
passwd = substr(host, RSTART + 1)
|
||||
host = substr(host, 1, RSTART - 1)
|
||||
} else {
|
||||
passwd = ""
|
||||
}
|
||||
}
|
||||
|
||||
host == host_param {
|
||||
if (mode) {
|
||||
# state_should == present
|
||||
if (!written) {
|
||||
# replace first line if host matches (but only if no line has
|
||||
# been written already -> no duplicates)
|
||||
print_should()
|
||||
written = 1
|
||||
}
|
||||
next
|
||||
} else {
|
||||
# state_should == absent
|
||||
next
|
||||
}
|
||||
}
|
||||
|
||||
# leave other lines alone
|
||||
{
|
||||
print
|
||||
}
|
||||
|
||||
END {
|
||||
if (mode && !written) {
|
||||
# append line if no match to replace was found
|
||||
print_should()
|
||||
}
|
||||
}
|
72
type/__dma_auth/gencode-remote
Executable file
72
type/__dma_auth/gencode-remote
Executable file
|
@ -0,0 +1,72 @@
|
|||
#!/bin/sh -e
|
||||
#
|
||||
# 2020 Dennis Camera (dennis.camera@ssrq-sds-fds.ch)
|
||||
#
|
||||
# This file is part of cdist.
|
||||
#
|
||||
# cdist 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, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# cdist 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 cdist. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
quote() { printf "'%s'" "$(printf '%s' "$*" | sed -e "s/'/'\\\\''/g")"; }
|
||||
drop_awk_comments() { quote "$(sed '/^[[:blank:]]*#.*$/d;/^$/d' "$@")"; }
|
||||
|
||||
state_is=$(cat "${__object:?}/explorer/state")
|
||||
state_should=$(cat "${__object:?}/parameter/state")
|
||||
|
||||
server=${__object_id:?}
|
||||
login=$(cat "${__object:?}/parameter/login")
|
||||
|
||||
|
||||
auth_conf=$(cat "${__object:?}/explorer/auth_conf")
|
||||
test -n "${auth_conf}" || {
|
||||
echo 'Cannot determine path of dma auth.conf' >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
if test "${state_is}" = "${state_should}"
|
||||
then
|
||||
# state is as it should
|
||||
exit 0
|
||||
fi
|
||||
|
||||
case ${state_should}
|
||||
in
|
||||
(present)
|
||||
test -n "${login}" || { echo '--login must be non-empty' >&2; exit 1; }
|
||||
|
||||
if test "${state_is}" = 'absent'
|
||||
then
|
||||
printf 'add authuser %s on %s\n' "${login}" "${server}" >>"${__messages_out:?}"
|
||||
else
|
||||
printf 'set authuser %s on %s\n' "${login}" "${server}" >>"${__messages_out:?}"
|
||||
fi
|
||||
;;
|
||||
(absent)
|
||||
printf 'delete authuser %s on %s\n' "${login}" "${server}" >>"${__messages_out:?}"
|
||||
;;
|
||||
(*)
|
||||
printf 'Invalid --state: %s.\n' "${state_should}" >&2
|
||||
printf 'Acceptable values are: present, absent.\n' >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
cat <<EOF
|
||||
test -f $(quote "${auth_conf}") || touch $(quote "${auth_conf}")
|
||||
|
||||
awk $(drop_awk_comments "${__type:?}/files/update_dma_auth.awk") <$(quote "${auth_conf}") >$(quote "${auth_conf}.tmp") \
|
||||
&& cat $(quote "${auth_conf}.tmp") >$(quote "${auth_conf}")
|
||||
rm -f $(quote "${auth_conf}.tmp")
|
||||
EOF
|
66
type/__dma_auth/man.rst
Normal file
66
type/__dma_auth/man.rst
Normal file
|
@ -0,0 +1,66 @@
|
|||
cdist-type__dma_auth(7)
|
||||
=======================
|
||||
|
||||
NAME
|
||||
----
|
||||
cdist-type__dma_auth - Configure SMTP logins for the DragonFly Mail Agent MTA.
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
This cdist type allows you to set up credentials to log in to remote SMTP
|
||||
servers.
|
||||
|
||||
NB: dma currently (v0.13) does not differentiate between users on a host.
|
||||
It will use whatever user it finds in the ``auth.conf`` first.
|
||||
Thus, this type will use the ``__object_id`` as the host specifier.
|
||||
|
||||
|
||||
REQUIRED PARAMETERS
|
||||
-------------------
|
||||
login
|
||||
The user's LOGIN name on the SMTP server.
|
||||
password
|
||||
The user's password (in plain text.)
|
||||
|
||||
|
||||
OPTIONAL PARAMETERS
|
||||
-------------------
|
||||
state
|
||||
Either ``present`` or ``absent``. Defaults to ``present``.
|
||||
|
||||
BOOLEAN PARAMETERS
|
||||
------------------
|
||||
None.
|
||||
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
# Set the password for smarthost
|
||||
__dma_auth smarthost.example.com --login joe --password hunter2
|
||||
|
||||
# Set credentials for user at an external provider
|
||||
__dma_auth mail.provider.com --login paul@example.com --password letmein
|
||||
|
||||
# Delete credentials for example.com (for all users)
|
||||
__dma_auth example.com --login '' --password '' --state absent
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
:strong:`cdist-type__dma`\ (7), :strong:`dma`\ (8)
|
||||
|
||||
|
||||
AUTHORS
|
||||
-------
|
||||
Dennis Camera <dennis.camera@ssrq-sds-fds.ch>
|
||||
|
||||
|
||||
COPYING
|
||||
-------
|
||||
Copyright \(C) 2020 Dennis Camera. You can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
0
type/__dma_auth/nonparallel
Normal file
0
type/__dma_auth/nonparallel
Normal file
1
type/__dma_auth/parameter/default/state
Normal file
1
type/__dma_auth/parameter/default/state
Normal file
|
@ -0,0 +1 @@
|
|||
present
|
1
type/__dma_auth/parameter/optional
Normal file
1
type/__dma_auth/parameter/optional
Normal file
|
@ -0,0 +1 @@
|
|||
state
|
2
type/__dma_auth/parameter/required
Normal file
2
type/__dma_auth/parameter/required
Normal file
|
@ -0,0 +1,2 @@
|
|||
login
|
||||
password
|
73
type/__mail_alias/explorer/aliases
Executable file
73
type/__mail_alias/explorer/aliases
Executable file
|
@ -0,0 +1,73 @@
|
|||
#!/bin/sh -e
|
||||
#
|
||||
# 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch)
|
||||
#
|
||||
# This file is part of cdist.
|
||||
#
|
||||
# cdist 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, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# cdist 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 cdist. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Find aliases for a given user name and print the aliases (each one on a
|
||||
# separate line)
|
||||
|
||||
aliases_file=$("${__type_explorer:?}/aliases_file")
|
||||
test -r "${aliases_file}" || exit 0
|
||||
|
||||
: "${__object_id:?}" # assert __object_id is set, because it is used in AWK
|
||||
|
||||
awk -F ':[ \t]*' '
|
||||
function print_aliases(aliases, matches) {
|
||||
# prints comma-separated aliases (one per line)
|
||||
split(aliases, matches, /,[ \t]*/)
|
||||
for (i in matches) {
|
||||
gsub(/^[ \t]*|[ \t]*$/, "", matches[i])
|
||||
if (matches[i]) print matches[i]
|
||||
}
|
||||
}
|
||||
|
||||
/^#/ {
|
||||
# comment line (ignore)
|
||||
select = 0; cont = 0 # comments terminate alias lists and continuations
|
||||
next
|
||||
}
|
||||
|
||||
{
|
||||
# is this line a continuation line?
|
||||
# (the prev. line ended in a backslash or the line starts with whitespace)
|
||||
is_cont = /^[ \t]/ || cont
|
||||
|
||||
# detect if the line is a line to be continued (ends with a backslash)
|
||||
cont = /\\$/
|
||||
|
||||
# if it is, we drop the backslash from the line
|
||||
if (cont) sub(/[ \t]*\\$/, "", $0)
|
||||
}
|
||||
|
||||
is_cont {
|
||||
# if in the alias list of the "target" user, we also print these aliases.
|
||||
if (select) print_aliases($0)
|
||||
next
|
||||
}
|
||||
|
||||
$1 == ENVIRON["__object_id"] {
|
||||
# "target" user -> print alias list
|
||||
select = 1
|
||||
print_aliases($2)
|
||||
next
|
||||
}
|
||||
|
||||
{
|
||||
# other user
|
||||
select = 0
|
||||
}
|
||||
' "${aliases_file}"
|
52
type/__mail_alias/explorer/aliases_file
Executable file
52
type/__mail_alias/explorer/aliases_file
Executable file
|
@ -0,0 +1,52 @@
|
|||
#!/bin/sh -e
|
||||
#
|
||||
# 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch)
|
||||
#
|
||||
# This file is part of cdist.
|
||||
#
|
||||
# cdist 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, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# cdist 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 cdist. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# This explorer finds the aliases file to modify.
|
||||
|
||||
found() { echo "$*"; exit 0; }
|
||||
|
||||
check_file() {
|
||||
if test -f "$1"
|
||||
then
|
||||
found "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
case $("${__explorer:?}/os")
|
||||
in
|
||||
(freebsd|openbsd|solaris)
|
||||
check_file /etc/mail/aliases
|
||||
|
||||
# default
|
||||
found /etc/mail/aliases
|
||||
;;
|
||||
(alpine|debian|devuan|ubuntu)
|
||||
check_file /etc/aliases
|
||||
|
||||
# default
|
||||
found /etc/aliases
|
||||
;;
|
||||
(*)
|
||||
check_file /etc/mail/aliases
|
||||
check_file /etc/aliases
|
||||
|
||||
# default
|
||||
found /etc/aliases
|
||||
;;
|
||||
esac
|
96
type/__mail_alias/files/update_aliases.awk
Normal file
96
type/__mail_alias/files/update_aliases.awk
Normal file
|
@ -0,0 +1,96 @@
|
|||
#!/usr/bin/awk -f
|
||||
#
|
||||
# 2020 Dennis Camera (dennis.camera@ssrq-sds-fds.ch)
|
||||
#
|
||||
# This file is part of cdist.
|
||||
#
|
||||
# cdist 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, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# cdist 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 cdist. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
function getvalue(path, line) {
|
||||
# Reads the first line of the file located at path and returns it.
|
||||
getline line < path
|
||||
close(path)
|
||||
return line
|
||||
}
|
||||
|
||||
function sepafter(f, def, _) {
|
||||
# finds the separator between field $f and $(f+1)
|
||||
_ = substr($0, length($f)+1, index(substr($0, length($f)+1), $(f+1))-1)
|
||||
return _ ? _ : def
|
||||
}
|
||||
|
||||
function write_aliases( line) {
|
||||
if (aliases_written) return
|
||||
|
||||
# print aliases line
|
||||
printf "%s%s", ENVIRON["__object_id"], sepafter(1, ": ")
|
||||
while ((getline line < aliases_should_file) > 0) {
|
||||
if (aliases_written) printf ", "
|
||||
printf "%s", line
|
||||
aliases_written = 1
|
||||
}
|
||||
printf "\n"
|
||||
close(aliases_should_file)
|
||||
}
|
||||
|
||||
BEGIN {
|
||||
FS = ":[ \t]*"
|
||||
|
||||
parameter_dir = ENVIRON["__object"] "/parameter/"
|
||||
|
||||
mode = (getvalue(parameter_dir "state") != "absent")
|
||||
aliases_should_file = (parameter_dir "/alias")
|
||||
}
|
||||
|
||||
/^[ \t]*\#/ {
|
||||
# comment line (leave alone)
|
||||
select = 0; cont = 0 # comments terminate alias lists and continuations
|
||||
print
|
||||
next
|
||||
}
|
||||
|
||||
{
|
||||
# is this line a continuation line?
|
||||
# (the prev. line ended in a backslash or the line starts with whitespace)
|
||||
is_cont = /^[ \t]/ || cont
|
||||
|
||||
# detect if the line is a line to be continued (ends with a backslash)
|
||||
cont = /\\$/
|
||||
}
|
||||
|
||||
is_cont {
|
||||
# we only print the line if it has not been rewritten (select)
|
||||
if (!select) print
|
||||
next
|
||||
}
|
||||
|
||||
$1 == ENVIRON["__object_id"] {
|
||||
# "target" user -> rewrite aliases list
|
||||
select = 1
|
||||
if (mode) write_aliases()
|
||||
next
|
||||
}
|
||||
|
||||
{
|
||||
# other user
|
||||
select = 0
|
||||
print
|
||||
}
|
||||
|
||||
END {
|
||||
# if the last line was an alias, the separator will be reused (looks better)
|
||||
if (mode && !aliases_written)
|
||||
write_aliases()
|
||||
}
|
87
type/__mail_alias/gencode-remote
Executable file
87
type/__mail_alias/gencode-remote
Executable file
|
@ -0,0 +1,87 @@
|
|||
#!/bin/sh -e
|
||||
#
|
||||
# 2020 Dennis Camera (dennis.camera@ssrq-sds-fds.ch)
|
||||
#
|
||||
# This file is part of cdist.
|
||||
#
|
||||
# cdist 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, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# cdist 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 cdist. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
quote() { printf "'%s'" "$(printf '%s' "$*" | sed -e "s/'/'\\\\''/g")"; }
|
||||
drop_awk_comments() { quote "$(sed '/^[[:blank:]]*#.*$/d;/^$/d' "$@")"; }
|
||||
|
||||
aliases_file=$(cat "${__object:?}/explorer/aliases_file")
|
||||
|
||||
test -n "${aliases_file}" || {
|
||||
echo 'Could not determine aliases file path.' >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
state_should=$(cat "${__object:?}/parameter/state")
|
||||
|
||||
case ${state_should}
|
||||
in
|
||||
(present)
|
||||
if cmp -s "${__object:?}/explorer/aliases" "${__object:?}/parameter/alias"
|
||||
then
|
||||
# all good!
|
||||
exit 0
|
||||
fi
|
||||
|
||||
test -s "${__object:?}/parameter/alias" || {
|
||||
printf 'The --alias parameter is required if --state present.\n' >&2
|
||||
printf 'Use --state absent to remove all aliases.\n' >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
if test -s "${__object:?}/explorer/aliases"
|
||||
then
|
||||
echo "update aliases" >>"${__messages_out:?}"
|
||||
else
|
||||
echo "add aliases" >>"${__messages_out:?}"
|
||||
fi
|
||||
;;
|
||||
(absent)
|
||||
# nothing to do if no aliases found.
|
||||
test -s "${__object:?}/explorer/aliases" || exit 0
|
||||
|
||||
echo "delete aliases" >>"${__messages_out:?}"
|
||||
;;
|
||||
(*)
|
||||
printf 'Invalid --state: %s.\n' "${state_should}" >&2
|
||||
printf 'Acceptable values are: present, absent.\n' >&2
|
||||
exit 1
|
||||
esac
|
||||
|
||||
cat <<EOF
|
||||
test -f $(quote "${aliases_file}") || touch $(quote "${aliases_file}")
|
||||
|
||||
awk $(drop_awk_comments "${__type:?}/files/update_aliases.awk") <$(quote "${aliases_file}") >$(quote "${aliases_file}.tmp") \
|
||||
|| {
|
||||
rm -f $(quote "${aliases_file}.tmp")
|
||||
echo 'Generating new aliases file failed!' >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
if ! cmp -s $(quote "${aliases_file}") $(quote "${aliases_file}.tmp")
|
||||
then
|
||||
# aliases file was modified, replace:
|
||||
cat $(quote "${aliases_file}.tmp") >$(quote "${aliases_file}")
|
||||
|
||||
# then, run newaliases if present ("missing" on Alpine Linux because of typo)
|
||||
command -v newaliases >/dev/null 2>&1 && newaliases || true
|
||||
fi
|
||||
rm -f $(quote "${aliases_file}.tmp")
|
||||
EOF
|
76
type/__mail_alias/man.rst
Normal file
76
type/__mail_alias/man.rst
Normal file
|
@ -0,0 +1,76 @@
|
|||
cdist-type__mail_alias(7)
|
||||
=========================
|
||||
|
||||
NAME
|
||||
----
|
||||
cdist-type__mail_alias - Manage mail aliases.
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
This cdist type allows you to configure mail aliases (/etc/aliases).
|
||||
|
||||
|
||||
REQUIRED PARAMETERS
|
||||
-------------------
|
||||
None.
|
||||
|
||||
|
||||
OPTIONAL PARAMETERS
|
||||
-------------------
|
||||
state
|
||||
'present' or 'absent', defaults to 'present'
|
||||
alias
|
||||
an alias, i.e. a mail address where mail for the user should be redirected
|
||||
to.
|
||||
This parameter can be specified multiple times to redirect to multiple
|
||||
recipients.
|
||||
If ``--state`` is ``present`` this parameter is required.
|
||||
See `aliases(5)` for the different forms this parameter can take.
|
||||
|
||||
|
||||
BOOLEAN PARAMETERS
|
||||
------------------
|
||||
None.
|
||||
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
# Redirect root mail to a "real" email address
|
||||
__mail_alias root --alias admin@example.com
|
||||
|
||||
# Disable redirection of mail for joe
|
||||
__mail_alias joe --state absent
|
||||
|
||||
|
||||
BUGS
|
||||
----
|
||||
- Quoted strings are not parsed by this type. As a result, aliases
|
||||
containing ``,`` (commas) are treated incorrectly (they are treated as
|
||||
separate aliases.)
|
||||
Make sure that email addresses, file names, and pipe commands do not contain
|
||||
commas.
|
||||
- ``:include:`` directives in the aliases file are not evaluated by this type.
|
||||
They are treated like a regular alias, the values of the included file are
|
||||
not expanded.
|
||||
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
:strong:`aliases`\ (5)
|
||||
|
||||
|
||||
AUTHORS
|
||||
-------
|
||||
Dennis Camera <dennis.camera@ssrq-sds-fds.ch>
|
||||
|
||||
|
||||
COPYING
|
||||
-------
|
||||
Copyright \(C) 2020 Dennis Camera. You can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
0
type/__mail_alias/nonparallel
Normal file
0
type/__mail_alias/nonparallel
Normal file
1
type/__mail_alias/parameter/default/state
Normal file
1
type/__mail_alias/parameter/default/state
Normal file
|
@ -0,0 +1 @@
|
|||
present
|
1
type/__mail_alias/parameter/optional
Normal file
1
type/__mail_alias/parameter/optional
Normal file
|
@ -0,0 +1 @@
|
|||
state
|
1
type/__mail_alias/parameter/optional_multiple
Normal file
1
type/__mail_alias/parameter/optional_multiple
Normal file
|
@ -0,0 +1 @@
|
|||
alias
|
Loading…
Reference in a new issue