diff options
author | Wojtek Kosior <koszko@koszko.org> | 2024-01-09 12:15:02 +0100 |
---|---|---|
committer | Wojtek Kosior <koszko@koszko.org> | 2024-01-22 21:18:53 +0100 |
commit | cde0ea6ba5de37154ba8ce48d5d33fcd39f154c8 (patch) | |
tree | 3503df7034d143944e28956f71d420ce93d2def2 | |
parent | ed03ee42a204984254628a038f4c8c2beec2010a (diff) | |
download | guix-cde0ea6ba5de37154ba8ce48d5d33fcd39f154c8.tar.gz guix-cde0ea6ba5de37154ba8ce48d5d33fcd39f154c8.zip |
services: Support running Exim with setuid/setgid.
In a typical configuration, Exim binary is setuid root and the Exim daemon
process listens for connections under a non-root system account (usually
`exim`). Upon receiving a message, it forks into a child process which
re-executes the binary to regain privileges and deliver the mail to its
destination (e.g. a Maildir inside user's home directory).
Besides the setuid binary itself, such setup also requires the Exim
configuration file to live at the path Exim considers safe. It defaults to
/etc/exim.conf and changing it requires rebuilding the Exim daemon. If a
configuration at unsafe path is used instead, Exim drops its privileges before
reading it and becomes unable to perform certain kinds of email delivery.
* gnu/services/mail.scm (<exim-configuration>)[setuid-user]: New field.
(<exim-configuration>)[setgid-group]: New field.
(exim-computed-config-file): Delete variable.
(exim-shepherd-service)[start]: Use Exim's default config at /etc/exim.conf.
(exim-activation): Atomically put Exim's current config at /etc/exim.conf and
verify its syntactic correctness.
(exim-setuids): New variable.
(exim-service-type)[extensions]: Extend `setuid-program-service-type`.
Change-Id: Ie6153baac80180d3d48f6b5a6959895df06aef0b
-rw-r--r-- | gnu/services/mail.scm | 67 |
1 files changed, 44 insertions, 23 deletions
diff --git a/gnu/services/mail.scm b/gnu/services/mail.scm index afe1bb6016..d5c5e5d35e 100644 --- a/gnu/services/mail.scm +++ b/gnu/services/mail.scm @@ -7,6 +7,9 @@ ;;; Copyright © 2020 Jonathan Brielmaier <jonathan.brielmaier@web.de> ;;; Copyright © 2023 Thomas Ieong <th.ieong@free.fr> ;;; Copyright © 2023 Saku Laesvuori <saku@laesvuori.fi> +;;; Copyright © 2023, 2024 Wojtek Kosior <koszko@koszko.org> +;;; Additions and modifications by Wojtek Kosior are additionally +;;; dual-licensed under the Creative Commons Zero v1.0. ;;; ;;; This file is part of GNU Guix. ;;; @@ -1816,10 +1819,14 @@ database---computed from the given alias list."))) (define-record-type* <exim-configuration> exim-configuration make-exim-configuration exim-configuration? - (package exim-configuration-package ;file-like - (default exim)) - (config-file exim-configuration-config-file ;file-like - (default #f))) + (package exim-configuration-package ;file-like + (default exim)) + (config-file exim-configuration-config-file ;file-like + (default #f)) + (setuid-user exim-configuration-setuid-user + (default #f)) + (setgid-group exim-configuration-setgid-group + (default #f))) (define %exim-accounts (list (user-group @@ -1833,17 +1840,6 @@ database---computed from the given alias list."))) (home-directory "/var/empty") (shell (file-append shadow "/sbin/nologin"))))) -(define (exim-computed-config-file package config-file) - (computed-file "exim.conf" - #~(call-with-output-file #$output - (lambda (port) - (format port " -exim_user = exim -exim_group = exim -.include ~a" - #$(or config-file - (file-append package "/etc/exim.conf"))))))) - (define exim-shepherd-service (match-lambda (($ <exim-configuration> package config-file) @@ -1852,29 +1848,53 @@ exim_group = exim (documentation "Run the exim daemon.") (requirement '(networking)) (start #~(make-forkexec-constructor - '(#$(file-append package "/bin/exim") - "-bd" "-v" "-C" - #$(exim-computed-config-file package config-file)))) + '(#$(file-append package "/bin/exim") "-bd" "-v"))) (stop #~(make-kill-destructor))))))) (define exim-activation (match-lambda - (($ <exim-configuration> package config-file) + (($ <exim-configuration> package config-file setuid-user setgid-group) (with-imported-modules '((guix build utils)) #~(begin - (use-modules (guix build utils)) + (use-modules (guix build utils) + (ice-9 format)) (let ((uid (passwd:uid (getpw "exim"))) (gid (group:gid (getgr "exim")))) (mkdir-p "/var/spool/exim") (chown "/var/spool/exim" uid gid)) - (zero? (system* #$(file-append package "/bin/exim") - "-bV" "-C" #$(exim-computed-config-file package config-file)))))))) + ;; Exim often rereads its config file. Let's substitute it + ;; atomically. + (with-output-to-file "/etc/exim.conf.new" + (lambda _ + (format #t " +~:[~;exim_path = /run/setuid-programs/exim~%~] +.include ~a" + (or #$setuid-user #$setgid-group) + #$(or config-file + (file-append package "/etc/exim.conf"))))) + + (chmod "/etc/exim.conf.new" #o444) + (rename-file "/etc/exim.conf.new" "/etc/exim.conf") + + (zero? (system* #$(file-append package "/bin/exim") "-bV"))))))) (define exim-profile (compose list exim-configuration-package)) +(define exim-setuids + (match-lambda + (($ <exim-configuration> package config-file setuid-user setgid-group) + (if (or setuid-user setgid-group) + (list (setuid-program + (program (file-append package "/bin/exim")) + (setuid? #t) + (user (or setuid-user "exim")) + (setgid? (not (not setgid-group))) + (group (or setgid-group 0)))) + '())))) + (define exim-service-type (service-type (name 'exim) @@ -1883,7 +1903,8 @@ exim_group = exim (service-extension account-service-type (const %exim-accounts)) (service-extension activation-service-type exim-activation) (service-extension profile-service-type exim-profile) - (service-extension mail-aliases-service-type (const '())))) + (service-extension mail-aliases-service-type (const '())) + (service-extension setuid-program-service-type exim-setuids))) (description "Run the Exim mail transfer agent (MTA)."))) |