mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-01-29 16:24:10 +00:00
4f0dadbf38
After final improvements to the official formatter implementation, this commit now performs the first treewide reformat of Nix files using it. This is part of the implementation of RFC 166. Only "inactive" files are reformatted, meaning only files that aren't being touched by any PR with activity in the past 2 months. This is to avoid conflicts for PRs that might soon be merged. Later we can do a full treewide reformat to get the rest, which should not cause as many conflicts. A CI check has already been running for some time to ensure that new and already-formatted files are formatted, so the files being reformatted here should also stay formatted. This commit was automatically created and can be verified using nix-builda08b3a4d19
.tar.gz \ --argstr baseRevb32a094368
result/bin/apply-formatting $NIXPKGS_PATH
400 lines
13 KiB
Nix
400 lines
13 KiB
Nix
{
|
|
config,
|
|
lib,
|
|
pkgs,
|
|
...
|
|
}:
|
|
let
|
|
cfg = config.services.openldap;
|
|
openldap = cfg.package;
|
|
configDir = if cfg.configDir != null then cfg.configDir else "/etc/openldap/slapd.d";
|
|
|
|
ldapValueType =
|
|
let
|
|
# Can't do types.either with multiple non-overlapping submodules, so define our own
|
|
singleLdapValueType = lib.mkOptionType rec {
|
|
name = "LDAP";
|
|
# TODO: It would be nice to define a { secret = ...; } option, using
|
|
# systemd's LoadCredentials for secrets. That would remove the last
|
|
# barrier to using DynamicUser for openldap. This is blocked on
|
|
# systemd/systemd#19604
|
|
description = ''
|
|
LDAP value - either a string, or an attrset containing
|
|
`path` or `base64` for included
|
|
values or base-64 encoded values respectively.
|
|
'';
|
|
check = x: lib.isString x || (lib.isAttrs x && (x ? path || x ? base64));
|
|
merge = lib.mergeEqualOption;
|
|
};
|
|
in
|
|
# We don't coerce to lists of single values, as some values must be unique
|
|
lib.types.either singleLdapValueType (lib.types.listOf singleLdapValueType);
|
|
|
|
ldapAttrsType =
|
|
let
|
|
options = {
|
|
attrs = lib.mkOption {
|
|
type = lib.types.attrsOf ldapValueType;
|
|
default = { };
|
|
description = "Attributes of the parent entry.";
|
|
};
|
|
children = lib.mkOption {
|
|
# Hide the child attributes, to avoid infinite recursion in e.g. documentation
|
|
# Actual Nix evaluation is lazy, so this is not an issue there
|
|
type =
|
|
let
|
|
hiddenOptions = lib.mapAttrs (name: attr: attr // { visible = false; }) options;
|
|
in
|
|
lib.types.attrsOf (lib.types.submodule { options = hiddenOptions; });
|
|
default = { };
|
|
description = "Child entries of the current entry, with recursively the same structure.";
|
|
example = lib.literalExpression ''
|
|
{
|
|
"cn=schema" = {
|
|
# The attribute used in the DN must be defined
|
|
attrs = { cn = "schema"; };
|
|
children = {
|
|
# This entry's DN is expanded to "cn=foo,cn=schema"
|
|
"cn=foo" = { ... };
|
|
};
|
|
# These includes are inserted after "cn=schema", but before "cn=foo,cn=schema"
|
|
includes = [ ... ];
|
|
};
|
|
}
|
|
'';
|
|
};
|
|
includes = lib.mkOption {
|
|
type = lib.types.listOf lib.types.path;
|
|
default = [ ];
|
|
description = ''
|
|
LDIF files to include after the parent's attributes but before its children.
|
|
'';
|
|
};
|
|
};
|
|
in
|
|
lib.types.submodule { inherit options; };
|
|
|
|
valueToLdif =
|
|
attr: values:
|
|
let
|
|
listValues = if lib.isList values then values else lib.singleton values;
|
|
in
|
|
map (
|
|
value:
|
|
if lib.isAttrs value then
|
|
if lib.hasAttr "path" value then "${attr}:< file://${value.path}" else "${attr}:: ${value.base64}"
|
|
else
|
|
"${attr}: ${lib.replaceStrings [ "\n" ] [ "\n " ] value}"
|
|
) listValues;
|
|
|
|
attrsToLdif =
|
|
dn:
|
|
{
|
|
attrs,
|
|
children,
|
|
includes,
|
|
...
|
|
}:
|
|
[
|
|
''
|
|
dn: ${dn}
|
|
${lib.concatStringsSep "\n" (lib.flatten (lib.mapAttrsToList valueToLdif attrs))}
|
|
''
|
|
]
|
|
++ (map (path: "include: file://${path}\n") includes)
|
|
++ (lib.flatten (lib.mapAttrsToList (name: value: attrsToLdif "${name},${dn}" value) children));
|
|
in
|
|
{
|
|
options = {
|
|
services.openldap = {
|
|
enable = lib.mkOption {
|
|
type = lib.types.bool;
|
|
default = false;
|
|
description = "Whether to enable the ldap server.";
|
|
};
|
|
|
|
package = lib.mkPackageOption pkgs "openldap" {
|
|
extraDescription = ''
|
|
This can be used to, for example, set an OpenLDAP package
|
|
with custom overrides to enable modules or other
|
|
functionality.
|
|
'';
|
|
};
|
|
|
|
user = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "openldap";
|
|
description = "User account under which slapd runs.";
|
|
};
|
|
|
|
group = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "openldap";
|
|
description = "Group account under which slapd runs.";
|
|
};
|
|
|
|
urlList = lib.mkOption {
|
|
type = lib.types.listOf lib.types.str;
|
|
default = [ "ldap:///" ];
|
|
description = "URL list slapd should listen on.";
|
|
example = [ "ldaps:///" ];
|
|
};
|
|
|
|
settings = lib.mkOption {
|
|
type = ldapAttrsType;
|
|
description = "Configuration for OpenLDAP, in OLC format";
|
|
example = lib.literalExpression ''
|
|
{
|
|
attrs.olcLogLevel = [ "stats" ];
|
|
children = {
|
|
"cn=schema".includes = [
|
|
"''${pkgs.openldap}/etc/schema/core.ldif"
|
|
"''${pkgs.openldap}/etc/schema/cosine.ldif"
|
|
"''${pkgs.openldap}/etc/schema/inetorgperson.ldif"
|
|
];
|
|
"olcDatabase={-1}frontend" = {
|
|
attrs = {
|
|
objectClass = "olcDatabaseConfig";
|
|
olcDatabase = "{-1}frontend";
|
|
olcAccess = [ "{0}to * by dn.exact=uidNumber=0+gidNumber=0,cn=peercred,cn=external,cn=auth manage stop by * none stop" ];
|
|
};
|
|
};
|
|
"olcDatabase={0}config" = {
|
|
attrs = {
|
|
objectClass = "olcDatabaseConfig";
|
|
olcDatabase = "{0}config";
|
|
olcAccess = [ "{0}to * by * none break" ];
|
|
};
|
|
};
|
|
"olcDatabase={1}mdb" = {
|
|
attrs = {
|
|
objectClass = [ "olcDatabaseConfig" "olcMdbConfig" ];
|
|
olcDatabase = "{1}mdb";
|
|
olcDbDirectory = "/var/lib/openldap/ldap";
|
|
olcDbIndex = [
|
|
"objectClass eq"
|
|
"cn pres,eq"
|
|
"uid pres,eq"
|
|
"sn pres,eq,subany"
|
|
];
|
|
olcSuffix = "dc=example,dc=com";
|
|
olcAccess = [ "{0}to * by * read break" ];
|
|
};
|
|
};
|
|
};
|
|
};
|
|
'';
|
|
};
|
|
|
|
# This option overrides settings
|
|
configDir = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.path;
|
|
default = null;
|
|
description = ''
|
|
Use this config directory instead of generating one from the
|
|
`settings` option. Overrides all NixOS settings.
|
|
'';
|
|
example = "/var/lib/openldap/slapd.d";
|
|
};
|
|
|
|
mutableConfig = lib.mkOption {
|
|
type = lib.types.bool;
|
|
default = false;
|
|
description = ''
|
|
Whether to allow writable on-line configuration. If
|
|
`true`, the NixOS settings will only be used to
|
|
initialize the OpenLDAP configuration if it does not exist, and are
|
|
subsequently ignored.
|
|
'';
|
|
};
|
|
|
|
declarativeContents = lib.mkOption {
|
|
type = with lib.types; attrsOf lines;
|
|
default = { };
|
|
description = ''
|
|
Declarative contents for the LDAP database, in LDIF format by suffix.
|
|
|
|
All data will be erased when starting the LDAP server. Modifications
|
|
to the database are not prevented, they are just dropped on the next
|
|
reboot of the server. Performance-wise the database and indexes are
|
|
rebuilt on each server startup, so this will slow down server startup,
|
|
especially with large databases.
|
|
|
|
Note that the root of the DB must be defined in
|
|
`services.openldap.settings` and the
|
|
`olcDbDirectory` must begin with
|
|
`"/var/lib/openldap"`.
|
|
'';
|
|
example = lib.literalExpression ''
|
|
{
|
|
"dc=example,dc=org" = '''
|
|
dn= dn: dc=example,dc=org
|
|
objectClass: domain
|
|
dc: example
|
|
|
|
dn: ou=users,dc=example,dc=org
|
|
objectClass = organizationalUnit
|
|
ou: users
|
|
|
|
# ...
|
|
''';
|
|
}
|
|
'';
|
|
};
|
|
};
|
|
};
|
|
|
|
meta.maintainers = with lib.maintainers; [ kwohlfahrt ];
|
|
|
|
config =
|
|
let
|
|
dbSettings = lib.mapAttrs' (name: { attrs, ... }: lib.nameValuePair attrs.olcSuffix attrs) (
|
|
lib.filterAttrs (
|
|
name: { attrs, ... }: (lib.hasPrefix "olcDatabase=" name) && attrs ? olcSuffix
|
|
) cfg.settings.children
|
|
);
|
|
settingsFile = pkgs.writeText "config.ldif" (
|
|
lib.concatStringsSep "\n" (attrsToLdif "cn=config" cfg.settings)
|
|
);
|
|
writeConfig = pkgs.writeShellScript "openldap-config" ''
|
|
set -euo pipefail
|
|
|
|
${lib.optionalString (!cfg.mutableConfig) ''
|
|
chmod -R u+w ${configDir}
|
|
rm -rf ${configDir}/*
|
|
''}
|
|
if [ ! -e "${configDir}/cn=config.ldif" ]; then
|
|
${openldap}/bin/slapadd -F ${configDir} -bcn=config -l ${settingsFile}
|
|
fi
|
|
chmod -R ${if cfg.mutableConfig then "u+rw" else "u+r-w"} ${configDir}
|
|
'';
|
|
|
|
contentsFiles = lib.mapAttrs (dn: ldif: pkgs.writeText "${dn}.ldif" ldif) cfg.declarativeContents;
|
|
writeContents = pkgs.writeShellScript "openldap-load" ''
|
|
set -euo pipefail
|
|
|
|
rm -rf $2/*
|
|
${openldap}/bin/slapadd -F ${configDir} -b $1 -l $3
|
|
'';
|
|
in
|
|
lib.mkIf cfg.enable {
|
|
assertions =
|
|
[
|
|
{
|
|
assertion = (cfg.declarativeContents != { }) -> cfg.configDir == null;
|
|
message = ''
|
|
Declarative DB contents (${lib.attrNames cfg.declarativeContents}) are not
|
|
supported with user-managed configuration.
|
|
'';
|
|
}
|
|
]
|
|
++ (map (dn: {
|
|
assertion = (lib.getAttr dn dbSettings) ? "olcDbDirectory";
|
|
# olcDbDirectory is necessary to prepopulate database using `slapadd`.
|
|
message = ''
|
|
Declarative DB ${dn} does not exist in `services.openldap.settings`, or does not have
|
|
`olcDbDirectory` configured.
|
|
'';
|
|
}) (lib.attrNames cfg.declarativeContents))
|
|
++ (lib.mapAttrsToList (
|
|
dn:
|
|
{
|
|
olcDbDirectory ? null,
|
|
...
|
|
}:
|
|
{
|
|
# For forward compatibility with `DynamicUser`, and to avoid accidentally clobbering
|
|
# directories with `declarativeContents`.
|
|
assertion =
|
|
(olcDbDirectory != null)
|
|
-> (
|
|
(lib.hasPrefix "/var/lib/openldap/" olcDbDirectory) && (olcDbDirectory != "/var/lib/openldap/")
|
|
);
|
|
message = ''
|
|
Database ${dn} has `olcDbDirectory` (${olcDbDirectory}) that is not a subdirectory of
|
|
`/var/lib/openldap/`.
|
|
'';
|
|
}
|
|
) dbSettings);
|
|
environment.systemPackages = [ openldap ];
|
|
|
|
# Literal attributes must always be set
|
|
services.openldap.settings = {
|
|
attrs = {
|
|
objectClass = "olcGlobal";
|
|
cn = "config";
|
|
};
|
|
children."cn=schema".attrs = {
|
|
cn = "schema";
|
|
objectClass = "olcSchemaConfig";
|
|
};
|
|
};
|
|
|
|
systemd.services.openldap = {
|
|
description = "OpenLDAP Server Daemon";
|
|
documentation = [
|
|
"man:slapd"
|
|
"man:slapd-config"
|
|
"man:slapd-mdb"
|
|
];
|
|
wantedBy = [ "multi-user.target" ];
|
|
wants = [ "network-online.target" ];
|
|
after = [ "network-online.target" ];
|
|
serviceConfig = {
|
|
User = cfg.user;
|
|
Group = cfg.group;
|
|
ExecStartPre =
|
|
[
|
|
"!${pkgs.coreutils}/bin/mkdir -p ${configDir}"
|
|
"+${pkgs.coreutils}/bin/chown $USER ${configDir}"
|
|
]
|
|
++ (lib.optional (cfg.configDir == null) writeConfig)
|
|
++ (lib.mapAttrsToList (
|
|
dn: content:
|
|
lib.escapeShellArgs [
|
|
writeContents
|
|
dn
|
|
(lib.getAttr dn dbSettings).olcDbDirectory
|
|
content
|
|
]
|
|
) contentsFiles)
|
|
++ [ "${openldap}/bin/slaptest -u -F ${configDir}" ];
|
|
ExecStart = lib.escapeShellArgs ([
|
|
"${openldap}/libexec/slapd"
|
|
"-d"
|
|
"0"
|
|
"-F"
|
|
configDir
|
|
"-h"
|
|
(lib.concatStringsSep " " cfg.urlList)
|
|
]);
|
|
Type = "notify";
|
|
# Fixes an error where openldap attempts to notify from a thread
|
|
# outside the main process:
|
|
# Got notification message from PID 6378, but reception only permitted for main PID 6377
|
|
NotifyAccess = "all";
|
|
RuntimeDirectory = "openldap";
|
|
StateDirectory =
|
|
[ "openldap" ]
|
|
++ (map ({ olcDbDirectory, ... }: lib.removePrefix "/var/lib/" olcDbDirectory) (
|
|
lib.attrValues dbSettings
|
|
));
|
|
StateDirectoryMode = "700";
|
|
AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
|
|
CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
|
|
};
|
|
};
|
|
|
|
users.users = lib.optionalAttrs (cfg.user == "openldap") {
|
|
openldap = {
|
|
group = cfg.group;
|
|
isSystemUser = true;
|
|
};
|
|
};
|
|
|
|
users.groups = lib.optionalAttrs (cfg.group == "openldap") {
|
|
openldap = { };
|
|
};
|
|
};
|
|
}
|