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