summaryrefslogtreecommitdiff
path: root/env/users/mailbox.nix
blob: 46bbd6ae66c9cd873edc19dac25885eea9cb7af2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
{ config, lib, pkgs, ... }:
with lib; let
  cfg = config.local;
in
{
  options.local.mailHost.enable = mkEnableOption "mailbox host service";

  config =
    let
      imapHostname = cfg.domains.imap.main;
    in
    mkIf cfg.mailHost.enable {
      services.dovecot2 =
        let
          cert = config.security.acme.certs.${imapHostname}.directory;
        in
        {
          enable = true;
          enablePAM = false;
          enableLmtp = true;

          #sslServerKey = "${cert}/key.pem";
          #sslServerCert = "${cert}/fullchain.pem";

          mailUser = "vmail";
          mailGroup = "vmail";
          mailLocation = "maildir:~/mail";

          extraConfig =
            let
              inherit (config.networking) domain;

              # https://dovecot.org/list/dovecot/2019-March/115250.html
              # Otra solución posible (https://serverfault.com/a/1062274/980378):
              #  auth_username_format = %{if;%d;eq;${domain};%Ln;%Lu}
              localEntry = canonical: username: ''
                ${username}:::::::user=${canonical} userdb_user=${canonical}
              '';

              localEntries = concatStrings
                (flatten (mapAttrsToList
                  (canonical: user:
                    map (localEntry canonical) user.hardAliases)
                  cfg.users));

              localAliases = pkgs.writeText "local-mailboxes" localEntries;

              vmailPath = "/var/lib/vmail/%{if;%d;ne;;%Ld;${domain}}";
            in
            ''
              # Esto enfuerza user@domain.tld
              auth_username_format = %{if;%Ld;eq;${domain};%Ln;%{if;%d;ne;;%Lu;%Ln@invalid}}

              passdb {
                driver = passwd-file
                args = ${localAliases}

                result_internalfail = return-fail
              }

              passdb {
                driver = passwd-file
                args = username_format=%Ln ${vmailPath}/passwd
              }

              passdb {
                driver = pam
                args = dovecot2
                username_filter = !*@*.*
                #TODO: algo como 'override_fields = allow_nets=...'
              }

              userdb {
                driver = passwd-file
                args = ${localAliases}

                result_success = continue
                result_internalfail = return-fail
              }

              userdb {
                driver = passwd-file
                args = username_format=%Ln ${vmailPath}/passwd
                override_fields = uid=vmail gid=vmail home=${vmailPath}/home/%Ln
              }

              userdb {
                driver = passwd
                args = blocking=no
                skip = found
              }
            '';
        };

      security = {
        # Necesario debido a 'enablePAM = false'
        pam.services.dovecot2 = { };

        #acme.certs.${imapHostname} = {
        #  inherit (config.services.dovecot2) group;
        #};
      };

      users = {
        users.${config.services.dovecot2.mailUser}.uid = 995;
        groups.${config.services.dovecot2.mailGroup}.gid = 993;
      };

      #networking.firewall.allowedTCPPorts = [ 143 993 ];

      #local.certs.imap.enable = true;
    };
}