From 9e71165dd3fa31accbcce8d5875aa774ab8b8fe1 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Wed, 30 Aug 2023 11:40:19 +0200 Subject: run Exim in container --- .gitignore | 1 + Makefile | 55 +++++++++--- container.scm | 106 ++++++++++++++++++++-- exim.conf | 262 +++++++++++++++++++++++++++++++++++++++++++++++++++++ exim4.conf | 263 ------------------------------------------------------ guix-container.sh | 101 ++++++++++++++------- 6 files changed, 474 insertions(+), 314 deletions(-) create mode 100644 exim.conf delete mode 100644 exim4.conf diff --git a/.gitignore b/.gitignore index 2b7dbc1..67a94e3 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ container-runner log +test-root pidfile hosts *.touchfile diff --git a/Makefile b/Makefile index 1acdba5..0bea659 100644 --- a/Makefile +++ b/Makefile @@ -34,9 +34,10 @@ ALL_EGG_INFOS = \ $(HYDRILLA_WEBSITE_INFO) \ $(HYDRILLA_INFO) -CONTAINER_PREREQUISITES = container.scm $(ALL_EGG_INFOS) hydrilla-wsgi.py +CONTAINER_PREREQUISITES = container.scm $(ALL_EGG_INFOS) hydrilla-wsgi.py \ + exim.conf -TEST_ROOT_DIR = "/tmp/$$(pwd | sed 's|/|!|g')"'!!test-root' +TEST_ROOT_DIR = "/tmp/$$(pwd | sed 's|/|!|g')"'!!test-root/current' all: | container-runner.touchfile log sample-malcontent @@ -59,7 +60,7 @@ hosts: hosts-extra /etc/hosts cat $^ > $@ log: - ln -sf $(TEST_ROOT_DIR)/var/log/guix-container $@ + ln -sf test-root/var/log/guix-container $@ sample-malcontent: mkdir $@ @@ -68,12 +69,31 @@ sample-malcontent: make -C subrepos/hydrilla shell-with-hydrilla-only LETSENCRYPT_ETC_DIR = $(TEST_ROOT_DIR)/etc/letsencrypt +EXIM_ETC_DIR = $(TEST_ROOT_DIR)/etc/exim HYDRILLA_WEBSITE_ETC_DIR = $(TEST_ROOT_DIR)/etc/guix-container/hydrilla-website MALCONTENT_DIR = $(TEST_ROOT_DIR)/var/lib/hydrilla/malcontent_dirs GITOLITE_DIR = $(TEST_ROOT_DIR)/var/lib/gitolite3 +EXIM_SPOOL_DIR = $(TEST_ROOT_DIR)/var/spool/exim + +test-root: sample-malcontent Makefile + rm -f $@ + ln -sf $(TEST_ROOT_DIR) $@ + $(MAKE) prepare-test-root + +.PHONY: ensure-test-root +ensure-test-root: + $(MAKE) test-root + if [ \! -e $(TEST_ROOT_DIR) ]; then \ + $(MAKE) prepare-test-root; \ + fi +.PHONY: prepare-test-root prepare-test-root: sample-malcontent - rm -rf $(TEST_ROOT_DIR) + @# Move the old test root + if [ -e $(TEST_ROOT_DIR) ]; then \ + mv $(TEST_ROOT_DIR) \ + $(TEST_ROOT_DIR)/../"old-$$(date --iso-8601=seconds)"; \ + fi @# Prepare replacement `/var/www` for WWW_SUBDIR in \ koszko.org/html \ @@ -92,6 +112,17 @@ prepare-test-root: sample-malcontent printf 'test secret\n' > $(LETSENCRYPT_ETC_DIR)/dummy-keys-and-stuff.txt chmod 540 $(LETSENCRYPT_ETC_DIR)/dummy-keys-and-stuff.txt chgrp 1001 $(LETSENCRYPT_ETC_DIR)/dummy-keys-and-stuff.txt + @# Prepare replacement `/etc/exim` + mkdir --mode=755 -p $(EXIM_ETC_DIR) + guix shell openssl -- openssl genrsa -out $(EXIM_ETC_DIR)/dkim.pem 2048 + chmod 640 $(EXIM_ETC_DIR)/dkim.pem + chown 106:113 $(EXIM_ETC_DIR)/dkim.pem + printf koszko: > $(EXIM_ETC_DIR)/passwd + printf silnehaslo | guix shell whois -- mkpasswd --method=sha-256 -s \ + >> $(EXIM_ETC_DIR)/passwd + echo >> $(EXIM_ETC_DIR)/passwd + chmod 640 $(EXIM_ETC_DIR)/passwd + chown 106:113 $(EXIM_ETC_DIR)/passwd @# Prepare replacement `/etc` mkdir --mode=750 -p $(HYDRILLA_WEBSITE_ETC_DIR) printf 'test non-secret\n' > $(HYDRILLA_WEBSITE_ETC_DIR)/secret.txt @@ -108,18 +139,23 @@ prepare-test-root: sample-malcontent printf "sheets-websites.git\n" > $(GITOLITE_DIR)/projects.list chmod -R o-rwx,g-w $(GITOLITE_DIR) chgrp -R 118 $(GITOLITE_DIR) + @# Prepare replacement `/var/spool/exim` + mkdir -p $(EXIM_SPOOL_DIR) + chmod 750 $(EXIM_SPOOL_DIR) + chown 106:113 $(EXIM_SPOOL_DIR) -GUIX_CONTAINER_FLAGS = -e ./container-runner -p ./pidfile -r $(TEST_ROOT_DIR) +GUIX_CONTAINER_FLAGS = -e ./container-runner -p ./pidfile \ + -r "$$(realpath test-root)" -start-container: guix-container.sh container-runner.touchfile \ - prepare-test-root | log +start-container: guix-container.sh container-runner.touchfile ensure-test-root \ + | log ./$< start $(GUIX_CONTAINER_FLAGS) stop-container: guix-container.sh ./$< stop $(GUIX_CONTAINER_FLAGS) restart-container: guix-container.sh container-runner.touchfile \ - prepare-test-root | log + ensure-test-root | log ./$< restart $(GUIX_CONTAINER_FLAGS) enter-container: pidfile @@ -152,11 +188,10 @@ clean: clean-runner for SUBREPO in $(SUBREPOS_WITH_MAKEFILE); do \ $(MAKE) -C subrepos/"$$SUBREPO" clean; \ done - rm -rf log hosts schemas sample-malcontent + rm -rf log test-root hosts schemas sample-malcontent .PHONY: all \ clean-runner clean \ - prepare-test-root \ start-container stop-container restart-container \ enter-container fake-client \ install \ diff --git a/container.scm b/container.scm index 7caf4fe..a513dda 100644 --- a/container.scm +++ b/container.scm @@ -4,15 +4,14 @@ ;; ;; Available under the terms of Creative Commons Zero v1.0 Universal. -(use-modules (gnu) +(use-modules ((srfi srfi-1) #:select (append-map filter-map)) + (gnu) (koszko-org-website) (sheets-websites) (hydrilla-website) (hydrilla-json-schemas) (hydrilla-base) (ice-9 match) - ;; srfi-1 provides `append-map`. - (srfi srfi-1) ;; srfi-26 provides `cut`. (srfi srfi-26) (guix records) @@ -24,14 +23,17 @@ (guix packages) (guix search-paths) (guix modules) + ((guix utils) #:select (substitute-keyword-arguments)) ;; The following exports account-service-type. (gnu system shadow)) (use-package-modules web python - version-control) + version-control + mail) (use-service-modules web shepherd - certbot) + certbot + mail) (define %here (getcwd)) @@ -376,6 +378,10 @@ "CustomLog /var/log/httpd/access.log combined" "\n" "ScriptSock /var/run/cgid.sock" "\n"))))))) +(define (extension-of-type? ext type) + (eq? (service-type-name (service-extension-target ext)) + (service-type-name type))) + (define %koszko-httpd-deploy-hook (program-file "httpd-deploy-hook" @@ -416,8 +422,7 @@ ;; Prevent certbot from pulling in Nginx — we use Apache here. (extensions (filter (lambda (ext) - (not (eq? (service-type-name (service-extension-target ext)) - (service-type-name nginx-service-type)))) + (not (extension-of-type? ext nginx-service-type))) (service-type-extensions certbot-service-type)))) (certbot-configuration (email "koszko@koszko.org") @@ -437,6 +442,66 @@ (deploy-hook %koszko-httpd-deploy-hook))))) %all-site-confs))))) +(define koszko-exim-service-type + (service-type + (inherit exim-service-type) + (extensions (filter-map + (lambda (ext) + (cond + ((extension-of-type? ext account-service-type) + ;; Avoid double declaration of "exim" user and group. + #f) + ((extension-of-type? ext activation-service-type) + ;; Make exim logs accessible under /var/log + (let ((old-activation (service-extension-compute ext))) + (define (new-activation exim-config) + #~(begin + (symlink "../spool/exim/log" "/var/log/exim") + #$(old-activation exim-config))) + + (service-extension activation-service-type + new-activation))) + (else + ext))) + (service-type-extensions exim-service-type))))) + +(define %koszko-exim-service + (service koszko-exim-service-type + (exim-configuration + (package (package/inherit exim + (arguments + (substitute-keyword-arguments + (package-arguments exim) + ((#:phases phases) + #~(modify-phases #$phases + (add-after 'configure 'configure-enable-maildir + (lambda _ + (substitute* "Local/Makefile" + (("# (SUPPORT_MAILDIR=yes)" all line) + line)))))))))) + (config-file (local-file "./exim.conf"))))) + +(define %koszko-mail-aliases-service + (service mail-aliases-service-type + '(("mailer-daemon" "postmaster") + ("postmaster" "root") + ("nobody" "root") + ("hostmaster" "root") + ("usenet" "root") + ("news" "root") + ("webmaster" "root") + ("www" "root") + ("ftp" "root") + ("abuse" "root") + ("noc" "root") + ("security" "root") + ("root" "urz") + ("dmarc" "urz") + ("admin" "urz") + ("wk" "urz") + ("koszko" "urz") + ("my-contribution-is-licensed-cc0" "urz")))) + (operating-system (host-name "koszko") (timezone "Europe/Warsaw") @@ -444,6 +509,10 @@ ;; Some groups must have explicit ids so that the host can provide ;; files that are readable by certain daemons and not readable by the ;; world. + (user-group + (name "exim") + (id 113) + (system? #t)) (user-group (name "httpd") (id 133) @@ -456,8 +525,20 @@ (name "certsaccess") (id 1001) (system? #t)) + (user-group + (name "urz") + (id 1000)) + (user-group + (name "joanna") + (id 1003)) %base-groups)) (users (cons* + (user-account + (name "exim") + (group "exim") + (supplementary-groups '("certsaccess")) + (uid 106) + (system? #t)) (user-account (name "httpd") (group "httpd") @@ -472,6 +553,15 @@ (group "gitolite3") (uid 110) (system? #t)) + (user-account + (name "urz") + (group "urz") + (supplementary-groups '("cdrom" "floppy" "audio" "video" "netdev")) + (uid 1000)) + (user-account + (name "joanna") + (group "joanna") + (uid 1001)) %base-user-accounts)) (file-systems (cons (file-system (device (file-system-label "does-not-matter")) @@ -498,4 +588,6 @@ (description "Make other services assume network is there.")) #f) %koszko-certbot-service + %koszko-exim-service + %koszko-mail-aliases-service %base-services))) diff --git a/exim.conf b/exim.conf new file mode 100644 index 0000000..a5b2ec2 --- /dev/null +++ b/exim.conf @@ -0,0 +1,262 @@ +# SPDX-License-Identifier: GPL-2.0-or-later and CC0-1.0 +# Copyright (c) 2004-2023 University of Cambridge +# Copyright (C) 2023 Wojtek Kosior + +# Changes by Wojtek are available under CC0. + +# Adapted from +# https://git.exim.org/exim.git/blob/3e6d406e8ae9681a8cc1b404e7f5d1bd6d65d201:/src/src/configure.default + +spool_directory = /var/spool/exim +log_file_path = $spool_directory/log/%slog +log_selector = +smtp_protocol_error +smtp_syntax_error \ + +tls_certificate_verified +tls_peerdn + +domainlist local_domains = @:localhost:koszko.org:koszkonutek-tmp.pl.eu.org +domainlist relay_to_domains = +hostlist relay_from_hosts = : 127.0.0.1 : ::::1 + +acl_smtp_rcpt = acl_check_rcpt +.ifdef _HAVE_PRDR +# currently does nothing +acl_smtp_data_prdr = acl_check_prdr +.endif +acl_smtp_data = acl_check_data + +tls_certificate = /etc/letsencrypt/live/guixbot_koszko.org/fullchain.pem +tls_privatekey = /etc/letsencrypt/live/guixbot_koszko.org/privkey.pem + +tls_verify_certificates = ${if exists{/etc/ssl/certs/ca-certificates.crt}\ + {/etc/ssl/certs/ca-certificates.crt}\ + {/dev/null}} + +.ifdef _HAVE_GNUTLS +tls_dhparam = historic +.endif + +# For OpenSSL, prefer EC- over RSA-authenticated ciphers +.ifdef _HAVE_OPENSSL +tls_require_ciphers = ECDSA:RSA:!COMPLEMENTOFDEFAULT +.endif + +daemon_smtp_ports = 25 : 12525 : 465 : 587 +tls_on_connect_ports = 465 : 587 + +primary_hostname = koszko.org +qualify_domain = koszko.org + +never_users = root + +host_lookup = * + +dns_dnssec_ok = 1 + +#rfc1413_hosts = * +#rfc1413_query_timeout = 5s + +.ifdef _HAVE_PRDR +prdr_enable = true +.endif + +ignore_bounce_errors_after = 2d + +timeout_frozen_after = 7d + +freeze_tell = admin + +check_rfc2047_length = false + +accept_8bitmime = false + +keep_environment = + +begin acl + +acl_check_rcpt: + + accept hosts = : + control = dkim_disable_verify + + deny message = Restricted characters in address + domains = +local_domains + local_parts = ^[.] : ^.*[@%!/|`#&?] + + deny message = Restricted characters in address + domains = !+local_domains + local_parts = ^[./|] : ^.*[@%!`#&?] : ^.*/\\.\\./ + + accept local_parts = postmaster + domains = +local_domains + + require verify = sender + + deny condition = ${if and {\ + {>{$rcpt_count}{10}}\ + {<{$recipients_count}{${eval:$rcpt_count/2}}} }} + message = Rejected for too many bad recipients + logwrite = REJECT [$sender_host_address]: bad recipient count high [${eval:$rcpt_count-$recipients_count}] + + accept hosts = +relay_from_hosts + control = submission/sender_retain + control = dkim_disable_verify + + accept authenticated = * + # TODO: only use this for email sent by the admin + control = submission/sender_retain + control = dkim_disable_verify + + require message = relay not permitted + domains = +local_domains : +relay_to_domains + + require verify = recipient + + accept + + +.ifdef _HAVE_PRDR +acl_check_prdr: + + warn set acl_m_did_prdr = y + + accept +.endif + +acl_check_data: + + deny condition = ${if > {$max_received_linelength}{998}} + message = maximum allowed line length is 998 octets, \ + got $max_received_linelength + + deny !verify = header_syntax + message = header syntax + log_message = header syntax ($acl_verify_message) + + accept + +begin routers + +dnslookup: + driver = dnslookup + domains = ! +local_domains + transport = remote_smtp + same_domain_copy_routing = yes + 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 ; ::1 + dnssec_request_domains = * + no_more + +system_aliases: + driver = redirect + allow_fail + allow_defer + data = ${lookup{$local_part}lsearch{/etc/aliases}} + +userforward: + driver = redirect + check_local_user +# local_part_suffix = +* : -* +# local_part_suffix_optional + file = $home/.forward +# allow_filter + no_verify + no_expn + check_ancestor + file_transport = address_file + pipe_transport = address_pipe + reply_transport = address_reply + +localuser: + driver = accept + check_local_user + transport = local_delivery + cannot_route_message = Unknown user + +begin transports + +remote_smtp: + driver = smtp + +dkim_domain = koszko.org +dkim_selector = mail +dkim_private_key = /etc/exim/dkim.pem + +.ifdef _HAVE_DANE +dnssec_request_domains = * +hosts_try_dane = * +.endif + +local_delivery: + driver = appendfile + directory = $home/Maildir + create_directory + delivery_date_add + envelope_to_add + return_path_add + maildir_format + directory_mode = 0700 + mode = 0600 + mode_fail_narrower = false + +address_pipe: + driver = pipe + return_fail_output + +address_file: + driver = appendfile + delivery_date_add + envelope_to_add + return_path_add + +address_reply: + driver = autoreply + +begin retry + +# Address or Domain Error Retries +# ----------------- ----- ------- + +* * F,2h,15m; G,16h,1h,1.5; F,4d,6h + +begin rewrite + +begin authenticators + +# PLAIN authentication has no server prompts. The client sends its +# credentials in one lump, containing an authorization ID (which we do not +# use), an authentication ID, and a password. The latter two appear as +# $auth2 and $auth3 in the configuration and should be checked against a +# valid username and password. In a real configuration you would typically +# use $auth2 as a lookup key, and compare $auth3 against the result of the +# lookup, perhaps using the crypteq{}{} condition. + +PLAIN: + driver = plaintext + server_set_id = $auth2 + server_prompts = : + server_condition = "${if crypteq{$auth3}{${extract{1}{:}{${lookup{$auth2}lsearch{/etc/exim/passwd}{$value}{*:*}}}}}{1}{0}}" + server_advertise_condition = ${if def:tls_in_cipher } + +# LOGIN authentication has traditional prompts and responses. There is no +# authorization ID in this mechanism, so unlike PLAIN the username and +# password are $auth1 and $auth2. Apart from that you can use the same +# server_condition setting for both authenticators. + +LOGIN: + driver = plaintext + server_set_id = $auth1 + server_prompts = <| Username: | Password: + server_condition = "${if crypteq{$auth2}{${extract{1}{:}{${lookup{$auth1}lsearch{/etc/exim/passwd}{$value}{*:*}}}}}{1}{0}}" + server_advertise_condition = ${if def:tls_in_cipher } + +# Hehe +HAPPY_HACKING: + driver = plaintext + server_set_id = $auth1 + server_prompts = <| Login hackera: \ + | Hasło hackera: \ + | Ulubiony kolor: \ + | Imię pierwszego zwierzątka domowego: \ + | Panieńskie nazwisko Babci od strony Mamy: + server_condition = 0 + server_advertise_condition = 1 diff --git a/exim4.conf b/exim4.conf deleted file mode 100644 index ac0261b..0000000 --- a/exim4.conf +++ /dev/null @@ -1,263 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later and CC0-1.0 -# Copyright (c) 2004-2023 University of Cambridge -# Copyright (C) 2023 Wojtek Kosior - -# Changes by Wojtek are available under CC0. - -# Adapted from -# https://git.exim.org/exim.git/blob/3e6d406e8ae9681a8cc1b404e7f5d1bd6d65d201:/src/src/configure.default - -log_file_path = /var/log/exim/${s}log -log_selector = +smtp_protocol_error +smtp_syntax_error \ - +tls_certificate_verified +tls_peerdn - -domainlist local_domains = @:localhost:koszko.org:koszkonutek-tmp.pl.eu.org -domainlist relay_to_domains = -hostlist relay_from_hosts = : 127.0.0.1 : ::::1 - -acl_smtp_rcpt = acl_check_rcpt -.ifdef _HAVE_PRDR -# currently does nothing -acl_smtp_data_prdr = acl_check_prdr -.endif -acl_smtp_data = acl_check_data - -tls_certificate = /etc/letsencrypt/live/guixbot_koszko.org/fullchain.pem -tls_privatekey = /etc/letsencrypt/live/guixbot_koszko.org/privkey.pem - -tls_verify_certificates = ${if exists{/etc/ssl/certs/ca-certificates.crt}\ - {/etc/ssl/certs/ca-certificates.crt}\ - {/dev/null}} - -.ifdef _HAVE_GNUTLS -tls_dhparam = historic -.endif - -# For OpenSSL, prefer EC- over RSA-authenticated ciphers -.ifdef _HAVE_OPENSSL -tls_require_ciphers = ECDSA:RSA:!COMPLEMENTOFDEFAULT -.endif - -daemon_smtp_ports = 25 : 12525 : 465 : 587 -tls_on_connect_ports = 465 : 587 - -primary_hostname = koszko.org -qualify_domain = koszko.org - -never_users = root - -host_lookup = * - -dns_dnssec_ok = 1 - -#rfc1413_hosts = * -#rfc1413_query_timeout = 5s - -.ifdef _HAVE_PRDR -prdr_enable = true -.endif - -ignore_bounce_errors_after = 2d - -timeout_frozen_after = 7d - -freeze_tell = admin - -spool_directory = /var/spool/exim4 - -check_rfc2047_length = false - -accept_8bitmime = false - -keep_environment = - -begin acl - -acl_check_rcpt: - - accept hosts = : - control = dkim_disable_verify - - deny message = Restricted characters in address - domains = +local_domains - local_parts = ^[.] : ^.*[@%!/|`#&?] - - deny message = Restricted characters in address - domains = !+local_domains - local_parts = ^[./|] : ^.*[@%!`#&?] : ^.*/\\.\\./ - - accept local_parts = postmaster - domains = +local_domains - - require verify = sender - - deny condition = ${if and {\ - {>{$rcpt_count}{10}}\ - {<{$recipients_count}{${eval:$rcpt_count/2}}} }} - message = Rejected for too many bad recipients - logwrite = REJECT [$sender_host_address]: bad recipient count high [${eval:$rcpt_count-$recipients_count}] - - accept hosts = +relay_from_hosts - control = submission/sender_retain - control = dkim_disable_verify - - accept authenticated = * - # TODO: only use this for email sent by the admin - control = submission/sender_retain - control = dkim_disable_verify - - require message = relay not permitted - domains = +local_domains : +relay_to_domains - - require verify = recipient - - accept - - -.ifdef _HAVE_PRDR -acl_check_prdr: - - warn set acl_m_did_prdr = y - - accept -.endif - -acl_check_data: - - deny condition = ${if > {$max_received_linelength}{998}} - message = maximum allowed line length is 998 octets, \ - got $max_received_linelength - - deny !verify = header_syntax - message = header syntax - log_message = header syntax ($acl_verify_message) - - accept - -begin routers - -dnslookup: - driver = dnslookup - domains = ! +local_domains - transport = remote_smtp - same_domain_copy_routing = yes - 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 ; ::1 - dnssec_request_domains = * - no_more - -system_aliases: - driver = redirect - allow_fail - allow_defer - data = ${lookup{$local_part}lsearch{/etc/aliases}} - -userforward: - driver = redirect - check_local_user -# local_part_suffix = +* : -* -# local_part_suffix_optional - file = $home/.forward -# allow_filter - no_verify - no_expn - check_ancestor - file_transport = address_file - pipe_transport = address_pipe - reply_transport = address_reply - -localuser: - driver = accept - check_local_user - transport = local_delivery - cannot_route_message = Unknown user - -begin transports - -remote_smtp: - driver = smtp - -dkim_domain = koszko.org -dkim_selector = mail -dkim_private_key = /etc/exim4/dkim.pem - -.ifdef _HAVE_DANE -dnssec_request_domains = * -hosts_try_dane = * -.endif - -local_delivery: - driver = appendfile - directory = $home/Maildir - create_directory - delivery_date_add - envelope_to_add - return_path_add - maildir_format - directory_mode = 0700 - mode = 0600 - mode_fail_narrower = false - -address_pipe: - driver = pipe - return_fail_output - -address_file: - driver = appendfile - delivery_date_add - envelope_to_add - return_path_add - -address_reply: - driver = autoreply - -begin retry - -# Address or Domain Error Retries -# ----------------- ----- ------- - -* * F,2h,15m; G,16h,1h,1.5; F,4d,6h - -begin rewrite - -begin authenticators - -# PLAIN authentication has no server prompts. The client sends its -# credentials in one lump, containing an authorization ID (which we do not -# use), an authentication ID, and a password. The latter two appear as -# $auth2 and $auth3 in the configuration and should be checked against a -# valid username and password. In a real configuration you would typically -# use $auth2 as a lookup key, and compare $auth3 against the result of the -# lookup, perhaps using the crypteq{}{} condition. - -PLAIN: - driver = plaintext - server_set_id = $auth2 - server_prompts = : - server_condition = "${if crypteq{$auth3}{${extract{1}{:}{${lookup{$auth2}lsearch{/etc/exim4/passwd}{$value}{*:*}}}}}{1}{0}}" - server_advertise_condition = ${if def:tls_in_cipher } - -# LOGIN authentication has traditional prompts and responses. There is no -# authorization ID in this mechanism, so unlike PLAIN the username and -# password are $auth1 and $auth2. Apart from that you can use the same -# server_condition setting for both authenticators. - -LOGIN: - driver = plaintext - server_set_id = $auth1 - server_prompts = <| Username: | Password: - server_condition = "${if crypteq{$auth2}{${extract{1}{:}{${lookup{$auth1}lsearch{/etc/exim4/passwd}{$value}{*:*}}}}}{1}{0}}" - server_advertise_condition = ${if def:tls_in_cipher } - -# Hehe -HAPPY_HACKING: - driver = plaintext - server_set_id = $auth1 - server_prompts = <| Login hackera: \ - | Hasło hackera: \ - | Ulubiony kolor: \ - | Imię pierwszego zwierzątka domowego: \ - | Panieńskie nazwisko Babci od strony Mamy: - server_condition = 0 - server_advertise_condition = 1 diff --git a/guix-container.sh b/guix-container.sh index da8b765..d117ae3 100755 --- a/guix-container.sh +++ b/guix-container.sh @@ -2,7 +2,7 @@ # SPDX-License-Identifier: CC0-1.0 -# Copyright (C) 2022 Wojtek Kosior +# Copyright (C) 2022-2023 Wojtek Kosior # # Available under the terms of Creative Commons Zero v1.0 Universal. @@ -87,6 +87,49 @@ is_running() { return $? } +network_setup() { + SHEPHERD_PID="$1" + + ip link add veth-guix-out type veth peer name veth-guix-in + ip link set veth-guix-in netns "$SHEPHERD_PID" + + ip link set veth-guix-out up + ip addr add 10.207.87.1/24 dev veth-guix-out + + nsenter --target "$SHEPHERD_PID" --net ip link set lo up + nsenter --target "$SHEPHERD_PID" --net ip link set veth-guix-in up + nsenter --target "$SHEPHERD_PID" --net ip addr add \ + 10.207.87.2/24 dev veth-guix-in + nsenter --target "$SHEPHERD_PID" --net ip route add \ + default via 10.207.87.1 dev veth-guix-in + + if [ -n "$HOST_SYSTEM_ROOT" ]; then + # Don't connect to the real net when running in a test environment. + return + fi + + for LINKNAME in $(ip route | grep default | awk '{print $5}'); do + iptables -t nat -A POSTROUTING \ + -s 10.207.87.1/24 -o "$LINKNAME" -j MASQUERADE + iptables -t nat -A PREROUTING \ + -i "$LINKNAME" -p tcp \ + -m multiport --dports 25,12525,465,587 \ + -j DNAT --to-destination 10.207.87.2 + done + + cat /etc/resolv.conf | + nsenter --target "$SHEPHERD_PID" --all \ + /run/current-system/profile/bin/tee /etc/resolv.conf > /dev/null + + echo 1 > /proc/sys/net/ipv4/ip_forward +} + +iptables_rip_rule() { + while iptables "$@" 2>/dev/null; do + true + done +} + network_rip() { ip link delete veth-guix-out 2>/dev/null || true @@ -99,18 +142,26 @@ network_rip() { echo 0 > /proc/sys/net/ipv4/ip_forward for LINKNAME in $(ip route | grep default | awk '{print $5}'); do - iptables -t nat -D POSTROUTING \ - -s 10.207.87.1/24 -o "$LINKNAME" -j MASQUERADE 2>/dev/null \ - || true + iptables_rip_rule -t nat -D PREROUTING \ + -i "$LINKNAME" -p tcp \ + -m multiport --dports 25,12525,465,587 \ + -j DNAT --to-destination 10.207.87.2 + iptables_rip_rule -t nat -D POSTROUTING \ + -s 10.207.87.1/24 -o "$LINKNAME" \ + -j MASQUERADE done } stop() { network_rip + if ! is_running; then + return + fi + if [ -x /sbin/start-stop-daemon ]; then - /sbin/start-stop-daemon \ - --stop --signal TERM --pidfile "$PIDFILE" --remove-pidfile --quiet \ + /sbin/start-stop-daemon \ + --stop --signal TERM --pidfile "$PIDFILE" --remove-pidfile --quiet \ --retry 60 2>/dev/null || true else DAEMON_PID="$(cat "$PIDFILE")" @@ -153,18 +204,24 @@ start() { HYDRILLAREPOS_HTTP_REAL="$HOST_SYSTEM_ROOT"/var/www/hydrillarepos.koszko.org/html LOG_REAL="$LOG_DIR"/container ETC_LETSENCRYPT_REAL="$HOST_SYSTEM_ROOT"/etc/letsencrypt + ETC_EXIM_REAL="$HOST_SYSTEM_ROOT"/etc/exim ETC_REAL="$HOST_SYSTEM_ROOT"/etc/guix-container + VAR_SPOOL_EXIM_REAL="$HOST_SYSTEM_ROOT"/var/spool/exim VAR_HYDRILLA_REAL="$HOST_SYSTEM_ROOT"/var/lib/hydrilla VAR_GITOLITE_REAL="$HOST_SYSTEM_ROOT"/var/lib/gitolite3 + HOME_REAL="$HOST_SYSTEM_ROOT"/home KOSZKO_SIDELOAD_DIR_SHARE_OPT=--share="$KOSZKO_SIDELOAD_REAL"=/srv/http/koszko.org HYDRILLA_HTTP_DIR_SHARE_OPT=--share="$HYDRILLA_HTTP_REAL"=/srv/http/hydrilla.koszko.org HYDRILLAREPOS_HTTP_DIR_SHARE_OPT=--share="$HYDRILLAREPOS_HTTP_REAL"=/srv/http/hydrillarepos.koszko.org LOG_DIR_SHARE_OPT=--share="$LOG_REAL"=/var/log ETC_LETSENCRYPT_DIR_SHARE_OPT=--share="$ETC_LETSENCRYPT_REAL"=/etc/letsencrypt + ETC_EXIM_DIR_SHARE_OPT=--share="$ETC_EXIM_REAL"=/etc/exim ETC_DIR_SHARE_OPT=--share="$ETC_REAL"=/etc + VAR_SPOOL_EXIM_DIR_SHARE_OPT=--share="$VAR_SPOOL_EXIM_REAL"=/var/spool/exim VAR_HYDRILLA_DIR_SHARE_OPT=--share="$VAR_HYDRILLA_REAL"=/var/lib/hydrilla VAR_GITOLITE_DIR_SHARE_OPT=--share="$VAR_GITOLITE_REAL"=/var/lib/gitolite3 + HOME_DIR_SHARE_OPT=--share="$HOME_REAL"=/home mkdir --mode=700 -p "$LOG_DIR" mkdir --mode=700 -p "$LOG_DIR"/container @@ -174,9 +231,12 @@ start() { "$HYDRILLAREPOS_HTTP_DIR_SHARE_OPT" \ "$LOG_DIR_SHARE_OPT" \ "$ETC_LETSENCRYPT_DIR_SHARE_OPT" \ + "$ETC_EXIM_DIR_SHARE_OPT" \ "$ETC_DIR_SHARE_OPT" \ + "$VAR_SPOOL_EXIM_DIR_SHARE_OPT" \ "$VAR_HYDRILLA_DIR_SHARE_OPT" \ "$VAR_GITOLITE_DIR_SHARE_OPT" \ + "$HOME_DIR_SHARE_OPT" \ >> "$LOG_DIR"/stdout.log 2>> "$LOG_DIR"/stderr.log & GUILE_PID=$! @@ -200,34 +260,7 @@ start() { network_rip - ip link add veth-guix-out type veth peer name veth-guix-in - ip link set veth-guix-in netns "$SHEPHERD_PID" - - ip link set veth-guix-out up - ip addr add 10.207.87.1/24 dev veth-guix-out - - nsenter --target "$SHEPHERD_PID" --net ip link set lo up - nsenter --target "$SHEPHERD_PID" --net ip link set veth-guix-in up - nsenter --target "$SHEPHERD_PID" --net ip addr add \ - 10.207.87.2/24 dev veth-guix-in - nsenter --target "$SHEPHERD_PID" --net ip route add \ - default via 10.207.87.1 dev veth-guix-in - - if [ -n "$HOST_SYSTEM_ROOT" ]; then - # Don't connect to the real net when running in a test environment. - return - fi - - for LINKNAME in $(ip route | grep default | awk '{print $5}'); do - iptables -t nat -A POSTROUTING \ - -s 10.207.87.1/24 -o "$LINKNAME" -j MASQUERADE - done - - cat /etc/resolv.conf | - nsenter --target "$SHEPHERD_PID" --all \ - /run/current-system/profile/bin/tee /etc/resolv.conf > /dev/null - - echo 1 > /proc/sys/net/ipv4/ip_forward + network_setup "$SHEPHERD_PID" } trap onexit EXIT -- cgit v1.2.3