{pkgs, lib, config, ...}: let inherit (config) networking; inherit (config.services) openldap; inherit (config.users) users groups; inherit (pkgs.lib) unlines; domainSuffix = openldap.domainSuffix; posixAccount = { uid , uidNumber ? null , gidNumber ? uidNumber , cn ? "" , sn ? "" , userPassword ? "{SSHA}dwqaKo5nmId8Bym5PghloK+UEndwrVTN" , mailAlias ? [] , loginShell ? "/run/current-system/sw/bin/bash" , mailEnabled ? true , mailForwardingAddress ? [] , domain ? networking.domain }: "\n" + lib.concatStringsSep "\n\n" [ (unlines ([ '' dn: uid=${uid},ou=accounts,ou=posix,${domainSuffix} objectClass: person objectClass: posixAccount objectClass: PostfixBookMailAccount objectClass: PostfixBookMailForward cn: ${cn} sn: ${sn} mail: ${uid}${lib.optionalString (networking.domain != "") "@${networking.domain}"} mailEnabled: ${if mailEnabled then "TRUE" else "FALSE"} #mailGroupMember: ${networking.domainBase} homeDirectory: /home/${uid} uidNumber: ${toString uidNumber} gidNumber: ${toString gidNumber} loginShell: ${loginShell}'' ] ++ lib.optional (userPassword != "") "userPassword: ${userPassword}" ++ map (forward: "mailForwardingAddress: ${forward}") mailForwardingAddress ++ map (alias: "mailAlias: ${alias}@${networking.domain}") mailAlias ++ lib.optional (mailAlias == []) "mailAlias:" # NOTE: required by PostfixBookMailForward )) '' 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: ${networking.domainBase} dn: cn=admin,${domainSuffix} objectClass: simpleSecurityObject objectClass: organizationalRole description: ${networking.domainBase} 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=${networking.domainBase},ou=groups,ou=posix,${domainSuffix} objectClass: top objectClass: posixGroup gidnumber: 20000 memberuid: ju memberuid: sevy '' + lib.concatMapStrings posixAccount [ { 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; } { uid="post"; domain="friot"; mailForwardingAddress = ["ju@${networking.domain}"]; } { uid="host"; mailForwardingAddress = ["ju@${networking.domain}"]; } ]; }; }; }; }; }