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       # FIXME: even with the correct LD_LIBRARY_PATH to libnss_ldap.so,
 
 108       #        passwd still does not work on LDAP accounts.
 
 115       server = "ldapi:///";
 
 116       base = "ou=posix,${openldap.domainSuffix}";
 
 118         #distinguishedName = "cn=admin,${openldap.domainSuffix}";
 
 121     services.openldap = {
 
 123       dataDir   = "/var/db/ldap";
 
 124       configDir = "/var/db/slapd";
 
 125       urlList   = [ "ldapi:///" ]; # UNIX socket
 
 127     systemd.services.openldap = {
 
 129           # NOTE: slapd's config is always re-initialized.
 
 130           rm -rf "${openldap.configDir}"/cn=config \
 
 131                  "${openldap.configDir}"/cn=config.ldif
 
 132           install -D -d -m 0700 -o "${openldap.user}" -g "${openldap.group}" "${openldap.configDir}"
 
 133           # NOTE: olcDbDirectory must be created before adding the config.
 
 135           unlinesAttrs (olcSuffix: {data, olcDbDirectory, resetData, ...}:
 
 136             lib.optionalString resetData ''
 
 137               rm -rf "${olcDbDirectory}"
 
 139             install -D -d -m 0700 -o "${openldap.user}" -g "${openldap.group}" "${olcDbDirectory}"
 
 140             '') openldap.databases
 
 142           # NOTE: slapd is supposed to be stopped while in preStart,
 
 143           #       hence slap* commands can safely be used.
 
 145           ${pkgs.openldap}/bin/slapadd -n 0 \
 
 146            -F "${openldap.configDir}" \
 
 148           chown -R "${openldap.user}:${openldap.group}" "${openldap.configDir}"
 
 149           # NOTE: slapadd(8): To populate the config database slapd-config(5),
 
 150           #                   use -n 0 as it is always the first database.
 
 151           #                   It must physically exist on the filesystem prior to this, however.
 
 153         unlinesAttrs (olcSuffix: {data, olcDbDirectory, resetData, ...}:
 
 154           lib.optionalString resetData ''
 
 155             ${pkgs.openldap}/bin/slapadd \
 
 156              -F "${openldap.configDir}" \
 
 157              -l ${pkgs.writeText "data.ldif" data}
 
 159           test ! -e "${olcDbDirectory}" ||
 
 160           chown -R "${openldap.user}:${openldap.group}" "${olcDbDirectory}"
 
 161         '') openldap.databases;