--- /dev/null
+{pkgs, lib, config, ...}:
+let inherit (config.services) openldap;
+ inherit (config.users) ldap;
+ cnConfigLDIF = pkgs.writeText "cn=config.ldif" ''
+ dn: cn=config
+ cn: config
+ objectClass: olcGlobal
+ #olcPidFile: /run/slapd/slapd.pid
+ # List of arguments that were passed to the server
+ #olcArgsFile: /run/slapd/slapd.args
+ # Read slapd-config(5) for possible values
+ olcLogLevel: none
+ # The tool-threads parameter sets the actual amount of cpu's that is used
+ # for indexing.
+ olcToolThreads: 1
+
+ dn: olcDatabase={-1}frontend,cn=config
+ olcDatabase: {-1}frontend
+ objectClass: olcDatabaseConfig
+ objectClass: olcFrontendConfig
+ # The maximum number of entries that is returned for a search operation
+ olcSizeLimit: 500
+ # Allow unlimited access to local connection from the local root user
+ olcAccess: to *
+ by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage
+ by * break
+ # Allow unauthenticated read access for schema and base DN autodiscovery
+ olcAccess: to dn.exact=""
+ by * read
+ olcAccess: to dn.base="cn=Subschema"
+ by * read
+
+ dn: olcDatabase=config,cn=config
+ olcDatabase: config
+ objectClass: olcDatabaseConfig
+ olcRootDN: cn=admin,cn=config
+ # Access to cn=config, system root can be manager
+ # with SASL mechanism (-Y EXTERNAL) over unix socket (-H ldapi://)
+ olcAccess: to *
+ by dn.exact="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage
+ by * break
+
+ dn: cn=schema,cn=config
+ cn: schema
+ objectClass: olcSchemaConfig
+
+ include: file://${pkgs.openldap}/etc/schema/core.ldif
+ include: file://${pkgs.openldap}/etc/schema/cosine.ldif
+ include: file://${pkgs.openldap}/etc/schema/nis.ldif
+ include: file://${pkgs.openldap}/etc/schema/inetorgperson.ldif
+
+ dn: cn=module{0},cn=config
+ cn: module{0}
+ objectClass: olcModuleList
+ # Where the dynamically loaded modules are stored
+ #olcModulePath: /usr/lib/ldap
+ olcModuleLoad: back_mdb
+
+ dn: olcBackend={1}mdb,cn=config
+ olcBackend: {1}mdb
+ objectClass: olcBackendConfig
+
+ include: file://${mdb1Config}
+ '';
+ mdb1Suffix = "dc=${config.networking.baseName}";
+ mdb1Config = pkgs.writeText "${mdb1Suffix}.config.ldif" ''
+ # sudo ldapsearch -LLL -D cn=admin,cn=config -Y EXTERNAL -b 'olcDatabase={1}mdb,cn=config' -s sub
+ dn: olcDatabase={1}mdb,cn=config
+ olcDatabase: {1}mdb
+ objectClass: olcDatabaseConfig
+ objectClass: olcMdbConfig
+ # Checkpoint the database periodically in case of system
+ # failure and to speed slapd shutdown.
+ olcDbCheckpoint: 512 30
+ # Database max size is 1G
+ olcDbMaxSize: 1073741824
+ olcLastMod: TRUE
+ olcSuffix: ${mdb1Suffix}
+ olcDbDirectory: ${openldap.dataDir}
+ # Database superuser. Needed for syncrepl.
+ olcRootDN: cn=admin,${mdb1Suffix}
+ # superuser password, generated with slappasswd -s SECRET
+ # olcRootPW: {SSHA}VUlLVeNl3IKltfX50f/PokMRnlhRsSDI
+ olcDbIndex: objectClass eq
+ olcDbIndex: cn,uid eq
+ olcDbIndex: uidNumber,gidNumber eq
+ olcDbIndex: member,memberUid eq
+ olcAccess: to attrs=userPassword
+ by self write
+ by anonymous auth
+ by * none
+ olcAccess: to attrs=shadowLastChange
+ by self write
+ by * none
+ olcAccess: to dn.sub="ou=posix,${mdb1Suffix}"
+ by dn="gidNumber=${toString config.users.groups.nslcd.gid}+uidNumber=${toString config.users.users.nslcd.uid},cn=peercred,cn=external,cn=auth" manage
+ olcAccess: to *
+ by self read
+ by * none
+ '';
+ mdb1LDIF = pkgs.writeText "${mdb1Suffix}.ldif" ''
+ dn: ${mdb1Suffix}
+ dc: ${config.networking.baseName}
+ objectClass: top
+ objectClass: dcObject
+ objectClass: organization
+ o: Commonsoft
+
+ dn: cn=admin,${mdb1Suffix}
+ cn: admin
+ objectClass: simpleSecurityObject
+ objectClass: organizationalRole
+ description: ${config.networking.baseName} LDAP administrator
+ roleOccupant: ${mdb1Suffix}
+ userPassword:
+
+ dn: ou=posix,${mdb1Suffix}
+ ou: posix
+ objectClass: top
+ objectClass: organizationalUnit
+
+ dn: ou=accounts,ou=posix,${mdb1Suffix}
+ ou: accounts
+ objectClass: top
+ objectClass: organizationalUnit
+
+ dn: ou=groups,ou=posix,${mdb1Suffix}
+ ou: groups
+ objectClass: top
+ objectClass: organizationalUnit
+
+ dn: cn=users,ou=groups,ou=posix,${mdb1Suffix}
+ cn: users
+ objectclass: top
+ objectclass: posixGroup
+ gidnumber: 10000
+ memberuid: julm
+ memberuid: sevy
+
+ dn: uid=julm,ou=accounts,ou=posix,${mdb1Suffix}
+ uid: julm
+ objectClass: account
+ objectClass: posixAccount
+ cn: Julien M.
+ uidNumber: 10000
+ gidNumber: 10000
+ homeDirectory: /home/julm
+ loginShell: /run/current-system/sw/bin/bash
+ userPassword: {SSHA}144Rfau9KJ14U0U4KdLNB7OrtpiEc3E3
+
+ dn: uid=sevy,ou=accounts,ou=posix,${mdb1Suffix}
+ uid: sevy
+ objectClass: account
+ objectClass: posixAccount
+ cn: Séverine P.
+ uidNumber: 10001
+ gidNumber: 10000
+ homeDirectory: /home/sevy
+ loginShell: /run/current-system/sw/bin/bash
+ userPassword: {SSHA}dwqaKo5nmId8Bym5PghloK+UEndwrVTN
+ '';
+in
+{
+ config = {
+ users.ldap = {
+ enable = true;
+ # FIXME: even with the correct LD_LIBRARY_PATH to libnss_ldap.so,
+ # passwd still does not work on LDAP accounts.
+ daemon = {
+ enable = true;
+ extraConfig = ''
+ sasl_mech EXTERNAL
+ '';
+ };
+ server = "ldapi:///";
+ base = "ou=posix,${mdb1Suffix}";
+ bind = {
+ #distinguishedName = "cn=admin,${mdb1Suffix}";
+ };
+ };
+ services.openldap = {
+ enable = true;
+ dataDir = "/var/db/ldap";
+ configDir = "/var/db/slapd";
+ urlList = [ "ldapi:///" ]; # UNIX socket
+ };
+ systemd.services.openldap = {
+ preStart = ''
+ # NOTE: the config is always re-initialized.
+ rm -rf "${openldap.configDir}"/cn=config \
+ "${openldap.configDir}"/cn=config.ldif
+ umask 0077
+ install -D -d -m 0700 \
+ -o "${openldap.user}" \
+ -g "${openldap.group}" \
+ "${openldap.dataDir}" \
+ "${openldap.configDir}"
+
+ # NOTE: slapd is stopped in preStart, slap* commands can therefore be used.
+ ${pkgs.openldap}/bin/slapadd -n 0 -F "${openldap.configDir}" -l ${cnConfigLDIF}
+ # NOTE: slapadd(8): To populate the config database slapd-config(5),
+ # use -n 0 as it is always the first database.
+ # It must physically exist on the filesystem prior to this, however.
+
+ # NOTE: the data are only initialized, never re-initialized.
+ if test ! -e "${openldap.dataDir}"/data.mdb
+ then
+ ${pkgs.openldap}/bin/slapadd -F "${openldap.configDir}" -l ${mdb1LDIF}
+ fi
+ chown -R "${openldap.user}:${openldap.group}" \
+ "${openldap.dataDir}" \
+ "${openldap.configDir}"
+ '';
+ };
+ };
+}