1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 cfg = config.services.openldap;
8 openldap = pkgs.openldap;
9
10 dataFile = pkgs.writeText "ldap-contents.ldif" cfg.declarativeContents;
11 configFile = pkgs.writeText "slapd.conf" cfg.extraConfig;
12 configOpts = if cfg.configDir == null then "-f ${configFile}"
13 else "-F ${cfg.configDir}";
14in
15
16{
17
18 ###### interface
19
20 options = {
21
22 services.openldap = {
23
24 enable = mkOption {
25 type = types.bool;
26 default = false;
27 description = "
28 Whether to enable the ldap server.
29 ";
30 };
31
32 user = mkOption {
33 type = types.string;
34 default = "openldap";
35 description = "User account under which slapd runs.";
36 };
37
38 group = mkOption {
39 type = types.string;
40 default = "openldap";
41 description = "Group account under which slapd runs.";
42 };
43
44 urlList = mkOption {
45 type = types.listOf types.string;
46 default = [ "ldap:///" ];
47 description = "URL list slapd should listen on.";
48 example = [ "ldaps:///" ];
49 };
50
51 dataDir = mkOption {
52 type = types.string;
53 default = "/var/db/openldap";
54 description = "The database directory.";
55 };
56
57 configDir = mkOption {
58 type = types.nullOr types.path;
59 default = null;
60 description = "Use this optional config directory instead of using slapd.conf";
61 example = "/var/db/slapd.d";
62 };
63
64 extraConfig = mkOption {
65 type = types.lines;
66 default = "";
67 description = "
68 slapd.conf configuration
69 ";
70 example = literalExample ''
71 '''
72 include ${pkgs.openldap.out}/etc/schema/core.schema
73 include ${pkgs.openldap.out}/etc/schema/cosine.schema
74 include ${pkgs.openldap.out}/etc/schema/inetorgperson.schema
75 include ${pkgs.openldap.out}/etc/schema/nis.schema
76
77 database bdb
78 suffix dc=example,dc=org
79 rootdn cn=admin,dc=example,dc=org
80 # NOTE: change after first start
81 rootpw secret
82 directory /var/db/openldap
83 '''
84 '';
85 };
86
87 declarativeContents = mkOption {
88 type = with types; nullOr lines;
89 default = null;
90 description = ''
91 Declarative contents for the LDAP database, in LDIF format.
92
93 Note a few facts when using it. First, the database
94 <emphasis>must</emphasis> be stored in the directory defined by
95 <code>dataDir</code>. Second, all <code>dataDir</code> will be erased
96 when starting the LDAP server. Third, modifications to the database
97 are not prevented, they are just dropped on the next reboot of the
98 server. Finally, performance-wise the database and indexes are rebuilt
99 on each server startup, so this will slow down server startup,
100 especially with large databases.
101 '';
102 example = ''
103 dn: dc=example,dc=org
104 objectClass: domain
105 dc: example
106
107 dn: ou=users,dc=example,dc=org
108 objectClass = organizationalUnit
109 ou: users
110
111 # ...
112 '';
113 };
114 };
115
116 };
117
118
119 ###### implementation
120
121 config = mkIf cfg.enable {
122
123 environment.systemPackages = [ openldap ];
124
125 systemd.services.openldap = {
126 description = "LDAP server";
127 wantedBy = [ "multi-user.target" ];
128 after = [ "network.target" ];
129 preStart = ''
130 mkdir -p /var/run/slapd
131 chown -R "${cfg.user}:${cfg.group}" /var/run/slapd
132 ${optionalString (cfg.declarativeContents != null) ''
133 rm -Rf "${cfg.dataDir}"
134 ''}
135 mkdir -p "${cfg.dataDir}"
136 ${optionalString (cfg.declarativeContents != null) ''
137 ${openldap.out}/bin/slapadd ${configOpts} -l ${dataFile}
138 ''}
139 chown -R "${cfg.user}:${cfg.group}" "${cfg.dataDir}"
140 '';
141 serviceConfig.ExecStart =
142 "${openldap.out}/libexec/slapd -d 0 " +
143 "-u '${cfg.user}' -g '${cfg.group}' " +
144 "-h '${concatStringsSep " " cfg.urlList}' " +
145 "${configOpts}";
146 };
147
148 users.users.openldap =
149 { name = cfg.user;
150 group = cfg.group;
151 uid = config.ids.uids.openldap;
152 };
153
154 users.groups.openldap =
155 { name = cfg.group;
156 gid = config.ids.gids.openldap;
157 };
158
159 };
160}