{ pkgs, lib, config, host, ... }:
let
  inherit (config) networking;
  inherit (config.services) openldap;
  inherit (config.users) ldap;
  domainSuffix = "dc=" + lib.concatStringsSep ",dc=" (lib.splitString "." networking.domain);
in
{
  imports = [
    openldap/sourcephile.fr.nix
    openldap/autogeree.net.nix
  ];
  users.ldap = {
    enable = false;
    server = "ldapi:///";
    base = "ou=posix,${domainSuffix}";
    bind = {
      #distinguishedName = "cn=admin,${domainSuffix}";
    };
    daemon = {
      enable = false;
      extraConfig = ''
        log syslog info

        sasl_mech EXTERNAL
        # NOTE: nslcd cannot use SASL to bind to rootpwmoddn
        # which is the DN used by nslcd when passwd is run by root
        # to change the userPassword of an LDAP user.
        # SEE: https://www.reddit.com/r/linuxadmin/comments/53sxpl/how_do_i_configure_nslcd_to_use_a_sasl_external/d7w9awd/
        # Thus, use: ldappasswd -H ldapi:// -Y EXTERNAL uid=$user,ou=accounts,ou=posix,dc=sourcephile,dc=fr
      '';
    };
  };
  services.openldap = {
    enable = true;
    urlList = [ "ldapi:///" ]; # UNIX socket
    # sudo ldapsearch -LLL -H ldapi:// -D cn=admin,cn=config -Y EXTERNAL -b "" -s base supportedControl
    settings = {
      attrs = {
        objectClass = "olcGlobal";
        olcLogLevel = [ "stats" ];
        # The tool-threads parameter sets the actual amount of CPU's
        # that is used for indexing.
        olcToolThreads = toString host.CPUs;
      };
      children = {
        "cn=schema".includes = [
          "${pkgs.openldap}/etc/schema/core.ldif"
          "${pkgs.openldap}/etc/schema/cosine.ldif"
          "${pkgs.openldap}/etc/schema/nis.ldif"
          "${pkgs.openldap}/etc/schema/inetorgperson.ldif"
          "${openldap/schema/postfix-book.ldif}"
        ];
        # The first database is the special frontend database
        # whose settings are applied globally to all the other databases.
        # Beware that cn={0}module,cn=config must appear before
        # for enabling password schemes provided by the modules in olcPasswordHash.
        # ldapsearch -LLL -H ldapi:// -D cn=admin,cn=config -Y EXTERNAL -b 'olcDatabase={-1}frontend,cn=config' -s sub '*'
        "olcDatabase={-1}frontend".attrs = {
          objectClass = [ "olcDatabaseConfig" "olcFrontendConfig" ];
          olcDatabase = "{-1}frontend";
          # The maximum number of entries that is returned for a search operation
          olcSizeLimit = "500";
          olcAccess = [
            # Allow unlimited access to local connection from the local root user
            ''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
            ''to dn.exact=""
          by * read
          ''
            ''to dn.base="cn=Subschema"
          by * read
          ''
          ];
          # Hash algorithm to be used by LDAP Password Modify Extended Operation or the ppolicy overlay
          #olcPasswordHash = "{PBKDF2-SHA256}";
          olcPasswordHash = "{SSHA}";
        };
        "cn={0}module".attrs = {
          objectClass = [ "olcModuleList" ];
          olcModulePath = "${pkgs.openldap}/lib/modules";
          #olcModuleLoad = "pw-sha2";
          #olcModuleLoad = "pw-pbkdf2";
          olcModuleLoad = "back_mdb";
        };

        "olcDatabase={0}config".attrs = {
          objectClass = "olcDatabaseConfig";
          olcDatabase = "{0}config";
          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
          ''
          ];
        };
      };
    };
    /*
      cnConfig = ''
      dn: cn=schema,cn=config
      objectClass: olcSchemaConfig

      dn: olcBackend=mdb,cn=config
      objectClass: olcBackendConfig
      '';
    */
  };
}