mirror of
https://github.com/NixOS/nixpkgs.git
synced 2024-11-23 14:11:36 +00:00
65cfba23af
NOTE: slapd.conf is deprecated, hence use cn=config.
291 lines
9 KiB
Nix
291 lines
9 KiB
Nix
{ config, lib, pkgs, ... }:
|
|
|
|
with pkgs;
|
|
with lib;
|
|
|
|
let
|
|
|
|
cfg = config.users.ldap;
|
|
|
|
# Careful: OpenLDAP seems to be very picky about the indentation of
|
|
# this file. Directives HAVE to start in the first column!
|
|
ldapConfig = {
|
|
target = "ldap.conf";
|
|
source = writeText "ldap.conf" ''
|
|
uri ${config.users.ldap.server}
|
|
base ${config.users.ldap.base}
|
|
timelimit ${toString config.users.ldap.timeLimit}
|
|
bind_timelimit ${toString config.users.ldap.bind.timeLimit}
|
|
bind_policy ${config.users.ldap.bind.policy}
|
|
${optionalString config.users.ldap.useTLS ''
|
|
ssl start_tls
|
|
''}
|
|
${optionalString (config.users.ldap.bind.distinguishedName != "") ''
|
|
binddn ${config.users.ldap.bind.distinguishedName}
|
|
''}
|
|
${optionalString (cfg.extraConfig != "") cfg.extraConfig }
|
|
'';
|
|
};
|
|
|
|
nslcdConfig = {
|
|
target = "nslcd.conf";
|
|
source = writeText "nslcd.conf" ''
|
|
uid nslcd
|
|
gid nslcd
|
|
uri ${cfg.server}
|
|
base ${cfg.base}
|
|
timelimit ${toString cfg.timeLimit}
|
|
bind_timelimit ${toString cfg.bind.timeLimit}
|
|
${optionalString (cfg.bind.distinguishedName != "")
|
|
"binddn ${cfg.bind.distinguishedName}" }
|
|
${optionalString (cfg.daemon.rootpwmoddn != "")
|
|
"rootpwmoddn ${cfg.daemon.rootpwmoddn}" }
|
|
${optionalString (cfg.daemon.extraConfig != "") cfg.daemon.extraConfig }
|
|
'';
|
|
};
|
|
|
|
insertLdapPassword = !config.users.ldap.daemon.enable &&
|
|
config.users.ldap.bind.distinguishedName != "";
|
|
|
|
in
|
|
|
|
{
|
|
|
|
###### interface
|
|
|
|
options = {
|
|
|
|
users.ldap = {
|
|
|
|
enable = mkOption {
|
|
type = types.bool;
|
|
default = false;
|
|
description = "Whether to enable authentication against an LDAP server.";
|
|
};
|
|
|
|
loginPam = mkOption {
|
|
type = types.bool;
|
|
default = true;
|
|
description = "Whether to include authentication against LDAP in login PAM";
|
|
};
|
|
|
|
nsswitch = mkOption {
|
|
type = types.bool;
|
|
default = true;
|
|
description = "Whether to include lookup against LDAP in NSS";
|
|
};
|
|
|
|
server = mkOption {
|
|
example = "ldap://ldap.example.org/";
|
|
description = "The URL of the LDAP server.";
|
|
};
|
|
|
|
base = mkOption {
|
|
example = "dc=example,dc=org";
|
|
description = "The distinguished name of the search base.";
|
|
};
|
|
|
|
useTLS = mkOption {
|
|
default = false;
|
|
description = ''
|
|
If enabled, use TLS (encryption) over an LDAP (port 389)
|
|
connection. The alternative is to specify an LDAPS server (port
|
|
636) in <option>users.ldap.server</option> or to forego
|
|
security.
|
|
'';
|
|
};
|
|
|
|
timeLimit = mkOption {
|
|
default = 0;
|
|
type = types.int;
|
|
description = ''
|
|
Specifies the time limit (in seconds) to use when performing
|
|
searches. A value of zero (0), which is the default, is to
|
|
wait indefinitely for searches to be completed.
|
|
'';
|
|
};
|
|
|
|
daemon = {
|
|
enable = mkOption {
|
|
default = false;
|
|
description = ''
|
|
Whether to let the nslcd daemon (nss-pam-ldapd) handle the
|
|
LDAP lookups for NSS and PAM. This can improve performance,
|
|
and if you need to bind to the LDAP server with a password,
|
|
it increases security, since only the nslcd user needs to
|
|
have access to the bindpw file, not everyone that uses NSS
|
|
and/or PAM. If this option is enabled, a local nscd user is
|
|
created automatically, and the nslcd service is started
|
|
automatically when the network get up.
|
|
'';
|
|
};
|
|
|
|
extraConfig = mkOption {
|
|
default = "";
|
|
type = types.lines;
|
|
description = ''
|
|
Extra configuration options that will be added verbatim at
|
|
the end of the nslcd configuration file (nslcd.conf).
|
|
'' ;
|
|
} ;
|
|
|
|
rootpwmoddn = mkOption {
|
|
default = "";
|
|
example = "cn=admin,dc=example,dc=com";
|
|
type = types.str;
|
|
description = ''
|
|
The distinguished name to use to bind to the LDAP server
|
|
when the root user tries to modify a user's password.
|
|
'';
|
|
};
|
|
|
|
rootpwmodpw = mkOption {
|
|
default = "";
|
|
example = "/run/keys/nslcd.rootpwmodpw";
|
|
type = types.str;
|
|
description = ''
|
|
The path to a file containing the credentials with which
|
|
to bind to the LDAP server if the root user tries to change a user's password
|
|
'';
|
|
};
|
|
};
|
|
|
|
bind = {
|
|
distinguishedName = mkOption {
|
|
default = "";
|
|
example = "cn=admin,dc=example,dc=com";
|
|
type = types.str;
|
|
description = ''
|
|
The distinguished name to bind to the LDAP server with. If this
|
|
is not specified, an anonymous bind will be done.
|
|
'';
|
|
};
|
|
|
|
password = mkOption {
|
|
default = "/etc/ldap/bind.password";
|
|
type = types.str;
|
|
description = ''
|
|
The path to a file containing the credentials to use when binding
|
|
to the LDAP server (if not binding anonymously).
|
|
'';
|
|
};
|
|
|
|
timeLimit = mkOption {
|
|
default = 30;
|
|
type = types.int;
|
|
description = ''
|
|
Specifies the time limit (in seconds) to use when connecting
|
|
to the directory server. This is distinct from the time limit
|
|
specified in <literal>users.ldap.timeLimit</literal> and affects
|
|
the initial server connection only.
|
|
'';
|
|
};
|
|
|
|
policy = mkOption {
|
|
default = "hard_open";
|
|
type = types.enum [ "hard_open" "hard_init" "soft" ];
|
|
description = ''
|
|
Specifies the policy to use for reconnecting to an unavailable
|
|
LDAP server. The default is <literal>hard_open</literal>, which
|
|
reconnects if opening the connection to the directory server
|
|
failed. By contrast, <literal>hard_init</literal> reconnects if
|
|
initializing the connection failed. Initializing may not
|
|
actually contact the directory server, and it is possible that
|
|
a malformed configuration file will trigger reconnection. If
|
|
<literal>soft</literal> is specified, then
|
|
<literal>nss_ldap</literal> will return immediately on server
|
|
failure. All hard reconnect policies block with exponential
|
|
backoff before retrying.
|
|
'';
|
|
};
|
|
};
|
|
|
|
extraConfig = mkOption {
|
|
default = "";
|
|
type = types.lines;
|
|
description = ''
|
|
Extra configuration options that will be added verbatim at
|
|
the end of the ldap configuration file (ldap.conf).
|
|
If <literal>users.ldap.daemon</literal> is enabled, this
|
|
configuration will not be used. In that case, use
|
|
<literal>users.ldap.daemon.extraConfig</literal> instead.
|
|
'' ;
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
###### implementation
|
|
|
|
config = mkIf cfg.enable {
|
|
|
|
environment.etc = if cfg.daemon.enable then [nslcdConfig] else [ldapConfig];
|
|
|
|
system.activationScripts = mkIf insertLdapPassword {
|
|
ldap = stringAfter [ "etc" "groups" "users" ] ''
|
|
if test -f "${cfg.bind.password}" ; then
|
|
umask 0077
|
|
conf="$(mktemp)"
|
|
printf 'bindpw %s\n' "$(cat ${cfg.bind.password})" |
|
|
cat ${ldapConfig.source} - >"$conf"
|
|
mv -fT "$conf" /etc/ldap.conf
|
|
fi
|
|
'';
|
|
};
|
|
|
|
system.nssModules = singleton (
|
|
if cfg.daemon.enable then nss_pam_ldapd else nss_ldap
|
|
);
|
|
|
|
users = mkIf cfg.daemon.enable {
|
|
groups.nslcd = {
|
|
gid = config.ids.gids.nslcd;
|
|
};
|
|
|
|
users.nslcd = {
|
|
uid = config.ids.uids.nslcd;
|
|
description = "nslcd user.";
|
|
group = "nslcd";
|
|
};
|
|
};
|
|
|
|
systemd.services = mkIf cfg.daemon.enable {
|
|
|
|
nslcd = {
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
preStart = ''
|
|
umask 0077
|
|
conf="$(mktemp)"
|
|
{
|
|
cat ${nslcdConfig.source}
|
|
test -z '${cfg.bind.distinguishedName}' -o ! -f '${cfg.bind.password}' ||
|
|
printf 'bindpw %s\n' "$(cat '${cfg.bind.password}')"
|
|
test -z '${cfg.daemon.rootpwmoddn}' -o ! -f '${cfg.daemon.rootpwmodpw}' ||
|
|
printf 'rootpwmodpw %s\n' "$(cat '${cfg.daemon.rootpwmodpw}')"
|
|
} >"$conf"
|
|
mv -fT "$conf" /etc/nslcd.conf
|
|
'';
|
|
|
|
# NOTE: because one cannot pass a custom config path to `nslcd`
|
|
# (which is only able to use `/etc/nslcd.conf`)
|
|
# changes in `nslcdConfig` won't change `serviceConfig`,
|
|
# and thus won't restart `nslcd`.
|
|
# Therefore `restartTriggers` is used on `/etc/nslcd.conf`.
|
|
restartTriggers = [ nslcdConfig.source ];
|
|
|
|
serviceConfig = {
|
|
ExecStart = "${nss_pam_ldapd}/sbin/nslcd";
|
|
Type = "forking";
|
|
PIDFile = "/run/nslcd/nslcd.pid";
|
|
Restart = "always";
|
|
RuntimeDirectory = [ "nslcd" ];
|
|
};
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
}
|