Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide NSS modules globally, make nscd unnecessary (v2) #1

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 11 additions & 34 deletions nixos/modules/config/nsswitch.nix
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,22 @@ with lib;

{
options = {

# NSS modules. Hacky!
# Only works with nscd!
system.nssModules = mkOption {
type = types.listOf types.path;
internal = true;
default = [];
description = ''
Search path for NSS (Name Service Switch) modules. This allows
several DNS resolution methods to be specified via
Path containing NSS (Name Service Switch) modules.
This allows several DNS resolution methods to be specified via
<filename>/etc/nsswitch.conf</filename>.
'';
apply = list:
{
inherit list;
path = makeLibraryPath list;
path = pkgs.symlinkJoin {
name = "nss-modules";
paths = list;
};
};
};

Expand All @@ -30,10 +30,6 @@ with lib;
type = types.listOf types.str;
description = ''
List of passwd entries to configure in <filename>/etc/nsswitch.conf</filename>.

Note that "files" is always prepended while "systemd" is appended if nscd is enabled.

This option only takes effect if nscd is enabled.
'';
default = [];
};
Expand All @@ -42,10 +38,6 @@ with lib;
type = types.listOf types.str;
description = ''
List of group entries to configure in <filename>/etc/nsswitch.conf</filename>.

Note that "files" is always prepended while "systemd" is appended if nscd is enabled.

This option only takes effect if nscd is enabled.
'';
default = [];
};
Expand All @@ -54,10 +46,6 @@ with lib;
type = types.listOf types.str;
description = ''
List of shadow entries to configure in <filename>/etc/nsswitch.conf</filename>.

Note that "files" is always prepended.

This option only takes effect if nscd is enabled.
'';
default = [];
};
Expand All @@ -66,10 +54,6 @@ with lib;
type = types.listOf types.str;
description = ''
List of hosts entries to configure in <filename>/etc/nsswitch.conf</filename>.

Note that "files" is always prepended, and "dns" and "myhostname" are always appended.

This option only takes effect if nscd is enabled.
'';
default = [];
};
Expand All @@ -78,10 +62,6 @@ with lib;
type = types.listOf types.str;
description = ''
List of services entries to configure in <filename>/etc/nsswitch.conf</filename>.

Note that "files" is always prepended.

This option only takes effect if nscd is enabled.
'';
default = [];
};
Expand All @@ -93,14 +73,11 @@ with lib;
];

