diff --git a/Makefile-man.am b/Makefile-man.am
index 8ab733360d..3ac1906a4a 100644
--- a/Makefile-man.am
+++ b/Makefile-man.am
@@ -23,6 +23,7 @@ MANPAGES += \
man/localtime.5 \
man/machine-id.5 \
man/machine-info.5 \
+ man/nss-systemd.8 \
man/os-release.5 \
man/sd-bus-errors.3 \
man/sd-bus.3 \
@@ -255,6 +256,7 @@ MANPAGES_ALIAS += \
man/SD_WARNING.3 \
man/init.1 \
man/journald.conf.d.5 \
+ man/libnss_systemd.so.2.8 \
man/poweroff.8 \
man/reboot.8 \
man/sd_bus_creds_get_audit_login_uid.3 \
@@ -587,6 +589,7 @@ man/SD_NOTICE.3: man/sd-daemon.3
man/SD_WARNING.3: man/sd-daemon.3
man/init.1: man/systemd.1
man/journald.conf.d.5: man/journald.conf.5
+man/libnss_systemd.so.2.8: man/nss-systemd.8
man/poweroff.8: man/halt.8
man/reboot.8: man/halt.8
man/sd_bus_creds_get_audit_login_uid.3: man/sd_bus_creds_get_pid.3
@@ -1071,6 +1074,9 @@ man/init.html: man/systemd.html
man/journald.conf.d.html: man/journald.conf.html
$(html-alias)
+man/libnss_systemd.so.2.html: man/nss-systemd.html
+ $(html-alias)
+
man/poweroff.html: man/halt.html
$(html-alias)
@@ -2519,6 +2525,7 @@ EXTRA_DIST += \
man/nss-myhostname.xml \
man/nss-mymachines.xml \
man/nss-resolve.xml \
+ man/nss-systemd.xml \
man/os-release.xml \
man/pam_systemd.xml \
man/resolved.conf.xml \
diff --git a/Makefile.am b/Makefile.am
index 3d5ce1e2c3..a4241122d5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -5001,6 +5001,27 @@ test_nss_LDADD = \
manual_tests += \
test-nss
+# ------------------------------------------------------------------------------
+libnss_systemd_la_SOURCES = \
+ src/nss-systemd/nss-systemd.sym \
+ src/nss-systemd/nss-systemd.c
+
+libnss_systemd_la_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ -module \
+ -export-dynamic \
+ -avoid-version \
+ -shared \
+ -shrext .so.2 \
+ -Wl,--version-script=$(top_srcdir)/src/nss-systemd/nss-systemd.sym
+
+libnss_systemd_la_LIBADD = \
+ libsystemd-internal.la \
+ libbasic.la
+
+lib_LTLIBRARIES += \
+ libnss_systemd.la
+
# ------------------------------------------------------------------------------
if HAVE_MYHOSTNAME
libnss_myhostname_la_SOURCES = \
diff --git a/README b/README
index ca8993cb12..19c15a70b0 100644
--- a/README
+++ b/README
@@ -201,7 +201,7 @@ USERS AND GROUPS:
"systemd-coredump" system user and group to exist.
NSS:
- systemd ships with three NSS modules:
+ systemd ships with four glibc NSS modules:
nss-myhostname resolves the local hostname to locally
configured IP addresses, as well as "localhost" to
@@ -210,15 +210,22 @@ NSS:
nss-resolve enables DNS resolution via the systemd-resolved
DNS/LLMNR caching stub resolver "systemd-resolved".
- nss-mymachines enables resolution of all local containers
- registered with machined to their respective IP addresses.
+ nss-mymachines enables resolution of all local containers registered
+ with machined to their respective IP addresses. It also maps UID/GIDs
+ ranges used by containers to useful names.
- To make use of these NSS modules, please add them to the
- "hosts: " line in /etc/nsswitch.conf. The "resolve" module
- should replace the glibc "dns" module in this file.
+ nss-systemd enables resolution of all dynamically allocated service
+ users. (See the DynamicUser= setting in unit files.)
- The three modules should be used in the following order:
+ To make use of these NSS modules, please add them to the "hosts:",
+ "passwd:" and "group:" lines in /etc/nsswitch.conf. The "resolve"
+ module should replace the glibc "dns" module in this file (and don't
+ worry, it chain-loads the "dns" module if it can't talk to resolved).
+ The four modules should be used in the following order:
+
+ passwd: compat mymachines systemd
+ group: compat mymachines systemd
hosts: files mymachines resolve myhostname
SYSV INIT.D SCRIPTS:
diff --git a/man/nss-myhostname.xml b/man/nss-myhostname.xml
index a920ec334f..b1daaba02b 100644
--- a/man/nss-myhostname.xml
+++ b/man/nss-myhostname.xml
@@ -106,8 +106,8 @@
Here is an example /etc/nsswitch.conf file that enables
nss-myhostname correctly:
-passwd: compat mymachines
-group: compat mymachines
+passwd: compat mymachines systemd
+group: compat mymachines systemd
shadow: compat
hosts: files mymachines resolve myhostname
@@ -138,6 +138,7 @@ netgroup: nis
See Also
systemd1,
+ nss-systemd8,
nss-resolve8,
nss-mymachines8,
nsswitch.conf5,
diff --git a/man/nss-mymachines.xml b/man/nss-mymachines.xml
index ec047449bf..a70119e256 100644
--- a/man/nss-mymachines.xml
+++ b/man/nss-mymachines.xml
@@ -82,8 +82,8 @@
Here is an example /etc/nsswitch.conf file that enables
nss-mymachines correctly:
- passwd: compat mymachines
-group: compat mymachines
+ passwd: compat mymachines systemd
+group: compat mymachines systemd
shadow: compat
hosts: files mymachines resolve myhostname
@@ -103,6 +103,7 @@ netgroup: nis
systemd1,
systemd-machined.service8,
+ nss-systemd8,
nss-resolve8,
nss-myhostname8,
nsswitch.conf5,
diff --git a/man/nss-resolve.xml b/man/nss-resolve.xml
index d9e56453e8..e6cc1d982a 100644
--- a/man/nss-resolve.xml
+++ b/man/nss-resolve.xml
@@ -81,8 +81,8 @@
Here is an example /etc/nsswitch.conf file that enables nss-resolve
correctly:
-passwd: compat mymachines
-group: compat mymachines
+passwd: compat mymachines systemd
+group: compat mymachines systemd
shadow: compat
hosts: files mymachines resolve myhostname
@@ -102,8 +102,9 @@ netgroup: nis
systemd1,
systemd-resolved8,
- nss-mymachines8,
+ nss-systemd8,
nss-myhostname8,
+ nss-mymachines8,
nsswitch.conf5
diff --git a/man/nss-systemd.xml b/man/nss-systemd.xml
new file mode 100644
index 0000000000..4228372e51
--- /dev/null
+++ b/man/nss-systemd.xml
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+
+
+ nss-systemd
+ systemd
+
+
+
+ Developer
+ Lennart
+ Poettering
+ lennart@poettering.net
+
+
+
+
+
+ nss-systemd
+ 8
+
+
+
+ nss-systemd
+ libnss_systemd.so.2
+ Provide UNIX user and group name resolution for dynamic users and groups.
+
+
+
+ libnss_systemd.so.2
+
+
+
+ Description
+
+ nss-systemd is a plug-in module for the GNU Name Service Switch (NSS) functionality of the
+ GNU C Library (glibc), providing UNIX user and group name resolution for dynamic users and
+ groups allocated through the DynamicUser= option in systemd unit files. See
+ systemd.exec5 for details on
+ this option.
+
+ To activate the NSS module, add systemd to the lines starting with
+ passwd: and group: in /etc/nsswitch.conf.
+
+ It is recommended to place systemd after the files or
+ compat entry of the /etc/nsswitch.conf lines so that
+ /etc/passwd and /etc/group based mappings take precedence.
+
+
+
+ Example
+
+ Here is an example /etc/nsswitch.conf file that enables
+ nss-systemd correctly:
+
+ passwd: compat mymachines systemd
+group: compat mymachines systemd
+shadow: compat
+
+hosts: files mymachines resolve myhostname
+networks: files
+
+protocols: db files
+services: db files
+ethers: db files
+rpc: db files
+
+netgroup: nis
+
+
+
+
+ See Also
+
+ systemd1,
+ systemd.exec5,
+ nss-resolve8,
+ nss-myhostname8,
+ nss-mymachines8,
+ nsswitch.conf5,
+ getent1
+
+
+
+
diff --git a/src/core/execute.c b/src/core/execute.c
index c186f2a705..26e9cd5339 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -1670,6 +1670,12 @@ static int exec_child(
if (context->dynamic_user && dcreds) {
+ /* Make sure we bypass our own NSS module for any NSS checks */
+ if (putenv((char*) "SYSTEMD_NSS_DYNAMIC_BYPASS=1") != 0) {
+ *exit_status = EXIT_USER;
+ return -errno;
+ }
+
r = dynamic_creds_realize(dcreds, &uid, &gid);
if (r < 0) {
*exit_status = EXIT_USER;
diff --git a/src/nss-systemd/Makefile b/src/nss-systemd/Makefile
new file mode 120000
index 0000000000..d0b0e8e008
--- /dev/null
+++ b/src/nss-systemd/Makefile
@@ -0,0 +1 @@
+../Makefile
\ No newline at end of file
diff --git a/src/nss-systemd/nss-systemd.c b/src/nss-systemd/nss-systemd.c
new file mode 100644
index 0000000000..e7a4393bb0
--- /dev/null
+++ b/src/nss-systemd/nss-systemd.c
@@ -0,0 +1,332 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see .
+***/
+
+#include
+
+#include "sd-bus.h"
+
+#include "bus-common-errors.h"
+#include "env-util.h"
+#include "macro.h"
+#include "nss-util.h"
+#include "signal-util.h"
+#include "user-util.h"
+#include "util.h"
+
+NSS_GETPW_PROTOTYPES(systemd);
+NSS_GETGR_PROTOTYPES(systemd);
+
+enum nss_status _nss_systemd_getpwnam_r(
+ const char *name,
+ struct passwd *pwd,
+ char *buffer, size_t buflen,
+ int *errnop) {
+
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+ uint32_t translated;
+ size_t l;
+ int r;
+
+ BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
+
+ assert(name);
+ assert(pwd);
+
+ /* Make sure that we don't go in circles when allocating a dynamic UID by checking our own database */
+ if (getenv_bool("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
+ goto not_found;
+
+ r = sd_bus_open_system(&bus);
+ if (r < 0)
+ goto fail;
+
+ r = sd_bus_call_method(bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "LookupDynamicUserByName",
+ &error,
+ &reply,
+ "s",
+ name);
+ if (r < 0) {
+ if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_DYNAMIC_USER))
+ goto not_found;
+
+ goto fail;
+ }
+
+ r = sd_bus_message_read(reply, "u", &translated);
+ if (r < 0)
+ goto fail;
+
+ l = strlen(name);
+ if (buflen < l+1) {
+ *errnop = ENOMEM;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ memcpy(buffer, name, l+1);
+
+ pwd->pw_name = buffer;
+ pwd->pw_uid = (uid_t) translated;
+ pwd->pw_gid = (uid_t) translated;
+ pwd->pw_gecos = (char*) "Dynamic User";
+ pwd->pw_passwd = (char*) "*"; /* locked */
+ pwd->pw_dir = (char*) "/";
+ pwd->pw_shell = (char*) "/sbin/nologin";
+
+ *errnop = 0;
+ return NSS_STATUS_SUCCESS;
+
+not_found:
+ *errnop = 0;
+ return NSS_STATUS_NOTFOUND;
+
+fail:
+ *errnop = -r;
+ return NSS_STATUS_UNAVAIL;
+}
+
+enum nss_status _nss_systemd_getpwuid_r(
+ uid_t uid,
+ struct passwd *pwd,
+ char *buffer, size_t buflen,
+ int *errnop) {
+
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+ const char *translated;
+ size_t l;
+ int r;
+
+ BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
+
+ if (!uid_is_valid(uid)) {
+ r = -EINVAL;
+ goto fail;
+ }
+
+ if (uid <= SYSTEM_UID_MAX)
+ goto not_found;
+
+ if (getenv_bool("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
+ goto not_found;
+
+ r = sd_bus_open_system(&bus);
+ if (r < 0)
+ goto fail;
+
+ r = sd_bus_call_method(bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "LookupDynamicUserByUID",
+ &error,
+ &reply,
+ "u",
+ (uint32_t) uid);
+ if (r < 0) {
+ if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_DYNAMIC_USER))
+ goto not_found;
+
+ goto fail;
+ }
+
+ r = sd_bus_message_read(reply, "s", &translated);
+ if (r < 0)
+ goto fail;
+
+ l = strlen(translated) + 1;
+ if (buflen < l) {
+ *errnop = ENOMEM;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ memcpy(buffer, translated, l);
+
+ pwd->pw_name = buffer;
+ pwd->pw_uid = uid;
+ pwd->pw_gid = uid;
+ pwd->pw_gecos = (char*) "Dynamic User";
+ pwd->pw_passwd = (char*) "*"; /* locked */
+ pwd->pw_dir = (char*) "/";
+ pwd->pw_shell = (char*) "/sbin/nologin";
+
+ *errnop = 0;
+ return NSS_STATUS_SUCCESS;
+
+not_found:
+ *errnop = 0;
+ return NSS_STATUS_NOTFOUND;
+
+fail:
+ *errnop = -r;
+ return NSS_STATUS_UNAVAIL;
+}
+
+enum nss_status _nss_systemd_getgrnam_r(
+ const char *name,
+ struct group *gr,
+ char *buffer, size_t buflen,
+ int *errnop) {
+
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+ uint32_t translated;
+ size_t l;
+ int r;
+
+ BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
+
+ assert(name);
+ assert(gr);
+
+ if (getenv_bool("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
+ goto not_found;
+
+ r = sd_bus_open_system(&bus);
+ if (r < 0)
+ goto fail;
+
+ r = sd_bus_call_method(bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "LookupDynamicUserByName",
+ &error,
+ &reply,
+ "s",
+ name);
+ if (r < 0) {
+ if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_DYNAMIC_USER))
+ goto not_found;
+
+ goto fail;
+ }
+
+ r = sd_bus_message_read(reply, "u", &translated);
+ if (r < 0)
+ goto fail;
+
+ l = sizeof(char*) + strlen(name) + 1;
+ if (buflen < l) {
+ *errnop = ENOMEM;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ memzero(buffer, sizeof(char*));
+ strcpy(buffer + sizeof(char*), name);
+
+ gr->gr_name = buffer + sizeof(char*);
+ gr->gr_gid = (gid_t) translated;
+ gr->gr_passwd = (char*) "*"; /* locked */
+ gr->gr_mem = (char**) buffer;
+
+ *errnop = 0;
+ return NSS_STATUS_SUCCESS;
+
+not_found:
+ *errnop = 0;
+ return NSS_STATUS_NOTFOUND;
+
+fail:
+ *errnop = -r;
+ return NSS_STATUS_UNAVAIL;
+}
+
+enum nss_status _nss_systemd_getgrgid_r(
+ gid_t gid,
+ struct group *gr,
+ char *buffer, size_t buflen,
+ int *errnop) {
+
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+ const char *translated;
+ size_t l;
+ int r;
+
+ BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
+
+ if (!gid_is_valid(gid)) {
+ r = -EINVAL;
+ goto fail;
+ }
+
+ if (gid <= SYSTEM_GID_MAX)
+ goto not_found;
+
+ if (getenv_bool("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
+ goto not_found;
+
+ r = sd_bus_open_system(&bus);
+ if (r < 0)
+ goto fail;
+
+ r = sd_bus_call_method(bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "LookupDynamicUserByUID",
+ &error,
+ &reply,
+ "u",
+ (uint32_t) gid);
+ if (r < 0) {
+ if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_DYNAMIC_USER))
+ goto not_found;
+
+ goto fail;
+ }
+
+ r = sd_bus_message_read(reply, "s", &translated);
+ if (r < 0)
+ goto fail;
+
+ l = sizeof(char*) + strlen(translated) + 1;
+ if (buflen < l) {
+ *errnop = ENOMEM;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ memzero(buffer, sizeof(char*));
+ strcpy(buffer + sizeof(char*), translated);
+
+ gr->gr_name = buffer + sizeof(char*);
+ gr->gr_gid = gid;
+ gr->gr_passwd = (char*) "*"; /* locked */
+ gr->gr_mem = (char**) buffer;
+
+ *errnop = 0;
+ return NSS_STATUS_SUCCESS;
+
+not_found:
+ *errnop = 0;
+ return NSS_STATUS_NOTFOUND;
+
+fail:
+ *errnop = -r;
+ return NSS_STATUS_UNAVAIL;
+}
diff --git a/src/nss-systemd/nss-systemd.sym b/src/nss-systemd/nss-systemd.sym
new file mode 100644
index 0000000000..955078788a
--- /dev/null
+++ b/src/nss-systemd/nss-systemd.sym
@@ -0,0 +1,17 @@
+/***
+ This file is part of systemd.
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+***/
+
+{
+global:
+ _nss_systemd_getpwnam_r;
+ _nss_systemd_getpwuid_r;
+ _nss_systemd_getgrnam_r;
+ _nss_systemd_getgrgid_r;
+local: *;
+};