From 93f185df6555de235e7d188682ea54767d8cfbc2 Mon Sep 17 00:00:00 2001 From: Jamey Sharp Date: Wed, 3 Jul 2019 12:26:47 -0700 Subject: [PATCH 1/7] nixos/nscd: no longer need to wait for readiness This postStart step was introduced on 2014-04-24 with the comment that "Nscd forks into the background before it's ready to accept connections." However, that was fixed upstream almost two months earlier, on 2014-03-03, with the comment that "This, along with setting the nscd service type to forking in its systemd configuration file, allows systemd to be certain that the nscd service is ready and is accepting connections." The fix was released several months later in glibc 2.20, which was merged in NixOS sometime before 15.09, so it certainly should be safe to remove this workaround by now. --- nixos/modules/services/system/nscd.nix | 9 --------- 1 file changed, 9 deletions(-) diff --git a/nixos/modules/services/system/nscd.nix b/nixos/modules/services/system/nscd.nix index fd1570d1198..d9444a279ea 100644 --- a/nixos/modules/services/system/nscd.nix +++ b/nixos/modules/services/system/nscd.nix @@ -75,15 +75,6 @@ in "${pkgs.glibc.bin}/sbin/nscd --invalidate hosts" ]; }; - - # Urgggggh... Nscd forks before opening its socket and writing - # its pid. So wait until it's ready. - postStart = - '' - while ! ${pkgs.glibc.bin}/sbin/nscd -g > /dev/null; do - sleep 0.2 - done - ''; }; }; From 597563d248470857470481681e3d187866c4a3b7 Mon Sep 17 00:00:00 2001 From: Jamey Sharp Date: Wed, 3 Jul 2019 12:39:48 -0700 Subject: [PATCH 2/7] nixos/nscd: let systemd manage directories Previously this module created both /var/db/nscd and /run/nscd using shell commands in a preStart script. Note that both of these paths are hard-coded in the nscd source. (Well, the latter is actually /var/run/nscd but /var/run is a symlink to /run so it works out the same.) /var/db/nscd is only used if the nscd.conf "persistent" option is turned on for one or more databases, which it is not in our default config file. I'm not even sure persistent mode can work under systemd, since `nscd --shutdown` is not synchronous so systemd will always unceremoniously kill nscd without reliably giving it time to mark the databases as unused. Nonetheless, if someone wants to use that option, they can ensure the directory exists using systemd.tmpfiles.rules. systemd can create /run/nscd for us with the RuntimeDirectory directive, with the added benefit of causing systemd to delete the directory on service stop or restart. The default value of RuntimeDirectoryMode is 755, the same as the mode which this module was using before. I don't think the `rm -f /run/nscd/nscd.pid` was necessary after NixOS switched to systemd and used its PIDFile directive, because systemd deletes the specified file after the service stops, and because the file can't persist across reboots since /run is a tmpfs. Even if the file still exists when nscd starts, it's only a problem if the pid it contains has been reused by another process, which is unlikely. Anyway, this change makes that deletion even less necessary, because now systemd deletes the entire /run/nscd directory when the service stops. --- nixos/modules/services/system/nscd.nix | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/nixos/modules/services/system/nscd.nix b/nixos/modules/services/system/nscd.nix index d9444a279ea..14644003539 100644 --- a/nixos/modules/services/system/nscd.nix +++ b/nixos/modules/services/system/nscd.nix @@ -51,13 +51,6 @@ in environment = { LD_LIBRARY_PATH = nssModulesPath; }; - preStart = - '' - mkdir -m 0755 -p /run/nscd - rm -f /run/nscd/nscd.pid - mkdir -m 0755 -p /var/db/nscd - ''; - restartTriggers = [ config.environment.etc.hosts.source config.environment.etc."nsswitch.conf".source @@ -67,6 +60,7 @@ in serviceConfig = { ExecStart = "@${pkgs.glibc.bin}/sbin/nscd nscd"; Type = "forking"; + RuntimeDirectory = "nscd"; PIDFile = "/run/nscd/nscd.pid"; Restart = "always"; ExecReload = From de251704d66331f61417b9eaa42c58270ea6c766 Mon Sep 17 00:00:00 2001 From: Jamey Sharp Date: Wed, 3 Jul 2019 13:11:05 -0700 Subject: [PATCH 3/7] nixos/nscd: run with a dynamic user nscd doesn't create any files outside of /run/nscd unless the nscd.conf "persistent" option is used, which we don't do by default. Therefore it doesn't matter what UID/GID we run this service as, so long as it isn't shared with any other running processes. /run/nscd does need to be owned by the same UID that the service is running as, but systemd takes care of that for us thanks to the RuntimeDirectory directive. If someone wants to turn on the "persistent" option, they need to manually configure users.users.nscd and systemd.tmpfiles.rules so that /var/db/nscd is owned by the same user that nscd runs as. In an all-defaults boot.isContainer configuration of NixOS, this removes the only user which did not have a pre-assigned UID. --- nixos/modules/services/system/nscd.conf | 1 - nixos/modules/services/system/nscd.nix | 7 ++----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/nixos/modules/services/system/nscd.conf b/nixos/modules/services/system/nscd.conf index 603a5d01acc..b294e933918 100644 --- a/nixos/modules/services/system/nscd.conf +++ b/nixos/modules/services/system/nscd.conf @@ -6,7 +6,6 @@ # fallback to trying to handle the request by itself. Which won't work as glibc # is not aware of the path in which the nss modules live. As a workaround, we # have `enable-cache yes` with an explicit ttl of 0 -server-user nscd threads 1 paranoia no debug-level 0 diff --git a/nixos/modules/services/system/nscd.nix b/nixos/modules/services/system/nscd.nix index 14644003539..cf034caa128 100644 --- a/nixos/modules/services/system/nscd.nix +++ b/nixos/modules/services/system/nscd.nix @@ -39,11 +39,6 @@ in config = mkIf cfg.enable { environment.etc."nscd.conf".text = cfg.config; - users.users.nscd = - { isSystemUser = true; - description = "Name service cache daemon user"; - }; - systemd.services.nscd = { description = "Name Service Cache Daemon"; @@ -60,6 +55,8 @@ in serviceConfig = { ExecStart = "@${pkgs.glibc.bin}/sbin/nscd nscd"; Type = "forking"; + User = "nscd"; + DynamicUser = true; RuntimeDirectory = "nscd"; PIDFile = "/run/nscd/nscd.pid"; Restart = "always"; From 4c64375e91ca400c646316ae2da8d3603aebfb9c Mon Sep 17 00:00:00 2001 From: Jamey Sharp Date: Wed, 3 Jul 2019 15:30:17 -0700 Subject: [PATCH 4/7] nixos/nscd: delete redundant nscd.conf options These options were being set to the same value as the defaults that are hardcoded in nscd. Delete them so it's clear which settings are actually important for NixOS. One exception is `threads 1`, which is different from the built-in default of 4. However, both values are equivalent because nscd forces the number of threads to be at least as many as the number of kinds of databases it supports, which is 5. --- nixos/modules/services/system/nscd.conf | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/nixos/modules/services/system/nscd.conf b/nixos/modules/services/system/nscd.conf index b294e933918..bd802bd3c2e 100644 --- a/nixos/modules/services/system/nscd.conf +++ b/nixos/modules/services/system/nscd.conf @@ -6,46 +6,28 @@ # fallback to trying to handle the request by itself. Which won't work as glibc # is not aware of the path in which the nss modules live. As a workaround, we # have `enable-cache yes` with an explicit ttl of 0 -threads 1 -paranoia no -debug-level 0 enable-cache passwd yes positive-time-to-live passwd 0 negative-time-to-live passwd 0 -suggested-size passwd 211 -check-files passwd yes -persistent passwd no shared passwd yes enable-cache group yes positive-time-to-live group 0 negative-time-to-live group 0 -suggested-size group 211 -check-files group yes -persistent group no shared group yes enable-cache netgroup yes positive-time-to-live netgroup 0 negative-time-to-live netgroup 0 -suggested-size netgroup 211 -check-files netgroup yes -persistent netgroup no shared netgroup yes enable-cache hosts yes positive-time-to-live hosts 600 negative-time-to-live hosts 0 -suggested-size hosts 211 -check-files hosts yes -persistent hosts no shared hosts yes enable-cache services yes positive-time-to-live services 0 negative-time-to-live services 0 -suggested-size services 211 -check-files services yes -persistent services no shared services yes From c38fa99757baec0ba04c41985783b6f63a58ced2 Mon Sep 17 00:00:00 2001 From: Jamey Sharp Date: Sat, 6 Jul 2019 09:24:49 -0700 Subject: [PATCH 5/7] nixos/nscd: don't need to specify username Thanks to @arianvp for pointing out that when DynamicUser is true, systemd defaults the value of User to be the name of the unit, which in this case is already "nscd". --- nixos/modules/services/system/nscd.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/nixos/modules/services/system/nscd.nix b/nixos/modules/services/system/nscd.nix index cf034caa128..d094e9893ff 100644 --- a/nixos/modules/services/system/nscd.nix +++ b/nixos/modules/services/system/nscd.nix @@ -55,7 +55,6 @@ in serviceConfig = { ExecStart = "@${pkgs.glibc.bin}/sbin/nscd nscd"; Type = "forking"; - User = "nscd"; DynamicUser = true; RuntimeDirectory = "nscd"; PIDFile = "/run/nscd/nscd.pid"; From f7c776760babb4f2d5d4341a5dbd882bf7751e9c Mon Sep 17 00:00:00 2001 From: Jamey Sharp Date: Sun, 7 Jul 2019 08:43:41 -0700 Subject: [PATCH 6/7] nixos/nscd: only drop privs after nss module init NixOS usually needs nscd just to have a single place where LD_LIBRARY_PATH can be set to include all NSS modules, but nscd is also useful if some of the NSS modules need to read files which are only accessible by root. For example, nixos/modules/config/ldap.nix needs this when users.ldap.enable = true; users.ldap.daemon.enable = false; and users.ldap.bind.passwordFile exists. In that case, the module creates an /etc/ldap.conf which is only readable by root, but which the NSS module needs to read in order to find out what LDAP server to connect to and with what credentials. If nscd is started as root and configured with the server-user option in nscd.conf, then it gives each NSS module the opportunity to initialize itself before dropping privileges. The initialization happens in the glibc-internal __nss_disable_nscd function, which pre-loads all the configured NSS modules for passwd, group, hosts, and services (but not netgroup for some reason?) and, for each loaded module, calls an init function if one is defined. After that finishes, nscd's main() calls nscd_init() which ends by calling finish_drop_privileges(). There are provisions in systemd for using DynamicUser with a service which needs to drop privileges itself, so this patch does that. --- nixos/modules/services/system/nscd.conf | 1 + nixos/modules/services/system/nscd.nix | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/nixos/modules/services/system/nscd.conf b/nixos/modules/services/system/nscd.conf index bd802bd3c2e..2b7523a7346 100644 --- a/nixos/modules/services/system/nscd.conf +++ b/nixos/modules/services/system/nscd.conf @@ -6,6 +6,7 @@ # fallback to trying to handle the request by itself. Which won't work as glibc # is not aware of the path in which the nss modules live. As a workaround, we # have `enable-cache yes` with an explicit ttl of 0 +server-user nscd enable-cache passwd yes positive-time-to-live passwd 0 diff --git a/nixos/modules/services/system/nscd.nix b/nixos/modules/services/system/nscd.nix index d094e9893ff..c2d0cd5d0eb 100644 --- a/nixos/modules/services/system/nscd.nix +++ b/nixos/modules/services/system/nscd.nix @@ -53,7 +53,7 @@ in ]; serviceConfig = - { ExecStart = "@${pkgs.glibc.bin}/sbin/nscd nscd"; + { ExecStart = "!@${pkgs.glibc.bin}/sbin/nscd nscd"; Type = "forking"; DynamicUser = true; RuntimeDirectory = "nscd"; From d79584c90253107d8d29869de0951545a567554a Mon Sep 17 00:00:00 2001 From: Jamey Sharp Date: Fri, 12 Jul 2019 12:07:45 -0700 Subject: [PATCH 7/7] nixos/nscd: document why it is configured this way --- nixos/modules/services/system/nscd.nix | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/nixos/modules/services/system/nscd.nix b/nixos/modules/services/system/nscd.nix index c2d0cd5d0eb..e11f7e049d8 100644 --- a/nixos/modules/services/system/nscd.nix +++ b/nixos/modules/services/system/nscd.nix @@ -52,6 +52,12 @@ in config.environment.etc."nscd.conf".source ]; + # We use DynamicUser because in default configurations nscd doesn't + # create any files that need to survive restarts. However, in some + # configurations, nscd needs to be started as root; it will drop + # privileges after all the NSS modules have read their configuration + # files. So prefix the ExecStart command with "!" to prevent systemd + # from dropping privileges early. See ExecStart in systemd.service(5). serviceConfig = { ExecStart = "!@${pkgs.glibc.bin}/sbin/nscd nscd"; Type = "forking";