nss: add new "nss-systemd" NSS module for mapping dynamic users

With this NSS module all dynamic service users will be resolvable via NSS like
any real user.
This commit is contained in:
Lennart Poettering 2016-07-14 19:19:49 +02:00
parent 6f3e79859d
commit 409093fe10
11 changed files with 515 additions and 14 deletions

View File

@ -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 \

View File

@ -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 = \

21
README
View File

@ -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:

View File

@ -106,8 +106,8 @@
<para>Here is an example <filename>/etc/nsswitch.conf</filename> file that enables
<command>nss-myhostname</command> correctly:</para>
<programlisting>passwd: compat mymachines
group: compat mymachines
<programlisting>passwd: compat mymachines systemd
group: compat mymachines systemd
shadow: compat
hosts: files mymachines resolve <command>myhostname</command>
@ -138,6 +138,7 @@ netgroup: nis</programlisting>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>nss-systemd</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>nss-resolve</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>nss-mymachines</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>nsswitch.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,

View File

@ -82,8 +82,8 @@
<para>Here is an example <filename>/etc/nsswitch.conf</filename> file that enables
<command>nss-mymachines</command> correctly:</para>
<programlisting>passwd: compat <command>mymachines</command>
group: compat <command>mymachines</command>
<programlisting>passwd: compat <command>mymachines</command> systemd
group: compat <command>mymachines</command> systemd
shadow: compat
hosts: files <command>mymachines</command> resolve myhostname
@ -103,6 +103,7 @@ netgroup: nis</programlisting>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-machined.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>nss-systemd</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>nss-resolve</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>nss-myhostname</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>nsswitch.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,

View File

@ -81,8 +81,8 @@
<para>Here is an example <filename>/etc/nsswitch.conf</filename> file that enables <command>nss-resolve</command>
correctly:</para>
<programlisting>passwd: compat mymachines
group: compat mymachines
<programlisting>passwd: compat mymachines systemd
group: compat mymachines systemd
shadow: compat
hosts: files mymachines <command>resolve</command> myhostname
@ -102,8 +102,9 @@ netgroup: nis</programlisting>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-resolved</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>nss-mymachines</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>nss-systemd</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>nss-myhostname</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>nss-mymachines</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>nsswitch.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
</para>
</refsect1>

107
man/nss-systemd.xml Normal file
View File

@ -0,0 +1,107 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<!--
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 <http://www.gnu.org/licenses/>.
-->
<refentry id="nss-systemd">
<refentryinfo>
<title>nss-systemd</title>
<productname>systemd</productname>
<authorgroup>
<author>
<contrib>Developer</contrib>
<firstname>Lennart</firstname>
<surname>Poettering</surname>
<email>lennart@poettering.net</email>
</author>
</authorgroup>
</refentryinfo>
<refmeta>
<refentrytitle>nss-systemd</refentrytitle>
<manvolnum>8</manvolnum>
</refmeta>
<refnamediv>
<refname>nss-systemd</refname>
<refname>libnss_systemd.so.2</refname>
<refpurpose>Provide UNIX user and group name resolution for dynamic users and groups.</refpurpose>
</refnamediv>
<refsynopsisdiv>
<para><filename>libnss_systemd.so.2</filename></para>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para><command>nss-systemd</command> is a plug-in module for the GNU Name Service Switch (NSS) functionality of the
GNU C Library (<command>glibc</command>), providing UNIX user and group name resolution for dynamic users and
groups allocated through the <varname>DynamicUser=</varname> option in systemd unit files. See
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for details on
this option.</para>
<para>To activate the NSS module, add <literal>systemd</literal> to the lines starting with
<literal>passwd:</literal> and <literal>group:</literal> in <filename>/etc/nsswitch.conf</filename>.</para>
<para>It is recommended to place <literal>systemd</literal> after the <literal>files</literal> or
<literal>compat</literal> entry of the <filename>/etc/nsswitch.conf</filename> lines so that
<filename>/etc/passwd</filename> and <filename>/etc/group</filename> based mappings take precedence.</para>
</refsect1>
<refsect1>
<title>Example</title>
<para>Here is an example <filename>/etc/nsswitch.conf</filename> file that enables
<command>nss-systemd</command> correctly:</para>
<programlisting>passwd: compat mymachines <command>systemd</command>
group: compat mymachines <command>systemd</command>
shadow: compat
hosts: files mymachines resolve myhostname
networks: files
protocols: db files
services: db files
ethers: db files
rpc: db files
netgroup: nis</programlisting>
</refsect1>
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>nss-resolve</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>nss-myhostname</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>nss-mymachines</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>nsswitch.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>getent</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>

View File

@ -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;

1
src/nss-systemd/Makefile Symbolic link
View File

@ -0,0 +1 @@
../Makefile

View File

@ -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 <http://www.gnu.org/licenses/>.
***/
#include <nss.h>
#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;
}

View File

@ -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: *;
};