config = {
assertions = [
{
# Prevent users from disabling nscd, with nssModules being set.
# If disabling nscd is really necessary, it's still possible to opt out
# by forcing config.system.nssModules to [].
assertion = config.system.nssModules.path != "" -> config.services.nscd.enable;
message = "Loading NSS modules from system.nssModules (${config.system.nssModules.path}), requires services.nscd.enable being set to true.";
}
# Provide NSS modules at a platform-specific path in /run
systemd.tmpfiles.rules = let
glibcPlatform = "${if pkgs.stdenv.hostPlatform.is64bit then "64" else "32"}-${pkgs.glibc.version}";
in [
"L+ /run/nss-modules-${glibcPlatform} - - - - ${config.system.nssModules.path}"
];

# Name Service Switch configuration file. Required by the C
Expand Down
4 changes: 0 additions & 4 deletions nixos/modules/services/network-filesystems/samba.nix
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ let
${smbToString (map shareConfig (attrNames cfg.shares))}
'');

# This may include nss_ldap, needed for samba if it has to use ldap.
nssModulesPath = config.system.nssModules.path;

daemonService = appName: args:
{ description = "Samba Service Daemon ${appName}";

Expand All @@ -44,7 +41,6 @@ let
partOf = [ "samba.target" ];

environment = {
LD_LIBRARY_PATH = nssModulesPath;
LOCALE_ARCHIVE = "/run/current-system/sw/lib/locale/locale-archive";
};

Expand Down
4 changes: 0 additions & 4 deletions nixos/modules/services/networking/avahi-daemon.nix
Original file line number Diff line number Diff line change
Expand Up @@ -264,10 +264,6 @@ in
wantedBy = [ "multi-user.target" ];
requires = [ "avahi-daemon.socket" ];

# Make NSS modules visible so that `avahi_nss_support ()' can
# return a sensible value.
environment.LD_LIBRARY_PATH = config.system.nssModules.path;

path = [ pkgs.coreutils pkgs.avahi ];

serviceConfig = {
Expand Down
4 changes: 0 additions & 4 deletions nixos/modules/services/networking/ssh/lshd.nix
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,6 @@ in

wantedBy = [ "multi-user.target" ];

environment = {
LD_LIBRARY_PATH = config.system.nssModules.path;
};

preStart = ''
test -d /etc/lsh || mkdir -m 0755 -p /etc/lsh
test -d /var/spool/lsh || mkdir -m 0755 -p /var/spool/lsh
Expand Down
3 changes: 0 additions & 3 deletions nixos/modules/services/networking/ssh/sshd.nix
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ let
cfg = config.services.openssh;
cfgc = config.programs.ssh;

nssModulesPath = config.system.nssModules.path;

userOptions = {

options.openssh.authorizedKeys = {
Expand Down Expand Up @@ -425,7 +423,6 @@ in
after = [ "network.target" ];
stopIfChanged = false;
path = [ cfgc.package pkgs.gawk ];
environment.LD_LIBRARY_PATH = nssModulesPath;

restartTriggers = optionals (!cfg.startWhenNeeded) [
config.environment.etc."ssh/sshd_config".source
Expand Down
1 change: 0 additions & 1 deletion nixos/modules/services/system/dbus.nix
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ in
# Don't restart dbus-daemon. Bad things tend to happen if we do.
reloadIfChanged = true;
restartTriggers = [ configDir ];
environment = { LD_LIBRARY_PATH = config.system.nssModules.path; };
};

systemd.user = {
Expand Down
8 changes: 0 additions & 8 deletions nixos/modules/services/system/nscd.conf
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
# We basically use nscd as a proxy for forwarding nss requests to appropriate
# nss modules, as we run nscd with LD_LIBRARY_PATH set to the directory
# containing all such modules
# Note that we can not use `enable-cache no` As this will actually cause nscd
# to just reject the nss requests it receives, which then causes glibc to
# 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
Expand Down
18 changes: 10 additions & 8 deletions nixos/modules/services/system/nscd.nix
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ with lib;

let

nssModulesPath = config.system.nssModules.path;
cfg = config.services.nscd;

nscd = if pkgs.stdenv.hostPlatform.libc == "glibc"
Expand All @@ -26,8 +25,10 @@ in
default = true;
description = ''
Whether to enable the Name Service Cache Daemon.
Disabling this is strongly discouraged, as this effectively disables NSS Lookups
from all non-glibc NSS modules, including the ones provided by systemd.

When this option is disabled, NSS lookups from non-glibc NSS modules are disabled for:
- binaries that use a glibc version different from the system glibc
- 32-bit binaries on 64-bit hosts.
'';
};

Expand All @@ -48,14 +49,13 @@ in
environment.etc."nscd.conf".text = cfg.config;

systemd.services.nscd =
{ description = "Name Service Cache Daemon";
{
description = "Name Service Cache Daemon";

before = [ "nss-lookup.target" "nss-user-lookup.target" ];
wants = [ "nss-lookup.target" "nss-user-lookup.target" ];
wantedBy = [ "multi-user.target" ];

environment = { LD_LIBRARY_PATH = nssModulesPath; };

restartTriggers = [
config.environment.etc.hosts.source
config.environment.etc."nsswitch.conf".source
Expand All @@ -69,14 +69,16 @@ in
# files. So prefix the ExecStart command with "!" to prevent systemd
# from dropping privileges early. See ExecStart in systemd.service(5).
serviceConfig =
{ ExecStart = "!@${nscd}/sbin/nscd nscd";
{
ExecStart = "!@${nscd}/sbin/nscd nscd";
Type = "forking";
DynamicUser = true;
RuntimeDirectory = "nscd";
PIDFile = "/run/nscd/nscd.pid";
Restart = "always";
ExecReload =
[ "${nscd}/sbin/nscd --invalidate passwd"
[
"${nscd}/sbin/nscd --invalidate passwd"
"${nscd}/sbin/nscd --invalidate group"
"${nscd}/sbin/nscd --invalidate hosts"
];
Expand Down
1 change: 0 additions & 1 deletion nixos/modules/system/boot/resolved.nix
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,6 @@ in

users.users.systemd-resolve.group = "systemd-resolve";

# add resolve to nss hosts database if enabled and nscd enabled
# system.nssModules is configured in nixos/modules/system/boot/systemd.nix
# added with order 501 to allow modules to go before with mkBefore
system.nssDatabases.hosts = (mkOrder 501 ["resolve [!UNAVAIL=return]"]);
Expand Down
1 change: 1 addition & 0 deletions nixos/tests/all-tests.nix
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ in
nomad = handleTest ./nomad.nix {};
novacomd = handleTestOn ["x86_64-linux"] ./novacomd.nix {};
nsd = handleTest ./nsd.nix {};
nssmodules-without-nscd = handleTest ./nssmodules-without-nscd.nix {};
nzbget = handleTest ./nzbget.nix {};
nzbhydra2 = handleTest ./nzbhydra2.nix {};
oh-my-zsh = handleTest ./oh-my-zsh.nix {};
Expand Down
21 changes: 21 additions & 0 deletions nixos/tests/nssmodules-without-nscd.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Ensure that NSS modules are accessible by glibc client binaries when
# nscd is disabled

import ./make-test-python.nix ({ lib, ... } : {
name = "nssmodules-without-nscd";

meta = with lib.maintainers; {
maintainers = [ earvstedt flokli ];
};

nodes.node = {
services.nscd.enable = false;
};

# Test dynamic user resolution via `libnss_systemd.so` which is only available
# through `system.nssModules`
testScript = ''
node.succeed("systemd-run --property=DynamicUser=yes --property=User=testuser sleep infinity")
node.succeed("getent passwd testuser")
'';
})
47 changes: 47 additions & 0 deletions pkgs/development/libraries/glibc/add-extra-module-load-path.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
Add NSS module load path /run/nss-modules-${word_size}-${glibc_version}/lib
as a fallback. Previously, glibc only looked for NSS modules in ${glibc.out}/lib and
LD_LIBRARY_PATH.

On NixOS, this removes the dependency on nscd for enabling NSS functionality in
glibc clients.
nscd has caching bugs and leaks DNS requests across network namespaces.

The module load path is only used by binaries that use the same glibc
version and word size as the NSS modules. This avoids failures due to ABI
incompatibilities. Incompatible binaries can still be served by nscd.

On non-NixOS systems, this patch doesn't change behaviour, as the path
doesn't exist there.

diff --git a/nss/nss_module.c b/nss/nss_module.c
index 6c5f341f..80b6eac0 100644
--- a/nss/nss_module.c
+++ b/nss/nss_module.c
@@ -133,5 +133,27 @@ module_load (struct nss_module *module)
return false;

handle = __libc_dlopen (shlib_name);
+
+ /* After loading from the default locations, try loading from
+ the NixOS module load path. */
+ if (handle == NULL) {
+
+ #define STR_(x) #x
+ #define STR(x) STR_(x)
+
+ const char nix_nss_path[] = "/run/nss-modules-" STR(__WORDSIZE) "-"
+ STR(__GLIBC__) "." STR(__GLIBC_MINOR__) "/lib/";
+ char shlib_path[1024];
+ size_t nix_nss_path_len = sizeof(nix_nss_path) - 1;
+ size_t shlib_name_len = strlen(shlib_name);
+ size_t shlib_path_len = nix_nss_path_len + shlib_name_len;
+
+ if (shlib_path_len < sizeof(shlib_path)) {
+ memcpy(&shlib_path[0], nix_nss_path, nix_nss_path_len);
+ memcpy(&shlib_path[nix_nss_path_len], shlib_name, shlib_name_len + 1);
+ handle = __libc_dlopen(shlib_path);
+ }
+ }
+
free (shlib_name);
}
2 changes: 2 additions & 0 deletions pkgs/development/libraries/glibc/common.nix
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ stdenv.mkDerivation ({

/* https://github.com/NixOS/nixpkgs/pull/137601 */
./nix-nss-open-files.patch

./add-extra-module-load-path.patch
]
++ lib.optional stdenv.hostPlatform.isMusl ./fix-rpc-types-musl-conflicts.patch
++ lib.optional stdenv.buildPlatform.isDarwin ./darwin-cross-build.patch;
Expand Down