diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/xyz/euandreh/queue.scm | 796 |
1 files changed, 749 insertions, 47 deletions
diff --git a/src/xyz/euandreh/queue.scm b/src/xyz/euandreh/queue.scm index 7a5f60d..a752b2d 100644 --- a/src/xyz/euandreh/queue.scm +++ b/src/xyz/euandreh/queue.scm @@ -1,6 +1,6 @@ (define-module (xyz euandreh queue) + #:use-module ((gnu build linux-container) #:prefix container:) #:use-module ((guix licenses) #:prefix license:) - ;; #:use-module ((nonguix licenses) #:prefix ng-license:) #:use-module ((srfi srfi-1) #:prefix srfi-1:) #:use-module (guix build-system gnu) #:use-module (guix build-system python) @@ -360,7 +360,7 @@ collections.OrderedDict that works in Python 2.4-2.6.") python-pytz python-tornado)) (home-page "https://python-telegram-bot.org/") - (synopsis "We have made you a wrapper you can't refuse") + (synopsis "Python library to interface with the Telegram Bot API") (description "We have made you a wrapper you can't refuse") (license #f))) @@ -384,7 +384,7 @@ collections.OrderedDict that works in Python 2.4-2.6.") #~(begin (use-modules (guix build utils)) (format (current-error-port) - "Setting ownership and permission for \"/etc/passwd\".~%") + "Setting ownership and permission for \"/etc/shadow\".~%") (chown "/etc/shadow" (passwd:uid (getpwnam "root")) (group:gid (getgrnam #$group))) @@ -429,14 +429,22 @@ collections.OrderedDict that works in Python 2.4-2.6.") (supplementary-groups cyrus-sasl-configuration-supplementary-groups (default '("etc-shadow"))) (authmech cyrus-sasl-configuration-authmech (default "shadow")) (services cyrus-sasl-configuration-services (default '())) - (state-dir cyrus-sasl-configuration-state-dir (default "/var/lib/saslauthd"))) + (config-dirname cyrus-sasl-configuration-config-dirname (default "sasl2")) + (run-directory cyrus-sasl-configuration-run-directory (default "/var/run/saslauthd")) + (run-in-container? cyrus-sasl-configuration-run-in-container? (default #t)) + (container-name cyrus-sasl-configuration-container-name (default "saslauthd")) + (container-namespaces cyrus-sasl-configuration-container-namespaces (default %namespaces)) + (extra-mappings cyrus-sasl-configuration-extra-mappings (default '()))) + (define (cyrus-sasl-etc-files config) + ;; FIXME: support opaque files + ;; FIXME: extend this with postfix instead of making postfix add here (match-record config <cyrus-sasl-configuration> - (services state-dir) - `(("sasl2" + (services config-dirname run-directory) + `((,config-dirname ,(file-union - "cyrus-sasl" + config-dirname (map (lambda (service-config) (match-record service-config <cyrus-service-configuration> (name authmech log-level) @@ -445,21 +453,21 @@ collections.OrderedDict that works in Python 2.4-2.6.") (format #f "pwcheck_method: ~a~%saslauthd_path: ~a/mux~%log_level: ~a~%" authmech - state-dir + run-directory log-level))))) services)))))) (define (cyrus-sasl-activation config) (match-record config <cyrus-sasl-configuration> - (user state-dir) + (user run-directory) #~(begin (use-modules (guix build utils)) (let ((user (getpwnam #$user))) (format (current-error-port) - "Creating Cyrus SASL socket directory: \"~a\".~%" #$state-dir) - (mkdir-p #$state-dir) - (chown #$state-dir (passwd:uid user) (passwd:gid user)) - (chmod #$state-dir #o755))))) + "Creating Cyrus SASL socket directory: \"~a\".~%" #$run-directory) + (mkdir-p #$run-directory) + (chown #$run-directory (passwd:uid user) (passwd:gid user)) + (chmod #$run-directory #o755))))) (define (cyrus-sasl-accounts config) (match-record config <cyrus-sasl-configuration> @@ -471,31 +479,60 @@ collections.OrderedDict that works in Python 2.4-2.6.") (supplementary-groups supplementary-groups) (comment "Cyrus SASL system user") (home-directory "/var/empty") - (shell (file-append shadow "/sbin/nologin")) + (create-home-directory? #f) + (shell + (file-append shadow "/sbin/nologin")) (system? #t)) (user-group (name group) (system? #t))))) + (define (cyrus-sasl-shepherd-service config) (match-record config <cyrus-sasl-configuration> - (cyrus-sasl user group supplementary-groups authmech state-dir) - (list - (shepherd-service - (provision '(cyrus-sasl)) - (documentation "FIXME:DOCUMENTATION") - (start #~(make-forkexec-constructor - (list - #$(file-append cyrus-sasl "/sbin/saslauthd") - "-a" - #$authmech - "-d" - "-m" - #$state-dir) - #:user #$user - #:group #$group - #:supplementary-groups '(#$@supplementary-groups))) - (stop #~(make-kill-destructor)))))) + (cyrus-sasl user group supplementary-groups authmech config-dirname run-directory + services run-in-container? container-name container-namespaces extra-mappings) + (let* ((config-dir (string-append "/etc/" config-dirname)) + (bin (file-append cyrus-sasl "/sbin/saslauthd")) + (cmd (if (not run-in-container?) + bin + (least-authority-wrapper + bin + #:name container-name + #:mappings (append + (list + (file-system-mapping + (source run-directory) + (target source) + (writable? #t)) + (file-system-mapping + (source "/etc/passwd") + (target source)) + (file-system-mapping + (source "/etc/shadow") + (target source))) + extra-mappings) + #:namespaces container-namespaces)))) + (list + (shepherd-service + (provision '(cyrus-sasl)) + (documentation "FIXME:DOCUMENTATION") + (start #~(make-forkexec-constructor + (list #$cmd "-a" #$authmech "-d" "-m" #$run-directory) + #:user #$user + #:group #$group + #:supplementary-groups '(#$@supplementary-groups))) + (stop #~(make-kill-destructor)) + (actions + (list + (shepherd-action + (name 'configuration) + (documentation "FIXME:DOCUMENTATION") + (procedure + #~(lambda _ + (for-each (lambda (name) + (format #t "~a/~a~%" #$config-dir name)) + (map cyrus-service-configuration-name #$services)))))))))))) (define cyrus-sasl-service-type (service-type @@ -528,16 +565,20 @@ collections.OrderedDict that works in Python 2.4-2.6.") dkimproxyout-configuration make-dkimproxyout-configuration dkimproxyout-configuration? - (dkimproxy dkimproxyout-configuration-dkimproxy (default dkimproxy)) - (user dkimproxyout-configuration-user (default "dkimproxyout")) - (group dkimproxyout-configuration-group (default "dkimproxyout")) - (config-name dkimproxyout-configuration-config-name (default "dkimproxyout.conf")) - (listen dkimproxyout-configuration-listen (default "127.0.0.1:10027")) - (relay dkimproxyout-configuration-relay (default "127.0.0.1:10028")) - (domains dkimproxyout-configuration-domains (default (list (gethostname)))) - (selector dkimproxyout-configuration-selector (default "dkimproxyout")) - (key-size dkimproxyout-configuration-key-size (default 2048)) - (data-directory dkimproxyout-configuration-data-directory (default "/var/lib/dkimproxyout"))) + (dkimproxy dkimproxyout-configuration-dkimproxy (default dkimproxy)) + (user dkimproxyout-configuration-user (default "dkimproxyout")) + (group dkimproxyout-configuration-group (default "dkimproxyout")) + (config-name dkimproxyout-configuration-config-name (default "dkimproxyout.conf")) + (listen dkimproxyout-configuration-listen (default "127.0.0.1:10027")) + (relay dkimproxyout-configuration-relay (default "127.0.0.1:10028")) + (domains dkimproxyout-configuration-domains (default (list (gethostname)))) + (selector dkimproxyout-configuration-selector (default "dkimproxyout")) + (key-size dkimproxyout-configuration-key-size (default 2048)) + (data-directory dkimproxyout-configuration-data-directory (default "/var/lib/dkimproxyout")) + (run-in-container? dkimproxyout-configuration-run-in-container? (default #f)) + (container-name dkimproxyout-configuration-container-name (default "dkimproxyout")) + (container-namespaces dkimproxyout-configuration-container-namespaces (default (srfi-1:fold delq %namespaces '(net)))) + (extra-mappings dkimproxyout-configuration-extra-mappings (default '()))) (define (generate-out.cf config) (match-record config <dkimproxyout-configuration> @@ -578,7 +619,9 @@ keyfile ~a/private.key (group group) (comment "DKIMproxy.out signing system user") (home-directory "/var/empty") - (shell (file-append shadow "/sbin/nologin")) + (create-home-directory? #f) + (shell + (file-append shadow "/sbin/nologin")) (system? #t)) (user-group (name group) @@ -599,6 +642,8 @@ keyfile ~a/private.key (let ((private-key (string-append #$data-directory "/private.key")) (public-key (string-append #$data-directory "/public.key"))) (unless (file-exists? private-key) + (format (current-error-port) + "The public/private keypair doesn't exist yet. Generating one...~%") (cond ((zero? (system* #$(file-append openssl "/bin/openssl") "genrsa" @@ -624,18 +669,35 @@ keyfile ~a/private.key (chmod private-key #o400) (chmod public-key #o644)))))) + (define (dkimproxyout-shepherd-service config) (match-record config <dkimproxyout-configuration> - (dkimproxy user group config-name) - (let ((config-file (string-append "/etc/" config-name))) + (dkimproxy user group config-name data-directory + run-in-container? container-name container-namespaces extra-mappings) + (let* ((config-file (string-append "/etc/" config-name)) + (bin (file-append dkimproxy "/bin/dkimproxy.out")) + (cmd (if (not run-in-container?) + bin + (least-authority-wrapper + bin + #:name container-name + #:mappings (append + (list + (file-system-mapping + (source config-file) + (target source)) + (file-system-mapping + (source + (string-append data-directory "/private.key")) + (target source))) + extra-mappings) + #:namespaces container-namespaces)))) (list (shepherd-service (provision '(dkimproxyout)) (documentation "FIXME:DOCUMENTATION") (start #~(make-forkexec-constructor - (list - #$(file-append dkimproxy "/bin/dkimproxy.out") - "--conf_file" #$config-file) + (list #$cmd "--conf_file" #$config-file) #:user #$user #:group #$group)) (stop #~(make-kill-destructor)) @@ -648,6 +710,7 @@ keyfile ~a/private.key #~(lambda _ (format #t "~a~%" #$config-file))))))))))) + (define-public dkimproxyout-service-type (service-type (name 'dkimproxyout) @@ -668,6 +731,645 @@ keyfile ~a/private.key + + + + + + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Postfix ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + + +(define-record-type* <postfix-configuration> + postfix-configuration + make-postfix-configuration + postfix-configuration? + (postfix postfix-configuration-postfix (default postfix)) + (set-sendmail? postfix-configuration-set-sendmail? (default #t)) + (master.cf-file postfix-configuration-master.cf-file (default #f)) + (main.cf-file postfix-configuration-main.cf-file (default #f)) + (master.cf-extra postfix-configuration-master.cf-extra (default "")) + (main.cf-extra postfix-configuration-main.cf-extra (default "")) + (config-dirname postfix-configuration-config-dirname (default "postfix")) + (data-directory postfix-configuration-data-directory (default "/var/lib/postfix")) + (queue-directory postfix-configuration-queue-directory (default "/var/spool/postfix")) + (user postfix-configuration-user (default "postfix")) + (group postfix-configuration-group (default "postfix")) + (setgid-group postfix-configuration-setgid-group (default "postdrop")) + (root-aliases postfix-configuration-root-aliases (default '("abuse" "admin" "hostmaster" "postmaster"))) + (cert-file postfix-configuration-cert-file (default #f)) + (key-file postfix-configuration-key-file (default #f)) + (hostname postfix-configuration-hostname (default (gethostname))) + (run-in-container? postfix-configuration-run-in-container? (default #f)) + (container-name postfix-configuration-container-name (default "postfix")) + (container-namespaces postfix-configuration-container-namespaces (default (srfi-1:fold delq %namespaces '(net)))) + (extra-mappings postfix-configuration-extra-mappings (default '()))) + +; FIXME: hardcoded value of dkimproxy listen and relay +(define (generate-master.cf config) + (match-record config <postfix-configuration> + (master.cf-extra) + (format #f + #"- + # ============================================================================================================ + # service type private unpriv chroot wakeup maxproc command + args + # (yes) (yes) (no) (never) (100) + # ============================================================================================================= + + + anvil unix - - n - 1 anvil + bounce unix - - n - 0 bounce + cleanup unix n - n - 0 cleanup + defer unix - - n - 0 bounce + discard unix - - n - - discard + error unix - - n - - error + flush unix n - n 1000? 0 flush + lmtp unix - - n - - lmtp + local unix - n n - - local + # FIXME: replace 127.0.0.1 with localhost + pickup unix n - n 60 1 pickup + -o content_filter=dksign:[127.0.0.1]:10027 + proxymap unix - - n - - proxymap + proxywrite unix - - n - 1 proxymap + qmgr unix n - n 300 1 qmgr + relay unix - - n - - smtp -o syslog_name=postfix/relay + retry unix - - n - - error + rewrite unix - - n - - trivial-rewrite + scache unix - - n - 1 scache + showq unix n - n - - showq + smtp inet n - n - - smtpd -o syslog_name=postfix/smtp + smtp unix - - n - - smtp + submission inet n - n - - smtpd -o syslog_name=postfix/submission + -o smtpd_tls_security_level=encrypt + -o content_filter=dksign:[127.0.0.1]:10027 + tlsmgr unix - - n 1000? 1 tlsmgr + trace unix - - n - 0 bounce + verify unix - - n - 1 verify + virtual unix - n n - - virtual + postlog unix-dgram n - n - 1 postlogd + + # FIXME: doesn't work for sendmail -t in localhost + dksign unix - - n - - smtp + -o syslog_name=postfix/dkimproxyout-listen + -o smtp_send_xforward_command=yes + -o smtp_discard_ehlo_keywords=8bitmime,starttls + 127.0.0.1:10028 inet n - n - - smtpd + -o syslog_name=postfix/dkimproxyout-relay + -o content_filter= + -o receive_override_options=no_unknown_recipient_checks,no_header_body_checks + -o smtpd_helo_restrictions= + -o smtpd_client_restrictions= + -o smtpd_sender_restrictions= + -o smtpd_recipient_restrictions=permit_mynetworks,reject + -o mynetworks=127.0.0.0/8 + -o smtpd_authorized_xforward_hosts=127.0.0.0/8 + ~a + "# + master.cf-extra))) + +(define (cert-for config) + (match-record config <postfix-configuration> + (cert-file hostname) + (or cert-file (format #f "/etc/letsencrypt/live/~a/fullchain.pem" hostname)))) + +(define (key-for config) + (match-record config <postfix-configuration> + (key-file hostname) + (or key-file (format #f "/etc/letsencrypt/live/~a/privkey.pem" hostname)))) + +(define (generate-main.cf config) + (match-record config <postfix-configuration> + (postfix queue-directory data-directory user setgid-group hostname main.cf-extra) + (format #f + #"- + compatibility_level = 3.6 + + queue_directory = ~a + data_directory = ~a + mail_owner = ~a + setgid_group = ~a + + myhostname = ~a + mydestination = $myhostname, $mydomain, localhost.$mydomain, localhost + + alias_maps = hash:/etc/aliases + # alias_maps = hash:/etc/aliases, static:andreh + + mail_spoo_directory = /var/mail/ + + header_checks = regexp:{ { /^Received:.*/ IGNORE }, { /^X-Originating-IP:.*/ IGNORE } } + + smtpd_use_tls = yes + smtpd_tls_cert_file = ~a + smtpd_tls_key_file = ~a + smtp_use_tls = $smtpd_use_tls + smtp_tls_cert_file = $smtpd_tls_cert_file + smtp_tls_key_file = $smtpd_tls_key_file + + smtp_tls_security_level = may + + recipient_delimiter = + + + # smtpd_sasl_security_options = FIXME: deny all + smtpd_sasl_tls_security_options = noanonymous + # FIXME: shouldn't this be "encrypt"? + smtpd_tls_security_level = may + smtpd_tls_auth_only = yes + + smtpd_relay_restrictions = $smtpd_recipient_restrictions + smtpd_recipient_restrictions = permit_mynetworks, + permit_sasl_authenticated, reject_unauth_destination + smtpd_sasl_auth_enable = yes + cyrus_sasl_config_path = /etc/sasl2 + debug_peer_list = 127.0.0.1 + + milter_default_action = accept + # smtpd_milters = FIXME + ~a + "# + queue-directory + data-directory + user + setgid-group + hostname + + (cert-for config) + (key-for config) + main.cf-extra))) + +(define (postfix-etc-files config) + (match-record config <postfix-configuration> + (master.cf-file main.cf-file config-dirname) + `((,config-dirname + ,(file-union + config-dirname + `(("master.cf" ,(plain-file "master.cf" (or master.cf-file (generate-master.cf config)))) + ("main.cf" ,(plain-file "main.cf" (or main.cf-file (generate-main.cf config)))))))))) + +(define (postfix-accounts config) + (match-record config <postfix-configuration> + (user group setgid-group) + (list + (user-account + (name user) + (group group) + (comment "Postfix system user") + (home-directory "/var/empty") + (create-home-directory? #f) + (shell + (file-append shadow "/sbin/nologin")) + (system? #t)) + (user-group + (name group) + (system? #t)) + (user-group + (name setgid-group) + (system? #t))))) + +(define (postfix-setuid-programs config) + (match-record config <postfix-configuration> + (postfix setgid-group set-sendmail?) + (append + (list + (setuid-program + (program (file-append postfix "/sbin/postdrop")) + (setuid? #f) + (setgid? #t) + (group setgid-group)) + (setuid-program + (program (file-append postfix "/sbin/postqueue")) + (setuid? #f) + (setgid? #t) + (group setgid-group))) + (if set-sendmail? + (list + (setuid-program + (program (file-append postfix "/sbin/sendmail")) + (setuid? #f) + (setgid? #t) + (group setgid-group))) + '())))) + +(define (postfix-activation config) + (match-record config <postfix-configuration> + (queue-directory) + #~(begin + (use-modules (guix build utils)) + (let ((user (getpwnam "root"))) + (format (current-error-port) + "Creating Postfix queue directory: \"~a\".~%" #$queue-directory) + (mkdir-p #$queue-directory) + (chown #$queue-directory (passwd:uid user) (passwd:gid user)) + (chmod #$queue-directory #o755) + (format (current-error-port) + "Creating email spool director: \"/var/mail\".~%") + (mkdir-p "/var/mail") + (format (current-error-port) + "Updating /etc/aliases: FIXME.~%") + ;; FIXME: add -c option +#; + (invoke #$(file-append postfix "/sbin/postalias") "/etc/aliases"))))) + +(define (postfix-shepherd-service config) + (match-record config <postfix-configuration> + (postfix config-dirname data-directory queue-directory + run-in-container? container-name container-namespaces extra-mappings) + (let* ((config-dir (string-append "/etc/" config-dirname)) + (bin (file-append postfix "/sbin/postfix")) + (cmd (if (not run-in-container?) + bin + (least-authority-wrapper + bin + #:name container-name + #:mappings (append + (list + (file-system-mapping + (source data-directory) + (target source) + (writable? #t)) + (file-system-mapping + (source queue-directory) + (target source) + (writable? #t))) + extra-mappings) + #:namespaces container-namespaces)))) + (list + (shepherd-service + (provision '(postfix)) + (documentation + #"- + Run the Postfix MTA. + + This is the entrypoint for starting the "master" process. Then the + "master" process itself takes responsability of starting all the + required daemons and commands."#) + (start #~(make-forkexec-constructor + (list + #$(file-append postfix "/sbin/postfix") + "-c" + #$config-dir + "start-fg") + #:pid-file "/var/lib/postfix/master.lock")) + (stop #~(make-kill-destructor SIGKILL)) + (actions + (list + (shepherd-action + (name 'configuration) + (documentation + #"- + FIXME:DOCUMENTATION + "#) + (procedure + #~(lambda _ + (format #t "~a/master.cf~%" #$config-dir) + (format #t "~a/main.cf~%" #$config-dir)))) + (shepherd-action + (name 'reload) + (documentation + #"- + Re-read the "master.cf" and "main.cf" configuration files. + + Daemon processes terminate when possible, and when restarted + use the values of the new configuration files. + + This live-reload option is usually preferable over a stop/start + cycle, as it incurs in no interruption of the running service."#) + (procedure + #~(lambda _ + (invoke #$(file-append postfix "/sbin/postfix") + "-c" + #$config-dir + "reload"))))))))))) + +(define (postfix-aliases config) + (match-record config <postfix-configuration> + (root-aliases) + (map (lambda (alias) + `(,alias "root")) + root-aliases))) + + +(define (postfix-nginx-locations config) + (match-record config <postfix-configuration>) + (hostname) + (nginx-server-configuration + (server-name (list (string-append "mta-sts." hostname))) + (listen '("[::]:443 ssl http2" "443 ssl http2")) + (ssl-certificate (cert-for config)) + (ssl-certificate-key (key-for config)) + (locations + (list + (nginx-location-configuration + (uri "= /.well-known/mta-sts.txt") + (body + (list + (list "alias " + (plain-file + "mta-sts.txt" + (format #f #"- + version: STSv1 + mode: enforce + mx: ~a + max_age: 604800 + "# + hostname)) + ";")))))))) + +(define (postfix-certificates config) + (match-record config <postfix-configuration> + (hostname) + (list + (certificate-configuration + (domains (list hostname (string-append "mta-sts." hostname))))))) + +(define (postfix-sasl-service _config) + (list + (cyrus-service-configuration + (name "smtpd.conf")))) + + +(define postfix-service-type + (service-type + (name 'postfix) + (extensions + (list + (service-extension etc-service-type + postfix-etc-files) + (service-extension account-service-type + postfix-accounts) + (service-extension setuid-program-service-type + postfix-setuid-programs) + (service-extension activation-service-type + postfix-activation) + (service-extension mail-aliases-service-type + postfix-aliases) + (service-extension profile-service-type + (compose list postfix-configuration-postfix)) + (service-extension shepherd-root-service-type + postfix-shepherd-service) + (service-extension nginx-service-type + postfix-nginx-locations) + (service-extension certbot-service-type + postfix-certificates) + (service-extension cyrus-sasl-service-type + postfix-sasl-services))) + (default-value (postfix-configuration)) + (description + #"- + Run the Postfix MTA. + + This is the top-level system service for Postfix. + + It includes: + - populating /etc/postfix/ with read-only configuration files; + - the user and groups used by Postfix when handling email delivery; + - the special setgid binaries for daily usage, such as "sendmail"; + - the Shepherd service for starting, stopping and *reloading* the + service without restarting it; + - the activation script for creating the required directories and + configuring them with the correct permissions; + - the binaries in the system profile so that one doesn't need to explicilty + include the package when the service is already enabled. + + An extension to the log-rotation service isn't included: the default + rottlog configuration already includes /var/log/maillog in its routine, + so it is kept out. + + The defaults of <postfix-configuration> provide sane default values for + most things, such as group names, data and queue directories, etc. When + used as-is, it creates a Postfix server that sends email from local users + of the domain provided by "/etc/hostname"."#))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Dovecot ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + + +(define-record-type* <dovecot2-configuration> + dovecot2-configuration + make-dovecot2-configuration + dovecot2-configuration? + (dovecot2 dovecot2-configuration-dovecot2 (default dovecot)) + (raw-file dovecot2-configuration-raw-file (default #f)) + (extra-content dovecot2-configuration-extra-content (default "")) + (config-name dovecot2-configuration-config-name (default "dovecot2.conf")) + (user dovecot2-configuration-user (default "dovecot2")) + (group dovecot2-configuration-group (default "dovecot2")) + (auth-worker-group dovecot2-configuration-auth-worker-group (default "etc-shadow")) + (untrusted-user dovecot2-configuration-untrusted-user (default "dovenull2")) + (untrusted-group dovecot2-configuration-untrusted-group (default "dovenull2")) + (base-dir dovecot2-configuration-base-dir (default "/var/run/dovecot2")) + (state-dir dovecot2-configuration-state-dir (default "/var/lib/dovecot2")) + (hostname dovecot2-configuration-hostname (default (gethostname)))) + +(define (generate-dovecot-config config) + (match-record config <dovecot2-configuration> + (user group auth-worker-group untrusted-user + hostname base-dir state-dir extra-content) + (format #f + #"- + protocols = imap + + default_internal_user = ~a + default_internal_group = ~a + default_login_user = ~a + auth_mechanisms = plain login + auth_username_format = %n + + passdb { + driver = shadow + } + userdb { + driver = passwd + } + service auth-worker { + group = ~a + } + + + ssl = required + ssl_cert = </etc/letsencrypt/live/~a/fullchain.pem + ssl_key = </etc/letsencrypt/live/~a/privkey.pem + ssl_dh = <~a/dhparam.pem + + base_dir = ~a + state_dir = ~a + + verbose_proctitle = yes + + # FIXMEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE + # mail_location = maildir:~~/Mail:INBOX=~~/Mail/Inbox:LAYOUT=fs + # mail_location = maildir:~~/Mail:INBOX=~~/Mail/Inbox:LAYOUT=fs + + # FIXME: + # mail_plugins + + + namespace inbox { + inbox = yes + mailbox Drafts { + special_use = \Drafts + auto = subscribe + } + mailbox Sent { + special_use = \Sent + auto = subscribe + } + mailbox Archive { + special_use = \Archive + auto = subscribe + } + mailbox Spam { + special_use = \Junk + auto = subscribe + autoexpunge = 30d + } + mailbox Trash { + special_use = \Trash + auto = subscribe + } + } + ~a + "# + user + group + untrusted-user + auth-worker-group + hostname + hostname + state-dir + base-dir + state-dir + extra-content))) + +(define (dovecot2-etc-files config) + (match-record config <dovecot2-configuration> + (raw-file config-name) + `((,config-name ,(plain-file config-name + (or raw-file + (generate-dovecot-config config))))))) + +(define (dovecot2-accounts config) + (match-record config <dovecot2-configuration> + (user group untrusted-user untrusted-group) + (list + (user-account + (name user) + (group group) + (comment "Dovecot system user") + (home-directory "/var/empty") + (create-home-directory? #f) + (shell + (file-append shadow "/sbin/nologin")) + (system? #t)) + (user-account + (name untrusted-user) + (group untrusted-group) + (comment "Dovecot user for untrusted logins") + (home-directory "/var/empty") + (create-home-directory? #f) + (shell + (file-append shadow "/sbin/nologin")) + (system? #t)) + (user-group + (name group) + (system? #t)) + (user-group + (name untrusted-group) + (system? #t))))) + +(define (dovecot2-activation config) + (match-record config <dovecot2-configuration> + (base-dir state-dir) + #~(begin + (use-modules (guix build utils)) + (let ((user (getpwnam "root"))) + (format (current-error-port) + "Creating Dovecot base_dir directory: \"~a\".~%" #$base-dir) + (mkdir-p #$base-dir) + (let ((dhparam.pem (string-append #$state-dir "/dhparam.pem"))) + (unless (file-exists? dhparam.pem) + (format (current-error-port) + "dhparam.pem file doesn't exist yet. Generating one...~%") + (cond + ((zero? (system* (string-append #$openssl "/bin/openssl") + "dhparam" "-out" dhparam.pem "2048")) + (format (current-error-port) + "Dovecot2 dhparam.pem file created: \"~a\".~%" dhparam.pem)) + (else + (format (current-error-port) + "Failed to create dhparam.pem file: \"~a\".~%" dhparam.pem))))))))) + +(define (dovecot2-shepherd-service config) + (match-record config <dovecot2-configuration> + (dovecot2 config-name) + (let ((config-file (string-append "/etc/" config-name))) + (list + (shepherd-service + (provision '(dovecot2)) + (documentation "FIXME:DOCUMENTATION: heredoc syntax") + (start #~(make-forkexec-constructor + (list + #$(file-append dovecot2 "/sbin/dovecot") + "-F" + "-c" + #$config-file))) + (stop #~(make-kill-destructor)) + (actions + (list + (shepherd-action + (name 'configuration) + (documentation "FIXME:DOCUMENTATION: heredoc syntax") + (procedure + #~(lambda _ + (format #t "~a~%" #$config-file)))) + (shepherd-action + (name 'reload) + (documentation "FIXME:DOCUMENTATION: heredoc syntax") + (procedure + #~(lambda _ + (invoke #$(file-append dovecot "/bin/doveadm") + "-c" + #$config-file + "reload"))))))))))) + +(define dovecot2-service-type + (service-type + (name 'dovecot2) + (extensions + (list + (service-extension etc-service-type + dovecot2-etc-files) + (service-extension account-service-type + dovecot2-accounts) + (service-extension activation-service-type + dovecot2-activation) + (service-extension profile-service-type + (compose list dovecot2-configuration-dovecot2)) + (service-extension shepherd-root-service-type + dovecot2-shepherd-service))) + (default-value (dovecot2-configuration)) + (description "FIXME:DOCUMENTATION: heredoc syntax"))) + +;; FIXME +;; automate personal server with: +;; - euandreh:git-service-type +;; - euandreh:mail-service-type + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; OS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + + (list postfix python-telegram-bot) |