aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWojtek Kosior <koszko@koszko.org>2024-01-09 12:15:02 +0100
committerWojtek Kosior <koszko@koszko.org>2024-01-22 21:18:53 +0100
commitcde0ea6ba5de37154ba8ce48d5d33fcd39f154c8 (patch)
tree3503df7034d143944e28956f71d420ce93d2def2
parented03ee42a204984254628a038f4c8c2beec2010a (diff)
downloadguix-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.scm67
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).")))