summaryrefslogtreecommitdiff
path: root/env/users/mailbox.nix
blob: 06e67efec8f32ecdda9e62feba9260917951bd6e (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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
{ 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} nopassword userdb_user=${canonical}
              '';

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

              localMailboxes = 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}}

              # FIXME: Esta cadena de passdbs hace que 'doveadm user lookup'
              # falle para usuarios locales, pero todo lo demás sirve. Parece
              # ser debido a que pam no puede enumerar.

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

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

                # Esta es una forma de determinar si se encontró el usuario en
                # el passwd-file por medio de nopassword sin realmente
                # autenticarlo. Cuidado con result_success, porque si eso se
                # configura mal se permite inicio de sesión con cualquier
                # contraseña (!!!).
                result_success = continue
                result_failure = return-fail
                result_internalfail = return-fail

                username_filter = !*@*
              }

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

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

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

                result_success = continue-ok
                result_internalfail = return-fail
                skip = found
              }

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

      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;
    };
}