summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO2
-rw-r--r--configure.ac9
-rw-r--r--man/nss-mymachines.xml35
-rw-r--r--man/systemd.netdev.xml11
-rw-r--r--man/systemd.network.xml43
-rw-r--r--src/basic/bitmap.c48
-rw-r--r--src/basic/macro.h13
-rw-r--r--src/basic/missing.h6
-rw-r--r--src/basic/virt.c20
-rw-r--r--src/libsystemd/sd-bus/bus-common-errors.h2
-rw-r--r--src/libsystemd/sd-netlink/netlink-types.c3
-rw-r--r--src/machine/machined-dbus.c231
-rw-r--r--src/machine/org.freedesktop.machine1.conf16
-rw-r--r--src/network/networkd-link.c23
-rw-r--r--src/network/networkd-netdev-gperf.gperf1
-rw-r--r--src/network/networkd-netdev-tunnel.c3
-rw-r--r--src/network/networkd-netdev-tunnel.h1
-rw-r--r--src/network/networkd-network-gperf.gperf5
-rw-r--r--src/network/networkd.h5
-rw-r--r--src/nss-mymachines/nss-mymachines.c320
-rw-r--r--src/nss-mymachines/nss-mymachines.sym4
-rw-r--r--src/resolve/dns-type.c5
-rw-r--r--src/resolve/dns-type.h1
-rw-r--r--src/resolve/resolved-dns-packet.c226
-rw-r--r--src/resolve/resolved-dns-rr.c14
-rw-r--r--src/resolve/resolved-dns-rr.h7
-rw-r--r--src/resolve/resolved-dns-transaction.c4
-rw-r--r--src/shared/nss-util.h33
-rw-r--r--src/tmpfiles/tmpfiles.c7
-rw-r--r--units/systemd-networkd.service.m4.in2
30 files changed, 949 insertions, 151 deletions
diff --git a/TODO b/TODO
index 4ac1f829d5..30b444331d 100644
--- a/TODO
+++ b/TODO
@@ -51,8 +51,6 @@ Features:
* install: include generator dirs in unit file search paths
-* introduce an NSS module that uses machined info to give container UIDs pretty names when user namespacing is used.
-
* stop using off_t, it's a crazy type. Use uint64_t instead.
* logind: follow PropertiesChanged state more closely, to deal with quick logouts and relogins
diff --git a/configure.ac b/configure.ac
index ff6364aba2..2fddf29f36 100644
--- a/configure.ac
+++ b/configure.ac
@@ -38,6 +38,11 @@ AM_INIT_AUTOMAKE([foreign 1.11 -Wall -Wno-portability silent-rules tar-pax no-di
AM_SILENT_RULES([yes])
AC_CANONICAL_HOST
AC_DEFINE_UNQUOTED([CANONICAL_HOST], "$host", [Canonical host string.])
+
+AC_CHECK_TOOLS([AR], [gcc-ar ar], [:])
+AC_CHECK_TOOLS([NM], [gcc-nm nm], [:])
+AC_CHECK_TOOLS([RANLIB], [gcc-ranlib ranlib], [:])
+
LT_PREREQ(2.2)
LT_INIT([disable-static])
@@ -196,7 +201,7 @@ AS_CASE([$CC], [*clang*],
AS_CASE([$CFLAGS], [*-O[[12345sz\ ]]*],
[CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [\
- -flto -ffat-lto-objects])],
+ -flto])],
[AC_MSG_RESULT([skipping -flto, optimization not enabled])])
AC_SUBST([OUR_CFLAGS], "$with_cflags $sanitizer_cflags")
@@ -302,7 +307,7 @@ AC_CHECK_DECLS([IFLA_INET6_ADDR_GEN_MODE,
IFLA_IPTUN_ENCAP_DPORT,
IFLA_GRE_ENCAP_DPORT,
IFLA_BRIDGE_VLAN_INFO,
- IFLA_BRPORT_UNICAST_FLOOD,
+ IFLA_BRPORT_LEARNING_SYNC,
NDA_IFINDEX,
IFA_FLAGS],
[], [], [[
diff --git a/man/nss-mymachines.xml b/man/nss-mymachines.xml
index eb1ed2592b..41ec458e4b 100644
--- a/man/nss-mymachines.xml
+++ b/man/nss-mymachines.xml
@@ -59,21 +59,26 @@
<para><command>nss-mymachines</command> is a plugin for the GNU
Name Service Switch (NSS) functionality of the GNU C Library
(<command>glibc</command>) providing hostname resolution for
- containers running locally, that are registered with
+ container names of containers running locally, that are registered
+ with
<citerefentry><refentrytitle>systemd-machined.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
- The container names are resolved to IP addresses of the specific
- container, ordered by their scope.</para>
+ The container names are resolved to the IP addresses of the
+ specific container, ordered by their scope.</para>
+
+ <para>The module also resolves user IDs used by containers to user
+ names indicating the container name, and back.</para>
<para>To activate the NSS modules, <literal>mymachines</literal>
- has to be added to the line starting with
- <literal>hosts:</literal> in
+ has to be added to the lines starting with
+ <literal>hosts:</literal>, <literal>passwd:</literal> and
+ <literal>group:</literal> in
<filename>/etc/nsswitch.conf</filename>.</para>
<para>It is recommended to place <literal>mymachines</literal>
- near the end of the <filename>nsswitch.conf</filename> line to
- make sure that this mapping is only used as fallback, and any DNS
- or <filename>/etc/hosts</filename> based mapping takes
- precedence.</para>
+ near the end of the <filename>nsswitch.conf</filename> lines to
+ make sure that its mappings are only used as fallback, and any
+ other mappings, such as DNS or <filename>/etc/hosts</filename>
+ based mappings take precedence.</para>
</refsect1>
<refsect1>
@@ -82,17 +87,17 @@
<para>Here's an example <filename>/etc/nsswitch.conf</filename>
file, that enables <command>mymachines</command> correctly:</para>
-<programlisting>passwd: compat
-group: compat
-shadow: compat
+ <programlisting>passwd: compat <command>mymachines</command>
+group: compat <command>mymachines</command>
+shadow: compat
-hosts: files dns <command>mymachines</command> myhostname
+hosts: files dns <command>mymachines</command> myhostname
networks: files
protocols: db files
services: db files
-ethers: db files
-rpc: db files
+ethers: db files
+rpc: db files
netgroup: nis</programlisting>
diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml
index d15c21be60..b100f96b85 100644
--- a/man/systemd.netdev.xml
+++ b/man/systemd.netdev.xml
@@ -504,6 +504,17 @@
</listitem>
</varlistentry>
<varlistentry>
+ <term><varname>DiffServiceCodePoint=</varname></term>
+ <listitem>
+ <para>A boolean. When true, inherits the Differentiated
+ Service Code Point (DSCP) field between inner and outer
+ header for ip6_tunnel. DSCP is a field in an IP packet
+ that enables different levels of service to be assigned
+ to network traffic. Defaults to <literal>no</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term><varname>Mode=</varname></term>
<listitem>
<para>An <literal>ip6tnl</literal> tunnels can have three
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 90a0e8fff6..d654db4993 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -669,6 +669,48 @@
following keys.</para>
<variablelist class='network-directives'>
<varlistentry>
+ <term><varname>UnicastFlood=</varname></term>
+ <listitem>
+ <para>A boolean. UnicastFlood configures whether a given port will flood
+ unicast traffic for which there is no FDB entry. By default this
+ flag is off.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><varname>HairPin=</varname></term>
+ <listitem>
+ <para> A boolean. Configures whether traffic may be send back
+ out of the port on which it was received. By default, this
+ flag is false. and the bridge will not forward traffic back
+ out of the receiving port. By default the flag is off.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><varname>BPDUGuard=</varname></term>
+ <listitem>
+ <para> A boolean. Configures whether STP Bridge Protocol Data Units will be
+ processed by the bridge port. By default, the flag is false allowing BPDU
+ processing. Turning this flag on will cause the port to stop processing
+ STP Bridge Protocol Data Units. By default the flag is off.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><varname>FastLeave=</varname></term>
+ <listitem>
+ <para> A boolean. This flag allows the bridge to immediately stop multicast
+ traffic on a port that receives IGMP Leave message. It is only used with
+ IGMP snooping if enabled on the bridge. By default the flag is off.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><varname>RootBlock=</varname></term>
+ <listitem>
+ <para> A boolean. Configures whether a given port is allowed to
+ become root port or not. Only used when STP is enabled on the bridge.
+ By default the flag is off.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term><varname>Cost=</varname></term>
<listitem>
<para>Each port in a bridge may have different speed. Cost
@@ -678,7 +720,6 @@
</varlistentry>
</variablelist>
</refsect1>
-
<refsect1>
<title>[BridgeFDB] Section Options</title>
<para>The <literal>[BridgeFDB]</literal> section manages the
diff --git a/src/basic/bitmap.c b/src/basic/bitmap.c
index 0747749d13..bf9d8d4d7c 100644
--- a/src/basic/bitmap.c
+++ b/src/basic/bitmap.c
@@ -24,7 +24,7 @@
#include "bitmap.h"
struct Bitmap {
- long long unsigned *bitmaps;
+ uint64_t *bitmaps;
size_t n_bitmaps;
size_t bitmaps_allocated;
};
@@ -37,9 +37,9 @@ struct Bitmap {
/* This indicates that we reached the end of the bitmap */
#define BITMAP_END ((unsigned) -1)
-#define BITMAP_NUM_TO_OFFSET(n) ((n) / (sizeof(long long unsigned) * 8))
-#define BITMAP_NUM_TO_REM(n) ((n) % (sizeof(long long unsigned) * 8))
-#define BITMAP_OFFSET_TO_NUM(offset, rem) ((offset) * sizeof(long long unsigned) * 8 + (rem))
+#define BITMAP_NUM_TO_OFFSET(n) ((n) / (sizeof(uint64_t) * 8))
+#define BITMAP_NUM_TO_REM(n) ((n) % (sizeof(uint64_t) * 8))
+#define BITMAP_OFFSET_TO_NUM(offset, rem) ((offset) * sizeof(uint64_t) * 8 + (rem))
Bitmap *bitmap_new(void) {
return new0(Bitmap, 1);
@@ -56,6 +56,8 @@ void bitmap_free(Bitmap *b) {
int bitmap_ensure_allocated(Bitmap **b) {
Bitmap *a;
+ assert(b);
+
if (*b)
return 0;
@@ -69,7 +71,7 @@ int bitmap_ensure_allocated(Bitmap **b) {
}
int bitmap_set(Bitmap *b, unsigned n) {
- long long unsigned bitmask;
+ uint64_t bitmask;
unsigned offset;
assert(b);
@@ -87,7 +89,7 @@ int bitmap_set(Bitmap *b, unsigned n) {
b->n_bitmaps = offset + 1;
}
- bitmask = 1ULL << BITMAP_NUM_TO_REM(n);
+ bitmask = UINT64_C(1) << BITMAP_NUM_TO_REM(n);
b->bitmaps[offset] |= bitmask;
@@ -95,26 +97,27 @@ int bitmap_set(Bitmap *b, unsigned n) {
}
void bitmap_unset(Bitmap *b, unsigned n) {
- long long unsigned bitmask;
+ uint64_t bitmask;
unsigned offset;
- assert(b);
+ if (!b)
+ return;
offset = BITMAP_NUM_TO_OFFSET(n);
if (offset >= b->n_bitmaps)
return;
- bitmask = 1ULL << BITMAP_NUM_TO_REM(n);
+ bitmask = UINT64_C(1) << BITMAP_NUM_TO_REM(n);
b->bitmaps[offset] &= ~bitmask;
}
bool bitmap_isset(Bitmap *b, unsigned n) {
- long long unsigned bitmask;
+ uint64_t bitmask;
unsigned offset;
- if (!b || !b->bitmaps)
+ if (!b)
return false;
offset = BITMAP_NUM_TO_OFFSET(n);
@@ -122,7 +125,7 @@ bool bitmap_isset(Bitmap *b, unsigned n) {
if (offset >= b->n_bitmaps)
return false;
- bitmask = 1ULL << BITMAP_NUM_TO_REM(n);
+ bitmask = UINT64_C(1) << BITMAP_NUM_TO_REM(n);
return !!(b->bitmaps[offset] & bitmask);
}
@@ -133,31 +136,31 @@ bool bitmap_isclear(Bitmap *b) {
assert(b);
for (i = 0; i < b->n_bitmaps; i++)
- if (b->bitmaps[i])
+ if (b->bitmaps[i] != 0)
return false;
return true;
}
void bitmap_clear(Bitmap *b) {
- unsigned i;
-
assert(b);
- for (i = 0; i < b->n_bitmaps; i++)
- b->bitmaps[i] = 0;
+ b->n_bitmaps = 0;
}
bool bitmap_iterate(Bitmap *b, Iterator *i, unsigned *n) {
- long long unsigned bitmask;
+ uint64_t bitmask;
unsigned offset, rem;
+ assert(i);
+ assert(n);
+
if (!b || i->idx == BITMAP_END)
return false;
offset = BITMAP_NUM_TO_OFFSET(i->idx);
rem = BITMAP_NUM_TO_REM(i->idx);
- bitmask = 1ULL << rem;
+ bitmask = UINT64_C(1) << rem;
for (; offset < b->n_bitmaps; offset ++) {
if (b->bitmaps[offset]) {
@@ -181,7 +184,6 @@ bool bitmap_iterate(Bitmap *b, Iterator *i, unsigned *n) {
}
bool bitmap_equal(Bitmap *a, Bitmap *b) {
- unsigned i;
if (!a ^ !b)
return false;
@@ -192,9 +194,5 @@ bool bitmap_equal(Bitmap *a, Bitmap *b) {
if (a->n_bitmaps != b->n_bitmaps)
return false;
- for (i = 0; i < a->n_bitmaps; i++)
- if (a->bitmaps[i] != b->bitmaps[i])
- return false;
-
- return true;
+ return memcmp(a->bitmaps, b->bitmaps, sizeof(uint64_t) * a->n_bitmaps) == 0;
}
diff --git a/src/basic/macro.h b/src/basic/macro.h
index ea01d701d2..627d768b76 100644
--- a/src/basic/macro.h
+++ b/src/basic/macro.h
@@ -26,6 +26,7 @@
#include <sys/types.h>
#include <sys/uio.h>
#include <inttypes.h>
+#include <stdbool.h>
#define _printf_(a,b) __attribute__ ((format (printf, a, b)))
#define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__)))
@@ -461,6 +462,18 @@ do { \
#define GID_INVALID ((gid_t) -1)
#define MODE_INVALID ((mode_t) -1)
+static inline bool UID_IS_INVALID(uid_t uid) {
+ /* We consider both the old 16bit -1 user and the newer 32bit
+ * -1 user invalid, since they are or used to be incompatible
+ * with syscalls such as setresuid() or chown(). */
+
+ return uid == (uid_t) ((uint32_t) -1) || uid == (uid_t) ((uint16_t) -1);
+}
+
+static inline bool GID_IS_INVALID(gid_t gid) {
+ return gid == (gid_t) ((uint32_t) -1) || gid == (gid_t) ((uint16_t) -1);
+}
+
#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \
static inline void func##p(type *p) { \
if (*p) \
diff --git a/src/basic/missing.h b/src/basic/missing.h
index bd49f10e76..ed6cd80c75 100644
--- a/src/basic/missing.h
+++ b/src/basic/missing.h
@@ -832,7 +832,7 @@ static inline int setns(int fd, int nstype) {
#define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_BRPORT_UNICAST_FLOOD
+#if !HAVE_DECL_IFLA_BRPORT_LEARNING_SYNC
#define IFLA_BRPORT_UNSPEC 0
#define IFLA_BRPORT_STATE 1
#define IFLA_BRPORT_PRIORITY 2
@@ -843,7 +843,9 @@ static inline int setns(int fd, int nstype) {
#define IFLA_BRPORT_FAST_LEAVE 7
#define IFLA_BRPORT_LEARNING 8
#define IFLA_BRPORT_UNICAST_FLOOD 9
-#define __IFLA_BRPORT_MAX 10
+#define IFLA_BRPORT_PROXYARP 10
+#define IFLA_BRPORT_LEARNING_SYNC 11
+#define __IFLA_BRPORT_MAX 12
#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
#endif
diff --git a/src/basic/virt.c b/src/basic/virt.c
index 1299a75ed5..a8d26716a1 100644
--- a/src/basic/virt.c
+++ b/src/basic/virt.c
@@ -188,7 +188,7 @@ int detect_vm(const char **id) {
_cleanup_free_ char *domcap = NULL, *cpuinfo_contents = NULL;
static thread_local int cached_found = -1;
static thread_local const char *cached_id = NULL;
- const char *_id = NULL;
+ const char *_id = NULL, *_id_cpuid = NULL;
int r;
if (_likely_(cached_found >= 0)) {
@@ -234,10 +234,26 @@ int detect_vm(const char **id) {
/* this will set _id to "other" and return 0 for unknown hypervisors */
r = detect_vm_cpuid(&_id);
- if (r != 0)
+
+ /* finish when found a known hypervisor other than kvm */
+ if (r < 0 || (r > 0 && !streq(_id, "kvm")))
goto finish;
+ _id_cpuid = _id;
+
r = detect_vm_dmi(&_id);
+
+ /* kvm with and without Virtualbox */
+ if (streq_ptr(_id_cpuid, "kvm")) {
+ if (r > 0 && streq(_id, "oracle"))
+ goto finish;
+
+ _id = _id_cpuid;
+ r = 1;
+ goto finish;
+ }
+
+ /* information from dmi */
if (r != 0)
goto finish;
diff --git a/src/libsystemd/sd-bus/bus-common-errors.h b/src/libsystemd/sd-bus/bus-common-errors.h
index 0dbfbddcf6..f2092795f4 100644
--- a/src/libsystemd/sd-bus/bus-common-errors.h
+++ b/src/libsystemd/sd-bus/bus-common-errors.h
@@ -46,6 +46,8 @@
#define BUS_ERROR_NO_MACHINE_FOR_PID "org.freedesktop.machine1.NoMachineForPID"
#define BUS_ERROR_MACHINE_EXISTS "org.freedesktop.machine1.MachineExists"
#define BUS_ERROR_NO_PRIVATE_NETWORKING "org.freedesktop.machine1.NoPrivateNetworking"
+#define BUS_ERROR_NO_SUCH_USER_MAPPING "org.freedesktop.machine1.NoSuchUserMapping"
+#define BUS_ERROR_NO_SUCH_GROUP_MAPPING "org.freedesktop.machine1.NoSuchGroupMapping"
#define BUS_ERROR_NO_SUCH_SESSION "org.freedesktop.login1.NoSuchSession"
#define BUS_ERROR_NO_SESSION_FOR_PID "org.freedesktop.login1.NoSessionForPID"
diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c
index 8c6fd8ad30..ff1b8a260f 100644
--- a/src/libsystemd/sd-netlink/netlink-types.c
+++ b/src/libsystemd/sd-netlink/netlink-types.c
@@ -329,8 +329,11 @@ static const struct NLType rtnl_prot_info_bridge_port_types[IFLA_BRPORT_MAX + 1]
[IFLA_BRPORT_MODE] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_GUARD] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_PROTECT] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BRPORT_FAST_LEAVE] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_LEARNING] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_UNICAST_FLOOD] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BRPORT_PROXYARP] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BRPORT_LEARNING_SYNC] = { .type = NETLINK_TYPE_U8 },
};
static const NLTypeSystem rtnl_prot_info_type_systems[AF_MAX] = {
diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c
index 0e971a6789..3637815fc9 100644
--- a/src/machine/machined-dbus.c
+++ b/src/machine/machined-dbus.c
@@ -31,12 +31,13 @@
#include "bus-common-errors.h"
#include "cgroup-util.h"
#include "btrfs-util.h"
+#include "formats-util.h"
+#include "process-util.h"
#include "machine-image.h"
#include "machine-pool.h"
#include "image-dbus.h"
#include "machined.h"
#include "machine-dbus.h"
-#include "formats-util.h"
static int property_get_pool_path(
sd_bus *bus,
@@ -840,6 +841,230 @@ static int method_set_image_limit(sd_bus_message *message, void *userdata, sd_bu
return bus_image_method_set_limit(message, i, error);
}
+static int method_map_from_machine_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ _cleanup_fclose_ FILE *f = NULL;
+ Manager *m = userdata;
+ const char *name, *p;
+ Machine *machine;
+ uint32_t uid;
+ int r;
+
+ r = sd_bus_message_read(message, "su", &name, &uid);
+ if (r < 0)
+ return r;
+
+ if (UID_IS_INVALID(uid))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
+
+ machine = hashmap_get(m->machines, name);
+ if (!machine)
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
+
+ p = procfs_file_alloca(machine->leader, "uid_map");
+ f = fopen(p, "re");
+ if (!f)
+ return -errno;
+
+ for (;;) {
+ uid_t uid_base, uid_shift, uid_range, converted;
+ int k;
+
+ errno = 0;
+ k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT, &uid_base, &uid_shift, &uid_range);
+ if (k < 0 && feof(f))
+ break;
+ if (k != 3) {
+ if (ferror(f) && errno != 0)
+ return -errno;
+
+ return -EIO;
+ }
+
+ if (uid < uid_base || uid >= uid_base + uid_range)
+ continue;
+
+ converted = uid - uid_base + uid_shift;
+ if (UID_IS_INVALID(converted))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
+
+ return sd_bus_reply_method_return(message, "u", (uint32_t) converted);
+ }
+
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "Machine '%s' has no matching user mappings.", name);
+}
+
+static int method_map_to_machine_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+ Machine *machine;
+ uid_t uid;
+ Iterator i;
+ int r;
+
+ r = sd_bus_message_read(message, "u", &uid);
+ if (r < 0)
+ return r;
+ if (UID_IS_INVALID(uid))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
+ if (uid < 0x10000)
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "User " UID_FMT " belongs to host UID range", uid);
+
+ HASHMAP_FOREACH(machine, m->machines, i) {
+ _cleanup_fclose_ FILE *f = NULL;
+ char p[strlen("/proc//uid_map") + DECIMAL_STR_MAX(pid_t) + 1];
+
+ xsprintf(p, "/proc/" UID_FMT "/uid_map", machine->leader);
+ f = fopen(p, "re");
+ if (!f) {
+ log_warning_errno(errno, "Failed top open %s, ignoring,", p);
+ continue;
+ }
+
+ for (;;) {
+ _cleanup_free_ char *o = NULL;
+ uid_t uid_base, uid_shift, uid_range, converted;
+ int k;
+
+ errno = 0;
+ k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT, &uid_base, &uid_shift, &uid_range);
+ if (k < 0 && feof(f))
+ break;
+ if (k != 3) {
+ if (ferror(f) && errno != 0)
+ return -errno;
+
+ return -EIO;
+ }
+
+ if (uid < uid_shift || uid >= uid_shift + uid_range)
+ continue;
+
+ converted = (uid - uid_shift + uid_base);
+ if (UID_IS_INVALID(converted))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
+
+ o = machine_bus_path(machine);
+ if (!o)
+ return -ENOMEM;
+
+ return sd_bus_reply_method_return(message, "sou", machine->name, o, (uint32_t) converted);
+ }
+ }
+
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "No matching user mapping for " UID_FMT ".", uid);
+}
+
+static int method_map_from_machine_group(sd_bus_message *message, void *groupdata, sd_bus_error *error) {
+ _cleanup_fclose_ FILE *f = NULL;
+ Manager *m = groupdata;
+ const char *name, *p;
+ Machine *machine;
+ uint32_t gid;
+ int r;
+
+ r = sd_bus_message_read(message, "su", &name, &gid);
+ if (r < 0)
+ return r;
+
+ if (GID_IS_INVALID(gid))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
+
+ machine = hashmap_get(m->machines, name);
+ if (!machine)
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
+
+ p = procfs_file_alloca(machine->leader, "gid_map");
+ f = fopen(p, "re");
+ if (!f)
+ return -errno;
+
+ for (;;) {
+ gid_t gid_base, gid_shift, gid_range, converted;
+ int k;
+
+ errno = 0;
+ k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT, &gid_base, &gid_shift, &gid_range);
+ if (k < 0 && feof(f))
+ break;
+ if (k != 3) {
+ if (ferror(f) && errno != 0)
+ return -errno;
+
+ return -EIO;
+ }
+
+ if (gid < gid_base || gid >= gid_base + gid_range)
+ continue;
+
+ converted = gid - gid_base + gid_shift;
+ if (GID_IS_INVALID(converted))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
+
+ return sd_bus_reply_method_return(message, "u", (uint32_t) converted);
+ }
+
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "Machine '%s' has no matching group mappings.", name);
+}
+
+static int method_map_to_machine_group(sd_bus_message *message, void *groupdata, sd_bus_error *error) {
+ Manager *m = groupdata;
+ Machine *machine;
+ gid_t gid;
+ Iterator i;
+ int r;
+
+ r = sd_bus_message_read(message, "u", &gid);
+ if (r < 0)
+ return r;
+ if (GID_IS_INVALID(gid))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
+ if (gid < 0x10000)
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "Group " GID_FMT " belongs to host GID range", gid);
+
+ HASHMAP_FOREACH(machine, m->machines, i) {
+ _cleanup_fclose_ FILE *f = NULL;
+ char p[strlen("/proc//gid_map") + DECIMAL_STR_MAX(pid_t) + 1];
+
+ xsprintf(p, "/proc/" GID_FMT "/gid_map", machine->leader);
+ f = fopen(p, "re");
+ if (!f) {
+ log_warning_errno(errno, "Failed top open %s, ignoring,", p);
+ continue;
+ }
+
+ for (;;) {
+ _cleanup_free_ char *o = NULL;
+ gid_t gid_base, gid_shift, gid_range, converted;
+ int k;
+
+ errno = 0;
+ k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT, &gid_base, &gid_shift, &gid_range);
+ if (k < 0 && feof(f))
+ break;
+ if (k != 3) {
+ if (ferror(f) && errno != 0)
+ return -errno;
+
+ return -EIO;
+ }
+
+ if (gid < gid_shift || gid >= gid_shift + gid_range)
+ continue;
+
+ converted = (gid - gid_shift + gid_base);
+ if (GID_IS_INVALID(converted))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
+
+ o = machine_bus_path(machine);
+ if (!o)
+ return -ENOMEM;
+
+ return sd_bus_reply_method_return(message, "sou", machine->name, o, (uint32_t) converted);
+ }
+ }
+
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "No matching group mapping for " GID_FMT ".", gid);
+}
+
const sd_bus_vtable manager_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path, 0, 0),
@@ -869,6 +1094,10 @@ const sd_bus_vtable manager_vtable[] = {
SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetPoolLimit", "t", NULL, method_set_pool_limit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetImageLimit", "st", NULL, method_set_image_limit, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("MapFromMachineUser", "su", "u", method_map_from_machine_user, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("MapToMachineUser", "u", "sou", method_map_to_machine_user, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("MapFromMachineGroup", "su", "u", method_map_from_machine_group, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("MapToMachineGroup", "u", "sou", method_map_to_machine_group, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_SIGNAL("MachineNew", "so", 0),
SD_BUS_SIGNAL("MachineRemoved", "so", 0),
SD_BUS_VTABLE_END
diff --git a/src/machine/org.freedesktop.machine1.conf b/src/machine/org.freedesktop.machine1.conf
index 93aaf6a377..d58f01507b 100644
--- a/src/machine/org.freedesktop.machine1.conf
+++ b/src/machine/org.freedesktop.machine1.conf
@@ -113,6 +113,22 @@
send_member="SetImageLimit"/>
<allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Manager"
+ send_member="MapFromMachineUser"/>
+
+ <allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Manager"
+ send_member="MapToMachineUser"/>
+
+ <allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Manager"
+ send_member="MapFromMachineGroup"/>
+
+ <allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Manager"
+ send_member="MapToMachineGroup"/>
+
+ <allow send_destination="org.freedesktop.machine1"
send_interface="org.freedesktop.machine1.Machine"
send_member="GetAddresses"/>
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 9550e89a15..55510b46e9 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -846,9 +846,6 @@ static int link_set_bridge(Link *link) {
assert(link);
assert(link->network);
- if(link->network->cost == 0)
- return 0;
-
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
if (r < 0)
return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
@@ -861,6 +858,26 @@ static int link_set_bridge(Link *link) {
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_PROTINFO attribute: %m");
+ r = sd_netlink_message_append_u8(req, IFLA_BRPORT_GUARD, link->network->bpdu_guard);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_GUARD attribute: %m");
+
+ r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MODE, link->network->hairpin);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_MODE attribute: %m");
+
+ r = sd_netlink_message_append_u8(req, IFLA_BRPORT_FAST_LEAVE, link->network->fast_leave);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_FAST_LEAVE attribute: %m");
+
+ r = sd_netlink_message_append_u8(req, IFLA_BRPORT_PROTECT, link->network->root_block);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_PROTECT attribute: %m");
+
+ r = sd_netlink_message_append_u8(req, IFLA_BRPORT_UNICAST_FLOOD, link->network->unicast_flood);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_UNICAST_FLOOD attribute: %m");
+
if(link->network->cost != 0) {
r = sd_netlink_message_append_u32(req, IFLA_BRPORT_COST, link->network->cost);
if (r < 0)
diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf
index 63258c0376..bdc43e87f6 100644
--- a/src/network/networkd-netdev-gperf.gperf
+++ b/src/network/networkd-netdev-gperf.gperf
@@ -37,6 +37,7 @@ Tunnel.TTL, config_parse_unsigned, 0,
Tunnel.DiscoverPathMTU, config_parse_bool, 0, offsetof(Tunnel, pmtudisc)
Tunnel.Mode, config_parse_ip6tnl_mode, 0, offsetof(Tunnel, ip6tnl_mode)
Tunnel.IPv6FlowLabel, config_parse_ipv6_flowlabel, 0, offsetof(Tunnel, ipv6_flowlabel)
+Tunnel.DiffServiceCodePoint, config_parse_bool, 0, offsetof(Tunnel, dscp)
Peer.Name, config_parse_ifname, 0, offsetof(Veth, ifname_peer)
Peer.MACAddress, config_parse_hwaddr, 0, offsetof(Veth, mac_peer)
VXLAN.Id, config_parse_uint64, 0, offsetof(VxLan, id)
diff --git a/src/network/networkd-netdev-tunnel.c b/src/network/networkd-netdev-tunnel.c
index a13edf6936..ecf0604c4b 100644
--- a/src/network/networkd-netdev-tunnel.c
+++ b/src/network/networkd-netdev-tunnel.c
@@ -271,6 +271,9 @@ static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_netl
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_FLOWINFO attribute: %m");
}
+ if (t->dscp)
+ t->flags |= IP6_TNL_F_RCV_DSCP_COPY;
+
r = sd_netlink_message_append_u32(m, IFLA_IPTUN_FLAGS, t->flags);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_FLAGS attribute: %m");
diff --git a/src/network/networkd-netdev-tunnel.h b/src/network/networkd-netdev-tunnel.h
index 47981fbe32..e08e2891e7 100644
--- a/src/network/networkd-netdev-tunnel.h
+++ b/src/network/networkd-netdev-tunnel.h
@@ -57,6 +57,7 @@ struct Tunnel {
IPv6FlowLabel ipv6_flowlabel;
bool pmtudisc;
+ bool dscp;
};
extern const NetDevVTable ipip_vtable;
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 3a78c3d8a8..720f6b9d0b 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -73,6 +73,11 @@ DHCP.CriticalConnection, config_parse_bool, 0
DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier)
DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric)
Bridge.Cost, config_parse_unsigned, 0, offsetof(Network, cost)
+Bridge.BPDUGuard, config_parse_bool, 0, offsetof(Network, bpdu_guard)
+Bridge.HairPin, config_parse_bool, 0, offsetof(Network, hairpin)
+Bridge.FastLeave, config_parse_bool, 0, offsetof(Network, fast_leave)
+Bridge.RootBlock, config_parse_bool, 0, offsetof(Network, root_block)
+Bridge.UnicastFlood, config_parse_bool, 0, offsetof(Network, unicast_flood)
BridgeFDB.MACAddress, config_parse_fdb_hwaddr, 0, 0
BridgeFDB.VLANId, config_parse_fdb_vlan_id, 0, 0
/* backwards compatibility: do not add new entries to this section */
diff --git a/src/network/networkd.h b/src/network/networkd.h
index fb95f90169..6418c0a536 100644
--- a/src/network/networkd.h
+++ b/src/network/networkd.h
@@ -150,6 +150,11 @@ struct Network {
bool dhcp_server;
+ bool bpdu_guard;
+ bool hairpin;
+ bool fast_leave;
+ bool root_block;
+ bool unicast_flood;
unsigned cost;
AddressFamilyBoolean ip_forward;
diff --git a/src/nss-mymachines/nss-mymachines.c b/src/nss-mymachines/nss-mymachines.c
index f712033e6c..cdec83d074 100644
--- a/src/nss-mymachines/nss-mymachines.c
+++ b/src/nss-mymachines/nss-mymachines.c
@@ -28,9 +28,12 @@
#include "util.h"
#include "nss-util.h"
#include "bus-util.h"
+#include "bus-common-errors.h"
#include "in-addr-util.h"
NSS_GETHOSTBYNAME_PROTOTYPES(mymachines);
+NSS_GETPW_PROTOTYPES(mymachines);
+NSS_GETGR_PROTOTYPES(mymachines);
static int count_addresses(sd_bus_message *m, int af, unsigned *ret) {
unsigned c = 0;
@@ -380,4 +383,319 @@ fail:
return NSS_STATUS_UNAVAIL;
}
-NSS_GETHOSTBYNAME_FALLBACKS(mymachines)
+NSS_GETHOSTBYNAME_FALLBACKS(mymachines);
+
+enum nss_status _nss_mymachines_getpwnam_r(
+ const char *name,
+ struct passwd *pwd,
+ char *buffer, size_t buflen,
+ int *errnop) {
+
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_bus_message_unref_ sd_bus_message* reply = NULL;
+ _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
+ const char *p, *e, *machine;
+ uint32_t mapped;
+ uid_t uid;
+ size_t l;
+ int r;
+
+ assert(name);
+ assert(pwd);
+
+ p = startswith(name, "vu-");
+ if (!p)
+ goto not_found;
+
+ e = strrchr(p, '-');
+ if (!e || e == p)
+ goto not_found;
+
+ r = parse_uid(e + 1, &uid);
+ if (r < 0)
+ goto not_found;
+
+ machine = strndupa(p, e - p);
+ if (!machine_name_is_valid(machine))
+ goto not_found;
+
+ r = sd_bus_open_system(&bus);
+ if (r < 0)
+ goto fail;
+
+ r = sd_bus_call_method(bus,
+ "org.freedesktop.machine1",
+ "/org/freedesktop/machine1",
+ "org.freedesktop.machine1.Manager",
+ "MapFromMachineUser",
+ &error,
+ &reply,
+ "su",
+ machine, (uint32_t) uid);
+ if (r < 0) {
+ if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_USER_MAPPING))
+ goto not_found;
+
+ goto fail;
+ }
+
+ r = sd_bus_message_read(reply, "u", &mapped);
+ 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 = mapped;
+ pwd->pw_gid = 65534; /* nobody */
+ pwd->pw_gecos = buffer;
+ 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_mymachines_getpwuid_r(
+ uid_t uid,
+ struct passwd *pwd,
+ char *buffer, size_t buflen,
+ int *errnop) {
+
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_bus_message_unref_ sd_bus_message* reply = NULL;
+ _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
+ const char *machine, *object;
+ uint32_t mapped;
+ int r;
+
+ if (UID_IS_INVALID(uid)) {
+ r = -EINVAL;
+ goto fail;
+ }
+
+ /* We consider all uids < 65536 host uids */
+ if (uid < 0x10000)
+ goto not_found;
+
+ r = sd_bus_open_system(&bus);
+ if (r < 0)
+ goto fail;
+
+ r = sd_bus_call_method(bus,
+ "org.freedesktop.machine1",
+ "/org/freedesktop/machine1",
+ "org.freedesktop.machine1.Manager",
+ "MapToMachineUser",
+ &error,
+ &reply,
+ "u",
+ (uint32_t) uid);
+ if (r < 0) {
+ if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_USER_MAPPING))
+ goto not_found;
+
+ goto fail;
+ }
+
+ r = sd_bus_message_read(reply, "sou", &machine, &object, &mapped);
+ if (r < 0)
+ goto fail;
+
+ if (snprintf(buffer, buflen, "vu-%s-" UID_FMT, machine, (uid_t) mapped) >= (int) buflen) {
+ *errnop = ENOMEM;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ pwd->pw_name = buffer;
+ pwd->pw_uid = uid;
+ pwd->pw_gid = 65534; /* nobody */
+ pwd->pw_gecos = buffer;
+ 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_mymachines_getgrnam_r(
+ const char *name,
+ struct group *gr,
+ char *buffer, size_t buflen,
+ int *errnop) {
+
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_bus_message_unref_ sd_bus_message* reply = NULL;
+ _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
+ const char *p, *e, *machine;
+ uint32_t mapped;
+ uid_t gid;
+ size_t l;
+ int r;
+
+ assert(name);
+ assert(gr);
+
+ p = startswith(name, "vg-");
+ if (!p)
+ goto not_found;
+
+ e = strrchr(p, '-');
+ if (!e || e == p)
+ goto not_found;
+
+ r = parse_gid(e + 1, &gid);
+ if (r < 0)
+ goto not_found;
+
+ machine = strndupa(p, e - p);
+ if (!machine_name_is_valid(machine))
+ goto not_found;
+
+ r = sd_bus_open_system(&bus);
+ if (r < 0)
+ goto fail;
+
+ r = sd_bus_call_method(bus,
+ "org.freedesktop.machine1",
+ "/org/freedesktop/machine1",
+ "org.freedesktop.machine1.Manager",
+ "MapFromMachineGroup",
+ &error,
+ &reply,
+ "su",
+ machine, (uint32_t) gid);
+ if (r < 0) {
+ if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_GROUP_MAPPING))
+ goto not_found;
+
+ goto fail;
+ }
+
+ r = sd_bus_message_read(reply, "u", &mapped);
+ 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;
+ 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_mymachines_getgrgid_r(
+ gid_t gid,
+ struct group *gr,
+ char *buffer, size_t buflen,
+ int *errnop) {
+
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_bus_message_unref_ sd_bus_message* reply = NULL;
+ _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
+ const char *machine, *object;
+ uint32_t mapped;
+ int r;
+
+ if (GID_IS_INVALID(gid)) {
+ r = -EINVAL;
+ goto fail;
+ }
+
+ /* We consider all gids < 65536 host gids */
+ if (gid < 0x10000)
+ goto not_found;
+
+ r = sd_bus_open_system(&bus);
+ if (r < 0)
+ goto fail;
+
+ r = sd_bus_call_method(bus,
+ "org.freedesktop.machine1",
+ "/org/freedesktop/machine1",
+ "org.freedesktop.machine1.Manager",
+ "MapToMachineGroup",
+ &error,
+ &reply,
+ "u",
+ (uint32_t) gid);
+ if (r < 0) {
+ if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_GROUP_MAPPING))
+ goto not_found;
+
+ goto fail;
+ }
+
+ r = sd_bus_message_read(reply, "sou", &machine, &object, &mapped);
+ if (r < 0)
+ goto fail;
+
+ if (buflen < sizeof(char*) + 1) {
+ *errnop = ENOMEM;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ memzero(buffer, sizeof(char*));
+ if (snprintf(buffer + sizeof(char*), buflen - sizeof(char*), "vg-%s-" GID_FMT, machine, (gid_t) mapped) >= (int) buflen) {
+ *errnop = ENOMEM;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ 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-mymachines/nss-mymachines.sym b/src/nss-mymachines/nss-mymachines.sym
index f80b51c1aa..0728ac3ba7 100644
--- a/src/nss-mymachines/nss-mymachines.sym
+++ b/src/nss-mymachines/nss-mymachines.sym
@@ -13,5 +13,9 @@ global:
_nss_mymachines_gethostbyname2_r;
_nss_mymachines_gethostbyname3_r;
_nss_mymachines_gethostbyname4_r;
+ _nss_mymachines_getpwnam_r;
+ _nss_mymachines_getpwuid_r;
+ _nss_mymachines_getgrnam_r;
+ _nss_mymachines_getgrgid_r;
local: *;
};
diff --git a/src/resolve/dns-type.c b/src/resolve/dns-type.c
index a3e740896f..e1087b3219 100644
--- a/src/resolve/dns-type.c
+++ b/src/resolve/dns-type.c
@@ -43,3 +43,8 @@ int dns_type_from_string(const char *s) {
return sc->id;
}
+
+/* XXX: find an authorotative list of all pseudo types? */
+bool dns_type_is_pseudo(int n) {
+ return IN_SET(n, DNS_TYPE_ANY, DNS_TYPE_AXFR, DNS_TYPE_IXFR, DNS_TYPE_OPT);
+}
diff --git a/src/resolve/dns-type.h b/src/resolve/dns-type.h
index 86951d233a..950af36ee3 100644
--- a/src/resolve/dns-type.h
+++ b/src/resolve/dns-type.h
@@ -25,6 +25,7 @@
const char *dns_type_to_string(int type);
int dns_type_from_string(const char *s);
+bool dns_type_is_pseudo(int n);
/* DNS record types, taken from
* http://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml.
diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c
index b1cde4ab35..649e8b74e1 100644
--- a/src/resolve/resolved-dns-packet.c
+++ b/src/resolve/resolved-dns-packet.c
@@ -275,7 +275,7 @@ static void dns_packet_truncate(DnsPacket *p, size_t sz) {
if (p->size <= sz)
return;
- HASHMAP_FOREACH_KEY(s, n, p->names, i) {
+ HASHMAP_FOREACH_KEY(n, s, p->names, i) {
if (PTR_TO_SIZE(n) < sz)
continue;
@@ -509,22 +509,22 @@ static int dns_packet_append_type_window(DnsPacket *p, uint8_t window, uint8_t l
assert(p);
assert(types);
- if (length == 0)
- return 0;
-
saved_size = p->size;
- r = dns_packet_append_uint8(p, window, NULL);
- if (r < 0)
- goto fail;
+ if (length != 0) {
- r = dns_packet_append_uint8(p, length, NULL);
- if (r < 0)
- goto fail;
+ r = dns_packet_append_uint8(p, window, NULL);
+ if (r < 0)
+ goto fail;
- r = dns_packet_append_blob(p, types, length, NULL);
- if (r < 0)
- goto fail;
+ r = dns_packet_append_uint8(p, length, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_blob(p, types, length, NULL);
+ if (r < 0)
+ goto fail;
+ }
if (start)
*start = saved_size;
@@ -761,7 +761,7 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
if (r < 0)
goto fail;
- r = dns_packet_append_blob(p, rr->sshfp.key, rr->sshfp.key_size, NULL);
+ r = dns_packet_append_blob(p, rr->sshfp.fingerprint, rr->sshfp.fingerprint_size, NULL);
break;
case DNS_TYPE_DNSKEY:
@@ -933,6 +933,42 @@ int dns_packet_read_blob(DnsPacket *p, void *d, size_t sz, size_t *start) {
return 0;
}
+static int dns_packet_read_memdup(
+ DnsPacket *p, size_t size,
+ void **ret, size_t *ret_size,
+ size_t *ret_start) {
+
+ const void *src;
+ size_t start;
+ int r;
+
+ assert(p);
+ assert(ret);
+
+ r = dns_packet_read(p, size, &src, &start);
+ if (r < 0)
+ return r;
+
+ if (size <= 0)
+ *ret = NULL;
+ else {
+ void *copy;
+
+ copy = memdup(src, size);
+ if (!copy)
+ return -ENOMEM;
+
+ *ret = copy;
+ }
+
+ if (ret_size)
+ *ret_size = size;
+ if (ret_start)
+ *ret_start = start;
+
+ return 0;
+}
+
int dns_packet_read_uint8(DnsPacket *p, uint8_t *ret, size_t *start) {
const void *d;
int r;
@@ -1172,9 +1208,12 @@ static int dns_packet_read_type_window(DnsPacket *p, Bitmap **types, size_t *sta
if (bitmap[i] & bitmask) {
uint16_t n;
- /* XXX: ignore pseudo-types? see RFC4034 section 4.1.2 */
n = (uint16_t) window << 8 | (uint16_t) bit;
+ /* Ignore pseudo-types. see RFC4034 section 4.1.2 */
+ if (dns_type_is_pseudo(n))
+ continue;
+
r = bitmap_set(*types, n);
if (r < 0)
goto fail;
@@ -1197,6 +1236,38 @@ fail:
return r;
}
+static int dns_packet_read_type_windows(DnsPacket *p, Bitmap **types, size_t size, size_t *start) {
+ size_t saved_rindex;
+ int r;
+
+ saved_rindex = p->rindex;
+
+ while (p->rindex < saved_rindex + size) {
+ r = dns_packet_read_type_window(p, types, NULL);
+ if (r < 0)
+ goto fail;
+
+ /* don't read past end of current RR */
+ if (p->rindex > saved_rindex + size) {
+ r = -EBADMSG;
+ goto fail;
+ }
+ }
+
+ if (p->rindex != saved_rindex + size) {
+ r = -EBADMSG;
+ goto fail;
+ }
+
+ if (start)
+ *start = saved_rindex;
+
+ return 0;
+fail:
+ dns_packet_rewind(p, saved_rindex);
+ return r;
+}
+
int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) {
_cleanup_free_ char *name = NULL;
uint16_t class, type;
@@ -1239,26 +1310,6 @@ fail:
return r;
}
-static int dns_packet_read_public_key(DnsPacket *p, size_t length,
- void **dp, size_t *lengthp,
- size_t *start) {
- int r;
- const void *d;
- void *d2;
-
- r = dns_packet_read(p, length, &d, NULL);
- if (r < 0)
- return r;
-
- d2 = memdup(d, length);
- if (!d2)
- return -ENOMEM;
-
- *dp = d2;
- *lengthp = length;
- return 0;
-}
-
static bool loc_size_ok(uint8_t size) {
uint8_t m = size >> 4, e = size & 0xF;
@@ -1281,7 +1332,6 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
size_t saved_rindex, offset;
uint16_t rdlength;
- const void *d;
int r;
assert(p);
@@ -1492,12 +1542,19 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
if (r < 0)
goto fail;
- r = dns_packet_read_public_key(p, rdlength - 4,
- &rr->ds.digest, &rr->ds.digest_size,
- NULL);
+ r = dns_packet_read_memdup(p, rdlength - 4,
+ &rr->ds.digest, &rr->ds.digest_size,
+ NULL);
if (r < 0)
goto fail;
+ if (rr->ds.digest_size <= 0) {
+ /* the accepted size depends on the algorithm, but for now
+ just ensure that the value is greater than zero */
+ r = -EBADMSG;
+ goto fail;
+ }
+
break;
case DNS_TYPE_SSHFP:
r = dns_packet_read_uint8(p, &rr->sshfp.algorithm, NULL);
@@ -1508,9 +1565,17 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
if (r < 0)
goto fail;
- r = dns_packet_read_public_key(p, rdlength - 2,
- &rr->sshfp.key, &rr->sshfp.key_size,
- NULL);
+ r = dns_packet_read_memdup(p, rdlength - 2,
+ &rr->sshfp.fingerprint, &rr->sshfp.fingerprint_size,
+ NULL);
+
+ if (rr->sshfp.fingerprint_size <= 0) {
+ /* the accepted size depends on the algorithm, but for now
+ just ensure that the value is greater than zero */
+ r = -EBADMSG;
+ goto fail;
+ }
+
break;
case DNS_TYPE_DNSKEY: {
@@ -1539,9 +1604,17 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
if (r < 0)
goto fail;
- r = dns_packet_read_public_key(p, rdlength - 4,
- &rr->dnskey.key, &rr->dnskey.key_size,
- NULL);
+ r = dns_packet_read_memdup(p, rdlength - 4,
+ &rr->dnskey.key, &rr->dnskey.key_size,
+ NULL);
+
+ if (rr->dnskey.key_size <= 0) {
+ /* the accepted size depends on the algorithm, but for now
+ just ensure that the value is greater than zero */
+ r = -EBADMSG;
+ goto fail;
+ }
+
break;
}
@@ -1578,9 +1651,17 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
if (r < 0)
goto fail;
- r = dns_packet_read_public_key(p, offset + rdlength - p->rindex,
- &rr->rrsig.signature, &rr->rrsig.signature_size,
- NULL);
+ r = dns_packet_read_memdup(p, offset + rdlength - p->rindex,
+ &rr->rrsig.signature, &rr->rrsig.signature_size,
+ NULL);
+
+ if (rr->rrsig.signature_size <= 0) {
+ /* the accepted size depends on the algorithm, but for now
+ just ensure that the value is greater than zero */
+ r = -EBADMSG;
+ goto fail;
+ }
+
break;
case DNS_TYPE_NSEC:
@@ -1588,11 +1669,12 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
if (r < 0)
goto fail;
- while (p->rindex != offset + rdlength) {
- r = dns_packet_read_type_window(p, &rr->nsec.types, NULL);
- if (r < 0)
- goto fail;
- }
+ r = dns_packet_read_type_windows(p, &rr->nsec.types, offset + rdlength - p->rindex, NULL);
+ if (r < 0)
+ goto fail;
+
+ /* NSEC RRs with empty bitmpas makes no sense, but the RFC does not explicitly forbid them
+ so we allow it */
break;
@@ -1611,57 +1693,41 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
if (r < 0)
goto fail;
+ /* this may be zero */
r = dns_packet_read_uint8(p, &size, NULL);
if (r < 0)
goto fail;
- rr->nsec3.salt_size = size;
-
- r = dns_packet_read_blob(p, &d, rr->nsec3.salt_size, NULL);
+ r = dns_packet_read_memdup(p, size, &rr->nsec3.salt, &rr->nsec3.salt_size, NULL);
if (r < 0)
goto fail;
- rr->nsec3.salt = memdup(d, rr->nsec3.salt_size);
- if (!rr->nsec3.salt) {
- r = -ENOMEM;
- goto fail;
- }
-
r = dns_packet_read_uint8(p, &size, NULL);
if (r < 0)
goto fail;
- rr->nsec3.next_hashed_name_size = size;
-
- r = dns_packet_read(p, rr->nsec3.next_hashed_name_size, &d, NULL);
- if (r < 0)
+ if (size <= 0) {
+ r = -EBADMSG;
goto fail;
+ }
- rr->nsec3.next_hashed_name = memdup(d, rr->nsec3.next_hashed_name_size);
- if (!rr->nsec3.next_hashed_name) {
- r = -ENOMEM;
+ r = dns_packet_read_memdup(p, size, &rr->nsec3.next_hashed_name, &rr->nsec3.next_hashed_name_size, NULL);
+ if (r < 0)
goto fail;
- }
- r = dns_packet_append_types(p, rr->nsec3.types, NULL);
+ r = dns_packet_read_type_windows(p, &rr->nsec.types, offset + rdlength - p->rindex, NULL);
if (r < 0)
goto fail;
+ /* empty non-terminals can have NSEC3 records, so empty bitmaps are allowed */
+
break;
}
default:
unparseable:
- r = dns_packet_read(p, rdlength, &d, NULL);
+ r = dns_packet_read_memdup(p, rdlength, &rr->generic.data, &rr->generic.size, NULL);
if (r < 0)
goto fail;
-
- rr->generic.data = memdup(d, rdlength);
- if (!rr->generic.data) {
- r = -ENOMEM;
- goto fail;
- }
-
- rr->generic.size = rdlength;
break;
}
if (r < 0)
diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c
index 9c12205ab8..2bc9f2b520 100644
--- a/src/resolve/resolved-dns-rr.c
+++ b/src/resolve/resolved-dns-rr.c
@@ -276,7 +276,7 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
break;
case DNS_TYPE_SSHFP:
- free(rr->sshfp.key);
+ free(rr->sshfp.fingerprint);
break;
case DNS_TYPE_DNSKEY:
@@ -434,8 +434,8 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor
case DNS_TYPE_SSHFP:
return a->sshfp.algorithm == b->sshfp.algorithm &&
a->sshfp.fptype == b->sshfp.fptype &&
- a->sshfp.key_size == b->sshfp.key_size &&
- memcmp(a->sshfp.key, b->sshfp.key, a->sshfp.key_size) == 0;
+ a->sshfp.fingerprint_size == b->sshfp.fingerprint_size &&
+ memcmp(a->sshfp.fingerprint, b->sshfp.fingerprint, a->sshfp.fingerprint_size) == 0;
case DNS_TYPE_DNSKEY:
return a->dnskey.zone_key_flag == b->dnskey.zone_key_flag &&
@@ -687,7 +687,7 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
break;
case DNS_TYPE_SSHFP:
- t = hexmem(rr->sshfp.key, rr->sshfp.key_size);
+ t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size);
if (!t)
return -ENOMEM;
@@ -776,7 +776,7 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
case DNS_TYPE_NSEC3: {
_cleanup_free_ char *salt = NULL, *hash = NULL;
- if (rr->nsec3.salt_size) {
+ if (rr->nsec3.salt_size > 0) {
salt = hexmem(rr->nsec3.salt, rr->nsec3.salt_size);
if (!salt)
return -ENOMEM;
@@ -795,7 +795,7 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
rr->nsec3.algorithm,
rr->nsec3.flags,
rr->nsec3.iterations,
- rr->nsec3.salt_size ? salt : "-",
+ rr->nsec3.salt_size > 0 ? salt : "-",
hash,
t);
if (r < 0)
@@ -809,7 +809,7 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
if (!t)
return -ENOMEM;
- r = asprintf(&s, "%s \\# %"PRIu8" %s", k, rr->generic.size, t);
+ r = asprintf(&s, "%s \\# %zu %s", k, rr->generic.size, t);
if (r < 0)
return -ENOMEM;
break;
diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h
index bdd5a5c824..0f40f3ceef 100644
--- a/src/resolve/resolved-dns-rr.h
+++ b/src/resolve/resolved-dns-rr.h
@@ -53,7 +53,7 @@ struct DnsResourceRecord {
union {
struct {
void *data;
- uint16_t size;
+ size_t size;
} generic;
struct {
@@ -117,11 +117,12 @@ struct DnsResourceRecord {
size_t digest_size;
} ds;
+ /* https://tools.ietf.org/html/rfc4255#section-3.1 */
struct {
uint8_t algorithm;
uint8_t fptype;
- void *key;
- size_t key_size;
+ void *fingerprint;
+ size_t fingerprint_size;
} sshfp;
/* http://tools.ietf.org/html/rfc4034#section-2.1 */
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index e468f245f7..3d46c99df8 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -417,8 +417,10 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
/* Only consider responses with equivalent query section to the request */
if (!dns_question_is_superset(p->question, t->question) ||
- !dns_question_is_superset(t->question, p->question))
+ !dns_question_is_superset(t->question, p->question)) {
dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
+ return;
+ }
/* According to RFC 4795, section 2.9. only the RRs from the answer section shall be cached */
dns_cache_put(&t->scope->cache, p->question, DNS_PACKET_RCODE(p), p->answer, DNS_PACKET_ANCOUNT(p), 0, p->family, &p->sender);
diff --git a/src/shared/nss-util.h b/src/shared/nss-util.h
index 230a986040..3657aa5d9c 100644
--- a/src/shared/nss-util.h
+++ b/src/shared/nss-util.h
@@ -24,6 +24,9 @@
#include <nss.h>
#include <netdb.h>
#include <resolv.h>
+#include <pwd.h>
+#include <grp.h>
+
#define NSS_GETHOSTBYNAME_PROTOTYPES(module) \
enum nss_status _nss_##module##_gethostbyname4_r( \
@@ -109,7 +112,8 @@ enum nss_status _nss_##module##_gethostbyname_r( \
NULL, \
NULL); \
return ret; \
-}
+} \
+struct __useless_struct_to_allow_trailing_semicolon__
#define NSS_GETHOSTBYADDR_FALLBACKS(module) \
enum nss_status _nss_##module##_gethostbyaddr_r( \
@@ -125,4 +129,29 @@ enum nss_status _nss_##module##_gethostbyaddr_r( \
buffer, buflen, \
errnop, h_errnop, \
NULL); \
-}
+} \
+struct __useless_struct_to_allow_trailing_semicolon__
+
+#define NSS_GETPW_PROTOTYPES(module) \
+enum nss_status _nss_##module##_getpwnam_r( \
+ const char *name, \
+ struct passwd *pwd, \
+ char *buffer, size_t buflen, \
+ int *errnop) _public_; \
+enum nss_status _nss_mymachines_getpwuid_r( \
+ uid_t uid, \
+ struct passwd *pwd, \
+ char *buffer, size_t buflen, \
+ int *errnop) _public_
+
+#define NSS_GETGR_PROTOTYPES(module) \
+enum nss_status _nss_##module##_getgrnam_r( \
+ const char *name, \
+ struct group *gr, \
+ char *buffer, size_t buflen, \
+ int *errnop) _public_; \
+enum nss_status _nss_##module##_getgrgid_r( \
+ gid_t gid, \
+ struct group *gr, \
+ char *buffer, size_t buflen, \
+ int *errnop) _public_
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 42f757c4b7..271984b5a8 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -955,9 +955,10 @@ static int path_set_attribute(Item *item, const char *path) {
r = chattr_fd(fd, f, item->attribute_mask);
if (r < 0)
- return log_error_errno(r,
- "Cannot set file attribute for '%s', value=0x%08x, mask=0x%08x: %m",
- path, item->attribute_value, item->attribute_mask);
+ log_full_errno(r == -ENOTTY ? LOG_DEBUG : LOG_WARNING,
+ r,
+ "Cannot set file attribute for '%s', value=0x%08x, mask=0x%08x: %m",
+ path, item->attribute_value, item->attribute_mask);
return 0;
}
diff --git a/units/systemd-networkd.service.m4.in b/units/systemd-networkd.service.m4.in
index 64d9130c24..35be713ade 100644
--- a/units/systemd-networkd.service.m4.in
+++ b/units/systemd-networkd.service.m4.in
@@ -12,7 +12,7 @@ ConditionCapability=CAP_NET_ADMIN
DefaultDependencies=no
# dbus.service can be dropped once on kdbus, and systemd-udevd.service can be
# dropped once tuntap is moved to netlink
-After=systemd-udevd.service dbus.service network-pre.target systemd-sysusers.service
+After=systemd-udevd.service dbus.service network-pre.target systemd-sysusers.service systemd-sysctl.service
Before=network.target multi-user.target shutdown.target
Conflicts=shutdown.target
Wants=network.target