at 15.09-beta 7.5 kB view raw
1{ config, lib, pkgs, ... }: 2 3with pkgs; 4with lib; 5 6let 7 8 cfg = config.users.ldap; 9 10 # Careful: OpenLDAP seems to be very picky about the indentation of 11 # this file. Directives HAVE to start in the first column! 12 ldapConfig = { 13 target = "ldap.conf"; 14 source = writeText "ldap.conf" '' 15 uri ${config.users.ldap.server} 16 base ${config.users.ldap.base} 17 timelimit ${toString config.users.ldap.timeLimit} 18 bind_timelimit ${toString config.users.ldap.bind.timeLimit} 19 bind_policy ${config.users.ldap.bind.policy} 20 ${optionalString config.users.ldap.useTLS '' 21 ssl start_tls 22 tls_checkpeer no 23 ''} 24 ${optionalString (config.users.ldap.bind.distinguishedName != "") '' 25 binddn ${config.users.ldap.bind.distinguishedName} 26 ''} 27 ${optionalString (cfg.extraConfig != "") cfg.extraConfig } 28 ''; 29 }; 30 31 nslcdConfig = { 32 target = "nslcd.conf"; 33 source = writeText "nslcd.conf" '' 34 uid nslcd 35 gid nslcd 36 uri ${cfg.server} 37 base ${cfg.base} 38 timelimit ${toString cfg.timeLimit} 39 bind_timelimit ${toString cfg.bind.timeLimit} 40 ${optionalString (cfg.bind.distinguishedName != "") 41 "binddn ${cfg.bind.distinguishedName}" } 42 ${optionalString (cfg.daemon.extraConfig != "") cfg.daemon.extraConfig } 43 ''; 44 }; 45 46 insertLdapPassword = !config.users.ldap.daemon.enable && 47 config.users.ldap.bind.distinguishedName != ""; 48 49in 50 51{ 52 53 ###### interface 54 55 options = { 56 57 users.ldap = { 58 59 enable = mkOption { 60 default = false; 61 description = "Whether to enable authentication against an LDAP server."; 62 }; 63 64 server = mkOption { 65 example = "ldap://ldap.example.org/"; 66 description = "The URL of the LDAP server."; 67 }; 68 69 base = mkOption { 70 example = "dc=example,dc=org"; 71 description = "The distinguished name of the search base."; 72 }; 73 74 useTLS = mkOption { 75 default = false; 76 description = '' 77 If enabled, use TLS (encryption) over an LDAP (port 389) 78 connection. The alternative is to specify an LDAPS server (port 79 636) in <option>users.ldap.server</option> or to forego 80 security. 81 ''; 82 }; 83 84 timeLimit = mkOption { 85 default = 0; 86 type = types.int; 87 description = '' 88 Specifies the time limit (in seconds) to use when performing 89 searches. A value of zero (0), which is the default, is to 90 wait indefinitely for searches to be completed. 91 ''; 92 }; 93 94 daemon = { 95 enable = mkOption { 96 default = false; 97 description = '' 98 Whether to let the nslcd daemon (nss-pam-ldapd) handle the 99 LDAP lookups for NSS and PAM. This can improve performance, 100 and if you need to bind to the LDAP server with a password, 101 it increases security, since only the nslcd user needs to 102 have access to the bindpw file, not everyone that uses NSS 103 and/or PAM. If this option is enabled, a local nscd user is 104 created automatically, and the nslcd service is started 105 automatically when the network get up. 106 ''; 107 }; 108 109 extraConfig = mkOption { 110 default = ""; 111 type = types.string; 112 description = '' 113 Extra configuration options that will be added verbatim at 114 the end of the nslcd configuration file (nslcd.conf). 115 '' ; 116 } ; 117 }; 118 119 bind = { 120 distinguishedName = mkOption { 121 default = ""; 122 example = "cn=admin,dc=example,dc=com"; 123 type = types.string; 124 description = '' 125 The distinguished name to bind to the LDAP server with. If this 126 is not specified, an anonymous bind will be done. 127 ''; 128 }; 129 130 password = mkOption { 131 default = "/etc/ldap/bind.password"; 132 type = types.string; 133 description = '' 134 The path to a file containing the credentials to use when binding 135 to the LDAP server (if not binding anonymously). 136 ''; 137 }; 138 139 timeLimit = mkOption { 140 default = 30; 141 type = types.int; 142 description = '' 143 Specifies the time limit (in seconds) to use when connecting 144 to the directory server. This is distinct from the time limit 145 specified in <literal>users.ldap.timeLimit</literal> and affects 146 the initial server connection only. 147 ''; 148 }; 149 150 policy = mkOption { 151 default = "hard_open"; 152 type = types.string; 153 description = '' 154 Specifies the policy to use for reconnecting to an unavailable 155 LDAP server. The default is <literal>hard_open</literal>, which 156 reconnects if opening the connection to the directory server 157 failed. By contrast, <literal>hard_init</literal> reconnects if 158 initializing the connection failed. Initializing may not 159 actually contact the directory server, and it is possible that 160 a malformed configuration file will trigger reconnection. If 161 <literal>soft</literal> is specified, then 162 <literal>nss_ldap</literal> will return immediately on server 163 failure. All hard reconnect policies block with exponential 164 backoff before retrying. 165 ''; 166 }; 167 }; 168 169 extraConfig = mkOption { 170 default = ""; 171 type = types.string; 172 description = '' 173 Extra configuration options that will be added verbatim at 174 the end of the ldap configuration file (ldap.conf). 175 If <literal>users.ldap.daemon</literal> is enabled, this 176 configuration will not be used. In that case, use 177 <literal>users.ldap.daemon.extraConfig</literal> instead. 178 '' ; 179 }; 180 181 }; 182 183 }; 184 185 ###### implementation 186 187 config = mkIf cfg.enable { 188 189 environment.etc = if cfg.daemon.enable then [nslcdConfig] else [ldapConfig]; 190 191 system.activationScripts = mkIf insertLdapPassword { 192 ldap = stringAfter [ "etc" "groups" "users" ] '' 193 if test -f "${cfg.bind.password}" ; then 194 echo "bindpw "$(cat ${cfg.bind.password})"" | cat ${ldapConfig} - > /etc/ldap.conf.bindpw 195 mv -fT /etc/ldap.conf.bindpw /etc/ldap.conf 196 chmod 600 /etc/ldap.conf 197 fi 198 ''; 199 }; 200 201 system.nssModules = singleton ( 202 if cfg.daemon.enable then nss_pam_ldapd else nss_ldap 203 ); 204 205 users = mkIf cfg.daemon.enable { 206 extraGroups.nslcd = { 207 gid = config.ids.gids.nslcd; 208 }; 209 210 extraUsers.nslcd = { 211 uid = config.ids.uids.nslcd; 212 description = "nslcd user."; 213 group = "nslcd"; 214 }; 215 }; 216 217 systemd.services = mkIf cfg.daemon.enable { 218 219 nslcd = { 220 wantedBy = [ "multi-user.target" ]; 221 222 preStart = '' 223 mkdir -p /run/nslcd 224 rm -f /run/nslcd/nslcd.pid; 225 chown nslcd.nslcd /run/nslcd 226 ${optionalString (cfg.bind.distinguishedName != "") '' 227 if test -s "${cfg.bind.password}" ; then 228 ln -sfT "${cfg.bind.password}" /run/nslcd/bindpw 229 fi 230 ''} 231 ''; 232 233 serviceConfig = { 234 ExecStart = "${nss_pam_ldapd}/sbin/nslcd"; 235 Type = "forking"; 236 PIDFile = "/run/nslcd/nslcd.pid"; 237 Restart = "always"; 238 }; 239 }; 240 241 }; 242 243 }; 244}