1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 nssModulesPath = config.system.nssModules.path;
8 cfg = config.services.nscd;
9
10in
11
12{
13
14 ###### interface
15
16 options = {
17
18 services.nscd = {
19
20 enable = mkOption {
21 type = types.bool;
22 default = true;
23 description = lib.mdDoc ''
24 Whether to enable the Name Service Cache Daemon.
25 Disabling this is strongly discouraged, as this effectively disables NSS Lookups
26 from all non-glibc NSS modules, including the ones provided by systemd.
27 '';
28 };
29
30 enableNsncd = mkOption {
31 type = types.bool;
32 default = false;
33 description = lib.mdDoc ''
34 Whether to use nsncd instead of nscd.
35 This is a nscd-compatible daemon, that proxies lookups, without any caching.
36 '';
37 };
38
39 user = mkOption {
40 type = types.str;
41 default = "nscd";
42 description = lib.mdDoc ''
43 User account under which nscd runs.
44 '';
45 };
46
47 group = mkOption {
48 type = types.str;
49 default = "nscd";
50 description = lib.mdDoc ''
51 User group under which nscd runs.
52 '';
53 };
54
55 config = mkOption {
56 type = types.lines;
57 default = builtins.readFile ./nscd.conf;
58 description = lib.mdDoc "Configuration to use for Name Service Cache Daemon.";
59 };
60
61 package = mkOption {
62 type = types.package;
63 default =
64 if pkgs.stdenv.hostPlatform.libc == "glibc"
65 then pkgs.stdenv.cc.libc.bin
66 else pkgs.glibc.bin;
67 defaultText = lib.literalExpression ''
68 if pkgs.stdenv.hostPlatform.libc == "glibc"
69 then pkgs.stdenv.cc.libc.bin
70 else pkgs.glibc.bin;
71 '';
72 description = lib.mdDoc ''
73 package containing the nscd binary to be used by the service.
74 Ignored when enableNsncd is set to true.
75 '';
76 };
77
78 };
79
80 };
81
82
83 ###### implementation
84
85 config = mkIf cfg.enable {
86 environment.etc."nscd.conf".text = cfg.config;
87
88 users.users.${cfg.user} = {
89 isSystemUser = true;
90 group = cfg.group;
91 };
92
93 users.groups.${cfg.group} = { };
94
95 systemd.services.nscd =
96 {
97 description = "Name Service Cache Daemon"
98 + lib.optionalString cfg.enableNsncd " (nsncd)";
99
100 before = [ "nss-lookup.target" "nss-user-lookup.target" ];
101 wants = [ "nss-lookup.target" "nss-user-lookup.target" ];
102 wantedBy = [ "multi-user.target" ];
103 requiredBy = [ "nss-lookup.target" "nss-user-lookup.target" ];
104
105 environment = { LD_LIBRARY_PATH = nssModulesPath; };
106
107 restartTriggers = lib.optionals (!cfg.enableNsncd) ([
108 config.environment.etc.hosts.source
109 config.environment.etc."nsswitch.conf".source
110 config.environment.etc."nscd.conf".source
111 ] ++ optionals config.users.mysql.enable [
112 config.environment.etc."libnss-mysql.cfg".source
113 config.environment.etc."libnss-mysql-root.cfg".source
114 ]);
115
116 # In some configurations, nscd needs to be started as root; it will
117 # drop privileges after all the NSS modules have read their
118 # configuration files. So prefix the ExecStart command with "!" to
119 # prevent systemd from dropping privileges early. See ExecStart in
120 # systemd.service(5). We use a static user, because some NSS modules
121 # sill want to read their configuration files after the privilege drop
122 # and so users can set the owner of those files to the nscd user.
123 serviceConfig =
124 {
125 ExecStart =
126 if cfg.enableNsncd then "${pkgs.nsncd}/bin/nsncd"
127 else "!@${cfg.package}/bin/nscd nscd";
128 Type = if cfg.enableNsncd then "notify" else "forking";
129 User = cfg.user;
130 Group = cfg.group;
131 RemoveIPC = true;
132 PrivateTmp = true;
133 NoNewPrivileges = true;
134 RestrictSUIDSGID = true;
135 ProtectSystem = "strict";
136 ProtectHome = "read-only";
137 RuntimeDirectory = "nscd";
138 PIDFile = "/run/nscd/nscd.pid";
139 Restart = "always";
140 ExecReload =
141 lib.optionals (!cfg.enableNsncd) [
142 "${cfg.package}/bin/nscd --invalidate passwd"
143 "${cfg.package}/bin/nscd --invalidate group"
144 "${cfg.package}/bin/nscd --invalidate hosts"
145 ];
146 };
147 };
148 };
149}