at 16.09-beta 7.9 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 type = types.bool; 61 default = false; 62 description = "Whether to enable authentication against an LDAP server."; 63 }; 64 65 loginPam = mkOption { 66 type = types.bool; 67 default = true; 68 description = "Whether to include authentication against LDAP in login PAM"; 69 }; 70 71 nsswitch = mkOption { 72 type = types.bool; 73 default = true; 74 description = "Whether to include lookup against LDAP in NSS"; 75 }; 76 77 server = mkOption { 78 example = "ldap://ldap.example.org/"; 79 description = "The URL of the LDAP server."; 80 }; 81 82 base = mkOption { 83 example = "dc=example,dc=org"; 84 description = "The distinguished name of the search base."; 85 }; 86 87 useTLS = mkOption { 88 default = false; 89 description = '' 90 If enabled, use TLS (encryption) over an LDAP (port 389) 91 connection. The alternative is to specify an LDAPS server (port 92 636) in <option>users.ldap.server</option> or to forego 93 security. 94 ''; 95 }; 96 97 timeLimit = mkOption { 98 default = 0; 99 type = types.int; 100 description = '' 101 Specifies the time limit (in seconds) to use when performing 102 searches. A value of zero (0), which is the default, is to 103 wait indefinitely for searches to be completed. 104 ''; 105 }; 106 107 daemon = { 108 enable = mkOption { 109 default = false; 110 description = '' 111 Whether to let the nslcd daemon (nss-pam-ldapd) handle the 112 LDAP lookups for NSS and PAM. This can improve performance, 113 and if you need to bind to the LDAP server with a password, 114 it increases security, since only the nslcd user needs to 115 have access to the bindpw file, not everyone that uses NSS 116 and/or PAM. If this option is enabled, a local nscd user is 117 created automatically, and the nslcd service is started 118 automatically when the network get up. 119 ''; 120 }; 121 122 extraConfig = mkOption { 123 default = ""; 124 type = types.lines; 125 description = '' 126 Extra configuration options that will be added verbatim at 127 the end of the nslcd configuration file (nslcd.conf). 128 '' ; 129 } ; 130 }; 131 132 bind = { 133 distinguishedName = mkOption { 134 default = ""; 135 example = "cn=admin,dc=example,dc=com"; 136 type = types.str; 137 description = '' 138 The distinguished name to bind to the LDAP server with. If this 139 is not specified, an anonymous bind will be done. 140 ''; 141 }; 142 143 password = mkOption { 144 default = "/etc/ldap/bind.password"; 145 type = types.str; 146 description = '' 147 The path to a file containing the credentials to use when binding 148 to the LDAP server (if not binding anonymously). 149 ''; 150 }; 151 152 timeLimit = mkOption { 153 default = 30; 154 type = types.int; 155 description = '' 156 Specifies the time limit (in seconds) to use when connecting 157 to the directory server. This is distinct from the time limit 158 specified in <literal>users.ldap.timeLimit</literal> and affects 159 the initial server connection only. 160 ''; 161 }; 162 163 policy = mkOption { 164 default = "hard_open"; 165 type = types.enum [ "hard_open" "hard_init" "soft" ]; 166 description = '' 167 Specifies the policy to use for reconnecting to an unavailable 168 LDAP server. The default is <literal>hard_open</literal>, which 169 reconnects if opening the connection to the directory server 170 failed. By contrast, <literal>hard_init</literal> reconnects if 171 initializing the connection failed. Initializing may not 172 actually contact the directory server, and it is possible that 173 a malformed configuration file will trigger reconnection. If 174 <literal>soft</literal> is specified, then 175 <literal>nss_ldap</literal> will return immediately on server 176 failure. All hard reconnect policies block with exponential 177 backoff before retrying. 178 ''; 179 }; 180 }; 181 182 extraConfig = mkOption { 183 default = ""; 184 type = types.lines; 185 description = '' 186 Extra configuration options that will be added verbatim at 187 the end of the ldap configuration file (ldap.conf). 188 If <literal>users.ldap.daemon</literal> is enabled, this 189 configuration will not be used. In that case, use 190 <literal>users.ldap.daemon.extraConfig</literal> instead. 191 '' ; 192 }; 193 194 }; 195 196 }; 197 198 ###### implementation 199 200 config = mkIf cfg.enable { 201 202 environment.etc = if cfg.daemon.enable then [nslcdConfig] else [ldapConfig]; 203 204 system.activationScripts = mkIf insertLdapPassword { 205 ldap = stringAfter [ "etc" "groups" "users" ] '' 206 if test -f "${cfg.bind.password}" ; then 207 echo "bindpw "$(cat ${cfg.bind.password})"" | cat ${ldapConfig.source} - > /etc/ldap.conf.bindpw 208 mv -fT /etc/ldap.conf.bindpw /etc/ldap.conf 209 chmod 600 /etc/ldap.conf 210 fi 211 ''; 212 }; 213 214 system.nssModules = singleton ( 215 if cfg.daemon.enable then nss_pam_ldapd else nss_ldap 216 ); 217 218 users = mkIf cfg.daemon.enable { 219 extraGroups.nslcd = { 220 gid = config.ids.gids.nslcd; 221 }; 222 223 extraUsers.nslcd = { 224 uid = config.ids.uids.nslcd; 225 description = "nslcd user."; 226 group = "nslcd"; 227 }; 228 }; 229 230 systemd.services = mkIf cfg.daemon.enable { 231 232 nslcd = { 233 wantedBy = [ "multi-user.target" ]; 234 235 preStart = '' 236 mkdir -p /run/nslcd 237 rm -f /run/nslcd/nslcd.pid; 238 chown nslcd.nslcd /run/nslcd 239 ${optionalString (cfg.bind.distinguishedName != "") '' 240 if test -s "${cfg.bind.password}" ; then 241 ln -sfT "${cfg.bind.password}" /run/nslcd/bindpw 242 fi 243 ''} 244 ''; 245 246 serviceConfig = { 247 ExecStart = "${nss_pam_ldapd}/sbin/nslcd"; 248 Type = "forking"; 249 PIDFile = "/run/nslcd/nslcd.pid"; 250 Restart = "always"; 251 }; 252 }; 253 254 }; 255 256 }; 257}