25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 
 
 

295 satır
9.3 KiB

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