From e9337b346fcdea45dfebe30de3bc6c8182174ff4 Mon Sep 17 00:00:00 2001 From: Martin Weinelt Date: Fri, 20 Mar 2026 01:14:43 +0100 Subject: [PATCH] Rename mailserver.loginAccounts to mailserver.accounts The "login" prefix makes this option more confusing rather than clearer, because what other account types are there? LDAP ones for example, but you can login with those too, so the prefix is pointless. --- default.nix | 19 ++++++++++--------- docs/faq.rst | 2 +- docs/radicale.nix | 2 +- docs/radicale.rst | 2 +- docs/release-notes.rst | 2 +- docs/setup-example.nix | 2 +- mail-server/common.nix | 8 ++++---- mail-server/dovecot.nix | 6 +++--- mail-server/postfix.nix | 8 ++++---- mail-server/users.nix | 6 +++--- scripts/generate-options.py | 2 +- tests/clamav.nix | 2 +- tests/external.nix | 2 +- tests/internal.nix | 2 +- tests/ldap.nix | 2 +- tests/multiple.nix | 2 +- 16 files changed, 35 insertions(+), 34 deletions(-) diff --git a/default.nix b/default.nix index cc4f7a7..575cc6c 100644 --- a/default.nix +++ b/default.nix @@ -136,7 +136,7 @@ in description = "Message size limit enforced by Postfix."; }; - loginAccounts = mkOption { + accounts = mkOption { type = types.attrsOf ( types.submodule ( { name, ... }: @@ -170,7 +170,7 @@ in storing hashed secrets in the world-readable Nix store. Passing the hash through - {option}`mailserver.loginAccounts..hashedPasswordFile` + {option}`mailserver.accounts..hashedPasswordFile` allows relying on filesystem discretionary access control as another security boundary. ::: @@ -231,7 +231,7 @@ in example = [ ''/^tom\..*@domain\.com$/'' ]; default = [ ]; description = '' - Same as {option}`mailserver.loginAccounts..aliases` but + Same as {option}`mailserver.accounts..aliases` but using PCRE (Perl compatible regex). ''; }; @@ -248,7 +248,7 @@ in :::{warning} Does not allow sending from all addresses of these domains. - Use {option}`mailserver.loginAccounts..aliases` if that + Use {option}`mailserver.accounts..aliases` if that is required. ::: ''; @@ -295,7 +295,7 @@ in Emails sent to send-only accounts will be rejected with the reason configured in - {option}`mailserver.loginAccounts..sendOnlyRejectMessage`. + {option}`mailserver.accounts..sendOnlyRejectMessage`. ''; }; @@ -305,7 +305,7 @@ in description = '' The message returned to the sender for a send-only account. - See {option}`mailserver.loginAccounts..sendOnly`. + See {option}`mailserver.accounts..sendOnly`. ''; }; }; @@ -684,13 +684,13 @@ in aliases = mkOption { type = let - loginAccount = mkOptionType { + account = mkOptionType { name = "Login Account"; - check = account: builtins.elem account (builtins.attrNames cfg.loginAccounts); + check = account: builtins.elem account (builtins.attrNames cfg.accounts); }; in with types; - attrsOf (either loginAccount (nonEmptyListOf loginAccount)); + attrsOf (either account (nonEmptyListOf account)); example = { "postmaster@example.com" = "user1@example.com"; "abuse@example.com" = "user1@example.com"; @@ -1714,5 +1714,6 @@ in [ "mailserver" "ldap" "attributes" "mail" ] ) (mkRenamedOptionModule [ "mailserver" "extraVirtualAliases" ] [ "mailserver" "aliases" ]) + (mkRenamedOptionModule [ "mailserver" "loginAccounts" ] [ "mailserver" "accounts" ]) ]; } diff --git a/docs/faq.rst b/docs/faq.rst index ef306de..674ee0a 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -13,7 +13,7 @@ domain ``example.com`` and send mails with any address of this domain: .. code:: nix - mailserver.loginAccounts = { + mailserver.accounts = { "user@example.com" = { aliases = [ "@example.com" ]; }; diff --git a/docs/radicale.nix b/docs/radicale.nix index e740fb7..6ccecc7 100644 --- a/docs/radicale.nix +++ b/docs/radicale.nix @@ -12,7 +12,7 @@ let mapAttrsToList ; - mailAccounts = config.mailserver.loginAccounts; + mailAccounts = config.mailserver.accounts; htpasswd = pkgs.writeText "radicale.users" ( concatStrings (flip mapAttrsToList mailAccounts (mail: user: "${mail}+:${user.hashedPassword}\n")) ); diff --git a/docs/radicale.rst b/docs/radicale.rst index 244a41e..f594b8e 100644 --- a/docs/radicale.rst +++ b/docs/radicale.rst @@ -10,7 +10,7 @@ Limitations Radicale since the 3.x release (introduced in NixOS 20.09) does not support traditional crypt() password hashes any longer. To establish access for -existing :option:`mailserver.loginAccounts`, the hashing method used +existing :option:`mailserver.accounts`, the hashing method used for ``hashedPassword`` needs to be compatible with one of the available `htpasswd_encryption`_ methods. Such hashes can for example be created using diff --git a/docs/release-notes.rst b/docs/release-notes.rst index 9ee6ccc..e0c2bd8 100644 --- a/docs/release-notes.rst +++ b/docs/release-notes.rst @@ -21,7 +21,7 @@ NixOS 26.05 is an alternative to hashed passwords that integrates well with workflows established by `agenix`_/`sops-nix`_ that instead rely on encryption. This option prevents files from leaking in to the Nix store. - See :option:`mailserver.loginAccounts..passwordFile`. + See :option:`mailserver.accounts..passwordFile`. - LDAP setups require a migration of Dovecot home directories to `UUID based home directories`_. The exact UUID attribute can be customized through :option:`mailserver.ldap.attributes.uuid`. diff --git a/docs/setup-example.nix b/docs/setup-example.nix index aba25ed..66a8242 100644 --- a/docs/setup-example.nix +++ b/docs/setup-example.nix @@ -38,7 +38,7 @@ # A list of all login accounts. To create the password hashes, use # nix-shell -p mkpasswd --run 'mkpasswd -s' - loginAccounts = { + accounts = { "user1@example.com" = { # Reads the password hash from a file on the server hashedPasswordFile = "/a/file/containing/a/hashed/password"; diff --git a/mail-server/common.nix b/mail-server/common.nix index 3ca5c57..95f317b 100644 --- a/mail-server/common.nix +++ b/mail-server/common.nix @@ -51,12 +51,12 @@ rec { builtins.toString (mkHashFile name value.hashedPassword) else value.passwordFile - ) cfg.loginAccounts; + ) cfg.accounts; # Collect accounts with plain text passwords that require hashing - accountsWithPlaintextPasswordFiles = lib.filter ( - name: cfg.loginAccounts.${name}.passwordFile != null - ) (builtins.attrNames cfg.loginAccounts); + accountsWithPlaintextPasswordFiles = lib.filter (name: cfg.accounts.${name}.passwordFile != null) ( + builtins.attrNames cfg.accounts + ); # Appends the LDAP bind password to files to avoid writing this # password into the Nix store. diff --git a/mail-server/dovecot.nix b/mail-server/dovecot.nix index 9c89c4e..83c4859 100644 --- a/mail-server/dovecot.nix +++ b/mail-server/dovecot.nix @@ -115,7 +115,7 @@ let umask 077 for f in ${ - builtins.toString (lib.mapAttrsToList (name: _: passwordFiles."${name}") cfg.loginAccounts) + builtins.toString (lib.mapAttrsToList (name: _: passwordFiles."${name}") cfg.accounts) }; do if [ ! -f "$f" ]; then echo "Expected password hash file $f does not exist!" @@ -131,7 +131,7 @@ let "${name}:${"$(sed -n '1{p;p;q}' ${passwordFiles."${name}"} | ${lib.getExe' pkgs.dovecot "doveadm"} pw)"}::::::" else "${name}:${"$(head -n 1 ${passwordFiles."${name}"})"}::::::" - ) cfg.loginAccounts + ) cfg.accounts )} EOF @@ -141,7 +141,7 @@ let name: value: "${name}:::::::" + lib.optionalString (value.quota != null) "userdb_quota_rule=*:storage=${value.quota}" - ) cfg.loginAccounts + ) cfg.accounts )} EOF ''; diff --git a/mail-server/postfix.nix b/mail-server/postfix.nix index 70ae68e..52dc45a 100644 --- a/mail-server/postfix.nix +++ b/mail-server/postfix.nix @@ -51,7 +51,7 @@ let to = name; in map (from: { "${from}" = to; }) (value.aliases ++ lib.singleton name) - ) cfg.loginAccounts + ) cfg.accounts ) ); regex_valiases_postfix = mergeLookupTables ( @@ -62,7 +62,7 @@ let to = name; in map (from: { "${from}" = to; }) value.aliasesRegexp - ) cfg.loginAccounts + ) cfg.accounts ) ); @@ -75,7 +75,7 @@ let to = name; in map (from: { "@${from}" = to; }) value.catchAll - ) cfg.loginAccounts + ) cfg.accounts ) ); @@ -127,7 +127,7 @@ let # denied_recipients_postfix :: [ String ] denied_recipients_postfix = map (acct: "${acct.name} REJECT ${acct.sendOnlyRejectMessage}") ( - lib.filter (acct: acct.sendOnly) (lib.attrValues cfg.loginAccounts) + lib.filter (acct: acct.sendOnly) (lib.attrValues cfg.accounts) ); denied_recipients_file = builtins.toFile "denied_recipients" ( lib.concatStringsSep "\n" denied_recipients_postfix diff --git a/mail-server/users.nix b/mail-server/users.nix index 9863066..4c0f620 100644 --- a/mail-server/users.nix +++ b/mail-server/users.nix @@ -86,7 +86,7 @@ let rm "${sieveDirectory}/${name}/default.svbin" fi '' - ) (map (user: { inherit (user) name sieveScript; }) (lib.attrValues loginAccounts))} + ) (map (user: { inherit (user) name sieveScript; }) (lib.attrValues accounts))} ''; in { @@ -102,14 +102,14 @@ in ] ) == 1; message = "Login account ${acct.name} must provide exactly one of password file, hashed password, or hashed password file"; - }) (lib.attrValues loginAccounts); + }) (lib.attrValues accounts); # warn for accounts that specify both password and file warnings = map (acct: "${acct.name} specifies both a password hash and hash file; hash file will be used") ( lib.filter (acct: (acct.hashedPassword != null && acct.hashedPasswordFile != null)) ( - lib.attrValues loginAccounts + lib.attrValues accounts ) ); diff --git a/scripts/generate-options.py b/scripts/generate-options.py index c195504..f6ea83c 100644 --- a/scripts/generate-options.py +++ b/scripts/generate-options.py @@ -25,7 +25,7 @@ f = open(sys.argv[1]) options = json.load(f) groups = [ - "mailserver.loginAccounts", + "mailserver.accounts", "mailserver.x509", "mailserver.dkim", "mailserver.srs", diff --git a/tests/clamav.nix b/tests/clamav.nix index 900dd32..2600416 100644 --- a/tests/clamav.nix +++ b/tests/clamav.nix @@ -77,7 +77,7 @@ ]; virusScanning = true; - loginAccounts = { + accounts = { "user1@example.com" = { hashedPassword = "$6$/z4n8AQl6K$kiOkBTWlZfBd7PvF5GsJ8PmPgdZsFGN1jPGZufxxr60PoR0oUsrvzm2oQiflyz5ir9fFJ.d/zKm/NgLXNUsNX/"; aliases = [ "postmaster@example.com" ]; diff --git a/tests/external.nix b/tests/external.nix index a149144..e47013c 100644 --- a/tests/external.nix +++ b/tests/external.nix @@ -66,7 +66,7 @@ }; dmarcReporting.enable = true; - loginAccounts = { + accounts = { "user1@example.com" = { hashedPassword = "$6$/z4n8AQl6K$kiOkBTWlZfBd7PvF5GsJ8PmPgdZsFGN1jPGZufxxr60PoR0oUsrvzm2oQiflyz5ir9fFJ.d/zKm/NgLXNUsNX/"; aliases = [ "postmaster@example.com" ]; diff --git a/tests/internal.nix b/tests/internal.nix index a3cbfb8..15ada06 100644 --- a/tests/internal.nix +++ b/tests/internal.nix @@ -87,7 +87,7 @@ in ]; localDnsResolver = false; - loginAccounts = { + accounts = { "user1@example.com" = { hashedPasswordFile = hashedPasswordFile; }; diff --git a/tests/ldap.nix b/tests/ldap.nix index 2999bd8..fd9711f 100644 --- a/tests/ldap.nix +++ b/tests/ldap.nix @@ -133,7 +133,7 @@ in "frank@example.com" = "mallory@example.com"; }; - loginAccounts = { + accounts = { # Colliding local account takes precedence over LDAP account with # same address. "carol@example.com" = { diff --git a/tests/multiple.nix b/tests/multiple.nix index 3f9b5db..d627edd 100644 --- a/tests/multiple.nix +++ b/tests/multiple.nix @@ -35,7 +35,7 @@ let fqdn = "mail.${domain}"; domains = [ domain ]; localDnsResolver = false; - loginAccounts = { + accounts = { "user@${domain}" = { hashedPasswordFile = hashPassword "password"; };