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.
This commit is contained in:
+10
-9
@@ -136,7 +136,7 @@ in
|
|||||||
description = "Message size limit enforced by Postfix.";
|
description = "Message size limit enforced by Postfix.";
|
||||||
};
|
};
|
||||||
|
|
||||||
loginAccounts = mkOption {
|
accounts = mkOption {
|
||||||
type = types.attrsOf (
|
type = types.attrsOf (
|
||||||
types.submodule (
|
types.submodule (
|
||||||
{ name, ... }:
|
{ name, ... }:
|
||||||
@@ -170,7 +170,7 @@ in
|
|||||||
storing hashed secrets in the world-readable Nix store.
|
storing hashed secrets in the world-readable Nix store.
|
||||||
|
|
||||||
Passing the hash through
|
Passing the hash through
|
||||||
{option}`mailserver.loginAccounts.<name>.hashedPasswordFile`
|
{option}`mailserver.accounts.<name>.hashedPasswordFile`
|
||||||
allows relying on filesystem discretionary access control as
|
allows relying on filesystem discretionary access control as
|
||||||
another security boundary.
|
another security boundary.
|
||||||
:::
|
:::
|
||||||
@@ -231,7 +231,7 @@ in
|
|||||||
example = [ ''/^tom\..*@domain\.com$/'' ];
|
example = [ ''/^tom\..*@domain\.com$/'' ];
|
||||||
default = [ ];
|
default = [ ];
|
||||||
description = ''
|
description = ''
|
||||||
Same as {option}`mailserver.loginAccounts.<name>.aliases` but
|
Same as {option}`mailserver.accounts.<name>.aliases` but
|
||||||
using PCRE (Perl compatible regex).
|
using PCRE (Perl compatible regex).
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
@@ -248,7 +248,7 @@ in
|
|||||||
|
|
||||||
:::{warning}
|
:::{warning}
|
||||||
Does not allow sending from all addresses of these domains.
|
Does not allow sending from all addresses of these domains.
|
||||||
Use {option}`mailserver.loginAccounts.<name>.aliases` if that
|
Use {option}`mailserver.accounts.<name>.aliases` if that
|
||||||
is required.
|
is required.
|
||||||
:::
|
:::
|
||||||
'';
|
'';
|
||||||
@@ -295,7 +295,7 @@ in
|
|||||||
|
|
||||||
Emails sent to send-only accounts will
|
Emails sent to send-only accounts will
|
||||||
be rejected with the reason configured in
|
be rejected with the reason configured in
|
||||||
{option}`mailserver.loginAccounts.<name>.sendOnlyRejectMessage`.
|
{option}`mailserver.accounts.<name>.sendOnlyRejectMessage`.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -305,7 +305,7 @@ in
|
|||||||
description = ''
|
description = ''
|
||||||
The message returned to the sender for a send-only account.
|
The message returned to the sender for a send-only account.
|
||||||
|
|
||||||
See {option}`mailserver.loginAccounts.<name>.sendOnly`.
|
See {option}`mailserver.accounts.<name>.sendOnly`.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -684,13 +684,13 @@ in
|
|||||||
aliases = mkOption {
|
aliases = mkOption {
|
||||||
type =
|
type =
|
||||||
let
|
let
|
||||||
loginAccount = mkOptionType {
|
account = mkOptionType {
|
||||||
name = "Login Account";
|
name = "Login Account";
|
||||||
check = account: builtins.elem account (builtins.attrNames cfg.loginAccounts);
|
check = account: builtins.elem account (builtins.attrNames cfg.accounts);
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
with types;
|
with types;
|
||||||
attrsOf (either loginAccount (nonEmptyListOf loginAccount));
|
attrsOf (either account (nonEmptyListOf account));
|
||||||
example = {
|
example = {
|
||||||
"postmaster@example.com" = "user1@example.com";
|
"postmaster@example.com" = "user1@example.com";
|
||||||
"abuse@example.com" = "user1@example.com";
|
"abuse@example.com" = "user1@example.com";
|
||||||
@@ -1714,5 +1714,6 @@ in
|
|||||||
[ "mailserver" "ldap" "attributes" "mail" ]
|
[ "mailserver" "ldap" "attributes" "mail" ]
|
||||||
)
|
)
|
||||||
(mkRenamedOptionModule [ "mailserver" "extraVirtualAliases" ] [ "mailserver" "aliases" ])
|
(mkRenamedOptionModule [ "mailserver" "extraVirtualAliases" ] [ "mailserver" "aliases" ])
|
||||||
|
(mkRenamedOptionModule [ "mailserver" "loginAccounts" ] [ "mailserver" "accounts" ])
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -13,7 +13,7 @@ domain ``example.com`` and send mails with any address of this domain:
|
|||||||
|
|
||||||
.. code:: nix
|
.. code:: nix
|
||||||
|
|
||||||
mailserver.loginAccounts = {
|
mailserver.accounts = {
|
||||||
"user@example.com" = {
|
"user@example.com" = {
|
||||||
aliases = [ "@example.com" ];
|
aliases = [ "@example.com" ];
|
||||||
};
|
};
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ let
|
|||||||
mapAttrsToList
|
mapAttrsToList
|
||||||
;
|
;
|
||||||
|
|
||||||
mailAccounts = config.mailserver.loginAccounts;
|
mailAccounts = config.mailserver.accounts;
|
||||||
htpasswd = pkgs.writeText "radicale.users" (
|
htpasswd = pkgs.writeText "radicale.users" (
|
||||||
concatStrings (flip mapAttrsToList mailAccounts (mail: user: "${mail}+:${user.hashedPassword}\n"))
|
concatStrings (flip mapAttrsToList mailAccounts (mail: user: "${mail}+:${user.hashedPassword}\n"))
|
||||||
);
|
);
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@ Limitations
|
|||||||
|
|
||||||
Radicale since the 3.x release (introduced in NixOS 20.09) does not support
|
Radicale since the 3.x release (introduced in NixOS 20.09) does not support
|
||||||
traditional crypt() password hashes any longer. To establish access for
|
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
|
for ``hashedPassword`` needs to be compatible with one of the available
|
||||||
`htpasswd_encryption`_ methods. Such hashes can for example be created using
|
`htpasswd_encryption`_ methods. Such hashes can for example be created using
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ NixOS 26.05
|
|||||||
is an alternative to hashed passwords that integrates well with workflows
|
is an alternative to hashed passwords that integrates well with workflows
|
||||||
established by `agenix`_/`sops-nix`_ that instead rely on encryption. This
|
established by `agenix`_/`sops-nix`_ that instead rely on encryption. This
|
||||||
option prevents files from leaking in to the Nix store.
|
option prevents files from leaking in to the Nix store.
|
||||||
See :option:`mailserver.loginAccounts.<name>.passwordFile`.
|
See :option:`mailserver.accounts.<name>.passwordFile`.
|
||||||
- LDAP setups require a migration of Dovecot home directories to
|
- LDAP setups require a migration of Dovecot home directories to
|
||||||
`UUID based home directories`_. The exact UUID attribute can be customized
|
`UUID based home directories`_. The exact UUID attribute can be customized
|
||||||
through :option:`mailserver.ldap.attributes.uuid`.
|
through :option:`mailserver.ldap.attributes.uuid`.
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
|
|
||||||
# A list of all login accounts. To create the password hashes, use
|
# A list of all login accounts. To create the password hashes, use
|
||||||
# nix-shell -p mkpasswd --run 'mkpasswd -s'
|
# nix-shell -p mkpasswd --run 'mkpasswd -s'
|
||||||
loginAccounts = {
|
accounts = {
|
||||||
"user1@example.com" = {
|
"user1@example.com" = {
|
||||||
# Reads the password hash from a file on the server
|
# Reads the password hash from a file on the server
|
||||||
hashedPasswordFile = "/a/file/containing/a/hashed/password";
|
hashedPasswordFile = "/a/file/containing/a/hashed/password";
|
||||||
|
|||||||
@@ -51,12 +51,12 @@ rec {
|
|||||||
builtins.toString (mkHashFile name value.hashedPassword)
|
builtins.toString (mkHashFile name value.hashedPassword)
|
||||||
else
|
else
|
||||||
value.passwordFile
|
value.passwordFile
|
||||||
) cfg.loginAccounts;
|
) cfg.accounts;
|
||||||
|
|
||||||
# Collect accounts with plain text passwords that require hashing
|
# Collect accounts with plain text passwords that require hashing
|
||||||
accountsWithPlaintextPasswordFiles = lib.filter (
|
accountsWithPlaintextPasswordFiles = lib.filter (name: cfg.accounts.${name}.passwordFile != null) (
|
||||||
name: cfg.loginAccounts.${name}.passwordFile != null
|
builtins.attrNames cfg.accounts
|
||||||
) (builtins.attrNames cfg.loginAccounts);
|
);
|
||||||
|
|
||||||
# Appends the LDAP bind password to files to avoid writing this
|
# Appends the LDAP bind password to files to avoid writing this
|
||||||
# password into the Nix store.
|
# password into the Nix store.
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ let
|
|||||||
umask 077
|
umask 077
|
||||||
|
|
||||||
for f in ${
|
for f in ${
|
||||||
builtins.toString (lib.mapAttrsToList (name: _: passwordFiles."${name}") cfg.loginAccounts)
|
builtins.toString (lib.mapAttrsToList (name: _: passwordFiles."${name}") cfg.accounts)
|
||||||
}; do
|
}; do
|
||||||
if [ ! -f "$f" ]; then
|
if [ ! -f "$f" ]; then
|
||||||
echo "Expected password hash file $f does not exist!"
|
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)"}::::::"
|
"${name}:${"$(sed -n '1{p;p;q}' ${passwordFiles."${name}"} | ${lib.getExe' pkgs.dovecot "doveadm"} pw)"}::::::"
|
||||||
else
|
else
|
||||||
"${name}:${"$(head -n 1 ${passwordFiles."${name}"})"}::::::"
|
"${name}:${"$(head -n 1 ${passwordFiles."${name}"})"}::::::"
|
||||||
) cfg.loginAccounts
|
) cfg.accounts
|
||||||
)}
|
)}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ let
|
|||||||
name: value:
|
name: value:
|
||||||
"${name}:::::::"
|
"${name}:::::::"
|
||||||
+ lib.optionalString (value.quota != null) "userdb_quota_rule=*:storage=${value.quota}"
|
+ lib.optionalString (value.quota != null) "userdb_quota_rule=*:storage=${value.quota}"
|
||||||
) cfg.loginAccounts
|
) cfg.accounts
|
||||||
)}
|
)}
|
||||||
EOF
|
EOF
|
||||||
'';
|
'';
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ let
|
|||||||
to = name;
|
to = name;
|
||||||
in
|
in
|
||||||
map (from: { "${from}" = to; }) (value.aliases ++ lib.singleton name)
|
map (from: { "${from}" = to; }) (value.aliases ++ lib.singleton name)
|
||||||
) cfg.loginAccounts
|
) cfg.accounts
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
regex_valiases_postfix = mergeLookupTables (
|
regex_valiases_postfix = mergeLookupTables (
|
||||||
@@ -62,7 +62,7 @@ let
|
|||||||
to = name;
|
to = name;
|
||||||
in
|
in
|
||||||
map (from: { "${from}" = to; }) value.aliasesRegexp
|
map (from: { "${from}" = to; }) value.aliasesRegexp
|
||||||
) cfg.loginAccounts
|
) cfg.accounts
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ let
|
|||||||
to = name;
|
to = name;
|
||||||
in
|
in
|
||||||
map (from: { "@${from}" = to; }) value.catchAll
|
map (from: { "@${from}" = to; }) value.catchAll
|
||||||
) cfg.loginAccounts
|
) cfg.accounts
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -127,7 +127,7 @@ let
|
|||||||
|
|
||||||
# denied_recipients_postfix :: [ String ]
|
# denied_recipients_postfix :: [ String ]
|
||||||
denied_recipients_postfix = map (acct: "${acct.name} REJECT ${acct.sendOnlyRejectMessage}") (
|
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" (
|
denied_recipients_file = builtins.toFile "denied_recipients" (
|
||||||
lib.concatStringsSep "\n" denied_recipients_postfix
|
lib.concatStringsSep "\n" denied_recipients_postfix
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ let
|
|||||||
rm "${sieveDirectory}/${name}/default.svbin"
|
rm "${sieveDirectory}/${name}/default.svbin"
|
||||||
fi
|
fi
|
||||||
''
|
''
|
||||||
) (map (user: { inherit (user) name sieveScript; }) (lib.attrValues loginAccounts))}
|
) (map (user: { inherit (user) name sieveScript; }) (lib.attrValues accounts))}
|
||||||
'';
|
'';
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
@@ -102,14 +102,14 @@ in
|
|||||||
]
|
]
|
||||||
) == 1;
|
) == 1;
|
||||||
message = "Login account ${acct.name} must provide exactly one of password file, hashed password, or hashed password file";
|
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
|
# warn for accounts that specify both password and file
|
||||||
warnings =
|
warnings =
|
||||||
map (acct: "${acct.name} specifies both a password hash and hash file; hash file will be used")
|
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.filter (acct: (acct.hashedPassword != null && acct.hashedPasswordFile != null)) (
|
||||||
lib.attrValues loginAccounts
|
lib.attrValues accounts
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ f = open(sys.argv[1])
|
|||||||
options = json.load(f)
|
options = json.load(f)
|
||||||
|
|
||||||
groups = [
|
groups = [
|
||||||
"mailserver.loginAccounts",
|
"mailserver.accounts",
|
||||||
"mailserver.x509",
|
"mailserver.x509",
|
||||||
"mailserver.dkim",
|
"mailserver.dkim",
|
||||||
"mailserver.srs",
|
"mailserver.srs",
|
||||||
|
|||||||
+1
-1
@@ -77,7 +77,7 @@
|
|||||||
];
|
];
|
||||||
virusScanning = true;
|
virusScanning = true;
|
||||||
|
|
||||||
loginAccounts = {
|
accounts = {
|
||||||
"user1@example.com" = {
|
"user1@example.com" = {
|
||||||
hashedPassword = "$6$/z4n8AQl6K$kiOkBTWlZfBd7PvF5GsJ8PmPgdZsFGN1jPGZufxxr60PoR0oUsrvzm2oQiflyz5ir9fFJ.d/zKm/NgLXNUsNX/";
|
hashedPassword = "$6$/z4n8AQl6K$kiOkBTWlZfBd7PvF5GsJ8PmPgdZsFGN1jPGZufxxr60PoR0oUsrvzm2oQiflyz5ir9fFJ.d/zKm/NgLXNUsNX/";
|
||||||
aliases = [ "postmaster@example.com" ];
|
aliases = [ "postmaster@example.com" ];
|
||||||
|
|||||||
+1
-1
@@ -66,7 +66,7 @@
|
|||||||
};
|
};
|
||||||
dmarcReporting.enable = true;
|
dmarcReporting.enable = true;
|
||||||
|
|
||||||
loginAccounts = {
|
accounts = {
|
||||||
"user1@example.com" = {
|
"user1@example.com" = {
|
||||||
hashedPassword = "$6$/z4n8AQl6K$kiOkBTWlZfBd7PvF5GsJ8PmPgdZsFGN1jPGZufxxr60PoR0oUsrvzm2oQiflyz5ir9fFJ.d/zKm/NgLXNUsNX/";
|
hashedPassword = "$6$/z4n8AQl6K$kiOkBTWlZfBd7PvF5GsJ8PmPgdZsFGN1jPGZufxxr60PoR0oUsrvzm2oQiflyz5ir9fFJ.d/zKm/NgLXNUsNX/";
|
||||||
aliases = [ "postmaster@example.com" ];
|
aliases = [ "postmaster@example.com" ];
|
||||||
|
|||||||
+1
-1
@@ -87,7 +87,7 @@ in
|
|||||||
];
|
];
|
||||||
localDnsResolver = false;
|
localDnsResolver = false;
|
||||||
|
|
||||||
loginAccounts = {
|
accounts = {
|
||||||
"user1@example.com" = {
|
"user1@example.com" = {
|
||||||
hashedPasswordFile = hashedPasswordFile;
|
hashedPasswordFile = hashedPasswordFile;
|
||||||
};
|
};
|
||||||
|
|||||||
+1
-1
@@ -133,7 +133,7 @@ in
|
|||||||
"frank@example.com" = "mallory@example.com";
|
"frank@example.com" = "mallory@example.com";
|
||||||
};
|
};
|
||||||
|
|
||||||
loginAccounts = {
|
accounts = {
|
||||||
# Colliding local account takes precedence over LDAP account with
|
# Colliding local account takes precedence over LDAP account with
|
||||||
# same address.
|
# same address.
|
||||||
"carol@example.com" = {
|
"carol@example.com" = {
|
||||||
|
|||||||
+1
-1
@@ -35,7 +35,7 @@ let
|
|||||||
fqdn = "mail.${domain}";
|
fqdn = "mail.${domain}";
|
||||||
domains = [ domain ];
|
domains = [ domain ];
|
||||||
localDnsResolver = false;
|
localDnsResolver = false;
|
||||||
loginAccounts = {
|
accounts = {
|
||||||
"user@${domain}" = {
|
"user@${domain}" = {
|
||||||
hashedPasswordFile = hashPassword "password";
|
hashedPasswordFile = hashPassword "password";
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user