1 {pkgs, lib, config, ...}:
2 let inherit (builtins) baseNameOf readFile;
4 inherit (pkgs.lib) unlinesAttrs;
5 inherit (config.services) openldap;
6 inherit (config.users) ldap;
7 copyFile = file: pkgs.writeText (baseNameOf file) (readFile file);
8 configLDIF = pkgs.writeText "cn=config.ldif" (''
10 objectClass: olcGlobal
11 #olcPidFile: /run/slapd/slapd.pid
12 # List of arguments that were passed to the server
13 #olcArgsFile: /run/slapd/slapd.args
14 # Read slapd-config(5) for possible values
16 # The tool-threads parameter sets the actual amount of CPU's
17 # that is used for indexing.
20 dn: olcDatabase={-1}frontend,cn=config
21 objectClass: olcDatabaseConfig
22 objectClass: olcFrontendConfig
23 # The maximum number of entries that is returned for a search operation
25 # Allow unlimited access to local connection from the local root user
27 by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage
29 # Allow unauthenticated read access for schema and base DN autodiscovery
30 olcAccess: to dn.exact=""
32 olcAccess: to dn.base="cn=Subschema"
35 dn: olcDatabase=config,cn=config
36 objectClass: olcDatabaseConfig
37 olcRootDN: cn=admin,cn=config
38 # Access to cn=config, system root can be manager
39 # with SASL mechanism (-Y EXTERNAL) over unix socket (-H ldapi://)
41 by dn.exact="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage
44 dn: cn=schema,cn=config
45 objectClass: olcSchemaConfig
47 include: file://${pkgs.openldap}/etc/schema/core.ldif
48 include: file://${pkgs.openldap}/etc/schema/cosine.ldif
49 include: file://${pkgs.openldap}/etc/schema/nis.ldif
50 include: file://${pkgs.openldap}/etc/schema/inetorgperson.ldif
51 include: file://${copyFile openldap/schema/postfix-book.ldif}
53 dn: cn=module{0},cn=config
54 objectClass: olcModuleList
55 # Where the dynamically loaded modules are stored
56 #olcModulePath: /usr/lib/ldap
57 olcModuleLoad: back_mdb
59 '' + unlinesAttrs (olcSuffix: {conf, olcDbDirectory, ...}:
60 "include: file://" + pkgs.writeText "config.ldif" (conf + ''
61 olcSuffix: ${olcSuffix}
62 olcDbDirectory: ${olcDbDirectory}
64 ) openldap.databases);
68 openldap/commonsoft.nix
71 services.openldap.domainSuffix = lib.mkOption {
73 default = "dc=${lib.concatStringsSep ",dc=" (lib.splitString "." config.networking.domain)}";
75 LDAP suffix for config.networking.domain.
78 services.openldap.databases = lib.mkOption {
80 type = types.attrsOf (types.submodule ({name, options, config, ...}: {
84 description = "The database's config in LDIF.";
88 description = "The database's data in LDIF.";
90 olcDbDirectory = lib.mkOption {
92 description = "The directory where the database is stored.";
93 default = "${openldap.dataDir}/${name}";
95 resetData = lib.mkOption {
97 description = "Whether to reset the data at each start of the slapd service.";
107 server = "ldapi:///";
108 base = "ou=posix,${openldap.domainSuffix}";
110 #distinguishedName = "cn=admin,${openldap.domainSuffix}";
116 # NOTE: nslcd cannot use SASL to bind to rootpwmoddn
117 # which is the DN used by nslcd when passwd is run by root
118 # to change the userPassword of an LDAP user.
119 # SEE: https://www.reddit.com/r/linuxadmin/comments/53sxpl/how_do_i_configure_nslcd_to_use_a_sasl_external/d7w9awd/
120 # Thus, use: ldappasswd -H ldapi:// -Y EXTERNAL uid=$SomeUID,ou=accounts,ou=posix,dc=commonsoft,dc=org
124 services.openldap = {
126 dataDir = "/var/db/ldap";
127 configDir = "/var/db/slapd";
128 urlList = [ "ldapi:///" ]; # UNIX socket
130 systemd.services.openldap = {
132 # NOTE: slapd's config is always re-initialized.
133 rm -rf "${openldap.configDir}"/cn=config \
134 "${openldap.configDir}"/cn=config.ldif
135 install -D -d -m 0700 -o "${openldap.user}" -g "${openldap.group}" "${openldap.configDir}"
136 # NOTE: olcDbDirectory must be created before adding the config.
138 unlinesAttrs (olcSuffix: {data, olcDbDirectory, resetData, ...}:
139 lib.optionalString resetData ''
140 rm -rf "${olcDbDirectory}"
142 install -D -d -m 0700 -o "${openldap.user}" -g "${openldap.group}" "${olcDbDirectory}"
143 '') openldap.databases
145 # NOTE: slapd is supposed to be stopped while in preStart,
146 # hence slap* commands can safely be used.
148 ${pkgs.openldap}/bin/slapadd -n 0 \
149 -F "${openldap.configDir}" \
151 chown -R "${openldap.user}:${openldap.group}" "${openldap.configDir}"
152 # NOTE: slapadd(8): To populate the config database slapd-config(5),
153 # use -n 0 as it is always the first database.
154 # It must physically exist on the filesystem prior to this, however.
156 unlinesAttrs (olcSuffix: {data, olcDbDirectory, resetData, ...}:
157 lib.optionalString resetData ''
158 ${pkgs.openldap}/bin/slapadd \
159 -F "${openldap.configDir}" \
160 -l ${pkgs.writeText "data.ldif" data}
162 test ! -e "${olcDbDirectory}" ||
163 chown -R "${openldap.user}:${openldap.group}" "${olcDbDirectory}"
164 '') openldap.databases;