harden exim
[distro-setup] / mail-setup
1 #!/bin/bash
2 # * intro
3 # Copyright (C) 2019 Ian Kelling
4 # SPDX-License-Identifier: AGPL-3.0-or-later
5
6 # todo: harden dovecot. need to do some research. one way is for it to only listen on a wireguard vpn interface, so only clients that are on the vpn can access it.
7 # todo: consider hardening cups listening on 0.0.0.0
8 # todo: stop/disable local apache, and rpc.mountd, and kdeconnect when not in use.
9 # todo: check that spamd and unbound only listen locally.
10
11 # todo: hosts should only allow external mail that is authed and
12 # destined for backup route. it is a minor issue since traffic is
13 # limited to the wghole network.
14
15 # todo: emailing info@amnimal.ninja produces a bounce, user doesn't exist
16 # instead of a simple rejection like it should.
17
18 # todo: run mailping test after running, or otherwise
19 # clear out terminal alert
20
21 # todo: reinstall bk with bigger filesystem
22
23 # todo: on bk, dont send email if mailvpn is not up
24
25 # todo: mailtest-check should check on bk too
26
27 # todo: disable postgrey
28
29 # todo: in testforward-check, we should also look
30
31 # todo: test that bounces dont help create valid mailtest-check
32
33 # todo: move mail stuff in distro-end into this file
34
35 # todo: consider rotating dkim & publishing key so every past email I sent
36 # isnt necessarily signed
37
38 # todo: consider how to get clamav out of Debian-exim group
39 # so it cant read/write the whole mail spool, for better
40 # security.
41
42 # todo: create a cronjob to update or warn on expiring dnssec keys
43
44 # todo: we should test failed mail daily or so
45 # failed cronjob, failed sysd-log-once,
46 # a local bounce from a cronjob, a local bounce
47 # to a bad remote address, perhaps a local failure
48 # when the sending daemon is down.
49 # And send an alert email if no alerts have been sent
50 # in 2 or 3 days or something. todo, test cron mail on li.
51
52 # todo: look at mailinabox extra dns records, note these changelogs:
53 # - An MTA-STS policy for incoming mail is now published (in DNS and over HTTPS) when the primary hostname and email address domain both have a signed TLS certificate installed, allowing senders to know that an encrypted connection should be enforced.
54 # - The per-IP connection limit to the IMAP server has been doubled to allow more devices to connect at once, especially with multiple users behind a NAT.
55 #
56
57 # todo: mailtest-check failure on remote hosts is not going to alert me.
58 # sort that out.
59 # todo: test mail failure as well as success.
60 #
61 # todo: validate that mailtest-check is doing dnsbl checks.
62
63 # background: I want to run exim in a network namespace so it can send
64 # and receive through a vpn. This is needed so it can do ipv6, because
65 # outside the namespace if we dont have ipv6, to send ipv6 through the
66 # vpn, we have to send all our ipv6 through the vpn. I did this for a
67 # long time, it was fine, but it causes various pains, like increased
68 # latency, increased recaptcha because my ip is from a data center, just
69 # various issues I dont want on all the time. The problem with the
70 # namespace is that all kinds of programs want to invoke exim, but they
71 # wont be in the namespace. I could replace exim with a wrapper that
72 # jumps into the namespace, i tried that, it works fine. One remaining
73 # problem was that I would have needed to hook into exim upgrades to
74 # move exim and replace it with my wrapper script. Also, my script to
75 # join the namespace is not super reliable because it uses a pgrep.
76 # Instead, I should have created a systemd service for a process that
77 # will never die and just writes its pid somewhere convenient.
78 # That implementation
79 # is below here:
80 #
81 # sudoers:
82 # user ALL=(ALL) /usr/sbin/exim4
83 #
84 # move exim4 to eximian, use this script for exim4:
85 #
86 # #!/bin/bash
87 # if ip a show veth1-mail &>/dev/null; then
88 # /usr/sbin/eximian "$@"
89 # exit
90 # fi
91 # dosudo=false
92 # if [[ $USER && $USER != root ]]; then
93 # dosudo=true
94 # fi
95 # pid=$(pgrep -f "/usr/sbin/openvpn .* --config /etc/openvpn/.*mail.conf")
96 # if $dosudo; then
97 # sudo nsenter -t $pid -n -m sudo -u $USER /usr/sbin/eximian "$@"
98 # else
99 # nsenter -t $pid -n -m /usr/sbin/eximian "$@"
100 # fi
101 # ## end script
102 #
103 # an alternate solution: there is a small setguid program for
104 # network namespaces in my bookmarks.
105 #
106 # However, the solution I went with is: have 2 exim
107 # configs. A nonstandard location for the daemon that runs
108 # in the namespace. For all other invocations, it uses
109 # the default config location, which is altered to be
110 # in a smarthost config which sends mail to the deaemon.
111 #
112 # I have a bash function, enn to invoke exim like the daemon is running.
113 # and mailbash to just enter its network namespace.
114
115 if [ -z "$BASH_VERSION" ]; then echo "error: shell is not bash" >&2; exit 1; fi
116
117 shopt -s nullglob
118
119 if [[ -s /usr/local/lib/err ]]; then
120 source /usr/local/lib/err
121 elif [[ -s /a/bin/errhandle/err ]]; then
122 source /a/bin/errhandle/err
123 else
124 err "no err tracing script found"
125 fi
126 source /a/bin/distro-functions/src/identify-distros
127 source /a/bin/distro-functions/src/package-manager-abstractions
128
129 # has nextcloud_admin_pass in it
130 f=/p/c/machine_specific/$HOSTNAME/mail
131 if [[ -e $f ]]; then
132 # shellcheck source=/p/c/machine_specific/bk/mail
133 source $f
134 fi
135
136
137 [[ $EUID == 0 ]] || exec sudo -E "${BASH_SOURCE[0]}" "$@"
138
139
140 u=$(id -nu 1000)
141
142
143 usage() {
144 cat <<EOF
145 Usage: ${0##*/} anything_here_to_debug
146 Setup exim4 & dovecot & related things
147
148 -h|--help Print help and exit.
149 EOF
150 exit $1
151 }
152
153 # debug output if we pass any arg
154 if (( $# )); then
155 set -x
156 fi
157
158
159 ####### instructions for icedove #####
160 # Incoming mail server: mail.iankelling.org, port 143, username iank, connection security starttls, authentication method normal password,
161 # then click advanced so it accepts it.
162 # we could also just use 127.0.0.1 with no ssl
163 #
164 # hamburger -> preferences -> preferences -> advanced tab -> config editor button -> security.ssl.enable_ocsp_must_staple = false
165 # background: dovecot does not yet have ocsp stapling support
166 # reference: https://community.letsencrypt.org/t/simple-guide-using-lets-encrypt-ssl-certs-with-dovecot/2921
167 #
168 # for phone, k9mail, same thing but username alerts, pass in ivy-pass.
169 # also, bk.b8.nz for secondary alerts, username is iank. same alerts pass.
170 # fetching mail settings: folder poll frequency 10 minutes
171 #######
172
173
174 # * perstent password instructions
175 # Note: for cert cron, we need to manually run first to accept known_hosts
176
177 # # exim passwords:
178 # # for hosts which have all private files I just use the same user
179 # # for other hosts, each one get\'s their own password.
180 # # for generating secure pass, and storing for server too:
181 # f=$(mktemp)
182 # host=tp
183 # apg -m 50 -x 70 -n 1 -a 1 -M CLN >$f
184 # s sed -i "/^$host:/d" /p/c/filesystem/etc/exim4/passwd
185 # echo "$host:$(mkpasswd -m sha-512 -s <$f)" >>/p/c/filesystem/etc/exim4/passwd
186 # #reference: exim4_passwd_client(5)
187 # dir=/p/c/machine_specific/$host/filesystem/etc/exim4
188 # mkdir -p $dir
189 # echo "mail.iankelling.org:$host:$(<$f)" > $dir/passwd.client
190 # # then run this script
191
192 # # dovecot password, i just need 1 as I\'m the only user
193 # mkdir /p/c/filesystem/etc/dovecot
194 # echo "iank:$(doveadm pw -s SHA512-CRYPT)::::::" >>/p/c/filesystem/etc/dovecot/users
195
196 ####### end perstent password instructions ######
197
198
199 # * dkim dns
200 # # Remove 1 level of comments in this section, set the domain var
201 # # for the domain you are setting up, then run this and copy dns settings
202 # # into dns.
203 # domain=iankelling.org
204 # c /p/c/filesystem/etc/exim4
205 # # this has several bugs addressed in comments, but it was helpful
206 # # https://debian-administration.org/article/718/DKIM-signing_outgoing_mail_with_exim4
207
208 # openssl genrsa -out $domain-private.pem 2048
209 # # Then, to get the public key strings to put in bind:
210
211 # # selector is needed for having multiple keys for one domain.
212 # # I dun do that, so just use a static one: li
213 # # Debadmin page does not have v=, fastmail does, and this
214 # # says it\'s recommended in 3.6.1, default is DKIM1 anyways.
215 # # https://www.ietf.org/rfc/rfc6376.txt
216 # # Join and print all but first and last line.
217 # # last line: swap hold & pattern, remove newlines, print.
218 # # lines 2+: append to hold space
219 # echo "bind txt record: remember to truncate $domain so its relative to the bind zone"
220 # cat <<EOF
221 # a._domainkey.$domain TXT (
222 # "v=DKIM1\059 k=rsa\059 p=$(openssl rsa -in $domain-private.pem -pubout |&sed -rn '${x;s/\n//g;s/^(.*)(.{240}$)/\1"\n"\2/p};3,$H')" )
223 # EOF
224 # # sed explanation: skip the first few lines, then put them into the hold space, then
225 # # on the last line, back to the patern space, remove the newlines, then add a newline
226 # # at the last char - 240, because bind txt records need strings <=255 chars,
227 # # other dkim stuff at the begining is is 25 chars, and the pubkey is 393, so this
228 # # leaves us a bit of extra room at the end and a bunch at the beginning.
229
230 # # selector was also put into /etc/exim4/conf.d/main/000_local,
231
232 # * dmarc dns
233
234 # # 2017-02 dmarc policies:
235 # # host -t txt _dmarc.gmail.com
236 # # yahoo: p=reject, hotmail: p=none, gmail: p=none, fastmail none for legacy reasons
237 # # there were articles claiming gmail would be changing
238 # # to p=reject, in early 2017, which didn\'t happen. I see no sources on them. It\'s
239 # # expected to cause problems
240 # # with a few old mailing lists, copying theirs for now.
241 #
242 # echo "dmarc dns, name: _dmarc value: v=DMARC1; p=none; rua=mailto:mailauth-reports@$domain"
243
244 # * other dns
245
246 # # 2017-02 spf policies:
247 # # host -t txt lists.fedoraproject.org
248 # # google ~all, hotmail ~all, yahoo: ?all, fastmail ?all, outlook ~all
249 # # i include fastmail\'s settings, per their instructions,
250 # # and follow their policy. In mail in a box, or similar instructions,
251 # # I\'ve seen recommended to not use a restrictive policy.
252
253 # # to check if dns has updated, you do
254 # host -a mesmtp._domainkey.$domain
255
256 # # mx records,
257 # # setting it to iankelling.org would work the same, but this
258 # # is more flexible, I could change where mail.iankelling.org pointed.
259 # cat <<'EOF'
260 # mx records, 2 records each, for * and empty domain
261 # pri 10 mail.iankelling.org
262 # EOF
263
264 # # dnssec
265 # from brc2, run dnsecgen then dsign, update named.local.conf, publish keys to registrar
266
267 # * functions & constants
268
269 pre="${0##*/}:"
270 m() { printf "$pre %s\n" "$*"; "$@"; }
271 e() { printf "$pre %s\n" "$*"; }
272 err() { printf "$pre %s\n" "$*" >&2; exit 1; }
273
274 reload=false
275 # This file is so if we fail in the middle and rerun, we dont lose state
276 if [[ -e /var/local/mail-setup-reload ]]; then
277 reload=true
278 fi
279 i() { # install file
280 local tmp tmpdir dest="$1"
281 local base="${dest##*/}"
282 mkdir -p ${dest%/*}
283 ir=false # i result
284 tmpdir=$(mktemp -d)
285 cat >$tmpdir/"$base"
286 tmp=$(rsync -ic $tmpdir/"$base" "$dest")
287 if [[ $tmp ]]; then
288 printf "%s\n" "$tmp"
289 ir=true
290 if [[ $dest == /etc/systemd/system/* ]]; then
291 touch /var/local/mail-setup-reload
292 reload=true
293 fi
294 fi
295 rm -rf $tmpdir
296 }
297 setini() {
298 key="$1" value="$2" section="$3"
299 file="/etc/radicale/config"
300 sed -ri "/ *\[$section\]/,/^ *\[[^]]+\]/{/^\s*${key}[[:space:]=]/d};/ *\[$section\]/a $key = $value" "$file"
301 }
302 soff () {
303 for service; do
304 # ignore services that dont exist
305 if systemctl cat $service &>/dev/null; then
306 m systemctl disable --now $service
307 fi
308 done
309 }
310 sre() {
311 for service; do
312 m systemctl restart $service
313 m systemctl enable $service;
314 done
315 }
316 mailhost() {
317 [[ $HOSTNAME == "$MAIL_HOST" ]]
318 }
319 e() { printf "%s\n" "$*"; }
320 reifactive() {
321 for service; do
322 if systemctl is-active $service >/dev/null; then
323 m systemctl restart $service
324 fi
325 done
326 }
327 stopifactive() {
328 for service; do
329 if systemctl is-active $service >/dev/null; then
330 m systemctl stop $service
331 fi
332 done
333 }
334
335 mxhost=mx.iankelling.org
336 mxport=587
337 forward=$u@$mxhost
338
339 # old setup. left as comment for example
340 # mxhost=mail.messagingengine.com
341 # mxport=587
342 # forward=ian@iankelling.org
343
344 smarthost="$mxhost::$mxport"
345 uhome=$(eval echo ~$u)
346
347 # Somehow on one machine, a file got written with 664 perms.
348 # just being defensive here.
349 umask 0022
350
351 source /a/bin/bash_unpublished/source-state
352 if [[ ! $MAIL_HOST ]]; then
353 err "\$MAIL_HOST not set"
354 fi
355
356 bhost_t=false
357 case $HOSTNAME in
358 $MAIL_HOST) : ;;
359 kd|frodo|x2|x3|kw|sy|bo)
360 bhost_t=true
361 ;;
362 esac
363
364
365 # * Install universal packages
366
367
368 # installs epanicclean iptables-exim ip6tables-exim
369 /a/bin/ds/install-my-scripts
370
371 if [[ $(debian-codename-compat) == bionic ]]; then
372 cat >/etc/apt/preferences.d/spamassassin <<'EOF'
373 Package: spamassassin sa-compile spamc
374 Pin: release n=focal,o=Ubuntu
375 Pin-Priority: 500
376 EOF
377 fi
378
379 # light version of exim does not have sasl auth support.
380 pi-nostart exim4 exim4-daemon-heavy spamassassin openvpn unbound clamav-daemon wireguard
381
382 # note: pyzor debian readme says you need to run some initialization command
383 # but its outdated.
384 pi spf-tools-perl p0f postgrey pyzor razor jq moreutils certbot fail2ban
385 # bad packages that sometimes get automatically installed
386 pu openresolv resolvconf
387
388 soff openvpn
389
390
391 if [[ $(debian-codename) == etiona ]]; then
392 # ip6tables stopped loading on boot. openvpn has reduced capability set,
393 # so running iptables as part of openvpn startup wont work. This should do it.
394 pi iptables-persistent
395 cat >/etc/iptables/rules.v6 <<'EOF'
396 *mangle
397 COMMIT
398 *nat
399 COMMIT
400 EOF
401 # load it now.
402 m ip6tables -S >/dev/null
403 fi
404
405 # our nostart pi fails to avoid enabling
406
407
408 # * Mail clean cronjob
409
410 i /etc/systemd/system/mailclean.timer <<'EOF'
411 [Unit]
412 Description=Run mailclean daily
413
414 [Timer]
415 OnCalendar=monthly
416
417 [Install]
418 WantedBy=timers.target
419 EOF
420
421 i /etc/systemd/system/mailclean.service <<EOF
422 [Unit]
423 Description=Delete and archive old mail files
424 After=multi-user.target
425
426 [Service]
427 User=$u
428 Type=oneshot
429 ExecStart=/usr/local/bin/sysd-mail-once mailclean /a/bin/distro-setup/mailclean
430 EOF
431
432 # * postgrey
433
434
435 i /etc/default/postgrey <<'EOF'
436 POSTGREY_OPTS="--exim --unix=/var/run/postgrey/postgrey.sock --retry-window=4 --max-age=60"
437 EOF
438
439 # * clamav
440
441 m usermod -a -G Debian-exim clamav
442
443 i /etc/systemd/system/clamav-daemon.service.d/fix.conf <<EOF
444 [Service]
445 ExecStartPre=-/bin/mkdir /var/run/clamav
446 ExecStartPre=/bin/chown clamav /var/run/clamav
447 EOF
448
449 # * mail vpn config
450
451 # old.
452 #vpnser=mailvpn.service
453 # todo: this hangs if it cant resolv the endpoint. we
454 # want it to just retry in the background.
455 vpnser=wg-quick@wgmail.service
456
457 case $HOSTNAME in
458 $MAIL_HOST)
459 rsync -aiSAX --chown=root:root --chmod=g-s /p/c/filesystem/etc/wireguard/ /etc/wireguard
460 bindpaths="/etc/127.0.0.1-resolv:/run/systemd/resolve /etc/basic-nsswitch:/etc/resolved-nsswitch:norbind"
461 ;;&
462 bk)
463 bindpaths="/etc/10.173.8.1-resolv:/etc/127.0.0.1-resolv"
464 ;;&
465 *)
466 d=/p/c/machine_specific/$HOSTNAME/filesystem/etc/wireguard/
467 if [[ -d $d ]]; then
468 rsync -aiSAX --chown=root:root --chmod=g-s $d /etc/wireguard
469 fi
470 ;;
471 esac
472
473 case $HOSTNAME in
474 li) : ;;
475 *)
476 i /etc/systemd/system/wg-quick@wgmail.service.d/override.conf <<EOF
477 [Unit]
478 Requires=mailnn.service
479 After=network.target mailnn.service
480 JoinsNamespaceOf=mailnn.service
481 BindsTo=mailnn.service
482 StartLimitIntervalSec=0
483
484 [Service]
485 PrivateNetwork=true
486 # i dont think we need any of these, but it doesnt hurt to stay consistent
487 BindPaths=$bindpaths
488
489 Restart=on-failure
490 RestartSec=20
491 EOF
492 ;;
493 esac
494
495
496 # https://selivan.github.io/2017/12/30/systemd-serice-always-restart.html
497 i /etc/systemd/system/mailvpn.service <<EOF
498 [Unit]
499 Description=OpenVPN tunnel for mail
500 After=syslog.target network-online.target mailnn.service
501 Wants=network-online.target
502 Documentation=man:openvpn(8)
503 Documentation=https://community.openvpn.net/openvpn/wiki/Openvpn24ManPage
504 Documentation=https://community.openvpn.net/openvpn/wiki/HOWTO
505 # needed to continually restatr
506 JoinsNamespaceOf=mailnn.service
507 BindsTo=mailnn.service
508 StartLimitIntervalSec=0
509
510 [Service]
511 Type=notify
512 RuntimeDirectory=openvpn-client
513 RuntimeDirectoryMode=0710
514 WorkingDirectory=/etc/openvpn/client
515 ExecStart=/usr/sbin/openvpn --suppress-timestamps --nobind --config /etc/openvpn/client/mail.conf
516 #CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_OVERRIDE
517 LimitNPROC=10
518 # DeviceAllow=/dev/null rw
519 # DeviceAllow=/dev/net/tun rw
520 PrivateNetwork=true
521 # in the network namespace, we cant connect to systemd-resolved on 127.0.0.53,
522 # because of
523 # https://unix.stackexchange.com/questions/445782/how-to-allow-systemd-resolved-to-listen-to-an-interface-other-than-loopback
524 # there is a workaround there, but i dont think its really worth it,
525 # the mail server is fine with a static dns anyways.
526 # This thread is also interesting,
527 # https://github.com/slingamn/namespaced-openvpn/issues/7
528 # todo: the iptables rule at the bottom could be useful to prevent
529 # dns from leaking in my network namespaced vpn.
530 # I also like the idea of patching systemd-resolved so it
531 # will listen on other interfaces, but its not worth my time.
532 BindPaths=$bindpaths
533 Restart=always
534 # time to sleep before restarting a service
535 RestartSec=20
536
537 [Install]
538 WantedBy=multi-user.target
539 EOF
540
541 i /etc/systemd/system/mailnnroute.service <<'EOF'
542 [Unit]
543 Description=Network routing for mailnn
544 After=syslog.target network-online.target mailnn.service
545 Wants=network-online.target
546 JoinsNamespaceOf=mailnn.service
547 BindsTo=mailnn.service
548 StartLimitIntervalSec=0
549
550 [Service]
551 Type=simple
552 RemainAfterExit=true
553 PrivateNetwork=true
554 ExecStart=/usr/bin/flock -w 20 /tmp/newns.flock /a/bin/newns/newns -n 10.173.8 start mail
555 ExecStop=/usr/bin/flock -w 20 /tmp/newns.flock /a/bin/newns/newns stop mail
556 Restart=always
557 RestartSec=20
558
559
560 [Install]
561 WantedBy=multi-user.target
562 EOF
563
564 #
565 i /etc/systemd/system/mailnn.service <<'EOF'
566 [Unit]
567 Description=Network Namespace for mail vpn service that will live forever and cant fail
568 After=syslog.target network-online.target
569 Wants=network-online.target
570
571 [Service]
572 Type=simple
573 PrivateNetwork=true
574 ExecStart=/bin/sleep infinity
575
576 [Install]
577 WantedBy=multi-user.target
578 EOF
579
580 i /etc/systemd/system/mailbindwatchdog.service <<EOF
581 [Unit]
582 Description=Watchdog to restart services relying on systemd-resolved dir
583 After=syslog.target network-online.target
584 Wants=network-online.target
585 BindsTo=mailnn.service
586
587 [Service]
588 Type=simple
589 ExecStart=/usr/local/bin/mailbindwatchdog $vpnser ${nn_progs[@]} unbound.service radicale.service
590 Restart=always
591 # time to sleep before restarting a service
592 RestartSec=10
593
594 [Install]
595 WantedBy=multi-user.target
596 EOF
597
598
599
600 # old service name
601 rm -fv /etc/systemd/system/openvpn-client-mail@.service
602
603 # We use a local unbound because systemd-resolved wont accept our
604 # request, it will only listen to 127.0.0.53 in the main network
605 # namespace, and rejected feature requests to change that (although I
606 # could change the code and recompile), but anyways, that could answer
607 # with things specific to the lan that aren't applicable in this
608 # namespace, and since unbound is a recursive resolver, it means we just
609 # use our own ip against dnsbl rate limits.
610 #
611 # If we ever notice this change, chattr +i on it
612 # trust-ad is used in t10+, glibc 2.31
613
614 i /etc/127.0.0.1-resolv/stub-resolv.conf <<'EOF'
615 nameserver 127.0.0.1
616 options edns0 trust-ad
617 EOF
618
619 i /etc/127.0.0.53-resolv/stub-resolv.conf <<'EOF'
620 nameserver 127.0.0.53
621 options edns0 trust-ad
622 EOF
623
624
625 i /etc/10.173.8.1-resolv/stub-resolv.conf <<'EOF'
626 nameserver 10.173.8.1
627 options edns0 trust-ad
628 EOF
629
630 # this is just a bug fix for trisquel.
631 f=/etc/apparmor.d/usr.sbin.unbound
632 line="/usr/sbin/unbound flags=(attach_disconnected) {"
633 if ! grep -qFx "$line" $f; then
634 badline="/usr/sbin/unbound {"
635 if ! grep -qFx "$badline" $f; then
636 err expected line in $f not found
637 fi
638 sed -i "s,^$badline$,$line," $f
639 if systemctl is-active apparmor &>/dev/null; then
640 m systemctl reload apparmor
641 fi
642 fi
643
644 # note: anything added to nn_progs needs corresponding rm
645 # down below in the host switch
646 nn_progs=(exim4)
647 if mailhost; then
648 # Note dovecots lmtp doesnt need to be in the same nn to accept delivery.
649 # Its in the nn so remote clients can connect to it.
650 nn_progs+=(spamassassin dovecot)
651 fi
652
653 case $HOSTNAME in
654 $MAIL_HOST)
655 i /etc/systemd/system/unbound.service.d/nn.conf <<EOF
656 [Unit]
657 After=mailnn.service
658 JoinsNamespaceOf=mailnn.service
659 BindsTo=mailnn.service
660 StartLimitIntervalSec=0
661
662 [Service]
663 PrivateNetwork=true
664 # note the nsswitch bind is actually not needed for bk, but
665 # its the same file so it does no harm.
666 BindPaths=$bindpaths
667
668 Restart=always
669 RestartSec=20
670 EOF
671
672 # sooo, there are a few ways to get traffic from the mail network
673 # namespace to go over the wghole.
674 #
675 #1: unify the mail vpn and wghole
676 # into 1 network. this seems simple and logical, so I'm doing it.
677 # One general downside is tying things together, if I need to mess
678 # with one thing, it breaks the other. Oh well for now.
679 #
680 # 2. We can route 10.5.3.0/24 out of the mail nn and nat it into wghole.
681 #
682 # 3. We can setup the routing to happen on li, which seemed like I
683 # just needed to add 10.8.0.4/24 to AllowedIPs in at least the
684 # wghole clients, but I think that is kind of hacky and breaks ipv4
685 # routing within the mailvpn, it happened to work just because exim
686 # prefers ipv6 and that was also available in the mailvpn.
687 #
688 # 4. Put the hole interface into the mail network namespace. This
689 # doesn't work if the mail vpn is wg. For openvpn, it bypasses the
690 # vpn routing and establishes a direct connection. I only use the
691 # hole vpn for randomish things, it should be fine to join the mail
692 # nn for that. There should be some way to fix the routing issue
693 # by doing manual routing, but that doesn't seem like a good use of time.
694 # relevant:
695 # https://www.wireguard.com/netns/#
696 #
697 # for wireguard debugging
698 # echo module wireguard +p > /sys/kernel/debug/dynamic_debug/control
699 # dmesg -w
700
701 ;;&
702 $MAIL_HOST|bk)
703 for unit in ${nn_progs[@]}; do
704 i /etc/systemd/system/$unit.service.d/nn.conf <<EOF
705 [Unit]
706 # commented for old openvpn
707 Requires=$vpnser
708 After=network.target mailnn.service $vpnser
709 JoinsNamespaceOf=mailnn.service
710 BindsTo=mailnn.service
711 StartLimitIntervalSec=0
712
713 [Service]
714 PrivateNetwork=true
715 # note the nsswitch bind is actually not needed for bk, but
716 # its the same file so it does no harm.
717 BindPaths=$bindpaths
718
719 Restart=always
720 RestartSec=20
721 EOF
722 done
723 ;;
724 *)
725 for unit in exim4 spamassassin dovecot unbound; do
726 f=/etc/systemd/system/$unit.service.d/nn.conf
727 if [[ -s $f ]]; then
728 rm -fv $f
729 reload=true
730 fi
731 done
732 ;;
733 esac
734
735 # * spamassassin config
736 i /etc/sysctl.d/80-iank-mail.conf <<'EOF'
737 # see exim spec
738 net.netfilter.nf_conntrack_tcp_timeout_close_wait = 120
739 EOF
740 if $ir; then
741 m sysctl -p
742 fi
743
744 i /etc/spamassassin/mylocal.cf <<'EOF'
745 # this is mylocal.cf because the normal local.cf has a bunch of upstream stuff i dont want to mess with
746
747 # /usr/share/doc/exim4-base/README.Debian.gz:
748 # SpamAssassin's default report should not be used in a add_header
749 # statement since it contains empty lines. (This triggers e.g. Amavis'
750 # warning "BAD HEADER SECTION, Improper folded header field made up
751 # entirely of whitespace".) This is a safe, terse alternative:
752 clear_report_template
753 report (_SCORE_ / _REQD_ requ) _TESTSSCORES(,)_ autolearn=_AUTOLEARN
754 uridnsbl_skip_domain iankelling.org
755 uridnsbl_skip_domain amnimal.ninja
756 uridnsbl_skip_domain expertpathologyreview.com
757 uridnsbl_skip_domain zroe.org
758 EOF
759
760 # 2020-10-19 remove old file. remove this when all hosts updated
761 rm -fv /etc/systemd/system/spamddnsfix.{timer,service}
762
763 i /etc/default/spamassassin <<'EOF'
764 # defaults plus debugging flags for an issue im having
765 OPTIONS="--create-prefs --max-children 5 --helper-home-dir"
766 PIDFILE="/var/run/spamd.pid"
767 # my additions
768 NICE="--nicelevel 15"
769 CRON=1
770 EOF
771 ##### end spamassassin config
772
773
774 # * Update mail cert
775 if [[ -e /p/c/filesystem ]]; then
776 # note, man openvpn implies we could just call mail-route on vpn startup/shutdown with
777 # systemd, buuut it can remake the tun device unexpectedly, i got this in the log
778 # after my internet was down for a bit:
779 # NOTE: Pulled options changed on restart, will need to close and reopen TUN/TAP device.
780 m /a/exe/vpn-mk-client-cert -b mailclient -n mail li.iankelling.org
781 fi
782 case $HOSTNAME in
783 bk)
784 if [[ ! -e /etc/openvpn/client/mail.conf ]]; then
785 echo "$0: error: first, on a system with /p/c/filesystem, run mail-setup, or the vpn-mk-client-cert line above this err" 2>&2
786 exit 1
787 fi
788 ;;
789 esac
790
791 m rsync -aiSAX --chown=root:root --chmod=g-s /a/bin/ds/mail-cert-cron /usr/local/bin
792
793 i /etc/systemd/system/mailcert.service <<'EOF'
794 [Unit]
795 Description=Mail cert rsync
796 After=multi-user.target
797
798 [Service]
799 Type=oneshot
800 ExecStart=/usr/local/bin/sysd-mail-once mailcert /usr/local/bin/mail-cert-cron
801 EOF
802 i /etc/systemd/system/mailcert.timer <<'EOF'
803 [Unit]
804 Description=Run mail-cert once a day
805
806 [Timer]
807 OnCalendar=daily
808
809 [Install]
810 WantedBy=timers.target
811 EOF
812
813
814 wghost=${HOSTNAME}wg.b8.nz
815 if $bhost_t && [[ ! -e /etc/exim4/certs/$wghost/privkey.pem ]]; then
816 certbot -n --manual-public-ip-logging-ok --eff-email --agree-tos -m letsencrypt@iankelling.org \
817 certonly --manual --preferred-challenges=dns \
818 --manual-auth-hook /a/bin/ds/le-dns-challenge \
819 --manual-cleanup-hook /a/bin/ds/le-dns-challenge-cleanup \
820 --deploy-hook /a/bin/ds/le-exim-deploy -d $wghost
821 fi
822
823 # * fail2ban
824
825 # todo: test that these configs actually work, eg run
826 # s iptables-exim -S
827 # and see someone is banned.
828
829 sed 's/^ *before *= *iptables-common.conf/before = iptables-common-exim.conf/' \
830 /etc/fail2ban/action.d/iptables-multiport.conf| i /etc/fail2ban/action.d/iptables-exim.conf
831 i /etc/fail2ban/action.d/iptables-common-exim.conf <<'EOF'
832 # iank: same as iptables-common, except iptables is iptables-exim, ip6tables is ip6tables-exim
833
834 # Fail2Ban configuration file
835 #
836 # Author: Daniel Black
837 #
838 # This is a included configuration file and includes the definitions for the iptables
839 # used in all iptables based actions by default.
840 #
841 # The user can override the defaults in iptables-common.local
842 #
843 # Modified: Alexander Koeppe <format_c@online.de>, Serg G. Brester <serg.brester@sebres.de>
844 # made config file IPv6 capable (see new section Init?family=inet6)
845
846 [INCLUDES]
847
848 after = iptables-blocktype.local
849 iptables-common.local
850 # iptables-blocktype.local is obsolete
851
852 [Definition]
853
854 # Option: actionflush
855 # Notes.: command executed once to flush IPS, by shutdown (resp. by stop of the jail or this action)
856 # Values: CMD
857 #
858 actionflush = <iptables> -F f2b-<name>
859
860
861 [Init]
862
863 # Option: chain
864 # Notes specifies the iptables chain to which the Fail2Ban rules should be
865 # added
866 # Values: STRING Default: INPUT
867 chain = INPUT
868
869 # Default name of the chain
870 #
871 name = default
872
873 # Option: port
874 # Notes.: specifies port to monitor
875 # Values: [ NUM | STRING ] Default:
876 #
877 port = ssh
878
879 # Option: protocol
880 # Notes.: internally used by config reader for interpolations.
881 # Values: [ tcp | udp | icmp | all ] Default: tcp
882 #
883 protocol = tcp
884
885 # Option: blocktype
886 # Note: This is what the action does with rules. This can be any jump target
887 # as per the iptables man page (section 8). Common values are DROP
888 # REJECT, REJECT --reject-with icmp-port-unreachable
889 # Values: STRING
890 blocktype = REJECT --reject-with icmp-port-unreachable
891
892 # Option: returntype
893 # Note: This is the default rule on "actionstart". This should be RETURN
894 # in all (blocking) actions, except REJECT in allowing actions.
895 # Values: STRING
896 returntype = RETURN
897
898 # Option: lockingopt
899 # Notes.: Option was introduced to iptables to prevent multiple instances from
900 # running concurrently and causing irratic behavior. -w was introduced
901 # in iptables 1.4.20, so might be absent on older systems
902 # See https://github.com/fail2ban/fail2ban/issues/1122
903 # Values: STRING
904 lockingopt = -w
905
906 # Option: iptables
907 # Notes.: Actual command to be executed, including common to all calls options
908 # Values: STRING
909 iptables = /usr/local/bin/iptables-exim <lockingopt>
910
911
912 [Init?family=inet6]
913
914 # Option: blocktype (ipv6)
915 # Note: This is what the action does with rules. This can be any jump target
916 # as per the iptables man page (section 8). Common values are DROP
917 # REJECT, REJECT --reject-with icmp6-port-unreachable
918 # Values: STRING
919 blocktype = REJECT --reject-with icmp6-port-unreachable
920
921 # Option: iptables (ipv6)
922 # Notes.: Actual command to be executed, including common to all calls options
923 # Values: STRING
924 iptables = /usr/local/bin/ip6tables-exim <lockingopt>
925 EOF
926
927 i /etc/fail2ban/jail.d/exim.local <<'EOF'
928 [exim]
929 enabled = true
930 port = 25,587
931 filter = exim
932 banaction = iptables-exim
933 EOF
934 if $ir; then
935 m systemctl restart fail2ban
936 fi
937
938 # * common exim4 config
939
940
941 ## old, not using forward files anymore
942 rm -fv $uhome/.forward /root/.forward
943
944
945 # Make all system users be aliases. preventative
946 # prevents things like cron mail for user without alias
947 awk 'BEGIN { FS = ":" } ; $6 !~ /^\/home/ || $7 ~ /\/nologin$/ { print $1 }' /etc/passwd| while read -r user; do
948 if [[ ! $user ]]; then
949 continue
950 fi
951 if ! grep -q "^$user:" /etc/aliases; then
952 echo "$user: root" |m tee -a /etc/aliases
953 fi
954 done
955
956
957 awk 'BEGIN { FS = ":" } ; $6 ~ /^\/home/ && $7 !~ /\/nologin$/ { print $1 }' /etc/passwd| while read -r user; do
958 case $HOSTNAME in
959 $MAIL_HOST)
960 sed -i "/^user:/d" /etc/aliases
961 ;;
962 *)
963 if ! grep -q "^$user:" /etc/aliases; then
964 echo "$user: root" |m tee -a /etc/aliases
965 fi
966 ;;
967 esac
968 done
969
970 if ! grep -q "^ncsoft:" /etc/aliases; then
971 echo "ncsoft: graceq2323@gmail.com" |m tee -a /etc/aliases
972 fi
973
974
975
976 m gpasswd -a iank adm #needed for reading logs
977
978 ### make local bounces go to normal maildir
979 # local mail that bounces goes to /Maildir or /root/Maildir
980 dirs=(/m/md/bounces/{cur,tmp,new})
981 m mkdir -p ${dirs[@]}
982 m chown iank:iank /m /m/md
983 m ln -sfT /m/md /m/iank
984 m chmod 771 /m /m/md
985 m chown -R $u:Debian-exim /m/md/bounces
986 m chmod 775 ${dirs[@]}
987 m usermod -a -G Debian-exim $u
988 for d in /Maildir /root/Maildir; do
989 if [[ ! -L $d ]]; then
990 m rm -rf $d
991 fi
992 m ln -sf -T /m/md/bounces $d
993 done
994
995 # dkim, client passwd file
996 files=(/p/c/machine_specific/$HOSTNAME/filesystem/etc/exim4/*)
997 f=/p/c/filesystem/etc/exim4/passwd.client
998 if [[ -e $f ]]; then
999 files+=($f)
1000 fi
1001 if (( ${#files[@]} )); then
1002 m rsync -ahhi --chown=root:Debian-exim --chmod=0640 \
1003 ${files[@]} /etc/exim4
1004 fi
1005
1006 # by default, only 10 days of logs are kept. increase that.
1007 m sed -ri 's/^(\s*rotate\s).*/\11000/' /etc/logrotate.d/exim4-base
1008
1009
1010 ## disabled. not using .forward files, but this is still interesting
1011 ## for reference.
1012 # ## https://blog.dhampir.no/content/make-exim4-on-debian-respect-forward-and-etcaliases-when-using-a-smarthost
1013 # # i only need .forwards, so just doing that one.
1014 # cd /etc/exim4/conf.d/router
1015 # b=userforward_higher_priority
1016 # # replace the router name so it is unique
1017 # sed -r s/^\\S+:/$b:/ 600_exim4-config_userforward >175_$b
1018
1019 # todo, consider 'separate' in etc/exim4.conf, could it help on busy systems?
1020
1021 # alerts is basically the postmaster address
1022 m sed -i --follow-symlinks -f - /etc/aliases <<EOF
1023 \$a root: alerts@iankelling.org
1024 /^root:/d
1025 EOF
1026
1027 cat >/etc/exim4/conf.d/rewrite/34_iank_rewriting <<'EOF'
1028 ncsoft@zroe.org graceq2323@gmail.com hE
1029 EOF
1030
1031 # old name
1032 rm -fv /etc/exim4/conf.d/retry/37_retry
1033
1034 cat >/etc/exim4/conf.d/retry/17_retry <<'EOF'
1035 # Retry fast for my own domains
1036 iankelling.org * F,1d,10m;F,14d,1h
1037 amnimal.ninja * F,1d,10m;F,14d,1h
1038 expertpathologyreview.com * F,1d,10m;F,14d,1h
1039 je.b8.nz * F,1d,10m;F,14d,1h
1040 zroe.org * F,1d,10m;F,14d,1h
1041 eximbackup.b8.nz * F,1d,4m;F,14d,1h
1042 EOF
1043
1044
1045 rm -vf /etc/exim4/conf.d/main/000_localmacros # old filename
1046 cat >/etc/exim4/conf.d/main/000_local <<EOF
1047 MAIN_TLS_ENABLE = true
1048
1049 # require tls connections for all smarthosts
1050 REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS = *
1051
1052 # debian exim config added this in 2016 or so?
1053 # it's part of the smtp spec, to limit lines to 998 chars
1054 # but a fair amount of legit mail does not adhere to it. I don't think
1055 # this should be default, like it says in
1056 # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=828801
1057 # todo: the bug for introducing this was about headers, but
1058 # the fix maybe is for all lines? one says gmail rejects, the
1059 # other says gmail does not reject. figure out and open a new bug.
1060 IGNORE_SMTP_LINE_LENGTH_LIMIT = true
1061
1062 # more verbose logs
1063 MAIN_LOG_SELECTOR = +all
1064
1065 # Based on spec, seems like a good idea to be nice.
1066 smtp_return_error_details = true
1067
1068 # normally empty, I set this so I can set the envelope address
1069 # when doing mail redelivery to invoke filters. Also allows
1070 # me exiqgrep and stuff.
1071 MAIN_TRUSTED_GROUPS = $u
1072
1073 # default is 10. when exim has been down for a bit, fsf mailserver
1074 # will do a big send in one connection, then exim decides to put
1075 # the messages in the queue instead of delivering them, to avoid
1076 # spawning too many delivery processes. This is the same as the
1077 # fsfs value. And the corresponding one for how many messages
1078 # to send out in 1 connection remote_max_parallel = 256
1079 smtp_accept_queue_per_connection = 500
1080
1081
1082 DKIM_CANON = relaxed
1083 DKIM_SELECTOR = li
1084
1085 # from comments in
1086 # https://debian-administration.org/article/718/DKIM-signing_outgoing_mail_with_exim4
1087 # and its best for this to align https://tools.ietf.org/html/rfc7489#page-8
1088 # There could be some circumstance when the
1089 # from: isnt our domain, but the envelope sender is
1090 # and so still want to sign, but I cant think of any case.
1091 DKIM_DOMAIN = \${lc:\${domain:\$rh_from:}}
1092 # The file is based on the outgoing domain-name in the from-header.
1093 # sign if key exists
1094 DKIM_PRIVATE_KEY = \${if exists{/etc/exim4/\${dkim_domain}-private.pem} {/etc/exim4/\${dkim_domain}-private.pem}}
1095
1096 # most of the ones that gmail seems to use.
1097 # Exim has horrible default of signing unincluded
1098 # list- headers since they got mentioned in an
1099 # rfc, but this messes up mailing lists, like gnu/debian which want to
1100 # keep your dkim signature intact but add list- headers.
1101 DKIM_SIGN_HEADERS = mime-version:in-reply-to:references:from:date:subject:to
1102
1103 domainlist local_hostnames = ! je.b8.nz : ! bk.b8.nz : *.b8.nz : b8.nz
1104
1105 hostlist iank_trusted = <; \\
1106 # veth0
1107 10.173.8.1 ; \\
1108 # li li_ip6
1109 72.14.176.105 ; 2600:3c00::f03c:91ff:fe6d:baf8 ; \\
1110 # li_vpn_net li_vpn_net_ip6s
1111 10.8.0.0/24; 2600:3c00:e000:280::/64 ; 2600:3c00:e002:3800::/56 ; \\
1112 # bk bk_ip6
1113 85.119.83.50 ; 2001:ba8:1f1:f0c9::2 ; \\
1114 # je je_ipv6
1115 85.119.82.128 ; 2001:ba8:1f1:f09d::2 ; \\
1116 # fsf_mit_net fsf_mit_net_ip6 fsf_net fsf_net_ip6 fsf_office_net
1117 18.4.89.0/24 ; 2603:3005:71a:2e00::/64 ; 209.51.188.0/24 ; 2001:470:142::/48 ; 74.94.156.208/28
1118 EOF
1119
1120 rm -fv /etc/exim4/rcpt_local_acl # old path
1121
1122 i /etc/exim4/conf.d/local_deny_exceptions_acl <<'EOF'
1123 # This acl already exists in rcpt, this just makes it more widespread.
1124 # See the comment there for its rationale. The reason it needs to be
1125 # more widespread is that I've turned on sender verification, but cron
1126 # emails can fail sender verification since I may be in a network that
1127 # doesn't have my local dns.
1128 accept
1129 authenticated = *
1130
1131 # i setup a local programs smtp to mail.iankelling.org, this
1132 # skips sender verification for it.
1133 accept
1134 hosts = 10.173.8.1
1135 EOF
1136
1137 rm -fv /etc/exim4/data_local_acl # old path
1138 i /etc/exim4/conf.d/data_local_acl <<'EOF'
1139 # Except for the "condition =", this was
1140 # a comment in the check_data acl. The comment about this not
1141 # being suitable has been changed in newer exim versions. The only thing
1142 # related I found was to
1143 # add the condition =, cuz spamassassin has problems with big
1144 # messages and spammers don't bother with big messages,
1145 # but I've increased the size from 10k
1146 # suggested in official docs, and 100k in the wiki example because
1147 # those docs are rather old and I see a 110k spam message
1148 # pretty quickly looking through my spam folder.
1149
1150 warn
1151 !hosts = +iank_trusted
1152 remove_header = X-Spam_score: X-Spam_score_int : X-Spam_bar : X-Spam_report
1153
1154 warn
1155 !hosts = +iank_trusted
1156 condition = ${if < {$message_size}{5000K}}
1157 spam = Debian-exim:true
1158 add_header = X-Spam_score_int: $spam_score_int
1159 add_header = X-Spam_score: $spam_score
1160 add_header = X-Spam_bar: $spam_bar
1161 add_header = X-Spam_report: $spam_report
1162 add_header = X-Spam_action: $spam_action
1163
1164 warn
1165 condition = ${if def:malware_name}
1166 remove_header = Subject:
1167 add_header = Subject: [Clamav warning: $malware_name] $h_subject
1168 log_message = heuristic malware warning: $malware_name
1169
1170 #accept
1171 # spf = pass:fail:softfail:none:neutral:permerror:temperror
1172 # dmarc_status = reject:quarantine
1173 # add_header = Reply-to: dmarctest@iankelling.org
1174
1175 EOF
1176
1177 i /etc/exim4/conf.d/router/900_exim4-config_local_user <<EOF
1178 ### router/900_exim4-config_local_user
1179 #################################
1180
1181 # This router matches local user mailboxes. If the router fails, the error
1182 # message is "Unknown user".
1183 local_user:
1184 debug_print = "R: local_user for \$local_part@\$domain"
1185 driver = accept
1186 domains = +local_domains
1187 # ian: default file except where mentioned.
1188 # ian: commented this. I get all local parts. for bk, an rcpt
1189 # check handles checking with dovecot, and the only router
1190 # after this is root.
1191 # local_parts = ! root
1192 transport = LOCAL_DELIVERY
1193 cannot_route_message = Unknown user
1194 # ian: added for + addressing.
1195 local_part_suffix = +*
1196 local_part_suffix_optional
1197 EOF
1198 i /etc/exim4/conf.d/transport/30_exim4-config_dovecot_lmtp <<'EOF'
1199 dovecot_lmtp:
1200 driver = lmtp
1201 socket = /var/run/dovecot/lmtp
1202 #maximum number of deliveries per batch, default 1
1203 batch_max = 200
1204 envelope_to_add
1205 EOF
1206
1207 i /etc/exim4/conf.d/transport/30_remote_smtp_vpn <<'EOF'
1208 # same as debians 30_exim4-config_remote_smtp, but
1209 # with interface added at the end.
1210
1211 remote_smtp_vpn:
1212 debug_print = "T: remote_smtp_vpn for $local_part@$domain"
1213 driver = smtp
1214 .ifndef IGNORE_SMTP_LINE_LENGTH_LIMIT
1215 message_size_limit = ${if > {$max_received_linelength}{998} {1}{0}}
1216 .endif
1217 .ifdef REMOTE_SMTP_HOSTS_AVOID_TLS
1218 hosts_avoid_tls = REMOTE_SMTP_HOSTS_AVOID_TLS
1219 .endif
1220 .ifdef REMOTE_SMTP_HEADERS_REWRITE
1221 headers_rewrite = REMOTE_SMTP_HEADERS_REWRITE
1222 .endif
1223 .ifdef REMOTE_SMTP_RETURN_PATH
1224 return_path = REMOTE_SMTP_RETURN_PATH
1225 .endif
1226 .ifdef REMOTE_SMTP_HELO_DATA
1227 helo_data=REMOTE_SMTP_HELO_DATA
1228 .endif
1229 .ifdef DKIM_DOMAIN
1230 dkim_domain = DKIM_DOMAIN
1231 .endif
1232 .ifdef DKIM_SELECTOR
1233 dkim_selector = DKIM_SELECTOR
1234 .endif
1235 .ifdef DKIM_PRIVATE_KEY
1236 dkim_private_key = DKIM_PRIVATE_KEY
1237 .endif
1238 .ifdef DKIM_CANON
1239 dkim_canon = DKIM_CANON
1240 .endif
1241 .ifdef DKIM_STRICT
1242 dkim_strict = DKIM_STRICT
1243 .endif
1244 .ifdef DKIM_SIGN_HEADERS
1245 dkim_sign_headers = DKIM_SIGN_HEADERS
1246 .endif
1247 .ifdef TLS_DH_MIN_BITS
1248 tls_dh_min_bits = TLS_DH_MIN_BITS
1249 .endif
1250 .ifdef REMOTE_SMTP_TLS_CERTIFICATE
1251 tls_certificate = REMOTE_SMTP_TLS_CERTIFICATE
1252 .endif
1253 .ifdef REMOTE_SMTP_PRIVATEKEY
1254 tls_privatekey = REMOTE_SMTP_PRIVATEKEY
1255 .endif
1256 .ifdef REMOTE_SMTP_HOSTS_REQUIRE_TLS
1257 hosts_require_tls = REMOTE_SMTP_HOSTS_REQUIRE_TLS
1258 .endif
1259 .ifdef REMOTE_SMTP_TRANSPORTS_HEADERS_REMOVE
1260 headers_remove = REMOTE_SMTP_TRANSPORTS_HEADERS_REMOVE
1261 .endif
1262 interface = <; 10.8.0.4 ; 2600:3c00:e002:3800::4
1263 EOF
1264
1265 i /etc/exim4/conf.d/transport/30_smarthost_dkim <<'EOF'
1266 # ian: this is remote_smtp_smarthost plus the dkim parts from remote_smtp
1267
1268 smarthost_dkim:
1269 debug_print = "T: remote_smtp_smarthost for $local_part@$domain"
1270 driver = smtp
1271 multi_domain
1272 .ifndef IGNORE_SMTP_LINE_LENGTH_LIMIT
1273 message_size_limit = ${if > {$max_received_linelength}{998} {1}{0}}
1274 .endif
1275 hosts_try_auth = <; ${if exists{CONFDIR/passwd.client} \
1276 {\
1277 ${lookup{$host}nwildlsearch{CONFDIR/passwd.client}{$host_address}}\
1278 }\
1279 {} \
1280 }
1281 .ifdef REMOTE_SMTP_SMARTHOST_HOSTS_AVOID_TLS
1282 hosts_avoid_tls = REMOTE_SMTP_SMARTHOST_HOSTS_AVOID_TLS
1283 .endif
1284 .ifdef REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS
1285 hosts_require_tls = REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS
1286 .endif
1287 .ifdef REMOTE_SMTP_SMARTHOST_TLS_VERIFY_CERTIFICATES
1288 tls_verify_certificates = REMOTE_SMTP_SMARTHOST_TLS_VERIFY_CERTIFICATES
1289 .endif
1290 .ifdef REMOTE_SMTP_SMARTHOST_TLS_VERIFY_HOSTS
1291 tls_verify_hosts = REMOTE_SMTP_SMARTHOST_TLS_VERIFY_HOST
1292 .endif
1293 .ifdef REMOTE_SMTP_HEADERS_REWRITE
1294 headers_rewrite = REMOTE_SMTP_HEADERS_REWRITE
1295 .endif
1296 .ifdef REMOTE_SMTP_RETURN_PATH
1297 return_path = REMOTE_SMTP_RETURN_PATH
1298 .endif
1299 .ifdef REMOTE_SMTP_HELO_DATA
1300 helo_data=REMOTE_SMTP_HELO_DATA
1301 .endif
1302 .ifdef TLS_DH_MIN_BITS
1303 tls_dh_min_bits = TLS_DH_MIN_BITS
1304 .endif
1305 .ifdef REMOTE_SMTP_SMARTHOST_TLS_CERTIFICATE
1306 tls_certificate = REMOTE_SMTP_SMARTHOST_TLS_CERTIFICATE
1307 .endif
1308 .ifdef REMOTE_SMTP_SMARTHOST_PRIVATEKEY
1309 tls_privatekey = REMOTE_SMTP_SMARTHOST_PRIVATEKEY
1310 .endif
1311 .ifdef REMOTE_SMTP_TRANSPORTS_HEADERS_REMOVE
1312 headers_remove = REMOTE_SMTP_TRANSPORTS_HEADERS_REMOVE
1313 .endif
1314 .ifdef DKIM_DOMAIN
1315 dkim_domain = DKIM_DOMAIN
1316 .endif
1317 .ifdef DKIM_SELECTOR
1318 dkim_selector = DKIM_SELECTOR
1319 .endif
1320 .ifdef DKIM_PRIVATE_KEY
1321 dkim_private_key = DKIM_PRIVATE_KEY
1322 .endif
1323 .ifdef DKIM_CANON
1324 dkim_canon = DKIM_CANON
1325 .endif
1326 .ifdef DKIM_STRICT
1327 dkim_strict = DKIM_STRICT
1328 .endif
1329 .ifdef DKIM_SIGN_HEADERS
1330 dkim_sign_headers = DKIM_SIGN_HEADERS
1331 .endif
1332 EOF
1333
1334
1335 cat >/etc/exim4/update-exim4.conf.conf <<'EOF'
1336 # default stuff, i havent checked if its needed
1337 dc_minimaldns='false'
1338 dc_relay_nets=''
1339 CFILEMODE='644'
1340 dc_use_split_config='true'
1341 dc_mailname_in_oh='true'
1342 EOF
1343
1344
1345 # * radicale
1346 if mailhost; then
1347 if ! mountpoint /o; then
1348 echo "error /o is not a mountpoint" >&2
1349 exit 1
1350 fi
1351
1352 # davx/davdroid setup instructions at the bottom
1353
1354 # main docs:
1355 # http://radicale.org/user_documentation/
1356 # https://davdroid.bitfire.at/configuration/
1357
1358 # note on debugging: if radicale can't bind to the address,
1359 # in the log it just says "Starting Radicale". If you run
1360 # it in the foreground, it will give more info. Background
1361 # plus debug does not help.
1362 # sudo -u radicale radicale -D -f
1363
1364 # created password file with:
1365 # htpasswd -c /p/c/machine_specific/li/filesystem/etc/caldav-htpasswd
1366 # chmod 640 /p/c/machine_specific/li/filesystem/etc/caldav-htpasswd
1367 # # setup chgrp www-data in ./conflink
1368
1369 pi-nostart radicale
1370
1371 i /etc/systemd/system/radicale.service.d/override.conf <<EOF
1372 [Unit]
1373 # this unit is configured to start and stop whenever
1374 # $vpnser does
1375
1376 After=network.target network-online.target mailnn.service $vpnser
1377 BindsTo=$vpnser
1378
1379 Wants=network-online.target
1380 JoinsNamespaceOf=mailnn.service
1381 StartLimitIntervalSec=0
1382
1383 [Service]
1384 PrivateNetwork=true
1385 BindPaths=$bindpaths
1386 Restart=always
1387 # time to sleep before restarting a service
1388 RestartSec=20
1389
1390 [Install]
1391 # for openvpn
1392 RequiredBy=$vpnser
1393 EOF
1394
1395
1396 # use persistent uid/gid
1397 IFS=:; read -r _ _ uid _ < <(getent passwd radicale ); unset IFS
1398 IFS=:; read -r _ _ gid _ < <(getent group radicale ); unset IFS
1399 if [[ $uid != 609 ]]; then
1400 m systemctl stop radicale ||:
1401 m usermod -u 609 radicale
1402 m groupmod -g 609 radicale
1403 m usermod -g 609 radicale
1404 fi
1405 m find /o/radicale -xdev -exec chown -h 609 {} +
1406 m find /o/radicale -xdev -exec chgrp -h 609 {} +
1407
1408
1409 # I moved /var/lib/radicale after it's initialization.
1410 # I did a sudo -u radicale git init in the collections subfolder
1411 # after it gets created, per the git docs.
1412 m /a/exe/lnf -T /o/radicale /var/lib/radicale
1413
1414 # from https://www.williamjbowman.com/blog/2015/07/24/setting-up-webdav-caldav-and-carddav-servers/
1415
1416 # more config is for li in distro-end
1417
1418 # coment in this file says this is needed for it to run on startup
1419 sed -ri 's/^\s*#+\s*(ENABLE_RADICALE\s*=\s*yes\s*)/\1/' /etc/default/radicale
1420
1421 # comments say default is 0.0.0.0:5232
1422 m setini hosts 10.8.0.4:5232 server
1423 # https://radicale.org/2.1.html
1424 m setini type http_x_remote_user auth
1425
1426
1427 # disable power management feature, set to 240 min sync interval,
1428 # so it shouldn't be bad.
1429
1430 # davdroid from f-druid.
1431 # login with url and user name
1432 # url https://cal.iankelling.org/ian
1433 # username ian
1434 # pass, see password manager for radicale
1435 #
1436 # add account dialog:
1437 #
1438 # set account name as ian@iankelling.org, per help text below the
1439 # field.
1440 #
1441 # switch to groups are per-contact categories,
1442 # per https://davdroid.bitfire.at/configuration/radicale/
1443 #
1444 #
1445 # After setting up account, I added one address book, named
1446 # ianaddr. calender was already created, named ian. checked boxes under
1447 # both. synced.
1448 #
1449 # To restore from old phone to new phone, I wiped all data out, then copied over the newly created files. I think
1450 #
1451 # ignorable background info:
1452 #
1453 # opentasks uses the calendar file.
1454 #
1455 # The address book I created got a uuid as a name for the file. Note
1456 # the .props file says if it's a calendar or addressbook.
1457 #
1458 # When debugging, tailed /var/log/radicale/radicale.log and apache log,
1459 # both show the requests happening. Without creating the address book,
1460 # after creating a contact, a sync would delete it.
1461 #
1462 # Address books correspond to .props files in the radicale dir.
1463 #
1464 # Some background is here,
1465 # https://davdroid.bitfire.at/faq/entry/cant-manage-groups-on-device/
1466 # which shows separate vcard option is from rfc 6350, the other is 2426,
1467 # radicale page says it implements the former not the latter,
1468 # which conflicts with the documentation of which to select, but whatever.
1469 # http://radicale.org/technical_choices/
1470 # https://davdroid.bitfire.at/faq/entry/cant-manage-groups-on-device/
1471 #
1472 # Note, url above says only cayanogenmod 13+ and omnirom can manage groups.
1473
1474 # Note, radicale had built-in git support to track changes, but they
1475 # removed it in 2.0.
1476
1477 fi
1478
1479 # * dovecot
1480
1481 # ** $MAIL_HOST|bk|je)
1482 case $HOSTNAME in
1483 $MAIL_HOST|bk|je)
1484 # based on a little google and package search, just the dovecot
1485 # packages we need instead of dovecot-common.
1486 #
1487 # dovecot-lmtpd is for exim to deliver to dovecot instead of maildir
1488 # directly. The reason to do this is to use dovecot\'s sieve, which
1489 # can generally do more than exims filters (a few things less) and
1490 # sieve has the benefit of being supported in postfix and
1491 # proprietary/weird environments, so there is more examples on the
1492 # internet.
1493 pi dovecot-core dovecot-imapd dovecot-sieve dovecot-lmtpd dovecot-sqlite sqlite3
1494
1495 for f in /p/c{/machine_specific/$HOSTNAME,}/filesystem/etc/dovecot/users; do
1496 if [[ -e $f ]]; then
1497 m rsync -ahhi --chown=root:dovecot --chmod=0640 $f /etc/dovecot/
1498 break
1499 fi
1500 done
1501 for f in /p/c/subdir_files/sieve/*sieve /a/bin/ds/subdir_files/sieve/*sieve; do
1502 m sudo -u $u /a/exe/lnf -v -T $f $uhome/sieve/${f##*/}
1503 done
1504
1505 # https://wiki.dovecot.org/SSL/DovecotConfiguration
1506 i /etc/dovecot/dhparam <<'EOF'
1507 -----BEGIN DH PARAMETERS-----
1508 MIIBCAKCAQEAoleil6SBxGqQKk7j0y2vV3Oklv6XupZKn7PkPv485QuFeFagifeS
1509 A+Jz6Wquqk5zhGyCu63Hp4wzGs4TyQqoLjkaWL6Ra/Bw3g3ofPEzMGEsV1Qdqde4
1510 jorwiwtr2i9E6TXQp0noT/7VFeHulIkayTeW8JulINdMHs+oLylv16McGCIrxbkM
1511 8D1PuO0TP/CNDs2QbRvJ1RjY3CeGpxMhrSHVgBCUMwnA2cvz3bYjI7UMYMMDPNrE
1512 PLrwsYzXGGCdJsO2vsmmqqgLsZiapYJlUNjfiyWLt7E2H6WzkNB3VIhIPfLqFDPK
1513 xioE3sYKdjOt+p6mlg3l8+OLtODEFPHDqwIBAg==
1514 -----END DH PARAMETERS-----
1515 EOF
1516 {
1517 if [[ $HOSTNAME == "$MAIL_HOST" ]]; then
1518 cat <<'EOF'
1519 ssl_cert = </etc/exim4/fullchain.pem
1520 ssl_key = </etc/exim4/privkey.pem
1521 EOF
1522 else
1523 cat <<'EOF'
1524 ssl_cert = </etc/exim4/exim.crt
1525 ssl_key = </etc/exim4/exim.key
1526 EOF
1527 fi
1528 cat <<EOF
1529 # https://ssl-config.mozilla.org
1530 ssl = required
1531 # this is the same as the certbot list, in my cert cronjob, I check if that has changed upstream.
1532 ssl_cipher_list = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
1533 ssl_protocols = TLSv1.2
1534 ssl_prefer_server_ciphers = no
1535
1536 protocol lmtp {
1537 #per https://wiki2.dovecot.org/Pigeonhole/Sieve/Configuration
1538 # default is just \$mail_plugins
1539 mail_plugins = \$mail_plugins sieve
1540 }
1541 EOF
1542 if dpkg --compare-versions $(dpkg-query -f='${Version}\n' --show dovecot-core) ge 1:2.3; then
1543 cat <<EOF
1544 ssl_dh = </etc/dovecot/dhparam
1545 EOF
1546 fi
1547 } >/etc/dovecot/local.conf
1548
1549 ;;&
1550
1551 # ** $MAIL_HOST)
1552 $MAIL_HOST)
1553 # If we changed 90-sieve.conf and removed the active part of the
1554 # sieve option, we wouldn\'t need this, but I\'d rather not modify a
1555 # default config if not needed. This won\'t work as a symlink in /a/c
1556 # unfortunately.
1557 m sudo -u $u /a/exe/lnf -T sieve/main.sieve $uhome/.dovecot.sieve
1558
1559 if [[ ! -e $uhome/sieve/personal.sieve ]]; then
1560 m touch $uhome/sieve/personal{,end}{,test}.sieve
1561 fi
1562
1563 rm -fv /etc/dovecot/conf.d/20-lmtp.conf # file from prev version
1564 cat >>/etc/dovecot/local.conf <<EOF
1565 # simple password file based login
1566 !include conf.d/auth-passwdfile.conf.ext
1567
1568 # ian: %u is used for alerts user vs iank
1569 mail_location = maildir:/m/%u:LAYOUT=fs:INBOX=/m/%u/INBOX
1570 mail_uid = $u
1571 mail_gid = $u
1572
1573 protocol lmtp {
1574 # For a normal setup with exim, we need something like this, which
1575 # removes the domain part
1576 # auth_username_format = %Ln
1577 #
1578 # or else # Exim says something like
1579 # "LMTP error after RCPT ... 550 ... User doesn't exist someuser@somedomain"
1580 # Dovecot verbose log says something like
1581 # "auth-worker(9048): passwd(someuser@somedomain): unknown user"
1582 # reference: http://wiki.dovecot.org/LMTP/Exim
1583 #
1584 # However, I use this to direct all mail to the same inbox.
1585 # A normal way to do this, which I did at first is to have
1586 # a router in exim almost at the end, eg 950,
1587 #local_catchall:
1588 # debug_print = "R: catchall for \$local_part@\$domain"
1589 # driver = redirect
1590 # domains = +local_domains
1591 # data = $u
1592 # based on
1593 # http://blog.alteholz.eu/2015/04/exim4-and-catchall-email-address/
1594 # with superflous options removed.
1595 # However, this causes the envelope to be rewritten,
1596 # which makes filtering into mailboxes a little less robust or more complicated,
1597 # so I've done it this way instead. it also requires
1598 # modifying the local router in exim.
1599 auth_username_format = $u
1600 }
1601 EOF
1602 ;;&
1603 # ** bk|je)
1604 bk|je)
1605 chown -R mail.mail /m/md
1606
1607 f=/etc/dovecot/conf.d/10-auth.conf
1608 if [[ -e $f ]]; then
1609 mv $f $f-iank-disabled
1610 fi
1611
1612 cat >>/etc/dovecot/local.conf <<EOF
1613 !include /etc/dovecot/local.conf.ext
1614
1615 # for debugging info, uncomment these.
1616 # logs go to syslog and to /var/log/mail.log
1617 #auth_verbose=yes
1618 #mail_debug=yes
1619
1620
1621 protocol lmtp {
1622 # This downcases the localpart. default is case sensitive.
1623 # case sensitive local part will miss out on valid email when some person or system
1624 # mistakenly capitalizes things.
1625 auth_username_format = %Lu
1626 }
1627
1628 # make 147 only listen on localhost, plan to use for nextcloud.
1629 # copied from mailinabox
1630 service imap-login {
1631 inet_listener imap {
1632 address = 127.0.0.1
1633 }
1634 }
1635 # https://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_dovecot_authenticator.html
1636 service auth {
1637 unix_listener auth-client {
1638 user = Debian-exim
1639 group = Debian-exim
1640 }
1641 }
1642
1643
1644 plugin {
1645 sieve_before = /etc/dovecot/sieve-spam.sieve
1646 # from mailinabox
1647 sieve = /m/sieve/%d/%n.sieve
1648 sieve_dir = /m/sieve/%d/%n
1649 }
1650
1651
1652 # all taken from mailinabox.
1653 mail_location = maildir:/m/md/%d/%n
1654 # meh, ok.
1655 mail_privileged_group = mail
1656 # By default Dovecot allows users to log in only with UID numbers 500 and above. mail is 8
1657 first_valid_uid = 1
1658
1659 # todo: test these changes in the universal config
1660 # mailboxes taken from mailinabox but removed
1661 # settings duplicate to defaults
1662 namespace inbox {
1663 mailbox INBOX {
1664 auto = subscribe
1665 }
1666 mailbox Spam {
1667 special_use = \Junk
1668 auto = subscribe
1669 }
1670 mailbox Drafts {
1671 auto = subscribe
1672 }
1673 mailbox Sent {
1674 auto = subscribe
1675 }
1676 mailbox Trash {
1677 auto = subscribe
1678 }
1679 mailbox Archive {
1680 special_use = \Archive
1681 auto = subscribe
1682 }
1683 }
1684 auth_mechanisms = plain login
1685 EOF
1686
1687 i /etc/dovecot/sieve-spam.sieve <<'EOF'
1688 require ["regex", "fileinto", "imap4flags"];
1689
1690 if allof (header :regex "X-Spam-Status" "^Yes") {
1691 fileinto "Spam";
1692 stop;
1693 }
1694 EOF
1695
1696 i /etc/dovecot/local.conf.ext <<'EOF'
1697 passdb {
1698 driver = sql
1699 args = /etc/dovecot/dovecot-sql.conf.ext
1700 }
1701 userdb {
1702 driver = sql
1703 args = /etc/dovecot/dovecot-sql.conf.ext
1704 }
1705
1706 EOF
1707
1708 i /etc/dovecot/dovecot-sql.conf.ext <<'EOF'
1709 # from mailinabox
1710 driver = sqlite
1711 connect = /m/rc/users.sqlite
1712 default_pass_scheme = SHA512-CRYPT
1713 password_query = SELECT email as user, password FROM users WHERE email='%u';
1714 user_query = SELECT email AS user, "mail" as uid, "mail" as gid, "/m/md/%d/%n" as home FROM users WHERE email='%u';
1715 iterate_query = SELECT email AS user FROM users;
1716 EOF
1717 m chmod 0600 /etc/dovecot/dovecot-sql.conf.ext # per Dovecot instructions
1718
1719 # db needs to be in a www-data writable directory
1720 db=/m/rc/users.sqlite
1721 if [[ ! -s $db ]]; then
1722 m mkdir -p /m/rc
1723 m sqlite3 $db <<'EOF'
1724 CREATE TABLE users (
1725 id INTEGER PRIMARY KEY AUTOINCREMENT,
1726 email TEXT NOT NULL UNIQUE,
1727 password TEXT NOT NULL,
1728 extra,
1729 privileges TEXT NOT NULL DEFAULT '');
1730 EOF
1731 fi
1732 # example of adding a user:
1733 # hash: doveadm pw -s SHA512-CRYPT -p passhere
1734 # sqlite3 /m/rc/users.sqlite <<'EOF'
1735 #insert into users (email, password) values ('testignore@bk.b8.nz', 'hash');
1736 #EOF
1737 # update users set password = 'hash' where email = 'testignore@bk.b8.nz';
1738
1739 # this should be at the end since it requires a valid dovecot config
1740 m sievec /etc/dovecot/sieve-spam.sieve
1741 ;;&
1742 # ** bk)
1743 bk)
1744 # roundcube uses this
1745 mkdir -p /m/sieve
1746 chown mail.mail /m/sieve
1747 m pi dovecot-managesieved
1748 ;;
1749 esac
1750
1751 # * thunderbird autoconfig setup
1752
1753 bkdomains=(expertpathologyreview.com amnimal.ninja)
1754 if [[ $HOSTNAME == bk ]]; then
1755 for domain in ${bkdomains[@]}; do
1756 m /a/exe/web-conf apache2 autoconfig.$domain
1757 dir=/var/www/autoconfig.$domain/html/mail
1758 m mkdir -p $dir
1759 # taken from mailinabox
1760 i $dir/config-v1.1.xml <<EOF
1761 <?xml version="1.0" encoding="UTF-8"?>
1762 <clientConfig version="1.1">
1763 <emailProvider id="$domain">
1764 <domain>$domain</domain>
1765
1766 <displayName>$domain Mail</displayName>
1767 <displayShortName>$domain</displayShortName>
1768
1769 <incomingServer type="imap">
1770 <hostname>mail2.iankelling.org</hostname>
1771 <port>993</port>
1772 <socketType>SSL</socketType>
1773 <username>%EMAILADDRESS%</username>
1774 <authentication>password-cleartext</authentication>
1775 </incomingServer>
1776
1777 <outgoingServer type="smtp">
1778 <hostname>mail2.iankelling.org</hostname>
1779 <port>587</port>
1780 <socketType>STARTTLS</socketType>
1781 <username>%EMAILADDRESS%</username>
1782 <authentication>password-cleartext</authentication>
1783 <addThisServer>true</addThisServer>
1784 <useGlobalPreferredServer>false</useGlobalPreferredServer>
1785 </outgoingServer>
1786
1787 <documentation url="https://$domain/">
1788 <descr lang="en">$domain website.</descr>
1789 </documentation>
1790 </emailProvider>
1791
1792 <webMail>
1793 <loginPage url="https://$domain/roundcube" />
1794 <loginPageInfo url="https://$domain/roundcube" >
1795 <username>%EMAILADDRESS%</username>
1796 <usernameField id="rcmloginuser" name="_user" />
1797 <passwordField id="rcmloginpwd" name="_pass" />
1798 <loginButton id="rcmloginsubmit" />
1799 </loginPageInfo>
1800 </webMail>
1801 <clientConfigUpdate url="https://autoconfig.$domain/mail/config-v1.1.xml" />
1802 </clientConfig>
1803 EOF
1804 done
1805 fi
1806
1807 # * roundcube setup
1808
1809 if [[ $HOSTNAME == bk ]]; then
1810
1811 # zip according to /installer
1812 # which requires adding a line to /usr/local/lib/roundcubemail/config/config.inc.php
1813 # $config['enable_installer'] = true;
1814 pi roundcube roundcube-sqlite3 php-zip apache2 php-fpm
1815
1816 ### begin composer install
1817 # https://getcomposer.org/doc/faqs/how-to-install-composer-programmatically.md
1818 # cd $(mktemp -d)
1819 # sum="$(wget -q -O - https://composer.github.io/installer.sig)"
1820 # m php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
1821 # if [[ $sum != $(php -r "echo hash_file('sha384', 'composer-setup.php');") ]]; then
1822 # echo 'ERROR: Invalid composer installer checksum' >&2
1823 # rm -fv composer-setup.php
1824 # exit 1
1825 # fi
1826 # m php composer-setup.php --quiet
1827 # rm -fv composer-setup.php
1828 # m mv composer.phar /usr/local/bin
1829
1830 # the above method gets composer2, carddav plugin at least doesnt work with that
1831 # yet, it was just released 10-24-2020.
1832 m cd /usr/local/bin
1833 m wget -nv -N https://getcomposer.org/composer-1.phar
1834 chmod +x composer-1.phar
1835 ### end composer install
1836
1837 rcdirs=(/usr/local/lib/rcexpertpath /usr/local/lib/rcninja)
1838 ncdirs=(/var/www/ncexpertpath /var/www/ncninja)
1839 # point debian cronjob to our local install, preventing daily cron error
1840
1841 # debian's cronjob will fail, remove both paths it uses just to be sure
1842 rm -fv /usr/share/roundcube/bin/cleandb.sh /etc/cron.d/roundcube-core
1843
1844 #### begin dl roundcube
1845 # note, im r2e subbed to https://github.com/roundcube/roundcubemail/releases.atom
1846 v=1.4.13; f=roundcubemail-$v-complete.tar.gz
1847 cd /a/opt
1848 if [[ -e $f ]]; then
1849 timestamp=$(stat -c %Y $f)
1850 else
1851 timestamp=0
1852 fi
1853 m wget -nv -N https://github.com/roundcube/roundcubemail/releases/download/$v/$f
1854 new_timestamp=$(stat -c %Y $f)
1855 for rcdir in ${rcdirs[@]}; do
1856 if [[ $timestamp != "$new_timestamp" || ! -e "$rcdir/config/secret" ]]; then
1857 m tar -C /usr/local/lib --no-same-owner -zxf $f
1858 m rm -rf $rcdir
1859 m mv /usr/local/lib/roundcubemail-$v $rcdir
1860 fi
1861 done
1862 #### end dl roundcube
1863
1864 for ((i=0; i < ${#bkdomains[@]}; i++)); do
1865 domain=${bkdomains[i]}
1866 rcdir=${rcdirs[i]}
1867 rcbase=${rcdir##*/}
1868 ncdir=${ncdirs[i]}
1869
1870 # copied from debians cronjob
1871 i /etc/cron.d/$rcbase <<EOF
1872 # Roundcube database cleaning: finally removes all records that are
1873 # marked as deleted.
1874 0 5 * * * www-data $rcdir/bin/cleandb.sh >/dev/null
1875 EOF
1876
1877 m /a/exe/web-conf - apache2 $domain <<EOF
1878 Alias /roundcube $rcdir
1879 ### begin roundcube settings
1880 # taken from /etc/apache2/conf-available/roundcube.conf version 1.4.8+dfsg.1-1~bpo10+1
1881 <Directory $rcdir/>
1882 Options +FollowSymLinks
1883 # This is needed to parse $rcdir/.htaccess.
1884 AllowOverride All
1885 Require all granted
1886 </Directory>
1887 # Protecting basic directories:
1888 <Directory $rcdir/config>
1889 Options -FollowSymLinks
1890 AllowOverride None
1891 </Directory>
1892 ### end roundcube settings
1893
1894
1895 ### begin nextcloud settings
1896 Alias /nextcloud "$ncdir/"
1897 <Directory $ncdir/>
1898 Require all granted
1899 AllowOverride All
1900 Options FollowSymLinks MultiViews
1901
1902 <IfModule mod_dav.c>
1903 Dav off
1904 </IfModule>
1905
1906 </Directory>
1907
1908 # based on install checker, links to
1909 # https://docs.nextcloud.com/server/19/admin_manual/issues/general_troubleshooting.html#service-discovery
1910 # their example was a bit wrong, I figured it out by adding
1911 # LogLevel warn rewrite:trace5
1912 # then watching the apache logs
1913
1914 RewriteEngine on
1915 RewriteRule ^/\.well-known/host-meta /nextcloud/public.php?service=host-meta [QSA,L]
1916 RewriteRule ^/\.well-known/host-meta\.json /nextcloud/public.php?service=host-meta-json [QSA,L]
1917 RewriteRule ^/\.well-known/webfinger /nextcloud/public.php?service=webfinger [QSA,L]
1918 RewriteRule ^/\.well-known/carddav /nextcloud/remote.php/dav/ [R=301,L]
1919 RewriteRule ^/\.well-known/caldav /nextcloud/remote.php/dav/ [R=301,L]
1920 ### end nextcloud settings
1921 EOF
1922 if [[ ! -e $rcdir/config/secret ]]; then
1923 base64 </dev/urandom | head -c24 >$rcdir/config/secret || [[ $? == 141 || ${PIPESTATUS[0]} == 32 ]]
1924 fi
1925 secret=$(cat $rcdir/config/secret)
1926
1927 rclogdir=/var/log/$rcbase
1928 rctmpdir=/var/tmp/$rcbase
1929 rcdb=/m/rc/$rcbase.sqlite
1930 # config from mailinabox
1931 i $rcdir/config/config.inc.php <<EOF
1932 <?php
1933 \$config = array();
1934 # debian creates this for us
1935 \$config['log_dir'] = '$rclogdir/';
1936 # debian also creates a temp dir, but it is under its install dir,
1937 # seems better to have our own.
1938 \$config['temp_dir'] = '$rctmpdir/';
1939 \$config['db_dsnw'] = 'sqlite:///$rcdb?mode=0640';
1940 \$config['default_host'] = 'ssl://localhost';
1941 \$config['default_port'] = 993;
1942 \$config['imap_conn_options'] = array(
1943 'ssl' => array(
1944 'verify_peer' => false,
1945 'verify_peer_name' => false,
1946 ),
1947 );
1948 \$config['imap_timeout'] = 15;
1949 \$config['smtp_server'] = 'tls://127.0.0.1';
1950 \$config['smtp_conn_options'] = array(
1951 'ssl' => array(
1952 'verify_peer' => false,
1953 'verify_peer_name' => false,
1954 ),
1955 );
1956 \$config['product_name'] = 'webmail';
1957 \$config['des_key'] = '$secret';
1958 \$config['plugins'] = array('archive', 'zipdownload', 'password', 'managesieve', 'jqueryui', 'carddav', 'html5_notifier');
1959 \$config['skin'] = 'elastic';
1960 \$config['login_autocomplete'] = 2;
1961 \$config['password_charset'] = 'UTF-8';
1962 \$config['junk_mbox'] = 'Spam';
1963 # disable builtin addressbook
1964 \$config['address_book_type'] = '';
1965 ?>
1966 EOF
1967
1968 m mkdir -p $rclogdir
1969 m chmod 750 $rclogdir
1970 m chown www-data:adm $rclogdir
1971 # note: subscribed to updates:
1972 # r2e add rcmcarddav https://github.com/blind-coder/rcmcarddav/commits/master.atom ian@iankelling.org
1973 # r2e add roundcube https://github.com/roundcube/roundcubemail/releases.atom ian@iankelling.org
1974 m mkdir -p $rctmpdir /m/rc
1975 m chown -R www-data.www-data $rctmpdir /m/rc
1976 m chmod 750 $rctmpdir
1977 # Ensure the log file monitored by fail2ban exists, or else fail2ban can't start.
1978 # todo: check for other mailinabox things
1979 m sudo -u www-data touch $rclogdir/errors.log
1980
1981 #### begin carddav install
1982 # This is the official roundcube carddav repo.
1983 # Install doc suggests downloading with composer, but that
1984 # didnt work, it said some ldap package for roundcube was missing,
1985 # but I dont want to download some extra ldap thing.
1986 # https://github.com/blind-coder/rcmcarddav/blob/master/doc/INSTALL.md
1987 verf=$rcdir/plugins/carddav/myversion
1988 upgrade=false
1989 install=false
1990 v=4.0.0
1991 if [[ -e $verf ]]; then
1992 if [[ $(cat $verf) != "$v" ]]; then
1993 install=true
1994 upgrade=true
1995 fi
1996 else
1997 install=true
1998 fi
1999 if $install; then
2000 m rm -rf $rcdir/plugins/carddav
2001 tmpd=$(mktemp -d)
2002 m wget -nv -O $tmpd/t.tgz https://github.com/blind-coder/rcmcarddav/releases/download/v$v/carddav-v$v.tgz
2003 cd $rcdir/plugins
2004 tar xzf $tmpd/t.tgz
2005 rm -rf $tmpd
2006 m chown -R www-data:www-data $rcdir/plugins/carddav
2007 m cd $rcdir/plugins/carddav
2008 if $upgrade; then
2009 m sudo -u www-data composer-1.phar update --no-dev
2010 else
2011 m sudo -u www-data composer-1.phar install --no-dev
2012 fi
2013 m chown -R root:root $rcdir/plugins/carddav
2014 echo $v >$verf
2015 fi
2016
2017 # So, strangely, this worked in initial testing, but then
2018 # on first run it wouldn't show the existing contacts until
2019 # I went into the carddav settings and did "force immediate sync",
2020 # which seemed to fix things. Note, some of these settings
2021 # get initalized per/addressbook in the db, then need changing
2022 # there or through the settings menu.
2023
2024 # About categories, see https://www.davx5.com/tested-with/nextcloud
2025 # https://github.com/blind-coder/rcmcarddav/blob/master/doc/GROUPS.md
2026 i $rcdir/plugins/carddav/config.inc.php <<EOF;
2027 <?php
2028 \$prefs['_GLOBAL']['hide_preferences'] = false;
2029 \$prefs['davserver'] = array(
2030 # name in the UI is kind of dumb. This is just something short that seems to fit ok.
2031 'name' => 'Main',
2032 'username' => '%u', // login username
2033 'password' => '%p', // login password
2034 'url' => 'https://$domain/nextcloud/remote.php/dav/addressbooks/users/%u/contacts',
2035 'active' => true,
2036 'readonly' => false,
2037 'refresh_time' => '00:10:00',
2038 'fixed' => array('username','password'),
2039 'use_categories' => false,
2040 'hide' => false,
2041 );
2042 ?>
2043 EOF
2044 #### end carddav install
2045
2046 cd $rcdir/plugins
2047 if [[ ! -d html5_notifier ]]; then
2048 m git clone https://github.com/stremlau/html5_notifier
2049 fi
2050 cd $rcdir/plugins/html5_notifier
2051 m git pull --rebase
2052
2053 # todo: try out roundcube plugins: thunderbird labels
2054
2055 # Password changing plugin settings
2056 cat $rcdir/plugins/password/config.inc.php.dist - >$rcdir/plugins/password/config.inc.php <<'EOF'
2057 # following are from mailinabox
2058 $config['password_minimum_length'] = 8;
2059 $config['password_db_dsn'] = 'sqlite:////m/rc/users.sqlite';
2060 $config['password_query'] = 'UPDATE users SET password=%D WHERE email=%u';
2061 $config['password_dovecotpw'] = '/usr/bin/doveadm pw';
2062 $config['password_dovecotpw_method'] = 'SHA512-CRYPT';
2063 $config['password_dovecotpw_with_method'] = true;
2064 EOF
2065 # so PHP can use doveadm, for the password changing plugin
2066 m usermod -a -G dovecot www-data
2067 m usermod -a -G mail $u
2068
2069 # so php can update passwords
2070 m chown www-data:dovecot /m/rc/users.sqlite
2071 m chmod 664 /m/rc/users.sqlite
2072
2073 # Run Roundcube database migration script (database is created if it does not exist)
2074 m $rcdir/bin/updatedb.sh --dir $rcdir/SQL --package roundcube
2075 m chown www-data:www-data $rcdb
2076 m chmod 664 $rcdb
2077 done # end loop over domains and rcdirs
2078
2079 ### begin php setup for rc ###
2080 # Enable PHP modules.
2081 m phpenmod -v php mcrypt imap
2082 # dpkg says this is required
2083 m a2enmod proxy_fcgi setenvif
2084 fpm=$(dpkg-query -s php-fpm | sed -nr 's/^Depends:.* (php[^ ]*-fpm)( .*|$)/\1/p') # eg: php7.4-fpm
2085 phpver=$(dpkg-query -s php-fpm | sed -nr 's/^Depends:.* php([^ ]*)-fpm( .*|$)/\1/p')
2086 m a2enconf $fpm
2087 # 3 useless guides on php fpm fcgi debian 10 later, i figure out from reading
2088 # /etc/apache2/conf-enabled/php7.3-fpm.conf
2089 m a2dismod php$phpver
2090 # according to /install, we should set date.timezone,
2091 # but that is dumb, the system already has the right zone in
2092 # $rclogdir/errors.log
2093 # todo: consider other settings in
2094 # /a/opt/mailinabox/setup/nextcloud.sh
2095 i /etc/php/$phpver/cli/conf.d/30-local.ini <<'EOF'
2096 apc.enable_cli = 1
2097 EOF
2098
2099 i /etc/php/$phpver/fpm/conf.d/30-local.ini <<'EOF'
2100 date.timezone = "America/New_York"
2101 # for nextcloud
2102 upload_max_filesize = 2000M
2103 post_max_size = 2000M
2104 # install checker, nextcloud/settings/admin/overview
2105 memory_limit = 512M
2106 EOF
2107 m systemctl restart $fpm
2108 # dunno if reload/restart is needed
2109 m systemctl reload apache2
2110 # note bk backups are defined in crontab outside this file
2111 ### end php setup for rc ###
2112
2113 fi # end roundcube setup
2114
2115 # * nextcloud setup
2116
2117 if [[ $HOSTNAME == bk ]]; then
2118 # from install checker, nextcloud/settings/admin/overview and
2119 # https://docs.nextcloud.com/server/19/admin_manual/installation/source_installation.html
2120 # curl from the web installer requirement, but i switched to cli
2121 # it recommends php-file info, but that is part of php7.3-common, already got installed
2122 # with roundcube.
2123 m pi php-curl php-bz2 php-gmp php-bcmath php-imagick php-apcu
2124
2125 # https://docs.nextcloud.com/server/19/admin_manual/installation/source_installation.html
2126 cat >/etc/php/$phpver/fpm/pool.d/localwww.conf <<'EOF'
2127 [www]
2128 clear_env = no
2129 EOF
2130
2131 for ((i=0; i < ${#bkdomains[@]}; i++)); do
2132 domain=${bkdomains[i]}
2133 ncdir=${ncdirs[i]}
2134 ncbase=${ncdir##*/}
2135 m cd /var/www
2136 if [[ ! -e $ncdir/index.php ]]; then
2137 # if we wanted to only install a specific version, use something like
2138 # file=latest-22.zip
2139 file=latest.zip
2140 m wget -nv -N https://download.nextcloud.com/server/releases/$file
2141 m rm -rf nextcloud
2142 m unzip -q $file
2143 m rm -f $file
2144 m chown -R www-data.www-data nextcloud
2145 m mv nextcloud $ncdir
2146 m cd $ncdir
2147 m sudo -u www-data php occ maintenance:install --database sqlite --admin-user iank --admin-pass $nextcloud_admin_pass
2148 fi
2149 # note, strange this happend where updater did not increment the version var,
2150 # mine was stuck on 20. I manually updated it.
2151 m cd $ncdir/config
2152 if [[ ! -e config.php-orig ]]; then
2153 m cp -a config.php config.php-orig
2154 fi
2155 cat config.php-orig - >tmp.php <<EOF
2156 # https://docs.nextcloud.com/server/19/admin_manual/configuration_server/email_configuration.html
2157 \$CONFIG["mail_smtpmode"] = "sendmail";
2158 \$CONFIG["mail_smtphost"] = "127.0.0.1";
2159 \$CONFIG["mail_smtpport"] = 25;
2160 \$CONFIG["mail_smtptimeout"] = 10;
2161 \$CONFIG["mail_smtpsecure"] = "";
2162 \$CONFIG["mail_smtpauth"] = false;
2163 \$CONFIG["mail_smtpauthtype"] = "LOGIN";
2164 \$CONFIG["mail_smtpname"] = "";
2165 \$CONFIG["mail_smtppassword"] = "";
2166 \$CONFIG["mail_domain"] = "$domain";
2167
2168 # https://github.com/nextcloud/user_external#readme
2169 # plus mailinabox example
2170 #\$CONFIG['user_backends'] = array(array('class' => 'OC_User_IMAP','arguments' => array('127.0.0.1', 143, null),),);
2171
2172
2173 # based on installer check
2174 # https://docs.nextcloud.com/server/19/admin_manual/configuration_server/caching_configuration.html
2175 \$CONFIG['memcache.local'] = '\OC\Memcache\APCu';
2176
2177 \$CONFIG['overwrite.cli.url'] = 'https://$domain/nextcloud';
2178 \$CONFIG['htaccess.RewriteBase'] = '/nextcloud';
2179 \$CONFIG['trusted_domains'] = array (
2180 0 => '$domain',
2181 );
2182 #\$CONFIG[''] = '';
2183 fwrite(STDOUT, "<?php\n\\\$CONFIG = ");
2184 var_export(\$CONFIG);
2185 fwrite(STDOUT, ";\n");
2186 EOF
2187 m php tmp.php >config.php
2188 m rm tmp.php
2189 m sudo -u www-data php $ncdir/occ maintenance:update:htaccess
2190 list=$(sudo -u www-data php $ncdir/occ --output=json_pretty app:list)
2191 # user_external not compaible with nc 23
2192 for app in contacts calendar; do
2193 if [[ $(printf "%s\n" "$list"| jq ".enabled.$app") == null ]]; then
2194 m sudo -u www-data php $ncdir/occ app:install $app
2195 fi
2196 done
2197 i /etc/systemd/system/$ncbase.service <<EOF
2198 [Unit]
2199 Description=ncup $ncbase
2200 After=multi-user.target
2201
2202 [Service]
2203 Type=oneshot
2204 ExecStart=/usr/local/bin/ncup $ncbase
2205 User=www-data
2206 IOSchedulingClass=idle
2207 CPUSchedulingPolicy=idle
2208 EOF
2209 i /etc/systemd/system/$ncbase.timer <<EOF
2210 [Unit]
2211 Description=ncup $ncbase timer
2212
2213 [Timer]
2214 OnCalendar=Daily
2215
2216 [Install]
2217 WantedBy=timers.target
2218 EOF
2219 systemctl enable --now $ncbase.timer
2220 i /usr/local/bin/ncup <<'EOFOUTER'
2221 #!/bin/bash
2222 if ! test "$BASH_VERSION"; then echo "error: shell is not bash" >&2; exit 1; fi
2223 shopt -s inherit_errexit 2>/dev/null ||: # ignore fail in bash < 4.4
2224 set -eE -o pipefail
2225 trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" exit status: $?, PIPESTATUS: ${PIPESTATUS[*]}" >&2' ERR
2226
2227 ncbase=$1
2228 if ! php /var/www/$ncbase/updater/updater.phar -n; then
2229 echo failed nextcloud update for $ncbase >&2
2230 /sbin/exim -t <<EOF
2231 To: alerts@iankelling.org
2232 From: root@$(hostname -f)
2233 Subject: failed nextcloud update for $ncbase
2234
2235 For logs, run: jr -u $ncbase
2236 EOF
2237 fi
2238 EOFOUTER
2239
2240 mkdir -p /var/www/cron-errors
2241 chown www-data.www-data /var/www/cron-errors
2242 i /etc/cron.d/$ncbase <<EOF
2243 PATH=/sbin:/usr/sbin:/usr/bin:/bin:/usr/local/bin
2244 SHELL=/bin/bash
2245 # https://docs.nextcloud.com/server/20/admin_manual/configuration_server/background_jobs_configuration.html
2246 */5 * * * * www-data php -f $ncdir/cron.php --define apc.enable_cli=1 |& log-once nccron
2247 EOF
2248
2249 done
2250 fi
2251
2252
2253 # * exim host conditional config
2254
2255 # ** exim certs
2256
2257 all_dirs=(/p/c/filesystem)
2258 for x in /p/c/machine_specific/*.hosts /a/bin/ds/machine_specific/*.hosts; do
2259 if grep -qxF $HOSTNAME $x; then all_dirs+=( ${x%.hosts} ); fi
2260 done
2261 files=()
2262 for d in ${all_dirs[@]}; do
2263 f=$d/etc/exim4/passwd
2264 if [[ -e $f ]]; then
2265 files+=($f)
2266 fi
2267 tmp=($d/etc/exim4/*.pem)
2268 if (( ${#tmp[@]} )); then
2269 files+=(${tmp[@]})
2270 fi
2271 done
2272
2273 if (( ${#files[@]} )); then
2274 sudo rsync -ahhi --chown=root:Debian-exim --chmod=0640 ${files[@]} /etc/exim4/
2275 fi
2276
2277
2278 # ** exim: auth
2279
2280 case $HOSTNAME in
2281 bk|je)
2282 # avoid accepting mail for invalid users
2283 # https://wiki.dovecot.org/LMTP/Exim
2284 cat >>/etc/exim4/conf.d/rcpt_local_acl <<'EOF'
2285 deny
2286 message = invalid recipient
2287 domains = +local_domains
2288 !verify = recipient/callout=no_cache
2289 EOF
2290 i /etc/exim4/conf.d/auth/29_exim4-config_auth <<'EOF'
2291 dovecot_plain:
2292 driver = dovecot
2293 public_name = PLAIN
2294 server_socket = /var/run/dovecot/auth-client
2295 server_set_id = $auth1
2296 EOF
2297 ;;
2298 esac
2299 if $bhost_t; then
2300 i /etc/exim4/conf.d/auth/29_exim4-config_auth <<'EOF'
2301 # from 30_exim4-config_examples
2302 plain_server:
2303 driver = plaintext
2304 public_name = PLAIN
2305 server_condition = "${if crypteq{$auth3}{${extract{1}{:}{${lookup{$auth2}lsearch{CONFDIR/passwd}{$value}{*:*}}}}}{1}{0}}"
2306 server_set_id = $auth2
2307 server_prompts = :
2308 .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS
2309 server_advertise_condition = ${if eq{$tls_in_cipher}{}{}{*}}
2310 .endif
2311 EOF
2312 fi
2313
2314 # ** exim: main daemon use non-default config file
2315 case $HOSTNAME in
2316 bk|$MAIL_HOST)
2317 # to see the default comments in /etc/default/exim4:
2318 # s update-exim4defaults --force --init
2319 # which will overwrite any existing file
2320 i /etc/default/exim4 <<'EOF'
2321 QUEUERUNNER='combined'
2322 QUEUEINTERVAL='30m'
2323 COMMONOPTIONS='-C /etc/exim4/my.conf'
2324 UPEX4OPTS='-o /etc/exim4/my.conf'
2325 #E4BCD_PANICLOG_NOISE='exim user lost privilege for using -C option'
2326 EOF
2327 chown Debian-exim:Debian-exim /usr/sbin/exim4
2328 # needs guid set in order to become Debian-exim
2329 chmod g+s,u+s /usr/sbin/exim4
2330 i /etc/exim4/trusted_configs <<'EOF'
2331 /etc/exim4/my.conf
2332 EOF
2333 ;;
2334 *)
2335 # default file
2336 i /etc/default/exim4 <<'EOF'
2337 QUEUERUNNER='combined'
2338 QUEUEINTERVAL='30m'
2339 EOF
2340 ;;
2341 esac
2342
2343 # ** exim non-root
2344
2345 case $HOSTNAME in
2346 bk|je|li)
2347 # no reason to expect it to ever be there.
2348 rm -fv /etc/systemd/system/exim4.service.d/nonroot.conf
2349 ;;
2350 *)
2351 i /etc/systemd/system/exim4.service.d/nonroot.conf <<'EOF'
2352 [Service]
2353 # see 56.2 Root privilege in exim spec
2354 AmbientCapabilities=CAP_NET_BIND_SERVICE
2355 # https://www.redhat.com/sysadmin/mastering-systemd
2356 # things that seem good and reasonabl.e
2357 PrivateTmp=yes
2358 ProtectHome=yes
2359 # note, in t10 systemd, if one of these is an sshfs mountpoint,
2360 # this whole setting doesnt work. tried it with a newer systemd 250 though
2361 # an nspawn, and it worked there.
2362 InaccessiblePaths=d m media mnt nocow o p q
2363 NoNewPrivileges=yes
2364 ProtectSystem=yes
2365
2366 # when we get newer systemd
2367 #ProtectDevices=yes
2368 EOF
2369 i /etc/exim4/conf.d/main/000_local-noroot <<'EOF'
2370 # see 56.2 Root privilege in exim spec
2371 deliver_drop_privilege = true
2372 EOF
2373 # Note: there are other routers that would also fail due to not running as root,
2374 # but afaik, the main router will catch all mail. If not, we will see
2375 # something in the queue.
2376 rm -fv /etc/exim4/conf.d/router/600_exim4-config_userforward
2377 ;;
2378 esac
2379
2380 case $HOSTNAME in
2381
2382 # ** $MAIL_HOST|bk|je)
2383 $MAIL_HOST|bk|je)
2384
2385 echo|i /etc/exim4/conf.d/router/870_backup_local
2386
2387 cat >>/etc/exim4/update-exim4.conf.conf <<EOF
2388 # note: some things we don't set that are here by default because they are unused.
2389 dc_local_interfaces=''
2390 dc_eximconfig_configtype='internet'
2391 dc_localdelivery='dovecot_lmtp'
2392 EOF
2393 cat >>/etc/exim4/conf.d/main/000_local <<EOF
2394 # recommended if dns is expected to work
2395 CHECK_RCPT_VERIFY_SENDER = true
2396 # default config comment says: If you enable this, you might reject legitimate mail,
2397 # but eggs has had this a long time, so that seems unlikely.
2398 CHECK_RCPT_SPF = true
2399 CHECK_RCPT_REVERSE_DNS = true
2400 CHECK_MAIL_HELO_ISSUED = true
2401
2402 # enable 587 in addition to the default 25, so that
2403 # i can send mail where port 25 is firewalled by isp
2404 daemon_smtp_ports = 25 : 587
2405 # default of 25, can get stuck when catching up on mail
2406 smtp_accept_max = 400
2407 smtp_accept_reserve = 100
2408 smtp_reserve_hosts = +iank_trusted
2409
2410 # options exim has to avoid having to alter the default config files
2411 CHECK_RCPT_LOCAL_ACL_FILE = /etc/exim4/conf.d/rcpt_local_acl
2412 CHECK_DATA_LOCAL_ACL_FILE = /etc/exim4/conf.d/data_local_acl
2413 LOCAL_DENY_EXCEPTIONS_LOCAL_ACL_FILE = /etc/exim4/conf.d/local_deny_exceptions_acl
2414 # testing dmarc
2415 #dmarc_tld_file = /etc/public_suffix_list.dat
2416 EOF
2417 ;;&
2418
2419 # ** $MAIL_HOST|bk)
2420 $MAIL_HOST|bk)
2421
2422 cat >>/etc/exim4/conf.d/main/000_local <<EOF
2423 # je.b8.nz will run out of memory with freshclam
2424 av_scanner = clamd:/var/run/clamav/clamd.ctl
2425 EOF
2426
2427 cat >> /etc/exim4/conf.d/data_local_acl <<'EOF'
2428 deny
2429 malware = */defer_ok
2430 !condition = ${if match {$malware_name}{\N^Heuristic\N}}
2431 message = This message was detected as possible malware ($malware_name).
2432 EOF
2433
2434 cat >/etc/exim4/conf.d/main/000_local-nn <<EOF
2435 # MAIN_HARDCODE_PRIMARY_HOSTNAME might mess up the
2436 # smarthost config type, not sure.
2437 # failing message on mail-tester.com:
2438 # We check if there is a server (A Record) behind your hostname kd.
2439 # You may want to publish a DNS record (A type) for the hostname kd or use a different hostname in your mail software
2440 # https://serverfault.com/questions/46545/how-do-i-change-exim4s-primary-hostname-on-a-debian-box
2441 # and this one seemed appropriate from grepping config.
2442 # I originally set this to li.iankelling.org, but then ended up with errors when li tried to send
2443 # mail to kd, so this should basically be a name that no host has as their
2444 # canonical hostname since the actual host sits behind a nat and changes.
2445 MAIN_HARDCODE_PRIMARY_HOSTNAME = mail.iankelling.org
2446 # I used this to avoid sender verification, didnt work but it still
2447 # makes sense based on the spec.
2448 hosts_treat_as_local = defaultnn.b8.nz
2449
2450 # Outside nn, we get the default cert location from a debian macro,
2451 # and the cert file is put in place by a certbot hook.
2452 MAIN_TLS_CERTIFICATE = /etc/exim4/fullchain.pem
2453 MAIN_TLS_PRIVATEKEY = /etc/exim4/privkey.pem
2454 EOF
2455
2456 i /etc/exim4/conf.d/router/190_exim4-config_fsfsmarthost <<'EOF'
2457 gnusmarthost:
2458 debug_print = "R: smarthost for $local_part@$domain"
2459 driver = manualroute
2460 domains = ! +local_domains
2461 # send most mail through eggs, helps fsfs sender reputation.
2462 # uncomment and optionally move to 188 file to send through my own servers again
2463 senders = *@gnu.org
2464 transport = smarthost_dkim
2465 route_list = * fencepost.gnu.org::587 byname
2466 host_find_failed = ignore
2467 same_domain_copy_routing = yes
2468 no_more
2469 EOF
2470
2471 /a/exe/cedit defaultnn /etc/hosts <<'EOF' || [[ $? == 1 ]]
2472 10.173.8.1 defaultnn.b8.nz
2473 EOF
2474 ;;&
2475 # ** $MAIL_HOST)
2476 $MAIL_HOST)
2477
2478 i /etc/exim4/conf.d/router/195_dnslookup_vpn <<'EOF'
2479 # copied from /etc/exim4/conf.d/router/200_exim4-config_primary, but
2480 # use vpn transport. lower priority so it overrides the default route.
2481 # Use this in case our vpn fails, we dont send anything without it.
2482 .ifdef DCconfig_internet
2483 dnslookup_vpn:
2484 debug_print = "R: dnslookup for $local_part@$domain"
2485 driver = dnslookup
2486 domains = ! +local_domains
2487 transport = remote_smtp_vpn
2488 same_domain_copy_routing = yes
2489 ignore_target_hosts = <; 0.0.0.0 ; 127.0.0.0/8 ; 192.168.0.0/16 ; 172.16.0.0/12 ; 10.0.0.0/8 ; 169.254.0.0/16 ; 255.255.255.255 ; ::/128 ; ::1/128 ; fc00::/7 ; fe80::/10 ; 100::/64
2490 no_more
2491 .endif
2492 EOF
2493
2494
2495 # note on backups: I used to do an automatic sshfs and restricted
2496 # permissions to a specific directory on the remote server, /bu/mnt,
2497 # which required using a dedicated user, but realized smtp will be
2498 # more reliable and less fuss. If I ever need that again, see the
2499 # history of this file, and bum in brc2.
2500
2501 i /etc/exim4/conf.d/router/890_backup_copy <<EOF
2502 ### router/900_exim4-config_local_user
2503 #################################
2504
2505 # todo, it would be nice to save sent email too,
2506 # but its not so important, they still exist in my head
2507
2508 backup_redir:
2509 driver = redirect
2510 domains = +local_domains
2511 # b is just an arbirary short string
2512 data = b@eximbackup.b8.nz
2513 # note, to test this, i could temporarily allow testignore.
2514 # alerts avoids potential mail loop. root is already
2515 # redirected earlier, so that is just being overly cautious.
2516 local_parts = ! root : ! testignore : ! alerts
2517 unseen = true
2518
2519 backup_copy:
2520 driver = manualroute
2521 domains = eximbackup.b8.nz
2522 transport = backup_remote
2523 ignore_target_hosts = ${HOSTNAME}wg.b8.nz
2524 # note changes here also require change in passwd.client
2525 route_list = * eximbackup.b8.nz
2526 same_domain_copy_routing = yes
2527 errors_to = alerts@iankelling.org
2528 no_more
2529 EOF
2530
2531
2532 i /etc/exim4/conf.d/transport/30_backup_remote <<'EOF'
2533 backup_remote:
2534 driver = smtp
2535 multi_domain
2536 .ifndef IGNORE_SMTP_LINE_LENGTH_LIMIT
2537 message_size_limit = ${if > {$max_received_linelength}{998} {1}{0}}
2538 .endif
2539 hosts_require_auth = *
2540 hosts_try_auth = *
2541 envelope_to_add
2542 # manual return path because we want it to be the envelope sender
2543 # we got not the one we are using in this smtp transport
2544 headers_add = "Return-path: $sender_address"
2545 .ifdef REMOTE_SMTP_SMARTHOST_HOSTS_AVOID_TLS
2546 hosts_avoid_tls = REMOTE_SMTP_SMARTHOST_HOSTS_AVOID_TLS
2547 .endif
2548 .ifdef REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS
2549 hosts_require_tls = REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS
2550 .endif
2551 .ifdef REMOTE_SMTP_SMARTHOST_TLS_VERIFY_CERTIFICATES
2552 tls_verify_certificates = REMOTE_SMTP_SMARTHOST_TLS_VERIFY_CERTIFICATES
2553 .endif
2554 .ifdef REMOTE_SMTP_SMARTHOST_TLS_VERIFY_HOSTS
2555 tls_verify_hosts = REMOTE_SMTP_SMARTHOST_TLS_VERIFY_HOST
2556 .endif
2557 .ifdef REMOTE_SMTP_HEADERS_REWRITE
2558 headers_rewrite = REMOTE_SMTP_HEADERS_REWRITE
2559 .endif
2560 .ifdef REMOTE_SMTP_HELO_DATA
2561 helo_data=REMOTE_SMTP_HELO_DATA
2562 .endif
2563 .ifdef TLS_DH_MIN_BITS
2564 tls_dh_min_bits = TLS_DH_MIN_BITS
2565 .endif
2566 .ifdef REMOTE_SMTP_SMARTHOST_TLS_CERTIFICATE
2567 tls_certificate = REMOTE_SMTP_SMARTHOST_TLS_CERTIFICATE
2568 .endif
2569 .ifdef REMOTE_SMTP_SMARTHOST_PRIVATEKEY
2570 tls_privatekey = REMOTE_SMTP_SMARTHOST_PRIVATEKEY
2571 .endif
2572 .ifdef REMOTE_SMTP_TRANSPORTS_HEADERS_REMOVE
2573 headers_remove = REMOTE_SMTP_TRANSPORTS_HEADERS_REMOVE
2574 .endif
2575 EOF
2576
2577
2578 # this avoids some error. i cant remember what. todo:
2579 # test it out and document why/if its needed.
2580 # i /etc/exim4/host_local_deny_exceptions <<'EOF'
2581 # mail.fsf.org
2582 # *.posteo.de
2583 # EOF
2584
2585 # cron email from smarthost hosts will automatically be to
2586 # USER@FQDN. I redirect that to alerts@, on the smarthosts, but in
2587 # case that doesn't work, we still want to accept that mail, but not
2588 # from any host except the smarthosts. local_hostnames and this rule
2589 # is for that purpose.
2590 i /etc/exim4/conf.d/rcpt_local_acl <<'EOF'
2591 deny
2592 !authenticated = *
2593 domains = +local_hostnames
2594 message = no relay
2595 EOF
2596 echo|i /etc/exim4/conf.d/router/880_universal_forward
2597
2598 # for iank@fsf.org, i have mail.fsf.org forward it to fsf@iankelling.org.
2599 # and also have mail.iankelling.org whitelisted as a relay domain.
2600 # I could avoid that if I changed this to submit to 587 with a
2601 # password like a standard mua.
2602 i /etc/exim4/conf.d/router/188_exim4-config_smarthost <<'EOF'
2603 # ian: copied from /etc/exim4/conf.d/router/200_exim4-config_primary, and added senders = and
2604 # replaced DCsmarthost with hostname
2605 fsfsmarthost:
2606 debug_print = "R: smarthost for $local_part@$domain"
2607 driver = manualroute
2608 domains = ! +local_domains
2609 senders = *@fsf.org
2610 transport = remote_smtp_smarthost
2611 route_list = * mail.fsf.org::587 byname
2612 host_find_failed = ignore
2613 same_domain_copy_routing = yes
2614 no_more
2615
2616 posteosmarthost:
2617 debug_print = "R: smarthost for $local_part@$domain"
2618 driver = manualroute
2619 domains = ! +local_domains
2620 senders = *@posteo.net
2621 transport = remote_smtp_smarthost
2622 route_list = * posteo.de::587 byname
2623 host_find_failed = ignore
2624 same_domain_copy_routing = yes
2625 no_more
2626
2627 EOF
2628
2629 # Greping /etc/exim4, unqualified mails this would end up as
2630 # a return path, so it should go somewhere we will see.
2631 # The debconf output about mailname is as follows:
2632 # The 'mail name' is the domain name used to 'qualify' mail addresses without a domain
2633 # name.
2634 # This name will also be used by other programs. It should be the single, fully
2635 # qualified domain name (FQDN).
2636 # Thus, if a mail address on the local host is foo@example.org, the correct value for
2637 # this option would be example.org.
2638 # This name won\'t appear on From: lines of outgoing messages if rewriting is enabled.
2639 echo iankelling.org > /etc/mailname
2640
2641
2642 # mail.iankelling.org so local imap clients can connect with tls and
2643 # when they happen to not be local.
2644 # todo: this should be 10.8.0.4
2645
2646 /a/exe/cedit nn /etc/hosts <<'EOF' || [[ $? == 1 ]]
2647 # note: i put nn.b8.nz into bind for good measure
2648 10.173.8.2 nn.b8.nz mx.iankelling.org
2649 EOF
2650
2651 # note: systemd-resolved will consult /etc/hosts, dnsmasq wont. this assumes
2652 # weve configured this file in dnsmasq if we are using it.
2653 /a/exe/cedit mail /etc/dnsmasq-servers.conf <<'EOF' || [[ $? == 1 ]]
2654 server=/mx.iankelling.org/127.0.1.1
2655 EOF
2656 # I used to use debconf-set-selections + dpkg-reconfigure,
2657 # which then updates this file
2658 # but the process is slower than updating it directly and then I want to set other things in
2659 # update-exim4.conf.conf, so there's no point.
2660 # The file is documented in man update-exim4.conf,
2661 # except the man page is not perfect, read the bash script to be sure about things.
2662
2663 # The debconf questions output is additional documentation that is not
2664 # easily accessible, but super long, along with the initial default comment in this
2665 # file, so I've saved that into ./mail-notes.conf.
2666 #
2667 # # TODO: remove mx.iankelling.org once systems get updated mail-setup from jan 2022
2668 cat >>/etc/exim4/update-exim4.conf.conf <<EOF
2669 # man page: is used to build the local_domains list, together with "localhost"
2670 # this is duplicated in a later router.
2671 dc_other_hostnames='iankelling.org;zroe.org;r2e.iankelling.org;mx.iankelling.org;!je.b8.nz;!bk.b8.nz;*.b8.nz;b8.nz'
2672 EOF
2673
2674
2675 # dmarc. not used currently
2676 f=/etc/cron.daily/refresh-dmarc-tld-file
2677 cat >$f <<'EOF'
2678 #!/bin/bash
2679 cd /etc
2680 wget -q -N https://publicsuffix.org/list/public_suffix_list.dat
2681 EOF
2682 m chmod 755 $f
2683
2684 ;;
2685 # ** bk
2686 ## we use this host to monitor MAIL_HOST and host a mail server for someone
2687 bk)
2688
2689 echo|i /etc/exim4/conf.d/rcpt_local_acl
2690 echo|i /etc/exim4/conf.d/router/880_universal_forward
2691
2692 echo amnimal.ninja > /etc/mailname
2693
2694 /a/exe/cedit nn /etc/hosts <<'EOF' || [[ $? == 1 ]]
2695 10.173.8.2 nn.b8.nz
2696 EOF
2697
2698 sed -r -f - /etc/init.d/exim4 <<'EOF' | i /etc/init.d/exim4in
2699 s,/etc/default/exim4,/etc/default/exim4in,g
2700 s,/run/exim4/exim.pid,/run/exim4/eximin.pid,g
2701 s,(^[ #]*Provides:).*,\1 exim4in,
2702 s,(^[ #]*NAME=).*,\1"exim4in",
2703 EOF
2704 chmod +x /etc/init.d/exim4in
2705 i /etc/systemd/system/exim4in.service.d/alwaysrestart.conf <<'EOF'
2706 [Unit]
2707 # needed to continually restart
2708 StartLimitIntervalSec=0
2709
2710 [Service]
2711 Restart=always
2712 # time to sleep before restarting a service
2713 RestartSec=20
2714 EOF
2715
2716 i /etc/default/exim4in <<'EOF'
2717 # defaults but no queue runner and alternate config dir
2718 QUEUERUNNER='no'
2719 COMMONOPTIONS='-oP /run/exim4/eximin.pid'
2720 UPEX4OPTS='-d /etc/myexim4'
2721 EOF
2722
2723 cat >>/etc/exim4/update-exim4.conf.conf <<EOF
2724 # man page: is used to build the local_domains list, together with "localhost"
2725 dc_other_hostnames='amnimal.ninja;expertpathologyreview.com'
2726 EOF
2727
2728 ;;
2729 # ** je
2730 je)
2731 echo je.b8.nz > /etc/mailname
2732 cat >>/etc/exim4/update-exim4.conf.conf <<EOF
2733 dc_other_hostnames='je.b8.nz'
2734 EOF
2735 echo|i /etc/exim4/conf.d/router/188_exim4-config_smarthost
2736 echo|i /etc/exim4/conf.d/router/190_exim4-config_fsfsmarthost
2737 echo|i /etc/exim4/conf.d/rcpt_local_acl
2738 echo|i /etc/exim4/conf.d/router/880_universal_forward
2739 ;;
2740 # ** not MAIL_HOST|bk|je
2741 *)
2742 # this one should be removed for all non mail hosts, but
2743 # bk and je never become mail_host
2744 echo|i /etc/exim4/conf.d/router/195_dnslookup_vpn
2745
2746 echo|i /etc/exim4/conf.d/router/188_exim4-config_smarthost
2747 echo|i /etc/exim4/conf.d/router/190_exim4-config_fsfsmarthost
2748 echo|i /etc/exim4/conf.d/rcpt_local_acl
2749 echo|i /etc/exim4/conf.d/router/890_backup_copy
2750 echo|i /etc/exim4/conf.d/main/000_local-nn
2751
2752
2753 if $bhost_t; then
2754 cat >>/etc/exim4/conf.d/main/000_local <<EOF
2755 MAIN_TLS_CERTIFICATE = /etc/exim4/certs/$wghost/fullchain.pem
2756 MAIN_TLS_PRIVATEKEY = /etc/exim4/certs/$wghost/privkey.pem
2757 # so we can maintiain the originals of the backups.
2758 # we wouldnt want this if we were dealing with any other
2759 # local deliveries, but we sent all others to the smarthost
2760 # which then strips the headers.
2761 envelope_to_remove = false
2762 return_path_remove = false
2763 EOF
2764 fi
2765
2766 # catches things like cronjob email
2767 i /etc/exim4/conf.d/router/880_universal_forward <<'EOF'
2768 universal_forward:
2769 driver = redirect
2770 domains = +local_domains
2771 data = alerts@iankelling.org
2772 EOF
2773
2774
2775 for unit in ${nn_progs[@]}; do
2776 f=/etc/systemd/system/$unit.service.d/nn.conf
2777 rm -fv $f
2778 done
2779
2780 # dont i dont care if defaultnn section gets left, it wont
2781 # get used.
2782 echo | /a/exe/cedit nn /etc/hosts || [[ $? == 1 ]]
2783 echo | /a/exe/cedit mail /etc/dnsmasq-servers.conf || [[ $? == 1 ]]
2784
2785
2786 if $bhost_t; then
2787 install -d /bu
2788 install -d -g $u -o $u -m 771 /bu/md
2789 i /etc/exim4/conf.d/transport/30_backup_maildir <<EOF
2790 # modified debian maildir transport
2791 backup_maildir:
2792 driver = appendfile
2793 directory = /bu/md
2794 delivery_date_add
2795 # note, no return path or envelope added
2796 maildir_format
2797 directory_mode = 0700
2798 mode = 0644
2799 mode_fail_narrower = false
2800 user = $u
2801 EOF
2802
2803 i /etc/exim4/conf.d/router/870_backup_local <<EOF
2804 ### router/900_exim4-config_local_user
2805 #################################
2806
2807 backup_local:
2808 debug_print = "R: local_user for \$local_part@\$domain"
2809 driver = accept
2810 domains = eximbackup.b8.nz
2811 transport = backup_maildir
2812 EOF
2813
2814 # Bind to wghole to receive mailbackup.
2815 wgholeip=$(sed -rn 's/^ *Address *= *([^/]+).*/\1/p' /etc/wireguard/wghole.conf)
2816 cat >>/etc/exim4/update-exim4.conf.conf <<EOF
2817 dc_other_hostnames='eximbackup.b8.nz'
2818 dc_local_interfaces='127.0.0.1;::1;$wgholeip'
2819 EOF
2820
2821 # wghole & thus exim will fail to start without internet connectivity.
2822 i /etc/systemd/system/exim4.service.d/backup.conf <<'EOF'
2823 [Unit]
2824 StartLimitIntervalSec=0
2825
2826 [Service]
2827 Restart=always
2828 RestartSec=20
2829 EOF
2830
2831 else
2832 cat >>/etc/exim4/update-exim4.conf.conf <<EOF
2833 # Note: If theres like a temporary problem where mail gets sent to
2834 # one of these hosts, if exim isnt listening, it will be a temporary error
2835 # instead of a permanent 5xx.
2836 dc_local_interfaces='127.0.0.1;::1'
2837 EOF
2838 rm -fv /etc/systemd/system/exim4.service.d/backup.conf
2839 fi
2840 cat >>/etc/exim4/update-exim4.conf.conf <<EOF
2841 dc_eximconfig_configtype='smarthost'
2842 dc_smarthost='$smarthost'
2843 EOF
2844
2845 hostname -f |i /etc/mailname
2846 cat >>/etc/exim4/update-exim4.conf.conf <<EOF
2847 # The manpage incorrectly states this will do header rewriting, but
2848 # that only happens if we have dc_hide_mailname is set.
2849 dc_readhost='iankelling.org'
2850 # Only used in case of bounces.
2851 dc_localdelivery='maildir_home'
2852 EOF
2853 ;;
2854 esac
2855
2856
2857
2858
2859 # ** $MAILHOST|bk, things that belong at the end
2860 case $HOSTNAME in
2861 $MAIL_HOST|bk)
2862 # config for the non-nn exim
2863 m rsync -ra --delete /etc/exim4/ /etc/myexim4
2864 # If we ever wanted to have a separate spool,
2865 # we could do it like this.
2866 # cat >>/etc/exim4/conf.d/main/000_local-nn <<'EOF'
2867 # spool_directory = /var/spool/myexim4
2868 # EOF
2869 cat >>/etc/myexim4/update-exim4.conf.conf <<'EOF'
2870 dc_eximconfig_configtype='smarthost'
2871 dc_smarthost='nn.b8.nz'
2872 EOF
2873 ;;&
2874 bk)
2875
2876 # config for the non-nn exim
2877 cat >/etc/myexim4/conf.d/main/000_local-nn <<'EOF'
2878 MAIN_HARDCODE_PRIMARY_HOSTNAME = mail2.iankelling.org
2879 EOF
2880 ;;
2881 $MAIL_HOST)
2882 # for bk, we have a exim4in.service that will do this for us.
2883 m update-exim4.conf -d /etc/myexim4
2884 ;;
2885 esac
2886
2887 # * spool dir setup
2888
2889 # ** bind mount setup
2890 # put spool dir in directory that spans multiple distros.
2891 # based on http://www.postfix.org/qmgr.8.html and my notes in gnus
2892 #
2893 dir=/nocow/exim4
2894 sdir=/var/spool/exim4
2895 # we only do this if our system has $dir
2896
2897 # this used to do a symlink, but, in the boot logs, /nocow would get mounted succesfully,
2898 # about 2 seconds later, exim starts, and immediately puts into paniclog:
2899 # honVi-0000u3-82 Failed to create directory "/var/spool/exim4/input": No such file or directory
2900 # so, im trying a bind mount to get rid of that.
2901 if [[ -e /nocow ]]; then
2902 if ! grep -Fx "/nocow/exim4 /var/spool/exim4 none bind 0 0" /etc/fstab; then
2903 echo "/nocow/exim4 /var/spool/exim4 none bind 0 0" >>/etc/fstab
2904 fi
2905 i /etc/systemd/system/exim4.service.d/override.conf <<'EOF'
2906 [Unit]
2907 # without local-fs on exim, we get these kind of errors in paniclog on shutdown:
2908 # Failed to create spool file /var/spool/exim4//input//1jCLxz-0008V4-V9-D: Permission denied
2909 After=local-fs.target
2910 EOF
2911 if ! mountpoint -q $sdir; then
2912 stopifactive exim4 exim4in
2913 if [[ -L $sdir ]]; then
2914 m rm $sdir
2915 fi
2916 if [[ ! -e $dir && -d $sdir ]]; then
2917 m mv $sdir $dir
2918 fi
2919 if [[ ! -d $sdir ]]; then
2920 m mkdir $sdir
2921 m chmod 000 $sdir # only want it to be used when its mounted
2922 fi
2923 m mount $sdir
2924 fi
2925 fi
2926
2927
2928
2929 # ** exim/spool uid setup
2930 # i have the spool directory be common to distro multi-boot, so
2931 # we need the uid to be the same. 608 cuz it's kind of in the middle
2932 # of the free system uids.
2933 IFS=:; read -r _ _ uid _ < <(getent passwd Debian-exim ||:) ||:; unset IFS
2934 IFS=:; read -r _ _ gid _ < <(getent group Debian-exim ||:) ||:; unset IFS
2935 if [[ ! $uid ]]; then
2936 # from /var/lib/dpkg/info/exim4-base.postinst, plus uid and gid options
2937 m adduser --uid 608 --system --group --quiet --home /var/spool/exim4 \
2938 --no-create-home --disabled-login --force-badname Debian-exim
2939 elif [[ $uid != 608 ]]; then
2940 stopifactive exim4 exim4in
2941 m usermod -u 608 Debian-exim
2942 m groupmod -g 608 Debian-exim
2943 m usermod -g 608 Debian-exim
2944 m find / /nocow -path ./var/tmp -prune -o -xdev -uid $uid -execdir chown -h 608 {} +
2945 m find / /nocow -path ./var/tmp -prune -o -xdev -gid $gid -execdir chgrp -h 608 {} +
2946 fi
2947
2948 # * start / stop services
2949
2950 reifactive dnsmasq nscd
2951
2952 if $reload; then
2953 m systemctl daemon-reload
2954 fi
2955
2956 m systemctl --now enable epanicclean.timer
2957
2958 case $HOSTNAME in
2959 je)
2960 /a/exe/web-conf apache2 je.b8.nz
2961 ;;
2962 bk)
2963 /a/exe/web-conf apache2 mail2.iankelling.org
2964 ;;
2965 esac
2966
2967 m /a/bin/ds/mail-cert-cron -1
2968 sre mailcert.timer
2969
2970 case $HOSTNAME in
2971 bk)
2972 # todo, this should be done in distro-begin
2973 soff systemd-resolved
2974 ln -sf 127.0.0.1-resolv/stub-resolv.conf /etc/resolv.conf
2975 ;;&
2976 $MAIL_HOST|bk)
2977 m systemctl --now enable mailnn mailnnroute
2978 ;;&
2979 $MAIL_HOST)
2980 # we use dns to start wg
2981 if $reload; then
2982 sre unbound
2983 else
2984 m systemctl --now enable unbound
2985 fi
2986 ;;&
2987 $MAIL_HOST|bk)
2988 # If these have changes, id rather manually restart it, id rather
2989 # not restart and cause temporary errors
2990 if $reload; then
2991 sre $vpnser
2992 else
2993 m systemctl --now enable $vpnser
2994 fi
2995 if ! systemctl is-active clamav-daemon >/dev/null; then
2996 m systemctl --now enable clamav-daemon
2997 out=$(rsync -aiSAX --chown=root:root --chmod=g-s /a/bin/ds/filesystem/etc/systemd/system/epanicclean.{timer,service} /etc/systemd/system)
2998 if [[ $out ]]; then
2999 reload=true
3000 fi
3001
3002 # note, this will cause paniclog entries because it takes like 45
3003 # seconds for clamav to start, i use ./epanic-clean to remove
3004 # them.
3005 fi
3006 ;;&
3007 $MAIL_HOST|bk|je)
3008 # start spamassassin/dovecot before exim.
3009 sre dovecot spamassassin
3010 # need to wait a bit before restarting exim, else I
3011 # get a paniclog entry like: spam acl condition: all spamd servers failed
3012 sleep 3
3013 m systemctl --now enable mailclean.timer
3014 ;;&
3015 $MAIL_HOST)
3016 # < 2.1 (eg: in t9), uses a different data format which required manual
3017 # migration. dont start if we are running an old version.
3018 if dpkg --compare-versions $(dpkg -s radicale | awk '$1 == "Version:" { print $2 }') ge 2.1; then
3019 m systemctl --now enable radicale
3020 fi
3021 ;;&
3022 esac
3023
3024 # last use of $reload happens in previous block
3025 rm -f /var/local/mail-setup-reload
3026
3027
3028 case $HOSTNAME in
3029 $MAIL_HOST|bk|je) : ;;
3030 *)
3031 soff radicale mailclean.timer dovecot spamassassin $vpnser mailnn clamav-daemon
3032 ;;
3033 esac
3034
3035 sre exim4
3036
3037 case $HOSTNAME in
3038 $MAIL_HOST)
3039 m systemctl --now enable mailbindwatchdog
3040 ;;
3041 *)
3042 soff mailbindwatchdog
3043 ;;
3044 esac
3045
3046
3047 case $HOSTNAME in
3048 bk) sre exim4in ;;
3049 esac
3050
3051 # * mail monitoring / testing
3052
3053 # note, to test clamav, send an email with body that only contains
3054 # https://en.wikipedia.org/wiki/EICAR_test_file
3055 # which set malware_name to Eicar-Signature
3056 case $HOSTNAME in
3057 $MAIL_HOST|bk|je)
3058 # note: cronjob "ian" also does some important monitoring
3059 # todo: this will sometimes cause an alert because mailtest-check will run
3060 # before we have setup network namespace and spamassassin
3061 cat >/etc/cron.d/mailtest <<EOF
3062 SHELL=/bin/bash
3063 PATH=/usr/bin:/bin:/usr/local/bin
3064 MAILTO=alerts@iankelling.org
3065 */5 * * * * $u send-test-forward |& log-once send-test-forward
3066 */10 * * * * root chmod -R g+rw /m/md/bounces |& log-once -1 bounces-chmod
3067 # im seeing some intermittent failures on the slow check, do it all the time
3068 # for now. It looks like a dns failure.
3069 #5-59/5 * * * * root mailtest-check |& log-once -1 mailtest-check
3070 #0 * * * * root mailtest-check slow |& log-once -1 mailtest-slow
3071 */5 * * * * root timeout 290 mailtest-check slow |& log-once -12 mailtest-check
3072 EOF
3073 m sudo rsync -ahhi --chown=root:root --chmod=0755 \
3074 /b/ds/mailtest-check /b/ds/check-remote-mailqs /usr/local/bin/
3075 ;;&
3076 $MAIL_HOST)
3077 test_froms=(ian@iankelling.org z@zroe.org iank@gnu.org)
3078 test_to="testignore@expertpathologyreview.com, testignore@je.b8.nz, testignore@amnimal.ninja, jtuttle@gnu.org"
3079
3080 cat >>/etc/cron.d/mailtest <<EOF
3081 2 * * * * root check-remote-mailqs |& log-once check-remote-mailqs
3082 EOF
3083 ;;&
3084 bk)
3085 test_froms=(testignore@expertpathologyreview.com testignore@amnimal.ninja)
3086 test_to="testignore@iankelling.org, testignore@zroe.org, testignore@je.b8.nz"
3087 ;;&
3088 je)
3089 test_froms=(testignore@je.b8.nz)
3090 test_to="testignore@iankelling.org, testignore@zroe.org, testignore@expertpathologyreview.com, testignore@amnimal.ninja"
3091 ;;&
3092 $MAIL_HOST|bk|je)
3093 cat >/usr/local/bin/send-test-forward <<'EOF'
3094 #!/bin/bash
3095 olds=(
3096 $(/sbin/exiqgrep -o 260 -i -r '^(testignore@(iankelling\.org|zroe\.org|expertpathologyreview\.com|amnimal\.ninja|je\.b8\.nz)|jtuttle@gnu\.org)$')
3097 )
3098 if (( ${#olds[@]} )); then
3099 /sbin/exim -Mrm "${olds[@]}" >/dev/null
3100 fi
3101 EOF
3102 for test_from in ${test_froms[@]}; do
3103 cat >>/usr/local/bin/send-test-forward <<EOFOUTER
3104 /usr/sbin/exim -f $test_from -t <<EOF
3105 From: $test_from
3106 To: $test_to
3107 Subject: test \$(date +%Y-%m-%dT%H:%M:%S%z) \$(date +%s)
3108
3109 /usr/local/bin/send-test-forward
3110 EOF
3111 EOFOUTER
3112 done
3113 m chmod +x /usr/local/bin/send-test-forward
3114 ;;
3115 *)
3116 rm -fv /etc/cron.d/mailtest
3117 ;;
3118 esac
3119
3120
3121
3122 # * misc
3123 m sudo -u $u mkdir -p /home/$u/.cache
3124 set -- /m/mucache /home/$u/.cache/mu /m/.mu /home/$u/.mu
3125 while (($#)); do
3126 target=$1
3127 f=$2
3128 shift 2
3129 if [[ ! -L $f ]]; then
3130 if [[ -e $f ]]; then
3131 rm -rf $f
3132 fi
3133 m sudo -u $u ln -sf -T $target $f
3134 fi
3135 done
3136
3137
3138 # /etc/alias setup is debian specific, and exim postinst script sets up
3139 # an /etc/alias from root to the postmaster, based on the question
3140 # exim4-config exim4/dc_postmaster, as long as there exists an entry for
3141 # root, or there was no preexisting aliases file. postfix won\'t set up
3142 # a root to $postmaster alias if it\'s already installed. Easiest to
3143 # just set it ourselves.
3144
3145 # debconf question for postmaster:
3146 # Mail for the 'postmaster', 'root', and other system accounts needs to be redirected
3147 # to the user account of the actual system administrator.
3148 # If this value is left empty, such mail will be saved in /var/mail/mail, which is not
3149 # recommended.
3150 # Note that postmaster\'s mail should be read on the system to which it is directed,
3151 # rather than being forwarded elsewhere, so (at least one of) the users listed here
3152 # should not redirect their mail off this machine. A 'real-' prefix can be used to
3153 # force local delivery.
3154 # Multiple user names need to be separated by spaces.
3155 # Root and postmaster mail recipient:
3156
3157 m exit 0
3158 :
3159
3160 # Local Variables:
3161 # eval: (outline-minor-mode)
3162 # outline-regexp: "\\( *\\)# [*]\\{1,8\\} "
3163 # End:
3164 # this is combined with defining outline-level in init.el