{pkgs, lib, config, ...}: let inherit (config.services) openldap; inherit (config.users) users groups; inherit (config.networking) domain baseName; inherit (pkgs.lib) unlines; domainSuffix = openldap.domainSuffix; accountLDIF = { uid, uidNumber, gidNumber ? uidNumber , cn ? "" , sn ? "" , userPassword ? "{SSHA}dwqaKo5nmId8Bym5PghloK+UEndwrVTN" , mailAlias ? [] , loginShell ? "/run/current-system/sw/bin/bash" , mailEnabled ? true }: '' dn: uid=${uid},ou=accounts,ou=posix,${domainSuffix} objectclass: person objectClass: posixAccount objectclass: PostfixBookMailAccount objectclass: PostfixBookMailForward cn: ${cn} sn: ${sn} mail: ${uid}@${domain} ${unlines (map (ma: "mailAlias: ${ma}@${domain}") mailAlias)} #mailGroupMember: ${baseName} uidNumber: ${toString uidNumber} gidNumber: ${toString gidNumber} homeDirectory: /home/${uid} loginShell: ${loginShell} mailEnabled: ${if mailEnabled then "TRUE" else "FALSE"} ${lib.optionalString (userPassword != "") "userPassword: ${userPassword}"} dn: cn=${uid},ou=groups,ou=posix,${domainSuffix} objectclass: top objectclass: posixGroup gidnumber: ${toString gidNumber} memberuid: ${uid} ''; in { config = { services.openldap = { databases = { "${domainSuffix}" = { resetData = true; conf = '' # sudo ldapsearch -LLL -H ldapi:// -D cn=admin,cn=config -Y EXTERNAL -b 'olcDatabase={1}mdb,cn=config' -s sub dn: olcBackend={1}mdb,cn=config objectClass: olcBackendConfig dn: olcDatabase={1}mdb,cn=config objectClass: olcDatabaseConfig objectClass: olcMdbConfig # NOTE: 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 # NOTE: database superuser. Needed for syncrepl. olcRootDN: cn=admin,${domainSuffix} # NOTE: superuser password, generated with slappasswd -s SECRET #olcRootPW: {SSHA}NONVwwKnKsCBmFxkMqTCFekdu3SJQHc9 # olcDbIndex: objectClass eq olcDbIndex: cn,uid eq olcDbIndex: uidNumber,gidNumber eq olcDbIndex: member,memberUid eq olcDbIndex: mail eq olcDbIndex: mailEnabled eq # olcAccess: to attrs=userPassword by self write by anonymous auth by dn="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" read by * none olcAccess: to attrs=shadowLastChange by self write by * none olcAccess: to dn.sub="ou=posix,${domainSuffix}" by dn="gidNumber=${toString groups.nslcd.gid}+uidNumber=${toString users.nslcd.uid},cn=peercred,cn=external,cn=auth" read by dn="gidNumber=${toString groups.postfix.gid}+uidNumber=${toString users.postfix.uid},cn=peercred,cn=external,cn=auth" read by dn="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" read # NOTE: dovecot/auth runs as root, hence the gidNumber=0+uidNumber=0 olcAccess: to * by self read by * none ''; data = '' dn: ${domainSuffix} objectClass: top objectClass: dcObject objectClass: organization o: ${baseName} dn: cn=admin,${domainSuffix} objectClass: simpleSecurityObject objectClass: organizationalRole description: ${baseName} LDAP administrator roleOccupant: ${domainSuffix} userPassword: #userPassword: {SSHA}NONVwwKnKsCBmFxkMqTCFekdu3SJQHc9 dn: ou=posix,${domainSuffix} objectClass: top objectClass: organizationalUnit dn: ou=accounts,ou=posix,${domainSuffix} objectClass: top objectClass: organizationalUnit dn: ou=groups,ou=posix,${domainSuffix} objectClass: top objectClass: organizationalUnit dn: cn=${baseName},ou=groups,ou=posix,${domainSuffix} objectclass: top objectclass: posixGroup gidnumber: 20000 memberuid: ju memberuid: sevy '' + lib.concatMapStrings accountLDIF [ { uid="ju"; uidNumber=10000; cn="Julien M."; sn="julm"; mailAlias = ["juju"]; } { uid="sevy"; uidNumber=10001; cn="Séverine P."; sn="sévy"; mailAlias = ["severine.popek" "ouais-ouais"]; } { uid="nomail"; uidNumber=10002; mailAlias = ["noalias"]; mailEnabled = false; } ]; }; }; }; }; }