quota: expose global quota settings
With the options in the upstream dovecot module gone the quota support and its option now live in our downstream module. The only behavior change this introduces is not setting a global per user default instead of the previous 100G per user. Diabling quota support and setting per user quotas now raises an assertion: ```` Failed assertions: - Without quota support enabled, per-user quotas cannot be applied to the following accounts: - lowquota@example.com Either remove per user quota settings or re-enable `mailserver.quota.enable`. ````
This commit is contained in:
+34
-2
@@ -137,6 +137,35 @@ in
|
|||||||
description = "Message size limit enforced by Postfix.";
|
description = "Message size limit enforced by Postfix.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
quota = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = ''
|
||||||
|
Whether to enable quota support.
|
||||||
|
|
||||||
|
When enabled, incoming mail can be rejected if a mailbox exceeds its
|
||||||
|
quota.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
defaults = {
|
||||||
|
perUser = mkOption {
|
||||||
|
type = with types; nullOr str;
|
||||||
|
default = null;
|
||||||
|
example = "10G";
|
||||||
|
description = ''
|
||||||
|
Default quota applied to all users.
|
||||||
|
|
||||||
|
The value must use a size format like `500M`, `2G`, `10G`.
|
||||||
|
|
||||||
|
If set to `null`, no default per user quota is applied and only
|
||||||
|
explicit per user quotas apply, if set.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
accounts = mkOption {
|
accounts = mkOption {
|
||||||
type = types.attrsOf (
|
type = types.attrsOf (
|
||||||
types.submodule (
|
types.submodule (
|
||||||
@@ -260,8 +289,11 @@ in
|
|||||||
default = null;
|
default = null;
|
||||||
example = "2G";
|
example = "2G";
|
||||||
description = ''
|
description = ''
|
||||||
Per user quota rules. Accepted sizes are `xx k/M/G/T` with the
|
The quota limit for this user.
|
||||||
obvious meaning. Leave blank for the standard quota `100G`.
|
|
||||||
|
The value is must use a size format like `500M`, `2G`, `10G`.
|
||||||
|
|
||||||
|
If unset, will fall back to {option}`mailserver.quota.defaults.perUser` if set.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+35
-11
@@ -33,6 +33,9 @@ with (import ./common.nix {
|
|||||||
|
|
||||||
let
|
let
|
||||||
inherit (lib)
|
inherit (lib)
|
||||||
|
attrNames
|
||||||
|
concatMapStringsSep
|
||||||
|
filterAttrs
|
||||||
mapAttrs'
|
mapAttrs'
|
||||||
mkForce
|
mkForce
|
||||||
mkIf
|
mkIf
|
||||||
@@ -170,6 +173,22 @@ in
|
|||||||
assertion = junkMailboxNumber == 1;
|
assertion = junkMailboxNumber == 1;
|
||||||
message = "nixos-mailserver requires exactly one dovecot mailbox with the 'special_use' flag set to '\\Junk' (${builtins.toString junkMailboxNumber} have been found)";
|
message = "nixos-mailserver requires exactly one dovecot mailbox with the 'special_use' flag set to '\\Junk' (${builtins.toString junkMailboxNumber} have been found)";
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
assertion =
|
||||||
|
let
|
||||||
|
usersWithQuota = attrNames (
|
||||||
|
filterAttrs (_: account: account.quota != null) config.mailserver.loginAccounts
|
||||||
|
);
|
||||||
|
in
|
||||||
|
!cfg.quota.enable -> usersWithQuota == { };
|
||||||
|
message = ''
|
||||||
|
Without quota support enabled, per-user quotas cannot be applied to the following accounts:
|
||||||
|
|
||||||
|
${concatMapStringsSep "\n" (account: "- ${account}") quotaUsers}
|
||||||
|
|
||||||
|
Either remove per user quota settings or re-enable `mailserver.quota.enable`.
|
||||||
|
'';
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
warnings =
|
warnings =
|
||||||
@@ -278,7 +297,7 @@ in
|
|||||||
};
|
};
|
||||||
vsz_limit = "${toString cfg.lmtpMemoryLimit} MB";
|
vsz_limit = "${toString cfg.lmtpMemoryLimit} MB";
|
||||||
};
|
};
|
||||||
"service quota-status" = {
|
"service quota-status" = mkIf cfg.quota.enable {
|
||||||
executable = toString [
|
executable = toString [
|
||||||
"${config.services.dovecot2.package}/libexec/dovecot/quota-status"
|
"${config.services.dovecot2.package}/libexec/dovecot/quota-status"
|
||||||
"-p"
|
"-p"
|
||||||
@@ -336,8 +355,10 @@ in
|
|||||||
mail_max_userip_connections = cfg.maxConnectionsPerUser;
|
mail_max_userip_connections = cfg.maxConnectionsPerUser;
|
||||||
mail_plugins = [
|
mail_plugins = [
|
||||||
"$mail_plugins"
|
"$mail_plugins"
|
||||||
"imap_quota"
|
|
||||||
"imap_sieve"
|
"imap_sieve"
|
||||||
|
]
|
||||||
|
++ lib.optionals cfg.quota.enable [
|
||||||
|
"imap_quota"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
"protocol pop3" = {
|
"protocol pop3" = {
|
||||||
@@ -347,6 +368,8 @@ in
|
|||||||
# globally enabled plugins
|
# globally enabled plugins
|
||||||
mail_plugins = [
|
mail_plugins = [
|
||||||
"$mail_plugins"
|
"$mail_plugins"
|
||||||
|
]
|
||||||
|
++ lib.optionals cfg.quota.enable [
|
||||||
"quota"
|
"quota"
|
||||||
]
|
]
|
||||||
++ lib.optionals cfg.fullTextSearch.enable [
|
++ lib.optionals cfg.fullTextSearch.enable [
|
||||||
@@ -437,14 +460,6 @@ in
|
|||||||
lmtp_save_to_detail_mailbox = cfg.lmtpSaveToDetailMailbox;
|
lmtp_save_to_detail_mailbox = cfg.lmtpSaveToDetailMailbox;
|
||||||
|
|
||||||
plugin = {
|
plugin = {
|
||||||
quota_rule = "*:storage=100G"; # TODO: quota option
|
|
||||||
quota = "count:User quota"; # per virtual mail user quota
|
|
||||||
quota_status_success = "DUNNO";
|
|
||||||
quota_status_nouser = "DUNNO";
|
|
||||||
quota_status_overquota = "552 5.2.2 Mailbox is full";
|
|
||||||
quota_grace = "10%%";
|
|
||||||
quota_vsizes = true;
|
|
||||||
|
|
||||||
sieve = "file:${cfg.sieveDirectory}/%{user}/scripts;active=${cfg.sieveDirectory}/%{user}/active.sieve";
|
sieve = "file:${cfg.sieveDirectory}/%{user}/scripts;active=${cfg.sieveDirectory}/%{user}/active.sieve";
|
||||||
sieve_default = "file:${cfg.sieveDirectory}/%{user}/default.sieve";
|
sieve_default = "file:${cfg.sieveDirectory}/%{user}/default.sieve";
|
||||||
sieve_default_name = "default";
|
sieve_default_name = "default";
|
||||||
@@ -465,7 +480,16 @@ in
|
|||||||
fts_enforced = cfg.fullTextSearch.enforced;
|
fts_enforced = cfg.fullTextSearch.enforced;
|
||||||
}
|
}
|
||||||
// (listToMultiAttrs "fts_autoindex_exclude" cfg.fullTextSearch.autoIndexExclude)
|
// (listToMultiAttrs "fts_autoindex_exclude" cfg.fullTextSearch.autoIndexExclude)
|
||||||
);
|
)
|
||||||
|
// lib.optionalAttrs cfg.quota.enable {
|
||||||
|
quota_rule = mkIf (cfg.quota.defaults.perUser != null) "*:storage=${cfg.quota.defaults.perUser}";
|
||||||
|
quota = "count:User quota"; # per virtual mail user quota
|
||||||
|
quota_status_success = "DUNNO";
|
||||||
|
quota_status_nouser = "DUNNO";
|
||||||
|
quota_status_overquota = "552 5.2.2 Mailbox is full";
|
||||||
|
quota_grace = "10%%";
|
||||||
|
quota_vsizes = true;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
// lib.optionalAttrs cfg.debug.dovecot {
|
// lib.optionalAttrs cfg.debug.dovecot {
|
||||||
mail_debug = true;
|
mail_debug = true;
|
||||||
|
|||||||
@@ -373,6 +373,8 @@ in
|
|||||||
# reject selected recipients
|
# reject selected recipients
|
||||||
"check_recipient_access ${mappedFile "denied_recipients"}"
|
"check_recipient_access ${mappedFile "denied_recipients"}"
|
||||||
"check_recipient_access ${mappedFile "reject_recipients"}"
|
"check_recipient_access ${mappedFile "reject_recipients"}"
|
||||||
|
]
|
||||||
|
++ lib.optionals cfg.quota.enable [
|
||||||
# quota checking
|
# quota checking
|
||||||
"check_policy_service unix:/run/dovecot2/quota-status"
|
"check_policy_service unix:/run/dovecot2/quota-status"
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ groups = [
|
|||||||
"mailserver.dmarcReporting",
|
"mailserver.dmarcReporting",
|
||||||
"mailserver.tlsrpt",
|
"mailserver.tlsrpt",
|
||||||
"mailserver.fullTextSearch",
|
"mailserver.fullTextSearch",
|
||||||
|
"mailserver.quota",
|
||||||
"mailserver.redis",
|
"mailserver.redis",
|
||||||
"mailserver.ldap",
|
"mailserver.ldap",
|
||||||
"mailserver.monitoring",
|
"mailserver.monitoring",
|
||||||
|
|||||||
Reference in New Issue
Block a user