]> Git — Sourcephile - sourcephile-nix.git/blob - nixos/modules/services/mail/dovecot.nix
dovecot: fix INDEX corruption by INDEXPVT
[sourcephile-nix.git] / nixos / modules / services / mail / dovecot.nix
1 { pkgs, lib, config, ... }:
2 let
3 inherit (builtins) toString toFile attrNames;
4 inherit (lib) types;
5 inherit (pkgs.lib) unlinesAttrs unlinesValues unwords;
6 inherit (config.services) dovecot2 openldap;
7 inherit (config) networking;
8 stateDir = "/var/lib/dovecot";
9 mailDir = "${stateDir}/mail";
10 sieveDir = "${stateDir}/sieve";
11 authDir = "${stateDir}/auth";
12 escapeGroup = lib.stringAsChars (c: if "a"<=c && c<="z"
13 || "0"<=c && c<="9"
14 || c=="-"
15 then c else "_");
16 domainGroup = escapeGroup "${networking.domainBase}";
17 in
18 {
19 options.services.dovecot2 = {
20 domains = lib.mkOption {
21 default = {};
22 type = types.attrsOf (types.submodule ({domain, ...}: {
23 #config.domain = lib.mkDefault domain;
24 options = {
25 accounts = lib.mkOption {
26 type = types.attrsOf (types.submodule ({account, ...}: {
27 options = {
28 password = lib.mkOption {
29 type = types.str;
30 example = "{SSHA512}uyjL1KYx4z7HpfNvnKzuVxpMLD2KVueGGBvOcj7AF1EZCTVhT++IIKUVOC4xpZtWdqVD0OVmZqgYr2qpn/3t3Aj4oU0=";
31 description = ''Password.
32 Use: `doveadm pw -s SSHA512 -p "$password"`
33 '';
34 };
35 aliases = lib.mkOption {
36 type = with types; listOf types.str;
37 example = [ "abuse@${config.networking.domain}" ];
38 default = [];
39 description = ''Aliases of this account.'';
40 };
41 quota = lib.mkOption {
42 type = with types; nullOr types.str;
43 default = null;
44 example = "2G";
45 description = ''
46 Per user quota rules. Accepted sizes are `xx k/M/G/T` with the
47 obvious meaning. Leave blank for the standard quota `100G`.
48 '';
49 };
50 sieves = lib.mkOption {
51 type = with types; attrsOf str;
52 default = { main = ''
53 require ["include"];
54
55 #include :personal "roundcube";
56 include :global "spam";
57 include :global "list";
58 include :global "extension";
59 '';
60 };
61 };
62 groups = lib.mkOption {
63 type = with types; listOf str;
64 default = [];
65 };
66 };
67 }));
68 };
69 };
70 }));
71 };
72 sieves = {
73 global = lib.mkOption {
74 description = "global scripts.";
75 type = types.attrsOf types.str;
76 default = {};
77 };
78 before = lib.mkOption {
79 description = "before scripts.";
80 type = types.attrsOf types.str;
81 default = {};
82 };
83 after = lib.mkOption {
84 description = "after scripts.";
85 type = types.attrsOf types.str;
86 default = {};
87 };
88 };
89 };
90
91 config = lib.mkIf dovecot2.enable {
92 systemd.services.dovecot2 = {
93 preStart = unlinesValues {
94 installMailDir = ''
95 # SEE: http://wiki2.dovecot.org/SharedMailboxes/Permissions
96 install -D -d -m 0771 \
97 -o ${dovecot2.mailUser} \
98 -g ${dovecot2.mailGroup} \
99 ${mailDir}
100 '';
101
102 installSieve = ''
103 rm -rf "${sieveDir}"
104 install -D -d -m 0755 -o root -g root \
105 "${sieveDir}/bin"
106 '' + unlinesAttrs (dir: sieves: ''
107 install -D -d -m 0755 -o root -g root \
108 ${sieveDir} ${sieveDir}/${dir}.d
109 '' + unlinesAttrs (name: text: ''
110 src=${pkgs.writeText "${name}.sieve" text}
111 dst="${sieveDir}/${dir}.d/${name}.sieve"
112 ln -fns "$src" "$dst"
113 ${pkgs.dovecot_pigeonhole}/bin/sievec "$dst"
114 '') sieves
115 ) dovecot2.sieves;
116
117 installDomains =
118 lib.optionalString openldap.enable ''
119 # NOTE: make sure nslcd cache is in sync with the LDAP data
120 systemctl restart nslcd
121 '' + ''
122 install -D -d -m 1770 \
123 -o ${dovecot2.mailUser} \
124 -g ${domainGroup} \
125 ${mailDir}/${networking.domain} \
126 ${stateDir}/control/${networking.domain} \
127 ${stateDir}/index/${networking.domain}
128
129 # NOTE: do not set the sticky bit (+t)
130 # on acl/<domain>/, to let dovecot
131 # rename acl.db.lock (own by new user)
132 # to acl.db (own by old user)
133 install -D -d -m 0770 \
134 -o ${dovecot2.mailUser} \
135 -g ${domainGroup} \
136 ${stateDir}/acl/${networking.domain}
137
138 # NOTE: domainAliases point to the very same mailboxes as domain's.
139 for domainAlias in ${unwords networking.domainAliases}
140 do
141 ln -fns ${networking.domain} ${mailDir}/$domainAlias
142 ln -fns ${networking.domain} ${stateDir}/control/$domainAlias
143 ln -fns ${networking.domain} ${stateDir}/index/$domainAlias
144 ln -fns ${networking.domain} ${stateDir}/acl/$domainAlias
145 done
146 '';
147 };
148 };
149 };
150 }